diff --git a/.config/.DS_Store b/.config/.DS_Store new file mode 100644 index 0000000..8a08fc5 Binary files /dev/null and b/.config/.DS_Store differ diff --git a/.config/alacritty/alacritty.yml b/.config/alacritty/alacritty.yml deleted file mode 100644 index 730c23d..0000000 --- a/.config/alacritty/alacritty.yml +++ /dev/null @@ -1,44 +0,0 @@ -background_opacity: 0.7 -font: - normal: - family: Source Code Pro - style: Regular - - bold: - family: Source Code Pro - style: Bold - - italic: - family: Source Code Pro - style: Italic - - bold_italic: - family: Source Code Pro - style: Bold Italic - - size: 11 - # -# Colors (One Dark - https://github.com/atom/atom/tree/master/packages/one-dark-syntax) -colors: - primary: - background: '#282c34' - foreground: '#abb2bf' - cursor: - text: CellBackground - cursor: '#528bff' # syntax-cursor-color - selection: - text: CellForeground - background: '#3e4451' # syntax-selection-color - normal: - black: '#5c6370' # mono-3 - red: '#e06c75' # red 1 - green: '#98c379' - yellow: '#e5c07b' # orange 2 - blue: '#61afef' - magenta: '#c678dd' - cyan: '#56b6c2' - white: '#828997' # mono-2 - search: - bar: - foreground: '#abb2bf' - background: '#282c34' diff --git a/.config/albert/QtProject.conf b/.config/albert/QtProject.conf deleted file mode 100644 index f2020d1..0000000 --- a/.config/albert/QtProject.conf +++ /dev/null @@ -1,5 +0,0 @@ -[FileDialog] -history=@Invalid() -lastVisited=file:///home/adriel -qtVersion=5.15.2 -viewMode=Detail diff --git a/.config/albert/albert.conf b/.config/albert/albert.conf deleted file mode 100644 index 0de4208..0000000 --- a/.config/albert/albert.conf +++ /dev/null @@ -1,68 +0,0 @@ -[General] -frontendId=org.albert.frontend.widgetboxmodel -hotkey=Meta+Shift+G -incrementalSort=false -showTray=true -terminal=alacritty -e - -[org.albert.extension.applications] -enabled=true - -[org.albert.extension.calculator] -enabled=true - -[org.albert.extension.chromium] -enabled=true -fuzzy=false - -[org.albert.extension.files] -enabled=false - -[org.albert.extension.hashgenerator] -enabled=false - -[org.albert.extension.mpris] -enabled=true - -[org.albert.extension.python] -enabled=true - -[org.albert.extension.snippets] -enabled=true - -[org.albert.extension.ssh] -enabled=true - -[org.albert.extension.system] -enabled=true - -[org.albert.extension.terminal] -enabled=true - -[org.albert.extension.virtualbox] -enabled=false - -[org.albert.extension.websearch] -enabled=true - -[org.albert.frontend.qmlboxmodel] -alwaysOnTop=true -clearOnHide=false -hideOnClose=false -hideOnFocusLoss=true -showCentered=false -stylePath=/usr/share/albert/org.albert.frontend.qmlboxmodel/styles/BoxModel/MainComponent.qml -windowPosition=@Point(760 523) - -[org.albert.frontend.widgetboxmodel] -alwaysOnTop=true -clearOnHide=false -displayIcons=true -displayScrollbar=false -displayShadow=true -hideOnClose=false -hideOnFocusLoss=true -itemCount=10 -showCentered=true -theme=Spotlight Dark -windowPosition=@Point(620 283) diff --git a/.config/albert/core.db b/.config/albert/core.db deleted file mode 100644 index 51783f2..0000000 Binary files a/.config/albert/core.db and /dev/null differ diff --git a/.config/albert/last_used_version b/.config/albert/last_used_version deleted file mode 100644 index 50c2e5e..0000000 --- a/.config/albert/last_used_version +++ /dev/null @@ -1 +0,0 @@ -0.17.2 \ No newline at end of file diff --git a/.config/albert/org.albert.extension.snippets/snippets.db b/.config/albert/org.albert.extension.snippets/snippets.db deleted file mode 100644 index 9a43159..0000000 Binary files a/.config/albert/org.albert.extension.snippets/snippets.db and /dev/null differ diff --git a/.config/albert/org.albert.extension.websearch/engines.json b/.config/albert/org.albert.extension.websearch/engines.json deleted file mode 100644 index 589c69e..0000000 --- a/.config/albert/org.albert.extension.websearch/engines.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "iconPath": ":duckduckgo", - "name": "DuckDuckGo", - "trigger": "dd ", - "url": "https://duckduckgo.com/?q=%s" - }, - { - "iconPath": "/home/adriel/.config/albert/org.albert.extension.websearch/{d7c7cd85-d4b4-4a25-ad3d-94026469ef9f}.", - "name": "YewTube", - "trigger": "yt ", - "url": "https://yewtu.be/results?search_query=%s" - }, - { - "iconPath": ":github", - "name": "GitHub", - "trigger": "gh ", - "url": "https://github.com/search?utf8=✓&q=%s" - }, - { - "iconPath": ":amazon", - "name": "Amazon", - "trigger": "ama ", - "url": "http://www.amazon.com/s/?field-keywords=%s" - }, - { - "iconPath": ":wolfram", - "name": "Wolfram Alpha", - "trigger": "=", - "url": "https://www.wolframalpha.com/input/?i=%s" - } -] diff --git a/.config/albert/org.albert.extension.websearch/{d7c7cd85-d4b4-4a25-ad3d-94026469ef9f}. b/.config/albert/org.albert.extension.websearch/{d7c7cd85-d4b4-4a25-ad3d-94026469ef9f}. deleted file mode 100644 index 31a15c7..0000000 --- a/.config/albert/org.albert.extension.websearch/{d7c7cd85-d4b4-4a25-ad3d-94026469ef9f}. +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/.config/albert/org.albert.frontend.qmlboxmodel/style_properties.ini b/.config/albert/org.albert.frontend.qmlboxmodel/style_properties.ini deleted file mode 100644 index 1ccf0ae..0000000 --- a/.config/albert/org.albert.frontend.qmlboxmodel/style_properties.ini +++ /dev/null @@ -1,25 +0,0 @@ -[BoxModel] -animation_duration=200 -background_color="@Variant(\0\0\0\x43\x1\xa7\xa7\x32\x32\x37\x37;;\0\0)" -border_color=@Variant(\0\0\0\x43\x1\xff\xffUU\x95\x95\xdf\xdf\0\0) -border_size=0 -cursor_color=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) -font_name=Google Sans -foreground_color=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) -highlight_color=@Variant(\0\0\0\x43\x1\xff\xff\x61\x61\xab\xab\xff\xff\0\0) -icon_size=15 -input_color=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) -input_fontsize=24 -item_description_fontsize=12 -item_title_fontsize=16 -max_items=8 -padding=4 -radius=7 -selection_color=@Variant(\0\0\0\x43\x1\xff\xff\xc0\xc0\xc0\xc0\xc0\xc0\0\0) -settingsbutton_color=@Variant(\0\0\0\x43\x1\xff\xff\"\"&&))\0\0) -settingsbutton_hover_color=@Variant(\0\0\0\x43\x1\xff\xffUU\x95\x95\xdf\xdf\0\0) -settingsbutton_size=15 -shadow_color=@Variant(\0\0\0\x43\x1\0\0\0\0\0\0\0\0\0\0) -shadow_size=0 -spacing=6 -window_width=400 diff --git a/.config/bible-spotlight/bibles/KJV+.SQLite3 b/.config/bible-spotlight/bibles/KJV+.SQLite3 new file mode 100644 index 0000000..4af0cd2 Binary files /dev/null and b/.config/bible-spotlight/bibles/KJV+.SQLite3 differ diff --git a/.config/bible-spotlight/bibles/NIVUK.SQLite3 b/.config/bible-spotlight/bibles/NIVUK.SQLite3 new file mode 100644 index 0000000..8c7d257 Binary files /dev/null and b/.config/bible-spotlight/bibles/NIVUK.SQLite3 differ diff --git a/.config/brave-flags.conf b/.config/brave-flags.conf deleted file mode 100644 index 1af1827..0000000 --- a/.config/brave-flags.conf +++ /dev/null @@ -1 +0,0 @@ ---enable-features=UseOzonePlatform --ozone-platform=wayland diff --git a/.config/clifm/colors/default-256.clifm b/.config/clifm/colors/default-256.clifm new file mode 100644 index 0000000..eb05161 --- /dev/null +++ b/.config/clifm/colors/default-256.clifm @@ -0,0 +1,280 @@ +# Theme file for CliFM +# Theme name: clifm (256 colors version) +# Author: L. Abramovich +# License: GPL3 + +### How do we define colors? +# +# FiletypeColors, InterfaceColors, and ExtColors use the same format used +# by the LS_COLORS environment variable. Thus, "di=01;34" means that (non-empty) +# directories will be printed in bold blue. +# +# Color codes are just traditional ANSI escape sequences less the escape char +# and the final 'm'. +# 4-bit (16 colors), 8-bit (256 colors), and 24-bit (RGB/HEX) colors are supported. +# Example: +# 31 4-bit +# 38;5;160 8-bit +# 38;2;255;0;0 24-bit (RGB) +# #ff0000 24-bit (HEX) +# +# One attribute can be used for hex colors using a dash and an attribute +# number (RRGGBB-[1-9]), where 1-9 is: +# +# 1: Bold or increased intensity +# 2: Faint, decreased intensity or dim +# 3: Italic (Not widely supported) +# 4: Underline +# 5: Slow blink +# 6: Rapid blink +# 7: Reverse video or invert +# 8: Conceal or hide (Not widely supported) +# 9: Crossed-out or strike +# +# For example, to print bold red color, the hex code is #ff0000-1 + +### Use some variables to hold your color codes +# +# The 'define' keyword allows you to define up to 128 custom color variables. +# They can be used for: +# FiletypeColors +# InterfaceColors +# ExtColors +# DirIconColor +# +# For example, if 'M' is defined as "00;01;36", we can use this color for +# ELN's as follows: "el=M" (see below) + +define D=0 # Default terminal color +define BD=1 # Bold +define DIM=2 # Dimmed + +define DR=2;38;5;197 # Dimmed red +define R8=31 # Red (4-bit) +define BR8=1;31 # Bold red (4-bit) +define UR8=4;31 # Underlined red (4-bit) +define UDR8=4;2;31 # Underlined dimmed red (4-bit) +define DR8=2;31 # Dimmed red (4-bit) + +define G=38;5;76 # Green +define G8=32 # Green (4-bit) +define BG8=1;32 # Bold green (4-bit) +define DG8=2;32 # Dimmed green (4-bit) + +define Y=38;5;228 # Yellow +define BY=1;38;5;229 # Bold yellow +define LY=38;5;185 # Light yellow +define DY8=2;33 # Dimmed yellow (4-bit) +define BY8=1;33 # Bold yellow (4-bit) + +define BB8=1;34 # Bold blue (4-bit) +define DB8=2;34 # Dimmed blue (4-bit) + +define M=38;5;170 # Magenta +define M8=35 # Magenta (4-bit) +define BM8=1;35 # Bold magenta (4-bit) +define DM8=2;35 # Dimmed magenta (4-bit) +define UM8=4;35 # Underlined magenta (4-bit) +define UDM8=4;2;35 # Underlined dimmed magenta (4-bit) + +define C=38;5;43 # Cyan +define C8=36 # Cyan (4-bit) +define BC8=1;36 # Bold cyan (4-bit) +define DC8=2;36 # Dimmed cyan (4-bit) +define BDC8=1;2;36 # Bold dimmed cyan (4-bit) +define RC8=7;36 # Reverse cyan (4-bit) +define UDC8=4;2;36 # Underlined dimmed cyan (4-bit) + +define DW=38;5;246 # Dimmed white +define DW8=2;37 # Dimmed white (4-bit) +define UDW8=4;2;37 # Underlined dimmed white (4-bit) + +# Foreground-background combinations +define URW=4;31;47 # Red foreground, white background +define WR=37;41 # White foreground, red background +# K stands for black (B is used for Blue) +define KY=30;43 # Black foreground, yellow background +define KR=30;41 # Black foreground, red background +define KG=30;42 # Black foreground, green background +# BG is already used for bold green +define BlGr=34;42 # Blue foreground, green background +define WB=37;44 # white foreground, blue background + +define O=38;5;214 # Orange +define BO=1;38;5;214 # Bold orange + +# File groups (used for file extensions) +define DOC=38;5;228 # Yellow +define VIDEO=1;35 # Bold magenta (4-bit) +define IMAGE=35 # Magenta (4-bit) +define SOUND=38;5;214 # Orange +define CODE=1;38;5;247 # Bold gray +define ARCHIVE=1;31 # Bold red (4-bit) +define BOOK=38;5;223 # Salmon +define MARKUP=38;5;85 # Aqua +define TEMP=38;5;247 # Dimmed white + +### To know what are we applying colors to, we use the following codes: + +## File types +# bd = Block device +# ca = File with capabilities +# cd = Char device +# ed = Empty directory +# ee = Empty executable file +# ex = Executable file +# ef = Empty regular file +# fi = Regular file +# di = Directory +# ln = Symbolic link +# mh = Multi-hardlink file +# nd = Directory with no read permission +# ne = Empty directory with no read permission +# nf = Regular file with no read permission +# no = Unknown +# or = Broken symlink +# ow = Other-writable +# pi = FIFO/pipe +# sg = SGID file +# so = Socket +# st = Sticky (not other-writable) +# su = SUID file +# tw = Sticky and other-writable +# uf = Non-'stat'able file + +## Interface +# bm = Bookmarked directory +# fc = Files counter +# df = Default color +# dl = Dividing line +# el = ELN color +# mi = Misc indicators +# ts = TAB completion suffix +# tt = Tilde for trimmed files +# wc = Welcome message +# wp = Warning prompt + +## Auto-suggestions +# sb = Shell builtins +# sc = External commands and aliases +# sd = Internal commands description +# sf = File names +# sh = History +# sx = Internal commands and parameters +# sp = BAEJ suggestions pointer +# sz = File names (fuzzy) + +## Syntax highlighting +# hb = Brackets () [] {} +# hc = Comments +# hd = Paths (slashes) +# he = Expansion operators: * ~ +# hn = Numbers +# hp = Parameters: - +# hq = Quoted strings +# hr = Redirection > +# hs = Process separators | & ; */ +# hv = Variables $ */ +# hw = Wrong, non-existent command name + +## File properties +# dd = Date (1) +# dg = UID, GID +# dn = dash (none) +# do = Permissions in octal notation +# dp = Special files (SUID, SGID, etc) +# dr = Read +# dw = Write +# dxd = Execute (dirs) +# dxr = Execute (reg files) +# dz = Size (1) + +# (1) If unset, gradient colors will be used (default) + +## Workspaces +# wsN = Workspace number N + +## Prompt notifications +# em = Errors +# li = Selected files indicator +# nm = Notices +# ti = Trash indicator +# tx = Command line text +# si = Stealth mode indicator +# wm = Warnings +# xs = Exit code: success +# xf = Exit code: failure + +# NOTE: Whenever a code is unset, the default value is used + +# FiletypeColors defines the color used for file names when listing files, +# just as InterfaceColors defines colors for CliFM's interface. +FiletypeColors="bd=BY:ca=KR:cd=BO:di=BB8:ed=DB8:ee=G8:ef=DIM:ex=BG8:fi=D:ln=BC8:mh=RC8:nd=UBR8:ne=UDR8:nf=UDR8:no=URW:or=UDC8:ow=BlGr:pi=M:sg=KY:so=BM8:st=WB:su=WR:tw=KG:uf=UDW8:" + +InterfaceColors="bm=BG8:dd=:df=D:dg=:dl=DW8:dn=DW8:do=C:dp=:dr=:dw=:dxd=G:dxr=C:dz=:el=C8:em=BR8:fc=DW:hb=C8:hc=DW8:hd=C8:he=C8:hn=:hp=C8:hq=LY:hr=R8:hs=G8:hv=G8:li=BG8:mi=BC8:nm=BG8:si=BB8:sb=DY8:sc=DC8:sd=DW8:sf=UDC8:sh=DM8:sp=DR8:sx=DG8:sz=UDM8:ti=BC8:ts=UM8:tt=BDC8:tx=D:wc=BC8:wm=BY8:wp=DR8:ws1=B8:ws2=R8:ws3=Y:ws4=G8:ws5=C:ws6=O:ws7=M:ws8=DW:xf=BR8:xs=G8:" + +# Colors for specific file extensions (case insensitive) +ExtColors="*.tar=ARCHIVE:*.tgz=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.taz=ARCHIVE:*.lha=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.tlz=ARCHIVE:*.txz=ARCHIVE:*.tzo=ARCHIVE:*.t7z=ARCHIVE:*.zip=ARCHIVE:*.z=ARCHIVE:*.dz=ARCHIVE:*.gz=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lzo=ARCHIVE:*.xz=ARCHIVE:*.zst=ARCHIVE:*.tzst=ARCHIVE:*.bz2=ARCHIVE:*.bz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tz=ARCHIVE:*.deb=ARCHIVE:*.rpm=ARCHIVE:*.jar=ARCHIVE:*.war=ARCHIVE:*.ear=ARCHIVE:*.sar=ARCHIVE:*.rar=ARCHIVE:*.alz=ARCHIVE:*.ace=ARCHIVE:*.zoo=ARCHIVE:*.cpio=ARCHIVE:*.7z=ARCHIVE:*.rz=ARCHIVE:*.cab=ARCHIVE:*.wim=ARCHIVE:*.swm=ARCHIVE:*.dwm=ARCHIVE:*.esd=ARCHIVE:*.apk=ARCHIVE:*.iso=ARCHIVE:*.img=ARCHIVE:*.avif=IMAGE:*.jpg=IMAGE:*.jpeg=IMAGE:*.jxl=IMAGE:*.mjpg=IMAGE:*.mjpeg=IMAGE:*.gif=IMAGE:*.bmp=IMAGE:*.xbm=IMAGE:*.xpm=IMAGE:*.png=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.pcx=IMAGE:*.pbm=IMAGE:*.pgm=IMAGE:*.ppm=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.mng=IMAGE:*.mov=VIDEO:*.mpg=VIDEO:*.mpeg=VIDEO:*.m2v=VIDEO:*.mkv=VIDEO:*.webm=VIDEO:*.webp=VIDEO:*.ogm=VIDEO:*.mp4=VIDEO:*.m4v=VIDEO:*.mp4v=VIDEO:*.vob=VIDEO:*.qt=VIDEO:*.nuv=VIDEO:*.wmv=VIDEO:*.asf=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.flc=VIDEO:*.avi=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.gl=VIDEO:*.dl=VIDEO:*.xcf=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:*.cgm=VIDEO:*.emf=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.mov=VIDEO:*.mpg=VIDEO:*.mpeg=VIDEO:*.m2v=VIDEO:*.mkv=VIDEO:*.webm=VIDEO:*.webp=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.mp4=VIDEO:*.m4v=VIDEO:*.mp4v=VIDEO:*.vob=VIDEO:*.qt=VIDEO:*.nuv=VIDEO:*.wmv=VIDEO:*.flc=VIDEO:*.avi=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.asf=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.gl=VIDEO:*.dl=VIDEO:*.xcf=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:*.cgm=VIDEO:*.emf=VIDEO:*.aac=SOUND:*.au=SOUND:*.m4a=SOUND:*.mid=SOUND:*.midi=SOUND:*.mp3=SOUND:*.mka=SOUND:*.ogg=SOUND:*.opus=SOUND:*.spx=SOUND:*.wma=SOUND:*.wv=SOUND:*.wav=SOUND:*.flac=SOUND:*.aif=SOUND:*.pdf=BOOK:*.djvu=BOOK:*.epub=BOOK:*.mobi=BOOK:*.cbr=BOOK:*.cbz=BOOK:*.ps=DOC:*.sxw=DOC:*.doc=DOC:*.docx=DOC:*.xls=DOC:*.xlsx=DOC:*.xlr=DOC:*.sxi=DOC:*.ppt=DOC:*.pptx=DOC:*.odt=DOC:*.ods=DOC:*.odp=DOC:*.rtf=DOC:*.c=CODE:*.c++=CODE:*.cc=CODE:*.cpp=CODE:*.h=CODE:*.h++=CODE:*.hh=CODE:*.go=CODE:*.java=CODE:*.js=CODE:*.lua=CODE:*.php=CODE:*.rb=CODE:*.rs=CODE:*.kt=CODE:*.kts=CODE:*.hs=CODE:*.pl=CODE:*.vb=CODE:*.html=MARKUP:*.htm=MARKUP:*.shtml=MARKUP:xhtml=MARKUP:*.xml=MARKUP:*.css=MARKUP:*.tex=MARKUP:*.ltx=MARKUP:*.md=MARKUP:*.cache=TEMP:*.tmp=TEMP:*.temp=TEMP:*.log=TEMP:*.bak=TEMP:*.bk=TEMP:*.in=TEMP:*.out=TEMP:*.part=TEMP:*.aux=TEMP:*.old=TEMP:*.orig=TEMP:*.rej=TEMP:*.swp=TEMP:*.pid=TEMP:" + +# The series of color shades used to print timestamps +# The format is: "COLOR-TYPE,ERROR,SHADE1,SHADE2,SHADE3,SHADE4,SHADE5" +# +# COLOR-TYPE is one of: 1 (4-bit: 8 colors), 2 (8-bit: 256 colors), 3 (24-bit: truecolor) +# ERROR is the color used to print bad values +# SHADEn is the color used for the shade N +# +# For 4-bit colors (1), valid colors are in the range 30-37 +# For 8-bit colors (2), valid colors are in the range 0-255 +# For 24-bit colors (3), valid colors have this format: #RRGGBB +# +# An attribute (0-9) can be added to any color (either ERROR or SHADE) using a dash. +# For example: +# "34-1" -> "bold blue" (4-bit colors notation) +# "226-2" -> "dimmed yellow" (8-bit colors notation) +# "#ffaff00-4" -> "underlined orange" (24-bit colors notation) + +#DateShades="1,31-2,36-1,36,36-2" +#DateShades="2,196-2,231,253,250,247,244" +#DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" + +#NOTE: For DateShades to work, the 'dd' color code (solid color for dates) needs to be unset (default) + +# Same as DateShades, but for file sizes +#SizeShades="1,31-2,32,33,31" +#SizeShades="2,196-2,43,76,227,214,202" +#SizeShades="3,#ff0000-2,#00d7af,#87d700,#ffff5f,#ffaf00,#ff5f00" + +#NOTE: For SizeShades to work, the 'dz' color code (solid color for sizes) needs to be unset (default) + +# If icons are enabled, use this color for directories icon (only for icons-in-terminal and Nerd-fonts) +DirIconColor="Y" + +# The prompt used by CliFM. Use the 'prompt' command to check for available +# prompts. Enter 'prompt --help' for more information +# You can use here either prompt codes (see the prompts.clifm file for details) +# or a prompt name defined in the prompts file +Prompt="clifm" +#Prompt=curves +# Override prompt values (as defined in the prompts file) +#Prompt="" +#Notifications= +#EnableWarningPrompt= +#WarningPrompt="" + +# The string used to construct the line dividing the list of files and +# the prompt (Unicode is supported). Possible values: +# "0": Print just an empty line +# "C": C is a single char. This char is printed up to the end of the screen +# "CCC": 3 or more chars. Only these chars (no more) will be printed +# "": Print a special line drawn with box-drawing characters (not +# supported by all terminals/consoles) +# The color of this line is controlled by the 'dl' code in InterfaceColors +DividingLine="-" + +# If the fzf TAB completion mode is enabled, pass these options to fzf(1): +FzfTabOptions="--color='16,prompt:6,fg+:-1,pointer:4,hl:2,hl+:2,gutter:-1,marker:2,border:7:dim' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --inline-info --layout=reverse-list --preview-window=wrap,border-left" + +# Same options, but colorless +#FzfTabOptions="--color='bw' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --inline-info --layout=reverse-list --preview-window=wrap,border-left" + +# For more information consult fzf(1) diff --git a/.config/clifm/colors/default.clifm b/.config/clifm/colors/default.clifm new file mode 100644 index 0000000..905dfe1 --- /dev/null +++ b/.config/clifm/colors/default.clifm @@ -0,0 +1,271 @@ +# Theme file for CliFM +# Theme name: clifm (16 colors version). Check 'default-256' for a 256 colors version +# Author: L. Abramovich +# License: GPL3 + +### How do we define colors? +# +# FiletypeColors, InterfaceColors, and ExtColors use the same format used +# by the LS_COLORS environment variable. Thus, "di=01;34" means that (non-empty) +# directories will be printed in bold blue. +# +# Color codes are just traditional ANSI escape sequences less the escape char +# and the final 'm'. +# 4-bit (16 colors), 8-bit (256 colors), and 24-bit (RGB/HEX) colors are supported. +# Example: +# 31 4-bit +# 38;5;160 8-bit +# 38;2;255;0;0 24-bit (RGB) +# #ff0000 24-bit (HEX) +# +# One attribute can be used for hex colors using a dash and an attribute +# number (RRGGBB-[1-9]), where 1-9 is: +# +# 1: Bold or increased intensity +# 2: Faint, decreased intensity or dim +# 3: Italic (Not widely supported) +# 4: Underline +# 5: Slow blink +# 6: Rapid blink +# 7: Reverse video or invert +# 8: Conceal or hide (Not widely supported) +# 9: Crossed-out or strike +# +# For example, to print bold red color, the hex code is #ff0000-1 + +### Use some variables to hold your color codes +# +# The 'define' keyword allows you to define up to 128 custom color variables. +# They can be used for: +# FiletypeColors +# InterfaceColors +# ExtColors +# DirIconColor +# +# For example, if 'M' is defined as "00;01;36", we can use this color for +# ELN's as follows: "el=M" (see below) + +define D=0 # Default terminal color +define BD=1 # Bold +define DIM=2 # Dimmed + +define R=31 # Red +define BR=1;31 # Bold red +define DR=2;31 # Dimmed red +define UDR=4;2;31 # Underlined dimmed red +define UBR=4;1;31 # Underlined bold red + +define G=32 # Green +define BG=1;32 # Bold green +define DG=2;32 # Dimmed green + +define Y=33 # Yellow +define BY=1;33 # Bold yellow +define DY=2;33 # Dimmed yellow + +define B=34 # Blue +define BB=1;34 # Bold blue +define DB=2;34 # Dimmed blue + +define M=35 # Magenta +define BM=1;35 # Bold Magenta +define DM=2;35 # Dimmed magenta +define UM=4;35 # Underlined magenta +define UDM=4;2;35 # Underlined dimmed magenta + +define C=36 # Cyan +define BC=1;36 # Bold cyan +define DC=2;36 # Dimmed cyan +define RC=7;36 # Reverse cyan +define UDC=4;2;36 # Underlined dimmed cyan +define BDC=1;2;36 # Bold dimmed cyan + +define DW=2;37 # Dimmed white +define UDW=4;2;37 # Underlined dimmed white + +# Foreground-background combinations +define URW=4;31;47 # Red foreground, white background +define WR=37;41 # White foreground, red background +# K stands for black (B is used for Blue) +define KY=30;43 # Black foreground, yellow background +define KR=30;41 # Black foreground, red background +define KG=30;42 # Black foreground, green background +# BG is already used for bold green +define BlGr=34;42 # Blue foreground, green background +define WB=37;44 # white foreground, blue background + +# File groups (used for file extensions) +define DOC=1 # Bold +define VIDEO=1;35 # Bold magenta +define IMAGE=35 # Magenta +define SOUND=36 # Cyan +define CODE=1;33 # Bold yellow +define ARCHIVE=1;31 # Bold red +define TEMP=2;37 # Dimmed white +define BOOK=1 # Bold +define MARKUP=1;33 # Same as CODE + +### To know what are we applying colors to, we use the following codes: + +## File types +# bd = Block device +# ca = File with capabilities +# cd = Char device +# ed = Empty directory +# ee = Empty executable file +# ex = Executable file +# ef = Empty regular file +# fi = Regular file +# di = Directory +# ln = Symbolic link +# mh = Multi-hardlink file +# nd = Directory with no read permission +# ne = Empty directory with no read permission +# nf = Regular file with no read permission +# no = Unknown +# or = Broken symlink +# ow = Other-writable +# pi = FIFO/pipe +# sg = SGID file +# so = Socket +# st = Sticky (not other-writable) +# su = SUID file +# tw = Sticky and other-writable +# uf = Non-'stat'able file + +## Interface +# bm = Bookmarked directory +# fc = Files counter +# df = Default color +# dl = Dividing line +# el = ELN color +# mi = Misc indicators +# ts = TAB completion suffix +# tt = Tilde for trimmed files +# wc = Welcome message +# wp = Warning prompt + +## Auto-suggestions +# sb = Shell builtins +# sc = External commands and aliases +# sd = Internal commands description +# sf = File names +# sh = History +# sx = Internal commands and parameters +# sp = BAEJ suggestions pointer +# sz = File names (fuzzy) + +## Syntax highlighting +# hb = Brackets () [] {} +# hc = Comments +# hd = Paths (slashes) +# he = Expansion operators: * ~ +# hn = Numbers +# hp = Parameters: - +# hq = Quoted strings +# hr = Redirection > +# hs = Process separators | & ; */ +# hv = Variables $ */ +# hw = Wrong, non-existent command name + +## File properties +# dd = Date (1) +# dg = UID, GID +# dn = dash (none) +# do = Permissions in octal notation +# dp = Special files (SUID, SGID, etc) +# dr = Read +# dw = Write +# dxd = Execute (dirs) +# dxr = Execute (reg files) +# dz = Size (1) + +# (1) If unset, gradient colors will be used (default) + +## Workspaces +# wsN = Workspace number N + +## Prompt notifications +# em = Errors +# li = Selected files indicator +# nm = Notices +# ti = Trash indicator +# tx = Command line text +# si = Stealth mode indicator +# wm = Warnings +# xs = Exit code: success +# xf = Exit code: failure + +# NOTE: Whenever a code is unset, the default value is used + +# FiletypeColors defines the color used for file names when listing files, +# just as InterfaceColors defines colors for CliFM's interface. +FiletypeColors="bd=BY:ca=KR:cd=BD:di=BB:ed=DB:ee=G:ef=DIM:ex=BG:fi=D:ln=BC:mh=RC:nd=UBR:ne=UDR:nf=UDR:no=URW:or=UDC:ow=BlGr:pi=M:sg=KY:so=BM:st=WB:su=WR:tw=KG:uf=UDW:" + +InterfaceColors="bm=BG:dd=:df=D:dg=:dl=DW:dn=DW:do=C:dp=:dr=:dw=:dxd=:dxr=:dz=:el=C:em=BR:fc=DW:hb=C:hc=DW:hd=C:he=C:hn=:hp=C:hq=Y:hr=R:hs=G:hv=G:li=BG:mi=BC:nm=BG:si=BB:sb=DY:sc=DC:sd=DW:sf=UDC:sh=DM:sp=DR:sx=DG:sz=UDM:ti=BC:ts=UM:tt=BDC:tx=D:wc=BC:wm=BY:wp=DR:ws1=B:ws2=R:ws3=Y:ws4=G:ws5=C:ws6=C:ws7=C:ws8=C:xf=BR:xs=G:" + +# Colors for specific file extensions (case insensitive) +ExtColors="*.tar=ARCHIVE:*.tgz=ARCHIVE:*.arc=ARCHIVE:*.arj=ARCHIVE:*.taz=ARCHIVE:*.lha=ARCHIVE:*.lz4=ARCHIVE:*.lzh=ARCHIVE:*.lzma=ARCHIVE:*.tlz=ARCHIVE:*.txz=ARCHIVE:*.tzo=ARCHIVE:*.t7z=ARCHIVE:*.zip=ARCHIVE:*.z=ARCHIVE:*.dz=ARCHIVE:*.gz=ARCHIVE:*.lrz=ARCHIVE:*.lz=ARCHIVE:*.lzo=ARCHIVE:*.xz=ARCHIVE:*.zst=ARCHIVE:*.tzst=ARCHIVE:*.bz2=ARCHIVE:*.bz=ARCHIVE:*.tbz=ARCHIVE:*.tbz2=ARCHIVE:*.tz=ARCHIVE:*.deb=ARCHIVE:*.rpm=ARCHIVE:*.jar=ARCHIVE:*.war=ARCHIVE:*.ear=ARCHIVE:*.sar=ARCHIVE:*.rar=ARCHIVE:*.alz=ARCHIVE:*.ace=ARCHIVE:*.zoo=ARCHIVE:*.cpio=ARCHIVE:*.7z=ARCHIVE:*.rz=ARCHIVE:*.cab=ARCHIVE:*.wim=ARCHIVE:*.swm=ARCHIVE:*.dwm=ARCHIVE:*.esd=ARCHIVE:*.apk=ARCHIVE:*.iso=ARCHIVE:*.img=ARCHIVE:*.avif=IMAGE:*.jpg=IMAGE:*.jpeg=IMAGE:*.jxl=IMAGE:*.mjpg=IMAGE:*.mjpeg=IMAGE:*.gif=IMAGE:*.bmp=IMAGE:*.xbm=IMAGE:*.xpm=IMAGE:*.png=IMAGE:*.svg=IMAGE:*.svgz=IMAGE:*.pcx=IMAGE:*.pbm=IMAGE:*.pgm=IMAGE:*.ppm=IMAGE:*.tga=IMAGE:*.tif=IMAGE:*.tiff=IMAGE:*.mng=IMAGE:*.mov=VIDEO:*.mpg=VIDEO:*.mpeg=VIDEO:*.m2v=VIDEO:*.mkv=VIDEO:*.webm=VIDEO:*.webp=VIDEO:*.ogm=VIDEO:*.mp4=VIDEO:*.m4v=VIDEO:*.mp4v=VIDEO:*.vob=VIDEO:*.qt=VIDEO:*.nuv=VIDEO:*.wmv=VIDEO:*.asf=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.flc=VIDEO:*.avi=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.gl=VIDEO:*.dl=VIDEO:*.xcf=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:*.cgm=VIDEO:*.emf=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.mov=VIDEO:*.mpg=VIDEO:*.mpeg=VIDEO:*.m2v=VIDEO:*.mkv=VIDEO:*.webm=VIDEO:*.webp=VIDEO:*.ogm=VIDEO:*.ogv=VIDEO:*.ogx=VIDEO:*.mp4=VIDEO:*.m4v=VIDEO:*.mp4v=VIDEO:*.vob=VIDEO:*.qt=VIDEO:*.nuv=VIDEO:*.wmv=VIDEO:*.flc=VIDEO:*.avi=VIDEO:*.fli=VIDEO:*.flv=VIDEO:*.asf=VIDEO:*.rm=VIDEO:*.rmvb=VIDEO:*.gl=VIDEO:*.dl=VIDEO:*.xcf=VIDEO:*.xwd=VIDEO:*.yuv=VIDEO:*.cgm=VIDEO:*.emf=VIDEO:*.aac=SOUND:*.au=SOUND:*.m4a=SOUND:*.mid=SOUND:*.midi=SOUND:*.mp3=SOUND:*.mka=SOUND:*.ogg=SOUND:*.opus=SOUND:*.spx=SOUND:*.wma=SOUND:*.wv=SOUND:*.wav=SOUND:*.flac=SOUND:*.aif=SOUND:*.pdf=BOOK:*.djvu=BOOK:*.epub=BOOK:*.mobi=BOOK:*.cbr=BOOK:*.cbz=BOOK:*.ps=DOC:*.sxw=DOC:*.doc=DOC:*.docx=DOC:*.xls=DOC:*.xlsx=DOC:*.xlr=DOC:*.sxi=DOC:*.ppt=DOC:*.pptx=DOC:*.odt=DOC:*.ods=DOC:*.odp=DOC:*.rtf=DOC:*.c=CODE:*.c++=CODE:*.cc=CODE:*.cpp=CODE:*.h=CODE:*.h++=CODE:*.hh=CODE:*.go=CODE:*.java=CODE:*.js=CODE:*.lua=CODE:*.php=CODE:*.rb=CODE:*.rs=CODE:*.kt=CODE:*.kts=CODE:*.hs=CODE:*.pl=CODE:*.vb=CODE:*.html=MARKUP:*.htm=MARKUP:*.shtml=MARKUP:xhtml=MARKUP:*.xml=MARKUP:*.css=MARKUP:*.tex=MARKUP:*.ltx=MARKUP:*.md=MARKUP:*.cache=TEMP:*.tmp=TEMP:*.temp=TEMP:*.log=TEMP:*.bak=TEMP:*.bk=TEMP:*.in=TEMP:*.out=TEMP:*.part=TEMP:*.aux=TEMP:*.old=TEMP:*.orig=TEMP:*.rej=TEMP:*.swp=TEMP:*.pid=TEMP:" + +# The series of color shades used to print timestamps +# The format is: "COLOR-TYPE,ERROR,SHADE1,SHADE2,SHADE3,SHADE4,SHADE5" +# +# COLOR-TYPE is one of: 1 (4-bit: 8 colors), 2 (8-bit: 256 colors), 3 (24-bit: truecolor) +# ERROR is the color used to print bad values +# SHADEn is the color used for the shade N +# +# For 4-bit colors (1), valid colors are in the range 30-37 +# For 8-bit colors (2), valid colors are in the range 0-255 +# For 24-bit colors (3), valid colors have this format: #RRGGBB +# +# An attribute (0-9) can be added to any color (either ERROR or SHADE) using a dash. +# For example: +# "34-1" -> "bold blue" (4-bit colors notation) +# "226-2" -> "dimmed yellow" (8-bit colors notation) +# "#ffaff00-4" -> "underlined orange" (24-bit colors notation) + +#DateShades="1,31-2,36-1,36,36-2" +#DateShades="2,196-2,231,253,250,247,244" +#DateShades="3,#ff0000-2,#ffffff,#dadada,#bcbcbc,#9e9e9e,#808080" + +#NOTE: For DateShades to work, the 'dd' color code (solid color for dates) needs to be unset (default) + +# Same as DateShades, but for file sizes +#SizeShades="1,31-2,32,33,31" +#SizeShades="2,196-2,43,112,227,214,202" +#SizeShades="3,#ff0000-2,#00d7af,#87d700,#ffff5f,#ffaf00,#ff5f00" + +#NOTE: For SizeShades to work, the 'dz' color code (solid color for sizes) needs to be unset (default) + +# If icons are enabled, use this color for directories icon (only for icons-in-terminal and Nerd-fonts) +DirIconColor="Y" + +# The prompt used by CliFM. Use the 'prompt' command to check for available +# prompts. Enter 'prompt --help' for more information +# You can use here either prompt codes (see the prompts.clifm file for details) +# or a prompt name defined in the prompts file +Prompt="clifm" + +# Override prompt values (as defined in the prompts file) +#Prompt="" +#Notifications= +#EnableWarningPrompt= +#WarningPrompt="" + +# The string used to construct the line dividing the list of files and +# the prompt (Unicode is supported). Possible values: +# "0": Print just an empty line +# "C": C is a single char. This char is printed up to the end of the screen +# "CCC": 3 or more chars. Only these chars (no more) will be printed +# "": Print a special line drawn with box-drawing characters (not +# supported by all terminals/consoles) +# The color of this line is controlled by the 'dl' code in InterfaceColors +DividingLine="-" + +# If the fzf TAB completion mode is enabled, pass these options to fzf(1): +FzfTabOptions="--color='16,prompt:6,fg+:-1,pointer:4,hl:2,hl+:2,gutter:-1,marker:2,border:7:dim' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --inline-info --layout=reverse-list --preview-window=wrap,border-left" + +# Same options, but colorless +#FzfTabOptions="--color='bw' --marker='*' --bind tab:accept,right:accept,left:abort,alt-p:toggle-preview,change:top,alt-up:preview-page-up,alt-down:preview-page-down --inline-info --layout=reverse-list --preview-window=wrap,border-left" + +# For more information consult fzf(1) diff --git a/.config/clifm/keybindings.clifm b/.config/clifm/keybindings.clifm new file mode 100644 index 0000000..5dc05ae --- /dev/null +++ b/.config/clifm/keybindings.clifm @@ -0,0 +1,149 @@ +# Keybindings file for CliFM + +# Emacs style key escapes are the simplest way of setting your +# keybindings. For example, use "action:\C-t" to bind the action name +# 'action' to Ctrl-t +# Note: available action names are defined below + +# If you need some more control, hex, octal, and decimal notation is +# also supported (this is needed for example for function keys). For +# the sake of simplicity, CliFM provides a plugin to easily get the +# adequate codes. +# Use the 'kbgen' plugin (compile it first: gcc -o kbgen kbgen.c) to +# find out the escape code for the key o key sequence you want. Use +# either octal, hexadecimal codes or symbols. +# Ex: For Alt-/ (in rxvt terminals) 'kbgen' will print the following +# lines: +# Hex | Oct | Symbol +# ---- | ---- | ------ +# \x1b | \033 | ESC (\e) +# \x2f | \057 | / +# In this case, the keybinding, if using symbols, is: "\e/:function" +# In case you prefer the hex codes it would be: \x1b\x2f:function. +# GNU emacs escape sequences are also allowed (ex: "\M-a", Alt-a +# in most keyboards, or "\C-r" for Ctrl-r). +# Some codes, especially those involving keys like Ctrl or the arrow +# keys, vary depending on the terminal emulator and the system settings. +# These keybindings should be set up thus on a per terminal basis. +# You can also consult the terminfo database via the infocmp command. +# See terminfo(5) and infocmp(1). + +# Alt-j +previous-dir:\M-j +# Shift-left (rxvt) +previous-dir2:\e[d +# Shift-left (xterm) +previous-dir3:\e[2D +# Shift-left (others) +previous-dir4:\e[1;2D + +# Alt-k +next-dir:\M-k +# Shift-right (rxvt) +next-dir2:\e[c +# Shift-right (xterm) +next-dir3:\e[2C +# Shift-right (others) +next-dir4:\e[1;2C + +first-dir:\C-\M-j +last-dir:\C-\M-k + +# Alt-u +parent-dir:\M-u +# Shift-up (rxvt) +parent-dir2:\e[a +# Shift-up (xterm) +parent-dir3:\e[2A +# Shift-up (others) +parent-dir4:\e[1;2A + +# Alt-e +home-dir:\M-e +# Home key (rxvt) +#home-dir2:\e[7~ +# Home key (xterm) +#home-dir3:\e[H +# Home key (Emacs term) +#home-dir4:\e[1~ + +# Alt-r +root-dir:\M-r +# Alt-/ (rxvt) +root-dir2:\e/ +#root-dir3: + +pinned-dir:\M-p +workspace1:\M-1 +workspace2:\M-2 +workspace3:\M-3 +workspace4:\M-4 + +# Help +# F1-3 +show-cmds:\eOQ +show-cmds2:\e[12~ +show-kbinds:\eOR +show-kbinds2:\e[13~ +show-manpage:\eOP +show-manpage2:\e[11~ + +archive-sel:\C-\M-a +bookmark-sel:\C-\M-b +bookmarks:\M-b +clear-line:\M-c +clear-msgs:\M-t +create-file:\M-n +deselect-all:\M-d +dirs-first:\M-g +export-sel:\C-\M-e +launch-view:\M-- +lock:\M-o +mountpoints:\M-m +move-sel:\C-\M-n +new-instance:\C-x +next-profile:\C-\M-p +only-dirs:\M-, +open-sel:\C-\M-g +paste-sel:\C-\M-v +prepend-sudo:\M-v +previous-profile:\C-\M-o +rename-sel:\C-\M-r +remove-sel:\C-\M-d +refresh-screen:\C-r +selbox:\M-s +select-all:\M-a +show-dirhist:\M-h +sort-previous:\M-z +sort-next:\M-x +toggle-hidden:\M-i +toggle-hidden2:\M-. +toggle-light:\M-y +toggle-long:\M-l +toggle-max-name-len:\C-\M-l +toggle-disk-usage:\C-\M-i +toggle-virtualdir-full-paths:\M-w +trash-sel:\C-\M-t +untrash-all:\C-\M-u + +# F6-12 +edit-color-scheme:\e[19~ +open-bookmarks:\e[23~ +open-config:\e[21~ +#open-jump-db:\e[18~ +open-keybinds:\e[20~ +open-mime:\e[17~ +open-preview:\e[18~ +quit:\e[24~ + +# Plugins +# 1) Make sure your plugin is in the plugins directory (or use any of the +# plugins in there) +# 2) Link pluginx to your plugin using the 'actions edit' command. Ex: +# "plugin1=myplugin.sh" +# 3) Set a keybinding here for pluginx. Ex: "plugin1:\M-7" + +#plugin1: +#plugin2: +#plugin3: +#plugin4: diff --git a/.config/clifm/profiles/default/.last b/.config/clifm/profiles/default/.last new file mode 100644 index 0000000..623da53 --- /dev/null +++ b/.config/clifm/profiles/default/.last @@ -0,0 +1 @@ +*0:/Users/asand/clone/dotfiles/.config diff --git a/.config/clifm/profiles/default/actions.clifm b/.config/clifm/profiles/default/actions.clifm new file mode 100644 index 0000000..346bcbd --- /dev/null +++ b/.config/clifm/profiles/default/actions.clifm @@ -0,0 +1,41 @@ +###################### +# CliFM actions file # +###################### + +# Define here your custom actions. Actions are custom command names +# bound to a executable file located either in DATADIR/clifm/plugins +# (usually /usr/share/clifm/plugins) or in $XDG_CONFIG_HOME/clifm/plugins. +# Actions can be executed directly from CliFM command line, as if they +# were any other command, and the associated file will be executed +# instead. All parameters passed to the action command will be passed +# to the corresponding plugin as well. + ++=finder.sh +++=jumper.sh +-=fzfnav.sh +*=fzfsel.sh +**=fzfdesel.sh +//=rgfind.sh +_=fzcd.sh +bcp=batch_copy.sh +bmi=bm_import.sh +bn=batch_create.sh +clip=clip.sh +cr=cprm.sh +da=disk_analyzer.sh +dr=dragondrop.sh +fdups=fdups.sh +gg=pager.sh +h=fzfhist.sh +i=img_viewer.sh +ih=ihelp.sh +kbgen=kbgen +kd=decrypt.sh +ke=encrypt.sh +ml=mime_list.sh +music=music_player.sh +ptot=pdf_viewer.sh +rrm=recur_rm.sh +update=update.sh +vid=vid_viewer.sh +wall=wallpaper_setter.sh diff --git a/.config/clifm/profiles/default/bookmarks.clifm b/.config/clifm/profiles/default/bookmarks.clifm new file mode 100644 index 0000000..b387e53 --- /dev/null +++ b/.config/clifm/profiles/default/bookmarks.clifm @@ -0,0 +1,10 @@ +### This is the bookmarks file for clifm ### + +# Empty and commented lines are ommited +# Make your changes, save, and exit +# To remove a bookmark, delete the corresponding line, save, and exit +# Changes are applied automatically at exit (to cancel just quit the editor). + +# The bookmarks syntax is: [shortcut]name:path +# Example: +[c]clifm:/Users/asand/.config/clifm/profiles/default diff --git a/.config/clifm/profiles/default/clifmrc b/.config/clifm/profiles/default/clifmrc new file mode 100644 index 0000000..8b7a9d8 --- /dev/null +++ b/.config/clifm/profiles/default/clifmrc @@ -0,0 +1,432 @@ + ########################################### + # CLIFM # + # The command line file manager # + ########################################### + +# This is CliFM's main configuration file + +# Lines starting with either '#' or ';' are commented (ignored). +# Options starting with a ';' hold the default value, but are commented. +# To override a default value, uncomment the corresponding option. + + +#=====================================# +# 1. INTERFACE # +#=====================================# + +# Show hidden files (i.e. files starting with a dot)? +;ShowHiddenFiles=false + +# Use a regular expression to filter files from the files list. +# Example: "!.*~$" to exclude backup files (ending with ~), or "^\." to +# list only hidden files. File type filters are also supported. Example: +# "=d" to list directories only, or "!=l" to exclude symlinks. +# Run 'help file-filters' for more information. +;Filter="" + +# List directories first? +;ListDirsFirst=true + +# The amount of files contained by a directory is informed next +# to the directory name. However, this feature might slow things down +# when, for example, listing files on a remote server. The files counter +# can be disabled here, via the --no-files-counter option, or using the +# 'fc' command while in the program itself. +# Note: Classify (see below) must be set to true. +;FilesCounter=true + +# Mas, the files list pager. Possible values are: +# 0/false: Disable the pager +# 1/true: Run the pager whenever the list of files does not fit on the screen +# >1: Run the pager whenever the amount of files in the current directory is +# greater than or equal to this value (say, 1000) +;Pager=false + +# If running with colors, append directory indicator to directories. If +# running without colors (via the --no-color option), append file type +# indicator at the end of file names: +# '/' for directories +# '@' for symbolic links +# '=' for sockets +# '|' for FIFO/pipes +# '*' for for executable files +# '?' for unknown file types +# Bear in mind that when running in light mode the check for executable +# files won't be performed, and thereby no indicator will be added to +# executable files. +# Note: Setting this option to false disables the files counter. +;Classify=true + +# How to list files: 0 = vertically (like ls(1) would), 1 = horizontally +;ListingMode=0 + +# Choose sorting method: 0 = none, 1 = name, 2 = size, 3 = atime +# 4 = btime (ctime if not available), 5 = ctime, 6 = mtime, 7 = version +# (name if not available) 8 = extension, 9 = inode, 10 = owner-ID, and +# 11 = group-ID +;Sort=7 + +# By default, CliFM sorts files from less to more (ex: from 'a' to 'z' if +# using the "name" method). To invert this ordering, set SortReverse to +# true (you can also use the --sort-reverse option or the 'st' command) +;SortReverse=false + +# List files properties next to file names instead of just file names +;LongViewMode=false + +# Properties fields to be printed for each file name in long view mode +# f: files counter (for directories) +# d: inode number +# p|n = permissions: either symbolic (p) or numeric/octal (n) +# i = user/group IDs +# a|m|c = last (a)ccess, (m)odification, or status (c)hange time (YYYY-MM-DD HH:MM:SS) +# s|S = size (either human readable (s) or bytes (S)) +# x = extended attributes (marked as '@') +# A single dash ("-") disables all fields +# Example: print only permissions (numeric) and size (human readable): +#PropFields="ns" +;PropFields="fpims" + +# Format used to display timestamps in long view mode. +# Consult strftime(3) for information about time format specifiers. +# Defaults to "%b %e %H:%M" for recent files (< 6 months) and "%b %e %Y" +# for older files. +# Examples: +## ISO +;TimeStyle="%Y-%m-%d" +## Long ISO +;TimeStyle="%Y-%m-%d %H:%M" +## Full ISO +;TimeStyle="%Y-%m-%d %H:%M:%S %z" +## Legacy style (old versions) +;TimeStyle="%F %T" +## Relative time +;TimeStyle=relative + +# If running in long view, print directories full size (including contents) +;FullDirSize=false + +# Print files apparent size instead of actual device usage +# Note that on non-Linux or POSIX-compliant systems, du(1), used by clifm +# to get full directories size, has no option to display files apparent +# sizes, so that actual device usage is always used instead. +;ApparentSize=true + +# In light mode, extra file type checks (except those provided by +# the d_type field of the dirent structure (see readdir(3)) +# are disabled to speed up the listing process. stat(3) and access(3) +# are not executed at all, so that we cannot know in advance if a file +# is readable by the current user, if it is executable, SUID, SGID, if a +# symlink is broken, and so on. The file extension check is ignored as +# well, so that the color per extension feature is disabled. +;LightMode=false + +# If set to true, clear the screen before listing files +;ClearScreen=true + +# Maximum file name length for listed files. Names larger than +# MAXFILENAMELEN will be truncated at MAXFILENAMELEN using a tilde +# Set it to -1 (or empty) to remove this limit +# When running in long mode, this setting is overriden by MinFilenameTrim +;MaxFilenameLen=20 + +# Minimum length at which a file name can be trimmed in long view mode +# (including ELN length and spaces). When running in long mode, this +# setting overrides MaxFilenameLen whenever MAXFILENAMELEN is smaller +# than MINFILENAMETRIM. +;MinFilenameTrim=20 + +# A comma separated list of workspace names in the form NUM=NAME +# Example: "1=MAIN,2=EXTRA,3=GIT" or "1=α,2=β,3=γ" +;WorkspaceNames="" + +# If set to true, settings changed in the current workspace (only via +# the command line or keyboard shortcuts) are kept private to that +# workspace and made persistent (for the current session only), even +# when switching workspaces. +;PrivateWorkspaceSettings=false + +# Print the disk usage of the file system the current directory belongs to +# in the form FREE/TOTAL +;DiskUsage=false + +# If set to true, print a map of the current position in the directory +# history list, showing previous, current, and next entries +;DirhistMap=false + +# If set to true, always print the list of selected files. Since this +# list could become quite extensive, you can limit the number of printed +# entries using the MaxPrintSelfiles option below +;PrintSelfiles=false + +# Maximum amount of selected files to be printed if PrinSelFiles is set +# to true. Possible values: -1 = no limit, 0 = auto (never print more +# than half terminal height), or any positive value +;MaxPrintSelfiles=0 + +# Color schemes (or just themes) are stored in the colors directory +# ($XDG_DATA_DIRS/clifm/colors, usually /usr/local/share/clifm/colors +# or /usr/share/clifm/colors). You can place your custom themes in +# $HOME/.config/clifm/colors +# +# Use the 'cs' command or the '--color-scheme' command line option to set +# a theme +# +# Run 'cs edit' to edit the current theme +# +# Each theme includes color definitions, just as definitions for the +# prompt, the warning prompt, the dividing line, and the FZF window +# +# Use TAB to list available themes: 'cs TAB' +# +# Visit https://github.com/leo-arch/clifm-colors to get some extra themes +# +# Defaults to 'default-256', or 'default' (16 colors) if 256 colors support +# is not detected +;ColorScheme=one-dark + +# Enable/disable icons. +# By default, emojis (widely available today) are used as icons. +# Nerd-fonts and icons-in-terminal are supported as well, though clifm +# needs to be recompiled in order to enable support. Consult our Wiki +# (https://github.com/leo-arch/clifm/wiki) for more information. +;Icons=true + + +#=====================================# +# 2. COMMAND LINE # +#=====================================# + +# Enable fuzzy matching for filename/path completions and suggestions +;FuzzyMatching=false + +# Fuzzy algorithm. Available options are: +# 1 = faster, not Unicode aware +# 2 = slower, Unicode aware +;FuzzyAlgorithm=2 + +# TAB completion mode: 'standard', 'fzf', 'fzy' or 'smenu'. Defaults +# to 'fzf' if the binary is found in PATH. Othwerwise, the standard +# mode is used +;TabCompletionMode= + +# File previews for TAB completion (fzf mode only). Possible values: +# 'true', 'false', 'hidden' (enabled, but hidden; toggle with Alt-p) +;FzfPreview=true + +# If set to true, enable auto-suggestions +;AutoSuggestions=true + +# The following checks will be performed in the order specified +# by SuggestionStrategy. Available checks: +# a = Aliases names\n\ +# b = Bookmarks names (deprecated since v1.9.9)\n\ +# c = Path completion\n\ +# e = ELN's +# f = File names in current directory\n\ +# h = Commands history\n\ +# j = Jump database\n\ +# Use a dash (-) to skip a check. Ex: 'ehfj-ac' to skip the bookmarks +# check +;SuggestionStrategy=ehfj-ac + +# If set to true, suggest file names using the corresponding file type +# color (set via the color scheme file) +;SuggestFiletypeColor=false + +# Suggest a brief description for internal commands +;SuggestCmdDesc=true + +# Enable syntax highlighting? +;SyntaxHighlighting=true + +# Should CliFM be allowed to run external, shell commands? +;ExternalCommands=true + + +#=====================================# +# 3. COMMANDS # +#=====================================# + +# List files automatically after changing current directory +;AutoLs=true + +# If set to true, a command name that is the name of a directory or a +# file is executed as if it were the argument to the the 'cd' or the +# 'open' commands respectivelly: 'cd DIR' works the same as just 'DIR' +# and 'open FILE' works the same as just 'FILE'. +;Autocd=true +;AutoOpen=true + +# If set to true, the 'r' command executes 'trash' instead of rm(1). +;TrashAsRm=false + +# Set the default copy command. Available options are: +# 0 = 'cp -iRp', 1 = 'cp -Rp', 2 = 'advcp -giRp', 3 = 'advcp -gRp', +# 4 = 'wcp', and 5 = 'rsync -avP' +# 2-5 include a progress bar +# Only 0 and 2 will prompt before overwrite +;cpCmd=0 + +# Set the default move command. Available options are: +# 0 = 'mv -i', 1 = 'mv', 2 = 'advmv -gi', and 3 = 'advmv -g' +# 2 and 3 include a progress bar +# Only 0 and 2 will prompt before overwrite +;mvCmd=0 + +# If set to true, the 'r' command will never prompt before removals. +# Note: rm(1) is invoked with the -f flag +;rmForce=false + +# Choose the resource opener to open files with their default associated +# application (e.g. Ranger's rifle or xdg-open). If not set, 'lira', +# CliFM's built-in opener, is used instead. +;Opener= + +# Only used when opening a directory via a new CliFM instance (with the +# 'x' command), this option specifies the command to be used to launch a +# terminal emulator to run CliFM on it. +;TerminalCmd="xterm -e" + +# We have three search strategies: 0 = glob-only, 1 = regex-only, +# and 2 = glob-regex. Used by the quick search function +;SearchStrategy=2 + +# When a directory rank in the jump database is below MinJumpRank, it +# will be removed. If set to 0, directories are kept indefinitely +;MinJumpRank=10 + +# When the sum of all ranks in the jump database reaches MaxJumpTotalRank, +# all ranks will be reduced using a dynamic factor so that the total sum falls +# below MaxJumpTotalRank again. Those entries falling below MinJumpRank will +# be deleted +;MaxJumpTotalRank=100000 + +# Automatically purge the jump database from non-existing directories at +# startup. Note that this will remove paths pointing to unmounted removable +# devices and remote file systems +;PurgeJumpDB=false + + +#=====================================# +# 4. LOGS AND HISTORY # +#=====================================# + +# Send errors, warnings, and notices to the notification daemon? +;DesktopNotifications=false + +# Keep track of errors and warnings +;Logs=false +# Keep a record of external commands and internal commands able to modify the +# files system (e.g. 'r', 'c', 'm', and so on). Logs must be set to true. +;LogCmds=false +# Keep only the last N lines of the log file +;MaxLog=1000 + +# Limit the size of the commands history file to N entries +;MaxHistory=1000 +# Limit the size of the directory history file to N entries +;MaxDirhist=100 + + +#=====================================# +# 5. MISC # +#=====================================# + +# Enable case sensitive listing for files in the current directory +;CaseSensitiveList=false + +# Enable case sensitive lookup for the directory jumper function (via +# the 'j' command) +;CaseSensitiveDirJump=false + +# Enable case sensitive completion for file names +;CaseSensitivePathComp=false + +# Enable case sensitive search +;CaseSensitiveSearch=false + +# Whether to be Unicode aware or not. If using a 100% ASCII setup +# (e.g. English), you can turn this off +;Unicode=true + +# CliFM's starting path. If not specified, it defaults to the current +# working directory. If set, it overrides RestoreLastPath. +;StartingPath= + +# If set to true, start CliFM in the last visited directory (and in the +# last used workspace). This option is overriden by StartingPath (if set). +;RestoreLastPath=true + +# MaxPath is only used for the /p option of the prompt: the current +# working directory will be abbreviated to its basename (everything after +# the last slash) whenever the current path is longer than MaxPath. +;MaxPath=40 + +# Set readline editing mode: 0 for vi and 1 for emacs (default). +;RlEditMode=1 + +# Write the last visited directory to $XDG_CONFIG_HOME/clifm/.last to be +# later accessed by the corresponding shell function at program exit. +# To enable this feature consult the manpage. +;CdOnQuit=false + +# Should the Selection Box be shared among different profiles? +;ShareSelbox=false + +# Print a usage tip at startup +;Tips=true + +# Just a kind welcome message at startup +;WelcomeMessage=true + +# Set a custom welcome message +;WelcomeMessageStr="" + +# Print CliFM's logo screen at startup +;SplashScreen=false + + +#=====================================# +# 6. ALIASES # +#=====================================# + +# Bind '?' to the interactive help plugin. Run 'actions' to print the +# list of available plugins +#alias ?='ih' +# Bind 'b' to the directory history navigation plugin +#alias b='dh' +# Replace the standard deselect command (ds) by the fzfdesel plugin +#alias ds='**' +# You can use this alias to quickly change to the current virtual directory +#alias vtd='cd $CLIFM_VIRTUAL_DIR' +# Replace the built-in bulk rename function (br) by vidir(1) +#br='vidir' + +#=====================================# +# 7. PROMPT COMMANDS # +#=====================================# + +# Write below the commands you want to be executed before each prompt. Ex: +#promptcmd /usr/local/share/clifm/plugins/git_status.sh +#promptcmd date | awk '{print $1", "$2,$3", "$4}' + +#=====================================# +# 8. AUTOCOMMANDS # +#=====================================# + +# Control CliFM's settings on a per directory basis. For more information +# consult the manpage + +# Remote file systems are slow: let's speed this up by enabling the light +# mode and disabling the files counter +#autocmd /media/remotes/** lm=1,fc=0 + +# Just a friendly reminder +#autocmd ~/important !printf "Keep your fingers outta here!\n" && read -n1 + +# Plenty of images and vids? Launch the files previewer plugin +#autocmd ~/Downloads !/usr/local/share/clifm/plugins/fzfnav.sh + +# I want files in the third workspace to be listed in long view +#autocmd @ws3 lv=1 diff --git a/.config/clifm/profiles/default/cmdlogs.clifm b/.config/clifm/profiles/default/cmdlogs.clifm new file mode 100644 index 0000000..ccfd289 --- /dev/null +++ b/.config/clifm/profiles/default/cmdlogs.clifm @@ -0,0 +1,8 @@ +[2023-04-27T15:34:59-0700] /Users/asand/Documents/02 - Personal/03 - Classes/Socials 10:log off +[2023-04-28T06:44:03-0700] /Users/asand/Documents/02 - Personal/03 - Classes/English 10:log off +[2023-04-28T08:17:10-0700] /Users/asand/Documents/02 - Personal/03 - Classes/English 10:log off +[2023-04-28T13:38:26-0700] /Users/asand/Documents/02 - Personal/03 - Classes/Socials 10:log off +[2023-04-28T13:38:52-0700] /Users/asand/Documents/02 - Personal/03 - Classes/Socials 10:log off +[2023-04-28T13:38:59-0700] /Users/asand/Documents/02 - Personal/03 - Classes/Socials 10:log off +[2023-04-28T13:40:48-0700] /Users/asand/Documents/02 - Personal/03 - Classes/Socials 10:log off +[2023-05-09T16:03:13-0700] /Users/asand/Documents/02 - Personal/03 - Classes/Bible 10:log off diff --git a/.config/clifm/profiles/default/dirhist.clifm b/.config/clifm/profiles/default/dirhist.clifm new file mode 100644 index 0000000..cfe3615 --- /dev/null +++ b/.config/clifm/profiles/default/dirhist.clifm @@ -0,0 +1,89 @@ +/Users/asand/Documents/02 - Personal/03 - Classes/English 10 +/Users/asand/Documents/02 - Personal/03 - Classes +/Users/asand/Documents/02 - Personal/03 - Classes/Socials 10 +/Users/asand +/Users/asand/Documents/02 - Personal/03 - Classes/Socials 10 +/Users/asand +/Users/asand/Documents/02 - Personal/03 - Classes/English 10 +/Users/asand +/Users/asand/.config +/Users/asand/.config/yabai +/Users/asand/Documents/02 - Personal/03 - Classes/Socials 10 +/Users/asand/Documents/02 - Personal/03 - Classes/English 10 +/Users/asand/Documents/02 - Personal/03 - Classes +/Users/asand/Documents/02 - Personal/03 - Classes/Bible 10 +/Users/asand +/Users/asand/.config +/Users/asand/.config/yabai +/Users/asand/Documents/02 - Personal/03 - Classes/Bible 10 +/Users/asand/.config/sketchybar +/Users/asand/.config/sketchybar/items +/Users/asand +/Users/asand/Documents +/Users/asand/Documents/05 - Saved Content +/Users/asand/Documents/05 - Saved Content/000 - YouTube +/Users/asand +/Users/asand/Documents +/Users/asand/Documents/01 - Projects +/Users/asand/Documents +/Users/asand/Documents/02 - Personal +/Users/asand/Documents/02 - Personal/00 - Me +/Users/asand/Documents/02 - Personal/00 - Me/09 - Keys +/Users/asand +/Users/asand/Downloads +/Users/asand/Downloads/fullstack-hy2020.github.io-source +/Users/asand +/Users/asand/Documents +/Users/asand/Documents/01 - Projects +/Users/asand/Documents/01 - Projects/2 - Progress +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website/node_modules +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website/node_modules/howler +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website/node_modules/howler/dist +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website/node_modules/howler +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website/node_modules +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Forte +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/forte +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/forte/client +/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website +/Users/asand +/Users/asand/Documents +/Users/asand/Documents/05 - Saved Content +/Users/asand/Documents/05 - Saved Content/000 - YouTube +/Users/asand/Documents/05 - Saved Content/000 - YouTube/004 Spoken Gospel +/Users/asand/Documents/05 - Saved Content/000 - YouTube +/Users/asand/Documents/05 - Saved Content +/Users/asand/Documents/05 - Saved Content/000 - Music +/Users/asand/Documents/05 - Saved Content/000 - Music/1 - Audio +/Users/asand/Documents/05 - Saved Content/000 - Music/1 - Audio/Daniel Camporee +/Users/asand +/Users/asand/Music +/Users/asand/Music/StemRoller +/Users/asand/Music/StemRoller/Once Again (Finale) [bAO53Jhju2M]-156e91a2749716dd +/Users/asand +/Users/asand/clone +/Users/asand +/Users/asand/server +/Users/asand/server/matrix-docker-ansible-deploy +/Users/asand/clone/dotfiles +/Users/asand/clone/dotfiles/.config +/Users/asand/clone/dotfiles +/Users/asand/clone/dotfiles/.git +/Users/asand/clone/dotfiles +/Users/asand/clone/dotfiles/.local +/Users/asand/clone/dotfiles/.local/share +/Users/asand/clone/dotfiles/.local/share/applications +/Users/asand/clone/dotfiles/.local/share +/Users/asand/clone/dotfiles/.local/share/gnome-shell +/Users/asand/clone/dotfiles/.local/share +/Users/asand/clone/dotfiles/.local +/Users/asand/clone/dotfiles +/Users/asand/clone/dotfiles/scripts +/Users/asand/clone/dotfiles +/Users/asand/clone/dotfiles/scripts +/Users/asand/clone/dotfiles +/Users/asand/clone/dotfiles/.config diff --git a/.config/clifm/profiles/default/history.clifm b/.config/clifm/profiles/default/history.clifm new file mode 100644 index 0000000..184b9f9 --- /dev/null +++ b/.config/clifm/profiles/default/history.clifm @@ -0,0 +1,293 @@ +edit +#1682624541 +help +#1682624819 +l +#1682624822 +ls +#1682624869 +cs theme +#1682624874 +cs +#1682624878 +cs one-dark +#1682624902 +config +#1682624964 +icons +#1682624966 +icons on +#1682624971 +config +#1682634899 +v "009 - Women Advances in Status.txt" +#1682634913 +nvim "009 - Women Advances in Status.txt" +#1682652899 +cd +#1682652903 +j Socials +#1682652907 +cd +#1682653264 +edit +#1682689439 +j Englis +#1682689443 +v 6 +#1682689446 +nvim 6 +#1682694901 +.config +#1682694915 +Library +#1682694937 +Application\ Support/ +#1682694973 +~ +#1682694982 +j Engl +#1682694994 +nvim 6 +#1682695030 +m 6 003\ -\ Nature\ Lesson.md +#1682695037 +nvim 6 +#1682697335 +~ +#1682697337 +.config/ +#1682697349 +t 1 2 +#1682697370 +/Users/asand/Documents/02\ -\ Personal/03\ -\ Classes/English\ 10/ +#1682708555 +~ +#1682708558 +.config +#1682708572 +mkdir yabai +#1682708605 +#!/usr/bin/env sh + +# Unload the macOS WindowManager process +launchctl unload -F /System/Library/LaunchAgents/com.apple.WindowManager.plist > /dev/null 2>&1 & + +sudo yabai --load-sa +yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa" +yabai -m signal --add event=window_focused action="sketchybar --trigger window_focus" +yabai -m signal --add event=display_added action="sleep 2 && $HOME/.config/yabai/create_spaces.sh" +yabai -m signal --add event=display_removed action="sleep 1 && $HOME/.config/yabai/create_spaces.sh" +yabai -m signal --add event=window_created action="sketchybar --trigger windows_on_spaces" +yabai -m signal --add event=window_destroyed action="sketchybar --trigger windows_on_spaces" + +$HOME/.config/yabai/create_spaces.sh + +yabai -m config external_bar all:49:0 \ + window_border on \ + mouse_follows_focus off \ + focus_follows_mouse off \ + window_zoom_persist off \ + window_placement second_child \ + window_topmost off \ + window_shadow float \ + window_opacity on \ + window_opacity_duration 0.15 \ + active_window_opacity 1.0 \ + normal_window_opacity 0.95 \ + window_border_width 2 \ + window_border_hidpi off \ + window_border_radius 11 \ + window_animation_duration 0.22 \ + active_window_border_color 0xffe1e3e4 \ + normal_window_border_color 0xff2a2f38 \ + insert_feedback_color 0xff9dd274 \ + split_ratio 0.50 \ + auto_balance off \ + mouse_modifier fn \ + mouse_action1 move \ + mouse_action2 resize \ + mouse_drop_action swap \ + \ + top_padding 10 \ + bottom_padding 10 \ + left_padding 10 \ + right_padding 10 \ + window_gap 8 + +# Exclude problematic apps from being managed: +yabai -m rule --add app="^(LuLu|Vimac|Calculator|Software Update|Dictionary|VLC|System Preferences|System Settings|zoom.us|Photo Booth|Archive Utility|Python|LibreOffice|App Store|Steam|Alfred|Activity Monitor)$" manage=off +yabai -m rule --add label="Finder" app="^Finder$" title="(Co(py|nnect)|Move|Info|Pref)" manage=off +yabai -m rule --add label="Safari" app="^Safari$" title="^(General|(Tab|Password|Website|Extension)s|AutoFill|Se(arch|curity)|Privacy|Advance)$" manage=off +yabai -m rule --add label="About This Mac" app="System Information" title="About This Mac" manage=off +yabai -m rule --add label="Select file to save to" app="^Inkscape$" title="Select file to save to" manage=off + +yabai -m config layout bsp + +echo "yabai configuration loaded..":qQ:q +#1682708615 +nvim +#1682708627 +nvim yabairc +#1682708670 +fish +#1682712011 +j Socia +#1682714306 +n 010 - Women +#1682714323 +ls -la +#1682714332 +r 24 +#1682714339 +r 4 +#1682714448 +n "010 - Canada Emerging Autonomy" +#1682893493 +~ +#1682893498 +.config +#1682893519 +nvim 4 +#1682893575 +nvim calendar.sh +#1682893607 +lf +#1682893779 +nvim 10 +#1682973972 +j Eng +#1683673327 +j Bible +#1683673393 +n "P03 - Consecration Notes.md" +#1683758231 +~ +#1683758233 +.config +#1684368577 +j Bible +#1684450455 +open 20 +#1684500183 +stats +#1684500209 +tips +#1684899268 +nvim 3 +#1685306423 +~ +#1685306489 +mpv 20 +#1685306922 +mpv 18 +#1685306945 +mpv 6 +#1685307380 +mpv 11 +#1686890148 +~ +#1686890170 +gpg --import 2 +#1686890368 +gpg --import 4 +#1686890495 +gpg --import 2 +#1687120864 +~ +#1687120866 +Down +#1687120882 +npm install -g gatsby-cli +#1687120889 +sudo npm install -g gatsby-cli +#1687120927 +npm install +#1688546303 +http-server . +#1688546367 +http-server +#1688985027 +npm install howler +#1688985032 +cd node_modules/ +#1688985215 +http-server +#1689008127 +mkdir Forte +#1689008135 +t 1 +#1689008147 +git clone 'https://github.com/kaangiray26/forte' +#1689008168 +npm run build +#1689008205 +brew install vite +#1689008344 +npm run build +#1689008354 +brew remove vite +#1689008360 +npm install vite +#1689008403 +npm run build +#1689008407 +npm help +#1689008413 +npm install +#1689008420 +fish +#1700142747 +~ +#1700142765 +ls +#1700142770 +ls -la +#1700142785 +fish +#1700263351 +../.. +#1700263373 +ffmpeg -i 46 jesus-strong-and-kind.wav +#1700541724 +mkdir Daniel\ Camporee +#1700541735 +ytmd 'https://www.youtube.com/watch?v=KdLD7XMhVE8&list=OLAK5uy_kyjcPYNwqyrpgsiPSfwE88IlLnJLWl3KA&index=4' +#1700716933 +~ +#1700716960 +fish +#1702946294 +~ +#1704306253 +hh +#1704306302 +t 1 +#1704306314 +t 2 +#1704306317 +t 4 +#1704306362 +t 3 +#1704306370 +t 1 +#1704306372 +v 1 +#1704306377 +nvim 1 +#1704306428 +t 2 3 +#1704306447 +t 2 +#1704306465 +./net_test +#1704306485 +hh +#1704306638 +t 3 +#1704306666 +t 4 +#1704306861 +t 5 +#1704308565 +hh diff --git a/.config/clifm/profiles/default/jump.clifm b/.config/clifm/profiles/default/jump.clifm new file mode 100644 index 0000000..3697ea1 --- /dev/null +++ b/.config/clifm/profiles/default/jump.clifm @@ -0,0 +1,46 @@ +1:1704306013:1704306013:/Users/asand/Music/StemRoller/Once Again (Finale) [bAO53Jhju2M]-156e91a2749716dd +1:1704306013:1704306013:/Users/asand/Music/StemRoller +1:1704306013:1704306013:/Users/asand/Music +1:1704306013:1704306013:/Users/asand/Documents/05 - Saved Content/000 - Music/1 - Audio/Daniel Camporee +1:1704306013:1704306013:/Users/asand/Documents/05 - Saved Content/000 - Music/1 - Audio +1:1704306013:1704306013:/Users/asand/Documents/05 - Saved Content/000 - Music +1:1704306013:1704306013:/Users/asand/Documents/05 - Saved Content +1:1704306013:1704306013:/Users/asand/Documents/05 - Saved Content/000 - YouTube +1:1704306013:1704306013:/Users/asand/Documents +1:1704306013:1704306013:/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website +1:1704306013:1704306013:/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs +1:1704306013:1704306013:/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website/node_modules +1:1704306013:1704306013:/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website/node_modules/howler +1:1704306013:1704306013:/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Website/node_modules/howler/dist +1:1704306013:1704306013:/Users/asand/Documents/01 - Projects/2 - Progress +1:1704306013:1704306013:/Users/asand/Downloads/fullstack-hy2020.github.io-source +1:1704306013:1704306013:/Users/asand/Downloads +1:1704306013:1704306013:/Users/asand/Documents/02 - Personal/00 - Me/09 - Keys +1:1704306013:1704306013:/Users/asand/Documents/02 - Personal/00 - Me +1:1704306013:1704306013:/Users/asand/Documents/02 - Personal +1:1704306013:1704306013:/Users/asand/.config/sketchybar/items +1:1704306013:1704306013:/Users/asand/.config/sketchybar +1:1704306013:1704306013:/Users/asand/Documents/02 - Personal/03 - Classes/Bible 10 +1:1704306013:1704306013:/Users/asand/.config/yabai +1:1704306013:1704306013:/Users/asand/.config +1:1704306013:1704306013:/Users/asand/Documents/02 - Personal/03 - Classes +1:1704306013:1704306013:/Users/asand/Documents/02 - Personal/03 - Classes/English 10 +1:1704306013:1704306013:/Users/asand/Documents/02 - Personal/03 - Classes/Socials 10 +3:1704306025:1704306815:/Users/asand/clone/dotfiles +1:1704306025:1704306025:/Users/asand/server +1:1704306025:1704306025:/Users/asand +1:1704306025:1704306025:/Users/asand/clone +1:1704306025:1704306025:/Users/asand/Documents/05 - Saved Content/000 - YouTube/004 Spoken Gospel +1:1704306025:1704306025:/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/forte/client +1:1704306025:1704306025:/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/forte +1:1704306025:1704306025:/Users/asand/Documents/01 - Projects/2 - Progress/023 - Scripture Songs/Forte +1:1704306025:1704306025:/Users/asand/Documents/01 - Projects +2:1704306481:1704306488:/Users/asand/clone/dotfiles/scripts +1:1704306481:1704306481:/Users/asand/clone/dotfiles/.local +1:1704306481:1704306481:/Users/asand/clone/dotfiles/.local/share +1:1704306481:1704306481:/Users/asand/clone/dotfiles/.local/share/gnome-shell +1:1704306481:1704306481:/Users/asand/clone/dotfiles/.local/share/applications +1:1704306481:1704306481:/Users/asand/clone/dotfiles/.git +2:1704306481:1704308569:/Users/asand/clone/dotfiles/.config +1:1704306481:1704306481:/Users/asand/server/matrix-docker-ansible-deploy +@39500 diff --git a/.config/clifm/profiles/default/mimelist.clifm b/.config/clifm/profiles/default/mimelist.clifm new file mode 100644 index 0000000..147cb6d --- /dev/null +++ b/.config/clifm/profiles/default/mimelist.clifm @@ -0,0 +1,138 @@ + ################################### + # Configuration file for Lira # + # CliFM's resource opener # + ################################### + +# Commented and blank lines are omitted + +# The below settings cover the most common filetypes +# It is recommended to edit this file placing your prefered applications +# at the beginning of the apps list to speed up the opening process + +# The file is read top to bottom and left to right; the first existent +# application found will be used + +# Applications defined here are NOT desktop files, but commands (arguments +# could be used as well). Bear in mind that these commands will be executed +# directly without shell intervention, so that no shell goodies (like pipes, +# conditions, loops, etc) are available. In case you need something more +# complex than a single command (including shell capabilities) write your +# own script and place the path to the script in place of the command. +# For example: X:^text/.*:~/scripts/my_cool_script.sh + +# Applications defined here are NOT desktop files, but commands (arguments +# could be used as well). Write you own handmade scripts to open specific +# files if necessary. Ex: X:^text/.*:~/scripts/my_cool_script.sh + +# Use 'X' to specify a GUI environment and '!X' for non-GUI environments, +# like the kernel built-in console or a remote SSH session. + +# Use 'N' to match file names instead of MIME types. + +# Regular expressions are allowed for both file types and file names. + +# Use the %f placeholder to specify the position of the file name to be +# opened in the command. Example: +# 'mpv %f --terminal=no' -> 'mpv FILE --terminal=no' +# If %f is not specified, the file name will be added to the end of the +# command. Ex: 'mpv --terminal=no' -> 'mpv --terminal=no FILE' + +# Running the opening application in the background: +# For GUI applications: +# APP %f & +# For terminal applications: +# TERM -e APP %f & +# Replace 'TERM' and 'APP' by the corresponding values. The -e option +# might vary depending on the terminal emulator used (TERM) + +# Note on graphical applications: If the opening application is already +# running, the file will be opened, usually in a new tab, and CliFM won't +# wait for the file to be closed (because the procecss already returned). +# To avoid this, instruct the application to run a new instance. For example: +# geany -i, gedit -s, kate -n, pluma --new-window, and so on. + +# To silence STDERR and/or STDOUT use !E and !O respectivelly (they could +# be used together). Examples: +# Silence STDERR only and run in the foreground: +# mpv %f !E +# Silence both (STDERR and STDOUT) and run in the background: +# mpv %f !EO & +# or +# mpv %f !E !O & + +# Environment variables could be used as well. Example: +# X:text/plain=$EDITOR %f &;$VISUAL;nano;vi + +# Use Ranger's rifle (or whatever opener you prefer) to open all files +#.*=rifle + +########################### +# File names/extensions # +########################### + +# Match a full file name +#X:N:some_filename=cmd + +# Match all file names starting with 'str' +#X:N:^str.*=cmd + +# Match files with extension 'ext' +#X:N:.*\.ext$=cmd + +X:N:.*\.djvu$=djview;zathura;xreader;evince;atril +X:N:.*\.epub$=mupdf;zathura;xreader;ebook-viewer;FBReader;foliate +X:N:.*\.mobi$=ebook-viewer;FBReader;foliate +X:N:.*\.(cbr|cbz)$=mcomix;xreader;YACReader;qcomicbook;zathura;foliate +X:N:(.*\.clifm$|clifmrc)=$EDITOR;$VISUAL;kak;micro;nvim;vim;vi;mg;emacs;ed;nano;mili;leafpad;mousepad;featherpad;gedit -s;kate -n;pluma --new-window +!X:N:(.*\.clifm$|clifmrc)=$EDITOR;$VISUAL;kak;micro;nvim;vim;vi;mg;emacs;ed;nano + +################## +# MIME types # +################## + +# Directories - only for the open-with command (ow) and the --open command +# line option +# In graphical environments directories will be opened in a new window +X:inode/directory=xterm -e clifm %f &;xterm -e vifm %f &;pcmanfm %f &;thunar %f &;xterm -e ncdu %f & +!X:inode/directory=vifm;ranger;nnn;ncdu + +# Web content +X:^text/html$=$BROWSER;surf;vimprobable;vimprobable2;qutebrowser;dwb;jumanji;luakit;uzbl;uzbl-tabbed;uzbl-browser;uzbl-core;iceweasel;midori;opera;firefox;seamonkey;brave;chromium-browser;chromium;google-chrome;epiphany;konqueror;elinks;links2;links;lynx;w3m +!X:^text/html$=$BROWSER;elinks;links2;links;lynx;w3m + +# Text +#X:^text/x-(c|shellscript|perl|script.python|makefile|fortran|java-source|javascript|pascal)$=geany +X:^text/rtf$=libreoffice;soffice;ooffice +X:(^text/.*|application/json|inode/x-empty)=$EDITOR;$VISUAL;kak;micro;dte;nvim;vim;vi;mg;emacs;ed;nano;mili;leafpad;mousepad;featherpad;nedit;kate;gedit;pluma;io.elementary.code;liri-text;xed;atom;nota;gobby;kwrite;xedit +!X:(^text/.*|application/json|inode/x-empty)=$EDITOR;$VISUAL;kak;micro;dte;nvim;vim;vi;mg;emacs;ed;nano + +# Office documents +X:^application/.*(open|office)document.*=libreoffice;soffice;ooffice + +# Archives +# Note: 'ad' is CliFM's built-in archives utility (based on atool). Remove it if you +# prefer another application +X:^application/(zip|gzip|zstd|x-7z-compressed|x-xz|x-bzip*|x-tar|x-iso9660-image)=ad;xarchiver %f &;lxqt-archiver %f &;ark %f & +!X:^application/(zip|gzip|zstd|x-7z-compressed|x-xz|x-bzip*|x-tar|x-iso9660-image)=ad + +# PDF +X:.*/pdf$=mupdf;sioyek;llpp;lpdf;zathura;mupdf-x11;apvlv;xpdf;xreader;evince;atril;okular;epdfview;qpdfview + +# Images +X:^image/gif$=animate;pqiv;sxiv -a;nsxiv -a +X:^image/svg=display;inkscape +X:^image/.*=sxiv;nsxiv;pqiv;gpicview;qview;qimgv;mirage;ristretto;eog;eom;xviewer;viewnior;nomacs;geeqie;gwenview;gthumb;gimp +!X:^image/.*=fim;img2txt;cacaview;fbi;fbv + +# Video and audio +X:^video/.*=ffplay;mplayer;mplayer2;mpv;vlc;gmplayer;smplayer;celluloid;qmplayer2;haruna;totem +X:^audio/.*=ffplay -nodisp -autoexit;mplayer;mplayer2;mpv;vlc;gmplayer;smplayer;totem + +# Fonts +X:^font/.*=fontforge;fontpreview + +# Torrent: +X:application/x-bittorrent=rtorrent;transimission-gtk;transmission-qt;deluge-gtk;ktorrent + +# Fallback to another resource opener as last resource +.*=xdg-open;mimeo;mimeopen -n;whippet -m;open;linopen; diff --git a/.local/share/gnome-shell/gnome-overrides-migrated b/.config/clifm/profiles/default/msglogs.clifm similarity index 100% rename from .local/share/gnome-shell/gnome-overrides-migrated rename to .config/clifm/profiles/default/msglogs.clifm diff --git a/.config/clifm/profiles/default/nets.clifm b/.config/clifm/profiles/default/nets.clifm new file mode 100644 index 0000000..270e431 --- /dev/null +++ b/.config/clifm/profiles/default/nets.clifm @@ -0,0 +1,62 @@ +##################################### +# Remotes management file for CliFM # +##################################### + +# Blank and commented lines are omitted + +# The syntax is as follows: + +# A name for this remote. It will be used by the 'net' command +# and will be available for TAB completion +#[work_smb] + +# Comment=My work samba server +#Mountpoint=/home/user/.config/clifm/mounts/work_smb + +# Use %m as a placeholder for Mountpoint +#MountCmd=mount.cifs //WORK_IP/shared %m -o OPTIONS +#UnmountCmd=umount %m + +# Automatically mount this remote at startup +#AutoMount=true + +# Automatically unmount this remote at exit +#AutoUnmount=true + +# A few examples + +# A. Samba share +#[samba_share] +#Comment=my samba share +#Mountpoint="~/.config/clifm/mounts/samba_share" +#MountCmd=sudo mount.cifs //192.168.0.26/resource_name %m -o mapchars,credentials=/etc/samba/credentials/samba_share +#UnmountCmd=sudo umount %m +#AutoUnmount=false +#AutoMount=false + +# B. SSH file system (sshfs) +#[my_ssh] +#Comment=my ssh +#Mountpoint="/media/ssh" +#MountCmd=sshfs user@192.168.0.12: %m -C -p 22 +#UnmountCmd=fusermount3 -u %m +#AutoUnmount=false +#AutoMount=false + +# C. Mounting a local file system +#[local] +#Comment=Local filesystem +#Mountpoint="/media/extra" +#MountCmd=sudo mount -U 1232dsd761278... %m +#UnmountCmd=sudo umount %m +#AutoUnmount=false +#AutoMount=true + +# D. Mounting a removable device +#[USB] +#Comment=My USB drive +#Mountpoint="/media/usb" +#MountCmd=sudo mount -o gid=1000,fmask=113,dmask=002 -U 5647-1... %m +#UnmountCmd=sudo umount %m +#AutoUnmount=true +#AutoMount=false diff --git a/.config/clifm/profiles/default/preview.clifm b/.config/clifm/profiles/default/preview.clifm new file mode 100644 index 0000000..2580371 --- /dev/null +++ b/.config/clifm/profiles/default/preview.clifm @@ -0,0 +1,57 @@ + ###################################### + # Configuration file for Shotgun # + # CliFM's file previewer # + ###################################### + +# Commented and blank lines are omitted + +# It is recommended to edit this file setting your preferred applications +# first: the previewing process will be smoother and faster this way +# You can even remove whatever applications you don't use + +# For syntax details consult the mimelist.clifm file + +# Uncomment this line to use pistol (or any other previewing program) +#.*=pistol + +# Uncomment and edit this line to use Ranger's scope script: +#.*=/home/USER/.config/ranger/scope.sh %f 120 80 /tmp/clifm/ True + +# Directories +inode/directory=exa -a --tree --level=1 --;lsd -A --tree --depth=1 --color=always;tree -a -L 1;ls -Ap --color=always --indicator-style=none; + +# Web content +^text/html$=w3m -dump;lynx -dump --;elinks -dump;pandoc -s -t markdown --; + +# Text +^text/rtf=catdoc --; +N:.*\.json$=jq --color-output . ;python -m json.tool --; +N:.*\.md$=glow -s dark --;mdcat --; +^text/.*=highlight -f --out-format=xterm256 --force --;bat --style=plain --color=always --;cat --; + +# Office documents +N:.*\.xlsx$=xlsx2csv --;file -b --; +N:.*\.(odt|ods|odp|sxw)$=odt2txt;pandoc -s -t markdown --; +^application/(.*wordprocessingml.document|.*epub+zip|x-fictionbook+xml)=pandoc -s -t markdown --; +^application/msword=catdoc --;file -b --; +^application/ms-excel=xls2csv --;file -b --; + +# Archives +N:.*\.rar=unrar lt -p- --; +application/zstd=file -b --;true +application/(zip|gzip|x-7z-compressed|x-xz|x-bzip*|x-tar)=atool --list --;bsdtar --list --file; + +# PDF +^application/pdf$=pdftotext -l 10 -nopgbrk -q -- %f -;mutool draw -F txt -i --;exiftool; + +# Image, video, and audio +^image/vnd.djvu=djvutxt;exiftool; +^image/.*=exiftool; +^video/.*=mediainfo;exiftool; +^audio/.*=mediainfo;exiftool; + +# Torrent: +application/x-bittorrent=transmission-show --; + +# Fallback +.*=file -b --;true; diff --git a/.config/clifm/profiles/default/profile.clifm b/.config/clifm/profiles/default/profile.clifm new file mode 100644 index 0000000..95b34a7 --- /dev/null +++ b/.config/clifm/profiles/default/profile.clifm @@ -0,0 +1,9 @@ +# This is CliFM's profile file +# +# Write here the commands you want to be executed at startup +# Ex: +#echo "CliFM, the command line file manager"; read -r +# +# Uncommented, non-empty lines are executed line by line. If you +# want a multi-line command, just write a script for it: +#sh /path/to/my/script.sh diff --git a/.config/clifm/prompts.clifm b/.config/clifm/prompts.clifm new file mode 100644 index 0000000..4105633 --- /dev/null +++ b/.config/clifm/prompts.clifm @@ -0,0 +1,170 @@ +# This file is part of CliFM + +# Prompts for CliFM + +# Do not edit this file directly: use the 'prompt' command instead + +# The regular prompt (just as the warning one, a secondary prompt used +# to highlight invalid/non-existent command names) is built using command +# substitution ($(cmd)), string literals and/or one or more of the +# following escape sequences: + +# The prompt line is build using command substitution ($(cmd)), string +# literals and/or the following escape sequences: +# +# \e: Escape character +# \u: The username +# \H: The full hostname +# \h: The hostname, up to the first dot (.) +# \s: The name of the shell (everything after the last slash) currently +# used by CliFM +# \S: Current workspace number (colored according to wsx code in the color +# scheme file) +# \l: Print an L if running in light mode +# \P: The current profile name +# \n: A newline character +# \r: A carriage return +# \a: A bell character +# \d: The date, in abbreviated form (ex: Tue May 26) +# \t: The time, in 24-hour HH:MM:SS format +# \T: The time, in 12-hour HH:MM:SS format +# \@: The time, in 12-hour am/pm format +# \A: The time, in 24-hour HH:MM format +# \w: The full current working directory, with $HOME abbreviated with a +# tilde +# \W: The basename of $PWD, with $HOME abbreviated with a tilde +# \p: A mix of the two above, it abbreviates the current working directory +# only if longer than PathMax (a value defined in the configuration +# file). +# \z: Exit code of the last executed command (printed in green in case of +# success and in bold red in case of error) +# \$: #, if the effective user ID is 0 (root), and $ otherwise +# \nnn: The character whose ASCII code is the octal value nnn +# \\: A literal backslash +# \[: Begin a sequence of non-printing characters. This is mostly used to +# add color to the prompt line (using full ANSI escape sequences) +# \]: End a sequence of non-printing characters +# +# The following files statistics escape sequences are available as well: +# +# \D: Amount of sub-directories in the current directory +# \R: Amount of regular files in the current directory +# \X: Amount of executable files in the current directory +# \.: Amount of hidden files in the current directory +# \U: Amount of SUID files in the current directory +# \G: Amount of SGID files in the current directory +# \F: Amount of FIFO/pipe files in the current directory +# \K: Amount of socket files in the current directory +# \B: Amount of block device files in the current directory +# \C: Amount of character device files in the current directory +# \x: Amount of files with capabilities in the current directory +# \L: Amount of symbolic links in the current directory +# \o: Amount of broken symbolic links in the current directory +# \M: Amount of multi-link files in the current directory +# \E: Amount of files with extended attributes in the current directory +# \O: Amount of other-writable files in the current directory +# \": Amount of files with the sticky bit set in the current directory +# \?: Amount of files of unknown file type in the current directory +# \!: Amount of unstatable files in the current directory + +# Escape codes to control prompt notifications: +# +# \*: An asterisk + amount of selected files (e.g. *12) +# \%: 'T' + amount of trashed files (e.g. T3) +# \#: Print an 'R' if running as root +# \(: 'E' + amount of error messages (e.g. E2) +# \): 'W' + amount of warning messages (e.g. W2) +# \=: 'N' + amount of notice messages (e.g. N1) +# +# NOTE: Except in the case of \#, nothing is printed if the corresponding +# number is zero (no selected files, no trashed files, and so on) + +# Unicode characters could be inserted by directly pasting the +# corresponding char, or by inserting its hex code: +# echo -ne "paste_your_char" | hexdump -C + +# Set Notifications to false to prevent the automatic insertion of +# root, trash, messages (error, warning, and notice), and selected files +# indicators at the left of the prompt, in which case the prompt code +# should handle itself this data using the appropriate escape codes + +# To permanetly set any of the below prompts edit your color scheme file +# (via the 'cs edit' command), set Prompt to either the prompt code or +# the prompt name you want (e.g. Prompt="classic"), and comment out the +# remaining prompt lines +# +# NOTE: Since the below prompts have been designed for CliFM's default +# color scheme, you might need to edit the one you choose manually to +# make it fit your current color scheme. For example, the last color +# used in the warning prompt should match the 'wp' color defined in your +# color scheme file + +[clifm] +Notifications=true +RegularPrompt="\[\e[0m\][\[\e[0;36m\]\S\[\e[0m\]]\l \A \u:\H \[\e[0;36m\]\w\n\[\e[0m\]<\z\[\e[0m\]> \[\e[0;34m\]\$ \[\e[0m\]" +EnableWarningPrompt=true +WarningPrompt="\[\e[00;02;31m\](!) > " + +#[clifm-colorless] +#Notifications=true +#RegularPrompt="\[\e[0m\][\S]\l \A \u:\H \w\n<\z\[\e[0m\]> \$ " +#EnableWarningPrompt=true +#WarningPrompt="(!) > " + +[clifm-box-drawing] +# The box drawing set isn't supported by all terminals +Notifications=false +RegularPrompt="\[\e[0m\]\[\e[0;36m\]\[\e(0\]lq\[\e(B\]\[\e[0;31m\]\#\[\e[32m\]\*\[\e[36m\]\%\[\e[31m\]\(\[\e[33m\]\)\[\e[32m\]\=\[\e[0m\][\S\[\e[0m\]]\l \A \u:\H \[\e[0;36m\]\w\n\[\e[0;36m\]\[\e(0\]mq\[\e(B\]\[\e[0m\]<\z\[\e[0m\]> \[\e[0;34m\]\$ \[\e[0m\]" +EnableWarningPrompt=true +WarningPrompt="\[\e[0;36m\]\[\e(0\]mq\[\e(B\]\[\e[0m\]<\z\[\e[0m\]> \[\e[1;31m\]\! \[\e[00;02;31m\]" + +[classic] +Notifications=true +RegularPrompt="\[\e[1;32m\][\u@\H] \[\e[1;34m\]\w \[\e[0m\]\$ " +EnableWarningPrompt=true +WarningPrompt="\[\e[1;32m\][\u@\H] \[\e[1;34m\]\w \[\e[1;31m\]! \[\e[00;02;31m\]" + +[security-scanner] +# Print file statistics about the current directory (-:-:-:-) in this order: +# SUID, SGID, other-writable, and executable files +Notifications=true +RegularPrompt="\[\e[0m\][\[\e[0;36m\]\S\[\e[0m\]]\l \[\e[0m\]\[\e[1;31m\]\U\[\e[0m\]:\[\e[1;33m\]\G\[\e[0m\]:\[\e[1;34m\]\O\[\e[0m\]:\[\e[1;32m\]\X\[\e[0m\] \A \[\e[0;36m\]\w\n\[\e[0m\]<\z\[\e[0m\]> \[\e[0;34m\]\$ \[\e[0m\]" +EnableWarningPrompt=true +WarningPrompt="\[\e[00;02;31m\](!) > " + +[curves] +Notifications=false +RegularPrompt="\[\e[00;01;32m\]╭─\[\e[0m\]\[\e[1;32m\]\*\[\e[1;36m\]\%\[\e[1;31m\]\(\[\e[1;33m\]\)\[\e[1;32m\]\=\[\e[0m\][\S\[\e[0m\]]\[\e[01;32m\]─\[\e[0m\](\u:\H)\[\e[01;32m\]─\[\e[0m\][\[\e[00;36m\]\w\[\e[0m\]]\n\[\e[01;32m\]╰─\[\e[1;0m\]<\z\[\e[0m\]> \[\e[34m\]λ\[\e[0m\] " +EnableWarningPrompt=true +WarningPrompt="\[\e[0m\]\[\e[01;32m\]╰─\[\e[1;0m\]<\z\[\e[0m\]> \[\e[0;31m\]λ\[\e[00;02;31m\] " + +# The prompts below require a patched Nerdfont +[firestarter] +Notifications=false +RegularPrompt="\[\e[01;38;5;124m\]╭─\[\e[38;5;124m\]\[\e[37;48;5;124m\]\[\e[1;37m\]\#\[\e[32m\]\*\[\e[36m\]\%\[\e[37m\]\(\[\e[33m\]\)\[\e[32m\]\=\[\e[00;37;48;5;124m\][\S\[\e[37;48;5;124m\]] \[\e[0;48;5;124m\]\A \[\e[00;38;5;124;43m\]\[\e[00;30;43m\] \u:\H \[\e[00;33;48;5;124m\]\[\e[00;37;48;5;124m\] \w \[\e[00;38;5;124m\]\[\e[0m\]\n\[\e[01;38;5;124m\]╰─▶ \[\e[0m\]" +EnableWarningPrompt=true +WarningPrompt="\[\e[00;01;38;5;124m\]╰─\[\e[0;38;5;124m\]▶ \[\e[00;02;31m\]" + +[cold-winter] +Notifications=false +RegularPrompt="\[\e[00;37;100m\]\[\e[1;31m\]\#\[\e[32m\]\*\[\e[36m\]\%\[\e[31m\]\(\[\e[33m\]\)\[\e[32m\]\=\[\e[0;37;100m\][\S\[\e[00;37;100m\]] \A \[\e[00;90;46m\] \[\e[0;30;46m\]\u:\H \[\e[0;36;100m\] \[\e[00;37;100m\]\w \[\e[00;90;40m\] \n \[\e[1;90m\]\[\e[0m\] " +EnableWarningPrompt=true +WarningPrompt=" \[\e[0m\]\[\e[1;2;31m\] \[\e[00;02;31m\]" + +[spot] +Notifications=false +RegularPrompt="\[\e[00;38;5;0;48;5;53m\] \[\e[31m\]\#\[\e[32m\]\*\[\e[36m\]\%\[\e[31m\]\(\[\e[34m\]\)\[\e[32m\]\=\[\e[00;37;48;5;53m\][\S\[\e[37m\]] \[\e[38;5;53;48;5;178m\] \[\e[00;38;5;0;48;5;178m\]\A \u:\H \w \[\e[00;38;5;178;48;5;0m\]\[\e[0;40m\]\n\[\e[0;38;5;254;48;5;53m\] \$ \[\e[0;38;5;53;48;5;0m\] \[\e[0m\] " +EnableWarningPrompt=true +WarningPrompt="\n\[\e[0;37;48;5;124m\] \x \[\e[0;38;5;124;48;5;0m\] \[\e[00;02;31m\] " + +[artic-particles] +Notifications=false +RegularPrompt="\[\e[00;37;48;5;18m\] \A \[\e[00;38;5;18;47m\] \u:\H \[\e[00;37;48;5;18m\] \w \[\e[00;38;5;18;40m\] \n\[\e[00;37;48;5;18m\] \$ \[\e[00;38;5;18;40m\] " +EnableWarningPrompt=true +WarningPrompt="\[\e[00;02;31;47m\] \$ \[\e[00;37;0m\] \[\e[00;02;31m\]" + +[green-beret] +Notifications=false +RegularPrompt="╭─\[\e[0;38;5;239;48;5;0m\]\[\e[0;38;5;15;48;5;239m\]\[\e[31m\]\#\[\e[38;5;76m\]\*\[\e[36m\]\%\[\e[31m\]\(\[\e[33m\]\)\[\e[32m\]\=\[\e[38;5;15m\][\S\[\e[38;5;15m\]]  \A \[\e[0;38;5;239;48;5;70m\]\[\e[0;38;5;0;48;5;70m\] \w \[\e[0;38;5;70;48;5;0m\]\n\[\e[0;40m\]╰─\[\e[0;38;5;70;48;5;0m\]▶\[\e[0;40m\] " +EnableWarningPrompt=true +WarningPrompt="\[\e[0;40m\]╰─\[\e[0;38;5;9;48;5;0m\]▶ \[\e[00;02;31m\]" diff --git a/.config/clifm/readline.clifm b/.config/clifm/readline.clifm new file mode 100644 index 0000000..adfee33 --- /dev/null +++ b/.config/clifm/readline.clifm @@ -0,0 +1,77 @@ +# Readline keybindings for CliFM + +# For the complete list of Readline options see: +# https://www.gnu.org/software/bash/manual/html_node/Readline-Init-File-Syntax.html#Readline-Init-File-Syntax + +#$include /etc/inputrc + +# Color files by types +set colored-stats on +# Append char to indicate type +set visible-stats on +# Mark symlinked directories +set mark-symlinked-directories on +# Color the common prefix +set colored-completion-prefix on +# Color the common prefix in menu-complete +set menu-complete-display-prefix on +# Disable paste protection +set enable-bracketed-paste on + +set show-all-if-ambiguous on +set completion-ignore-case on + +set meta-flag on +set input-meta on +set output-meta on + +$if mode=emacs + +# For linux console and RH/Debian xterm +"\e[5C": forward-word +"\e[5D": backward-word +"\e\e[C": forward-word +"\e\e[D": backward-word +"\e[1;5C": forward-word +"\e[1;5D": backward-word + +# For rxvt +"\x1b\x4f\x64": backward-word +"\x1b\x4f\x63": forward-word + +# A few keybinds to avoid conflicts with CliFM specific keybinds +"\C-d": +"\e\e": +"\C-r\C-r": re-read-init-file +"\C-zA": do-lowercase-version +"\C-zB": do-lowercase-version +"\C-zC": do-lowercase-version +"\C-zD": do-lowercase-version +"\C-zE": do-lowercase-version +"\C-zF": do-lowercase-version +"\C-zG": do-lowercase-version +"\C-zH": do-lowercase-version +"\C-zI": do-lowercase-version +"\C-zJ": do-lowercase-version +"\C-zK": do-lowercase-version +"\C-zL": do-lowercase-version +"\C-zM": do-lowercase-version +"\C-zN": do-lowercase-version +"\C-zO": do-lowercase-version +"\C-zP": do-lowercase-version +"\C-zQ": do-lowercase-version +"\C-zR": do-lowercase-version +"\C-zS": do-lowercase-version +"\C-zT": do-lowercase-version +"\C-zU": do-lowercase-version +"\C-zV": do-lowercase-version +"\C-zW": do-lowercase-version +"\C-zX": do-lowercase-version +"\C-zY": do-lowercase-version +"\C-zZ": do-lowercase-version + +# History completion based on prefix +#"\e[A": history-search-backward +#"\e[B": history-search-forward + +$endif diff --git a/.config/dconf/user b/.config/dconf/user deleted file mode 100644 index 4a5c58e..0000000 Binary files a/.config/dconf/user and /dev/null differ diff --git a/.config/electron-flags.conf b/.config/electron-flags.conf deleted file mode 120000 index f3609ca..0000000 --- a/.config/electron-flags.conf +++ /dev/null @@ -1 +0,0 @@ -brave-flags.conf \ No newline at end of file diff --git a/.config/fish/config.fish b/.config/fish/config.fish index 0b95c8a..cb67840 100644 --- a/.config/fish/config.fish +++ b/.config/fish/config.fish @@ -1,10 +1,8 @@ -# MacOS -# export PATH=$HOME/Library/Python/3.8/bin:/opt/homebrew/bin:/usr/local/bin:/usr/local/sbin:$HOME/bin:/usr/local/git/bin:$PATH -alias l="exa" -alias v="nvim" -cowspeak -bbl=o -f=/usr/share/cowspeak/arts/cow.art -t="$(quote)" -set ANSIBLE_NOCOWS 1 if status is-interactive # Commands to run in interactive sessions can go here - end + +fish_add_path /Users/asand/.cargo/bin +fish_add_path /Users/asand/scripts +alias v=nvim +alias c=clifm diff --git a/.config/fish/fish_variables b/.config/fish/fish_variables index 2559813..dc46d90 100644 --- a/.config/fish/fish_variables +++ b/.config/fish/fish_variables @@ -2,7 +2,7 @@ # VERSION: 3.0 SETUVAR __fish_initialized:3400 SETUVAR fish_color_autosuggestion:4c566a -SETUVAR fish_color_cancel:\x2dr +SETUVAR fish_color_cancel:\x2d\x2dreverse SETUVAR fish_color_command:81a1c1 SETUVAR fish_color_comment:434c5e SETUVAR fish_color_cwd:green @@ -12,10 +12,12 @@ SETUVAR fish_color_error:ebcb8b SETUVAR fish_color_escape:00a6b2 SETUVAR fish_color_history_current:\x2d\x2dbold SETUVAR fish_color_host:normal -SETUVAR fish_color_host_remote:yellow +SETUVAR fish_color_host_remote:\x1d +SETUVAR fish_color_keyword:\x1d SETUVAR fish_color_match:\x2d\x2dbackground\x3dbrblue SETUVAR fish_color_normal:normal SETUVAR fish_color_operator:00a6b2 +SETUVAR fish_color_option:\x1d SETUVAR fish_color_param:eceff4 SETUVAR fish_color_quote:a3be8c SETUVAR fish_color_redirection:b48ead @@ -26,8 +28,17 @@ SETUVAR fish_color_user:brgreen SETUVAR fish_color_valid_path:\x2d\x2dunderline SETUVAR fish_greeting:\x1d SETUVAR fish_key_bindings:fish_default_key_bindings +SETUVAR fish_pager_color_background:\x1d SETUVAR fish_pager_color_completion:normal -SETUVAR fish_pager_color_description:B3A06D\x1eyellow +SETUVAR fish_pager_color_description:B3A06D SETUVAR fish_pager_color_prefix:normal\x1e\x2d\x2dbold\x1e\x2d\x2dunderline SETUVAR fish_pager_color_progress:brwhite\x1e\x2d\x2dbackground\x3dcyan -SETUVAR fish_pager_color_selected_background:\x2dr +SETUVAR fish_pager_color_secondary_background:\x1d +SETUVAR fish_pager_color_secondary_completion:\x1d +SETUVAR fish_pager_color_secondary_description:\x1d +SETUVAR fish_pager_color_secondary_prefix:\x1d +SETUVAR fish_pager_color_selected_background:\x2d\x2dbackground\x3dbrblack +SETUVAR fish_pager_color_selected_completion:\x1d +SETUVAR fish_pager_color_selected_description:\x1d +SETUVAR fish_pager_color_selected_prefix:\x1d +SETUVAR fish_user_paths:/Users/asand/\x2ecargo/bin\x1e/Users/asand/scripts diff --git a/.config/fish/functions/fish_prompt.fish b/.config/fish/functions/fish_prompt.fish index db84658..b7d38e6 100644 --- a/.config/fish/functions/fish_prompt.fish +++ b/.config/fish/functions/fish_prompt.fish @@ -60,7 +60,7 @@ function fish_prompt set_color -o white echo -n @ - if [ -z "$SSH_CLIENT" ] + if test -z "$SSH_CLIENT" set_color -o blue else set_color -o cyan @@ -115,7 +115,7 @@ function fish_prompt # Battery status type -q acpi and test (acpi -a 2> /dev/null | string match -r off) - and _nim_prompt_wrapper $retc B (acpi -b | cut -d' ' -f 4- | tail -n 1) + and _nim_prompt_wrapper $retc B (acpi -b | cut -d' ' -f 4-) # New line echo diff --git a/.config/inkscape/cphistory.xml b/.config/inkscape/cphistory.xml deleted file mode 100644 index cd91a84..0000000 --- a/.config/inkscape/cphistory.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/.config/inkscape/dialogs-state.ini b/.config/inkscape/dialogs-state.ini deleted file mode 100644 index aeb1f70..0000000 --- a/.config/inkscape/dialogs-state.ini +++ /dev/null @@ -1,21 +0,0 @@ -[Windows] -Count=1 - -[Window0Column0] -Notebook0Dialogs=216;210;209; -Notebook1Dialogs=230; -NotebookCount=2 -BeforeCanvas=false - -[Window0] -ColumnCount=1 -Floating=false - -[transient] -state1=[Windows]\nCount=1\n\n[Window0Column0]\nNotebook0Dialogs=208;\nNotebookCount=1\n\n[Window0]\nColumnCount=1\nPosition=true\nx=45\ny=29\nwidth=924\nheight=765\n -dialogs1=208; -state2=[Windows]\nCount=1\n\n[Window0Column0]\nNotebook0Dialogs=233;\nNotebookCount=1\n\n[Window0]\nColumnCount=1\nPosition=true\nx=45\ny=29\nwidth=364\nheight=520\n -dialogs2=233; -state3=[Windows]\nCount=1\n\n[Window0Column0]\nNotebook0Dialogs=236;\nNotebookCount=1\n\n[Window0]\nColumnCount=1\nPosition=true\nx=45\ny=29\nwidth=433\nheight=520\n -dialogs3=236; -count=3 diff --git a/.config/inkscape/extension-errors.log b/.config/inkscape/extension-errors.log deleted file mode 100644 index 6781d46..0000000 --- a/.config/inkscape/extension-errors.log +++ /dev/null @@ -1,12 +0,0 @@ -Extension "XFIG Input" failed to load because a dependency was not met. -Dependency: - type: executable - location: path - string: fig2dev - -Extension "Export to PDF via Scribus" failed to load because a dependency was not met. -Dependency: - type: executable - location: path - string: scribus - diff --git a/.config/inkscape/keys/default.xml b/.config/inkscape/keys/default.xml deleted file mode 100644 index 17ac8ab..0000000 --- a/.config/inkscape/keys/default.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - diff --git a/.config/inkscape/pages.csv b/.config/inkscape/pages.csv deleted file mode 100644 index 8860ee5..0000000 --- a/.config/inkscape/pages.csv +++ /dev/null @@ -1,77 +0,0 @@ -#Inkscape page sizes -#NAME, WIDTH, HEIGHT, UNIT -A4, 210, 297, mm -US Letter, 8.5, 11, in -US Legal, 8.5, 14, in -US Executive, 7.25, 10.5, in -US Ledger/Tabloid, 11, 17, in -A0, 841, 1189, mm -A1, 594, 841, mm -A2, 420, 594, mm -A3, 297, 420, mm -A5, 148, 210, mm -A6, 105, 148, mm -A7, 74, 105, mm -A8, 52, 74, mm -A9, 37, 52, mm -A10, 26, 37, mm -B0, 1000, 1414, mm -B1, 707, 1000, mm -B2, 500, 707, mm -B3, 353, 500, mm -B4, 250, 353, mm -B5, 176, 250, mm -B6, 125, 176, mm -B7, 88, 125, mm -B8, 62, 88, mm -B9, 44, 62, mm -B10, 31, 44, mm -C0, 917, 1297, mm -C1, 648, 917, mm -C2, 458, 648, mm -C3, 324, 458, mm -C4, 229, 324, mm -C5, 162, 229, mm -C6, 114, 162, mm -C7, 81, 114, mm -C8, 57, 81, mm -C9, 40, 57, mm -C10, 28, 40, mm -D1, 545, 771, mm -D2, 385, 545, mm -D3, 272, 385, mm -D4, 192, 272, mm -D5, 136, 192, mm -D6, 96, 136, mm -D7, 68, 96, mm -E3, 400, 560, mm -E4, 280, 400, mm -E5, 200, 280, mm -E6, 140, 200, mm -CSE, 462, 649, pt -US #10 Envelope, 9.5, 4.125, in -DL Envelope, 220, 110, mm -Banner 468x60, 468, 60, px -Icon 16x16, 16, 16, px -Icon 32x32, 32, 32, px -Icon 48x48, 48, 48, px -ID Card (ISO 7810), 85.60, 53.98, mm -Business Card (US), 3.5, 2, in -Business Card (Europe), 85, 55, mm -Business Card (AU/NZ), 90, 55, mm -Arch A, 9, 12, in -Arch B, 12, 18, in -Arch C, 18, 24, in -Arch D, 24, 36, in -Arch E, 36, 48, in -Arch E1, 30, 42, in -Video SD / PAL, 768, 576, px -Video SD-Widescreen / PAL, 1024, 576, px -Video SD / NTSC, 544, 480, px -Video SD-Widescreen / NTSC, 872, 486, px -Video HD 720p, 1280, 720, px -Video HD 1080p, 1920, 1080, px -Video DCI 2k (Full Frame), 2048, 1080, px -Video UHD 4k, 3840, 2160, px -Video DCI 4k (Full Frame), 4096, 2160, px -Video UHD 8k, 7680, 4320, px diff --git a/.config/inkscape/preferences.xml b/.config/inkscape/preferences.xml deleted file mode 100644 index 963c291..0000000 --- a/.config/inkscape/preferences.xml +++ /dev/null @@ -1,1112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.config/mpv/mpv.conf b/.config/mpv/mpv.conf new file mode 100644 index 0000000..ff66aed --- /dev/null +++ b/.config/mpv/mpv.conf @@ -0,0 +1 @@ +save-position-on-quit diff --git a/.config/pop-shell/config.json b/.config/pop-shell/config.json deleted file mode 100644 index 8c23b67..0000000 --- a/.config/pop-shell/config.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "float": [ - { - "class": "pop-shell-example", - "title": "pop-shell-example" - }, - { - "class": "albert", - "title": "albert — Albert" - }, - { - "class": "wofi", - "title": "drun" - }, - { - "class": "VirtualBox Manager" - }, - { - "class": "obs", - "title": "Windowed Projector (Preview)" - }, - { - "class": "X32-Edit" - }, - { - "class": "pensela" - }, - { - "class": "lmms" - }, - { - "class": "wofi" - }, - { - "class": "wofi", - "title": "dmenu" - } - ], - "skiptaskbarhidden": [], - "log_on_focus": false, - "move_pointer_on_switch": false, - "default_pointer_position": "TOP_LEFT" -} \ No newline at end of file diff --git a/.config/sketchybar/colors.sh b/.config/sketchybar/colors.sh new file mode 100755 index 0000000..d991924 --- /dev/null +++ b/.config/sketchybar/colors.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Color Palette +export BLACK=0xff181926 +export WHITE=0xffcad3f5 +export RED=0xffed8796 +export GREEN=0xffa6da95 +export BLUE=0xff8aadf4 +export YELLOW=0xffeed49f +export ORANGE=0xfff5a97f +export MAGENTA=0xffc6a0f6 +export GREY=0xff939ab7 +export TRANSPARENT=0x00000000 + +# General bar colors +export BAR_COLOR=0xff1e1e2e +export BAR_BORDER_COLOR=0xff494d64 #0xa024273a +export ICON_COLOR=$WHITE # Color of all icons +export LABEL_COLOR=$WHITE # Color of all labels +export BACKGROUND_1=0x603c3e4f +export BACKGROUND_2=0x60494d64 + +export POPUP_BACKGROUND_COLOR=0xff1e1e2e +export POPUP_BORDER_COLOR=$WHITE + +export SHADOW_COLOR=$BLACK diff --git a/.config/sketchybar/helper/cpu.h b/.config/sketchybar/helper/cpu.h new file mode 100644 index 0000000..c350ae3 --- /dev/null +++ b/.config/sketchybar/helper/cpu.h @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include + +#define MAX_TOPPROC_LEN 28 + +static const char TOPPROC[] = { "/bin/ps -Aceo pid,pcpu,comm -r" }; +static const char FILTER_PATTERN[] = { "com.apple." }; + +struct cpu { + host_t host; + mach_msg_type_number_t count; + host_cpu_load_info_data_t load; + host_cpu_load_info_data_t prev_load; + bool has_prev_load; + + char command[256]; +}; + +static inline void cpu_init(struct cpu* cpu) { + cpu->host = mach_host_self(); + cpu->count = HOST_CPU_LOAD_INFO_COUNT; + cpu->has_prev_load = false; + snprintf(cpu->command, 100, ""); +} + +static inline void cpu_update(struct cpu* cpu) { + kern_return_t error = host_statistics(cpu->host, + HOST_CPU_LOAD_INFO, + (host_info_t)&cpu->load, + &cpu->count ); + + if (error != KERN_SUCCESS) { + printf("Error: Could not read cpu host statistics.\n"); + return; + } + + if (cpu->has_prev_load) { + uint32_t delta_user = cpu->load.cpu_ticks[CPU_STATE_USER] + - cpu->prev_load.cpu_ticks[CPU_STATE_USER]; + + uint32_t delta_system = cpu->load.cpu_ticks[CPU_STATE_SYSTEM] + - cpu->prev_load.cpu_ticks[CPU_STATE_SYSTEM]; + + uint32_t delta_idle = cpu->load.cpu_ticks[CPU_STATE_IDLE] + - cpu->prev_load.cpu_ticks[CPU_STATE_IDLE]; + + double user_perc = (double)delta_user / (double)(delta_system + + delta_user + + delta_idle); + + double sys_perc = (double)delta_system / (double)(delta_system + + delta_user + + delta_idle); + + double total_perc = user_perc + sys_perc; + + FILE* file; + char line[1024]; + + file = popen(TOPPROC, "r"); + if (!file) { + printf("Error: TOPPROC command errored out...\n" ); + return; + } + + fgets(line, sizeof(line), file); + fgets(line, sizeof(line), file); + + char* start = strstr(line, FILTER_PATTERN); + char topproc[MAX_TOPPROC_LEN + 4]; + uint32_t caret = 0; + for (int i = 0; i < sizeof(line); i++) { + if (start && i == start - line) { + i+=9; + continue; + } + + if (caret >= MAX_TOPPROC_LEN && caret <= MAX_TOPPROC_LEN + 2) { + topproc[caret++] = '.'; + continue; + } + if (caret > MAX_TOPPROC_LEN + 2) break; + topproc[caret++] = line[i]; + if (line[i] == '\0') break; + } + + topproc[MAX_TOPPROC_LEN + 3] = '\0'; + + pclose(file); + + char color[16]; + if (total_perc >= .7) { + snprintf(color, 16, "%s", getenv("RED")); + } else if (total_perc >= .3) { + snprintf(color, 16, "%s", getenv("ORANGE")); + } else if (total_perc >= .1) { + snprintf(color, 16, "%s", getenv("YELLOW")); + } else { + snprintf(color, 16, "%s", getenv("LABEL_COLOR")); + } + + snprintf(cpu->command, 256, "--push cpu.sys %.2f " + "--push cpu.user %.2f " + "--set cpu.top label='%s' " + "--set cpu.percent label=%.0f%% label.color=%s ", + sys_perc, + user_perc, + topproc, + total_perc*100., + color ); + } + else { + snprintf(cpu->command, 256, ""); + } + + cpu->prev_load = cpu->load; + cpu->has_prev_load = true; +} diff --git a/.config/sketchybar/helper/helper b/.config/sketchybar/helper/helper new file mode 100755 index 0000000..a2d5bfc Binary files /dev/null and b/.config/sketchybar/helper/helper differ diff --git a/.config/sketchybar/helper/helper.c b/.config/sketchybar/helper/helper.c new file mode 100644 index 0000000..71c3038 --- /dev/null +++ b/.config/sketchybar/helper/helper.c @@ -0,0 +1,31 @@ +#include "cpu.h" +#include "sketchybar.h" + +struct cpu g_cpu; + +void handler(env env) { + // Environment variables passed from sketchybar can be accessed as seen below + char* name = env_get_value_for_key(env, "NAME"); + char* sender = env_get_value_for_key(env, "SENDER"); + char* info = env_get_value_for_key(env, "INFO"); + char* selected = env_get_value_for_key(env, "SELECTED"); + + if ((strcmp(name, "cpu.percent") == 0)) { + // CPU graph updates + cpu_update(&g_cpu); + + if (strlen(g_cpu.command) > 0) sketchybar(g_cpu.command); + } +} + +int main (int argc, char** argv) { + cpu_init(&g_cpu); + + if (argc < 2) { + printf("Usage: helper \"\"\n"); + exit(1); + } + + event_server_begin(handler, argv[1]); + return 0; +} diff --git a/.config/sketchybar/helper/makefile b/.config/sketchybar/helper/makefile new file mode 100644 index 0000000..ac8721a --- /dev/null +++ b/.config/sketchybar/helper/makefile @@ -0,0 +1,3 @@ + +helper: helper.c cpu.h sketchybar.h + clang -std=c99 -O3 helper.c -o helper diff --git a/.config/sketchybar/helper/sketchybar.h b/.config/sketchybar/helper/sketchybar.h new file mode 100644 index 0000000..25b180e --- /dev/null +++ b/.config/sketchybar/helper/sketchybar.h @@ -0,0 +1,227 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +typedef char* env; + +#define MACH_HANDLER(name) void name(env env) +typedef MACH_HANDLER(mach_handler); + +struct mach_message { + mach_msg_header_t header; + mach_msg_size_t msgh_descriptor_count; + mach_msg_ool_descriptor_t descriptor; +}; + +struct mach_buffer { + struct mach_message message; + mach_msg_trailer_t trailer; +}; + +struct mach_server { + bool is_running; + mach_port_name_t task; + mach_port_t port; + mach_port_t bs_port; + + pthread_t thread; + mach_handler* handler; +}; + +static struct mach_server g_mach_server; +static mach_port_t g_mach_port = 0; + +static inline char* env_get_value_for_key(env env, char* key) { + uint32_t caret = 0; + for(;;) { + if (!env[caret]) break; + if (strcmp(&env[caret], key) == 0) + return &env[caret + strlen(&env[caret]) + 1]; + + caret += strlen(&env[caret]) + + strlen(&env[caret + strlen(&env[caret]) + 1]) + + 2; + } + return (char*)""; +} + +static inline mach_port_t mach_get_bs_port() { + mach_port_name_t task = mach_task_self(); + + mach_port_t bs_port; + if (task_get_special_port(task, + TASK_BOOTSTRAP_PORT, + &bs_port ) != KERN_SUCCESS) { + return 0; + } + + mach_port_t port; + if (bootstrap_look_up(bs_port, + "git.felix.sketchybar", + &port ) != KERN_SUCCESS) { + return 0; + } + + return port; +} + +static inline void mach_receive_message(mach_port_t port, struct mach_buffer* buffer, bool timeout) { + *buffer = (struct mach_buffer) { 0 }; + mach_msg_return_t msg_return; + if (timeout) + msg_return = mach_msg(&buffer->message.header, + MACH_RCV_MSG | MACH_RCV_TIMEOUT, + 0, + sizeof(struct mach_buffer), + port, + 100, + MACH_PORT_NULL ); + else + msg_return = mach_msg(&buffer->message.header, + MACH_RCV_MSG, + 0, + sizeof(struct mach_buffer), + port, + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL ); + + if (msg_return != MACH_MSG_SUCCESS) { + buffer->message.descriptor.address = NULL; + } +} + +static inline char* mach_send_message(mach_port_t port, char* message, uint32_t len) { + if (!message || !port) { + return NULL; + } + + mach_port_t response_port; + mach_port_name_t task = mach_task_self(); + if (mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, + &response_port ) != KERN_SUCCESS) { + return NULL; + } + + if (mach_port_insert_right(task, response_port, + response_port, + MACH_MSG_TYPE_MAKE_SEND)!= KERN_SUCCESS) { + return NULL; + } + + struct mach_message msg = { 0 }; + msg.header.msgh_remote_port = port; + msg.header.msgh_local_port = response_port; + msg.header.msgh_id = response_port; + msg.header.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, + MACH_MSG_TYPE_MAKE_SEND, + 0, + MACH_MSGH_BITS_COMPLEX ); + + msg.header.msgh_size = sizeof(struct mach_message); + msg.msgh_descriptor_count = 1; + msg.descriptor.address = message; + msg.descriptor.size = len * sizeof(char); + msg.descriptor.copy = MACH_MSG_VIRTUAL_COPY; + msg.descriptor.deallocate = false; + msg.descriptor.type = MACH_MSG_OOL_DESCRIPTOR; + + mach_msg(&msg.header, + MACH_SEND_MSG, + sizeof(struct mach_message), + 0, + MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, + MACH_PORT_NULL ); + + struct mach_buffer buffer = { 0 }; + mach_receive_message(response_port, &buffer, true); + if (buffer.message.descriptor.address) + return (char*)buffer.message.descriptor.address; + mach_msg_destroy(&buffer.message.header); + + return NULL; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +static inline bool mach_server_begin(struct mach_server* mach_server, mach_handler handler, char* bootstrap_name) { + mach_server->task = mach_task_self(); + + if (mach_port_allocate(mach_server->task, + MACH_PORT_RIGHT_RECEIVE, + &mach_server->port ) != KERN_SUCCESS) { + return false; + } + + if (mach_port_insert_right(mach_server->task, + mach_server->port, + mach_server->port, + MACH_MSG_TYPE_MAKE_SEND) != KERN_SUCCESS) { + return false; + } + + if (task_get_special_port(mach_server->task, + TASK_BOOTSTRAP_PORT, + &mach_server->bs_port) != KERN_SUCCESS) { + return false; + } + + if (bootstrap_register(mach_server->bs_port, + bootstrap_name, + mach_server->port ) != KERN_SUCCESS) { + return false; + } + + mach_server->handler = handler; + mach_server->is_running = true; + struct mach_buffer buffer; + while (mach_server->is_running) { + mach_receive_message(mach_server->port, &buffer, false); + mach_server->handler((env)buffer.message.descriptor.address); + mach_msg_destroy(&buffer.message.header); + } + + return true; +} +#pragma clang diagnostic pop + +static inline char* sketchybar(char* message) { + uint32_t message_length = strlen(message) + 1; + char formatted_message[message_length + 1]; + + char quote = '\0'; + uint32_t caret = 0; + for (int i = 0; i < message_length; ++i) { + if (message[i] == '"' || message[i] == '\'') { + if (quote == message[i]) quote = '\0'; + else quote = message[i]; + continue; + } + formatted_message[caret] = message[i]; + if (message[i] == ' ' && !quote) formatted_message[caret] = '\0'; + caret++; + } + + if (caret > 0 && formatted_message[caret] == '\0' + && formatted_message[caret - 1] == '\0') { + caret--; + } + + formatted_message[caret] = '\0'; + if (!g_mach_port) g_mach_port = mach_get_bs_port(); + char* response = mach_send_message(g_mach_port, + formatted_message, + caret + 1 ); + + if (response) return response; + else return (char*)""; +} + +static inline void event_server_begin(mach_handler event_handler, char* bootstrap_name) { + mach_server_begin(&g_mach_server, event_handler, bootstrap_name); +} diff --git a/.config/sketchybar/icons.sh b/.config/sketchybar/icons.sh new file mode 100755 index 0000000..5ba2dbd --- /dev/null +++ b/.config/sketchybar/icons.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +# General Icons +LOADING=􀖇 +APPLE=􀣺 +PREFERENCES=􀺽 +ACTIVITY=􀒓 +LOCK=􀒳 +BELL=􀋚 +BELL_DOT=􀝗 + +# Git Icons +GIT_ISSUE=􀍷 +GIT_DISCUSSION=􀒤 +GIT_PULL_REQUEST=􀙡 +GIT_COMMIT=􀡚 +GIT_INDICATOR=􀂓 + +# Spotify Icons +SPOTIFY_BACK=􀊎 +SPOTIFY_PLAY_PAUSE=􀊈 +SPOTIFY_NEXT=􀊐 +SPOTIFY_SHUFFLE=􀊝 +SPOTIFY_REPEAT=􀊞 + +# Yabai Icons +YABAI_STACK=􀏭 +YABAI_FULLSCREEN_ZOOM=􀏜 +YABAI_PARENT_ZOOM=􀥃 +YABAI_FLOAT=􀢌 +YABAI_GRID=􀧍 + +# Battery Icons +BATTERY_100=􀛨 +BATTERY_75=􀺸 +BATTERY_50=􀺶 +BATTERY_25=􀛩 +BATTERY_0=􀛪 +BATTERY_CHARGING=􀢋 + +# Volume Icons +VOLUME_100=􀊩 +VOLUME_66=􀊧 +VOLUME_33=􀊥 +VOLUME_10=􀊡 +VOLUME_0=􀊣 diff --git a/.config/sketchybar/items/apple.sh b/.config/sketchybar/items/apple.sh new file mode 100755 index 0000000..066d709 --- /dev/null +++ b/.config/sketchybar/items/apple.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +POPUP_OFF='sketchybar --set apple.logo popup.drawing=off' +POPUP_CLICK_SCRIPT='sketchybar --set $NAME popup.drawing=toggle' + +apple_logo=( + icon=$APPLE + icon.font="$FONT:Black:16.0" + icon.color=$GREEN + padding_right=15 + label.drawing=off + click_script="$POPUP_CLICK_SCRIPT" + popup.height=35 +) + +apple_prefs=( + icon=$PREFERENCES + label="Preferences" + click_script="open -a 'System Preferences'; $POPUP_OFF" +) + +apple_activity=( + icon=$ACTIVITY + label="Activity" + click_script="open -a 'Activity Monitor'; $POPUP_OFF" +) + +apple_lock=( + icon=$LOCK + label="Lock Screen" + click_script="pmset displaysleepnow; $POPUP_OFF" +) + +sketchybar --add item apple.logo left \ + --set apple.logo "${apple_logo[@]}" \ + \ + --add item apple.prefs popup.apple.logo \ + --set apple.prefs "${apple_prefs[@]}" \ + \ + --add item apple.activity popup.apple.logo \ + --set apple.activity "${apple_activity[@]}" \ + \ + --add item apple.lock popup.apple.logo \ + --set apple.lock "${apple_lock[@]}" diff --git a/.config/sketchybar/items/battery.sh b/.config/sketchybar/items/battery.sh new file mode 100755 index 0000000..a5f68a3 --- /dev/null +++ b/.config/sketchybar/items/battery.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +battery=( + script="$PLUGIN_DIR/battery.sh" + icon.font="$FONT:Regular:19.0" + padding_right=5 + padding_left=0 + label.drawing=off + update_freq=120 + updates=on +) + +sketchybar --add item battery right \ + --set battery "${battery[@]}" \ + --subscribe battery power_source_change system_woke diff --git a/.config/sketchybar/items/brew.sh b/.config/sketchybar/items/brew.sh new file mode 100755 index 0000000..f84d0a6 --- /dev/null +++ b/.config/sketchybar/items/brew.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Trigger the brew_udpate event when brew update or upgrade is run from cmdline +# e.g. via function in .zshrc + +brew=( + icon=􀐛 + label=? + padding_right=10 + script="$PLUGIN_DIR/brew.sh" +) + +sketchybar --add event brew_update \ + --add item brew right \ + --set brew "${brew[@]}" \ + --subscribe brew brew_update + diff --git a/.config/sketchybar/items/calendar.sh b/.config/sketchybar/items/calendar.sh new file mode 100755 index 0000000..39ea99a --- /dev/null +++ b/.config/sketchybar/items/calendar.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +calendar=( + icon=cal + icon.font="$FONT:Black:12.0" + icon.padding_right=0 + label.width=45 + label.align=right + padding_left=15 + update_freq=30 + script="$PLUGIN_DIR/calendar.sh" + click_script="$PLUGIN_DIR/zen.sh" +) + +sketchybar --add item calendar right \ + --set calendar "${calendar[@]}" \ + --subscribe calendar system_woke diff --git a/.config/sketchybar/items/cpu.sh b/.config/sketchybar/items/cpu.sh new file mode 100755 index 0000000..249595d --- /dev/null +++ b/.config/sketchybar/items/cpu.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +cpu_top=( + label.font="$FONT:Semibold:7" + label=CPU + icon.drawing=off + width=0 + padding_right=15 + y_offset=6 +) + +cpu_percent=( + label.font="$FONT:Heavy:12" + label=CPU + y_offset=-4 + padding_right=15 + width=55 + icon.drawing=off + update_freq=4 + mach_helper="$HELPER" +) + +cpu_sys=( + width=0 + graph.color=$RED + graph.fill_color=$RED + label.drawing=off + icon.drawing=off + background.height=30 + background.drawing=on + background.color=$TRANSPARENT +) + +cpu_user=( + graph.color=$BLUE + label.drawing=off + icon.drawing=off + background.height=30 + background.drawing=on + background.color=$TRANSPARENT +) + +sketchybar --add item cpu.top right \ + --set cpu.top "${cpu_top[@]}" \ + \ + --add item cpu.percent right \ + --set cpu.percent "${cpu_percent[@]}" \ + \ + --add graph cpu.sys right 75 \ + --set cpu.sys "${cpu_sys[@]}" \ + \ + --add graph cpu.user right 75 \ + --set cpu.user "${cpu_user[@]}" diff --git a/.config/sketchybar/items/front_app.sh b/.config/sketchybar/items/front_app.sh new file mode 100755 index 0000000..07b1f7d --- /dev/null +++ b/.config/sketchybar/items/front_app.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +FRONT_APP_SCRIPT='sketchybar --set $NAME label="$INFO"' + +yabai=( + icon.width=0 + label.width=0 + script="$PLUGIN_DIR/yabai.sh" + icon.font="$FONT:Bold:16.0" + associated_display=active +) + +front_app=( + icon.drawing=off + label.font="$FONT:Black:12.0" + associated_display=active + script="$FRONT_APP_SCRIPT" +) + +sketchybar --add event window_focus \ + --add event windows_on_spaces \ + --add item yabai left \ + --set yabai "${yabai[@]}" \ + --subscribe yabai window_focus \ + windows_on_spaces \ + mouse.clicked \ + \ + --add item front_app left \ + --set front_app "${front_app[@]}" \ + --subscribe front_app front_app_switched diff --git a/.config/sketchybar/items/github.sh b/.config/sketchybar/items/github.sh new file mode 100755 index 0000000..536216e --- /dev/null +++ b/.config/sketchybar/items/github.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +POPUP_CLICK_SCRIPT="sketchybar --set \$NAME popup.drawing=toggle" + +github_bell=( + update_freq=180 + icon=$BELL + icon.font="$FONT:Bold:15.0" + icon.color=$BLUE + label=$LOADING + label.highlight_color=$BLUE + popup.align=right + script="$PLUGIN_DIR/github.sh" + click_script="$POPUP_CLICK_SCRIPT" +) + +github_template=( + drawing=off + background.corner_radius=12 + padding_left=7 + padding_right=7 + icon.background.height=2 + icon.background.y_offset=-12 +) + +sketchybar --add item github.bell right \ + --set github.bell "${github_bell[@]}" \ + --subscribe github.bell mouse.entered \ + mouse.exited \ + mouse.exited.global \ + \ + --add item github.template popup.github.bell \ + --set github.template "${github_template[@]}" diff --git a/.config/sketchybar/items/spaces.sh b/.config/sketchybar/items/spaces.sh new file mode 100755 index 0000000..058c8c8 --- /dev/null +++ b/.config/sketchybar/items/spaces.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +SPACE_ICONS=("1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12" "13" "14" "15") + +# Destroy space on right click, focus space on left click. +# New space by left clicking separator (>) + +sid=0 +spaces=() +for i in "${!SPACE_ICONS[@]}" +do + sid=$(($i+1)) + + space=( + associated_space=$sid + icon="${SPACE_ICONS[i]}" + icon.padding_left=10 + icon.padding_right=10 + padding_left=2 + padding_right=2 + label.padding_right=20 + icon.highlight_color=$RED + label.color=$GREY + label.highlight_color=$WHITE + label.font="sketchybar-app-font:Regular:16.0" + label.y_offset=-1 + background.color=$BACKGROUND_1 + background.border_color=$BACKGROUND_2 + background.drawing=off + label.drawing=off + script="$PLUGIN_DIR/space.sh" + ) + + sketchybar --add space space.$sid left \ + --set space.$sid "${space[@]}" \ + --subscribe space.$sid mouse.clicked +done + +spaces_bracket=( + background.color=$BACKGROUND_1 + background.border_color=$BACKGROUND_2 +) + +separator=( + icon=􀆊 + icon.font="$FONT:Heavy:16.0" + padding_left=10 + padding_right=8 + label.drawing=off + associated_display=active + click_script='yabai -m space --create && sketchybar --trigger space_change' + icon.color=$WHITE +) + +sketchybar --add bracket spaces_bracket '/space\..*/' \ + --set spaces_bracket "${spaces_bracket[@]}" \ + \ + --add item separator left \ + --set separator "${separator[@]}" diff --git a/.config/sketchybar/items/spotify.sh b/.config/sketchybar/items/spotify.sh new file mode 100755 index 0000000..80a2b24 --- /dev/null +++ b/.config/sketchybar/items/spotify.sh @@ -0,0 +1,197 @@ +#!/bin/bash + +SPOTIFY_EVENT="com.spotify.client.PlaybackStateChanged" +POPUP_SCRIPT="sketchybar -m --set spotify.anchor popup.drawing=toggle" + +spotify_anchor=( + script="$PLUGIN_DIR/spotify.sh" + click_script="$POPUP_SCRIPT" + popup.horizontal=on + popup.align=center + popup.height=150 + icon=􁁒 + icon.font="$FONT:Regular:25.0" + label.drawing=off + drawing=off + y_offset=2 +) + +spotify_cover=( + script="$PLUGIN_DIR/spotify.sh" + click_script="open -a 'Spotify'; $POPUP_SCRIPT" + label.drawing=off + icon.drawing=off + padding_left=12 + padding_right=10 + background.image.scale=0.2 + background.image.drawing=on + background.drawing=on +) + +spotify_title=( + icon.drawing=off + padding_left=0 + padding_right=0 + width=0 + label.font="$FONT:Heavy:15.0" + y_offset=55 +) + +spotify_artist=( + icon.drawing=off + y_offset=30 + padding_left=0 + padding_right=0 + width=0 +) + +spotify_album=( + icon.drawing=off + padding_left=0 + padding_right=0 + y_offset=15 + width=0 +) + +spotify_state=( + icon.drawing=on + icon.font="$FONT:Light Italic:10.0" + icon.width=35 + icon="00:00" + label.drawing=on + label.font="$FONT:Light Italic:10.0" + label.width=35 + label="00:00" + padding_left=0 + padding_right=0 + y_offset=-15 + width=0 + slider.background.height=6 + slider.background.corner_radius=1 + slider.background.color=$GREY + slider.highlight_color=$GREEN + slider.percentage=40 + slider.width=115 + script="$PLUGIN_DIR/spotify.sh" + update_freq=1 + updates=when_shown +) + +spotify_shuffle=( + icon=􀊝 + icon.padding_left=5 + icon.padding_right=5 + icon.color=$BLACK + icon.highlight_color=$GREY + label.drawing=off + script="$PLUGIN_DIR/spotify.sh" + y_offset=-45 +) + +spotify_back=( + icon=􀊎 + icon.padding_left=5 + icon.padding_right=5 + icon.color=$BLACK + script="$PLUGIN_DIR/spotify.sh" + label.drawing=off + y_offset=-45 +) + +spotify_play=( + icon=􀊔 + background.height=40 + background.corner_radius=20 + width=40 + align=center + background.color=$POPUP_BACKGROUND_COLOR + background.border_color=$WHITE + background.border_width=0 + background.drawing=on + icon.padding_left=4 + icon.padding_right=5 + updates=on + label.drawing=off + script="$PLUGIN_DIR/spotify.sh" + y_offset=-45 +) + +spotify_next=( + icon=􀊐 + icon.padding_left=5 + icon.padding_right=5 + icon.color=$BLACK + label.drawing=off + script="$PLUGIN_DIR/spotify.sh" + y_offset=-45 +) + +spotify_repeat=( + icon=􀊞 + icon.highlight_color=$GREY + icon.padding_left=5 + icon.padding_right=10 + icon.color=$BLACK + label.drawing=off + script="$PLUGIN_DIR/spotify.sh" + y_offset=-45 +) + +spotify_controls=( + background.color=$GREEN + background.corner_radius=11 + background.drawing=on + y_offset=-45 +) + +sketchybar --add event spotify_change $SPOTIFY_EVENT \ + --add item spotify.anchor center \ + --set spotify.anchor "${spotify_anchor[@]}" \ + --subscribe spotify.anchor mouse.entered mouse.exited \ + mouse.exited.global \ + \ + --add item spotify.cover popup.spotify.anchor \ + --set spotify.cover "${spotify_cover[@]}" \ + \ + --add item spotify.title popup.spotify.anchor \ + --set spotify.title "${spotify_title[@]}" \ + \ + --add item spotify.artist popup.spotify.anchor \ + --set spotify.artist "${spotify_artist[@]}" \ + \ + --add item spotify.album popup.spotify.anchor \ + --set spotify.album "${spotify_album[@]}" \ + \ + --add slider spotify.state popup.spotify.anchor \ + --set spotify.state "${spotify_state[@]}" \ + --subscribe spotify.state mouse.clicked \ + \ + --add item spotify.shuffle popup.spotify.anchor \ + --set spotify.shuffle "${spotify_shuffle[@]}" \ + --subscribe spotify.shuffle mouse.clicked \ + \ + --add item spotify.back popup.spotify.anchor \ + --set spotify.back "${spotify_back[@]}" \ + --subscribe spotify.back mouse.clicked \ + \ + --add item spotify.play popup.spotify.anchor \ + --set spotify.play "${spotify_play[@]}" \ + --subscribe spotify.play mouse.clicked spotify_change \ + \ + --add item spotify.next popup.spotify.anchor \ + --set spotify.next "${spotify_next[@]}" \ + --subscribe spotify.next mouse.clicked \ + \ + --add item spotify.repeat popup.spotify.anchor \ + --set spotify.repeat "${spotify_repeat[@]}" \ + --subscribe spotify.repeat mouse.clicked \ + \ + --add item spotify.spacer popup.spotify.anchor \ + --set spotify.spacer width=5 \ + \ + --add bracket spotify.controls spotify.shuffle \ + spotify.back \ + spotify.play \ + spotify.next \ + spotify.repeat \ + --set spotify.controls "${spotify_controls[@]}" \ diff --git a/.config/sketchybar/items/volume.sh b/.config/sketchybar/items/volume.sh new file mode 100755 index 0000000..794f77a --- /dev/null +++ b/.config/sketchybar/items/volume.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +volume_slider=( + script="$PLUGIN_DIR/volume.sh" + updates=on + label.drawing=off + icon.drawing=off + slider.highlight_color=$BLUE + slider.background.height=5 + slider.background.corner_radius=3 + slider.background.color=$BACKGROUND_2 + slider.knob=􀀁 + slider.knob.drawing=off +) + +volume_icon=( + click_script="$PLUGIN_DIR/volume_click.sh" + padding_left=10 + icon=$VOLUME_100 + icon.width=0 + icon.align=left + icon.color=$GREY + icon.font="$FONT:Regular:14.0" + label.width=25 + label.align=left + label.font="$FONT:Regular:14.0" +) + +status_bracket=( + background.color=$BACKGROUND_1 + background.border_color=$BACKGROUND_2 +) + +sketchybar --add slider volume right \ + --set volume "${volume_slider[@]}" \ + --subscribe volume volume_change \ + mouse.clicked \ + mouse.entered \ + mouse.exited \ + \ + --add item volume_icon right \ + --set volume_icon "${volume_icon[@]}" + +sketchybar --add bracket status brew github.bell volume_icon \ + --set status "${status_bracket[@]}" diff --git a/.config/sketchybar/plugins/battery.sh b/.config/sketchybar/plugins/battery.sh new file mode 100755 index 0000000..e678409 --- /dev/null +++ b/.config/sketchybar/plugins/battery.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +source "$CONFIG_DIR/icons.sh" +source "$CONFIG_DIR/colors.sh" + +BATTERY_INFO="$(pmset -g batt)" +PERCENTAGE=$(echo "$BATTERY_INFO" | grep -Eo "\d+%" | cut -d% -f1) +CHARGING=$(echo "$BATTERY_INFO" | grep 'AC Power') + +if [ $PERCENTAGE = "" ]; then + exit 0 +fi + +DRAWING=on +COLOR=$WHITE +case ${PERCENTAGE} in + 9[0-9]|100) ICON=$BATTERY_100; DRAWING=off + ;; + [6-8][0-9]) ICON=$BATTERY_75; DRAWING=off + ;; + [3-5][0-9]) ICON=$BATTERY_50 + ;; + [1-2][0-9]) ICON=$BATTERY_25; COLOR=$ORANGE + ;; + *) ICON=$BATTERY_0; COLOR=$RED +esac + +if [[ $CHARGING != "" ]]; then + ICON=$BATTERY_CHARGING + DRAWING=off +fi + +sketchybar --set $NAME drawing=$DRAWING icon="$ICON" icon.color=$COLOR diff --git a/.config/sketchybar/plugins/brew.sh b/.config/sketchybar/plugins/brew.sh new file mode 100755 index 0000000..9ee5c3c --- /dev/null +++ b/.config/sketchybar/plugins/brew.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +source "$CONFIG_DIR/colors.sh" + +COUNT=$(brew outdated | wc -l | tr -d ' ') + +COLOR=$RED + +case "$COUNT" in + [3-5][0-9]) COLOR=$ORANGE + ;; + [1-2][0-9]) COLOR=$YELLOW + ;; + [1-9]) COLOR=$WHITE + ;; + 0) COLOR=$GREEN + COUNT=􀆅 + ;; +esac + +sketchybar --set $NAME label=$COUNT icon.color=$COLOR diff --git a/.config/sketchybar/plugins/calendar.sh b/.config/sketchybar/plugins/calendar.sh new file mode 100755 index 0000000..187b206 --- /dev/null +++ b/.config/sketchybar/plugins/calendar.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +sketchybar --set $NAME icon="$(date '+%a, %d %b')" label="$(date '+%H:%M')" diff --git a/.config/sketchybar/plugins/github.sh b/.config/sketchybar/plugins/github.sh new file mode 100755 index 0000000..806704a --- /dev/null +++ b/.config/sketchybar/plugins/github.sh @@ -0,0 +1,90 @@ +#!/bin/bash + +update() { + source "$CONFIG_DIR/colors.sh" + source "$CONFIG_DIR/icons.sh" + + NOTIFICATIONS="$(gh api notifications)" + COUNT="$(echo "$NOTIFICATIONS" | jq 'length')" + args=() + if [ "$NOTIFICATIONS" = "[]" ]; then + args+=(--set $NAME icon=$BELL label="0") + else + args+=(--set $NAME icon=$BELL_DOT label="$COUNT") + fi + + PREV_COUNT=$(sketchybar --query github.bell | jq -r .label.value) + # For sound to play around with: + # afplay /System/Library/Sounds/Morse.aiff + + args+=(--remove '/github.notification\.*/') + + COUNTER=0 + COLOR=$BLUE + args+=(--set github.bell icon.color=$COLOR) + + while read -r repo url type title + do + COUNTER=$((COUNTER + 1)) + IMPORTANT="$(echo "$title" | egrep -i "(deprecat|break|broke)")" + COLOR=$BLUE + PADDING=0 + + if [ "${repo}" = "" ] && [ "${title}" = "" ]; then + repo="Note" + title="No new notifications" + fi + case "${type}" in + "'Issue'") COLOR=$GREEN; ICON=$GIT_ISSUE; URL="$(gh api "$(echo "${url}" | sed -e "s/^'//" -e "s/'$//")" | jq .html_url)" + ;; + "'Discussion'") COLOR=$WHITE; ICON=$GIT_DISCUSSION; URL="https://www.github.com/notifications" + ;; + "'PullRequest'") COLOR=$MAGENTA; ICON=$GIT_PULL_REQUEST; URL="$(gh api "$(echo "${url}" | sed -e "s/^'//" -e "s/'$//")" | jq .html_url)" + ;; + "'Commit'") COLOR=$WHITE; ICON=$GIT_COMMIT; URL="$(gh api "$(echo "${url}" | sed -e "s/^'//" -e "s/'$//")" | jq .html_url)" + ;; + esac + + if [ "$IMPORTANT" != "" ]; then + COLOR=$RED + ICON=􀁞 + args+=(--set github.bell icon.color=$COLOR) + fi + + notification=( + label="$(echo "$title" | sed -e "s/^'//" -e "s/'$//")" + icon="$ICON $(echo "$repo" | sed -e "s/^'//" -e "s/'$//"):" + icon.padding_left="$PADDING" + label.padding_right="$PADDING" + icon.color=$COLOR + position=popup.github.bell + icon.background.color=$COLOR + drawing=on + click_script="open $URL; sketchybar --set github.bell popup.drawing=off" + ) + + args+=(--clone github.notification.$COUNTER github.template \ + --set github.notification.$COUNTER "${notification[@]}") + done <<< "$(echo "$NOTIFICATIONS" | jq -r '.[] | [.repository.name, .subject.latest_comment_url, .subject.type, .subject.title] | @sh')" + + sketchybar -m "${args[@]}" > /dev/null + + if [ $COUNT -gt $PREV_COUNT ] 2>/dev/null || [ "$SENDER" = "forced" ]; then + sketchybar --animate tanh 15 --set github.bell label.y_offset=5 label.y_offset=0 + fi +} + +popup() { + sketchybar --set $NAME popup.drawing=$1 +} + +case "$SENDER" in + "routine"|"forced") update + ;; + "mouse.entered") popup on + ;; + "mouse.exited"|"mouse.exited.global") popup off + ;; + "mouse.clicked") popup toggle + ;; +esac diff --git a/.config/sketchybar/plugins/icon_map.sh b/.config/sketchybar/plugins/icon_map.sh new file mode 100755 index 0000000..aa67017 --- /dev/null +++ b/.config/sketchybar/plugins/icon_map.sh @@ -0,0 +1,384 @@ +case $@ in +"Brave Browser") + icon_result=":brave_browser:" + ;; +"Keyboard Maestro") + icon_result=":keyboard_maestro:" + ;; +"Min") + icon_result=":min_browser:" + ;; +"Final Cut Pro") + icon_result=":final_cut_pro:" + ;; +"FaceTime") + icon_result=":face_time:" + ;; +"Affinity Publisher") + icon_result=":affinity_publisher:" + ;; +"Messages" | "Nachrichten") + icon_result=":messages:" + ;; +"Tweetbot" | "Twitter") + icon_result=":twitter:" + ;; +"ClickUp") + icon_result=":click_up:" + ;; +"KeePassXC") + icon_result=":kee_pass_x_c:" + ;; +"Microsoft Edge") + icon_result=":microsoft_edge:" + ;; +"VLC") + icon_result=":vlc:" + ;; +"Emacs") + icon_result=":emacs:" + ;; +"Thunderbird") + icon_result=":thunderbird:" + ;; +"Notes") + icon_result=":notes:" + ;; +"Caprine") + icon_result=":caprine:" + ;; +"Zulip") + icon_result=":zulip:" + ;; +"Spark") + icon_result=":spark:" + ;; +"Microsoft To Do" | "Things") + icon_result=":things:" + ;; +"DEVONthink 3") + icon_result=":devonthink3:" + ;; +"GitHub Desktop") + icon_result=":git_hub:" + ;; +"App Store") + icon_result=":app_store:" + ;; +"Chromium" | "Google Chrome" | "Google Chrome Canary") + icon_result=":google_chrome:" + ;; +"zoom.us") + icon_result=":zoom:" + ;; +"MoneyMoney") + icon_result=":bank:" + ;; +"Color Picker") + icon_result=":color_picker:" + ;; +"Microsoft Word") + icon_result=":microsoft_word:" + ;; +"Microsoft Teams") + icon_result=":microsoft_teams:" + ;; +"Iris") + icon_result=":iris:" + ;; +"WebStorm") + icon_result=":web_storm:" + ;; +"Neovide" | "MacVim" | "Vim" | "VimR") + icon_result=":vim:" + ;; +"Sublime Text") + icon_result=":sublime_text:" + ;; +"PomoDone App") + icon_result=":pomodone:" + ;; +"Setapp") + icon_result=":setapp:" + ;; +"qutebrowser") + icon_result=":qute_browser:" + ;; +"Mattermost") + icon_result=":mattermost:" + ;; +"Notability") + icon_result=":notability:" + ;; +"WhatsApp") + icon_result=":whats_app:" + ;; +"OBS") + icon_result=":obsstudio:" + ;; +"Parallels Desktop") + icon_result=":parallels:" + ;; +"VMware Fusion") + icon_result=":vmware_fusion:" + ;; +"Pine") + icon_result=":pine:" + ;; +"Microsoft Excel") + icon_result=":microsoft_excel:" + ;; +"Microsoft PowerPoint") + icon_result=":microsoft_power_point:" + ;; +"Matlab") + icon_result=":matlab:" + ;; +"Numbers") + icon_result=":numbers:" + ;; +"Default") + icon_result=":default:" + ;; +"Element") + icon_result=":element:" + ;; +"Bear") + icon_result=":bear:" + ;; +"TeamSpeak 3") + icon_result=":team_speak:" + ;; +"Airmail") + icon_result=":airmail:" + ;; +"Firefox Developer Edition" | "Firefox Nightly") + icon_result=":firefox_developer_edition:" + ;; +"Trello") + icon_result=":trello:" + ;; +"TickTick") + icon_result=":tick_tick:" + ;; +"Notion") + icon_result=":notion:" + ;; +"Live") + icon_result=":ableton:" + ;; +"Evernote Legacy") + icon_result=":evernote_legacy:" + ;; +"Calendar" | "Fantastical") + icon_result=":calendar:" + ;; +"Android Studio") + icon_result=":android_studio:" + ;; +"Xcode") + icon_result=":xcode:" + ;; +"Slack") + icon_result=":slack:" + ;; +"Sequel Pro") + icon_result=":sequel_pro:" + ;; +"Bitwarden") + icon_result=":bit_warden:" + ;; +"System Preferences" | "System Settings") + icon_result=":gear:" + ;; +"Discord" | "Discord Canary" | "Discord PTB") + icon_result=":discord:" + ;; +"Vivaldi") + icon_result=":vivaldi:" + ;; +"Firefox") + icon_result=":firefox:" + ;; +"Skype") + icon_result=":skype:" + ;; +"Dropbox") + icon_result=":dropbox:" + ;; +"微信") + icon_result=":wechat:" + ;; +"Typora") + icon_result=":text:" + ;; +"Blender") + icon_result=":blender:" + ;; +"Canary Mail" | "HEY" | "Mail" | "Mailspring" | "MailMate" | "邮件" | "Outlook") + icon_result=":mail:" + ;; +"Safari" | "Safari Technology Preview") + icon_result=":safari:" + ;; +"Telegram") + icon_result=":telegram:" + ;; +"Keynote") + icon_result=":keynote:" + ;; +"Reeder") + icon_result=":reeder5:" + ;; +"Spotify") + icon_result=":spotify:" + ;; +"MAMP" | "MAMP PRO") + icon_result=":mamp:" + ;; +"Figma") + icon_result=":figma:" + ;; +"Joplin") + icon_result=":joplin:" + ;; +"Spotlight") + icon_result=":spotlight:" + ;; +"Music") + icon_result=":music:" + ;; +"Insomnia") + icon_result=":insomnia:" + ;; +"TIDAL") + icon_result=":tidal:" + ;; +"Alfred") + icon_result=":alfred:" + ;; +"Pages") + icon_result=":pages:" + ;; +"Folx") + icon_result=":folx:" + ;; +"Android Messages") + icon_result=":android_messages:" + ;; +"mpv") + icon_result=":mpv:" + ;; +"网易云音乐") + icon_result=":netease_music:" + ;; +"Transmit") + icon_result=":transmit:" + ;; +"Pi-hole Remote") + icon_result=":pihole:" + ;; +"Nova") + icon_result=":nova:" + ;; +"Affinity Designer") + icon_result=":affinity_designer:" + ;; +"IntelliJ IDEA") + icon_result=":idea:" + ;; +"Drafts") + icon_result=":drafts:" + ;; +"Audacity") + icon_result=":audacity:" + ;; +"Affinity Photo") + icon_result=":affinity_photo:" + ;; +"Atom") + icon_result=":atom:" + ;; +"Obsidian") + icon_result=":obsidian:" + ;; +"CleanMyMac X") + icon_result=":desktop:" + ;; +"Zotero") + icon_result=":zotero:" + ;; +"Todoist") + icon_result=":todoist:" + ;; +"LibreWolf") + icon_result=":libre_wolf:" + ;; +"Grammarly Editor") + icon_result=":grammarly:" + ;; +"OmniFocus") + icon_result=":omni_focus:" + ;; +"Reminders") + icon_result=":reminders:" + ;; +"Preview" | "Skim" | "zathura") + icon_result=":pdf:" + ;; +"1Password 7") + icon_result=":one_password:" + ;; +"Code" | "Code - Insiders") + icon_result=":code:" + ;; +"VSCodium") + icon_result=":vscodium:" + ;; +"Tower") + icon_result=":tower:" + ;; +"Calibre") + icon_result=":book:" + ;; +"Finder" | "访达") + icon_result=":finder:" + ;; +"Linear") + icon_result=":linear:" + ;; +"League of Legends") + icon_result=":league_of_legends:" + ;; +"Zeplin") + icon_result=":zeplin:" + ;; +"Signal") + icon_result=":signal:" + ;; +"Podcasts") + icon_result=":podcasts:" + ;; +"Alacritty" | "Hyper" | "iTerm2" | "kitty" | "Terminal" | "WezTerm") + icon_result=":terminal:" + ;; +"Tor Browser") + icon_result=":tor_browser:" + ;; +"Kakoune") + icon_result=":kakoune:" + ;; +"GrandTotal" | "Receipts") + icon_result=":dollar:" + ;; +"Sketch") + icon_result=":sketch:" + ;; +"Sequel Ace") + icon_result=":sequel_ace:" + ;; +*) + icon_result=":default:" + ;; +esac +echo $icon_result diff --git a/.config/sketchybar/plugins/space.sh b/.config/sketchybar/plugins/space.sh new file mode 100755 index 0000000..d924c6b --- /dev/null +++ b/.config/sketchybar/plugins/space.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +update() { + source "$CONFIG_DIR/colors.sh" + COLOR=$BACKGROUND_2 + if [ "$SELECTED" = "true" ]; then + COLOR=$GREY + fi + sketchybar --set $NAME icon.highlight=$SELECTED \ + label.highlight=$SELECTED \ + background.border_color=$COLOR +} + +mouse_clicked() { + if [ "$BUTTON" = "right" ]; then + yabai -m space --destroy $SID + sketchybar --trigger windows_on_spaces --trigger space_change + else + yabai -m space --focus $SID 2>/dev/null + fi +} + +case "$SENDER" in + "mouse.clicked") mouse_clicked + ;; + *) update + ;; +esac diff --git a/.config/sketchybar/plugins/spotify.sh b/.config/sketchybar/plugins/spotify.sh new file mode 100755 index 0000000..91de600 --- /dev/null +++ b/.config/sketchybar/plugins/spotify.sh @@ -0,0 +1,147 @@ +#!/bin/bash + +next () +{ + osascript -e 'tell application "Spotify" to play next track' +} + +back () +{ + osascript -e 'tell application "Spotify" to play previous track' +} + +play () +{ + osascript -e 'tell application "Spotify" to playpause' +} + +repeat () +{ + REPEAT=$(osascript -e 'tell application "Spotify" to get repeating') + if [ "$REPEAT" = "false" ]; then + sketchybar -m --set spotify.repeat icon.highlight=on + osascript -e 'tell application "Spotify" to set repeating to true' + else + sketchybar -m --set spotify.repeat icon.highlight=off + osascript -e 'tell application "Spotify" to set repeating to false' + fi +} + +shuffle () +{ + SHUFFLE=$(osascript -e 'tell application "Spotify" to get shuffling') + if [ "$SHUFFLE" = "false" ]; then + sketchybar -m --set spotify.shuffle icon.highlight=on + osascript -e 'tell application "Spotify" to set shuffling to true' + else + sketchybar -m --set spotify.shuffle icon.highlight=off + osascript -e 'tell application "Spotify" to set shuffling to false' + fi +} + +update () +{ + PLAYING=1 + if [ "$(echo "$INFO" | jq -r '.["Player State"]')" = "Playing" ]; then + PLAYING=0 + TRACK="$(echo "$INFO" | jq -r .Name | sed 's/\(.\{20\}\).*/\1.../')" + ARTIST="$(echo "$INFO" | jq -r .Artist | sed 's/\(.\{20\}\).*/\1.../')" + ALBUM="$(echo "$INFO" | jq -r .Album | sed 's/\(.\{25\}\).*/\1.../')" + SHUFFLE=$(osascript -e 'tell application "Spotify" to get shuffling') + REPEAT=$(osascript -e 'tell application "Spotify" to get repeating') + COVER=$(osascript -e 'tell application "Spotify" to get artwork url of current track') + fi + + args=() + if [ $PLAYING -eq 0 ]; then + curl -s --max-time 20 "$COVER" -o /tmp/cover.jpg + if [ "$ARTIST" == "" ]; then + args+=(--set spotify.title label="$TRACK" + --set spotify.album label="Podcast" + --set spotify.artist label="$ALBUM" ) + else + args+=(--set spotify.title label="$TRACK" + --set spotify.album label="$ALBUM" + --set spotify.artist label="$ARTIST") + fi + args+=(--set spotify.play icon=􀊆 + --set spotify.shuffle icon.highlight=$SHUFFLE + --set spotify.repeat icon.highlight=$REPEAT + --set spotify.cover background.image="/tmp/cover.jpg" + background.color=0x00000000 + --set spotify.anchor drawing=on ) + else + args+=(--set spotify.anchor drawing=off popup.drawing=off + --set spotify.play icon=􀊄 ) + fi + sketchybar -m "${args[@]}" +} + +scrubbing() { + DURATION_MS=$(osascript -e 'tell application "Spotify" to get duration of current track') + DURATION=$((DURATION_MS/1000)) + + TARGET=$((DURATION*PERCENTAGE/100)) + osascript -e "tell application \"Spotify\" to set player position to $TARGET" + sketchybar --set spotify.state slider.percentage=$PERCENTAGE +} + +scroll() { + DURATION_MS=$(osascript -e 'tell application "Spotify" to get duration of current track') + DURATION=$((DURATION_MS/1000)) + + FLOAT="$(osascript -e 'tell application "Spotify" to get player position')" + TIME=${FLOAT%.*} + + sketchybar --animate linear 10 \ + --set spotify.state slider.percentage="$((TIME*100/DURATION))" \ + icon="$(date -r $TIME +'%M:%S')" \ + label="$(date -r $DURATION +'%M:%S')" +} + +mouse_clicked () { + case "$NAME" in + "spotify.next") next + ;; + "spotify.back") back + ;; + "spotify.play") play + ;; + "spotify.shuffle") shuffle + ;; + "spotify.repeat") repeat + ;; + "spotify.state") scrubbing + ;; + *) exit + ;; + esac +} + +popup () { + sketchybar --set spotify.anchor popup.drawing=$1 +} + +routine() { + case "$NAME" in + "spotify.state") scroll + ;; + *) update + ;; + esac +} + +case "$SENDER" in + "mouse.clicked") mouse_clicked + ;; + "mouse.entered") popup on + ;; + "mouse.exited"|"mouse.exited.global") popup off + ;; + "routine") routine + ;; + "forced") exit 0 + ;; + *) update + ;; +esac diff --git a/.config/sketchybar/plugins/volume.sh b/.config/sketchybar/plugins/volume.sh new file mode 100755 index 0000000..d5077c8 --- /dev/null +++ b/.config/sketchybar/plugins/volume.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +WIDTH=100 + +volume_change() { + source "$CONFIG_DIR/icons.sh" + case $INFO in + [6-9][0-9]|100) ICON=$VOLUME_100 + ;; + [3-5][0-9]) ICON=$VOLUME_66 + ;; + [1-2][0-9]) ICON=$VOLUME_33 + ;; + [1-9]) ICON=$VOLUME_10 + ;; + 0) ICON=$VOLUME_0 + ;; + *) ICON=$VOLUME_100 + esac + + sketchybar --set volume_icon label=$ICON + + sketchybar --set $NAME slider.percentage=$INFO \ + --animate tanh 30 --set $NAME slider.width=$WIDTH + + sleep 2 + + # Check wether the volume was changed another time while sleeping + FINAL_PERCENTAGE=$(sketchybar --query $NAME | jq -r ".slider.percentage") + if [ "$FINAL_PERCENTAGE" -eq "$INFO" ]; then + sketchybar --animate tanh 30 --set $NAME slider.width=0 + fi +} + +mouse_clicked() { + osascript -e "set volume output volume $PERCENTAGE" +} + +mouse_entered() { + sketchybar --set $NAME slider.knob.drawing=on +} + +mouse_exited() { + sketchybar --set $NAME slider.knob.drawing=off +} + +case "$SENDER" in + "volume_change") volume_change + ;; + "mouse.clicked") mouse_clicked + ;; + "mouse.entered") mouse_entered + ;; + "mouse.exited") mouse_exited + ;; +esac diff --git a/.config/sketchybar/plugins/volume_click.sh b/.config/sketchybar/plugins/volume_click.sh new file mode 100755 index 0000000..5c2a365 --- /dev/null +++ b/.config/sketchybar/plugins/volume_click.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +WIDTH=100 + +detail_on() { + sketchybar --animate tanh 30 --set volume slider.width=$WIDTH +} + +detail_off() { + sketchybar --animate tanh 30 --set volume slider.width=0 +} + +toggle_detail() { + INITIAL_WIDTH=$(sketchybar --query volume | jq -r ".slider.width") + if [ "$INITIAL_WIDTH" -eq "0" ]; then + detail_on + else + detail_off + fi +} + +toggle_devices() { + which SwitchAudioSource >/dev/null || exit 0 + source "$CONFIG_DIR/colors.sh" + + args=(--remove '/volume.device\.*/' --set "$NAME" popup.drawing=toggle) + COUNTER=0 + CURRENT="$(SwitchAudioSource -t output -c)" + while IFS= read -r device; do + COLOR=$GREY + if [ "${device}" = "$CURRENT" ]; then + COLOR=$WHITE + fi + args+=(--add item volume.device.$COUNTER popup."$NAME" \ + --set volume.device.$COUNTER label="${device}" \ + label.color="$COLOR" \ + click_script="SwitchAudioSource -s \"${device}\" && sketchybar --set /volume.device\.*/ label.color=$GREY --set \$NAME label.color=$WHITE --set $NAME popup.drawing=off") + COUNTER=$((COUNTER+1)) + done <<< "$(SwitchAudioSource -a -t output)" + + sketchybar -m "${args[@]}" > /dev/null +} + +if [ "$BUTTON" = "right" ] || [ "$MODIFIER" = "shift" ]; then + toggle_devices +else + toggle_detail +fi diff --git a/.config/sketchybar/plugins/yabai.sh b/.config/sketchybar/plugins/yabai.sh new file mode 100755 index 0000000..c44482f --- /dev/null +++ b/.config/sketchybar/plugins/yabai.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +window_state() { + source "$CONFIG_DIR/colors.sh" + source "$CONFIG_DIR/icons.sh" + + WINDOW=$(yabai -m query --windows --window) + STACK_INDEX=$(echo "$WINDOW" | jq '.["stack-index"]') + + COLOR=$BAR_BORDER_COLOR + ICON="" + + if [ "$(echo "$WINDOW" | jq '.["is-floating"]')" = "true" ]; then + ICON+=$YABAI_FLOAT + COLOR=$MAGENTA + elif [ "$(echo "$WINDOW" | jq '.["has-fullscreen-zoom"]')" = "true" ]; then + ICON+=$YABAI_FULLSCREEN_ZOOM + COLOR=$GREEN + elif [ "$(echo "$WINDOW" | jq '.["has-parent-zoom"]')" = "true" ]; then + ICON+=$YABAI_PARENT_ZOOM + COLOR=$BLUE + elif [[ $STACK_INDEX -gt 0 ]]; then + LAST_STACK_INDEX=$(yabai -m query --windows --window stack.last | jq '.["stack-index"]') + ICON+=$YABAI_STACK + LABEL="$(printf "[%s/%s]" "$STACK_INDEX" "$LAST_STACK_INDEX")" + COLOR=$RED + fi + + args=(--animate sin 10 --bar border_color=$COLOR + --set $NAME icon.color=$COLOR) + + [ -z "$LABEL" ] && args+=(label.width=0) \ + || args+=(label="$LABEL" label.width=40) + + [ -z "$ICON" ] && args+=(icon.width=0) \ + || args+=(icon="$ICON" icon.width=30) + + sketchybar -m "${args[@]}" +} + +windows_on_spaces () { + CURRENT_SPACES="$(yabai -m query --displays | jq -r '.[].spaces | @sh')" + + args=(--set spaces_bracket drawing=off + --set '/space\..*/' background.drawing=on + --animate sin 10) + + while read -r line + do + for space in $line + do + icon_strip=" " + apps=$(yabai -m query --windows --space $space | jq -r ".[].app") + if [ "$apps" != "" ]; then + while IFS= read -r app; do + icon_strip+=" $($CONFIG_DIR/plugins/icon_map.sh "$app")" + done <<< "$apps" + fi + args+=(--set space.$space label="$icon_strip" label.drawing=on) + done + done <<< "$CURRENT_SPACES" + + sketchybar -m "${args[@]}" +} + +mouse_clicked() { + yabai -m window --toggle float + window_state +} + +case "$SENDER" in + "mouse.clicked") mouse_clicked + ;; + "forced") exit 0 + ;; + "window_focus") window_state + ;; + "windows_on_spaces") windows_on_spaces + ;; +esac diff --git a/.config/sketchybar/plugins/zen.sh b/.config/sketchybar/plugins/zen.sh new file mode 100755 index 0000000..966ef68 --- /dev/null +++ b/.config/sketchybar/plugins/zen.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +zen_on() { + sketchybar --set github.bell drawing=off \ + --set apple.logo drawing=off \ + --set '/cpu.*/' drawing=off \ + --set calendar icon.drawing=off \ + --set separator drawing=off \ + --set front_app drawing=off \ + --set volume_icon drawing=off \ + --set spotify.anchor drawing=off \ + --set spotify.play updates=off \ + --set brew drawing=off +} + +zen_off() { + sketchybar --set github.bell drawing=on \ + --set apple.logo drawing=on \ + --set '/cpu.*/' drawing=on \ + --set calendar icon.drawing=on \ + --set separator drawing=on \ + --set front_app drawing=on \ + --set volume_icon drawing=on \ + --set spotify.play updates=on \ + --set brew drawing=on +} + +if [ "$1" = "on" ]; then + zen_on +elif [ "$1" = "off" ]; then + zen_off +else + if [ "$(sketchybar --query apple.logo | jq -r ".geometry.drawing")" = "on" ]; then + zen_on + else + zen_off + fi +fi + diff --git a/.config/sketchybar/sketchybarrc b/.config/sketchybar/sketchybarrc new file mode 100755 index 0000000..17ba60d --- /dev/null +++ b/.config/sketchybar/sketchybarrc @@ -0,0 +1,83 @@ +#!/bin/bash + +source "$CONFIG_DIR/colors.sh" # Loads all defined colors +source "$CONFIG_DIR/icons.sh" # Loads all defined icons + +ITEM_DIR="$CONFIG_DIR/items" # Directory where the items are configured +PLUGIN_DIR="$CONFIG_DIR/plugins" # Directory where all the plugin scripts are stored + +FONT="SF Pro" # Needs to have Regular, Bold, Semibold, Heavy and Black variants +PADDINGS=3 # All paddings use this value (icon, label, background) + +# Setting up and starting the helper process +HELPER=git.felix.helper +killall helper +(cd $CONFIG_DIR/helper && make) +$CONFIG_DIR/helper/helper $HELPER > /dev/null 2>&1 & + +# Unload the macOS on screen indicator overlay for volume change +launchctl unload -F /System/Library/LaunchAgents/com.apple.OSDUIHelper.plist > /dev/null 2>&1 & + +# Setting up the general bar appearance of the bar +bar=( + height=45 + color=$BAR_COLOR + border_width=2 + border_color=$BAR_BORDER_COLOR + shadow=off + position=top + sticky=on + padding_right=10 + padding_left=10 + y_offset=-5 + margin=-2 +) + +sketchybar --bar "${bar[@]}" + +# Setting up default values +defaults=( + updates=when_shown + icon.font="$FONT:Bold:14.0" + icon.color=$ICON_COLOR + icon.padding_left=$PADDINGS + icon.padding_right=$PADDINGS + label.font="$FONT:Semibold:13.0" + label.color=$LABEL_COLOR + label.padding_left=$PADDINGS + label.padding_right=$PADDINGS + padding_right=$PADDINGS + padding_left=$PADDINGS + background.height=26 + background.corner_radius=9 + background.border_width=2 + popup.background.border_width=2 + popup.background.corner_radius=9 + popup.background.border_color=$POPUP_BORDER_COLOR + popup.background.color=$POPUP_BACKGROUND_COLOR + popup.blur_radius=20 + popup.background.shadow.drawing=on +) + +sketchybar --default "${defaults[@]}" + +# Left +source $ITEM_DIR/apple.sh +source $ITEM_DIR/spaces.sh +source $ITEM_DIR/front_app.sh + +# Center +source "$ITEM_DIR/spotify.sh" + +# Right +source "$ITEM_DIR/calendar.sh" +source "$ITEM_DIR/brew.sh" +source "$ITEM_DIR/github.sh" +source "$ITEM_DIR/battery.sh" +source "$ITEM_DIR/volume.sh" +source "$ITEM_DIR/cpu.sh" + +# Forcing all item scripts to run (never do this outside of sketchybarrc) +sketchybar --update + +echo "sketchybar configuation loaded.." diff --git a/.config/yabai/yabairc b/.config/yabai/yabairc new file mode 100755 index 0000000..4cab664 --- /dev/null +++ b/.config/yabai/yabairc @@ -0,0 +1,59 @@ +#!/usr/bin/env sh + +# Unload the macOS WindowManager process +launchctl unload -F /System/Library/LaunchAgents/com.apple.WindowManager.plist > /dev/null 2>&1 & + +sudo yabai --load-sa +yabai -m signal --add event=dock_did_restart action="sudo yabai --load-sa" +yabai -m signal --add event=window_focused action="sketchybar --trigger window_focus" +yabai -m signal --add event=display_added action="sleep 2 && $HOME/.config/yabai/create_spaces.sh" +yabai -m signal --add event=display_removed action="sleep 1 && $HOME/.config/yabai/create_spaces.sh" +yabai -m signal --add event=window_created action="sketchybar --trigger windows_on_spaces" +yabai -m signal --add event=window_destroyed action="sketchybar --trigger windows_on_spaces" + +$HOME/.config/yabai/create_spaces.sh + +yabai -m config external_bar all:40:0 \ + window_border on \ + mouse_follows_focus off \ + focus_follows_mouse autofocus \ + window_zoom_persist off \ + window_placement second_child \ + window_topmost off \ + window_shadow float \ + window_opacity on \ + window_opacity_duration 0.15 \ + active_window_opacity 1.0 \ + normal_window_opacity 0.95 \ + window_border_width 2 \ + window_border_hidpi off \ + window_border_radius 11 \ + window_animation_duration 0.22 \ + active_window_border_color 0xffe1e3e4 \ + normal_window_border_color 0xff2a2f38 \ + insert_feedback_color 0xff9dd274 \ + split_ratio 0.50 \ + auto_balance off \ + mouse_modifier fn \ + mouse_action1 move \ + mouse_action2 resize \ + mouse_drop_action swap \ + \ + top_padding 10 \ + bottom_padding 10 \ + left_padding 10 \ + right_padding 10 \ + window_gap 8 \ + window_border_blur off + +# Exclude problematic apps from being managed: +yabai -m rule --add app="^(LuLu|Vimac|Calculator|Software Update|Dictionary|VLC|System Preferences|System Settings|zoom.us|Photo Booth|Archive Utility|Python|LibreOffice|App Store|Steam|Alfred|Activity Monitor|Cerebro)$" manage=off +yabai -m rule --add label="Finder" app="^Finder$" title="(Co(py|nnect)|Move|Info|Pref)" manage=off +yabai -m rule --add label="Safari" app="^Safari$" title="^(General|(Tab|Password|Website|Extension)s|AutoFill|Se(arch|curity)|Privacy|Advance)$" manage=off +yabai -m rule --add label="About This Mac" app="System Information" title="About This Mac" manage=off +yabai -m rule --add label="Select file to save to" app="^Inkscape$" title="Select file to save to" manage=off +yabai -m rule --add label="Little Arc" app="^Arc$" title="Little Arc.*" + +yabai -m config layout bsp + +echo "yabai configuration loaded.." diff --git a/.local/share/applications/albert-start.desktop b/.local/share/applications/albert-start.desktop deleted file mode 100644 index 4cc9d30..0000000 --- a/.local/share/applications/albert-start.desktop +++ /dev/null @@ -1,8 +0,0 @@ -[Desktop Entry] -Type=Application -Encoding=UTF-8 -Name=Albert Starter -Comment=time to start albert -Exec=/home/adriel/scripts/albert-start -Terminal=false -X-Desktop-File-Install-Version=0.26 diff --git a/.local/share/gnome-shell/extensions/Move_Clock@rmy.pobox.com/extension.js b/.local/share/gnome-shell/extensions/Move_Clock@rmy.pobox.com/extension.js deleted file mode 100644 index ed336d2..0000000 --- a/.local/share/gnome-shell/extensions/Move_Clock@rmy.pobox.com/extension.js +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2011-2017 R M Yorston -// Licence: GPLv2+ - -const Main = imports.ui.main; -const SessionMode = imports.ui.sessionMode; - -function init() { -} - -function enable() { - // do nothing if the clock isn't centred in this mode - if ( Main.sessionMode.panel.center.indexOf('dateMenu') == -1 ) { - return; - } - - let centerBox = Main.panel._centerBox; - let rightBox = Main.panel._rightBox; - let dateMenu = Main.panel.statusArea['dateMenu']; - let children = centerBox.get_children(); - - // only move the clock if it's in the centre box - if ( children.indexOf(dateMenu.container) != -1 ) { - centerBox.remove_actor(dateMenu.container); - - children = rightBox.get_children(); - rightBox.insert_child_at_index(dateMenu.container, children.length-1); - } -} - -function disable() { - // do nothing if the clock isn't centred in this mode - if ( Main.sessionMode.panel.center.indexOf('dateMenu') == -1 ) { - return; - } - - let centerBox = Main.panel._centerBox; - let rightBox = Main.panel._rightBox; - let dateMenu = Main.panel.statusArea['dateMenu']; - let children = rightBox.get_children(); - - // only move the clock back if it's in the right box - if ( children.indexOf(dateMenu.container) != -1 ) { - rightBox.remove_actor(dateMenu.container); - centerBox.add_actor(dateMenu.container); - } -} diff --git a/.local/share/gnome-shell/extensions/Move_Clock@rmy.pobox.com/metadata.json b/.local/share/gnome-shell/extensions/Move_Clock@rmy.pobox.com/metadata.json deleted file mode 100644 index 785d9cc..0000000 --- a/.local/share/gnome-shell/extensions/Move_Clock@rmy.pobox.com/metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Move clock to left of status menu button", - "name": "Frippery Move Clock", - "shell-version": [ - "40", - "41" - ], - "url": "http://frippery.org/extensions", - "uuid": "Move_Clock@rmy.pobox.com", - "version": 25 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/LICENCE.txt b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/LICENCE.txt deleted file mode 100644 index 94a9ed0..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/LICENCE.txt +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/README.md b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/README.md deleted file mode 100644 index 4f46661..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/README.md +++ /dev/null @@ -1,212 +0,0 @@ -# arch-update -Update indicator for Arch Linux and GNOME Shell - -## Features -- Uses pacman's «checkupdates» by default and thus does not need root access -- Optional update count display on panel -- Optional notification on new updates (defaults to off) -- Launcher for your favorite update command -- Comes in English, French, Czech, German, Spanish, Brazilian Portuguese, Italian, Polish, Romanian, Arabic, Slovak, Chinese, Serbian, Swedish, Norwegian Bokmal, Russian, Persian, Turkish, Esperanto, Finnish, Dutch, Ukrainian, Korean languages. (Thanks translators !) - -## Requirements -If you use the default "checkupdates" way you will need to install "pacman-contrib". - -## One-click install -It's on extensions.gnome.org : -https://extensions.gnome.org/extension/1010/archlinux-updates-indicator/ - -## Install from AUR -Thanks to michiwend you can install it from Arch Linux User Repository : gnome-shell-extension-arch-update -https://aur.archlinux.org/packages/gnome-shell-extension-arch-update/ - -## Manual install -To install, simply download as zip and unzip contents in ~/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet - -## Changes - -### v45 -- Fixed an error on unloading introduced in v44 - -### v44 -- Minor refactoring - -### v43 -- Gnome 41 -- New translations : Dutch, Korean, Ukrainian -- Updated translations : Simplified Chinese, Russian - -### v42 -- Updated translation : German - -### v41 -- Fixed metadata for extensions website - -### v40 -- Gnome 40 only -- Updated translation : Russian - -### v39 -- Fixed update list empty after suspend -- Fixed update list not fully visible when lots of updates -- Updated translations : Chinese and Spanish - -### v38 -- Fixed crash about Gtk.IconTheme.get_defaults -- Added indicator position setting - -### v37 -- Theme support is back ! Also an option to force built-in icons if needed. - -### v36 -- Gnome 3.36.1 only -- Fixed open prefs from menu - -### v35 -- Gnome 3.36 only -- Fixed a warning about absolete call - -### v34 -- Gnome 3.36 -- New translation : Swedish -- Updated translations : Italian, German - -### v33 -- Removed deprecated code -- Removed support for older GS - -### v32 -- Gnome 3.34 - -### v31 -- Updated translation : Turkish - -### v30 -- Gnome 3.32 - -### v29 -- Update translation : Romanian -- Applied French translation to all French - -### v28 -- Gnome 3.30 -- New translation : Esperanto -- New translation : Finnish -- Updated translation : Brazilian -- Fix indicator alignment -- Fix some errors that could quickly fill log - -### v27 -- Added info about pacman-contrib for checkupdates script -- New translation : Estonian -- Updated translation : Romanian - -### v26 -- Gnome 3.28 -- New translation : Hebrew -- Update translation : Spanish - -### v25 -- Added optional package manager menu entry -- Added requirements in readme -- Updated Slovak translation -- Updated Italian translation -- Fixed a JS Warning -- Fixed a bug that crashes Gnome-SHELL on update - -### v24 -- Gnome 3.26 -- Updated Romanian translation - -### v23 -- Updated translation : Arabic - -### v22 -- Updated translation : Serbian -- New translation : Turkish - -### v21 -- Gnome 3.24 -- New translation : Persian - -### v20 -- Translations updates (German, Spanish) - -### v19 -- Ability to cancel checking -- New translation : Catalan -- Updated translations : Spanish, Brazilian - -### v18 -- Gnome 3.22 -- New preferences window -- Cleaner translations (some text are not translated yet) -- Menu does not close when updating - -### v17 -- New translation : Russian -- Updated translation : Czech - -### v16 -- Add vertical scroll bar on preferences window - -### v15 -- New feature : auto-expand update list -- New translation : Norwegian Bokmal -- Updated translation : Brazilian Portuguese - -### v14 -- Gnome 3.20 compatibility - -### v13 -- New translation : Serbian (sr and sr@latin) -- Updated translation : Spanish -- Minor bug fix - -### v12 -- New translation : Chinese -- Updated translation : Czech - -### v11 -- New option to strip out version numbers -- New translations : Slovak and Arabic -- Updated translations : Brazilian Portuguese, German - -### v10 -- Licence added : GNU GPL v3 -- Updated translations : Polish and Brazilian portuguese - -### v9 -- Added option to change command used to check for updates (for advanced users) -- Added Romanian and Polish translations - -### v8 -- Added Italian language - -### v7 -- Added Brazilian Portuguese translation - -### v6 -- Added Spanish language - -### v5 -- Option to have permanent notifications -- Asynchronous checking - No more 1 sec Shell freeze during updates check ! -- 'Updates pending' menu item can now be expanded to show updates list -- Option to only list new updates in notifications -- Aded "Update Now" action button on notifications - -### v4 -- Run update command from indicator -- Autodetect when updates are done -- Prefs dialog reworked - -### v3 -- Notification option -- Czech and German languages added - -## Credits -All icons are based on Thayer Williams' Archer logo, winner of Arch Linux logo contest. - -Some portions of the extension were inspired from Touchad Indicator and Lock keys. -https://github.com/orangeshirt/gnome-shell-extension-touchpad-indicator -https://github.com/kazysmaster/gnome-shell-extension-lockkeys diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/extension.js b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/extension.js deleted file mode 100644 index 3cb0344..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/extension.js +++ /dev/null @@ -1,509 +0,0 @@ -/* - This file is part of Arch Linux Updates Indicator - - Arch Linux Updates Indicator is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Arch Linux Updates Indicator is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Arch Linux Updates Indicator. If not, see . - - Copyright 2016 Raphaël Rochet -*/ - -const Clutter = imports.gi.Clutter; - -const St = imports.gi.St; -const GObject = imports.gi.GObject; -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; -const Gtk = imports.gi.Gtk; - -const Main = imports.ui.main; -const Panel = imports.ui.panel; -const PanelMenu = imports.ui.panelMenu; -const PopupMenu = imports.ui.popupMenu; -const MessageTray = imports.ui.messageTray; - -const Util = imports.misc.util; -const ExtensionUtils = imports.misc.extensionUtils; -const ExtensionManager = imports.ui.main.extensionManager; -const Me = ExtensionUtils.getCurrentExtension(); - -const Format = imports.format; -const Gettext = imports.gettext.domain('arch-update'); -const _ = Gettext.gettext; - -/* Options */ -let ALWAYS_VISIBLE = true; -let USE_BUILDIN_ICONS = true; -let SHOW_COUNT = true; -let BOOT_WAIT = 15; // 15s -let CHECK_INTERVAL = 60*60; // 1h -let NOTIFY = false; -let HOWMUCH = 0; -let TRANSIENT = true; -let UPDATE_CMD = "gnome-terminal -e 'sh -c \"sudo pacman -Syu ; echo Done - Press enter to exit; read _\" '"; -let CHECK_CMD = "/usr/bin/checkupdates"; -let MANAGER_CMD = ""; -let PACMAN_DIR = "/var/lib/pacman/local"; -let STRIP_VERSIONS = true; -let AUTO_EXPAND_LIST = 0; - -/* Variables we want to keep when extension is disabled (eg during screen lock) */ -let FIRST_BOOT = 1; -let UPDATES_PENDING = -1; -let UPDATES_LIST = []; - - -function init() { - String.prototype.format = Format.format; - ExtensionUtils.initTranslations("arch-update"); -} - -const ArchUpdateIndicator = GObject.registerClass( - { - _TimeoutId: null, - _FirstTimeoutId: null, - _updateProcess_sourceId: null, - _updateProcess_stream: null, - _updateProcess_pid: null, - _updateList: [], - }, -class ArchUpdateIndicator extends PanelMenu.Button { - - _init() { - super._init(0); - this.updateIcon = new St.Icon({gicon: this._getCustIcon('arch-unknown-symbolic'), style_class: 'system-status-icon'}); - - let box = new St.BoxLayout({ vertical: false, style_class: 'panel-status-menu-box' }); - this.label = new St.Label({ text: '', - y_expand: true, - y_align: Clutter.ActorAlign.CENTER }); - - box.add_child(this.updateIcon); - box.add_child(this.label); - this.add_child(box); - - // Prepare the special menu : a submenu for updates list that will look like a regular menu item when disabled - // Scrollability will also be taken care of by the popupmenu - this.menuExpander = new PopupMenu.PopupSubMenuMenuItem(''); - this.menuExpander.menu.box.style_class = 'arch-updates-list'; - - // Other standard menu items - let settingsMenuItem = new PopupMenu.PopupMenuItem(_('Settings')); - this.updateNowMenuItem = new PopupMenu.PopupMenuItem(_('Update now')); - this.managerMenuItem = new PopupMenu.PopupMenuItem(_('Open package manager')); - - // A special "Checking" menu item with a stop button - this.checkingMenuItem = new PopupMenu.PopupBaseMenuItem( {reactive:false} ); - let checkingLabel = new St.Label({ text: _('Checking') + " …" }); - let cancelButton = new St.Button({ - child: new St.Icon({ icon_name: 'process-stop-symbolic' }), - style_class: 'system-menu-action arch-updates-menubutton', - x_expand: true - }); - cancelButton.set_x_align(Clutter.ActorAlign.END); - this.checkingMenuItem.actor.add_actor( checkingLabel ); - this.checkingMenuItem.actor.add_actor( cancelButton ); - - // A little trick on "check now" menuitem to keep menu opened - this.checkNowMenuItem = new PopupMenu.PopupMenuItem( _('Check now') ); - this.checkNowMenuContainer = new PopupMenu.PopupMenuSection(); - this.checkNowMenuContainer.actor.add_actor(this.checkNowMenuItem.actor); - - // Assemble all menu items into the popup menu - this.menu.addMenuItem(this.menuExpander); - this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this.menu.addMenuItem(this.updateNowMenuItem); - this.menu.addMenuItem(this.checkingMenuItem); - this.menu.addMenuItem(this.checkNowMenuContainer); - this.menu.addMenuItem(this.managerMenuItem); - this.menu.addMenuItem(settingsMenuItem); - - // Bind some events - this.menu.connect('open-state-changed', this._onMenuOpened.bind(this)); - this.checkNowMenuItem.connect('activate', this._checkUpdates.bind(this)); - cancelButton.connect('clicked', this._cancelCheck.bind(this)); - settingsMenuItem.connect('activate', this._openSettings.bind(this)); - this.updateNowMenuItem.connect('activate', this._updateNow.bind(this)); - this.managerMenuItem.connect('activate', this._openManager.bind(this)); - - // Some initial status display - this._showChecking(false); - this._updateMenuExpander(false, _('Waiting first check')); - - // Restore previous updates list if any - this._updateList = UPDATES_LIST; - - // Load settings - this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.arch-update'); - this._settings.connect('changed', this._positionChanged.bind(this)); - this._settingsChangedId = this._settings.connect('changed', this._applySettings.bind(this)); - this._applySettings(); - - // Start monitoring external changes - this._startFolderMonitor(); - - if (FIRST_BOOT) { - // Schedule first check only if this is the first extension load - // This won't be run again if extension is disabled/enabled (like when screen is locked) - let that = this; - this._FirstTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, BOOT_WAIT, function () { - that._checkUpdates(); - that._FirstTimeoutId = null; - FIRST_BOOT = 0; - return false; // Run once - }); - } - - } - - _getCustIcon(icon_name) { - // I did not find a way to lookup icon via Gio, so use Gtk - // I couldn't find why, but get_default is sometimes null, hence this additional test - if (!USE_BUILDIN_ICONS && Gtk.IconTheme.get_default()) { - if (Gtk.IconTheme.get_default().has_icon(icon_name)) { - return Gio.icon_new_for_string( icon_name ); - } - } - // Icon not available in theme, or user prefers built in icon - return Gio.icon_new_for_string( Me.dir.get_child('icons').get_path() + "/" + icon_name + ".svg" ); - } - - _positionChanged(){ - this.container.get_parent().remove_actor(this.container); - let boxes = { - 0: Main.panel._leftBox, - 1: Main.panel._centerBox, - 2: Main.panel._rightBox - }; - let p = this._settings.get_int('position'); - let i = this._settings.get_int('position-number'); - boxes[p].insert_child_at_index(this.container, i); - } - - _openSettings() { - Gio.DBus.session.call( - 'org.gnome.Shell.Extensions', - '/org/gnome/Shell/Extensions', - 'org.gnome.Shell.Extensions', - 'OpenExtensionPrefs', - new GLib.Variant('(ssa{sv})', [Me.uuid, '', {}]), - null, - Gio.DBusCallFlags.NONE, - -1, - null); - } - - _openManager() { - Util.spawnCommandLine(MANAGER_CMD); - } - - _updateNow() { - Util.spawnCommandLine(UPDATE_CMD); - } - - _applySettings() { - ALWAYS_VISIBLE = this._settings.get_boolean('always-visible'); - USE_BUILDIN_ICONS = this._settings.get_boolean('use-buildin-icons'); - SHOW_COUNT = this._settings.get_boolean('show-count'); - BOOT_WAIT = this._settings.get_int('boot-wait'); - CHECK_INTERVAL = 60 * this._settings.get_int('check-interval'); - NOTIFY = this._settings.get_boolean('notify'); - HOWMUCH = this._settings.get_int('howmuch'); - TRANSIENT = this._settings.get_boolean('transient'); - UPDATE_CMD = this._settings.get_string('update-cmd'); - CHECK_CMD = this._settings.get_string('check-cmd'); - MANAGER_CMD = this._settings.get_string('package-manager'); - PACMAN_DIR = this._settings.get_string('pacman-dir'); - STRIP_VERSIONS = this._settings.get_boolean('strip-versions'); - AUTO_EXPAND_LIST = this._settings.get_int('auto-expand-list'); - this.managerMenuItem.actor.visible = ( MANAGER_CMD != "" ); - this._checkShowHide(); - this._updateStatus(); - let that = this; - if (this._TimeoutId) GLib.source_remove(this._TimeoutId); - this._TimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, CHECK_INTERVAL, function () { - that._checkUpdates(); - return true; - }); - } - - destroy() { - this._settings.disconnect( this._settingsChangedId ); - if (this._notifSource) { - // Delete the notification source, which lay still have a notification shown - this._notifSource.destroy(); - this._notifSource = null; - }; - if (this.monitor) { - // Stop spying on pacman local dir - this.monitor.cancel(); - this.monitor = null; - } - if (this._updateProcess_sourceId) { - // We leave the checkupdate process end by itself but undef handles to avoid zombies - GLib.source_remove(this._updateProcess_sourceId); - this._updateProcess_sourceId = null; - this._updateProcess_stream = null; - } - if (this._FirstTimeoutId) { - GLib.source_remove(this._FirstTimeoutId); - this._FirstTimeoutId = null; - } - if (this._TimeoutId) { - GLib.source_remove(this._TimeoutId); - this._TimeoutId = null; - } - super.destroy(); - } - - _checkShowHide() { - if ( UPDATES_PENDING == -3 ) { - // Do not apply visibility change while checking for updates - return; - } - if (!ALWAYS_VISIBLE && UPDATES_PENDING < 1) { - this.visible = false; - } else { - this.visible = true; - } - this.label.visible = SHOW_COUNT && UPDATES_PENDING > 0; - } - - _onMenuOpened() { - // This event is fired when menu is shown or hidden - // Only open the submenu if the menu is being opened and there is something to show - this._checkAutoExpandList(); - } - - _checkAutoExpandList() { - if (this.menu.isOpen && UPDATES_PENDING > 0 && UPDATES_PENDING <= AUTO_EXPAND_LIST) { - this.menuExpander.setSubmenuShown(true); - } else { - this.menuExpander.setSubmenuShown(false); - } - } - - _startFolderMonitor() { - if (PACMAN_DIR) { - this.pacman_dir = Gio.file_new_for_path(PACMAN_DIR); - this.monitor = this.pacman_dir.monitor_directory(0, null); - this.monitor.connect('changed', this._onFolderChanged.bind(this)); - } - } - - _onFolderChanged() { - // Folder have changed ! Let's schedule a check in a few seconds - let that = this; - if (this._FirstTimeoutId) GLib.source_remove(this._FirstTimeoutId); - this._FirstTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 5, function () { - that._checkUpdates(); - that._FirstTimeoutId = null; - return false; - }); - } - - _showChecking(isChecking) { - if (isChecking == true) { - this.updateIcon.set_gicon( this._getCustIcon('arch-unknown-symbolic') ); - this.checkNowMenuContainer.actor.visible = false; - this.checkingMenuItem.actor.visible = true;; - } else { - this.checkNowMenuContainer.actor.visible = true;; - this.checkingMenuItem.actor.visible = false;; - } - } - - _updateStatus(updatesCount) { - updatesCount = typeof updatesCount === 'number' ? updatesCount : UPDATES_PENDING; - if (updatesCount > 0) { - // Updates pending - this.updateIcon.set_gicon( this._getCustIcon('arch-updates-symbolic') ); - this._updateMenuExpander( true, Gettext.ngettext( "%d update pending", "%d updates pending", updatesCount ).format(updatesCount) ); - this.label.set_text(updatesCount.toString()); - if (NOTIFY && UPDATES_PENDING < updatesCount) { - if (HOWMUCH > 0) { - let updateList = []; - if (HOWMUCH > 1) { - updateList = this._updateList; - } else { - // Keep only packets that was not in the previous notification - updateList = this._updateList.filter(function(pkg) { return UPDATES_LIST.indexOf(pkg) < 0 }); - } - if (updateList.length > 0) { - // Show notification only if there's new updates - this._showNotification( - Gettext.ngettext( "New Arch Linux Update", "New Arch Linux Updates", updateList.length ), - updateList.join(', ') - ); - } - } else { - this._showNotification( - Gettext.ngettext( "New Arch Linux Update", "New Arch Linux Updates", updatesCount ), - Gettext.ngettext( "There is %d update pending", "There are %d updates pending", updatesCount ).format(updatesCount) - ); - } - } - // Store the new list - UPDATES_LIST = this._updateList; - } else { - this.label.set_text(''); - if (updatesCount == -1) { - // Unknown - this.updateIcon.set_gicon( this._getCustIcon('arch-unknown-symbolic') ); - this._updateMenuExpander( false, '' ); - } else if (updatesCount == -2) { - // Error - this.updateIcon.set_gicon( this._getCustIcon('arch-error-symbolic') ); - if ( this.lastUnknowErrorString.indexOf("/usr/bin/checkupdates") > 0 ) { - // We do a special change here due to checkupdates moved to pacman-contrib - this._updateMenuExpander( false, _("Note : you have to install pacman-contrib to use the 'checkupdates' script.") ); - } else { - this._updateMenuExpander( false, _('Error') + "\n" + this.lastUnknowErrorString ); - } - } else { - // Up to date - this.updateIcon.set_gicon( this._getCustIcon('arch-uptodate-symbolic') ); - this._updateMenuExpander( false, _('Up to date :)') ); - UPDATES_LIST = []; // Reset stored list - } - } - UPDATES_PENDING = updatesCount; - this._checkAutoExpandList(); - this._checkShowHide(); - } - - _updateMenuExpander(enabled, label) { - this.menuExpander.menu.box.destroy_all_children(); - if (label == "") { - // No text, hide the menuitem - this.menuExpander.actor.visible = false; - } else { - // We make our expander look like a regular menu label if disabled - this.menuExpander.actor.reactive = enabled; - this.menuExpander._triangle.visible = enabled; - this.menuExpander.label.set_text(label); - this.menuExpander.actor.visible = true; - if (enabled && this._updateList.length > 0) { - this._updateList.forEach( item => { - this.menuExpander.menu.box.add( new St.Label({ text: item }) ); - } ); - } - } - - // 'Update now' visibility is linked so let's save a few lines and set it here - this.updateNowMenuItem.actor.reactive = enabled; - } - - _checkUpdates() { - if(this._updateProcess_sourceId) { - // A check is already running ! Maybe we should kill it and run another one ? - return; - } - // Run asynchronously, to avoid shell freeze - even for a 1s check - this._showChecking(true); - try { - // Parse check command line - let [parseok, argvp] = GLib.shell_parse_argv( CHECK_CMD ); - if (!parseok) { throw 'Parse error' }; - let [res, pid, in_fd, out_fd, err_fd] = GLib.spawn_async_with_pipes(null, argvp, null, GLib.SpawnFlags.DO_NOT_REAP_CHILD, null); - // Let's buffer the command's output - that's a input for us ! - this._updateProcess_stream = new Gio.DataInputStream({ - base_stream: new Gio.UnixInputStream({fd: out_fd}) - }); - // We will process the output at once when it's done - this._updateProcess_sourceId = GLib.child_watch_add(0, pid, () => {this._checkUpdatesRead()} ); - this._updateProcess_pid = pid; - } catch (err) { - this._showChecking(false); - this.lastUnknowErrorString = err.message.toString(); - this._updateStatus(-2); - } - } - - _cancelCheck() { - if (this._updateProcess_pid == null) { return; }; - Util.spawnCommandLine( "kill " + this._updateProcess_pid ); - this._updateProcess_pid = null; // Prevent double kill - this._checkUpdatesEnd(); - } - - _checkUpdatesRead() { - // Read the buffered output - let updateList = []; - let out, size; - do { - [out, size] = this._updateProcess_stream.read_line_utf8(null); - if (out) updateList.push(out); - } while (out); - // If version numbers should be stripped, do it - if (STRIP_VERSIONS == true) { - updateList = updateList.map(function(p) { - // Try to keep only what's before the first space - var chunks = p.split(" ",2); - return chunks[0]; - }); - } - this._updateList = updateList; - this._checkUpdatesEnd(); - } - - _checkUpdatesEnd() { - // Free resources - this._updateProcess_stream.close(null); - this._updateProcess_stream = null; - GLib.source_remove(this._updateProcess_sourceId); - this._updateProcess_sourceId = null; - this._updateProcess_pid = null; - // Update indicator - this._showChecking(false); - this._updateStatus(this._updateList.length); - } - - _showNotification(title, message) { - if (this._notifSource == null) { - // We have to prepare this only once - this._notifSource = new MessageTray.SystemNotificationSource(); - this._notifSource.createIcon = function() { - let gicon = Gio.icon_new_for_string( Me.dir.get_child('icons').get_path() + "/arch-lit-symbolic.svg" ); - return new St.Icon({ gicon: gicon }); - }; - // Take care of note leaving unneeded sources - this._notifSource.connect('destroy', ()=>{this._notifSource = null;}); - Main.messageTray.add(this._notifSource); - } - let notification = null; - // We do not want to have multiple notifications stacked - // instead we will update previous - if (this._notifSource.notifications.length == 0) { - notification = new MessageTray.Notification(this._notifSource, title, message); - notification.addAction( _('Update now') , ()=>{this._updateNow();} ); - } else { - notification = this._notifSource.notifications[0]; - notification.update( title, message, { clear: true }); - } - notification.setTransient(TRANSIENT); - this._notifSource.showNotification(notification); - } - -}); - -let archupdateindicator; - -function enable() { - archupdateindicator = new ArchUpdateIndicator(); - Main.panel.addToStatusArea('ArchUpdateIndicator', archupdateindicator); - archupdateindicator._positionChanged(); -} - -function disable() { - archupdateindicator.destroy(); -} diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-error-symbolic.svg b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-error-symbolic.svg deleted file mode 100644 index fa32162..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-error-symbolic.svg +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-lit-symbolic.svg b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-lit-symbolic.svg deleted file mode 100644 index 92a9704..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-lit-symbolic.svg +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-unknown-symbolic.svg b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-unknown-symbolic.svg deleted file mode 100644 index 9831e3e..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-unknown-symbolic.svg +++ /dev/null @@ -1,395 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-updates-symbolic.svg b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-updates-symbolic.svg deleted file mode 100644 index 9c40fd4..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-updates-symbolic.svg +++ /dev/null @@ -1,316 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-uptodate-symbolic.svg b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-uptodate-symbolic.svg deleted file mode 100644 index e8dad98..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/icons/arch-uptodate-symbolic.svg +++ /dev/null @@ -1,171 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ar/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ar/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 3c3fb38..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ar/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ca/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ca/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 613acc3..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ca/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/cs_CZ/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/cs_CZ/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 9371ede..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/cs_CZ/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/de_DE/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/de_DE/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 56678ac..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/de_DE/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/eo/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/eo/LC_MESSAGES/arch-update.mo deleted file mode 100644 index dd4f276..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/eo/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/es/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/es/LC_MESSAGES/arch-update.mo deleted file mode 100755 index dbb28d2..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/es/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/et/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/et/LC_MESSAGES/arch-update.mo deleted file mode 100644 index f490a0d..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/et/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/et/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/et/arch-update.mo deleted file mode 100644 index c66ce9c..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/et/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/fa_IR/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/fa_IR/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 9c85679..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/fa_IR/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/fi_FI/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/fi_FI/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 6782a18..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/fi_FI/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/fr/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/fr/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 88b81b3..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/fr/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/he_IL/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/he_IL/LC_MESSAGES/arch-update.mo deleted file mode 100644 index d9c9150..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/he_IL/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/he_IL/LC_MESSAGES/he_IL.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/he_IL/LC_MESSAGES/he_IL.mo deleted file mode 100644 index e423732..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/he_IL/LC_MESSAGES/he_IL.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/it_IT/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/it_IT/LC_MESSAGES/arch-update.mo deleted file mode 100644 index fe6434a..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/it_IT/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ko/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ko/LC_MESSAGES/arch-update.mo deleted file mode 100644 index e7754be..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ko/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/nb_NO/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/nb_NO/LC_MESSAGES/arch-update.mo deleted file mode 100644 index f4ed344..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/nb_NO/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/nl/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/nl/LC_MESSAGES/arch-update.mo deleted file mode 100644 index a63958e..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/nl/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/pl/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/pl/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 0a5e626..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/pl/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/pt_BR/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/pt_BR/LC_MESSAGES/arch-update.mo deleted file mode 100644 index f7ddaa2..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/pt_BR/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ro/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ro/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 45cf6ec..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ro/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ru_RU/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ru_RU/LC_MESSAGES/arch-update.mo deleted file mode 100644 index ed944b7..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/ru_RU/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sk/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sk/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 9c2728b..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sk/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sr/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sr/LC_MESSAGES/arch-update.mo deleted file mode 100644 index a8f513b..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sr/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sr@latin/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sr@latin/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 7a3b032..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sr@latin/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sv/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sv/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 30ce671..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/sv/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/tr_TR/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/tr_TR/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 22cfd98..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/tr_TR/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/uk_UA/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/uk_UA/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 6d8a623..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/uk_UA/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/zh_CN/LC_MESSAGES/arch-update.mo b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/zh_CN/LC_MESSAGES/arch-update.mo deleted file mode 100644 index 5a6bfec..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/locale/zh_CN/LC_MESSAGES/arch-update.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/metadata.json b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/metadata.json deleted file mode 100644 index 8bd0859..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Update indicator for Arch Linux and GNOME Shell.\n** Note : you now need to install the package pacman-contrib to use the checkupdates script. **\n Can support AUR or other distros by changing command used to check for and apply updates.", - "name": "Arch Linux Updates Indicator", - "shell-version": [ - "40", - "41" - ], - "url": "https://github.com/RaphaelRochet/arch-update", - "uuid": "arch-update@RaphaelRochet", - "version": 45 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/prefs.js b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/prefs.js deleted file mode 100644 index 99aa0dc..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/prefs.js +++ /dev/null @@ -1,67 +0,0 @@ -/* - This file is part of Arch Linux Updates Indicator - - Arch Linux Updates Indicator is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Arch Linux Updates Indicator is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Arch Linux Updates Indicator. If not, see . - - Copyright 2016 Raphaël Rochet -*/ - -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; -const Gio = imports.gi.Gio; -const Lang = imports.lang; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const Gettext = imports.gettext.domain('arch-update'); -const _ = Gettext.gettext; - -let settings; - -function init() { - settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.arch-update'); - ExtensionUtils.initTranslations("arch-update"); -} - -function buildPrefsWidget(){ - - // Prepare labels and controls - let buildable = new Gtk.Builder(); - buildable.add_from_file( Me.dir.get_path() + '/prefs.xml' ); - let box = buildable.get_object('prefs_widget'); - - let version_label = buildable.get_object('version_info'); - version_label.set_text('[Arch-update v' + Me.metadata.version.toString() + ']'); - - // Bind fields to settings - settings.bind('boot-wait' , buildable.get_object('field_wait') , 'value' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('check-interval' , buildable.get_object('field_interval') , 'value' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('always-visible' , buildable.get_object('field_visible') , 'active' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('use-buildin-icons' , buildable.get_object('field_buildinicons') , 'active' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('show-count' , buildable.get_object('field_count') , 'active', Gio.SettingsBindFlags.DEFAULT); - settings.bind('notify' , buildable.get_object('field_notify') , 'active' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('howmuch', buildable.get_object('field_howmuch'), 'active', Gio.SettingsBindFlags.DEFAULT); - settings.bind('transient', buildable.get_object('field_transient'), 'active', Gio.SettingsBindFlags.DEFAULT); - settings.bind('strip-versions' , buildable.get_object('field_stripversions') , 'active' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('check-cmd' , buildable.get_object('field_checkcmd') , 'text' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('update-cmd' , buildable.get_object('field_updatecmd') , 'text' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('pacman-dir' , buildable.get_object('field_pacmandir') , 'text' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('auto-expand-list', buildable.get_object('field_autoexpandlist'), 'value', Gio.SettingsBindFlags.DEFAULT); - settings.bind('package-manager' , buildable.get_object('field_packagemanager') , 'text' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('position' , buildable.get_object('field_position') , 'active' , Gio.SettingsBindFlags.DEFAULT); - settings.bind('position-number' , buildable.get_object('field_positionnumber') , 'value' , Gio.SettingsBindFlags.DEFAULT); - - return box; -}; - diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/prefs.xml b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/prefs.xml deleted file mode 100644 index 38b3284..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/prefs.xml +++ /dev/null @@ -1,459 +0,0 @@ - - - - - - 5 - 5000 - 1 - - - 30 - 2000 - 30 - - - 0 - 99 - 1 - - - 0 - 99 - 1 - - - - - - - 18 - 18 - 18 - 18 - 18 - false - vertical - - - - vertical - 6 - - - - horizontal - 12 - - - Checking for updates - true - 1 - - - - - - - - Version info placeholder - false - 1 - - - - - - - - 12 - 12 - - - Time to wait before first check (seconds) - true - 1 - - - - - Adjust_1 - - - - - - - - 12 - 12 - - - Interval between updates check (minutes) - true - 1 - - - - - Adjust_2 - - - - - - - - 12 - 12 - - - Strip out versions numbers - true - 1 - - - - - true - - - - - - - - - - - vertical - 6 - - - - Indicator - true - 1 - - - - - - - - - 12 - 12 - - - Always visible - true - 1 - - - - - true - - - - - - - - 12 - 12 - - - Use built-in icons - true - 1 - - - - - true - - - - - - - - 12 - 12 - - - Show updates count on indicator - true - 1 - - - - - true - - - - - - - - 12 - 12 - true - - - Auto-expand updates list if updates count is less than this number (0 to disable) - true - 0 - 1 - - - - - Adjust_3 - - - - - - - 12 - 12 - true - - - Position in Panel - true - 0 - 1 - - - - - 12 - 12 - false - - - - Left - Center - Right - - - - - - Adjust_4 - - - - - - - - - - - - - vertical - 6 - - - - Notification - true - 1 - - - - - - - - - 12 - 12 - - - Send a notification when new updates are available - true - 1 - - - - - true - - - - - - - - 12 - 12 - - - Use transient notifications (auto dismiss) - true - 1 - - - - - true - - - - - - - - 12 - 12 - - - How much information to show on notifications - true - 1 - - - - - - Count only - New updates names - All updates names - - - - - - - - - - - - - - - Basic settings - - - - - - 18 - 18 - 18 - 18 - 18 - false - vertical - - - - vertical - 6 - - - Command to check for package updates - true - 1 - - - - - - - - - - - - vertical - 6 - - - Command to update packages - true - 1 - - - - - - - - - - - - vertical - 6 - - - Pacman local directory path - To detect when new packages are installed - true - 1 - - - - - - - - - - - - vertical - 6 - - - Command to open package manager (optional) - true - 1 - - - - - - - - - - - - - - - Advanced settings - - - - - - diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/schemas/gschemas.compiled b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/schemas/gschemas.compiled deleted file mode 100644 index 991df55..0000000 Binary files a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/schemas/gschemas.compiled and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/schemas/org.gnome.shell.extensions.arch-update.gschema.xml b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/schemas/org.gnome.shell.extensions.arch-update.gschema.xml deleted file mode 100644 index 87ae97a..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/schemas/org.gnome.shell.extensions.arch-update.gschema.xml +++ /dev/null @@ -1,111 +0,0 @@ - - - - - 15 - Time to wait before first check (seconds) - A first check is made this number of seconds after startup - - - - - 60 - Interval between updates check (minutes) - Time to wait between two automatic checks - - - - - true - Indicator is always visble - - If true, the indicator is always visible, even when non updates are pending - - - - - false - Use build-in icons - - If true, the build-in status icons are used instead of theme icons - - - - - true - Show updates count on indicator - - If true, the indicator will display the number of updates pending - - - - - false - Send a notification when new updates are available - Send a notification when new updates are available - - - - 0 - How much information to show on notifications - 0:count, 1:list - - - - true - Use transient notifications (auto dismiss) - - - - - "/usr/bin/checkupdates" - Command to run to check for updated packages. - Command to run to check for updated packages. - - - - "gnome-terminal -e 'sh -c \"sudo pacman -Syu ; echo Done - Press enter to exit; read _\" '" - Command to run to update packages. - Command to run to update packages. - - - - "/var/lib/pacman/local" - Pacman directory to monitor - - - - - true - Remove version numbers from checkupdates output - - - - - 0 - Auto-open list submenu when updates count is lower than this number - - - - - - "" - Command to run to open package manager. - - - - - 2 - Position in the panel - Position where the arch update will be displayed (left/center/right) - - - - -0 - Position of the arch update inside the box - - - - - diff --git a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/stylesheet.css b/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/stylesheet.css deleted file mode 100644 index 29a9f51..0000000 --- a/.local/share/gnome-shell/extensions/arch-update@RaphaelRochet/stylesheet.css +++ /dev/null @@ -1,36 +0,0 @@ -/* - This file is part of Arch Linux Updates Indicator - - Arch Linux Updates Indicator is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Arch Linux Updates Indicator is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Arch Linux Updates Indicator. If not, see . - - Copyright 2016 Raphaël Rochet -*/ - -.arch-updates-list { - margin: 10px; - padding-left: 20px; -} - -.arch-updates-menubutton { - /* Meant to be used as an override to display a small system-menu-action */ - border-radius: 10px; - padding: 0px 4px; -} -.arch-updates-menubutton:hover, .arch-updates-menubutton:focus { - /* 1px borders disapears, need to compensate */ - padding: 1px 5px; -} -.arch-updates-menubutton > StIcon { - icon-size: 16px; -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/COPYING b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/COPYING deleted file mode 100644 index d159169..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/COPYING +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/README.md b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/README.md deleted file mode 100644 index 1c76c69..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/README.md +++ /dev/null @@ -1,45 +0,0 @@ -# Dash to Dock -![screenshot](https://github.com/micheleg/dash-to-dock/raw/master/media/screenshot.jpg) - -## A dock for the GNOME Shell -This extension enhances the dash moving it out of the overview and transforming it in a dock for an easier launching of applications and a faster switching between windows and desktops without having to leave the desktop view. - -[](https://extensions.gnome.org/extension/307/dash-to-dock) - -For additional installation instructions and more information visit [https://micheleg.github.io/dash-to-dock/](https://micheleg.github.io/dash-to-dock/). - -## Installation from source - -The extension can be installed directly from source, either for the convenience of using git or to test the latest development version. Clone the desired branch with git - -### Build Dependencies - -To compile the stylesheet you'll need an implementation of SASS. Dash to Dock supports `dart-sass` (`sass`), `sassc`, and `ruby-sass`. Every distro should have at least one of these implementations, we recommend using `dart-sass` (`sass`) or `sassc` over `ruby-sass` as `ruby-sass` is deprecated. - -By default, Dash to Dock will attempt to build with `dart-sass`. To change this behavior set the `SASS` environment variable to either `sassc` or `ruby`. - -```bash -export SASS=sassc -# or... -export SASS=ruby -``` - -### Building - -Clone the repository or download the branch from github. A simple Makefile is included. - -Next use `make` to install the extension into your home directory. A Shell reload is required `Alt+F2 r Enter` under Xorg or under Wayland you may have to logout and login. The extension has to be enabled with *gnome-extensions-app* (GNOME Extensions) or with *dconf*. - -```bash -git clone https://github.com/micheleg/dash-to-dock.git -make -make install -``` - -## Bug Reporting - -Bugs should be reported to the Github bug tracker [https://github.com/micheleg/dash-to-dock/issues](https://github.com/micheleg/dash-to-dock/issues). - -## License -Dash to Dock Gnome Shell extension is distributed under the terms of the GNU General Public License, -version 2 or later. See the COPYING file for details. diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/Settings.ui b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/Settings.ui deleted file mode 100644 index d129661..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/Settings.ui +++ /dev/null @@ -1,2799 +0,0 @@ - - - - - 1 - 0.050000000000000003 - 0.25 - - - 0 - 12 - 12 - 12 - 12 - vertical - - - 0 - - - 0 - 1 - 1 - none - - - 100 - 80 - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - When set to minimize, double clicking minimizes all the windows of the application. - 1 - 0 - 40 - - - - 0 - 1 - - - - - - 0 - 1 - Shift+Click action - 0 - - - 0 - 0 - - - - - - 0 - center - - Raise window - Minimize window - Launch new instance - Cycle through windows - Minimize or overview - Show window previews - Minimize or show previews - Focus or show previews - Focus, minimize or show previews - Quit - - - 1 - 0 - 2 - - - - - - - - - - 100 - 80 - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - Behavior for Middle-Click. - 1 - 0 - 40 - - - - 0 - 1 - - - - - - 0 - 1 - Middle-Click action - 0 - - - 0 - 0 - - - - - - 0 - center - - Raise window - Minimize window - Launch new instance - Cycle through windows - Minimize or overview - Show window previews - Minimize or show previews - Focus or show previews - Focus, minimize or show previews - Quit - - - 1 - 0 - 2 - - - - - - - - - - 100 - 80 - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - Behavior for Shift+Middle-Click. - 1 - 0 - 40 - - - - 0 - 1 - - - - - - 0 - 1 - Shift+Middle-Click action - 0 - - - 0 - 0 - - - - - - 0 - center - - Raise window - Minimize window - Launch new instance - Cycle through windows - Minimize or overview - Show window previews - Minimize or show previews - Focus or show previews - Focus, minimize or show previews - Quit - - - 1 - 0 - 2 - - - - - - - - - - - - - - - - - 1 - 0.01 - 0.10 - - - 0.33 - 1 - 0.01 - 0.10 - - - 10 - 1 - 5 - - - 1 - 1 - 0 - 12 - 12 - 12 - 12 - vertical - - - 0 - - - - 0 - none - - - 100 - 80 - - - 0 - 12 - 12 - 12 - 12 - vertical - 12 - - - 0 - 32 - - - 1 - 0 - 0 - center - Enable Unity7 like glossy backlit items - - - - - - center - - - - - - - 0 - - - 1 - 0 - 0 - start - Use dominant color - - - - - - - - - - 0 - 32 - - - - 1 - 0 - - - - - - 0 - 1 - 0 - Customize indicator style - fill - - - 0 - 0 - - - - - - - - 0 - 1 - vertical - 12 - - - 0 - 32 - - - 1 - 0 - 0 - Color - - - - - - 1 - - - - - - - 0 - 32 - - - 1 - 0 - 0 - Border color - - - - - - 1 - - - - - - - 0 - 32 - - - 1 - 0 - 0 - Border width - - - - - - dot_border_width_adjustment - - - - - - - - - - - - - - - - - - - - 1 - 0.050000000000000003 - 0.25 - - - 16 - 128 - 1 - 10 - - - 0.0 - 1 - 0.01 - 0.1 - - - 6 - 6 - 6 - 6 - - - - - 0 - 24 - 24 - 24 - 24 - vertical - 24 - - - 0 - - - - 0 - none - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Show the dock on - - 0 - 0 - - - - - - 0 - 400 - center - - - 1 - 0 - - - - - - Show on all monitors. - 12 - - - 0 - 2 - 2 - - - - - - - - - - - - - - - - 100 - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - 0 - Position on screen - - - - - - 0 - 32 - - - Left - end - center - - - - - - - Bottom - center - - position_left_button - - - - - - Top - center - - - position_left_button - - - - - - Right - center - - position_left_button - - - - - - - - - - - - - - - - - - - 0 - - - - 0 - none - - - 100 - 80 - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Hide the dock when it obstructs a window of the current application. More refined settings are available. - 1 - 0 - - - 0 - 1 - - - - - - 0 - 1 - start - Intelligent autohide - - - 0 - 0 - - - - - - 0 - 6 - - - 1 - center - center - - - - 0 - emblem-system-symbolic - - - - - - - - end - center - - - - 1 - 0 - 2 - - - - - - - - - - - - - - - - - 0 - - - - 0 - none - - - 100 - 80 - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - Dock size limit - - - 0 - 0 - - - - - - 1 - baseline - 1 - dock_size_adjustment - 0 - 2 - right - - - - - - Panel mode: extend to the screen edge - 12 - - - 0 - 1 - 2 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - Icon size limit - - - 0 - 0 - - - - - - 1 - baseline - 1 - icon_size_adjustment - 1 - 0 - right - - - 1 - 0 - - - - - - Fixed icon size: scroll to reveal other icons - 12 - - - 0 - 1 - 2 - - - - - - - - - - True - - - False - 12 - 12 - 12 - 12 - 32 - - - False - Preview size scale - 0 - - 0 - 0 - - - - - - 1 - 1 - preview_size_adjustment - 0 - 0 - 0 - 2 - right - - - - - - 0 - 1 - - - - - - - - - - - - - - - - - 0 - Position and size - - - - - - - 1 - - - 0 - 24 - 24 - 24 - 24 - vertical - 24 - - - 0 - - - - 0 - none - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - - - - - - 0 - 1 - start - Show favorite applications - - - 0 - 0 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - - - - - - 0 - 1 - start - Show running applications - - - 0 - 0 - - - - - - Isolate workspaces. - start - 12 - - - 0 - 2 - 2 - - - - - - Isolate monitors. - start - 12 - - - 0 - 3 - 2 - - - - - - 3 - Show open windows previews. - - 0 - 1 - 2 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - - - - - - 0 - 1 - start - Keep the focused application always visible in the dash - - - 0 - 0 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - 2 - - - - - - 0 - 1 - If disabled, these settings are accessible from gnome-tweak-tool or the extension website. - 1 - 0 - - - 0 - 1 - - - - - - 0 - 1 - start - Show <i>Applications</i> icon - 1 - - - 0 - 0 - - - - - - Move the applications button at the beginning of the dock. - start - 12 - - - 0 - 2 - 2 - - - - - - - 3 - - - 0 - start - Animate <i>Show Applications</i>. - 1 - - - - 0 - 3 - 2 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - - - - - - 0 - 1 - start - Show trash can - - - 0 - 0 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - - - - - - 0 - 1 - start - Show mounted volumes and devices - - - 0 - 0 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - - - - - - 0 - 1 - start - Isolate volumes, devices and trash windows from file manager - - - 0 - 0 - - - - - - - - - - - - - - - - - - - 0 - Launchers - - - - - - - 2 - - - 0 - 24 - 24 - 24 - 24 - vertical - 24 - - - 0 - - - - 0 - none - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - start - 1 - Enable Super+(0-9) as shortcuts to activate apps. It can also be used together with Shift and Ctrl. - 1 - 1 - 0 - - - - 0 - 1 - - - - - - 0 - 1 - start - Use keyboard shortcuts to activate apps - - - 0 - 0 - - - - - - 0 - 6 - - - 1 - center - center - - - - 0 - emblem-system-symbolic - - - - - - - - end - center - - - - 1 - 0 - 2 - - - - - - - - - - - - - - - - - 0 - - - - 0 - none - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Behaviour when clicking on the icon of a running application. - 1 - 0 - - - - 0 - 1 - - - - - - 0 - 1 - start - Click action - 0 - - - 0 - 0 - - - - - - 0 - 6 - - - 1 - center - - - 0 - emblem-system-symbolic - - - - - - - - 0 - center - - Raise window - Minimize - Launch new instance - Cycle through windows - Minimize or overview - Show window previews - Minimize or show previews - Focus or show previews - Focus, minimize or show previews - - - - - 1 - 0 - 2 - - - - - - - - - - - - - - - - - 0 - - - - 0 - none - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Behaviour when scrolling on the icon of an application. - 1 - 0 - - - - 0 - 1 - - - - - - 0 - 1 - start - Scroll action - - - 0 - 0 - - - - - - 0 - 6 - - - 0 - center - - Do nothing - Cycle through windows - Switch workspace - - - - - 1 - 0 - 2 - - - - - - - - - - - - - - - - - - - 0 - start - Behavior - - - - - - - 3 - - - 0 - 24 - 24 - 24 - 24 - vertical - 24 - - - 0 - - - - none - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Few customizations meant to integrate the dock with the default GNOME theme. Alternatively, specific options can be enabled below. - 1 - 0 - - - - 0 - 1 - - - - - - 0 - 1 - start - Use built-in theme - - - 0 - 0 - - - - - - end - center - - 1 - 0 - 2 - - - - - - - - - - - - - - - - - 0 - - - - 0 - none - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - 2 - - - - - - 0 - 1 - start - Save space reducing padding and border radius. - - - - 0 - 1 - - - - - - 0 - 1 - start - Shrink the dash - - - 0 - 0 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Customize windows counter indicators - - - 0 - 0 - - - - - - 0 - 6 - - - 1 - center - center - - - - 0 - emblem-system-symbolic - - - - - - - - 0 - - Default - Dots - Squares - Dashes - Segmented - Solid - Ciliora - Metro - - - - - 1 - 0 - 2 - - - - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Set the background color for the dash. - 1 - 0 - - - - 0 - 1 - - - - - - 0 - 1 - start - Customize the dash color - - - 0 - 0 - - - - - - 0 - 6 - - - 1 - center - center - - - - - - end - center - - - - 1 - 0 - 2 - - - - - - - - - - - - 0 - vertical - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Tune the dash background opacity. - - - - 0 - 1 - - - - - - 0 - 1 - start - Customize opacity - - - 0 - 0 - - - - - - 0 - 6 - - - 1 - center - center - - - 0 - emblem-system-symbolic - - - - - - - - 0 - center - - Default - Fixed - Dynamic - - - - - 1 - 0 - 2 - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - Opacity - - - - - 1 - 1 - custom_opacity_adjustement - - 0 - 0 - 0 - 2 - right - - - - - - - - - - - - 100 - 80 - - - 0 - 32 - 12 - 12 - 12 - 12 - - - 1 - 0 - center - start - Force straight corner - - - - - - center - 3 - - - - - - - - - - - - - - - - - - 0 - Appearance - - - - - - - 4 - - - 0 - 0 - 24 - 24 - 1 - 1 - vertical - 5 - - - - - - 0 - <b>Dash to Dock</b> - 1 - - - - - 0 - center - - - 0 - end - version: - - - - - 0 - start - ... - - - - - - - 0 - Moves the dash out of the overview transforming it in a dock - center - 1 - 0 - - - - - 0 - center - 5 - - - 0 - Created by - - - - - Michele (<a href="mailto:micxgx@gmail.com">micxgx@gmail.com</a>) - 1 - - - - - - - Webpage - 1 - center - - https://micheleg.github.io/dash-to-dock/ - - - - - 1 - end - <span size="small">This program comes with ABSOLUTELY NO WARRANTY. -See the <a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html">GNU General Public License, version 2 or later</a> for details.</span> - 1 - center - 1 - 0 - - - - - - - 0 - About - - - - - - - 1 - 0.01 - 0.10000000000000001 - - - 1 - 0.01 - 0.10000000000000001 - - - 1 - 1 - 0 - 12 - 12 - 12 - 12 - vertical - - - 0 - - - - 0 - none - - - 100 - 80 - - - 0 - 12 - 12 - 12 - 12 - vertical - 12 - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - Customize minimum and maximum opacity values - fill - 0 - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - Minimum opacity - - - - - 1 - 1 - min_opacity_adjustement - - 0 - 0 - 0 - 2 - right - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - Maximum opacity - - - - - 1 - 1 - max_opacity_adjustement - - 0 - 0 - 0 - 2 - right - - - - - - - - - - - - - - - - - - - 1000 - 50 - 250 - - - 10 - 0.25 - 1 - - - 1 - 1 - 12 - 12 - 12 - 12 - vertical - - - - - none - - - 100 - 80 - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - 2 - - - - - - 0 - 1 - Number overlay - - - 0 - 0 - - - - - - 0 - Temporarily show the application numbers over the icons, corresponding to the shortcut. - 1 - 0 - 40 - - - - 0 - 1 - - - - - - - - - - 100 - 80 - - - 0 - 12 - 12 - 12 - 12 - 32 - - - end - center - - 1 - 0 - 2 - - - - - - 0 - 1 - start - Show the dock if it is hidden - - - 0 - 0 - - - - - - 0 - If using autohide, the dock will appear for a short time when triggering the shortcut. - 1 - 0 - 40 - - - - 0 - 1 - - - - - - - - - - 100 - 80 - - - 12 - 12 - 12 - 12 - 32 - - - center - 12 - - 1 - 0 - - - - - - 0 - 1 - Shortcut for the options above - - - 0 - 0 - - - - - - 0 - Syntax: <Shift>, <Ctrl>, <Alt>, <Super> - 1 - 0 - 40 - - - - 0 - 1 - - - - - - - - - - - - - - - 12 - 12 - 12 - 12 - 1 - 6 - 32 - - - end - shortcut_time_adjustment - 3 - - 1 - 0 - - - - - - 0 - 1 - Hide timeout (s) - - - 0 - 0 - - - - - - - - - - - - - - - - - 1 - 0.050000000000000003 - 0.25 - - - 1 - 1 - 0 - 12 - 12 - 12 - 12 - vertical - - - 0 - - - - 0 - none - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Show the dock by mouse hover on the screen edge. - 1 - 0 - - - - 0 - 1 - - - - - - 0 - 1 - Autohide - - - 0 - 0 - - - - - - end - center - - 1 - 0 - 2 - - - - - - Push to show: require pressure to show the dock - - - 0 - 3 - 2 - - - - - - Enable in fullscreen mode - 12 - - - 0 - 2 - 2 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 32 - - - 0 - 1 - start - Show the dock when it doesn't obstruct application windows. - 1 - 0 - - - - 0 - 1 - - - - - - 0 - 1 - Dodge windows - - - 0 - 0 - - - - - - end - center - - 1 - 0 - 2 - - - - - - 0 - vertical - - - All windows - 12 - - - - - - - Only focused application's windows - all_windows_radio_button - - - - - - Only maximized windows - all_windows_radio_button - - - - - 0 - 2 - 2 - - - - - - - - - - - - 0 - 12 - 12 - 12 - 12 - 1 - 6 - 32 - - - end - animation_time_adjustment - 3 - - 1 - 0 - - - - - - 0 - 1 - Animation duration (s) - - - 0 - 0 - - - - - - end - hide_timeout_adjustment - 3 - - 1 - 1 - - - - - - end - show_timeout_adjustment - 3 - - 1 - 2 - - - - - - 0.000 - pressure_threshold_adjustment - - 1 - 3 - - - - - - 0 - 1 - Hide timeout (s) - - - 0 - 1 - - - - - - 0 - 1 - Show timeout (s) - - - 0 - 2 - - - - - - 0 - 1 - Pressure threshold - - - 0 - 3 - - - - - - - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/appIconIndicators.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/appIconIndicators.js deleted file mode 100644 index c1839bf..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/appIconIndicators.js +++ /dev/null @@ -1,1031 +0,0 @@ -const Cairo = imports.cairo; -const Clutter = imports.gi.Clutter; -const GdkPixbuf = imports.gi.GdkPixbuf -const Gio = imports.gi.Gio; -const Graphene = imports.gi.Graphene; -const Gtk = imports.gi.Gtk; -const Main = imports.ui.main; -const Pango = imports.gi.Pango; -const Shell = imports.gi.Shell; -const St = imports.gi.St; - -const Util = imports.misc.util; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Docking = Me.imports.docking; -const Utils = Me.imports.utils; - -let tracker = Shell.WindowTracker.get_default(); - -const RunningIndicatorStyle = { - DEFAULT: 0, - DOTS: 1, - SQUARES: 2, - DASHES: 3, - SEGMENTED: 4, - SOLID: 5, - CILIORA: 6, - METRO: 7 -}; - -const MAX_WINDOWS_CLASSES = 4; - - -/* - * This is the main indicator class to be used. The desired bahviour is - * obtained by composing the desired classes below based on the settings. - * - */ -var AppIconIndicator = class DashToDock_AppIconIndicator { - - constructor(source) { - this._indicators = []; - - // Unity indicators always enabled for now - let unityIndicator = new UnityIndicator(source); - this._indicators.push(unityIndicator); - - // Choose the style for the running indicators - let runningIndicator = null; - let runningIndicatorStyle; - - let settings = Docking.DockManager.settings; - if (settings.get_boolean('apply-custom-theme' )) { - runningIndicatorStyle = RunningIndicatorStyle.DOTS; - } else { - runningIndicatorStyle = settings.get_enum('running-indicator-style'); - } - - switch (runningIndicatorStyle) { - case RunningIndicatorStyle.DEFAULT: - runningIndicator = new RunningIndicatorDefault(source); - break; - - case RunningIndicatorStyle.DOTS: - runningIndicator = new RunningIndicatorDots(source); - break; - - case RunningIndicatorStyle.SQUARES: - runningIndicator = new RunningIndicatorSquares(source); - break; - - case RunningIndicatorStyle.DASHES: - runningIndicator = new RunningIndicatorDashes(source); - break; - - case RunningIndicatorStyle.SEGMENTED: - runningIndicator = new RunningIndicatorSegmented(source); - break; - - case RunningIndicatorStyle.SOLID: - runningIndicator = new RunningIndicatorSolid(source); - break; - - case RunningIndicatorStyle.CILIORA: - runningIndicator = new RunningIndicatorCiliora(source); - break; - - case RunningIndicatorStyle.METRO: - runningIndicator = new RunningIndicatorMetro(source); - break; - - default: - runningIndicator = new RunningIndicatorBase(source); - } - - this._indicators.push(runningIndicator); - } - - update() { - for (let i=0; i this.update()); - this._signalsHandler.add(this._source, 'notify::focused', () => this.update()); - this._signalsHandler.add(this._source, 'notify::windows-count', () => this._updateCounterClass()); - this.update(); - } - - get _number() { - return Math.min(this._source.windowsCount, MAX_WINDOWS_CLASSES); - } - - update() { - this._updateCounterClass(); - this._updateDefaultDot(); - } - - _updateCounterClass() { - for (let i = 1; i <= MAX_WINDOWS_CLASSES; i++) { - let className = 'running' + i; - if (i != this._number) - this._source.remove_style_class_name(className); - else - this._source.add_style_class_name(className); - } - } - - _updateDefaultDot() { - if (this._source.running) - this._source._dot.show(); - else - this._source._dot.hide(); - } - - _hideDefaultDot() { - // I use opacity to hide the default dot because the show/hide function - // are used by the parent class. - this._source._dot.opacity = 0; - } - - _restoreDefaultDot() { - this._source._dot.opacity = 255; - } - - _enableBacklight() { - - let colorPalette = this._dominantColorExtractor._getColorPalette(); - - // Fallback - if (colorPalette === null) { - this._source._iconContainer.set_style( - 'border-radius: 5px;' + - 'background-gradient-direction: vertical;' + - 'background-gradient-start: #e0e0e0;' + - 'background-gradient-end: darkgray;' - ); - - return; - } - - this._source._iconContainer.set_style( - 'border-radius: 5px;' + - 'background-gradient-direction: vertical;' + - 'background-gradient-start: ' + colorPalette.original + ';' + - 'background-gradient-end: ' + colorPalette.darker + ';' - ); - - } - - _disableBacklight() { - this._source._iconContainer.set_style(null); - } - - destroy() { - this._disableBacklight(); - // Remove glossy background if the children still exists - if (this._source._iconContainer.get_children().length > 1) - this._source._iconContainer.get_children()[1].set_style(null); - this._restoreDefaultDot(); - - super.destroy(); - } -}; - -// We add a css class so third parties themes can limit their indicaor customization -// to the case we do nothing -var RunningIndicatorDefault = class DashToDock_RunningIndicatorDefault extends RunningIndicatorBase { - - constructor(source) { - super(source); - this._source.add_style_class_name('default'); - } - - destroy() { - this._source.remove_style_class_name('default'); - super.destroy(); - } -}; - -var RunningIndicatorDots = class DashToDock_RunningIndicatorDots extends RunningIndicatorBase { - - constructor(source) { - super(source) - - this._hideDefaultDot(); - - this._area = new St.DrawingArea({x_expand: true, y_expand: true}); - - // We draw for the bottom case and rotate the canvas for other placements - //set center of rotatoins to the center - this._area.set_pivot_point(0.5, 0.5); - // prepare transformation matrix - let m = new Graphene.Matrix(); - m.init_identity(); - let v = new Graphene.Vec3(); - v.init(0, 0, 1); - - switch (this._side) { - case St.Side.TOP: - m.xx = -1; - m.rotate(180, v); - break - - case St.Side.BOTTOM: - // nothing - break; - - case St.Side.LEFT: - m.yy = -1; - m.rotate(90, v); - break; - - case St.Side.RIGHT: - m.rotate(-90, v); - break - } - - this._area.set_transform(m); - - this._area.connect('repaint', this._updateIndicator.bind(this)); - this._source._iconContainer.add_child(this._area); - - let keys = ['custom-theme-running-dots-color', - 'custom-theme-running-dots-border-color', - 'custom-theme-running-dots-border-width', - 'custom-theme-customize-running-dots', - 'unity-backlit-items', - 'running-indicator-dominant-color']; - - keys.forEach(function(key) { - this._signalsHandler.add( - Docking.DockManager.settings, - 'changed::' + key, - this.update.bind(this) - ); - }, this); - - // Apply glossy background - // TODO: move to enable/disableBacklit to apply itonly to the running apps? - // TODO: move to css class for theming support - this._glossyBackgroundStyle = 'background-image: url(\'' + Me.path + '/media/glossy.svg\');' + - 'background-size: contain;'; - } - - update() { - super.update(); - - // Enable / Disable the backlight of running apps - if (!Docking.DockManager.settings.get_boolean('apply-custom-theme') && - Docking.DockManager.settings.get_boolean('unity-backlit-items')) { - this._source._iconContainer.get_children()[1].set_style(this._glossyBackgroundStyle); - if (this._source.running) - this._enableBacklight(); - else - this._disableBacklight(); - } else { - this._disableBacklight(); - this._source._iconContainer.get_children()[1].set_style(null); - } - - if (this._area) - this._area.queue_repaint(); - } - - _computeStyle() { - - let [width, height] = this._area.get_surface_size(); - this._width = height; - this._height = width; - - // By defaut re-use the style - background color, and border width and color - - // of the default dot - let themeNode = this._source._dot.get_theme_node(); - this._borderColor = themeNode.get_border_color(this._side); - this._borderWidth = themeNode.get_border_width(this._side); - this._bodyColor = themeNode.get_background_color(); - - let settings = Docking.DockManager.settings; - if (!settings.get_boolean('apply-custom-theme')) { - // Adjust for the backlit case - if (settings.get_boolean('unity-backlit-items')) { - // Use dominant color for dots too if the backlit is enables - let colorPalette = this._dominantColorExtractor._getColorPalette(); - - // Slightly adjust the styling - this._borderWidth = 2; - - if (colorPalette !== null) { - this._borderColor = Clutter.color_from_string(colorPalette.lighter)[1] ; - this._bodyColor = Clutter.color_from_string(colorPalette.darker)[1]; - } else { - // Fallback - this._borderColor = Clutter.color_from_string('white')[1]; - this._bodyColor = Clutter.color_from_string('gray')[1]; - } - } - - // Apply dominant color if requested - if (settings.get_boolean('running-indicator-dominant-color')) { - let colorPalette = this._dominantColorExtractor._getColorPalette(); - if (colorPalette !== null) { - this._bodyColor = Clutter.color_from_string(colorPalette.original)[1]; - } - } - - // Finally, use customize style if requested - if (settings.get_boolean('custom-theme-customize-running-dots')) { - this._borderColor = Clutter.color_from_string(settings.get_string('custom-theme-running-dots-border-color'))[1]; - this._borderWidth = settings.get_int('custom-theme-running-dots-border-width'); - this._bodyColor = Clutter.color_from_string(settings.get_string('custom-theme-running-dots-color'))[1]; - } - } - - // Define the radius as an arbitrary size, but keep large enough to account - // for the drawing of the border. - this._radius = Math.max(this._width/22, this._borderWidth/2); - this._padding = 0; // distance from the margin - this._spacing = this._radius + this._borderWidth; // separation between the dots - } - - _updateIndicator() { - - let area = this._area; - let cr = this._area.get_context(); - - this._computeStyle(); - this._drawIndicator(cr); - cr.$dispose(); - } - - _drawIndicator(cr) { - // Draw the required numbers of dots - let n = this._number; - - cr.setLineWidth(this._borderWidth); - Clutter.cairo_set_source_color(cr, this._borderColor); - - // draw for the bottom case: - cr.translate((this._width - (2*n)*this._radius - (n-1)*this._spacing)/2, this._height - this._padding); - for (let i = 0; i < n; i++) { - cr.newSubPath(); - cr.arc((2*i+1)*this._radius + i*this._spacing, -this._radius - this._borderWidth/2, this._radius, 0, 2*Math.PI); - } - - cr.strokePreserve(); - Clutter.cairo_set_source_color(cr, this._bodyColor); - cr.fill(); - } - - destroy() { - this._area.destroy(); - super.destroy(); - } -}; - -// Adapted from dash-to-panel by Jason DeRose -// https://github.com/jderose9/dash-to-panel -var RunningIndicatorCiliora = class DashToDock_RunningIndicatorCiliora extends RunningIndicatorDots { - - _drawIndicator(cr) { - if (this._source.running) { - let size = Math.max(this._width/20, this._borderWidth); - let spacing = size; // separation between the dots - let lineLength = this._width - (size*(this._number-1)) - (spacing*(this._number-1)); - let padding = this._borderWidth; - // For the backlit case here we don't want the outer border visible - if (Docking.DockManager.settings.get_boolean('unity-backlit-items') && - !Docking.DockManager.settings.get_boolean('custom-theme-customize-running-dots')) - padding = 0; - let yOffset = this._height - padding - size; - - cr.setLineWidth(this._borderWidth); - Clutter.cairo_set_source_color(cr, this._borderColor); - - cr.translate(0, yOffset); - cr.newSubPath(); - cr.rectangle(0, 0, lineLength, size); - for (let i = 1; i < this._number; i++) { - cr.newSubPath(); - cr.rectangle(lineLength + (i*spacing) + ((i-1)*size), 0, size, size); - } - - cr.strokePreserve(); - Clutter.cairo_set_source_color(cr, this._bodyColor); - cr.fill(); - } - } -}; - -// Adapted from dash-to-panel by Jason DeRose -// https://github.com/jderose9/dash-to-panel -var RunningIndicatorSegmented = class DashToDock_RunningIndicatorSegmented extends RunningIndicatorDots { - - _drawIndicator(cr) { - if (this._source.running) { - let size = Math.max(this._width/20, this._borderWidth); - let spacing = Math.ceil(this._width/18); // separation between the dots - let dashLength = Math.ceil((this._width - ((this._number-1)*spacing))/this._number); - let lineLength = this._width - (size*(this._number-1)) - (spacing*(this._number-1)); - let padding = this._borderWidth; - // For the backlit case here we don't want the outer border visible - if (Docking.DockManager.settings.get_boolean('unity-backlit-items') && - !Docking.DockManager.settings.get_boolean('custom-theme-customize-running-dots')) - padding = 0; - let yOffset = this._height - padding - size; - - cr.setLineWidth(this._borderWidth); - Clutter.cairo_set_source_color(cr, this._borderColor); - - cr.translate(0, yOffset); - for (let i = 0; i < this._number; i++) { - cr.newSubPath(); - cr.rectangle(i*dashLength + i*spacing, 0, dashLength, size); - } - - cr.strokePreserve(); - Clutter.cairo_set_source_color(cr, this._bodyColor); - cr.fill() - } - } -}; - -// Adapted from dash-to-panel by Jason DeRose -// https://github.com/jderose9/dash-to-panel -var RunningIndicatorSolid = class DashToDock_RunningIndicatorSolid extends RunningIndicatorDots { - - _drawIndicator(cr) { - if (this._source.running) { - let size = Math.max(this._width/20, this._borderWidth); - let padding = this._borderWidth; - // For the backlit case here we don't want the outer border visible - if (Docking.DockManager.settings.get_boolean('unity-backlit-items') && - !Docking.DockManager.settings.get_boolean('custom-theme-customize-running-dots')) - padding = 0; - let yOffset = this._height - padding - size; - - cr.setLineWidth(this._borderWidth); - Clutter.cairo_set_source_color(cr, this._borderColor); - - cr.translate(0, yOffset); - cr.newSubPath(); - cr.rectangle(0, 0, this._width, size); - - cr.strokePreserve(); - Clutter.cairo_set_source_color(cr, this._bodyColor); - cr.fill(); - } - } -}; - -// Adapted from dash-to-panel by Jason DeRose -// https://github.com/jderose9/dash-to-panel -var RunningIndicatorSquares = class DashToDock_RunningIndicatorSquares extends RunningIndicatorDots { - - _drawIndicator(cr) { - if (this._source.running) { - let size = Math.max(this._width/11, this._borderWidth); - let padding = this._borderWidth; - let spacing = Math.ceil(this._width/18); // separation between the dots - let yOffset = this._height - padding - size; - - cr.setLineWidth(this._borderWidth); - Clutter.cairo_set_source_color(cr, this._borderColor); - - cr.translate(Math.floor((this._width - this._number*size - (this._number-1)*spacing)/2), yOffset); - for (let i = 0; i < this._number; i++) { - cr.newSubPath(); - cr.rectangle(i*size + i*spacing, 0, size, size); - } - cr.strokePreserve(); - Clutter.cairo_set_source_color(cr, this._bodyColor); - cr.fill(); - } - } -} - -// Adapted from dash-to-panel by Jason DeRose -// https://github.com/jderose9/dash-to-panel -var RunningIndicatorDashes = class DashToDock_RunningIndicatorDashes extends RunningIndicatorDots { - - _drawIndicator(cr) { - if (this._source.running) { - let size = Math.max(this._width/20, this._borderWidth); - let padding = this._borderWidth; - let spacing = Math.ceil(this._width/18); // separation between the dots - let dashLength = Math.floor(this._width/4) - spacing; - let yOffset = this._height - padding - size; - - cr.setLineWidth(this._borderWidth); - Clutter.cairo_set_source_color(cr, this._borderColor); - - cr.translate(Math.floor((this._width - this._number*dashLength - (this._number-1)*spacing)/2), yOffset); - for (let i = 0; i < this._number; i++) { - cr.newSubPath(); - cr.rectangle(i*dashLength + i*spacing, 0, dashLength, size); - } - - cr.strokePreserve(); - Clutter.cairo_set_source_color(cr, this._bodyColor); - cr.fill(); - } - } -} - -// Adapted from dash-to-panel by Jason DeRose -// https://github.com/jderose9/dash-to-panel -var RunningIndicatorMetro = class DashToDock_RunningIndicatorMetro extends RunningIndicatorDots { - - constructor(source) { - super(source); - this._source.add_style_class_name('metro'); - } - - destroy() { - this._source.remove_style_class_name('metro'); - super.destroy(); - } - - _drawIndicator(cr) { - if (this._source.running) { - let size = Math.max(this._width/20, this._borderWidth); - let padding = 0; - // For the backlit case here we don't want the outer border visible - if (Docking.DockManager.settings.get_boolean('unity-backlit-items') && - !Docking.DockManager.settings.get_boolean('custom-theme-customize-running-dots')) - padding = 0; - let yOffset = this._height - padding - size; - - let n = this._number; - if(n <= 1) { - cr.translate(0, yOffset); - Clutter.cairo_set_source_color(cr, this._bodyColor); - cr.newSubPath(); - cr.rectangle(0, 0, this._width, size); - cr.fill(); - } else { - let blackenedLength = (1/48)*this._width; // need to scale with the SVG for the stacked highlight - let darkenedLength = this._source.focused ? (2/48)*this._width : (10/48)*this._width; - let blackenedColor = this._bodyColor.shade(.3); - let darkenedColor = this._bodyColor.shade(.7); - - cr.translate(0, yOffset); - - Clutter.cairo_set_source_color(cr, this._bodyColor); - cr.newSubPath(); - cr.rectangle(0, 0, this._width - darkenedLength - blackenedLength, size); - cr.fill(); - Clutter.cairo_set_source_color(cr, blackenedColor); - cr.newSubPath(); - cr.rectangle(this._width - darkenedLength - blackenedLength, 0, 1, size); - cr.fill(); - Clutter.cairo_set_source_color(cr, darkenedColor); - cr.newSubPath(); - cr.rectangle(this._width - darkenedLength, 0, darkenedLength, size); - cr.fill(); - } - } - } -} - -/* - * Unity like notification and progress indicators - */ -var UnityIndicator = class DashToDock_UnityIndicator extends IndicatorBase { - - constructor(source) { - - super(source); - - this._notificationBadgeLabel = new St.Label(); - this._notificationBadgeBin = new St.Bin({ - child: this._notificationBadgeLabel, - x_align: Clutter.ActorAlign.END, - y_align: Clutter.ActorAlign.START, - x_expand: true, y_expand: true - }); - this._notificationBadgeLabel.add_style_class_name('notification-badge'); - this._notificationBadgeLabel.clutter_text.ellipsize = Pango.EllipsizeMode.MIDDLE; - this._notificationBadgeBin.hide(); - - this._source._iconContainer.add_child(this._notificationBadgeBin); - this.updateNotificationBadgeStyle(); - - const { remoteModel } = Docking.DockManager.getDefault(); - const remoteEntry = remoteModel.lookupById(this._source.app.id); - this._signalsHandler.add([ - remoteEntry, - ['count-changed', 'count-visible-changed'], - (sender, { count, count_visible }) => - this.setNotificationCount(count_visible ? count : 0) - ], [ - remoteEntry, - ['progress-changed', 'progress-visible-changed'], - (sender, { progress, progress_visible }) => - this.setProgress(progress_visible ? progress : -1) - ], [ - remoteEntry, - 'urgent-changed', - (sender, { urgent }) => this.setUrgent(urgent) - ], [ - St.ThemeContext.get_for_stage(global.stage), - 'changed', - this.updateNotificationBadgeStyle.bind(this) - ], [ - this._source._iconContainer, - 'notify::size', - this.updateNotificationBadgeStyle.bind(this) - ]); - } - - updateNotificationBadgeStyle() { - let themeContext = St.ThemeContext.get_for_stage(global.stage); - let fontDesc = themeContext.get_font(); - let defaultFontSize = fontDesc.get_size() / 1024; - let fontSize = defaultFontSize * 0.9; - let iconSize = Main.overview.dash.iconSize; - let defaultIconSize = Docking.DockManager.settings.get_default_value( - 'dash-max-icon-size').unpack(); - - if (!fontDesc.get_size_is_absolute()) { - // fontSize was exprimed in points, so convert to pixel - fontSize /= 0.75; - } - - fontSize = Math.round((iconSize / defaultIconSize) * fontSize); - let leftMargin = Math.round((iconSize / defaultIconSize) * 3); - - this._notificationBadgeLabel.set_style( - 'font-size: ' + fontSize + 'px;' + - 'margin-left: ' + leftMargin + 'px' - ); - } - - _notificationBadgeCountToText(count) { - if (count <= 9999) { - return count.toString(); - } else if (count < 1e5) { - let thousands = count / 1e3; - return thousands.toFixed(1).toString() + "k"; - } else if (count < 1e6) { - let thousands = count / 1e3; - return thousands.toFixed(0).toString() + "k"; - } else if (count < 1e8) { - let millions = count / 1e6; - return millions.toFixed(1).toString() + "M"; - } else if (count < 1e9) { - let millions = count / 1e6; - return millions.toFixed(0).toString() + "M"; - } else { - let billions = count / 1e9; - return billions.toFixed(1).toString() + "B"; - } - } - - setNotificationCount(count) { - if (count > 0) { - let text = this._notificationBadgeCountToText(count); - this._notificationBadgeLabel.set_text(text); - this._notificationBadgeBin.show(); - } else { - this._notificationBadgeBin.hide(); - } - } - - _showProgressOverlay() { - if (this._progressOverlayArea) { - this._updateProgressOverlay(); - return; - } - - this._progressOverlayArea = new St.DrawingArea({x_expand: true, y_expand: true}); - this._progressOverlayArea.add_style_class_name('progress-bar'); - this._progressOverlayArea.connect('repaint', () => { - this._drawProgressOverlay(this._progressOverlayArea); - }); - - this._source._iconContainer.add_child(this._progressOverlayArea); - let node = this._progressOverlayArea.get_theme_node(); - - let [hasColor, color] = node.lookup_color('-progress-bar-background', false); - if (hasColor) - this._progressbar_background = color - else - this._progressbar_background = new Clutter.Color({red: 204, green: 204, blue: 204, alpha: 255}); - - [hasColor, color] = node.lookup_color('-progress-bar-border', false); - if (hasColor) - this._progressbar_border = color; - else - this._progressbar_border = new Clutter.Color({red: 230, green: 230, blue: 230, alpha: 255}); - - this._updateProgressOverlay(); - } - - _hideProgressOverlay() { - if (this._progressOverlayArea) - this._progressOverlayArea.destroy(); - this._progressOverlayArea = null; - this._progressbar_background = null; - this._progressbar_border = null; - } - - _updateProgressOverlay() { - if (this._progressOverlayArea) - this._progressOverlayArea.queue_repaint(); - } - - _drawProgressOverlay(area) { - let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - let [surfaceWidth, surfaceHeight] = area.get_surface_size(); - let cr = area.get_context(); - - let iconSize = this._source.icon.iconSize * scaleFactor; - - let x = Math.floor((surfaceWidth - iconSize) / 2); - let y = Math.floor((surfaceHeight - iconSize) / 2); - - let lineWidth = Math.floor(1.0 * scaleFactor); - let padding = Math.floor(iconSize * 0.05); - let width = iconSize - 2.0*padding; - let height = Math.floor(Math.min(18.0*scaleFactor, 0.20*iconSize)); - x += padding; - y += iconSize - height - padding; - - cr.setLineWidth(lineWidth); - - // Draw the outer stroke - let stroke = new Cairo.LinearGradient(0, y, 0, y + height); - let fill = null; - stroke.addColorStopRGBA(0.5, 0.5, 0.5, 0.5, 0.1); - stroke.addColorStopRGBA(0.9, 0.8, 0.8, 0.8, 0.4); - Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); - - // Draw the background - x += lineWidth; - y += lineWidth; - width -= 2.0*lineWidth; - height -= 2.0*lineWidth; - - stroke = Cairo.SolidPattern.createRGBA(0.20, 0.20, 0.20, 0.9); - fill = new Cairo.LinearGradient(0, y, 0, y + height); - fill.addColorStopRGBA(0.4, 0.25, 0.25, 0.25, 1.0); - fill.addColorStopRGBA(0.9, 0.35, 0.35, 0.35, 1.0); - Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill); - - // Draw the finished bar - x += lineWidth; - y += lineWidth; - width -= 2.0*lineWidth; - height -= 2.0*lineWidth; - - let finishedWidth = Math.ceil(this._progress * width); - - let bg = this._progressbar_background; - let bd = this._progressbar_border; - - stroke = Cairo.SolidPattern.createRGBA(bd.red/255, bd.green/255, bd.blue/255, bd.alpha/255); - fill = Cairo.SolidPattern.createRGBA(bg.red/255, bg.green/255, bg.blue/255, bg.alpha/255); - - if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) - Utils.drawRoundedLine(cr, x + lineWidth/2.0 + width - finishedWidth, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); - else - Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); - - cr.$dispose(); - } - - setProgress(progress) { - if (progress < 0) { - this._hideProgressOverlay(); - } else { - this._progress = Math.min(progress, 1.0); - this._showProgressOverlay(); - } - } - - setUrgent(urgent) { - if (urgent || this._isUrgent !== undefined) - this._source.urgent = urgent; - - if (urgent) - this._isUrgent = urgent; - else - delete this._isUrgent; - } -} - - -// Global icon cache. Used for Unity7 styling. -let iconCacheMap = new Map(); -// Max number of items to store -// We don't expect to ever reach this number, but let's put an hard limit to avoid -// even the remote possibility of the cached items to grow indefinitely. -const MAX_CACHED_ITEMS = 1000; -// When the size exceed it, the oldest 'n' ones are deleted -const BATCH_SIZE_TO_DELETE = 50; -// The icon size used to extract the dominant color -const DOMINANT_COLOR_ICON_SIZE = 64; - -// Compute dominant color frim the app icon. -// The color is cached for efficiency. -var DominantColorExtractor = class DashToDock_DominantColorExtractor { - - constructor(app) { - this._app = app; - } - - /** - * Try to get the pixel buffer for the current icon, if not fail gracefully - */ - _getIconPixBuf() { - let iconTexture = this._app.create_icon_texture(16); - const themeLoader = Docking.DockManager.iconTheme; - - // Unable to load the icon texture, use fallback - if (iconTexture instanceof St.Icon === false) { - return null; - } - - iconTexture = iconTexture.get_gicon(); - - // Unable to load the icon texture, use fallback - if (iconTexture === null) { - return null; - } - - if (iconTexture instanceof Gio.FileIcon) { - // Use GdkPixBuf to load the pixel buffer from the provided file path - return GdkPixbuf.Pixbuf.new_from_file(iconTexture.get_file().get_path()); - } - - // Get the pixel buffer from the icon theme - let icon_info = themeLoader.lookup_icon(iconTexture.get_names()[0], DOMINANT_COLOR_ICON_SIZE, 0); - if (icon_info !== null) - return icon_info.load_icon(); - else - return null; - } - - /** - * The backlight color choosing algorithm was mostly ported to javascript from the - * Unity7 C++ source of Canonicals: - * https://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/launcher/LauncherIcon.cpp - * so it more or less works the same way. - */ - _getColorPalette() { - if (iconCacheMap.get(this._app.get_id())) { - // We already know the answer - return iconCacheMap.get(this._app.get_id()); - } - - let pixBuf = this._getIconPixBuf(); - if (pixBuf == null) - return null; - - let pixels = pixBuf.get_pixels(), - offset = 0; - - let total = 0, - rTotal = 0, - gTotal = 0, - bTotal = 0; - - let resample_y = 1, - resample_x = 1; - - // Resampling of large icons - // We resample icons larger than twice the desired size, as the resampling - // to a size s - // DOMINANT_COLOR_ICON_SIZE < s < 2*DOMINANT_COLOR_ICON_SIZE, - // most of the case exactly DOMINANT_COLOR_ICON_SIZE as the icon size is tipycally - // a multiple of it. - let width = pixBuf.get_width(); - let height = pixBuf.get_height(); - - // Resample - if (height >= 2* DOMINANT_COLOR_ICON_SIZE) - resample_y = Math.floor(height/DOMINANT_COLOR_ICON_SIZE); - - if (width >= 2* DOMINANT_COLOR_ICON_SIZE) - resample_x = Math.floor(width/DOMINANT_COLOR_ICON_SIZE); - - if (resample_x !==1 || resample_y !== 1) - pixels = this._resamplePixels(pixels, resample_x, resample_y); - - // computing the limit outside the for (where it would be repeated at each iteration) - // for performance reasons - let limit = pixels.length; - for (let offset = 0; offset < limit; offset+=4) { - let r = pixels[offset], - g = pixels[offset + 1], - b = pixels[offset + 2], - a = pixels[offset + 3]; - - let saturation = (Math.max(r,g, b) - Math.min(r,g, b)); - let relevance = 0.1 * 255 * 255 + 0.9 * a * saturation; - - rTotal += r * relevance; - gTotal += g * relevance; - bTotal += b * relevance; - - total += relevance; - } - - total = total * 255; - - let r = rTotal / total, - g = gTotal / total, - b = bTotal / total; - - let hsv = Utils.ColorUtils.RGBtoHSV(r * 255, g * 255, b * 255); - - if (hsv.s > 0.15) - hsv.s = 0.65; - hsv.v = 0.90; - - let rgb = Utils.ColorUtils.HSVtoRGB(hsv.h, hsv.s, hsv.v); - - // Cache the result. - let backgroundColor = { - lighter: Utils.ColorUtils.ColorLuminance(rgb.r, rgb.g, rgb.b, 0.2), - original: Utils.ColorUtils.ColorLuminance(rgb.r, rgb.g, rgb.b, 0), - darker: Utils.ColorUtils.ColorLuminance(rgb.r, rgb.g, rgb.b, -0.5) - }; - - if (iconCacheMap.size >= MAX_CACHED_ITEMS) { - //delete oldest cached values (which are in order of insertions) - let ctr=0; - for (let key of iconCacheMap.keys()) { - if (++ctr > BATCH_SIZE_TO_DELETE) - break; - iconCacheMap.delete(key); - } - } - - iconCacheMap.set(this._app.get_id(), backgroundColor); - - return backgroundColor; - } - - /** - * Downsample large icons before scanning for the backlight color to - * improve performance. - * - * @param pixBuf - * @param pixels - * @param resampleX - * @param resampleY - * - * @return []; - */ - _resamplePixels (pixels, resampleX, resampleY) { - let resampledPixels = []; - // computing the limit outside the for (where it would be repeated at each iteration) - // for performance reasons - let limit = pixels.length / (resampleX * resampleY) / 4; - for (let i = 0; i < limit; i++) { - let pixel = i * resampleX * resampleY; - - resampledPixels.push(pixels[pixel * 4]); - resampledPixels.push(pixels[pixel * 4 + 1]); - resampledPixels.push(pixels[pixel * 4 + 2]); - resampledPixels.push(pixels[pixel * 4 + 3]); - } - - return resampledPixels; - } -}; diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/appIcons.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/appIcons.js deleted file mode 100644 index cca3641..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/appIcons.js +++ /dev/null @@ -1,1435 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const Clutter = imports.gi.Clutter; -const GdkPixbuf = imports.gi.GdkPixbuf -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Signals = imports.signals; -const Meta = imports.gi.Meta; -const Shell = imports.gi.Shell; -const St = imports.gi.St; - -// Use __ () and N__() for the extension gettext domain, and reuse -// the shell domain with the default _() and N_() -const Gettext = imports.gettext.domain('dashtodock'); -const __ = Gettext.gettext; -const N__ = function(e) { return e }; - -const AppDisplay = imports.ui.appDisplay; -const AppFavorites = imports.ui.appFavorites; -const BoxPointer = imports.ui.boxpointer; -const Dash = imports.ui.dash; -const DND = imports.ui.dnd; -const IconGrid = imports.ui.iconGrid; -const Main = imports.ui.main; -const ParentalControlsManager = imports.misc.parentalControlsManager; -const PopupMenu = imports.ui.popupMenu; -const Util = imports.misc.util; -const Workspace = imports.ui.workspace; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Docking = Me.imports.docking; -const Utils = Me.imports.utils; -const WindowPreview = Me.imports.windowPreview; -const AppIconIndicators = Me.imports.appIconIndicators; -const DbusmenuUtils = Me.imports.dbusmenuUtils; - -const tracker = Shell.WindowTracker.get_default(); - -const clickAction = { - SKIP: 0, - MINIMIZE: 1, - LAUNCH: 2, - CYCLE_WINDOWS: 3, - MINIMIZE_OR_OVERVIEW: 4, - PREVIEWS: 5, - MINIMIZE_OR_PREVIEWS: 6, - FOCUS_OR_PREVIEWS: 7, - FOCUS_MINIMIZE_OR_PREVIEWS: 8, - QUIT: 9 -}; - -const scrollAction = { - DO_NOTHING: 0, - CYCLE_WINDOWS: 1, - SWITCH_WORKSPACE: 2 -}; - -let recentlyClickedAppLoopId = 0; -let recentlyClickedApp = null; -let recentlyClickedAppWindows = null; -let recentlyClickedAppIndex = 0; -let recentlyClickedAppMonitor = -1; - -/** - * Extend AppIcon - * - * - Apply a css class based on the number of windows of each application (#N); - * - Customized indicators for running applications in place of the default "dot" style which is hidden (#N); - * a class of the form "running#N" is applied to the AppWellIcon actor. - * like the original .running one. - * - Add a .focused style to the focused app - * - Customize click actions. - * - Update minimization animation target - * - Update menu if open on windows change - */ -var DockAbstractAppIcon = GObject.registerClass({ - GTypeFlags: GObject.TypeFlags.ABSTRACT, - Properties: { - 'focused': GObject.ParamSpec.boolean( - 'focused', 'focused', 'focused', - GObject.ParamFlags.READWRITE, - false), - 'running': GObject.ParamSpec.boolean( - 'running', 'running', 'running', - GObject.ParamFlags.READWRITE, - false), - 'urgent': GObject.ParamSpec.boolean( - 'urgent', 'urgent', 'urgent', - GObject.ParamFlags.READWRITE, - false), - 'windows-count': GObject.ParamSpec.uint( - 'windows-count', 'windows-count', 'windows-count', - GObject.ParamFlags.READWRITE, - 0, GLib.MAXUINT32, 0), - } -}, class DockAbstractAppIcon extends Dash.DashIcon { - // settings are required inside. - _init(app, monitorIndex, iconAnimator) { - super._init(app); - - // a prefix is required to avoid conflicting with the parent class variable - this.monitorIndex = monitorIndex; - this._signalsHandler = new Utils.GlobalSignalsHandler(this); - this.iconAnimator = iconAnimator; - this._indicator = new AppIconIndicators.AppIconIndicator(this); - - // Monitor windows-changes instead of app state. - // Keep using the same Id and function callback (that is extended) - if (this._stateChangedId > 0) { - this.app.disconnect(this._stateChangedId); - this._stateChangedId = 0; - } - - this._signalsHandler.add(this.app, 'windows-changed', () => this._updateWindows()); - this._signalsHandler.add(this.app, 'notify::state', () => this._updateRunningState()); - this._signalsHandler.add(global.display, 'window-demands-attention', (_dpy, window) => - this._onWindowDemandsAttention(window)); - this._signalsHandler.add(global.display, 'window-marked-urgent', (_dpy, window) => - this._onWindowDemandsAttention(window)); - - // In Wayland sessions, this signal is needed to track the state of windows dragged - // from one monitor to another. As this is triggered quite often (whenever a new winow - // of any application opened or moved to a different desktop), - // we restrict this signal to the case when 'isolate-monitors' is true, - // and if there are at least 2 monitors. - if (Docking.DockManager.settings.get_boolean('isolate-monitors') && - Main.layoutManager.monitors.length > 1) { - this._signalsHandler.removeWithLabel('isolate-monitors'); - this._signalsHandler.addWithLabel('isolate-monitors', - global.display, - 'window-entered-monitor', - this._onWindowEntered.bind(this)); - } - - this.connect('notify::running', () => { - if (this.running) - this.add_style_class_name('running'); - else - this.remove_style_class_name('running'); - }); - - this.connect('notify::focused', () => { - if (this.focused) - this.add_style_class_name('focused'); - else - this.remove_style_class_name('focused'); - }) - - this.connect('notify::urgent', () => { - const icon = this.icon._iconBin; - this._signalsHandler.removeWithLabel('urgent-windows') - if (this.urgent) { - icon.set_pivot_point(0.5, 0.5); - this.iconAnimator.addAnimation(icon, 'dance'); - if (!this._urgentWindows.size) { - const urgentWindows = this.getInterestingWindows(); - urgentWindows.forEach(w => (w._manualUrgency = true)); - this._updateUrgentWindows(urgentWindows); - } - } else { - this.iconAnimator.removeAnimation(icon, 'dance'); - icon.rotation_angle_z = 0; - this._urgentWindows.forEach(w => (delete w._manualUrgency)); - this._updateUrgentWindows(); - } - }); - - this._urgentWindows = new Set(); - this._progressOverlayArea = null; - this._progress = 0; - - let keys = ['apply-custom-theme', - 'running-indicator-style', - ]; - - keys.forEach(key => { - this._signalsHandler.add( - Docking.DockManager.settings, - 'changed::' + key, () => { - this._indicator.destroy(); - this._indicator = new AppIconIndicators.AppIconIndicator(this); - } - ); - }); - - this._updateState(); - this._numberOverlay(); - this.updateIconGeometry(); - - this._previewMenuManager = null; - this._previewMenu = null; - } - - _onDestroy() { - super._onDestroy(); - - // This is necessary due to an upstream bug - // https://bugzilla.gnome.org/show_bug.cgi?id=757556 - // It can be safely removed once it get solved upstrea. - if (this._menu) - this._menu.close(false); - } - - ownsWindow(window) { - return this.app === tracker.get_window_app(window); - } - - _onWindowEntered(metaScreen, monitorIndex, metaWin) { - if (this.ownsWindow(metaWin)) - this._updateWindows(); - } - - vfunc_scroll_event(scrollEvent) { - let settings = Docking.DockManager.settings; - let isEnabled = settings.get_enum('scroll-action') === scrollAction.CYCLE_WINDOWS; - if (!isEnabled) - return Clutter.EVENT_PROPAGATE; - - // We only activate windows of running applications, i.e. we never open new windows - // We check if the app is running, and that the # of windows is > 0 in - // case we use workspace isolation, - if (!this.running) - return Clutter.EVENT_PROPAGATE; - - if (this._optionalScrollCycleWindowsDeadTimeId) - return Clutter.EVENT_PROPAGATE; - else - this._optionalScrollCycleWindowsDeadTimeId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, 250, () => { - this._optionalScrollCycleWindowsDeadTimeId = 0; - }); - - let direction = null; - - switch (scrollEvent.direction) { - case Clutter.ScrollDirection.UP: - direction = Meta.MotionDirection.UP; - break; - case Clutter.ScrollDirection.DOWN: - direction = Meta.MotionDirection.DOWN; - break; - case Clutter.ScrollDirection.SMOOTH: - let [, dy] = Clutter.get_current_event().get_scroll_delta(); - if (dy < 0) - direction = Meta.MotionDirection.UP; - else if (dy > 0) - direction = Meta.MotionDirection.DOWN; - break; - } - - if (!Main.overview.visible) { - let reversed = direction === Meta.MotionDirection.UP; - if (this.focused && !this._urgentWindows.size) - this._cycleThroughWindows(reversed); - else { - // Activate the first window - let windows = this.getInterestingWindows(); - if (windows.length > 0) { - let w = windows[0]; - Main.activateWindow(w); - } - } - } - else - this.app.activate(); - return Clutter.EVENT_STOP; - } - - _updateWindows() { - if (this._menu && this._menu.isOpen) - this._menu.update(); - - this._updateState(); - this.updateIconGeometry(); - } - - _updateState() { - this._urgentWindows.clear(); - const interestingWindows = this.getInterestingWindows(); - this.windowsCount = interestingWindows.length; - this._updateRunningState(); - this._updateFocusState(); - this._updateUrgentWindows(interestingWindows); - } - - _updateRunningState() { - this.running = (this.app.state === Shell.AppState.RUNNING) && this.windowsCount; - } - - _updateFocusState() { - this.focused = (tracker.focus_app === this.app && this.running); - } - - _updateUrgentWindows(interestingWindows) { - this._signalsHandler.removeWithLabel('urgent-windows') - this._urgentWindows.clear(); - if (interestingWindows === undefined) - interestingWindows = this.getInterestingWindows(); - interestingWindows.forEach(win => { - if (win.urgent || win.demandsAttention || win._manualUrgency) - this._addUrgentWindow(win); - }); - this.urgent = !!this._urgentWindows.size; - } - - _onWindowDemandsAttention(window) { - if (this.ownsWindow(window)) - this._addUrgentWindow(window); - } - - _addUrgentWindow(window) { - if (this._urgentWindows.has(window)) - return; - - if (window._manualUrgency && window.has_focus()) { - delete window._manualUrgency; - return; - } - - this._urgentWindows.add(window); - this.urgent = true; - - const onDemandsAttentionChanged = () => { - if (!window.demandsAttention && !window.urgent && !window._manualUrgency) - this._updateUrgentWindows(); - }; - - if (window.demandsAttention) - this._signalsHandler.addWithLabel('urgent-windows', window, - 'notify::demands-attention', () => onDemandsAttentionChanged()); - if (window.urgent) - this._signalsHandler.addWithLabel('urgent-windows', window, - 'notify::urgent', () => onDemandsAttentionChanged()); - if (window._manualUrgency) { - this._signalsHandler.addWithLabel('urgent-windows', window, - 'focus', () => { - delete window._manualUrgency; - onDemandsAttentionChanged() - }); - } - } - - /** - * Update taraget for minimization animation - */ - updateIconGeometry() { - // If (for unknown reason) the actor is not on the stage the reported size - // and position are random values, which might exceeds the integer range - // resulting in an error when assigned to the a rect. This is a more like - // a workaround to prevent flooding the system with errors. - if (this.get_stage() == null) - return; - - let rect = new Meta.Rectangle(); - - [rect.x, rect.y] = this.get_transformed_position(); - [rect.width, rect.height] = this.get_transformed_size(); - - let windows = this.getWindows(); - if (Docking.DockManager.settings.get_boolean('multi-monitor')) { - let monitorIndex = this.monitorIndex; - windows = windows.filter(function(w) { - return w.get_monitor() == monitorIndex; - }); - } - windows.forEach(function(w) { - w.set_icon_geometry(rect); - }); - } - - _updateRunningStyle() { - // The logic originally in this function has been moved to - // AppIconIndicatorBase._updateDefaultDot(). However it cannot be removed as - // it called by the parent constructor. - } - - popupMenu() { - this._removeMenuTimeout(); - this.fake_release(); - this._draggable.fakeRelease(); - - if (!this._menu) { - this._menu = new DockAppIconMenu(this); - this._menu.connect('activate-window', (menu, window) => { - Main.activateWindow(window); - }); - this._menu.connect('open-state-changed', (menu, isPoppedUp) => { - if (!isPoppedUp) - this._onMenuPoppedDown(); - else { - // Setting the max-height is s useful if part of the menu is - // scrollable so the minimum height is smaller than the natural height. - let monitor_index = Main.layoutManager.findIndexForActor(this); - let workArea = Main.layoutManager.getWorkAreaForMonitor(monitor_index); - let position = Utils.getPosition(); - this._isHorizontal = ( position == St.Side.TOP || - position == St.Side.BOTTOM); - // If horizontal also remove the height of the dash - const { dockFixed: fixedDock } = Docking.DockManager.settings; - let additional_margin = this._isHorizontal && !fixedDock ? Main.overview.dash.height : 0; - let verticalMargins = this._menu.actor.margin_top + this._menu.actor.margin_bottom; - // Also set a max width to the menu, so long labels (long windows title) get truncated - this._menu.actor.style = ('max-height: ' + Math.round(workArea.height - additional_margin - verticalMargins) + 'px;' + - 'max-width: 400px'); - } - }); - let id = Main.overview.connect('hiding', () => { - this._menu.close(); - }); - this._menu.actor.connect('destroy', function() { - Main.overview.disconnect(id); - }); - - this._menuManager.addMenu(this._menu); - } - - this.emit('menu-state-changed', true); - - this.set_hover(true); - this._menu.popup(); - this._menuManager.ignoreRelease(); - this.emit('sync-tooltip'); - - return false; - } - - activate(button) { - let event = Clutter.get_current_event(); - let modifiers = event ? event.get_state() : 0; - - // Only consider SHIFT and CONTROL as modifiers (exclude SUPER, CAPS-LOCK, etc.) - modifiers = modifiers & (Clutter.ModifierType.SHIFT_MASK | Clutter.ModifierType.CONTROL_MASK); - - // We don't change the CTRL-click behaviour: in such case we just chain - // up the parent method and return. - if (modifiers & Clutter.ModifierType.CONTROL_MASK) { - // Keep default behaviour: launch new window - // By calling the parent method I make it compatible - // with other extensions tweaking ctrl + click - super.activate(button); - return; - } - - // We check what type of click we have and if the modifier SHIFT is - // being used. We then define what buttonAction should be for this - // event. - let buttonAction = 0; - let settings = Docking.DockManager.settings; - if (button && button == 2 ) { - if (modifiers & Clutter.ModifierType.SHIFT_MASK) - buttonAction = settings.get_enum('shift-middle-click-action'); - else - buttonAction = settings.get_enum('middle-click-action'); - } - else if (button && button == 1) { - if (modifiers & Clutter.ModifierType.SHIFT_MASK) - buttonAction = settings.get_enum('shift-click-action'); - else - buttonAction = settings.get_enum('click-action'); - } - - // We check if the app is running, and that the # of windows is > 0 in - // case we use workspace isolation. - let windows = this.getInterestingWindows(); - - // Some action modes (e.g. MINIMIZE_OR_OVERVIEW) require overview to remain open - // This variable keeps track of this - let shouldHideOverview = true; - - // We customize the action only when the application is already running - if (this.running) { - const hasUrgentWindows = !!this._urgentWindows.size; - const singleOrUrgentWindows = windows.length === 1 || hasUrgentWindows; - switch (buttonAction) { - case clickAction.MINIMIZE: - // In overview just activate the app, unless the acion is explicitely - // requested with a keyboard modifier - if (!Main.overview.visible || modifiers){ - // If we have button=2 or a modifier, allow minimization even if - // the app is not focused - if ((this.focused && !hasUrgentWindows) || button === 2 || modifiers & Clutter.ModifierType.SHIFT_MASK) { - // minimize all windows on double click and always in the case of primary click without - // additional modifiers - let click_count = 0; - if (Clutter.EventType.CLUTTER_BUTTON_PRESS) - click_count = event.get_click_count(); - let all_windows = (button == 1 && ! modifiers) || click_count > 1; - this._minimizeWindow(all_windows); - } - else - this._activateAllWindows(); - } - else { - let w = windows[0]; - Main.activateWindow(w); - } - break; - - case clickAction.MINIMIZE_OR_OVERVIEW: - // When a single window is present, toggle minimization - // If only one windows is present toggle minimization, but only when trigggered with the - // simple click action (no modifiers, no middle click). - if (singleOrUrgentWindows && !modifiers && button == 1) { - let w = windows[0]; - if (this.focused) { - // Window is raised, minimize it - this._minimizeWindow(w); - } else { - // Window is minimized, raise it - Main.activateWindow(w); - } - // Launch overview when multiple windows are present - // TODO: only show current app windows when gnome shell API will allow it - } else { - shouldHideOverview = false; - Main.overview.toggle(); - } - break; - - case clickAction.CYCLE_WINDOWS: - if (!Main.overview.visible) { - if (this.focused && !hasUrgentWindows) - this._cycleThroughWindows(); - else { - // Activate the first window - let w = windows[0]; - Main.activateWindow(w); - } - } - else - this.app.activate(); - break; - - case clickAction.FOCUS_OR_PREVIEWS: - if (this.focused && !hasUrgentWindows && - (windows.length > 1 || modifiers || button != 1)) { - this._windowPreviews(); - } else { - // Activate the first window - let w = windows[0]; - Main.activateWindow(w); - } - break; - - case clickAction.FOCUS_MINIMIZE_OR_PREVIEWS: - if (this.focused && !hasUrgentWindows) { - if (windows.length > 1 || modifiers || button != 1) - this._windowPreviews(); - else if (!Main.overview.visible) - this._minimizeWindow(); - } else { - // Activate the first window - let w = windows[0]; - Main.activateWindow(w); - } - break; - - case clickAction.LAUNCH: - this.launchNewWindow(); - break; - - case clickAction.PREVIEWS: - if (!Main.overview.visible) { - // If only one windows is present just switch to it, but only when trigggered with the - // simple click action (no modifiers, no middle click). - if (singleOrUrgentWindows && !modifiers && button == 1) { - let w = windows[0]; - Main.activateWindow(w); - } else - this._windowPreviews(); - } - else { - this.app.activate(); - } - break; - - case clickAction.MINIMIZE_OR_PREVIEWS: - // When a single window is present, toggle minimization - // If only one windows is present toggle minimization, but only when trigggered with the - // simple click action (no modifiers, no middle click). - if (!Main.overview.visible) { - if (singleOrUrgentWindows && !modifiers && button == 1) { - let w = windows[0]; - if (this.focused) { - // Window is raised, minimize it - this._minimizeWindow(w); - } else { - // Window is minimized, raise it - Main.activateWindow(w); - } - } else { - // Launch previews when multiple windows are present - this._windowPreviews(); - } - } else { - this.app.activate(); - } - break; - - case clickAction.QUIT: - this.closeAllWindows(); - break; - - case clickAction.SKIP: - let w = windows[0]; - Main.activateWindow(w); - break; - } - } - else { - this.launchNewWindow(); - } - - // Hide overview except when action mode requires it - if(shouldHideOverview) { - Main.overview.hide(); - } - } - - shouldShowTooltip() { - return this.hover && (!this._menu || !this._menu.isOpen) && - (!this._previewMenu || !this._previewMenu.isOpen); - } - - _windowPreviews() { - if (!this._previewMenu) { - this._previewMenuManager = new PopupMenu.PopupMenuManager(this); - - this._previewMenu = new WindowPreview.WindowPreviewMenu(this); - - this._previewMenuManager.addMenu(this._previewMenu); - - this._previewMenu.connect('open-state-changed', (menu, isPoppedUp) => { - if (!isPoppedUp) - this._onMenuPoppedDown(); - }); - let id = Main.overview.connect('hiding', () => { - this._previewMenu.close(); - }); - this._previewMenu.actor.connect('destroy', function() { - Main.overview.disconnect(id); - }); - - } - - if (this._previewMenu.isOpen) - this._previewMenu.close(); - else - this._previewMenu.popup(); - - return false; - } - - // Try to do the right thing when attempting to launch a new window of an app. In - // particular, if the application doens't allow to launch a new window, activate - // the existing window instead. - launchNewWindow(p) { - let appInfo = this.app.get_app_info(); - let actions = appInfo.list_actions(); - if (this.app.can_open_new_window()) { - this.animateLaunch(); - // This is used as a workaround for a bug resulting in no new windows being opened - // for certain running applications when calling open_new_window(). - // - // https://bugzilla.gnome.org/show_bug.cgi?id=756844 - // - // Similar to what done when generating the popupMenu entries, if the application provides - // a "New Window" action, use it instead of directly requesting a new window with - // open_new_window(), which fails for certain application, notably Nautilus. - if (actions.indexOf('new-window') == -1) { - this.app.open_new_window(-1); - } - else { - let i = actions.indexOf('new-window'); - if (i !== -1) - this.app.launch_action(actions[i], global.get_current_time(), -1); - } - } - else { - // Try to manually activate the first window. Otherwise, when the app is activated by - // switching to a different workspace, a launch spinning icon is shown and disappers only - // after a timeout. - let windows = this.getWindows(); - if (windows.length > 0) - Main.activateWindow(windows[0]) - else - this.app.activate(); - } - } - - _numberOverlay() { - // Add label for a Hot-Key visual aid - this._numberOverlayLabel = new St.Label(); - this._numberOverlayBin = new St.Bin({ - child: this._numberOverlayLabel, - x_align: Clutter.ActorAlign.START, - y_align: Clutter.ActorAlign.START, - x_expand: true, y_expand: true - }); - this._numberOverlayLabel.add_style_class_name('number-overlay'); - this._numberOverlayOrder = -1; - this._numberOverlayBin.hide(); - - this._iconContainer.add_child(this._numberOverlayBin); - - } - - updateNumberOverlay() { - // We apply an overall scale factor that might come from a HiDPI monitor. - // Clutter dimensions are in physical pixels, but CSS measures are in logical - // pixels, so make sure to consider the scale. - let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - // Set the font size to something smaller than the whole icon so it is - // still visible. The border radius is large to make the shape circular - let [minWidth, natWidth] = this._iconContainer.get_preferred_width(-1); - let font_size = Math.round(Math.max(12, 0.3*natWidth) / scaleFactor); - let size = Math.round(font_size*1.2); - this._numberOverlayLabel.set_style( - 'font-size: ' + font_size + 'px;' + - 'border-radius: ' + this.icon.iconSize + 'px;' + - 'width: ' + size + 'px; height: ' + size +'px;' - ); - } - - setNumberOverlay(number) { - this._numberOverlayOrder = number; - this._numberOverlayLabel.set_text(number.toString()); - } - - toggleNumberOverlay(activate) { - if (activate && this._numberOverlayOrder > -1) { - this.updateNumberOverlay(); - this._numberOverlayBin.show(); - } - else - this._numberOverlayBin.hide(); - } - - _minimizeWindow(param) { - // Param true make all app windows minimize - let windows = this.getInterestingWindows(); - let current_workspace = global.workspace_manager.get_active_workspace(); - for (let i = 0; i < windows.length; i++) { - let w = windows[i]; - if (w.get_workspace() == current_workspace && w.showing_on_its_workspace()) { - w.minimize(); - // Just minimize one window. By specification it should be the - // focused window on the current workspace. - if(!param) - break; - } - } - } - - // By default only non minimized windows are activated. - // This activates all windows in the current workspace. - _activateAllWindows() { - // First activate first window so workspace is switched if needed. - // We don't do this if isolation is on! - if (!Docking.DockManager.settings.get_boolean('isolate-workspaces') && - !Docking.DockManager.settings.get_boolean('isolate-monitors')) - this.app.activate(); - - // then activate all other app windows in the current workspace - let windows = this.getInterestingWindows(); - let activeWorkspace = global.workspace_manager.get_active_workspace_index(); - - if (windows.length <= 0) - return; - - let activatedWindows = 0; - - for (let i = windows.length - 1; i >= 0; i--) { - if (windows[i].get_workspace().index() == activeWorkspace) { - Main.activateWindow(windows[i]); - activatedWindows++; - } - } - } - - //This closes all windows of the app. - closeAllWindows() { - let windows = this.getInterestingWindows(); - const time = global.get_current_time(); - windows.forEach(w => w.delete(time)); - } - - _cycleThroughWindows(reversed) { - // Store for a little amount of time last clicked app and its windows - // since the order changes upon window interaction - let MEMORY_TIME=3000; - - let app_windows = this.getInterestingWindows(); - - if (app_windows.length <1) - return - - if (recentlyClickedAppLoopId > 0) - GLib.source_remove(recentlyClickedAppLoopId); - recentlyClickedAppLoopId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, MEMORY_TIME, this._resetRecentlyClickedApp); - - // If there isn't already a list of windows for the current app, - // or the stored list is outdated, use the current windows list. - let monitorIsolation = Docking.DockManager.settings.get_boolean('isolate-monitors'); - if (!recentlyClickedApp || - recentlyClickedApp.get_id() != this.app.get_id() || - recentlyClickedAppWindows.length != app_windows.length || - (recentlyClickedAppMonitor != this.monitorIndex && monitorIsolation)) { - recentlyClickedApp = this.app; - recentlyClickedAppWindows = app_windows; - recentlyClickedAppMonitor = this.monitorIndex; - recentlyClickedAppIndex = 0; - } - - if (reversed) { - recentlyClickedAppIndex--; - if (recentlyClickedAppIndex < 0) recentlyClickedAppIndex = recentlyClickedAppWindows.length - 1; - } else { - recentlyClickedAppIndex++; - } - let index = recentlyClickedAppIndex % recentlyClickedAppWindows.length; - let window = recentlyClickedAppWindows[index]; - - Main.activateWindow(window); - } - - _resetRecentlyClickedApp() { - if (recentlyClickedAppLoopId > 0) - GLib.source_remove(recentlyClickedAppLoopId); - recentlyClickedAppLoopId=0; - recentlyClickedApp =null; - recentlyClickedAppWindows = null; - recentlyClickedAppIndex = 0; - recentlyClickedAppMonitor = -1; - - return false; - } - - getWindows() { - return this.app.get_windows(); - } - - // Filter out unnecessary windows, for instance - // nautilus desktop window. - getInterestingWindows() { - const interestingWindows = getInterestingWindows(this.getWindows(), - this.monitorIndex); - - if (!this._urgentWindows.size) - return interestingWindows; - - return [...new Set([...this._urgentWindows, ...interestingWindows])]; - } -}); - -var DockAppIcon = GObject.registerClass({ -}, class DockAppIcon extends DockAbstractAppIcon { - _init(app, monitorIndex, iconAnimator) { - super._init(app, monitorIndex, iconAnimator); - - this._signalsHandler.add(tracker, 'notify::focus-app', () => this._updateFocusState()); - } -}); - -var DockLocationAppIcon = GObject.registerClass({ -}, class DockLocationAppIcon extends DockAbstractAppIcon { - _init(app, monitorIndex, iconAnimator) { - if (!app.location) - throw new Error('Provided application %s has no location'.format(app)); - - super._init(app, monitorIndex, iconAnimator); - - if (Docking.DockManager.settings.isolateLocations) { - this._signalsHandler.add(tracker, 'notify::focus-app', () => this._updateFocusState()); - } else { - this._signalsHandler.add(global.display, 'notify::focus-window', - () => this._updateFocusState()); - } - } - - get location() { - return this.app.location; - } - - _updateFocusState() { - if (Docking.DockManager.settings.isolateLocations) - return super._updateFocusState(); - - this.focused = (this.app.isFocused && this.running); - } -}); - -function makeAppIcon(app, monitorIndex, iconAnimator) { - if (app.location) - return new DockLocationAppIcon(app, monitorIndex, iconAnimator); - - - return new DockAppIcon(app, monitorIndex, iconAnimator); -} - -let discreteGpuAvailable = AppDisplay.discreteGpuAvailable; - -/** - * DockAppIconMenu - * - * - set popup arrow side based on dash orientation - * - Add close windows option based on quitfromdash extension - * (https://github.com/deuill/shell-extension-quitfromdash) - * - Add open windows thumbnails instead of list - * - update menu when application windows change - */ -const DockAppIconMenu = class DockAppIconMenu extends PopupMenu.PopupMenu { - - constructor(source) { - super(source, 0.5, Utils.getPosition()); - - this._signalsHandler = new Utils.GlobalSignalsHandler(this); - - // We want to keep the item hovered while the menu is up - this.blockSourceEvents = true; - - this._source = source; - this._parentalControlsManager = ParentalControlsManager.getDefault(); - - this.actor.add_style_class_name('app-menu'); - this.actor.add_style_class_name('app-well-menu'); - this.actor.add_style_class_name('dock-app-menu'); - - // Chain our visibility and lifecycle to that of the source - this._signalsHandler.add(source, 'notify::mapped', () => { - if (!source.mapped) - this.close(); - }); - source.connect('destroy', () => this.destroy()); - - Main.uiGroup.add_actor(this.actor); - - const { remoteModel } = Docking.DockManager.getDefault(); - const remoteModelApp = remoteModel?.lookupById(this._source?.app?.id); - if (remoteModelApp && DbusmenuUtils.haveDBusMenu()) { - const [onQuicklist, onDynamicSection] = Utils.splitHandler((sender, { quicklist }, dynamicSection) => { - dynamicSection.removeAll(); - if (quicklist) { - quicklist.get_children().forEach(remoteItem => - dynamicSection.addMenuItem(DbusmenuUtils.makePopupMenuItem(remoteItem, false))); - } - }); - - this._signalsHandler.add([ - remoteModelApp, - 'quicklist-changed', - onQuicklist - ], [ - this, - 'dynamic-section-changed', - onDynamicSection - ]); - } - - if (discreteGpuAvailable === undefined) { - const updateDiscreteGpuAvailable = () => { - const switcherooProxy = global.get_switcheroo_control(); - if (switcherooProxy) { - const prop = switcherooProxy.get_cached_property('HasDualGpu'); - discreteGpuAvailable = prop?.unpack() ?? false; - } else { - discreteGpuAvailable = false; - } - } - updateDiscreteGpuAvailable(); - global.connect('notify::switcheroo-control', - () => updateDiscreteGpuAvailable()); - } - } - - _appendSeparator() { - this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - } - - _appendMenuItem(labelText) { - const item = new PopupMenu.PopupMenuItem(labelText); - this.addMenuItem(item); - return item; - } - - popup(_activatingButton) { - this._rebuildMenu(); - this.open(BoxPointer.PopupAnimation.FULL); - } - - _rebuildMenu() { - this.removeAll(); - - if (Docking.DockManager.settings.get_boolean('show-windows-preview')) { - // Display the app windows menu items and the separator between windows - // of the current desktop and other windows. - - this._allWindowsMenuItem = new PopupMenu.PopupSubMenuMenuItem(__('All Windows'), false); - this._allWindowsMenuItem.hide(); - this.addMenuItem(this._allWindowsMenuItem); - } else { - const windows = this._source.getInterestingWindows().filter( - w => !w.skip_taskbar); - - if (windows.length > 0) { - this.addMenuItem( - /* Translators: This is the heading of a list of open windows */ - new PopupMenu.PopupSeparatorMenuItem(_('Open Windows'))); - } - - windows.forEach(window => { - let title = window.title - ? window.title : this._source.app.get_name(); - let item = this._appendMenuItem(title); - item.connect('activate', () => { - this.emit('activate-window', window); - }); - }); - } - - if (!this._source.app.is_window_backed()) { - this._appendSeparator(); - - let appInfo = this._source.app.get_app_info(); - let actions = appInfo.list_actions(); - if (this._source.app.can_open_new_window() && - actions.indexOf('new-window') == -1) { - this._newWindowMenuItem = this._appendMenuItem(_('New Window')); - this._newWindowMenuItem.connect('activate', () => { - if (this._source.app.state == Shell.AppState.STOPPED) - this._source.animateLaunch(); - - this._source.app.open_new_window(-1); - this.emit('activate-window', null); - }); - this._appendSeparator(); - } - - if (discreteGpuAvailable && - this._source.app.state == Shell.AppState.STOPPED) { - const appPrefersNonDefaultGPU = appInfo.get_boolean('PrefersNonDefaultGPU'); - const gpuPref = appPrefersNonDefaultGPU - ? Shell.AppLaunchGpu.DEFAULT - : Shell.AppLaunchGpu.DISCRETE; - this._onGpuMenuItem = this._appendMenuItem(appPrefersNonDefaultGPU - ? _('Launch using Integrated Graphics Card') - : _('Launch using Discrete Graphics Card')); - this._onGpuMenuItem.connect('activate', () => { - this._source.animateLaunch(); - this._source.app.launch(0, -1, gpuPref); - this.emit('activate-window', null); - }); - } - - for (let i = 0; i < actions.length; i++) { - let action = actions[i]; - let item = this._appendMenuItem(appInfo.get_action_name(action)); - item.connect('activate', (emitter, event) => { - this._source.app.launch_action(action, event.get_time(), -1); - this.emit('activate-window', null); - }); - } - - let canFavorite = global.settings.is_writable('favorite-apps') && - (this._source instanceof DockAppIcon) && - this._parentalControlsManager.shouldShowApp(this._source.app.app_info); - - if (canFavorite) { - this._appendSeparator(); - - let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id()); - - if (isFavorite) { - let item = this._appendMenuItem(_('Remove from Favorites')); - item.connect('activate', () => { - let favs = AppFavorites.getAppFavorites(); - favs.removeFavorite(this._source.app.get_id()); - }); - } else { - let item = this._appendMenuItem(_('Add to Favorites')); - item.connect('activate', () => { - let favs = AppFavorites.getAppFavorites(); - favs.addFavorite(this._source.app.get_id()); - }); - } - } - - if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop') && - (this._source instanceof DockAppIcon)) { - this._appendSeparator(); - let item = this._appendMenuItem(_('Show Details')); - item.connect('activate', () => { - let id = this._source.app.get_id(); - let args = GLib.Variant.new('(ss)', [id, '']); - Gio.DBus.get(Gio.BusType.SESSION, null, - function(o, res) { - let bus = Gio.DBus.get_finish(res); - bus.call('org.gnome.Software', - '/org/gnome/Software', - 'org.gtk.Actions', 'Activate', - GLib.Variant.new('(sava{sv})', - ['details', [args], null]), - null, 0, -1, null, null); - Main.overview.hide(); - }); - }); - } - } - - // dynamic menu - const items = this._getMenuItems(); - let i = items.length; - if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) { - i -= 2; - } - if (global.settings.is_writable('favorite-apps')) { - i -= 2; - } - if (i < 0) { - i = 0; - } - const dynamicSection = new PopupMenu.PopupMenuSection(); - this.addMenuItem(dynamicSection, i); - this.emit('dynamic-section-changed', dynamicSection); - - // quit menu - this._appendSeparator(); - this._quitfromDashMenuItem = this._appendMenuItem(_('Quit')); - this._quitfromDashMenuItem.connect('activate', () => { - this._source.closeAllWindows(); - }); - - this.update(); - } - - // update menu content when application windows change. This is desirable as actions - // acting on windows (closing) are performed while the menu is shown. - update() { - // update, show or hide the quit menu - if (this._source.windowsCount > 0) { - let quitFromDashMenuText = ""; - if (this._source.windowsCount == 1) - this._quitfromDashMenuItem.label.set_text(_('Quit')); - else - this._quitfromDashMenuItem.label.set_text(__('Quit %d Windows').format(this._source.windowsCount)); - - this._quitfromDashMenuItem.actor.show(); - - } else { - this._quitfromDashMenuItem.actor.hide(); - } - - if (Docking.DockManager.settings.get_boolean('show-windows-preview')){ - const windows = this._source.getInterestingWindows(); - - // update, show, or hide the allWindows menu - // Check if there are new windows not already displayed. In such case, repopulate the allWindows - // menu. Windows removal is already handled by each preview being connected to the destroy signal - let old_windows = this._allWindowsMenuItem.menu._getMenuItems().map(function(item){ - return item._window; - }); - - let new_windows = windows.filter(function(w) {return old_windows.indexOf(w) < 0;}); - if (new_windows.length > 0) { - this._populateAllWindowMenu(windows); - - // Try to set the width to that of the submenu. - // TODO: can't get the actual size, getting a bit less. - // Temporary workaround: add 15px to compensate - this._allWindowsMenuItem.width = this._allWindowsMenuItem.menu.actor.width + 15; - - } - - // The menu is created hidden and never hidded after being shown. Instead, a singlal - // connected to its items destroy will set is insensitive if no more windows preview are shown. - if (windows.length > 0){ - this._allWindowsMenuItem.show(); - this._allWindowsMenuItem.setSensitive(true); - } - } - - // Update separators - this._getMenuItems().forEach(item => { - if ('label' in item) { - this._updateSeparatorVisibility(item); - } - }); - } - - _populateAllWindowMenu(windows) { - - this._allWindowsMenuItem.menu.removeAll(); - - if (windows.length > 0) { - - let activeWorkspace = global.workspace_manager.get_active_workspace(); - let separatorShown = windows[0].get_workspace() != activeWorkspace; - - for (let i = 0; i < windows.length; i++) { - let window = windows[i]; - if (!separatorShown && window.get_workspace() != activeWorkspace) { - this._allWindowsMenuItem.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - separatorShown = true; - } - - let item = new WindowPreview.WindowPreviewMenuItem(window); - this._allWindowsMenuItem.menu.addMenuItem(item); - item.connect('activate', () => { - this.emit('activate-window', window); - }); - - // This is to achieve a more gracefull transition when the last windows is closed. - item.connect('destroy', () => { - if(this._allWindowsMenuItem.menu._getMenuItems().length == 1) // It's still counting the item just going to be destroyed - this._allWindowsMenuItem.setSensitive(false); - }); - } - } - } -}; - -// Filter out unnecessary windows, for instance -// nautilus desktop window. -function getInterestingWindows(windows, monitorIndex) { - let settings = Docking.DockManager.settings; - - // When using workspace isolation, we filter out windows - // that are not in the current workspace - if (settings.get_boolean('isolate-workspaces')) - windows = windows.filter(function(w) { - return w.get_workspace().index() == global.workspace_manager.get_active_workspace_index(); - }); - - if (settings.get_boolean('isolate-monitors')) - windows = windows.filter(function(w) { - return w.get_monitor() == monitorIndex; - }); - - return windows; -} - -/** - * A ShowAppsIcon improved class. - * - * - set label position based on dash orientation (Note, I am reusing most machinery of the appIcon class) - * - implement a popupMenu based on the AppIcon code (Note, I am reusing most machinery of the appIcon class) - * - */ - -var DockShowAppsIcon = GObject.registerClass({ - Signals: { - 'menu-state-changed': { param_types: [GObject.TYPE_BOOLEAN] }, - 'sync-tooltip': {} - } -} -, class DockShowAppsIcon extends Dash.ShowAppsIcon { - _init() { - super._init(); - - // Re-use appIcon methods - let appIconPrototype = AppDisplay.AppIcon.prototype; - this.toggleButton.y_expand = false; - this.toggleButton.connect('popup-menu', - appIconPrototype._onKeyboardPopupMenu.bind(this)); - this.toggleButton.connect('clicked', - this._removeMenuTimeout.bind(this)); - - this.reactive = true; - this.toggleButton.popupMenu = () => this.popupMenu.call(this); - this.toggleButton._removeMenuTimeout = () => this._removeMenuTimeout.call(this); - - this._menu = null; - this._menuManager = new PopupMenu.PopupMenuManager(this); - this._menuTimeoutId = 0; - } - - vfunc_leave_event(leaveEvent) - { - return AppDisplay.AppIcon.prototype.vfunc_leave_event.call( - this.toggleButton, leaveEvent); - } - - vfunc_button_press_event(buttonPressEvent) - { - return AppDisplay.AppIcon.prototype.vfunc_button_press_event.call( - this.toggleButton, buttonPressEvent); - } - - vfunc_touch_event(touchEvent) - { - return AppDisplay.AppIcon.prototype.vfunc_touch_event.call( - this.toggleButton, touchEvent); - } - - showLabel() { - itemShowLabel.call(this); - } - - _onMenuPoppedDown() { - AppDisplay.AppIcon.prototype._onMenuPoppedDown.apply(this, arguments); - } - - _setPopupTimeout() { - AppDisplay.AppIcon.prototype._onMenuPoppedDown.apply(this, arguments); - } - - _removeMenuTimeout() { - AppDisplay.AppIcon.prototype._removeMenuTimeout.apply(this, arguments); - } - - popupMenu() { - this._removeMenuTimeout(); - this.toggleButton.fake_release(); - - if (!this._menu) { - this._menu = new DockShowAppsIconMenu(this); - this._menu.connect('open-state-changed', (menu, isPoppedUp) => { - if (!isPoppedUp) - this._onMenuPoppedDown(); - }); - let id = Main.overview.connect('hiding', () => { - this._menu.close(); - }); - this._menu.actor.connect('destroy', function() { - Main.overview.disconnect(id); - }); - this._menuManager.addMenu(this._menu); - } - - this.emit('menu-state-changed', true); - - this.toggleButton.set_hover(true); - this._menu.popup(); - this._menuManager.ignoreRelease(); - this.emit('sync-tooltip'); - - return false; - } -}); - - -/** - * A menu for the showAppsIcon - */ -class DockShowAppsIconMenu extends DockAppIconMenu { - _rebuildMenu() { - this.removeAll(); - - /* Translators: %s is "Settings", which is automatically translated. You - can also translate the full message if this fits better your language. */ - let name = __('Dash to Dock %s').format(_('Settings')) - let item = this._appendMenuItem(name); - - item.connect('activate', function () { - ExtensionUtils.openPrefs(); - }); - } -}; - -/** - * This function is used for both extendShowAppsIcon and extendDashItemContainer - */ -function itemShowLabel() { - // Check if the label is still present at all. When switching workpaces, the - // item might have been destroyed in between. - if (!this._labelText || this.label.get_stage() == null) - return; - - this.label.set_text(this._labelText); - this.label.opacity = 0; - this.label.show(); - - let [stageX, stageY] = this.get_transformed_position(); - let node = this.label.get_theme_node(); - - let itemWidth = this.allocation.x2 - this.allocation.x1; - let itemHeight = this.allocation.y2 - this.allocation.y1; - - let labelWidth = this.label.get_width(); - let labelHeight = this.label.get_height(); - - let x, y, xOffset, yOffset; - - let position = Utils.getPosition(); - this._isHorizontal = ((position == St.Side.TOP) || (position == St.Side.BOTTOM)); - let labelOffset = node.get_length('-x-offset'); - - switch (position) { - case St.Side.LEFT: - yOffset = Math.floor((itemHeight - labelHeight) / 2); - y = stageY + yOffset; - xOffset = labelOffset; - x = stageX + this.get_width() + xOffset; - break; - case St.Side.RIGHT: - yOffset = Math.floor((itemHeight - labelHeight) / 2); - y = stageY + yOffset; - xOffset = labelOffset; - x = Math.round(stageX) - labelWidth - xOffset; - break; - case St.Side.TOP: - y = stageY + labelOffset + itemHeight; - xOffset = Math.floor((itemWidth - labelWidth) / 2); - x = stageX + xOffset; - break; - case St.Side.BOTTOM: - yOffset = labelOffset; - y = stageY - labelHeight - yOffset; - xOffset = Math.floor((itemWidth - labelWidth) / 2); - x = stageX + xOffset; - break; - } - - // keep the label inside the screen border - // Only needed fot the x coordinate. - - // Leave a few pixel gap - let gap = 5; - let monitor = Main.layoutManager.findMonitorForActor(this); - if (x - monitor.x < gap) - x += monitor.x - x + labelOffset; - else if (x + labelWidth > monitor.x + monitor.width - gap) - x -= x + labelWidth - (monitor.x + monitor.width) + gap; - - this.label.remove_all_transitions(); - this.label.set_position(x, y); - this.label.ease({ - opacity: 255, - duration: Dash.DASH_ITEM_LABEL_SHOW_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD - }); -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/dash.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/dash.js deleted file mode 100644 index a7561e8..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/dash.js +++ /dev/null @@ -1,1113 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const Clutter = imports.gi.Clutter; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Meta = imports.gi.Meta; -const Shell = imports.gi.Shell; -const St = imports.gi.St; - -const AppDisplay = imports.ui.appDisplay; -const AppFavorites = imports.ui.appFavorites; -const Dash = imports.ui.dash; -const DND = imports.ui.dnd; -const IconGrid = imports.ui.iconGrid; -const Main = imports.ui.main; -const PopupMenu = imports.ui.popupMenu; -const Util = imports.misc.util; -const Workspace = imports.ui.workspace; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Docking = Me.imports.docking; -const Utils = Me.imports.utils; -const AppIcons = Me.imports.appIcons; -const Locations = Me.imports.locations; - -const DASH_ANIMATION_TIME = Dash.DASH_ANIMATION_TIME; -const DASH_ITEM_LABEL_HIDE_TIME = Dash.DASH_ITEM_LABEL_HIDE_TIME; -const DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT; -const DASH_VISIBILITY_TIMEOUT = 3; - -/** - * Extend DashItemContainer - * - * - set label position based on dash orientation - * - */ -var DockDashItemContainer = GObject.registerClass( -class DockDashItemContainer extends Dash.DashItemContainer { - - showLabel() { - return AppIcons.itemShowLabel.call(this); - } -}); - -const DockDashIconsVerticalLayout = GObject.registerClass( - class DockDashIconsVerticalLayout extends Clutter.BoxLayout { - _init() { - super._init({ - orientation: Clutter.Orientation.VERTICAL, - }); - } - - vfunc_get_preferred_height(container, forWidth) { - const [natHeight] = super.vfunc_get_preferred_height(container, forWidth); - return [natHeight, 0]; - } -}); - - -const baseIconSizes = [16, 22, 24, 32, 48, 64, 96, 128]; - -/** - * This class is a fork of the upstream dash class (ui.dash.js) - * - * Summary of changes: - * - disconnect global signals adding a destroy method; - * - play animations even when not in overview mode - * - set a maximum icon size - * - show running and/or favorite applications - * - hide showApps label when the custom menu is shown. - * - add scrollview - * ensure actor is visible on keyfocus inseid the scrollview - * - add 128px icon size, might be useful for hidpi display - * - sync minimization application target position. - * - keep running apps ordered. - */ -var DockDash = GObject.registerClass({ - Properties: { - 'requires-visibility': GObject.ParamSpec.boolean( - 'requires-visibility', 'requires-visibility', 'requires-visibility', - GObject.ParamFlags.READWRITE, - false), - }, - Signals: { - 'menu-closed': {}, - 'icon-size-changed': {}, - } -}, class DockDash extends St.Widget { - - _init(monitorIndex) { - // Initialize icon variables and size - this._maxWidth = -1; - this._maxHeight = -1; - this.iconSize = Docking.DockManager.settings.get_int('dash-max-icon-size'); - this._availableIconSizes = baseIconSizes; - this._shownInitially = false; - this._initializeIconSize(this.iconSize); - - this._separator = null; - - this._monitorIndex = monitorIndex; - this._position = Utils.getPosition(); - this._isHorizontal = ((this._position == St.Side.TOP) || - (this._position == St.Side.BOTTOM)); - - this._dragPlaceholder = null; - this._dragPlaceholderPos = -1; - this._animatingPlaceholdersCount = 0; - this._showLabelTimeoutId = 0; - this._resetHoverTimeoutId = 0; - this._labelShowing = false; - - super._init({ - name: 'dash', - offscreen_redirect: Clutter.OffscreenRedirect.ALWAYS, - layout_manager: new Clutter.BinLayout() - }); - - this._dashContainer = new St.BoxLayout({ - name: "dashtodockDashContainer", - x_align: Clutter.ActorAlign.CENTER, - y_align: Clutter.ActorAlign.CENTER, - vertical: !this._isHorizontal, - y_expand: this._isHorizontal, - x_expand: !this._isHorizontal, - }); - - this._scrollView = new St.ScrollView({ - name: 'dashtodockDashScrollview', - hscrollbar_policy: this._isHorizontal ? St.PolicyType.EXTERNAL : St.PolicyType.NEVER, - vscrollbar_policy: this._isHorizontal ? St.PolicyType.NEVER : St.PolicyType.EXTERNAL, - x_expand: this._isHorizontal, - y_expand: !this._isHorizontal, - enable_mouse_scrolling: false - }); - - if (Docking.DockManager.settings.dockExtended) { - if (!this._isHorizontal) { - this._scrollView.y_align = Clutter.ActorAlign.START; - } else { - this._scrollView.x_align = Clutter.ActorAlign.START; - } - } - - this._scrollView.connect('scroll-event', this._onScrollEvent.bind(this)); - - let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; - this._box = new St.BoxLayout({ - vertical: !this._isHorizontal, - clip_to_allocation: false, - ...(!this._isHorizontal ? { layout_manager: new DockDashIconsVerticalLayout() } : {}), - x_align: rtl ? Clutter.ActorAlign.END : Clutter.ActorAlign.START, - y_align: this._isHorizontal ? Clutter.ActorAlign.CENTER: Clutter.ActorAlign.START, - y_expand: !this._isHorizontal, - x_expand: this._isHorizontal - }); - this._box._delegate = this; - this._dashContainer.add_actor(this._scrollView); - this._scrollView.add_actor(this._box); - - this._showAppsIcon = new AppIcons.DockShowAppsIcon(); - this._showAppsIcon.show(false); - this._showAppsIcon.icon.setIconSize(this.iconSize); - this._showAppsIcon.x_expand = false; - this._showAppsIcon.y_expand = false; - if (!this._isHorizontal) - this._showAppsIcon.y_align = Clutter.ActorAlign.START; - this._hookUpLabel(this._showAppsIcon); - this._showAppsIcon.connect('menu-state-changed', (_icon, opened) => { - this._itemMenuStateChanged(this._showAppsIcon, opened); - }); - - if (Docking.DockManager.settings.get_boolean('show-apps-at-top')) { - this._dashContainer.insert_child_below(this._showAppsIcon, null); - } else { - this._dashContainer.insert_child_above(this._showAppsIcon, null); - } - - this._background = new St.Widget({ - style_class: 'dash-background', - y_expand: this._isHorizontal, - x_expand: !this._isHorizontal, - }); - - const sizerBox = new Clutter.Actor(); - sizerBox.add_constraint(new Clutter.BindConstraint({ - source: this._isHorizontal ? this._showAppsIcon.icon : this._dashContainer, - coordinate: Clutter.BindCoordinate.HEIGHT, - })); - sizerBox.add_constraint(new Clutter.BindConstraint({ - source: this._isHorizontal ? this._dashContainer : this._showAppsIcon.icon, - coordinate: Clutter.BindCoordinate.WIDTH, - })); - this._background.add_child(sizerBox); - - this.add_child(this._background); - this.add_child(this._dashContainer); - - this._workId = Main.initializeDeferredWork(this._box, this._redisplay.bind(this)); - - this._shellSettings = new Gio.Settings({ - schema_id: 'org.gnome.shell' - }); - - this._appSystem = Shell.AppSystem.get_default(); - - this.iconAnimator = new Docking.IconAnimator(this); - - this._signalsHandler = new Utils.GlobalSignalsHandler(this); - this._signalsHandler.add([ - this._appSystem, - 'installed-changed', - () => { - AppFavorites.getAppFavorites().reload(); - this._queueRedisplay(); - } - ], [ - AppFavorites.getAppFavorites(), - 'changed', - this._queueRedisplay.bind(this) - ], [ - this._appSystem, - 'app-state-changed', - this._queueRedisplay.bind(this) - ], [ - Main.overview, - 'item-drag-begin', - this._onItemDragBegin.bind(this) - ], [ - Main.overview, - 'item-drag-end', - this._onItemDragEnd.bind(this) - ], [ - Main.overview, - 'item-drag-cancelled', - this._onItemDragCancelled.bind(this) - ], [ - Main.overview, - 'window-drag-begin', - this._onWindowDragBegin.bind(this) - ], [ - Main.overview, - 'window-drag-cancelled', - this._onWindowDragEnd.bind(this) - ], [ - Main.overview, - 'window-drag-end', - this._onWindowDragEnd.bind(this) - ]); - - this.connect('destroy', this._onDestroy.bind(this)); - } - - vfunc_get_preferred_height(forWidth) { - let [minHeight, natHeight] = super.vfunc_get_preferred_height.call(this, forWidth); - if (!this._isHorizontal && this._maxHeight !== -1 && natHeight > this._maxHeight) - return [minHeight, this._maxHeight] - else - return [minHeight, natHeight] - } - - vfunc_get_preferred_width(forHeight) { - let [minWidth, natWidth] = super.vfunc_get_preferred_width.call(this, forHeight); - if (this._isHorizontal && this._maxWidth !== -1 && natWidth > this._maxWidth) - return [minWidth, this._maxWidth] - else - return [minWidth, natWidth] - } - - get _container() { - return this._dashContainer; - } - - _onDestroy() { - this.iconAnimator.destroy(); - - if (this._requiresVisibilityTimeout) - GLib.source_remove(this._requiresVisibilityTimeout); - } - - - _onItemDragBegin() { - return Dash.Dash.prototype._onItemDragBegin.call(this, ...arguments); - } - - _onItemDragCancelled() { - return Dash.Dash.prototype._onItemDragCancelled.call(this, ...arguments); - } - - _onItemDragEnd() { - return Dash.Dash.prototype._onItemDragEnd.call(this, ...arguments); - } - - _endItemDrag() { - return Dash.Dash.prototype._endItemDrag.call(this, ...arguments); - } - - _onItemDragMotion() { - return Dash.Dash.prototype._onItemDragMotion.call(this, ...arguments); - } - - _appIdListToHash() { - return Dash.Dash.prototype._appIdListToHash.call(this, ...arguments); - } - - _queueRedisplay() { - return Dash.Dash.prototype._queueRedisplay.call(this, ...arguments); - } - - _hookUpLabel() { - return Dash.Dash.prototype._hookUpLabel.call(this, ...arguments); - } - - _syncLabel() { - return Dash.Dash.prototype._syncLabel.call(this, ...arguments); - } - - _clearDragPlaceholder() { - return Dash.Dash.prototype._clearDragPlaceholder.call(this, ...arguments); - } - - _clearEmptyDropTarget() { - return Dash.Dash.prototype._clearEmptyDropTarget.call(this, ...arguments); - } - - handleDragOver(source, actor, x, y, time) { - let ret; - if (this._isHorizontal) { - ret = Dash.Dash.prototype.handleDragOver.call(this, source, actor, x, y, time); - - if (ret == DND.DragMotionResult.CONTINUE) - return ret; - } else { - const propertyInjections = new Utils.PropertyInjectionsHandler(); - propertyInjections.add(this._box, 'width', { - get: () => this._box.get_children().reduce((a, c) => a + c.height, 0), - }); - - if (this._dragPlaceholder) { - propertyInjections.add(this._dragPlaceholder, 'width', { - get: () => this._dragPlaceholder.height, - }); - } - - ret = Dash.Dash.prototype.handleDragOver.call(this, source, actor, y, x, time); - propertyInjections.destroy(); - - if (ret == DND.DragMotionResult.CONTINUE) - return ret; - - if (this._dragPlaceholder) { - this._dragPlaceholder.child.set_width(this.iconSize / 2); - this._dragPlaceholder.child.set_height(this.iconSize); - - let pos = this._dragPlaceholderPos; - if (this._isHorizontal && (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)) - pos = this._box.get_children() - 1 - pos; - - if (pos != this._dragPlaceholderPos) { - this._dragPlaceholderPos = pos; - this._box.set_child_at_index(this._dragPlaceholder, - this._dragPlaceholderPos) - } - } - } - - if (this._dragPlaceholder) { - // Ensure the next and previous icon are visible when moving the placeholder - // (I assume there's room for both of them) - const children = this._box.get_children(); - if (this._dragPlaceholderPos > 0) - ensureActorVisibleInScrollView(this._scrollView, - children[this._dragPlaceholderPos - 1]); - - if (this._dragPlaceholderPos >= -1 && - this._dragPlaceholderPos < children.length - 1) - ensureActorVisibleInScrollView(this._scrollView, - children[this._dragPlaceholderPos + 1]); - } - - return ret; - } - - acceptDrop() { - return Dash.Dash.prototype.acceptDrop.call(this, ...arguments); - } - - _onWindowDragBegin() { - return Dash.Dash.prototype._onWindowDragBegin.call(this, ...arguments); - } - - _onWindowDragEnd() { - return Dash.Dash.prototype._onWindowDragEnd.call(this, ...arguments); - } - - _onScrollEvent(actor, event) { - // If scroll is not used because the icon is resized, let the scroll event propagate. - if (!Docking.DockManager.settings.get_boolean('icon-size-fixed')) - return Clutter.EVENT_PROPAGATE; - - // reset timeout to avid conflicts with the mousehover event - if (this._ensureAppIconVisibilityTimeoutId > 0) { - GLib.source_remove(this._ensureAppIconVisibilityTimeoutId); - this._ensureAppIconVisibilityTimeoutId = 0; - } - - // Skip to avoid double events mouse - // TODO: Horizontal events are emulated, potentially due to a conflict - // with the workspace switching gesture. - if (!this._isHorizontal && event.is_pointer_emulated()) { - return Clutter.EVENT_STOP; - } - - let adjustment, delta = 0; - - if (this._isHorizontal) - adjustment = this._scrollView.get_hscroll_bar().get_adjustment(); - else - adjustment = this._scrollView.get_vscroll_bar().get_adjustment(); - - let increment = adjustment.step_increment; - - if (this._isHorizontal) { - switch (event.get_scroll_direction()) { - case Clutter.ScrollDirection.LEFT: - delta = -increment; - break; - case Clutter.ScrollDirection.RIGHT: - delta = +increment; - break; - case Clutter.ScrollDirection.SMOOTH: - let [dx, dy] = event.get_scroll_delta(); - // TODO: Handle y - //delta = dy * increment; - // Also consider horizontal component, for instance touchpad - delta = dx * increment; - break; - } - } else { - switch (event.get_scroll_direction()) { - case Clutter.ScrollDirection.UP: - delta = -increment; - break; - case Clutter.ScrollDirection.DOWN: - delta = +increment; - break; - case Clutter.ScrollDirection.SMOOTH: - let [, dy] = event.get_scroll_delta(); - delta = dy * increment; - break; - } - } - - const value = adjustment.get_value(); - - // TODO: Remove this if possible. - if (Number.isNaN(value)) { - adjustment.set_value(delta); - } else { - adjustment.set_value(value + delta); - } - - return Clutter.EVENT_STOP; - } - - _createAppItem(app) { - const appIcon = new AppIcons.makeAppIcon(app, this._monitorIndex, this.iconAnimator); - - if (appIcon._draggable) { - appIcon._draggable.connect('drag-begin', () => { - appIcon.opacity = 50; - }); - appIcon._draggable.connect('drag-end', () => { - appIcon.opacity = 255; - }); - } - - appIcon.connect('menu-state-changed', (appIcon, opened) => { - this._itemMenuStateChanged(item, opened); - }); - - const item = new DockDashItemContainer(); - item.setChild(appIcon); - - appIcon.connect('notify::hover', () => { - if (appIcon.hover) { - this._ensureAppIconVisibilityTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, 100, () => { - ensureActorVisibleInScrollView(this._scrollView, appIcon); - this._ensureAppIconVisibilityTimeoutId = 0; - return GLib.SOURCE_REMOVE; - }); - } - else { - if (this._ensureAppIconVisibilityTimeoutId > 0) { - GLib.source_remove(this._ensureAppIconVisibilityTimeoutId); - this._ensureAppIconVisibilityTimeoutId = 0; - } - } - }); - - appIcon.connect('clicked', (actor) => { - ensureActorVisibleInScrollView(this._scrollView, actor); - }); - - appIcon.connect('key-focus-in', (actor) => { - let [x_shift, y_shift] = ensureActorVisibleInScrollView(this._scrollView, actor); - - // This signal is triggered also by mouse click. The popup menu is opened at the original - // coordinates. Thus correct for the shift which is going to be applied to the scrollview. - if (appIcon._menu) { - appIcon._menu._boxPointer.xOffset = -x_shift; - appIcon._menu._boxPointer.yOffset = -y_shift; - } - }); - - appIcon.connect('notify::focused', () => { - const { settings } = Docking.DockManager; - if (appIcon.focused && settings.get_boolean('scroll-to-focused-application')) - ensureActorVisibleInScrollView(this._scrollView, item); - }); - - appIcon.connect('notify::urgent', () => { - if (appIcon.urgent) { - ensureActorVisibleInScrollView(this._scrollView, item); - this._requireVisibility(); - } - }); - - // Override default AppIcon label_actor, now the - // accessible_name is set at DashItemContainer.setLabelText - appIcon.label_actor = null; - item.setLabelText(app.get_name()); - - appIcon.icon.setIconSize(this.iconSize); - this._hookUpLabel(item, appIcon); - - return item; - } - - _requireVisibility() { - this.requiresVisibility = true; - - if (this._requiresVisibilityTimeout) - GLib.source_remove(this._requiresVisibilityTimeout); - - this._requiresVisibilityTimeout = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, - DASH_VISIBILITY_TIMEOUT, () => { - this._requiresVisibilityTimeout = 0; - this.requiresVisibility = false; - }); - } - - /** - * Return an array with the "proper" appIcons currently in the dash - */ - getAppIcons() { - // Only consider children which are "proper" - // icons (i.e. ignoring drag placeholders) and which are not - // animating out (which means they will be destroyed at the end of - // the animation) - let iconChildren = this._box.get_children().filter(function(actor) { - return actor.child && - !!actor.child.icon && - !actor.animatingOut; - }); - - let appIcons = iconChildren.map(function(actor) { - return actor.child; - }); - - return appIcons; - } - - _updateAppsIconGeometry() { - let appIcons = this.getAppIcons(); - appIcons.forEach(function(icon) { - icon.updateIconGeometry(); - }); - } - - _itemMenuStateChanged(item, opened) { - Dash.Dash.prototype._itemMenuStateChanged.call(this, item, opened); - - if (!opened) { - // I want to listen from outside when a menu is closed. I used to - // add a custom signal to the appIcon, since gnome 3.8 the signal - // calling this callback was added upstream. - this.emit('menu-closed'); - } - } - - _adjustIconSize() { - // For the icon size, we only consider children which are "proper" - // icons (i.e. ignoring drag placeholders) and which are not - // animating out (which means they will be destroyed at the end of - // the animation) - let iconChildren = this._box.get_children().filter(actor => { - return actor.child && - actor.child._delegate && - actor.child._delegate.icon && - !actor.animatingOut; - }); - - iconChildren.push(this._showAppsIcon); - - if (this._maxWidth === -1 && this._maxHeight === -1) - return; - - // Check if the container is present in the stage. This avoids critical - // errors when unlocking the screen - if (!this._container.get_stage()) - return; - - const themeNode = this._dashContainer.get_theme_node(); - const maxAllocation = new Clutter.ActorBox({ - x1: 0, - y1: 0, - x2: this._isHorizontal ? this._maxWidth : 42 /* whatever */, - y2: this._isHorizontal ? 42 : this._maxHeight - }); - let maxContent = themeNode.get_content_box(maxAllocation); - let availSpace; - if (this._isHorizontal) - availSpace = maxContent.get_width(); - else - availSpace = maxContent.get_height(); - - let spacing = themeNode.get_length('spacing'); - - const [{ child: firstButton }] = iconChildren; - const { child: firstIcon } = firstButton.icon; - - // if no icons there's nothing to adjust - if (!firstIcon) - return; - - // Enforce valid spacings during the size request - firstIcon.ensure_style(); - const [, , iconWidth, iconHeight] = firstIcon.get_preferred_size(); - const [, , buttonWidth, buttonHeight] = firstButton.get_preferred_size(); - - if (this._isHorizontal) { - // Subtract icon padding and box spacing from the available width - availSpace -= iconChildren.length * (buttonWidth - iconWidth) + - (iconChildren.length - 1) * spacing; - - if (this._separator) { - const [, , separatorWidth] = this._separator.get_preferred_size(); - availSpace -= separatorWidth + spacing; - } - } else { - // Subtract icon padding and box spacing from the available height - availSpace -= iconChildren.length * (buttonHeight - iconHeight) + - (iconChildren.length - 1) * spacing; - - if (this._separator) { - const [, , , separatorHeight] = this._separator.get_preferred_size(); - availSpace -= separatorHeight + spacing; - } - } - - const maxIconSize = availSpace / iconChildren.length; - let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - let iconSizes = this._availableIconSizes.map(s => s * scaleFactor); - - let newIconSize = this._availableIconSizes[0]; - for (let i = 0; i < iconSizes.length; i++) { - if (iconSizes[i] <= maxIconSize) - newIconSize = this._availableIconSizes[i]; - } - - if (newIconSize == this.iconSize) - return; - - let oldIconSize = this.iconSize; - this.iconSize = newIconSize; - this.emit('icon-size-changed'); - - let scale = oldIconSize / newIconSize; - for (let i = 0; i < iconChildren.length; i++) { - let icon = iconChildren[i].child._delegate.icon; - - // Set the new size immediately, to keep the icons' sizes - // in sync with this.iconSize - icon.setIconSize(this.iconSize); - - // Don't animate the icon size change when the overview - // is transitioning, not visible or when initially filling - // the dash - if (!Main.overview.visible || Main.overview.animationInProgress || - !this._shownInitially) - continue; - - let [targetWidth, targetHeight] = icon.icon.get_size(); - - // Scale the icon's texture to the previous size and - // tween to the new size - icon.icon.set_size(icon.icon.width * scale, - icon.icon.height * scale); - - icon.icon.ease({ - width: targetWidth, - height: targetHeight, - duration: DASH_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - - if (this._separator) { - const animateProperties = this._isHorizontal ? - { height: this.iconSize } : { width: this.iconSize }; - - this._separator.ease({ - ...animateProperties, - duration: DASH_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - } - - _redisplay() { - let favorites = AppFavorites.getAppFavorites().getFavoriteMap(); - - let running = this._appSystem.get_running(); - const dockManager = Docking.DockManager.getDefault(); - const { settings } = dockManager; - - if (settings.get_boolean('isolate-workspaces') || - settings.get_boolean('isolate-monitors')) { - // When using isolation, we filter out apps that have no windows in - // the current workspace - let monitorIndex = this._monitorIndex; - running = running.filter(app => - AppIcons.getInterestingWindows(app.get_windows(), monitorIndex).length); - } - - let children = this._box.get_children().filter(actor => { - return actor.child && - actor.child._delegate && - actor.child._delegate.app; - }); - // Apps currently in the dash - let oldApps = children.map(actor => actor.child._delegate.app); - // Apps supposed to be in the dash - let newApps = []; - - const showFavorites = settings.get_boolean('show-favorites'); - if (showFavorites) { - for (let id in favorites) - newApps.push(favorites[id]); - } - - if (settings.get_boolean('show-running')) { - // We reorder the running apps so that they don't change position on the - // dash with every redisplay() call - - // First: add the apps from the oldApps list that are still running - oldApps.forEach(oldApp => { - const index = running.indexOf(oldApp); - if (index > -1) { - const [app] = running.splice(index, 1); - if (!showFavorites || !(app.get_id() in favorites)) - newApps.push(app); - } - }); - - // Second: add the new apps - running.forEach(app => { - if (!showFavorites || !(app.get_id() in favorites)) - newApps.push(app); - }); - } - - this._signalsHandler.removeWithLabel('show-mounts'); - if (dockManager.removables) { - this._signalsHandler.addWithLabel('show-mounts', - dockManager.removables, 'changed', this._queueRedisplay.bind(this)); - dockManager.removables.getApps().forEach(removable => { - if (!newApps.includes(removable)) - newApps.push(removable); - }); - } else { - oldApps = oldApps.filter(app => !app.location || app.isTrash) - } - - this._signalsHandler.removeWithLabel('show-trash'); - if (dockManager.trash) { - this._signalsHandler.addWithLabel('show-trash', - dockManager.trash, 'changed', this._queueRedisplay.bind(this)); - const trashApp = dockManager.trash.getApp(); - if (!newApps.includes(trashApp)) - newApps.push(trashApp); - } else { - oldApps = oldApps.filter(app => !app.isTrash) - } - - // Figure out the actual changes to the list of items; we iterate - // over both the list of items currently in the dash and the list - // of items expected there, and collect additions and removals. - // Moves are both an addition and a removal, where the order of - // the operations depends on whether we encounter the position - // where the item has been added first or the one from where it - // was removed. - // There is an assumption that only one item is moved at a given - // time; when moving several items at once, everything will still - // end up at the right position, but there might be additional - // additions/removals (e.g. it might remove all the launchers - // and add them back in the new order even if a smaller set of - // additions and removals is possible). - // If above assumptions turns out to be a problem, we might need - // to use a more sophisticated algorithm, e.g. Longest Common - // Subsequence as used by diff. - - let addedItems = []; - let removedActors = []; - - let newIndex = 0; - let oldIndex = 0; - while (newIndex < newApps.length || oldIndex < oldApps.length) { - let oldApp = oldApps.length > oldIndex ? oldApps[oldIndex] : null; - let newApp = newApps.length > newIndex ? newApps[newIndex] : null; - - // No change at oldIndex/newIndex - if (oldApp == newApp) { - oldIndex++; - newIndex++; - continue; - } - - // App removed at oldIndex - if (oldApp && !newApps.includes(oldApp)) { - removedActors.push(children[oldIndex]); - oldIndex++; - continue; - } - - // App added at newIndex - if (newApp && !oldApps.includes(newApp)) { - addedItems.push({ app: newApp, - item: this._createAppItem(newApp), - pos: newIndex }); - newIndex++; - continue; - } - - // App moved - let nextApp = newApps.length > newIndex + 1 - ? newApps[newIndex + 1] : null; - let insertHere = nextApp && nextApp == oldApp; - let alreadyRemoved = removedActors.reduce((result, actor) => { - let removedApp = actor.child._delegate.app; - return result || removedApp == newApp; - }, false); - - if (insertHere || alreadyRemoved) { - let newItem = this._createAppItem(newApp); - addedItems.push({ app: newApp, - item: newItem, - pos: newIndex + removedActors.length }); - newIndex++; - } else { - removedActors.push(children[oldIndex]); - oldIndex++; - } - } - - for (let i = 0; i < addedItems.length; i++) { - this._box.insert_child_at_index(addedItems[i].item, - addedItems[i].pos); - } - - for (let i = 0; i < removedActors.length; i++) { - let item = removedActors[i]; - - // Don't animate item removal when the overview is transitioning - // or hidden - if (!Main.overview.animationInProgress) - item.animateOutAndDestroy(); - else - item.destroy(); - } - - this._adjustIconSize(); - - // Skip animations on first run when adding the initial set - // of items, to avoid all items zooming in at once - - let animate = this._shownInitially && - !Main.overview.animationInProgress; - - if (!this._shownInitially) - this._shownInitially = true; - - for (let i = 0; i < addedItems.length; i++) - addedItems[i].item.show(animate); - - // Update separator - const nFavorites = Object.keys(favorites).length; - const nIcons = children.length + addedItems.length - removedActors.length; - if (nFavorites > 0 && nFavorites < nIcons) { - if (!this._separator) { - this._separator = new St.Widget({ - style_class: 'dash-separator', - x_align: this._isHorizontal ? - Clutter.ActorAlign.FILL : Clutter.ActorAlign.CENTER, - y_align: this._isHorizontal ? - Clutter.ActorAlign.CENTER : Clutter.ActorAlign.FILL, - width: this._isHorizontal ? -1 : this.iconSize, - height: this._isHorizontal ? this.iconSize : -1, - }); - this._box.add_child(this._separator); - } - let pos = nFavorites; - if (this._dragPlaceholder) - pos++; - this._box.set_child_at_index(this._separator, pos); - } else if (this._separator) { - this._separator.destroy(); - this._separator = null; - } - - // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744 - // Without it, StBoxLayout may use a stale size cache - this._box.queue_relayout(); - // TODO - // This is required for icon reordering when the scrollview is used. - this._updateAppsIconGeometry(); - - // This will update the size, and the corresponding number for each icon - this._updateNumberOverlay(); - } - - _updateNumberOverlay() { - let appIcons = this.getAppIcons(); - let counter = 1; - appIcons.forEach(function(icon) { - if (counter < 10){ - icon.setNumberOverlay(counter); - counter++; - } else if (counter == 10) { - icon.setNumberOverlay(0); - counter++; - } else { - // No overlay after 10 - icon.setNumberOverlay(-1); - } - icon.updateNumberOverlay(); - }); - - } - - toggleNumberOverlay(activate) { - let appIcons = this.getAppIcons(); - appIcons.forEach(function(icon) { - icon.toggleNumberOverlay(activate); - }); - } - - _initializeIconSize(max_size) { - let max_allowed = baseIconSizes[baseIconSizes.length-1]; - max_size = Math.min(max_size, max_allowed); - - if (Docking.DockManager.settings.get_boolean('icon-size-fixed')) - this._availableIconSizes = [max_size]; - else { - this._availableIconSizes = baseIconSizes.filter(function(val) { - return (val notifiedProperties.push(pspec.name)); - - if (Docking.DockManager.settings.get_boolean('show-apps-at-top')) { - this._dashContainer.set_child_below_sibling(this._showAppsIcon, null); - } else { - this._dashContainer.set_child_above_sibling(this._showAppsIcon, null); - } - - this._signalsHandler.removeWithLabel('first-last-child-workaround'); - - // This is indeed ugly, but we need to ensure that the last and first - // visible widgets are re-computed by St, that is buggy because of a - // mutter issue that is being fixed: - // https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2047 - if (!notifiedProperties.includes('first-child')) - this._dashContainer.notify('first-child'); - if (!notifiedProperties.includes('last-child')) - this._dashContainer.notify('last-child'); - } -}); - - -/** - * This is a copy of the same function in utils.js, but also adjust horizontal scrolling - * and perform few further checks on the current value to avoid changing the values when - * it would be clamp to the current one in any case. - * Return the amount of shift applied - */ -function ensureActorVisibleInScrollView(scrollView, actor) { - const { adjustment: vAdjustment } = scrollView.vscroll; - const { adjustment: hAdjustment } = scrollView.hscroll; - const { value: vValue0, pageSize: vPageSize, upper: vUpper } = vAdjustment; - const { value: hValue0, pageSize: hPageSize, upper: hUpper } = hAdjustment; - let [hValue, vValue] = [hValue0, vValue0]; - let vOffset = 0; - let hOffset = 0; - let fade = scrollView.get_effect('fade'); - if (fade) { - vOffset = fade.fade_margins.top; - hOffset = fade.fade_margins.left; - } - - let box = actor.get_allocation_box(); - let y1 = box.y1, y2 = box.y2, x1 = box.x1, x2 = box.x2; - - let parent = actor.get_parent(); - while (parent != scrollView) { - if (!parent) - throw new Error('Actor not in scroll view'); - - let box = parent.get_allocation_box(); - y1 += box.y1; - y2 += box.y1; - x1 += box.x1; - x2 += box.x1; - parent = parent.get_parent(); - } - - if (y1 < vValue + vOffset) - vValue = Math.max(0, y1 - vOffset); - else if (vValue < vUpper - vPageSize && y2 > vValue + vPageSize - vOffset) - vValue = Math.min(vUpper -vPageSize, y2 + vOffset - vPageSize); - - if (x1 < hValue + hOffset) - hValue = Math.max(0, x1 - hOffset); - else if (hValue < hUpper - hPageSize && x2 > hValue + hPageSize - hOffset) - hValue = Math.min(hUpper - hPageSize, x2 + hOffset - hPageSize); - - if (vValue !== vValue0) { - vAdjustment.ease(vValue, { - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - duration: Util.SCROLL_TIME - }); - } - - if (hValue !== hValue0) { - hAdjustment.ease(hValue, { - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - duration: Util.SCROLL_TIME - }); - } - - return [hValue - hValue0, vValue - vValue0]; -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/dbusmenuUtils.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/dbusmenuUtils.js deleted file mode 100644 index 3af8dc6..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/dbusmenuUtils.js +++ /dev/null @@ -1,274 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const Atk = imports.gi.Atk; -const Clutter = imports.gi.Clutter; -let Dbusmenu = null; /* Dynamically imported */ -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const St = imports.gi.St; - -const PopupMenu = imports.ui.popupMenu; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Utils = Me.imports.utils; - -// Dbusmenu features not (yet) supported: -// -// * The CHILD_DISPLAY property -// -// This seems to have only one possible value in the Dbusmenu API, so -// there's little point in depending on it--the code in libdbusmenu sets it -// if and only if an item has children, so for our purposes it's simpler -// and more intuitive to just check children.length. (This does ignore the -// possibility of a program not using libdbusmenu and setting CHILD_DISPLAY -// independently, perhaps to indicate that an childless menu item should -// nevertheless be displayed like a submenu.) -// -// * Children more than two levels deep -// -// PopupMenu doesn't seem to support submenus in submenus. -// -// * Shortcut keys -// -// If these keys are supposed to be installed as global shortcuts, we'd -// have to query these aggressively and not wait for the DBus menu to be -// mapped to a popup menu. A shortcut key that only works once the popup -// menu is open and has key focus is possibly of marginal value. - -function haveDBusMenu() { - if (Dbusmenu) - return Dbusmenu; - - try { - Dbusmenu = imports.gi.Dbusmenu; - return Dbusmenu; - } catch (e) { - log(`Failed to import DBusMenu, quicklists are not avaialble: ${e}`); - return null; - } -} - - -function makePopupMenuItem(dbusmenuItem, deep) { - // These are the only properties guaranteed to be available when the root - // item is first announced. Other properties might be loaded already, but - // be sure to connect to Dbusmenu.MENUITEM_SIGNAL_PROPERTY_CHANGED to get - // the most up-to-date values in case they aren't. - const itemType = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_TYPE); - const label = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_LABEL); - const visible = dbusmenuItem.property_get_bool(Dbusmenu.MENUITEM_PROP_VISIBLE); - const enabled = dbusmenuItem.property_get_bool(Dbusmenu.MENUITEM_PROP_ENABLED); - const accessibleDesc = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_ACCESSIBLE_DESC); - //const childDisplay = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_CHILD_DISPLAY); - - let item; - const signalsHandler = new Utils.GlobalSignalsHandler(); - const wantIcon = itemType === Dbusmenu.CLIENT_TYPES_IMAGE; - - // If the basic type of the menu item needs to change, call this. - const recreateItem = () => { - const newItem = makePopupMenuItem(dbusmenuItem, deep); - const parentMenu = item._parent; - parentMenu.addMenuItem(newItem); - // Reminder: Clutter thinks of later entries in the child list as - // "above" earlier ones, so "above" here means "below" in terms of the - // menu's vertical order. - parentMenu.actor.set_child_above_sibling(newItem.actor, item.actor); - if (newItem.menu) { - parentMenu.actor.set_child_above_sibling(newItem.menu.actor, newItem.actor); - } - parentMenu.actor.remove_child(item.actor); - item.destroy(); - item = null; - }; - - const updateDisposition = () => { - const disposition = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_DISPOSITION); - let icon_name = null; - switch (disposition) { - case Dbusmenu.MENUITEM_DISPOSITION_ALERT: - case Dbusmenu.MENUITEM_DISPOSITION_WARNING: - icon_name = 'dialog-warning-symbolic'; - break; - case Dbusmenu.MENUITEM_DISPOSITION_INFORMATIVE: - icon_name = 'dialog-information-symbolic'; - break; - } - if (icon_name) { - item._dispositionIcon = new St.Icon({ - icon_name, - style_class: 'popup-menu-icon', - y_align: Clutter.ActorAlign.CENTER, - y_expand: true, - }); - let expander; - for (let child = item.label.get_next_sibling();; child = child.get_next_sibling()) { - if (!child) { - expander = new St.Bin({ - style_class: 'popup-menu-item-expander', - x_expand: true, - }); - item.actor.add_child(expander); - break; - } else if (child instanceof St.Widget && child.has_style_class_name('popup-menu-item-expander')) { - expander = child; - break; - } - } - item.actor.insert_child_above(item._dispositionIcon, expander); - } else if (item._dispositionIcon) { - item.actor.remove_child(item._dispositionIcon); - item._dispositionIcon = null; - } - }; - - const updateIcon = () => { - if (!wantIcon) { - return; - } - const iconData = dbusmenuItem.property_get_byte_array(Dbusmenu.MENUITEM_PROP_ICON_DATA); - const iconName = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_ICON_NAME); - if (iconName) { - item.icon.icon_name = iconName; - } else if (iconData.length) { - item.icon.gicon = Gio.BytesIcon.new(iconData); - } - }; - - const updateOrnament = () => { - const toggleType = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_TOGGLE_TYPE); - switch (toggleType) { - case Dbusmenu.MENUITEM_TOGGLE_CHECK: - item.actor.accessible_role = Atk.Role.CHECK_MENU_ITEM; - break; - case Dbusmenu.MENUITEM_TOGGLE_RADIO: - item.actor.accessible_role = Atk.Role.RADIO_MENU_ITEM; - break; - default: - item.actor.accessible_role = Atk.Role.MENU_ITEM; - } - let ornament = PopupMenu.Ornament.NONE; - const state = dbusmenuItem.property_get_int(Dbusmenu.MENUITEM_PROP_TOGGLE_STATE); - if (state === Dbusmenu.MENUITEM_TOGGLE_STATE_UNKNOWN) { - // PopupMenu doesn't natively support an "unknown" ornament, but we - // can hack one in: - item.setOrnament(ornament); - item.actor.add_accessible_state(Atk.StateType.INDETERMINATE); - item._ornamentLabel.text = '\u2501'; - item.actor.remove_style_pseudo_class('checked'); - } else { - item.actor.remove_accessible_state(Atk.StateType.INDETERMINATE); - if (state === Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED) { - if (toggleType === Dbusmenu.MENUITEM_TOGGLE_CHECK) { - ornament = PopupMenu.Ornament.CHECK; - } else if (toggleType === Dbusmenu.MENUITEM_TOGGLE_RADIO) { - ornament = PopupMenu.Ornament.DOT; - } - item.actor.add_style_pseudo_class('checked'); - } else { - item.actor.remove_style_pseudo_class('checked'); - } - item.setOrnament(ornament); - } - }; - - const onPropertyChanged = (dbusmenuItem, name, value) => { - // `value` is null when a property is cleared, so handle those cases - // with sensible defaults. - switch (name) { - case Dbusmenu.MENUITEM_PROP_TYPE: - recreateItem(); - break; - case Dbusmenu.MENUITEM_PROP_ENABLED: - item.setSensitive(value ? value.unpack() : false); - break; - case Dbusmenu.MENUITEM_PROP_LABEL: - item.label.text = value ? value.unpack() : ''; - break; - case Dbusmenu.MENUITEM_PROP_VISIBLE: - item.actor.visible = value ? value.unpack() : false; - break; - case Dbusmenu.MENUITEM_PROP_DISPOSITION: - updateDisposition(); - break; - case Dbusmenu.MENUITEM_PROP_ACCESSIBLE_DESC: - item.actor.get_accessible().accessible_description = value && value.unpack() || ''; - break; - case Dbusmenu.MENUITEM_PROP_ICON_DATA: - case Dbusmenu.MENUITEM_PROP_ICON_NAME: - updateIcon(); - break; - case Dbusmenu.MENUITEM_PROP_TOGGLE_TYPE: - case Dbusmenu.MENUITEM_PROP_TOGGLE_STATE: - updateOrnament(); - break; - } - }; - - - // Start actually building the menu item. - const children = dbusmenuItem.get_children(); - if (children.length && !deep) { - // Make a submenu. - item = new PopupMenu.PopupSubMenuMenuItem(label, wantIcon); - const updateChildren = () => { - const children = dbusmenuItem.get_children(); - if (!children.length) { - return recreateItem(); - } - item.menu.removeAll(); - children.forEach(remoteChild => - item.menu.addMenuItem(makePopupMenuItem(remoteChild, true))); - }; - updateChildren(); - signalsHandler.add( - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_ADDED, updateChildren], - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_MOVED, updateChildren], - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_REMOVED, updateChildren]); - - } else { - // Don't make a submenu. - if (!deep) { - // We only have the potential to get a submenu if we aren't deep. - signalsHandler.add( - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_ADDED, recreateItem], - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_MOVED, recreateItem], - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_REMOVED, recreateItem]); - } - - if (itemType === Dbusmenu.CLIENT_TYPES_SEPARATOR) { - item = new PopupMenu.PopupSeparatorMenuItem(); - } else if (wantIcon) { - item = new PopupMenu.PopupImageMenuItem(label, null); - item.icon = item._icon; - } else { - item = new PopupMenu.PopupMenuItem(label); - } - } - - // Set common initial properties. - item.actor.visible = visible; - item.setSensitive(enabled); - if (accessibleDesc) { - item.actor.get_accessible().accessible_description = accessibleDesc; - } - updateDisposition(); - updateIcon(); - updateOrnament(); - - // Prevent an initial resize flicker. - if (wantIcon) { - item.icon.icon_size = 16; - } - - signalsHandler.add(dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_PROPERTY_CHANGED, onPropertyChanged); - - // Connections on item will be lost when item is disposed; there's no need - // to add them to signalsHandler. - item.connect('activate', () => { - dbusmenuItem.handle_event(Dbusmenu.MENUITEM_EVENT_ACTIVATED, new GLib.Variant('i', 0), Math.floor(Date.now()/1000)); - }); - item.connect('destroy', () => signalsHandler.destroy()); - - return item; -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/docking.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/docking.js deleted file mode 100644 index 5ba0c3b..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/docking.js +++ /dev/null @@ -1,2340 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const Clutter = imports.gi.Clutter; -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; -const GObject = imports.gi.GObject; -const Meta = imports.gi.Meta; -const Shell = imports.gi.Shell; -const St = imports.gi.St; -const Params = imports.misc.params; - -const Main = imports.ui.main; -const AppDisplay = imports.ui.appDisplay; -const Dash = imports.ui.dash; -const IconGrid = imports.ui.iconGrid; -const Overview = imports.ui.overview; -const OverviewControls = imports.ui.overviewControls; -const PointerWatcher = imports.ui.pointerWatcher; -const Signals = imports.signals; -const SearchController = imports.ui.searchController; -const WorkspaceSwitcherPopup= imports.ui.workspaceSwitcherPopup; -const Layout = imports.ui.layout; -const LayoutManager = imports.ui.main.layoutManager; -const Workspace = imports.ui.workspace; -const WorkspacesView = imports.ui.workspacesView; -const WorkspaceThumbnail = imports.ui.workspaceThumbnail; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Utils = Me.imports.utils; -const Intellihide = Me.imports.intellihide; -const Theming = Me.imports.theming; -const DockDash = Me.imports.dash; -const Locations = Me.imports.locations; -const LauncherAPI = Me.imports.launcherAPI; -const FileManager1API = Me.imports.fileManager1API; - -const DOCK_DWELL_CHECK_INTERVAL = 100; - -var State = { - HIDDEN: 0, - SHOWING: 1, - SHOWN: 2, - HIDING: 3 -}; - -const scrollAction = { - DO_NOTHING: 0, - CYCLE_WINDOWS: 1, - SWITCH_WORKSPACE: 2 -}; - -/** - * A simple St.Widget with one child whose allocation takes into account the - * slide out of its child via the slide-x property ([0:1]). - * - * Required since I want to track the input region of this container which is - * based on its allocation even if the child overlows the parent actor. By doing - * this the region of the dash that is slideout is not steling anymore the input - * regions making the extesion usable when the primary monitor is the right one. - * - * The slide-x parameter can be used to directly animate the sliding. The parent - * must have a WEST (SOUTH) anchor_point to achieve the sliding to the RIGHT (BOTTOM) - * side. -*/ -var DashSlideContainer = GObject.registerClass({ - Properties: { - 'monitor-index': GObject.ParamSpec.uint( - 'monitor-index', 'monitor-index', 'monitor-index', - GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, - 0, GLib.MAXUINT32, 0), - 'side': GObject.ParamSpec.enum( - 'side', 'side', 'side', - GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, - St.Side, St.Side.LEFT), - 'slide-x': GObject.ParamSpec.double( - 'slide-x', 'slide-x', 'slide-x', - GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT, - 0, 1, 1), - } -}, class DashSlideContainer extends St.Bin { - - _init(params = {}) { - super._init(params); - - this._slideoutSize = 0; // minimum size when slided out - this.connect('notify::slide-x', () => this.queue_relayout()); - - if (this.side == St.Side.TOP && DockManager.settings.dockFixed) { - this._signalsHandler = new Utils.GlobalSignalsHandler(this); - this._signalsHandler.add(Main.panel, 'notify::height', - () => this.queue_relayout()); - } - } - - vfunc_allocate(box) { - let contentBox = this.get_theme_node().get_content_box(box); - - this.set_allocation(box); - - if (this.child == null) - return; - - let availWidth = contentBox.x2 - contentBox.x1; - let availHeight = contentBox.y2 - contentBox.y1; - let [, , natChildWidth, natChildHeight] = - this.child.get_preferred_size(); - - let childWidth = natChildWidth; - let childHeight = natChildHeight; - - let childBox = new Clutter.ActorBox(); - - let slideoutSize = this._slideoutSize; - - if (this.side == St.Side.LEFT) { - childBox.x1 = (this.slideX -1) * (childWidth - slideoutSize); - childBox.x2 = slideoutSize + this.slideX * (childWidth - slideoutSize); - childBox.y1 = 0; - childBox.y2 = childBox.y1 + childHeight; - } - else if ((this.side == St.Side.RIGHT) || (this.side == St.Side.BOTTOM)) { - childBox.x1 = 0; - childBox.x2 = childWidth; - childBox.y1 = 0; - childBox.y2 = childBox.y1 + childHeight; - } - else if (this.side == St.Side.TOP) { - const monitor = Main.layoutManager.monitors[this.monitorIndex]; - let yOffset = 0; - if (Main.panel.x === monitor.x && Main.panel.y === monitor.y && - DockManager.settings.dockFixed) - yOffset = Main.panel.height; - childBox.x1 = 0; - childBox.x2 = childWidth; - childBox.y1 = (this.slideX - 1) * (childHeight - slideoutSize) + yOffset; - childBox.y2 = slideoutSize + this.slideX * (childHeight - slideoutSize) + yOffset; - availHeight += yOffset; - } - - this.child.allocate(childBox); - - this.child.set_clip(-childBox.x1, -childBox.y1, - -childBox.x1+availWidth, -childBox.y1 + availHeight); - } - - /** - * Just the child width but taking into account the slided out part - */ - vfunc_get_preferred_width(forHeight) { - let [minWidth, natWidth] = super.vfunc_get_preferred_width(forHeight); - if ((this.side == St.Side.LEFT) || (this.side == St.Side.RIGHT)) { - minWidth = (minWidth - this._slideoutSize) * this.slideX + this._slideoutSize; - natWidth = (natWidth - this._slideoutSize) * this.slideX + this._slideoutSize; - } - return [minWidth, natWidth]; - } - - /** - * Just the child height but taking into account the slided out part - */ - vfunc_get_preferred_height(forWidth) { - let [minHeight, natHeight] = super.vfunc_get_preferred_height(forWidth); - if ((this.side == St.Side.TOP) || (this.side == St.Side.BOTTOM)) { - minHeight = (minHeight - this._slideoutSize) * this.slideX + this._slideoutSize; - natHeight = (natHeight - this._slideoutSize) * this.slideX + this._slideoutSize; - - if (this.side == St.Side.TOP && DockManager.settings.dockFixed) { - const monitor = Main.layoutManager.monitors[this.monitorIndex]; - if (Main.panel.x === monitor.x && Main.panel.y === monitor.y) { - minHeight += Main.panel.height; - natHeight += Main.panel.height; - } - } - } - return [minHeight, natHeight]; - } -}); - -var DockedDash = GObject.registerClass({ - Signals: { - 'showing': {}, - 'hiding': {}, - } -}, class DashToDock extends St.Bin { - - _init(monitorIndex) { - this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL); - - // Load settings - let settings = DockManager.settings; - this._monitorIndex = monitorIndex; - this._position = Utils.getPosition(); - this._isHorizontal = ((this._position == St.Side.TOP) || (this._position == St.Side.BOTTOM)); - - // Temporary ignore hover events linked to autohide for whatever reason - this._ignoreHover = false; - this._oldignoreHover = null; - // This variables are linked to the settings regardles of autohide or intellihide - // being temporary disable. Get set by _updateVisibilityMode; - this._autohideIsEnabled = null; - this._intellihideIsEnabled = null; - - // Create intellihide object to monitor windows overlapping - this._intellihide = new Intellihide.Intellihide(this._monitorIndex); - - // initialize dock state - this._dockState = State.HIDDEN; - - // Put dock on the required monitor - this._monitor = Main.layoutManager.monitors[this._monitorIndex]; - - // this store size and the position where the dash is shown; - // used by intellihide module to check window overlap. - this.staticBox = new Clutter.ActorBox(); - - // Initialize pressure barrier variables - this._canUsePressure = false; - this._pressureBarrier = null; - this._barrier = null; - this._removeBarrierTimeoutId = 0; - - // Initialize dwelling system variables - this._dockDwelling = false; - this._dockWatch = null; - this._dockDwellUserTime = 0; - this._dockDwellTimeoutId = 0 - - // Create a new dash object - this.dash = new DockDash.DockDash(this._monitorIndex); - - if (Main.overview.isDummy || !settings.get_boolean('show-show-apps-button')) - this.dash.hideShowAppsButton(); - - // Create the main actor and the containers for sliding in and out and - // centering, turn on track hover - - let positionStyleClass = ['top', 'right', 'bottom', 'left']; - // This is the centering actor - super._init({ - name: 'dashtodockContainer', - reactive: false, - style_class: positionStyleClass[this._position], - }); - - // This is the sliding actor whose allocation is to be tracked for input regions - this._slider = new DashSlideContainer({ - monitor_index: this._monitor.index, - side: this._position, - slide_x: 0, - ...(this._isHorizontal ? { - x_align: Clutter.ActorAlign.CENTER, - } : { - y_align: Clutter.ActorAlign.CENTER, - }) - }); - - // This is the actor whose hover status us tracked for autohide - this._box = new St.BoxLayout({ - name: 'dashtodockBox', - reactive: true, - track_hover: true - }); - this._box.connect('notify::hover', this._hoverChanged.bind(this)); - - // Connect global signals - this._signalsHandler = new Utils.GlobalSignalsHandler(this); - this._bindSettingsChanges(); - this._signalsHandler.add([ - // update when workarea changes, for instance if other extensions modify the struts - //(like moving th panel at the bottom) - global.display, - 'workareas-changed', - this._resetPosition.bind(this) - ], [ - global.display, - 'in-fullscreen-changed', - this._updateBarrier.bind(this) - ], [ - // Monitor windows overlapping - this._intellihide, - 'status-changed', - this._updateDashVisibility.bind(this) - ], [ - // sync hover after a popupmenu is closed - this.dash, - 'menu-closed', - () => { this._box.sync_hover() } - ], [ - this.dash, - 'notify::requires-visibility', - () => this._updateDashVisibility(), - ]); - - if (!Main.overview.isDummy) { - this._signalsHandler.add([ - Main.overview, - 'item-drag-begin', - this._onDragStart.bind(this) - ], [ - Main.overview, - 'item-drag-end', - this._onDragEnd.bind(this) - ], [ - Main.overview, - 'item-drag-cancelled', - this._onDragEnd.bind(this) - ], [ - Main.overview, - 'showing', - this._onOverviewShowing.bind(this) - ], [ - Main.overview, - 'hiding', - this._onOverviewHiding.bind(this) - ], - [ - Main.overview, - 'hidden', - this._onOverviewHidden.bind(this) - ]); - } - - this._themeManager = new Theming.ThemeManager(this); - this._signalsHandler.add(this._themeManager, 'updated', - () => this.dash.resetAppIcons()); - - this._signalsHandler.add(DockManager.iconTheme, 'changed', - () => this.dash.resetAppIcons()); - - // Since the actor is not a topLevel child and its parent is now not added to the Chrome, - // the allocation change of the parent container (slide in and slideout) doesn't trigger - // anymore an update of the input regions. Force the update manually. - this.connect('notify::allocation', - Main.layoutManager._queueUpdateRegions.bind(Main.layoutManager)); - - - // Since Clutter has no longer ClutterAllocationFlags, - // "allocation-changed" signal has been removed. MR !1245 - this.dash._container.connect('notify::allocation', this._updateStaticBox.bind(this)); - this._slider.connect(this._isHorizontal ? 'notify::x' : 'notify::y', this._updateStaticBox.bind(this)); - - // Load optional features that need to be activated for one dock only - if (this._monitorIndex == settings.get_int('preferred-monitor')) - this._enableExtraFeatures(); - // Load optional features that need to be activated once per dock - this._optionalScrollWorkspaceSwitch(); - - // Delay operations that require the shell to be fully loaded and with - // user theme applied. - - this._signalsHandler.addWithLabel('initialize', global.stage, - 'after-paint', () => this._initialize()); - - // Add dash container actor and the container to the Chrome. - this.set_child(this._slider); - this._slider.set_child(this._box); - this._box.add_actor(this.dash); - - // Add aligning container without tracking it for input region - Main.uiGroup.add_child(this); - if (Main.uiGroup.contains(global.top_window_group)) - Main.uiGroup.set_child_below_sibling(this, global.top_window_group); - - if (settings.get_boolean('dock-fixed')) { - // Note: tracking the fullscreen directly on the slider actor causes some hiccups when fullscreening - // windows of certain applications - Main.layoutManager._trackActor(this, {affectsInputRegion: false, trackFullscreen: true}); - Main.layoutManager._trackActor(this._slider, {affectsStruts: true}); - } - else - Main.layoutManager._trackActor(this._slider); - - // Create and apply height/width constraint to the dash. - if (this._isHorizontal) { - this.connect('notify::width', () => { - this.dash.setMaxSize(this.width, this.height); - }); - } else { - this.connect('notify::height', () => { - this.dash.setMaxSize(this.width, this.height) - }); - } - - if (this._position == St.Side.RIGHT) - this.connect('notify::width', () => this.translation_x = -this.width); - else if (this._position == St.Side.BOTTOM) - this.connect('notify::height', () => this.translation_y = -this.height); - - // Set initial position - this._resetPosition(); - - this.connect('destroy', this._onDestroy.bind(this)); - } - - get monitorIndex() { - return this._monitorIndex; - } - - get position() { - return this._position; - } - - get isHorizontal() { - return this._isHorizontal; - } - - _untrackDock() { - Main.layoutManager._untrackActor(this); - Main.layoutManager._untrackActor(this._slider); - } - - _trackDock() { - if (DockManager.settings.dockFixed) { - if (Main.layoutManager._findActor(this) == -1) - Main.layoutManager._trackActor(this, { affectsInputRegion: false, trackFullscreen: true }); - if (Main.layoutManager._findActor(this._slider) == -1) - Main.layoutManager._trackActor(this._slider, { affectsStruts: true }); - } else { - if (Main.layoutManager._findActor(this._slider) == -1) - Main.layoutManager._trackActor(this._slider); - } - } - - _initialize() { - this._signalsHandler.removeWithLabel('initialize'); - - // Apply custome css class according to the settings - this._themeManager.updateCustomTheme(); - - this._updateVisibilityMode(); - - // In case we are already inside the overview when the extension is loaded, - // for instance on unlocking the screen if it was locked with the overview open. - if (Main.overview.visibleTarget) { - this._onOverviewShowing(); - } - - this._updateAutoHideBarriers(); - } - - _onDestroy() { - // The dash, intellihide and themeManager have global signals as well internally - this.dash.destroy(); - this._intellihide.destroy(); - this._themeManager.destroy(); - - if (this._marginLater) { - Meta.later_remove(this._marginLater); - delete this._marginLater; - } - - // Remove barrier timeout - if (this._removeBarrierTimeoutId > 0) - GLib.source_remove(this._removeBarrierTimeoutId); - - // Remove existing barrier - this._removeBarrier(); - - // Remove pointer watcher - if (this._dockWatch) { - PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch); - this._dockWatch = null; - } - } - - _updateAutoHideBarriers() { - // Remove pointer watcher - if (this._dockWatch) { - PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch); - this._dockWatch = null; - } - - // Setup pressure barrier (GS38+ only) - this._updatePressureBarrier(); - this._updateBarrier(); - - // setup dwelling system if pressure barriers are not available - this._setupDockDwellIfNeeded(); - } - - _bindSettingsChanges() { - let settings = DockManager.settings; - this._signalsHandler.add([ - settings, - 'changed::scroll-action', - () => { this._optionalScrollWorkspaceSwitch(); } - ], [ - settings, - 'changed::dash-max-icon-size', - () => { this.dash.setIconSize(settings.get_int('dash-max-icon-size')); } - ], [ - settings, - 'changed::icon-size-fixed', - () => { this.dash.setIconSize(settings.get_int('dash-max-icon-size')); } - ], [ - settings, - 'changed::show-favorites', - () => { this.dash.resetAppIcons(); } - ], [ - settings, - 'changed::show-trash', - () => { this.dash.resetAppIcons(); }, - Utils.SignalsHandlerFlags.CONNECT_AFTER, - ], [ - settings, - 'changed::show-mounts', - () => { this.dash.resetAppIcons(); }, - Utils.SignalsHandlerFlags.CONNECT_AFTER - ], [ - settings, - 'changed::isolate-locations', - () => this.dash.resetAppIcons(), - Utils.SignalsHandlerFlags.CONNECT_AFTER - ], [ - settings, - 'changed::show-running', - () => { this.dash.resetAppIcons(); } - ], [ - settings, - 'changed::show-apps-at-top', - () => { this.dash.updateShowAppsButton(); } - ], [ - settings, - 'changed::show-show-apps-button', - () => { - if (!Main.overview.isDummy && - settings.get_boolean('show-show-apps-button')) - this.dash.showShowAppsButton(); - else - this.dash.hideShowAppsButton(); - } - ], [ - settings, - 'changed::dock-fixed', - () => { - this._untrackDock(); - this._trackDock(); - - this._resetPosition(); - this._updateAutoHideBarriers(); - this._updateVisibilityMode(); - } - ], [ - settings, - 'changed::intellihide', - this._updateVisibilityMode.bind(this) - ], [ - settings, - 'changed::intellihide-mode', - () => { this._intellihide.forceUpdate(); } - ], [ - settings, - 'changed::autohide', - () => { - this._updateVisibilityMode(); - this._updateAutoHideBarriers(); - } - ], [ - settings, - 'changed::autohide-in-fullscreen', - this._updateBarrier.bind(this) - ], - [ - settings, - 'changed::extend-height', - this._resetPosition.bind(this) - ], [ - settings, - 'changed::height-fraction', - this._resetPosition.bind(this) - ], [ - settings, - 'changed::require-pressure-to-show', - () => this._updateAutoHideBarriers(), - ], [ - settings, - 'changed::pressure-threshold', - () => { - this._updatePressureBarrier(); - this._updateBarrier(); - } - ]); - - } - - /** - * This is call when visibility settings change - */ - _updateVisibilityMode() { - let settings = DockManager.settings; - if (DockManager.settings.dockFixed) { - this._autohideIsEnabled = false; - this._intellihideIsEnabled = false; - } - else { - this._autohideIsEnabled = settings.get_boolean('autohide') - this._intellihideIsEnabled = settings.get_boolean('intellihide') - } - - if (this._autohideIsEnabled) - this.add_style_class_name('autohide'); - else - this.remove_style_class_name('autohide'); - - if (this._intellihideIsEnabled) - this._intellihide.enable(); - else - this._intellihide.disable(); - - this._updateDashVisibility(); - } - - /** - * Show/hide dash based on, in order of priority: - * overview visibility - * fixed mode - * intellihide - * autohide - * overview visibility - */ - _updateDashVisibility() { - if (Main.overview.visibleTarget) - return; - - let settings = DockManager.settings; - - if (DockManager.settings.dockFixed) { - this._removeAnimations(); - this._animateIn(settings.get_double('animation-time'), 0); - } - else if (this._intellihideIsEnabled) { - if (!this.dash.requiresVisibility && this._intellihide.getOverlapStatus()) { - this._ignoreHover = false; - // Do not hide if autohide is enabled and mouse is hover - if (!this._box.hover || !this._autohideIsEnabled) - this._animateOut(settings.get_double('animation-time'), 0); - } - else { - this._ignoreHover = true; - this._removeAnimations(); - this._animateIn(settings.get_double('animation-time'), 0); - } - } - else { - if (this._autohideIsEnabled) { - this._ignoreHover = false; - - if (this._box.hover || this.dash.requiresVisibility) - this._animateIn(settings.get_double('animation-time'), 0); - else - this._animateOut(settings.get_double('animation-time'), 0); - } - else - this._animateOut(settings.get_double('animation-time'), 0); - } - } - - _onOverviewShowing() { - this.add_style_class_name('overview'); - - this._ignoreHover = true; - this._intellihide.disable(); - this._removeAnimations(); - this._animateIn(DockManager.settings.get_double('animation-time'), 0); - } - - _onOverviewHiding() { - this._ignoreHover = false; - this._intellihide.enable(); - this._updateDashVisibility(); - } - - _onOverviewHidden() { - this.remove_style_class_name('overview'); - } - - _hoverChanged() { - if (!this._ignoreHover) { - // Skip if dock is not in autohide mode for instance because it is shown - // by intellihide. - if (this._autohideIsEnabled) { - if (this._box.hover) - this._show(); - else - this._hide(); - } - } - } - - getDockState() { - return this._dockState; - } - - _show() { - this._delayedHide = false; - if ((this._dockState == State.HIDDEN) || (this._dockState == State.HIDING)) { - if (this._dockState == State.HIDING) - // suppress all potential queued transitions - i.e. added but not started, - // always give priority to show - this._removeAnimations(); - - this.emit('showing'); - this._animateIn(DockManager.settings.get_double('animation-time'), 0); - } - } - - _hide() { - // If no hiding animation is running or queued - if ((this._dockState == State.SHOWN) || (this._dockState == State.SHOWING)) { - let settings = DockManager.settings; - let delay = settings.get_double('hide-delay'); - - if (this._dockState == State.SHOWING) { - // if a show already started, let it finish; queue hide without removing the show. - // to obtain this, we wait for the animateIn animation to be completed - this._delayedHide = true; - return; - } - - this.emit('hiding'); - this._animateOut(settings.get_double('animation-time'), delay); - } - } - - _animateIn(time, delay) { - this._dockState = State.SHOWING; - this.dash.iconAnimator.start(); - this._delayedHide = false; - - this._slider.ease_property('slide-x', 1, { - duration: time * 1000, - delay: delay * 1000, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._dockState = State.SHOWN; - // Remove barrier so that mouse pointer is released and can access monitors on other side of dock - // NOTE: Delay needed to keep mouse from moving past dock and re-hiding dock immediately. This - // gives users an opportunity to hover over the dock - if (this._removeBarrierTimeoutId > 0) - GLib.source_remove(this._removeBarrierTimeoutId); - - if (!this._delayedHide) { - this._removeBarrierTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, 100, this._removeBarrier.bind(this)); - } else { - this._hide(); - } - } - }); - } - - _animateOut(time, delay) { - this._dockState = State.HIDING; - - this._slider.ease_property('slide-x', 0, { - duration: time * 1000, - delay: delay * 1000, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._dockState = State.HIDDEN; - // Remove queued barried removal if any - if (this._removeBarrierTimeoutId > 0) - GLib.source_remove(this._removeBarrierTimeoutId); - this._updateBarrier(); - this.dash.iconAnimator.pause(); - } - }); - } - - /** - * Dwelling system based on the GNOME Shell 3.14 messageTray code. - */ - _setupDockDwellIfNeeded() { - // If we don't have extended barrier features, then we need - // to support the old tray dwelling mechanism. - if (this._autohideIsEnabled && - (!global.display.supports_extended_barriers() || - !DockManager.settings.get_boolean('require-pressure-to-show'))) { - let pointerWatcher = PointerWatcher.getPointerWatcher(); - this._dockWatch = pointerWatcher.addWatch(DOCK_DWELL_CHECK_INTERVAL, this._checkDockDwell.bind(this)); - this._dockDwelling = false; - this._dockDwellUserTime = 0; - } - } - - _checkDockDwell(x, y) { - - let workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitor.index) - let shouldDwell; - // Check for the correct screen edge, extending the sensitive area to the whole workarea, - // minus 1 px to avoid conflicting with other active corners. - if (this._position == St.Side.LEFT) - shouldDwell = (x == this._monitor.x) && (y > workArea.y) && (y < workArea.y + workArea.height); - else if (this._position == St.Side.RIGHT) - shouldDwell = (x == this._monitor.x + this._monitor.width - 1) && (y > workArea.y) && (y < workArea.y + workArea.height); - else if (this._position == St.Side.TOP) - shouldDwell = (y == this._monitor.y) && (x > workArea.x) && (x < workArea.x + workArea.width); - else if (this._position == St.Side.BOTTOM) - shouldDwell = (y == this._monitor.y + this._monitor.height - 1) && (x > workArea.x) && (x < workArea.x + workArea.width); - - if (shouldDwell) { - // We only set up dwell timeout when the user is not hovering over the dock - // already (!this._box.hover). - // The _dockDwelling variable is used so that we only try to - // fire off one dock dwell - if it fails (because, say, the user has the mouse down), - // we don't try again until the user moves the mouse up and down again. - if (!this._dockDwelling && !this._box.hover && (this._dockDwellTimeoutId == 0)) { - // Save the interaction timestamp so we can detect user input - let focusWindow = global.display.focus_window; - this._dockDwellUserTime = focusWindow ? focusWindow.user_time : 0; - - this._dockDwellTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - DockManager.settings.get_double('show-delay') * 1000, - this._dockDwellTimeout.bind(this)); - GLib.Source.set_name_by_id(this._dockDwellTimeoutId, '[dash-to-dock] this._dockDwellTimeout'); - } - this._dockDwelling = true; - } - else { - this._cancelDockDwell(); - this._dockDwelling = false; - } - } - - _cancelDockDwell() { - if (this._dockDwellTimeoutId != 0) { - GLib.source_remove(this._dockDwellTimeoutId); - this._dockDwellTimeoutId = 0; - } - } - - _dockDwellTimeout() { - this._dockDwellTimeoutId = 0; - - if (!DockManager.settings.get_boolean('autohide-in-fullscreen') && - this._monitor.inFullscreen) - return GLib.SOURCE_REMOVE; - - // We don't want to open the tray when a modal dialog - // is up, so we check the modal count for that. When we are in the - // overview we have to take the overview's modal push into account - if (Main.modalCount > (Main.overview.visible ? 1 : 0)) - return GLib.SOURCE_REMOVE; - - // If the user interacted with the focus window since we started the tray - // dwell (by clicking or typing), don't activate the message tray - let focusWindow = global.display.focus_window; - let currentUserTime = focusWindow ? focusWindow.user_time : 0; - if (currentUserTime != this._dockDwellUserTime) - return GLib.SOURCE_REMOVE; - - // Reuse the pressure version function, the logic is the same - this._onPressureSensed(); - return GLib.SOURCE_REMOVE; - } - - _updatePressureBarrier() { - let settings = DockManager.settings; - this._canUsePressure = global.display.supports_extended_barriers(); - let pressureThreshold = settings.get_double('pressure-threshold'); - - // Remove existing pressure barrier - if (this._pressureBarrier) { - this._pressureBarrier.destroy(); - this._pressureBarrier = null; - } - - if (this._barrier) { - this._barrier.destroy(); - this._barrier = null; - } - - // Create new pressure barrier based on pressure threshold setting - if (this._canUsePressure && this._autohideIsEnabled && - DockManager.settings.get_boolean('require-pressure-to-show')) { - this._pressureBarrier = new Layout.PressureBarrier(pressureThreshold, settings.get_double('show-delay')*1000, - Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW); - this._pressureBarrier.connect('trigger', (barrier) => { - if (!settings.get_boolean('autohide-in-fullscreen') && this._monitor.inFullscreen) - return; - this._onPressureSensed(); - }); - } - } - - /** - * handler for mouse pressure sensed - */ - _onPressureSensed() { - if (Main.overview.visibleTarget) - return; - - // In case the mouse move away from the dock area before hovering it, in such case the leave event - // would never be triggered and the dock would stay visible forever. - let triggerTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 250, () => { - triggerTimeoutId = 0; - - let [x, y, mods] = global.get_pointer(); - let shouldHide = true; - switch (this._position) { - case St.Side.LEFT: - if (x <= this.staticBox.x2 && - x >= this._monitor.x && - y >= this._monitor.y && - y <= this._monitor.y + this._monitor.height) { - shouldHide = false; - } - break; - case St.Side.RIGHT: - if (x >= this.staticBox.x1 && - x <= this._monitor.x + this._monitor.width && - y >= this._monitor.y && - y <= this._monitor.y + this._monitor.height) { - shouldHide = false; - } - break; - case St.Side.TOP: - if (x >= this._monitor.x && - x <= this._monitor.x + this._monitor.width && - y <= this.staticBox.y2 && - y >= this._monitor.y) { - shouldHide = false; - } - break; - case St.Side.BOTTOM: - if (x >= this._monitor.x && - x <= this._monitor.x + this._monitor.width && - y >= this.staticBox.y1 && - y <= this._monitor.y + this._monitor.height) { - shouldHide = false; - } - } - if (shouldHide) { - this._hoverChanged(); - return GLib.SOURCE_REMOVE; - } - else { - return GLib.SOURCE_CONTINUE; - } - - }); - - this._show(); - } - - /** - * Remove pressure barrier - */ - _removeBarrier() { - if (this._barrier) { - if (this._pressureBarrier) - this._pressureBarrier.removeBarrier(this._barrier); - this._barrier.destroy(); - this._barrier = null; - } - this._removeBarrierTimeoutId = 0; - return false; - } - - /** - * Update pressure barrier size - */ - _updateBarrier() { - // Remove existing barrier - this._removeBarrier(); - - // The barrier needs to be removed in fullscreen with autohide disabled, otherwise the mouse can - // get trapped on monitor. - if (this._monitor.inFullscreen && - !DockManager.settings.get_boolean('autohide-in-fullscreen')) - return - - // Manually reset pressure barrier - // This is necessary because we remove the pressure barrier when it is triggered to show the dock - if (this._pressureBarrier) { - this._pressureBarrier._reset(); - this._pressureBarrier._isTriggered = false; - } - - // Create new barrier - // The barrier extends to the whole workarea, minus 1 px to avoid conflicting with other active corners - // Note: dash in fixed position doesn't use pressure barrier. - if (this._canUsePressure && this._autohideIsEnabled && - DockManager.settings.get_boolean('require-pressure-to-show')) { - let x1, x2, y1, y2, direction; - let workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitor.index) - - if (this._position == St.Side.LEFT) { - x1 = this._monitor.x + 1; - x2 = x1; - y1 = workArea.y + 1; - y2 = workArea.y + workArea.height - 1; - direction = Meta.BarrierDirection.POSITIVE_X; - } - else if (this._position == St.Side.RIGHT) { - x1 = this._monitor.x + this._monitor.width - 1; - x2 = x1; - y1 = workArea.y + 1; - y2 = workArea.y + workArea.height - 1; - direction = Meta.BarrierDirection.NEGATIVE_X; - } - else if (this._position == St.Side.TOP) { - x1 = workArea.x + 1; - x2 = workArea.x + workArea.width - 1; - y1 = this._monitor.y; - y2 = y1; - direction = Meta.BarrierDirection.POSITIVE_Y; - } - else if (this._position == St.Side.BOTTOM) { - x1 = workArea.x + 1; - x2 = workArea.x + workArea.width - 1; - y1 = this._monitor.y + this._monitor.height; - y2 = y1; - direction = Meta.BarrierDirection.NEGATIVE_Y; - } - - if (this._pressureBarrier && this._dockState == State.HIDDEN) { - this._barrier = new Meta.Barrier({ - display: global.display, - x1: x1, - x2: x2, - y1: y1, - y2: y2, - directions: direction - }); - this._pressureBarrier.addBarrier(this._barrier); - } - } - } - - _isPrimaryMonitor() { - return (this._monitorIndex == Main.layoutManager.primaryIndex); - } - - _resetPosition() { - // Ensure variables linked to settings are updated. - this._updateVisibilityMode(); - - const { dockFixed: fixedIsEnabled, dockExtended: extendHeight } = DockManager.settings; - - if (fixedIsEnabled) { - this.add_style_class_name('fixed'); - } else { - this.remove_style_class_name('fixed'); - } - - // Note: do not use the workarea coordinates in the direction on which the dock is placed, - // to avoid a loop [position change -> workArea change -> position change] with - // fixed dock. - let workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitorIndex); - - - let fraction = DockManager.settings.get_double('height-fraction'); - - if (extendHeight) - fraction = 1; - else if ((fraction < 0) || (fraction > 1)) - fraction = 0.95; - - if (this._isHorizontal) { - this.width = Math.round(fraction * workArea.width); - - let pos_y = this._monitor.y; - if (this._position == St.Side.BOTTOM) - pos_y += this._monitor.height; - - this.x = workArea.x + Math.round((1 - fraction) / 2 * workArea.width); - this.y = pos_y; - - if (extendHeight) { - this.dash._container.set_width(this.width); - this.add_style_class_name('extended'); - } else { - this.dash._container.set_width(-1); - this.remove_style_class_name('extended'); - } - } else { - this.height = Math.round(fraction * workArea.height); - - let pos_x = this._monitor.x; - if (this._position == St.Side.RIGHT) - pos_x += this._monitor.width; - - this.x = pos_x; - this.y = workArea.y + Math.round((1 - fraction) / 2 * workArea.height); - - this._signalsHandler.removeWithLabel('verticalOffsetChecker'); - - if (extendHeight) { - this.dash._container.set_height(this.height); - this.add_style_class_name('extended'); - } else { - this.dash._container.set_height(-1); - this.remove_style_class_name('extended'); - } - } - } - - _updateStaticBox() { - this.staticBox.init_rect( - this.x + this._slider.x - (this._position == St.Side.RIGHT ? this._box.width : 0), - this.y + this._slider.y - (this._position == St.Side.BOTTOM ? this._box.height : 0), - this._box.width, - this._box.height - ); - - this._intellihide.updateTargetBox(this.staticBox); - } - - _removeAnimations() { - this._slider.remove_all_transitions(); - } - - _onDragStart() { - this._oldignoreHover = this._ignoreHover; - this._ignoreHover = true; - this._animateIn(DockManager.settings.get_double('animation-time'), 0); - } - - _onDragEnd() { - if (this._oldignoreHover !== null) - this._ignoreHover = this._oldignoreHover; - this._oldignoreHover = null; - this._box.sync_hover(); - } - - /** - * Show dock and give key focus to it - */ - _onAccessibilityFocus() { - this._box.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); - this._animateIn(DockManager.settings.get_double('animation-time'), 0); - } - - // Optional features to be enabled only for the main Dock - _enableExtraFeatures() { - // Restore dash accessibility - Main.ctrlAltTabManager.addGroup( - this.dash, _('Dash'), 'user-bookmarks-symbolic', - {focusCallback: this._onAccessibilityFocus.bind(this)}); - } - - /** - * Switch workspace by scrolling over the dock - */ - _optionalScrollWorkspaceSwitch() { - let label = 'optionalScrollWorkspaceSwitch'; - - function isEnabled() { - return DockManager.settings.get_enum('scroll-action') === scrollAction.SWITCH_WORKSPACE; - } - - DockManager.settings.connect('changed::scroll-action', () => { - if (isEnabled.bind(this)()) - enable.bind(this)(); - else - disable.bind(this)(); - }); - - if (isEnabled.bind(this)()) - enable.bind(this)(); - - function enable() { - this._signalsHandler.removeWithLabel(label); - - this._signalsHandler.addWithLabel(label, - this._box, - 'scroll-event', - onScrollEvent.bind(this)); - } - - function disable() { - this._signalsHandler.removeWithLabel(label); - - if (this._optionalScrollWorkspaceSwitchDeadTimeId) { - GLib.source_remove(this._optionalScrollWorkspaceSwitchDeadTimeId); - this._optionalScrollWorkspaceSwitchDeadTimeId = 0; - } - } - - // This was inspired to desktop-scroller@obsidien.github.com - function onScrollEvent(actor, event) { - // When in overview change workspace only in windows view - if (Main.overview.visible) - return false; - - let activeWs = global.workspace_manager.get_active_workspace(); - let direction = null; - - let prev_direction, next_direction; - if (global.workspace_manager.layout_columns > global.workspace_manager.layout_rows) { - prev_direction = Meta.MotionDirection.UP; - next_direction = Meta.MotionDirection.DOWN; - } else { - prev_direction = Meta.MotionDirection.LEFT; - next_direction = Meta.MotionDirection.RIGHT; - } - - switch (event.get_scroll_direction()) { - case Clutter.ScrollDirection.UP: - direction = prev_direction; - break; - case Clutter.ScrollDirection.DOWN: - direction = next_direction; - break; - case Clutter.ScrollDirection.SMOOTH: - let [dx, dy] = event.get_scroll_delta(); - if (dy < 0) - direction = prev_direction; - else if (dy > 0) - direction = next_direction; - break; - } - - if (direction !== null) { - // Prevent scroll events from triggering too many workspace switches - // by adding a 250ms deadtime between each scroll event. - // Usefull on laptops when using a touchpad. - - // During the deadtime do nothing - if (this._optionalScrollWorkspaceSwitchDeadTimeId) - return false; - else - this._optionalScrollWorkspaceSwitchDeadTimeId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, 250, () => { - this._optionalScrollWorkspaceSwitchDeadTimeId = 0; - }); - - let ws; - - ws = activeWs.get_neighbor(direction) - - if (Main.wm._workspaceSwitcherPopup == null) - // Support Workspace Grid extension showing their custom Grid Workspace Switcher - if (global.workspace_manager.workspace_grid !== undefined) { - Main.wm._workspaceSwitcherPopup = - global.workspace_manager.workspace_grid.getWorkspaceSwitcherPopup(); - } else { - Main.wm._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup(); - } - // Set the actor non reactive, so that it doesn't prevent the - // clicks events from reaching the dash actor. I can't see a reason - // why it should be reactive. - Main.wm._workspaceSwitcherPopup.reactive = false; - Main.wm._workspaceSwitcherPopup.connect('destroy', function() { - Main.wm._workspaceSwitcherPopup = null; - }); - - // If Workspace Grid is installed, let them handle the scroll behaviour. - if (global.workspace_manager.workspace_grid !== undefined) - ws = global.workspace_manager.workspace_grid.actionMoveWorkspace(direction); - else - Main.wm.actionMoveWorkspace(ws); - - // Do not show workspaceSwitcher in overview - if (!Main.overview.visible) - Main.wm._workspaceSwitcherPopup.display(direction, ws.index()); - - return true; - } - else - return false; - } - } - - _activateApp(appIndex) { - let children = this.dash._box.get_children().filter(function(actor) { - return actor.child && - actor.child.app; - }); - - // Apps currently in the dash - let apps = children.map(function(actor) { - return actor.child; - }); - - // Activate with button = 1, i.e. same as left click - let button = 1; - if (appIndex < apps.length) - apps[appIndex].activate(button); - } -}); - -/* - * Handle keybaord shortcuts - */ -const DashToDock_KeyboardShortcuts_NUM_HOTKEYS = 10; - -var KeyboardShortcuts = class DashToDock_KeyboardShortcuts { - - constructor() { - this._signalsHandler = new Utils.GlobalSignalsHandler(); - - this._hotKeysEnabled = false; - if (DockManager.settings.get_boolean('hot-keys')) - this._enableHotKeys(); - - this._signalsHandler.add([ - DockManager.settings, - 'changed::hot-keys', - () => { - if (DockManager.settings.get_boolean('hot-keys')) - this._enableHotKeys.bind(this)(); - else - this._disableHotKeys.bind(this)(); - } - ]); - - this._optionalNumberOverlay(); - } - - destroy() { - // Remove keybindings - this._disableHotKeys(); - this._disableExtraShortcut(); - this._signalsHandler.destroy(); - } - - _enableHotKeys() { - if (this._hotKeysEnabled) - return; - - // Setup keyboard bindings for dash elements - let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-']; - keys.forEach( function(key) { - for (let i = 0; i < DashToDock_KeyboardShortcuts_NUM_HOTKEYS; i++) { - let appNum = i; - Main.wm.addKeybinding(key + (i + 1), DockManager.settings, - Meta.KeyBindingFlags.IGNORE_AUTOREPEAT, - Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW, - () => { - DockManager.getDefault().mainDock._activateApp(appNum); - this._showOverlay(); - }); - } - }, this); - - this._hotKeysEnabled = true; - } - - _disableHotKeys() { - if (!this._hotKeysEnabled) - return; - - let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-']; - keys.forEach( function(key) { - for (let i = 0; i < DashToDock_KeyboardShortcuts_NUM_HOTKEYS; i++) - Main.wm.removeKeybinding(key + (i + 1)); - }, this); - - this._hotKeysEnabled = false; - } - - _optionalNumberOverlay() { - let settings = DockManager.settings; - this._shortcutIsSet = false; - // Enable extra shortcut if either 'overlay' or 'show-dock' are true - if (settings.get_boolean('hot-keys') && - (settings.get_boolean('hotkeys-overlay') || settings.get_boolean('hotkeys-show-dock'))) - this._enableExtraShortcut(); - - this._signalsHandler.add([ - settings, - 'changed::hot-keys', - this._checkHotkeysOptions.bind(this) - ], [ - settings, - 'changed::hotkeys-overlay', - this._checkHotkeysOptions.bind(this) - ], [ - settings, - 'changed::hotkeys-show-dock', - this._checkHotkeysOptions.bind(this) - ]); - } - - _checkHotkeysOptions() { - let settings = DockManager.settings; - - if (settings.get_boolean('hot-keys') && - (settings.get_boolean('hotkeys-overlay') || settings.get_boolean('hotkeys-show-dock'))) - this._enableExtraShortcut(); - else - this._disableExtraShortcut(); - } - - _enableExtraShortcut() { - if (!this._shortcutIsSet) { - Main.wm.addKeybinding('shortcut', DockManager.settings, - Meta.KeyBindingFlags.IGNORE_AUTOREPEAT, - Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW, - this._showOverlay.bind(this)); - this._shortcutIsSet = true; - } - } - - _disableExtraShortcut() { - if (this._shortcutIsSet) { - Main.wm.removeKeybinding('shortcut'); - this._shortcutIsSet = false; - } - } - - _showOverlay() { - for (let dock of DockManager.allDocks) { - if (DockManager.settings.get_boolean('hotkeys-overlay')) - dock.dash.toggleNumberOverlay(true); - - // Restart the counting if the shortcut is pressed again - if (dock._numberOverlayTimeoutId) { - GLib.source_remove(dock._numberOverlayTimeoutId); - dock._numberOverlayTimeoutId = 0; - } - - // Hide the overlay/dock after the timeout - let timeout = DockManager.settings.get_double('shortcut-timeout') * 1000; - dock._numberOverlayTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, timeout, () => { - dock._numberOverlayTimeoutId = 0; - dock.dash.toggleNumberOverlay(false); - // Hide the dock again if necessary - dock._updateDashVisibility(); - }); - - // Show the dock if it is hidden - if (DockManager.settings.get_boolean('hotkeys-show-dock')) { - let showDock = (dock._intellihideIsEnabled || dock._autohideIsEnabled); - if (showDock) - dock._show(); - } - } - } -}; - -/** - * Isolate overview to open new windows for inactive apps - * Note: the future implementaion is not fully contained here. Some bits are around in other methods of other classes. - * This class just take care of enabling/disabling the option. - */ -var WorkspaceIsolation = class DashToDock_WorkspaceIsolation { - - constructor() { - - let settings = DockManager.settings; - - this._signalsHandler = new Utils.GlobalSignalsHandler(); - this._injectionsHandler = new Utils.InjectionsHandler(); - - this._signalsHandler.add([ - settings, - 'changed::isolate-workspaces', - () => { - DockManager.allDocks.forEach((dock) => - dock.dash.resetAppIcons()); - if (settings.get_boolean('isolate-workspaces') || - settings.get_boolean('isolate-monitors')) - this._enable.bind(this)(); - else - this._disable.bind(this)(); - } - ],[ - settings, - 'changed::isolate-monitors', - () => { - DockManager.allDocks.forEach((dock) => - dock.dash.resetAppIcons()); - if (settings.get_boolean('isolate-workspaces') || - settings.get_boolean('isolate-monitors')) - this._enable.bind(this)(); - else - this._disable.bind(this)(); - } - ]); - - if (settings.get_boolean('isolate-workspaces') || - settings.get_boolean('isolate-monitors')) - this._enable(); - - } - - _enable() { - - // ensure I never double-register/inject - // although it should never happen - this._disable(); - - DockManager.allDocks.forEach((dock) => { - this._signalsHandler.addWithLabel('isolation', [ - global.display, - 'restacked', - dock.dash._queueRedisplay.bind(dock.dash) - ], [ - global.window_manager, - 'switch-workspace', - dock.dash._queueRedisplay.bind(dock.dash) - ]); - - // This last signal is only needed for monitor isolation, as windows - // might migrate from one monitor to another without triggering 'restacked' - if (DockManager.settings.get_boolean('isolate-monitors')) - this._signalsHandler.addWithLabel('isolation', - global.display, - 'window-entered-monitor', - dock.dash._queueRedisplay.bind(dock.dash)); - }, this); - - // here this is the Shell.App - function IsolatedOverview() { - // These lines take care of Nautilus for icons on Desktop - let windows = this.get_windows().filter(function(w) { - return w.get_workspace().index() == global.workspace_manager.get_active_workspace_index(); - }); - if (windows.length == 1) - if (windows[0].skip_taskbar) - return this.open_new_window(-1); - - if (this.is_on_workspace(global.workspace_manager.get_active_workspace())) - return Main.activateWindow(windows[0]); - return this.open_new_window(-1); - } - - this._injectionsHandler.addWithLabel('isolation', - Shell.App.prototype, - 'activate', - IsolatedOverview); - } - - _disable () { - this._signalsHandler.removeWithLabel('isolation'); - this._injectionsHandler.removeWithLabel('isolation'); - } - - destroy() { - this._signalsHandler.destroy(); - this._injectionsHandler.destroy(); - } -}; - - -var DockManager = class DashToDock_DockManager { - - constructor() { - if (Me.imports.extension.dockManager) - throw new Error('DashToDock has been already initialized'); - - Me.imports.extension.dockManager = this; - - this._iconTheme = new Utils.IconTheme(); - this._remoteModel = new LauncherAPI.LauncherEntryRemoteModel(); - this._signalsHandler = new Utils.GlobalSignalsHandler(this); - this._methodInjections = new Utils.InjectionsHandler(this); - this._vfuncInjections = new Utils.VFuncInjectionsHandler(this); - this._propertyInjections = new Utils.PropertyInjectionsHandler(this); - this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.dash-to-dock'); - this._oldDash = Main.overview.isDummy ? null : Main.overview.dash; - - // Connect relevant signals to the toggling function - this._bindSettingsChanges(); - - this._ensureLocations(); - - /* Array of all the docks created */ - this._allDocks = []; - this._createDocks(); - - // status variable: true when the overview is shown through the dash - // applications button. - this._forcedOverview = false; - } - - static getDefault() { - return Me.imports.extension.dockManager - } - - static get allDocks() { - return DockManager.getDefault()._allDocks; - } - - static get settings() { - return DockManager.getDefault().settings; - } - - get settings() { - return this._settings; - } - - static get iconTheme() { - return DockManager.getDefault().iconTheme; - } - - get settings() { - return this._settings; - } - - get iconTheme() { - return this._iconTheme.iconTheme; - } - - get fm1Client() { - return this._fm1Client; - } - - get remoteModel() { - return this._remoteModel; - } - - get mainDock() { - return this._allDocks.length ? this._allDocks[0] : null; - } - - get removables() { - return this._removables; - } - - get trash() { - return this._trash; - } - - getDockByMonitor(monitorIndex) { - return this._allDocks.find(d => (d.monitorIndex === monitorIndex)); - } - - _ensureLocations() { - const showTrash = this._settings.get_boolean('show-trash'); - const showMounts = this._settings.get_boolean('show-mounts'); - - if (showTrash || showMounts) { - if (!this._fm1Client) - this._fm1Client = new FileManager1API.FileManager1Client(); - } else if (this._fm1Client) { - this._fm1Client.destroy(); - this._fm1Client = null; - } - - if (showMounts && !this._removables) { - this._removables = new Locations.Removables(); - } else if (!showMounts && this._removables) { - this._removables.destroy(); - this._removables = null; - } - - if (showTrash && !this._trash) { - this._trash = new Locations.Trash(); - } else if (!showTrash && this._trash) { - this._trash.destroy(); - this._trash = null; - } - - Locations.unWrapWindowsManagerApp(); - [this._methodInjections, this._vfuncInjections, this._propertyInjections].forEach( - injections => injections.removeWithLabel('locations')); - - if (showMounts || showTrash) { - this._vfuncInjections.addWithLabel('locations', Gio.DesktopAppInfo.prototype, - 'get_id', function () { return this.customId ?? this.vfunc_get_id() }); - - if (this.settings.isolateLocations) { - const fileManagerApp = Locations.wrapWindowsManagerApp(); - - this._methodInjections.addWithLabel('locations', [ - Shell.AppSystem.prototype, 'get_running', - function (originalMethod, ...args) { - const runningApps = originalMethod.call(this, ...args); - const locationApps = Locations.getRunningApps(); - if (!locationApps.length) - return runningApps; - - const fileManagerIdx = runningApps.indexOf(fileManagerApp); - if (fileManagerIdx > -1 && fileManagerApp?.state !== Shell.AppState.RUNNING) - runningApps.splice(fileManagerIdx, 1); - - return [...runningApps, ...locationApps].sort(Locations.shellAppCompare); - } - ], - [ - Shell.WindowTracker.prototype, 'get_window_app', - function (originalMethod, window) { - const locationApp = Locations.getRunningApps().find(a => - a.get_windows().includes(window)); - return locationApp ?? originalMethod.call(this, window); - } - ], - [ - Shell.WindowTracker.prototype, 'get_app_from_pid', - function (originalMethod, pid) { - const locationApp = Locations.getRunningApps().find(a => - a.get_pids().includes(pid)); - return locationApp ?? originalMethod.call(this, pid); - } - ]); - - const { get: defaultFocusAppGetter } = Object.getOwnPropertyDescriptor( - Shell.WindowTracker.prototype, 'focus_app'); - this._propertyInjections.addWithLabel('locations', - Shell.WindowTracker.prototype, 'focus_app', { - get: function () { - const locationApp = Locations.getRunningApps().find(a => a.isFocused); - return locationApp ?? defaultFocusAppGetter.call(this); - } - }); - } - } - } - - _toggle() { - if (this._toggleLater) - Meta.later_remove(this._toggleLater); - - this._toggleLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { - delete this._toggleLater; - this._restoreDash(); - this._deleteDocks(); - this._createDocks(); - this.emit('toggled'); - }); - } - - _bindSettingsChanges() { - this.settings.settingsSchema.list_keys().forEach(key => { - const camelKey = key.replace(/-([a-z\d])/g, k => k[1].toUpperCase()); - const updateSetting = () => - (this.settings[camelKey] = this.settings.get_value(key).recursiveUnpack()); - updateSetting(); - this._signalsHandler.addWithLabel('settings', this.settings, - `changed::${key}`, updateSetting); - }); - Object.defineProperties(this.settings, { - dockExtended: { get: () => this.settings.extendHeight }, - }); - - // Connect relevant signals to the toggling function - this._signalsHandler.add([ - Meta.MonitorManager.get(), - 'monitors-changed', - this._toggle.bind(this) - ], [ - Main.sessionMode, - 'updated', - this._toggle.bind(this) - ], [ - this._settings, - 'changed::multi-monitor', - this._toggle.bind(this) - ], [ - this._settings, - 'changed::preferred-monitor', - this._toggle.bind(this) - ], [ - this._settings, - 'changed::dock-position', - this._toggle.bind(this) - ], [ - this._settings, - 'changed::extend-height', - () => this._adjustPanelCorners() - ], [ - this._settings, - 'changed::dock-fixed', - () => this._adjustPanelCorners() - ], [ - this._settings, - 'changed::show-trash', - () => this._ensureLocations() - ], [ - this._settings, - 'changed::show-mounts', - () => this._ensureLocations() - ], [ - this._settings, - 'changed::isolate-locations', - () => this._ensureLocations() - ]); - } - - _createDocks() { - - // If there are no monitors (headless configurations, but it can also happen temporary while disconnecting - // and reconnecting monitors), just do nothing. When a monitor will be connected we we'll be notified and - // and thus create the docks. This prevents pointing trying to access monitors throughout the code, were we - // are assuming that at least the primary monitor is present. - if (Main.layoutManager.monitors.length <= 0) { - return; - } - - this._preferredMonitorIndex = this._settings.get_int('preferred-monitor'); - // In case of multi-monitor, we consider the dock on the primary monitor to be the preferred (main) one - // regardless of the settings - // The dock goes on the primary monitor also if the settings are incosistent (e.g. desired monitor not connected). - if (this._settings.get_boolean('multi-monitor') || - this._preferredMonitorIndex < 0 || this._preferredMonitorIndex > Main.layoutManager.monitors.length - 1 - ) { - this._preferredMonitorIndex = Main.layoutManager.primaryIndex; - } else { - // Primary monitor used to be always 0 in Gdk, but the shell has a different - // concept (where the order depends on mutter order). - // So even if now the extension settings may use the same logic of the shell - // we prefer not to break the previously configured systems, and so we still - // assume that the gsettings monitor numbering follows the old strategy. - // This ensure the indexing in the settings and in the shell are matched, - // i.e. that we start counting from the primaryMonitorIndex - this._preferredMonitorIndex = (Main.layoutManager.primaryIndex + this._preferredMonitorIndex) % Main.layoutManager.monitors.length ; - } - - // First we create the main Dock, to get the extra features to bind to this one - let dock = new DockedDash(this._preferredMonitorIndex); - this._allDocks.push(dock); - - // connect app icon into the view selector - dock.dash.showAppsButton.connect('notify::checked', this._onShowAppsButtonToggled.bind(this)); - - // Make the necessary changes to Main.overview.dash - this._prepareMainDash(); - - // Adjust corners if necessary - this._adjustPanelCorners(); - - if (this._settings.get_boolean('multi-monitor')) { - let nMon = Main.layoutManager.monitors.length; - for (let iMon = 0; iMon < nMon; iMon++) { - if (iMon == this._preferredMonitorIndex) - continue; - let dock = new DockedDash(iMon); - this._allDocks.push(dock); - // connect app icon into the view selector - dock.dash.showAppsButton.connect('notify::checked', this._onShowAppsButtonToggled.bind(this)); - } - } - - // Load optional features. We load *after* the docks are created, since - // we need to connect the signals to all dock instances. - this._workspaceIsolation = new WorkspaceIsolation(); - this._keyboardShortcuts = new KeyboardShortcuts(); - - this.emit('docks-ready'); - } - - _prepareMainDash() { - // Ensure Main.overview.dash is set to our dash in dummy mode - // while just use the default getter otherwise. - // The getter must be dynamic and not set only when we've a dummy - // overview because the mode can change dynamically. - this._propertyInjections.removeWithLabel('main-dash'); - let defaultDashGetter = Object.getOwnPropertyDescriptor( - Main.overview.constructor.prototype, 'dash').get; - this._propertyInjections.addWithLabel('main-dash', Main.overview, 'dash', { - get: () => Main.overview.isDummy ? - this.mainDock.dash : defaultDashGetter.call(Main.overview), - }); - - if (Main.overview.isDummy) - return; - - // Hide usual Dash - this._oldDash.hide(); - - // Also set dash width to 1, so it's almost not taken into account by code - // calculaing the reserved space in the overview. The reason to keep it at 1 is - // to allow its visibility change to trigger an allocaion of the appGrid which - // in turn is triggergin the appsIcon spring animation, required when no other - // actors has this effect, i.e in horizontal mode and without the workspaceThumnails - // 1 static workspace only) - this._oldDash.set_height(1); - - this._signalsHandler.addWithLabel('old-dash-changes', [ - this._oldDash, - 'notify::visible', - () => this._oldDash.hide() - ], [ - this._oldDash, - 'notify::height', - () => this._oldDash.set_height(1) - ]); - - // Pretend I'm the dash: meant to make appgrid swarm animation come from - // the right position of the appShowButton. - this.overviewControls.dash = this.mainDock.dash; - this.searchController._showAppsButton = this.mainDock.dash.showAppsButton; - - // We also need to ignore max-size changes - this._methodInjections.addWithLabel('main-dash', this._oldDash, - 'setMaxSize', () => {}); - this._methodInjections.addWithLabel('main-dash', this._oldDash, - 'allocate', () => {}); - // And to return the preferred height depending on the state - this._methodInjections.addWithLabel('main-dash', this._oldDash, - 'get_preferred_height', (_originalMethod, ...args) => { - if (this.mainDock.isHorizontal && !this.settings.dockFixed) - return this.mainDock.get_preferred_height(...args); - return [0, 0]; - }); - - const { ControlsManager, ControlsManagerLayout } = OverviewControls; - - this._methodInjections.addWithLabel('main-dash', ControlsManager.prototype, - 'runStartupAnimation', async function (originalMethod, callback) { - const injections = new Utils.InjectionsHandler(); - DockManager.allDocks.forEach(dock => (dock.opacity = 0)); - injections.add(DockManager.getDefault().mainDock.dash, 'ease', () => {}); - let callbackArgs = []; - const ret = await originalMethod.call(this, - (...args) => (callbackArgs = [...args])); - injections.destroy(); - - if (!DockManager.allDocks.length) { - // Docks may have been destroyed, let's wait till we've one again - const readyPromise = new Promise(resolve => { - const id = DockManager.getDefault().connect('docks-ready', () => { - DockManager.getDefault().disconnect(id); - resolve(); - }); - }) - await readyPromise; - } - - DockManager.allDocks.forEach(dock => { - const { dash } = dock; - - dash.set({ - opacity: 0, - translation_x: 0, - translation_y: 0, - }); - dock.opacity = 255; - - switch (dock.position) { - case St.Side.LEFT: - dash.translation_x = -dash.width; - break; - case St.Side.RIGHT: - dash.translation_x = dash.width; - break; - case St.Side.BOTTOM: - dash.translation_y = dash.height; - break; - case St.Side.TOP: - dash.translation_y = -dash.height; - break; - } - - const mainDockProperties = {}; - if (dock === DockManager.getDefault().mainDock) - mainDockProperties.onComplete = callback(...callbackArgs); - - const { STARTUP_ANIMATION_TIME } = Layout; - dash.ease({ - opacity: 255, - translation_x: 0, - translation_y: 0, - delay: STARTUP_ANIMATION_TIME, - duration: STARTUP_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - ...mainDockProperties, - }); - }); - return ret; - }); - - const maybeAdjustBoxToDock = box => { - if (this.mainDock.isHorizontal || this.settings.dockFixed) - return box; - - const [, preferredWidth] = this.mainDock.get_preferred_width(box.get_height()); - box.x2 -= preferredWidth; - if (this.mainDock.position === St.Side.LEFT) - box.set_origin(box.x1 + preferredWidth, box.y1); - - return box; - } - - this._vfuncInjections.addWithLabel('main-dash', ControlsManagerLayout.prototype, - 'allocate', function (container) { - const oldPostAllocation = this._runPostAllocation; - this._runPostAllocation = () => {}; - - const monitor = Main.layoutManager.findMonitorForActor(this._container); - const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index); - const startX = workArea.x - monitor.x; - const startY = workArea.y - monitor.y; - const workAreaBox = new Clutter.ActorBox(); - workAreaBox.set_origin(startX, startY); - workAreaBox.set_size(workArea.width, workArea.height); - - const propertyInjections = new Utils.PropertyInjectionsHandler(); - propertyInjections.add(Main.layoutManager.panelBox, 'height', { value: workAreaBox.y1 }); - - if (Main.layoutManager.panelBox.y === Main.layoutManager.primaryMonitor.y) - workAreaBox.y1 -= startY; - - this.vfunc_allocate(container, workAreaBox); - - propertyInjections.destroy(); - workAreaBox.y1 = startY; - maybeAdjustBoxToDock(workAreaBox); - - const adjustActorHorizontalAllocation = actor => { - if (!actor.visible || !workAreaBox.x1) - return; - - const contentBox = actor.get_allocation_box(); - contentBox.set_size(workAreaBox.get_width(), contentBox.get_height()); - contentBox.set_origin(workAreaBox.x1, contentBox.y1); - actor.allocate(contentBox); - }; - - [this._searchEntry, this._workspacesThumbnails, this._searchController].forEach( - actor => adjustActorHorizontalAllocation(actor)); - - this._runPostAllocation = oldPostAllocation; - this._runPostAllocation(); - }); - - // This can be removed or bypassed when GNOME/gnome-shell!1892 will be merged - function workspaceBoxOriginFixer(originalFunction, state, workAreaBox, ...args) { - const workspaceBox = originalFunction.call(this, state, workAreaBox, ...args); - workspaceBox.set_origin(workAreaBox.x1, workspaceBox.y1); - return workspaceBox; - }; - - this._methodInjections.addWithLabel('main-dash', [ - ControlsManagerLayout.prototype, - '_computeWorkspacesBoxForState', - function (originalFunction, state, ...args) { - const box = workspaceBoxOriginFixer.call(this, originalFunction, state, ...args); - if (state !== OverviewControls.ControlsState.HIDDEN) - maybeAdjustBoxToDock(box); - return box; - } - ], [ - ControlsManagerLayout.prototype, - '_getAppDisplayBoxForState', - function (...args) { - return maybeAdjustBoxToDock(workspaceBoxOriginFixer.call(this, ...args)); - } - ]); - - this._vfuncInjections.addWithLabel('main-dash', Workspace.WorkspaceBackground.prototype, - 'allocate', function (box) { - this.vfunc_allocate(box); - - // This code has been submitted upstream via GNOME/gnome-shell!1892 - // so can be removed when that gets merged (or bypassed on newer shell - // versions). - const monitor = Main.layoutManager.monitors[this._monitorIndex]; - const [contentWidth, contentHeight] = this._bin.get_content_box().get_size(); - const [mX1, mX2] = [monitor.x, monitor.x + monitor.width]; - const [mY1, mY2] = [monitor.y, monitor.y + monitor.height]; - const [wX1, wX2] = [this._workarea.x, this._workarea.x + this._workarea.width]; - const [wY1, wY2] = [this._workarea.y, this._workarea.y + this._workarea.height]; - const xScale = contentWidth / this._workarea.width; - const yScale = contentHeight / this._workarea.height; - const leftOffset = wX1 - mX1; - const topOffset = wY1 - mY1; - const rightOffset = mX2 - wX2; - const bottomOffset = mY2 - wY2; - - const contentBox = new Clutter.ActorBox(); - contentBox.set_origin(-leftOffset * xScale, -topOffset * yScale); - contentBox.set_size( - contentWidth + (leftOffset + rightOffset) * xScale, - contentHeight + (topOffset + bottomOffset) * yScale); - - this._backgroundGroup.allocate(contentBox); - }); - - // Always show the thumbnails box in fixed mode, so that we'll reduce the - // vertical space, causing the Workspace layout to show more workspaces. - // We might get the same also reducing the height of the workspace boxes - // in _computeWorkspacesBoxForState, but it would just waste vertical space - if (!this.mainDock.isHorizontal || this.settings.dockFixed) { - this._methodInjections.addWithLabel('main-dash', - WorkspaceThumbnail.ThumbnailsBox.prototype, '_updateShouldShow', - function () { - const shouldShow = global.workspace_manager.nWorkspaces > 1; - if (this._shouldShow === shouldShow) - return; - - this._shouldShow = shouldShow; - this.notify('should-show'); - }); - } - - // Reduce the space that the workspaces can use in secondary monitors - this._methodInjections.addWithLabel('main-dash', WorkspacesView.WorkspacesView.prototype, - '_getFirstFitAllWorkspaceBox', function (originalFunction, ...args) { - const box = originalFunction.call(this, ...args); - if (DockManager.settings.dockFixed || - this._monitorIndex === Main.layoutManager.primaryIndex) - return box; - - const dock = DockManager.getDefault().getDockByMonitor(this._monitorIndex); - if (!dock) - return box; - - if (dock.isHorizontal) { - const [, preferredHeight] = dock.get_preferred_height(box.get_width()); - box.y2 -= preferredHeight; - if (dock.position === St.Side.TOP) - box.set_origin(box.x1, box.y1 + preferredHeight); - } else { - const [, preferredWidth] = dock.get_preferred_width(box.get_height()); - box.x2 -= preferredWidth / 2; - if (dock.position === St.Side.LEFT) - box.set_origin(box.x1 + preferredWidth, box.y1); - } - return box; - }); - - // Ensure we handle Dnd events happening on the dock when we're dragging from AppDisplay - // Remove when merged https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2002 - this._methodInjections.addWithLabel('main-dash', AppDisplay.BaseAppView.prototype, - '_pageForCoords', function (originalFunction, ...args) { - if (!this._scrollView.has_pointer) - return AppDisplay.SidePages.NONE; - return originalFunction.call(this, ...args); - }); - } - - _deleteDocks() { - if (!this._allDocks.length) - return; - - // Remove extra features - this._workspaceIsolation.destroy(); - this._keyboardShortcuts.destroy(); - - // Delete all docks - this._allDocks.forEach(d => d.destroy()); - this._allDocks = []; - } - - _restoreDash() { - if (!this._oldDash) - return; - - this._signalsHandler.removeWithLabel('old-dash-changes'); - [this._methodInjections, this._vfuncInjections, this._propertyInjections].forEach( - injections => injections.removeWithLabel('main-dash')); - - this.overviewControls.layout_manager._dash = this._oldDash; - this.overviewControls.dash = this._oldDash; - this.searchController._showAppsButton = this._oldDash.showAppsButton; - Main.overview.dash.show(); - Main.overview.dash.set_height(-1); // reset default dash size - // This force the recalculation of the icon size - Main.overview.dash._maxHeight = -1; - } - - get overviewControls() { - return Main.overview._overview.controls; - } - - get searchController() { - return this.overviewControls._searchController; - } - - _onShowAppsButtonToggled(button) { - const { checked } = button; - const { overviewControls } = this; - - if (!Main.overview.visible) { - this.mainDock.dash.showAppsButton._fromDesktop = true; - if (this._settings.get_boolean('animate-show-apps')) { - Main.overview.show(OverviewControls.ControlsState.APP_GRID); - } else { - GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { - const oldAnimationTime = OverviewControls.SIDE_CONTROLS_ANIMATION_TIME; - Overview.ANIMATION_TIME = 1; - const id = Main.overview.connect('shown', () => { - Overview.ANIMATION_TIME = oldAnimationTime; - Main.overview.disconnect(id); - }); - Main.overview.show(OverviewControls.ControlsState.APP_GRID); - return GLib.SOURCE_REMOVE; - }); - } - } else { - if (!checked && this.mainDock.dash.showAppsButton._fromDesktop) { - if (this._settings.get_boolean('animate-show-apps')) { - Main.overview.hide(); - this.mainDock.dash.showAppsButton._fromDesktop = false; - } else { - GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { - const oldAnimationTime = Overview.ANIMATION_TIME; - Overview.ANIMATION_TIME = 1; - const id = Main.overview.connect('hidden', () => { - Overview.ANIMATION_TIME = oldAnimationTime; - Main.overview.disconnect(id); - }); - Main.overview.hide(); - this.mainDock.dash.showAppsButton._fromDesktop = false; - return GLib.SOURCE_REMOVE; - }); - } - } else { - // TODO: I'm not sure how reliable this is, we might need to move the - // _onShowAppsButtonToggled logic into the extension. - if (!checked) { - this.mainDock.dash.showAppsButton._fromDesktop = false; - } - - // Instead of "syncing" the stock button, let's call its callback directly. - overviewControls._onShowAppsButtonToggled.call(overviewControls); - } - } - - // Because we "disconnected" from the search controller, we have to manage its state. - this.searchController._setSearchActive(false); - } - - destroy() { - this.emit('destroy'); - if (this._toggleLater) { - Meta.later_remove(this._toggleLater); - delete this._toggleLater; - } - this._restoreDash(); - this._deleteDocks(); - this._revertPanelCorners(); - if (this._oldSelectorMargin) - this.searchController.margin_bottom = this._oldSelectorMargin; - if (this._fm1Client) { - this._fm1Client.destroy(); - this._fm1Client = null; - } - this._trash?.destroy(); - this._trash = null; - this._removables?.destroy(); - this._removables = null; - this._iconTheme.destroy(); - this._remoteModel.destroy(); - this._settings.run_dispose(); - this._settings = null; - this._oldDash = null; - - Me.imports.extension.dockManager = null; - } - - /** - * Adjust Panel corners - */ - _adjustPanelCorners() { - let position = Utils.getPosition(); - let isHorizontal = ((position == St.Side.TOP) || (position == St.Side.BOTTOM)); - let dockOnPrimary = this._settings.get_boolean('multi-monitor') || - this._preferredMonitorIndex == Main.layoutManager.primaryIndex; - - if (!isHorizontal && dockOnPrimary && this.settings.dockExtended && this.settings.dockFixed) { - Main.panel._rightCorner.hide(); - Main.panel._leftCorner.hide(); - } - else - this._revertPanelCorners(); - } - - _revertPanelCorners() { - Main.panel._leftCorner.show(); - Main.panel._rightCorner.show(); - } -}; -Signals.addSignalMethods(DockManager.prototype); - -// This class drives long-running icon animations, to keep them running in sync -// with each other, and to save CPU by pausing them when the dock is hidden. -var IconAnimator = class DashToDock_IconAnimator { - constructor(actor) { - this._count = 0; - this._started = false; - this._animations = { - dance: [], - }; - this._timeline = new Clutter.Timeline({ - duration: 3000, - repeat_count: -1, - actor - }); - - this._timeline.connect('new-frame', () => { - const progress = this._timeline.get_progress(); - const danceRotation = progress < 1/6 ? 15*Math.sin(progress*24*Math.PI) : 0; - const dancers = this._animations.dance; - for (let i = 0, iMax = dancers.length; i < iMax; i++) { - dancers[i].target.rotation_angle_z = danceRotation; - } - }); - } - - destroy() { - this._timeline.stop(); - this._timeline = null; - for (const name in this._animations) { - const pairs = this._animations[name]; - for (let i = 0, iMax = pairs.length; i < iMax; i++) { - const pair = pairs[i]; - pair.target.disconnect(pair.targetDestroyId); - } - } - this._animations = null; - } - - pause() { - if (this._started && this._count > 0) { - this._timeline.stop(); - } - this._started = false; - } - - start() { - if (!this._started && this._count > 0) { - this._timeline.start(); - } - this._started = true; - } - - addAnimation(target, name) { - const targetDestroyId = target.connect('destroy', () => this.removeAnimation(target, name)); - this._animations[name].push({ target, targetDestroyId }); - if (this._started && this._count === 0) { - this._timeline.start(); - } - this._count++; - } - - removeAnimation(target, name) { - const pairs = this._animations[name]; - for (let i = 0, iMax = pairs.length; i < iMax; i++) { - const pair = pairs[i]; - if (pair.target === target) { - target.disconnect(pair.targetDestroyId); - pairs.splice(i, 1); - this._count--; - if (this._started && this._count === 0) { - this._timeline.stop(); - } - return; - } - } - } -}; diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/extension.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/extension.js deleted file mode 100644 index 0b7b5c6..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/extension.js +++ /dev/null @@ -1,21 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Docking = Me.imports.docking; - -// We declare this with var so it can be accessed by other extensions in -// GNOME Shell 3.26+ (mozjs52+). -var dockManager; - -function init() { - ExtensionUtils.initTranslations('dashtodock'); -} - -function enable() { - new Docking.DockManager(); -} - -function disable() { - dockManager.destroy(); -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/fileManager1API.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/fileManager1API.js deleted file mode 100644 index 4ad7dc2..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/fileManager1API.js +++ /dev/null @@ -1,154 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const Gio = imports.gi.Gio; -const Signals = imports.signals; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Utils = Me.imports.utils; - -const FileManager1Iface = '\ - \ - '; - -const FileManager1Proxy = Gio.DBusProxy.makeProxyWrapper(FileManager1Iface); - -/** - * This class implements a client for the org.freedesktop.FileManager1 dbus - * interface, and specifically for the OpenWindowsWithLocations property - * which is published by Nautilus, but is not an official part of the interface. - * - * The property is a map from window identifiers to a list of locations open in - * the window. - */ -var FileManager1Client = class DashToDock_FileManager1Client { - - constructor() { - this._signalsHandler = new Utils.GlobalSignalsHandler(); - this._cancellable = new Gio.Cancellable(); - - this._locationMap = new Map(); - this._proxy = new FileManager1Proxy(Gio.DBus.session, - "org.freedesktop.FileManager1", - "/org/freedesktop/FileManager1", - (initable, error) => { - // Use async construction to avoid blocking on errors. - if (error) { - if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - global.log(error); - } else { - this._updateLocationMap(); - } - }, this._cancellable); - - this._signalsHandler.add([ - this._proxy, - 'g-properties-changed', - this._onPropertyChanged.bind(this) - ], [ - // We must additionally listen for Screen events to know when to - // rebuild our location map when the set of available windows changes. - global.workspace_manager, - 'workspace-switched', - this._updateLocationMap.bind(this) - ], [ - global.display, - 'window-entered-monitor', - this._updateLocationMap.bind(this) - ], [ - global.display, - 'window-left-monitor', - this._updateLocationMap.bind(this) - ]); - } - - destroy() { - this._cancellable.cancel(); - this._signalsHandler.destroy(); - this._proxy.run_dispose(); - } - - /** - * Return an array of windows that are showing a location or - * sub-directories of that location. - */ - getWindows(location) { - let ret = new Set(); - let locationEsc = location; - - if (!location.endsWith('/')) { - locationEsc += '/'; - } - - for (let [k,v] of this._locationMap) { - if ((k + '/').startsWith(locationEsc)) { - for (let l of v) { - ret.add(l); - } - } - } - return Array.from(ret); - } - - _onPropertyChanged(proxy, changed, invalidated) { - let property = changed.unpack(); - if (property && - ('OpenWindowsWithLocations' in property)) { - this._updateLocationMap(); - } - } - - _updateLocationMap() { - let properties = this._proxy.get_cached_property_names(); - if (properties == null) { - // Nothing to check yet. - return; - } - - if (properties.includes('OpenWindowsWithLocations')) { - this._updateFromPaths(); - } - } - - _updateFromPaths() { - let pathToLocations = this._proxy.OpenWindowsWithLocations; - let pathToWindow = getPathToWindow(); - - let locationToWindow = new Map(); - for (let path in pathToLocations) { - let locations = pathToLocations[path]; - for (let i = 0; i < locations.length; i++) { - let l = locations[i]; - // Use a set to deduplicate when a window has a - // location open in multiple tabs. - if (!locationToWindow.has(l)) { - locationToWindow.set(l, new Set()); - } - let window = pathToWindow.get(path); - if (window != null) { - locationToWindow.get(l).add(window); - } - } - } - this._locationMap = locationToWindow; - this.emit('windows-changed'); - } -} -Signals.addSignalMethods(FileManager1Client.prototype); - -/** - * Construct a map of gtk application window object paths to MetaWindows. - */ -function getPathToWindow() { - let pathToWindow = new Map(); - - for (let i = 0; i < global.workspace_manager.n_workspaces; i++) { - let ws = global.workspace_manager.get_workspace_by_index(i); - ws.list_windows().map(function(w) { - let path = w.get_gtk_window_object_path(); - if (path != null) { - pathToWindow.set(path, w); - } - }); - } - return pathToWindow; -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/intellihide.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/intellihide.js deleted file mode 100644 index 9c10938..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/intellihide.js +++ /dev/null @@ -1,321 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const GLib = imports.gi.GLib; -const Meta = imports.gi.Meta; -const Shell = imports.gi.Shell; - -const Main = imports.ui.main; -const Signals = imports.signals; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Docking = Me.imports.docking; -const Utils = Me.imports.utils; - -// A good compromise between reactivity and efficiency; to be tuned. -const INTELLIHIDE_CHECK_INTERVAL = 100; - -const OverlapStatus = { - UNDEFINED: -1, - FALSE: 0, - TRUE: 1 -}; - -const IntellihideMode = { - ALL_WINDOWS: 0, - FOCUS_APPLICATION_WINDOWS: 1, - MAXIMIZED_WINDOWS : 2 -}; - -// List of windows type taken into account. Order is important (keep the original -// enum order). -const handledWindowTypes = [ - Meta.WindowType.NORMAL, - Meta.WindowType.DOCK, - Meta.WindowType.DIALOG, - Meta.WindowType.MODAL_DIALOG, - Meta.WindowType.TOOLBAR, - Meta.WindowType.MENU, - Meta.WindowType.UTILITY, - Meta.WindowType.SPLASHSCREEN -]; - -/** - * A rough and ugly implementation of the intellihide behaviour. - * Intallihide object: emit 'status-changed' signal when the overlap of windows - * with the provided targetBoxClutter.ActorBox changes; - */ -var Intellihide = class DashToDock_Intellihide { - - constructor(monitorIndex) { - // Load settings - this._monitorIndex = monitorIndex; - - this._signalsHandler = new Utils.GlobalSignalsHandler(); - this._tracker = Shell.WindowTracker.get_default(); - this._focusApp = null; // The application whose window is focused. - this._topApp = null; // The application whose window is on top on the monitor with the dock. - - this._isEnabled = false; - this.status = OverlapStatus.UNDEFINED; - this._targetBox = null; - - this._checkOverlapTimeoutContinue = false; - this._checkOverlapTimeoutId = 0; - - this._trackedWindows = new Map(); - - // Connect global signals - this._signalsHandler.add([ - // Add signals on windows created from now on - global.display, - 'window-created', - this._windowCreated.bind(this) - ], [ - // triggered for instance when the window list order changes, - // included when the workspace is switched - global.display, - 'restacked', - this._checkOverlap.bind(this) - ], [ - // when windows are alwasy on top, the focus window can change - // without the windows being restacked. Thus monitor window focus change. - this._tracker, - 'notify::focus-app', - this._checkOverlap.bind(this) - ], [ - // update wne monitor changes, for instance in multimonitor when monitor are attached - Meta.MonitorManager.get(), - 'monitors-changed', - this._checkOverlap.bind(this) - ]); - } - - destroy() { - // Disconnect global signals - this._signalsHandler.destroy(); - - // Remove residual windows signals - this.disable(); - } - - enable() { - this._isEnabled = true; - this._status = OverlapStatus.UNDEFINED; - global.get_window_actors().forEach(function(wa) { - this._addWindowSignals(wa); - }, this); - this._doCheckOverlap(); - } - - disable() { - this._isEnabled = false; - - for (let wa of this._trackedWindows.keys()) { - this._removeWindowSignals(wa); - } - this._trackedWindows.clear(); - - if (this._checkOverlapTimeoutId > 0) { - GLib.source_remove(this._checkOverlapTimeoutId); - this._checkOverlapTimeoutId = 0; - } - } - - _windowCreated(display, metaWindow) { - this._addWindowSignals(metaWindow.get_compositor_private()); - } - - _addWindowSignals(wa) { - if (!this._handledWindow(wa)) - return; - let signalId = wa.connect('notify::allocation', this._checkOverlap.bind(this)); - this._trackedWindows.set(wa, signalId); - wa.connect('destroy', this._removeWindowSignals.bind(this)); - } - - _removeWindowSignals(wa) { - if (this._trackedWindows.get(wa)) { - wa.disconnect(this._trackedWindows.get(wa)); - this._trackedWindows.delete(wa); - } - - } - - updateTargetBox(box) { - this._targetBox = box; - this._checkOverlap(); - } - - forceUpdate() { - this._status = OverlapStatus.UNDEFINED; - this._doCheckOverlap(); - } - - getOverlapStatus() { - return (this._status == OverlapStatus.TRUE); - } - - _checkOverlap() { - if (!this._isEnabled || (this._targetBox == null)) - return; - - /* Limit the number of calls to the doCheckOverlap function */ - if (this._checkOverlapTimeoutId) { - this._checkOverlapTimeoutContinue = true; - return - } - - this._doCheckOverlap(); - - this._checkOverlapTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, INTELLIHIDE_CHECK_INTERVAL, () => { - this._doCheckOverlap(); - if (this._checkOverlapTimeoutContinue) { - this._checkOverlapTimeoutContinue = false; - return GLib.SOURCE_CONTINUE; - } else { - this._checkOverlapTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - }); - } - - _doCheckOverlap() { - - if (!this._isEnabled || (this._targetBox == null)) - return; - - let overlaps = OverlapStatus.FALSE; - let windows = global.get_window_actors(); - - if (windows.length > 0) { - /* - * Get the top window on the monitor where the dock is placed. - * The idea is that we dont want to overlap with the windows of the topmost application, - * event is it's not the focused app -- for instance because in multimonitor the user - * select a window in the secondary monitor. - */ - - let topWindow = null; - for (let i = windows.length - 1; i >= 0; i--) { - let meta_win = windows[i].get_meta_window(); - if (this._handledWindow(windows[i]) && (meta_win.get_monitor() == this._monitorIndex)) { - topWindow = meta_win; - break; - } - } - - if (topWindow !== null) { - this._topApp = this._tracker.get_window_app(topWindow); - // If there isn't a focused app, use that of the window on top - this._focusApp = this._tracker.focus_app || this._topApp - - windows = windows.filter(this._intellihideFilterInteresting, this); - - for (let i = 0; i < windows.length; i++) { - let win = windows[i].get_meta_window(); - - if (win) { - let rect = win.get_frame_rect(); - - let test = (rect.x < this._targetBox.x2) && - (rect.x + rect.width > this._targetBox.x1) && - (rect.y < this._targetBox.y2) && - (rect.y + rect.height > this._targetBox.y1); - - if (test) { - overlaps = OverlapStatus.TRUE; - break; - } - } - } - } - } - - if (this._status !== overlaps) { - this._status = overlaps; - this.emit('status-changed', this._status); - } - - } - - // Filter interesting windows to be considered for intellihide. - // Consider all windows visible on the current workspace. - // Optionally skip windows of other applications - _intellihideFilterInteresting(wa) { - let meta_win = wa.get_meta_window(); - if (!this._handledWindow(wa)) - return false; - - let currentWorkspace = global.workspace_manager.get_active_workspace_index(); - let wksp = meta_win.get_workspace(); - let wksp_index = wksp.index(); - - // Depending on the intellihide mode, exclude non-relevent windows - switch (Docking.DockManager.settings.get_enum('intellihide-mode')) { - case IntellihideMode.ALL_WINDOWS: - // Do nothing - break; - - case IntellihideMode.FOCUS_APPLICATION_WINDOWS: - // Skip windows of other apps - if (this._focusApp) { - // The DropDownTerminal extension is not an application per se - // so we match its window by wm class instead - if (meta_win.get_wm_class() == 'DropDownTerminalWindow') - return true; - - let currentApp = this._tracker.get_window_app(meta_win); - let focusWindow = global.display.get_focus_window() - - // Consider half maximized windows side by side - // and windows which are alwayson top - if((currentApp != this._focusApp) && (currentApp != this._topApp) - && !((focusWindow && focusWindow.maximized_vertically && !focusWindow.maximized_horizontally) - && (meta_win.maximized_vertically && !meta_win.maximized_horizontally) - && meta_win.get_monitor() == focusWindow.get_monitor()) - && !meta_win.is_above()) - return false; - } - break; - - case IntellihideMode.MAXIMIZED_WINDOWS: - // Skip unmaximized windows - if (!meta_win.maximized_vertically && !meta_win.maximized_horizontally) - return false; - break; - } - - if ( wksp_index == currentWorkspace && meta_win.showing_on_its_workspace() ) - return true; - else - return false; - - } - - // Filter windows by type - // inspired by Opacify@gnome-shell.localdomain.pl - _handledWindow(wa) { - let metaWindow = wa.get_meta_window(); - - if (!metaWindow) - return false; - - // The DropDownTerminal extension uses the POPUP_MENU window type hint - // so we match its window by wm class instead - if (metaWindow.get_wm_class() == 'DropDownTerminalWindow') - return true; - - let wtype = metaWindow.get_window_type(); - for (let i = 0; i < handledWindowTypes.length; i++) { - var hwtype = handledWindowTypes[i]; - if (hwtype == wtype) - return true; - else if (hwtype > wtype) - return false; - } - return false; - } -}; - -Signals.addSignalMethods(Intellihide.prototype); diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/launcherAPI.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/launcherAPI.js deleted file mode 100644 index 55f44f7..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/launcherAPI.js +++ /dev/null @@ -1,281 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const Gio = imports.gi.Gio; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const DbusmenuUtils = Me.imports.dbusmenuUtils; - -const Dbusmenu = DbusmenuUtils.haveDBusMenu(); - -var LauncherEntryRemoteModel = class DashToDock_LauncherEntryRemoteModel { - - constructor() { - this._entrySourceStacks = new Map(); - this._remoteMaps = new Map(); - - this._launcher_entry_dbus_signal_id = - Gio.DBus.session.signal_subscribe(null, // sender - 'com.canonical.Unity.LauncherEntry', // iface - 'Update', // member - null, // path - null, // arg0 - Gio.DBusSignalFlags.NONE, - (connection, sender_name, object_path, interface_name, signal_name, parameters) => - this._onUpdate(sender_name, ...parameters.deep_unpack())); - - this._dbus_name_owner_changed_signal_id = - Gio.DBus.session.signal_subscribe('org.freedesktop.DBus', // sender - 'org.freedesktop.DBus', // interface - 'NameOwnerChanged', // member - '/org/freedesktop/DBus', // path - null, // arg0 - Gio.DBusSignalFlags.NONE, - (connection, sender_name, object_path, interface_name, signal_name, parameters) => - this._onDBusNameChange(...parameters.deep_unpack().slice(1))); - - this._acquireUnityDBus(); - } - - destroy() { - if (this._launcher_entry_dbus_signal_id) { - Gio.DBus.session.signal_unsubscribe(this._launcher_entry_dbus_signal_id); - } - - if (this._dbus_name_owner_changed_signal_id) { - Gio.DBus.session.signal_unsubscribe(this._dbus_name_owner_changed_signal_id); - } - - this._releaseUnityDBus(); - } - - _lookupStackById(appId) { - let sourceStack = this._entrySourceStacks.get(appId); - if (!sourceStack) { - this._entrySourceStacks.set(appId, sourceStack = new PropertySourceStack(new LauncherEntry(), launcherEntryDefaults)); - } - return sourceStack; - } - - lookupById(appId) { - return this._lookupStackById(appId).target; - } - - _acquireUnityDBus() { - if (!this._unity_bus_id) { - this._unity_bus_id = Gio.DBus.session.own_name('com.canonical.Unity', - Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT | Gio.BusNameOwnerFlags.REPLACE, - null, () => this._unity_bus_id = 0); - } - } - - _releaseUnityDBus() { - if (this._unity_bus_id) { - Gio.DBus.session.unown_name(this._unity_bus_id); - this._unity_bus_id = 0; - } - } - - _onDBusNameChange(before, after) { - if (!before || !this._remoteMaps.size) { - return; - } - const remoteMap = this._remoteMaps.get(before); - if (!remoteMap) { - return; - } - this._remoteMaps.delete(before); - if (after && !this._remoteMaps.has(after)) { - this._remoteMaps.set(after, remoteMap); - } else { - for (const [appId, remote] of remoteMap) { - const sourceStack = this._entrySourceStacks.get(appId); - const changed = sourceStack.remove(remote); - if (changed) { - sourceStack.target._emitChangedEvents(changed); - } - } - } - } - - _onUpdate(senderName, appUri, properties) { - if (!senderName) { - return; - } - - const appId = appUri.replace(/(^\w+:|^)\/\//, ''); - if (!appId) { - return; - } - - let remoteMap = this._remoteMaps.get(senderName); - if (!remoteMap) { - this._remoteMaps.set(senderName, remoteMap = new Map()); - } - let remote = remoteMap.get(appId); - if (!remote) { - remoteMap.set(appId, remote = Object.assign({}, launcherEntryDefaults)); - } - for (const name in properties) { - if (name === 'quicklist' && Dbusmenu) { - const quicklistPath = properties[name].unpack(); - if (quicklistPath && (!remote._quicklistMenuClient || remote._quicklistMenuClient.dbus_object !== quicklistPath)) { - remote.quicklist = null; - let menuClient = remote._quicklistMenuClient; - if (menuClient) { - menuClient.dbus_object = quicklistPath; - } else { - // This property should not be enumerable - Object.defineProperty(remote, '_quicklistMenuClient', { - writable: true, - value: menuClient = new Dbusmenu.Client({ dbus_name: senderName, dbus_object: quicklistPath }), - }); - } - const handler = () => { - const root = menuClient.get_root(); - if (remote.quicklist !== root) { - remote.quicklist = root; - if (sourceStack.isTop(remote)) { - sourceStack.target.quicklist = root; - sourceStack.target._emitChangedEvents(['quicklist']); - } - } - }; - menuClient.connect(Dbusmenu.CLIENT_SIGNAL_ROOT_CHANGED, handler); - } - } else { - remote[name] = properties[name].unpack(); - } - } - - const sourceStack = this._lookupStackById(appId); - sourceStack.target._emitChangedEvents(sourceStack.update(remote)); - } -}; - -const launcherEntryDefaults = { - count: 0, - progress: 0, - urgent: false, - quicklist: null, - 'count-visible': false, - 'progress-visible': false, -}; - -const LauncherEntry = class DashToDock_LauncherEntry { - constructor() { - this._connections = new Map(); - this._handlers = new Map(); - this._nextId = 0; - } - - connect(eventNames, callback) { - if (typeof eventNames === 'string') { - eventNames = [eventNames]; - } - callback(this, this); - const id = this._nextId++; - const handler = { id, callback }; - eventNames.forEach(name => { - let handlerList = this._handlers.get(name); - if (!handlerList) { - this._handlers.set(name, handlerList = []); - } - handlerList.push(handler); - }); - this._connections.set(id, eventNames); - return id; - } - - disconnect(id) { - const eventNames = this._connections.get(id); - if (!eventNames) { - return; - } - this._connections.delete(id); - eventNames.forEach(name => { - const handlerList = this._handlers.get(name); - if (handlerList) { - for (let i = 0, iMax = handlerList.length; i < iMax; i++) { - if (handlerList[i].id === id) { - handlerList.splice(i, 1); - break; - } - } - } - }); - } - - _emitChangedEvents(propertyNames) { - const handlers = new Set(); - propertyNames.forEach(name => { - const handlerList = this._handlers.get(name + '-changed'); - if (handlerList) { - for (let i = 0, iMax = handlerList.length; i < iMax; i++) { - handlers.add(handlerList[i]); - } - } - }); - Array.from(handlers).sort((x, y) => x.id - y.id).forEach(handler => handler.callback(this, this)); - } -} - -for (const name in launcherEntryDefaults) { - const jsName = name.replace(/-/g, '_'); - LauncherEntry.prototype[jsName] = launcherEntryDefaults[name]; - if (jsName !== name) { - Object.defineProperty(LauncherEntry.prototype, name, { - get() { - return this[jsName]; - }, - set(value) { - this[jsName] = value; - }, - }); - } -} - -const PropertySourceStack = class DashToDock_PropertySourceStack { - constructor(target, bottom) { - this.target = target; - this._bottom = bottom; - this._stack = []; - } - - isTop(source) { - return this._stack.length > 0 && this._stack[this._stack.length - 1] === source; - } - - update(source) { - if (!this.isTop(source)) { - this.remove(source); - this._stack.push(source); - } - return this._assignFrom(source); - } - - remove(source) { - const stack = this._stack; - const top = stack[stack.length - 1]; - if (top === source) { - stack.length--; - return this._assignFrom(stack.length > 0 ? stack[stack.length - 1] : this._bottom); - } - for (let i = 0, iMax = stack.length; i < iMax; i++) { - if (stack[i] === source) { - stack.splice(i, 1); - break; - } - } - } - - _assignFrom(source) { - const changedProperties = []; - for (const name in source) { - if (this.target[name] !== source[name]) { - this.target[name] = source[name]; - changedProperties.push(name); - } - } - return changedProperties; - } -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/ar/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/ar/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 78deaa5..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/ar/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/cs/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/cs/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 1cc799d..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/cs/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/de/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/de/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index f7b2ed5..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/de/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/el/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/el/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index b116119..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/el/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/es/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/es/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 99888b0..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/es/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/eu/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/eu/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 03fec78..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/eu/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/fr/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/fr/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index a9a712c..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/fr/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/gl/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/gl/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index b89c102..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/gl/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/hu/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/hu/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 6e2d85e..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/hu/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/id/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/id/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 950b3ff..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/id/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/it/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/it/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index fc1f722..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/it/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/ja/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/ja/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 9b9b943..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/ja/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/nb/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/nb/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 005884f..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/nb/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/nl/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/nl/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 91063e8..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/nl/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/pl/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/pl/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index c9d87d9..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/pl/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/pt/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/pt/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index b298694..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/pt/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/pt_BR/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/pt_BR/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index cbe7c66..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/pt_BR/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/ru/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/ru/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 0c187f3..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/ru/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sk/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sk/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 5b25bec..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sk/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sr/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sr/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index da3e086..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sr/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sr@latin/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sr@latin/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 1fcfb47..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sr@latin/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sv/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sv/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index bab036e..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/sv/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/tr/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/tr/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index b2e36b6..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/tr/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/uk_UA/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/uk_UA/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index a475c96..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/uk_UA/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/zh_CN/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/zh_CN/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 8ebfc33..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/zh_CN/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/zh_TW/LC_MESSAGES/dashtodock.mo b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/zh_TW/LC_MESSAGES/dashtodock.mo deleted file mode 100644 index 3ca257a..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locale/zh_TW/LC_MESSAGES/dashtodock.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locations.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locations.js deleted file mode 100644 index 7373335..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/locations.js +++ /dev/null @@ -1,660 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; -const Shell = imports.gi.Shell; -const Signals = imports.signals; - -// Use __ () and N__() for the extension gettext domain, and reuse -// the shell domain with the default _() and N_() -const Gettext = imports.gettext.domain('dashtodock'); -const __ = Gettext.gettext; -const N__ = function(e) { return e }; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Docking = Me.imports.docking; -const Utils = Me.imports.utils; - -const FILE_MANAGER_DESKTOP_APP_ID = 'org.gnome.Nautilus.desktop'; -const TRASH_URI = 'trash://'; -const UPDATE_TRASH_DELAY = 500; - -const NautilusFileOperations2Interface = '\ - \ - \ - \ - \ - \ - \ -'; - -const NautilusFileOperations2ProxyInterface = Gio.DBusProxy.makeProxyWrapper(NautilusFileOperations2Interface); - -function makeNautilusFileOperationsProxy() { - const proxy = new NautilusFileOperations2ProxyInterface( - Gio.DBus.session, - 'org.gnome.Nautilus', - '/org/gnome/Nautilus/FileOperations2', (_p, error) => { - if (error) - logError(error, 'Error connecting to Nautilus'); - } - ); - - proxy.platformData = params => { - const defaultParams = { - parentHandle: '', - timestamp: global.get_current_time(), - windowPosition: 'center', - }; - const { parentHandle, timestamp, windowPosition } = { - ...defaultParams, - ...params, - }; - - return { - 'parent-handle': new GLib.Variant('s', parentHandle), - 'timestamp': new GLib.Variant('u', timestamp), - 'window-position': new GLib.Variant('s', windowPosition), - }; - }; - - return proxy; -} - -function wrapWindowsBackedApp(shellApp) { - if (shellApp._dtdData) - throw new Error('%s has been already wrapped'.format(shellApp)); - - shellApp._dtdData = { - windows: [], - methodInjections: new Utils.InjectionsHandler(), - propertyInjections: new Utils.PropertyInjectionsHandler(), - destroy: function () { - this.windows = []; - this.methodInjections.destroy(); - this.propertyInjections.destroy(); - } - }; - - const m = (...args) => shellApp._dtdData.methodInjections.add(shellApp, ...args); - const p = (...args) => shellApp._dtdData.propertyInjections.add(shellApp, ...args); - shellApp._mi = m; - shellApp._pi = p; - - m('get_state', () => - shellApp.get_windows().length ? Shell.AppState.RUNNING : Shell.AppState.STOPPED); - p('state', { get: () => shellApp.get_state() }); - - m('get_windows', () => shellApp._dtdData.windows); - m('get_n_windows', () => shellApp.get_windows().length); - m('get_pids', () => shellApp.get_windows().reduce((pids, w) => { - if (w.get_pid() > 0 && !pids.includes(w.get_pid())) - pids.push(w.get_pid()); - return pids; - }, [])); - m('is_on_workspace', (_om, workspace) => shellApp.get_windows().some(w => - w.get_workspace() === workspace)); - m('request_quit', () => shellApp.get_windows().filter(w => - w.can_close()).forEach(w => w.delete(global.get_current_time()))); - - shellApp._updateWindows = function () { - throw new GObject.NotImplementedError(`_updateWindows in ${this.constructor.name}`); - }; - - let updateWindowsIdle = GLib.idle_add(GLib.DEFAULT_PRIORITY, () => { - shellApp._updateWindows(); - updateWindowsIdle = undefined; - return GLib.SOURCE_REMOVE; - }); - - const windowTracker = Shell.WindowTracker.get_default(); - shellApp._checkFocused = function () { - if (this.get_windows().some(w => w.has_focus())) { - this.isFocused = true; - windowTracker.notify('focus-app'); - } else if (this.isFocused) { - this.isFocused = false; - windowTracker.notify('focus-app'); - } - } - - shellApp._checkFocused(); - const focusWindowNotifyId = global.display.connect('notify::focus-window', () => - shellApp._checkFocused()); - - // Re-implements shell_app_activate_window for generic activation and alt-tab support - m('activate_window', function (_om, window, timestamp) { - if (!window) - [window] = this.get_windows(); - else if (!this.get_windows().includes(window)) - return; - - const currentWorkspace = global.workspace_manager.get_active_workspace(); - const workspace = window.get_workspace(); - const sameWorkspaceWindows = this.get_windows().filter(w => - w.get_workspace() === workspace); - sameWorkspaceWindows.forEach(w => w.raise()); - - if (workspace !== currentWorkspace) - workspace.activate_with_focus(window, timestamp); - else - window.activate(timestamp); - }); - - // Re-implements shell_app_activate_full for generic activation and dash support - m('activate_full', function (_om, workspace, timestamp) { - if (!timestamp) - timestamp = global.get_current_time(); - - switch (this.state) { - case Shell.AppState.STOPPED: - try { - this.launch(timestamp, workspace, Shell.AppLaunchGpu.APP_PREF); - } catch (e) { - global.notify_error(__("Failed to launch “%s”".format( - this.get_name())), e.message); - } - break; - case Shell.AppState.RUNNING: - this.activate_window(null, timestamp); - break; - } - }); - - m('activate', () => shellApp.activate_full(-1, 0)); - - m('compare', (_om, other) => shellAppCompare(shellApp, other)); - - shellApp.destroy = function() { - global.display.disconnect(focusWindowNotifyId); - updateWindowsIdle && GLib.source_remove(updateWindowsIdle); - this._dtdData.destroy(); - this._dtdData = undefined; - this.destroy = undefined; - } - - return shellApp; -} - -// We can't inherit from Shell.App as it's a final type, so let's patch it -function makeLocationApp(params) { - if (!params.location) - throw new TypeError('Invalid location'); - - location = params.location; - delete params.location; - - const shellApp = new Shell.App(params); - wrapWindowsBackedApp(shellApp); - shellApp.appInfo.customId = 'location:%s'.format(location); - - Object.defineProperties(shellApp, { - location: { value: location }, - isTrash: { value: location.startsWith(TRASH_URI) }, - }); - - shellApp._mi('toString', defaultToString => - '[LocationApp - %s]'.format(defaultToString.call(shellApp))); - - // FIXME: We need to add a new API to Nautilus to open new windows - shellApp._mi('can_open_new_window', () => false); - - const { fm1Client } = Docking.DockManager.getDefault(); - shellApp._updateWindows = function () { - const oldState = this.state; - const oldWindows = this.get_windows(); - this._dtdData.windows = fm1Client.getWindows(this.location); - - if (this.get_windows().length !== oldWindows.length || - this.get_windows().some((win, index) => win !== oldWindows[index])) - this.emit('windows-changed'); - - if (oldState !== this.state) { - Shell.AppSystem.get_default().emit('app-state-changed', this); - this.notify('state'); - this._checkFocused(); - } - }; - - const windowsChangedId = fm1Client.connect('windows-changed', () => - shellApp._updateWindows()); - - const parentDestroy = shellApp.destroy; - shellApp.destroy = function () { - fm1Client.disconnect(windowsChangedId); - parentDestroy.call(this); - } - - return shellApp; -} - -function getFileManagerApp() { - return Shell.AppSystem.get_default().lookup_app(FILE_MANAGER_DESKTOP_APP_ID); -} - -function wrapWindowsManagerApp() { - const fileManagerApp = getFileManagerApp(); - if (!fileManagerApp) - return null; - - if (fileManagerApp._dtdData) - return fileManagerApp; - - const originalGetWindows = fileManagerApp.get_windows; - wrapWindowsBackedApp(fileManagerApp); - - const { fm1Client } = Docking.DockManager.getDefault(); - const windowsChangedId = fileManagerApp.connect('windows-changed', () => - fileManagerApp._updateWindows()); - const fm1WindowsChangedId = fm1Client.connect('windows-changed', () => - fileManagerApp._updateWindows()); - - fileManagerApp._updateWindows = function () { - const oldState = this.state; - const oldWindows = this.get_windows(); - const locationWindows = []; - getRunningApps().forEach(a => locationWindows.push(...a.get_windows())); - this._dtdData.windows = originalGetWindows.call(this).filter(w => - !locationWindows.includes(w)); - - if (this.get_windows().length !== oldWindows.length || - this.get_windows().some((win, index) => win !== oldWindows[index])) { - this.block_signal_handler(windowsChangedId); - this.emit('windows-changed'); - this.unblock_signal_handler(windowsChangedId); - } - - if (oldState !== this.state) { - Shell.AppSystem.get_default().emit('app-state-changed', this); - this.notify('state'); - this._checkFocused(); - } - }; - - fileManagerApp._mi('toString', defaultToString => - '[FileManagerApp - %s]'.format(defaultToString.call(fileManagerApp))); - - const parentDestroy = fileManagerApp.destroy; - fileManagerApp.destroy = function () { - fileManagerApp.disconnect(windowsChangedId); - fm1Client.disconnect(fm1WindowsChangedId); - parentDestroy.call(this); - } - - return fileManagerApp; -} - -function unWrapWindowsManagerApp() { - const fileManagerApp = getFileManagerApp(); - if (!fileManagerApp || !fileManagerApp._dtdData) - return; - - fileManagerApp.destroy(); -} - -// Re-implements shell_app_compare so that can be used to resort running apps -function shellAppCompare(app, other) { - if (app.state !== other.state) { - if (app.state === Shell.AppState.RUNNING) - return -1; - return 1; - } - - const windows = app.get_windows(); - const otherWindows = other.get_windows(); - - const isMinimized = windows => !windows.some(w => w.showing_on_its_workspace()); - const otherMinimized = isMinimized(otherWindows); - if (isMinimized(windows) != otherMinimized) { - if (otherMinimized) - return -1; - return 1; - } - - if (app.state === Shell.AppState.RUNNING) { - if (windows.length && !otherWindows.length) - return -1; - else if (!windows.length && otherWindows.length) - return 1; - - const lastUserTime = windows => - Math.max(...windows.map(w => w.get_user_time())); - return lastUserTime(otherWindows) - lastUserTime(windows); - } - - return 0; -} - -/** - * This class maintains a Shell.App representing the Trash and keeps it - * up-to-date as the trash fills and is emptied over time. - */ -var Trash = class DashToDock_Trash { - _promisified = false; - - static initPromises() { - if (Trash._promisified) - return; - - Gio._promisify(Gio.FileEnumerator.prototype, 'close_async', 'close_finish'); - Gio._promisify(Gio.FileEnumerator.prototype, 'next_files_async', 'next_files_finish'); - Gio._promisify(Gio.file_new_for_uri(TRASH_URI).constructor.prototype, - 'enumerate_children_async', 'enumerate_children_finish'); - Trash._promisified = true; - } - - constructor() { - Trash.initPromises(); - this._cancellable = new Gio.Cancellable(); - this._file = Gio.file_new_for_uri(TRASH_URI); - try { - this._monitor = this._file.monitor_directory(0, this._cancellable); - this._signalId = this._monitor.connect( - 'changed', - this._onTrashChange.bind(this) - ); - } catch (e) { - if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - return; - logError(e, 'Impossible to monitor trash'); - } - this._empty = true; - this._schedUpdateId = 0; - this._updateTrash(); - } - - destroy() { - this._cancellable.cancel(); - this._cancellable = null; - this._monitor?.disconnect(this._signalId); - this._monitor = null; - this._file = null; - this._trashApp?.destroy(); - } - - _onTrashChange() { - if (this._schedUpdateId) { - GLib.source_remove(this._schedUpdateId); - } - this._schedUpdateId = GLib.timeout_add( - GLib.PRIORITY_LOW, UPDATE_TRASH_DELAY, () => { - this._schedUpdateId = 0; - this._updateTrash(); - return GLib.SOURCE_REMOVE; - }); - } - - async _updateTrash() { - try { - const priority = GLib.PRIORITY_LOW; - const cancellable = this._cancellable; - const childrenEnumerator = await this._file.enumerate_children_async( - Gio.FILE_ATTRIBUTE_STANDARD_TYPE, Gio.FileQueryInfoFlags.NONE, - priority, cancellable); - const children = await childrenEnumerator.next_files_async(1, - priority, cancellable); - this._empty = !children.length; - this._ensureApp(); - - await childrenEnumerator.close_async(priority, null); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e, 'Impossible to enumerate trash children'); - } - } - - _ensureApp() { - if (this._trashApp == null || - this._lastEmpty !== this._empty) { - let trashKeys = new GLib.KeyFile(); - trashKeys.set_string('Desktop Entry', 'Name', __('Trash')); - trashKeys.set_string('Desktop Entry', 'Icon', - this._empty ? 'user-trash' : 'user-trash-full'); - trashKeys.set_string('Desktop Entry', 'Type', 'Application'); - trashKeys.set_string('Desktop Entry', 'Exec', 'gio open %s'.format(TRASH_URI)); - trashKeys.set_string('Desktop Entry', 'StartupNotify', 'false'); - if (!this._empty) { - trashKeys.set_string('Desktop Entry', 'Actions', 'empty-trash;'); - trashKeys.set_string('Desktop Action empty-trash', 'Name', __('Empty Trash')); - trashKeys.set_string('Desktop Action empty-trash', 'Exec', 'true'); - } - - let trashAppInfo = Gio.DesktopAppInfo.new_from_keyfile(trashKeys); - this._trashApp?.destroy(); - this._trashApp = makeLocationApp({ - location: TRASH_URI + '/', - appInfo: trashAppInfo, - }); - - if (!this._empty) { - this._trashApp._mi('launch_action', - (launchAction, actionName, timestamp, ...args) => { - if (actionName === 'empty-trash') { - const nautilus = makeNautilusFileOperationsProxy(); - const askConfirmation = true; - nautilus.EmptyTrashRemote(askConfirmation, - nautilus.platformData({ timestamp }), (_p, error) => { - if (error) - logError(error, 'Empty trash failed'); - }); - return; - } - - return launchAction.call(this, actionName, timestamp, ...args); - }); - } - this._lastEmpty = this._empty; - - this.emit('changed'); - } - } - - getApp() { - this._ensureApp(); - return this._trashApp; - } -} -Signals.addSignalMethods(Trash.prototype); - -/** - * This class maintains Shell.App representations for removable devices - * plugged into the system, and keeps the list of Apps up-to-date as - * devices come and go and are mounted and unmounted. - */ -var Removables = class DashToDock_Removables { - - constructor() { - this._signalsHandler = new Utils.GlobalSignalsHandler(); - - this._monitor = Gio.VolumeMonitor.get(); - this._volumeApps = [] - this._mountApps = [] - - this._monitor.get_volumes().forEach( - (volume) => { - this._onVolumeAdded(this._monitor, volume); - } - ); - - this._monitor.get_mounts().forEach( - (mount) => { - this._onMountAdded(this._monitor, mount); - } - ); - - this._signalsHandler.add([ - this._monitor, - 'mount-added', - this._onMountAdded.bind(this) - ], [ - this._monitor, - 'mount-removed', - this._onMountRemoved.bind(this) - ], [ - this._monitor, - 'volume-added', - this._onVolumeAdded.bind(this) - ], [ - this._monitor, - 'volume-removed', - this._onVolumeRemoved.bind(this) - ]); - } - - destroy() { - this._signalsHandler.destroy(); - this._monitor.run_dispose(); - } - - _getWorkingIconName(icon) { - if (icon instanceof Gio.EmblemedIcon) { - icon = icon.get_icon(); - } - if (icon instanceof Gio.ThemedIcon) { - const { iconTheme } = Docking.DockManager.getDefault(); - let names = icon.get_names(); - for (let i = 0; i < names.length; i++) { - let iconName = names[i]; - if (iconTheme.has_icon(iconName)) { - return iconName; - } - } - return ''; - } else { - return icon.to_string(); - } - } - - _onVolumeAdded(monitor, volume) { - if (!volume.can_mount()) { - return; - } - - if (volume.get_identifier('class') == 'network') { - return; - } - - let activationRoot = volume.get_activation_root(); - if (!activationRoot) { - // Can't offer to mount a device if we don't know - // where to mount it. - // These devices are usually ejectable so you - // don't normally unmount them anyway. - return; - } - - let escapedUri = activationRoot.get_uri() - let uri = GLib.uri_unescape_string(escapedUri, null); - - let volumeKeys = new GLib.KeyFile(); - volumeKeys.set_string('Desktop Entry', 'Name', volume.get_name()); - volumeKeys.set_string('Desktop Entry', 'Icon', this._getWorkingIconName(volume.get_icon())); - volumeKeys.set_string('Desktop Entry', 'Type', 'Application'); - volumeKeys.set_string('Desktop Entry', 'Exec', 'gio open "' + uri + '"'); - volumeKeys.set_string('Desktop Entry', 'StartupNotify', 'false'); - volumeKeys.set_string('Desktop Entry', 'Actions', 'mount;'); - volumeKeys.set_string('Desktop Action mount', 'Name', __('Mount')); - volumeKeys.set_string('Desktop Action mount', 'Exec', 'gio mount "' + uri + '"'); - let volumeAppInfo = Gio.DesktopAppInfo.new_from_keyfile(volumeKeys); - const volumeApp = makeLocationApp({ - location: escapedUri, - appInfo: volumeAppInfo, - }); - this._volumeApps.push(volumeApp); - this.emit('changed'); - } - - _onVolumeRemoved(monitor, volume) { - for (let i = 0; i < this._volumeApps.length; i++) { - let app = this._volumeApps[i]; - if (app.get_name() == volume.get_name()) { - const [volumeApp] = this._volumeApps.splice(i, 1); - volumeApp.destroy(); - } - } - this.emit('changed'); - } - - _onMountAdded(monitor, mount) { - // Filter out uninteresting mounts - if (!mount.can_eject() && !mount.can_unmount()) - return; - if (mount.is_shadowed()) - return; - - let volume = mount.get_volume(); - if (!volume || volume.get_identifier('class') == 'network') { - return; - } - - const escapedUri = mount.get_default_location().get_uri() - let uri = GLib.uri_unescape_string(escapedUri, null); - - let mountKeys = new GLib.KeyFile(); - mountKeys.set_string('Desktop Entry', 'Name', mount.get_name()); - mountKeys.set_string('Desktop Entry', 'Icon', - this._getWorkingIconName(volume.get_icon())); - mountKeys.set_string('Desktop Entry', 'Type', 'Application'); - mountKeys.set_string('Desktop Entry', 'Exec', 'gio open "' + uri + '"'); - mountKeys.set_string('Desktop Entry', 'StartupNotify', 'false'); - mountKeys.set_string('Desktop Entry', 'Actions', 'unmount;'); - if (mount.can_eject()) { - mountKeys.set_string('Desktop Action unmount', 'Name', __('Eject')); - mountKeys.set_string('Desktop Action unmount', 'Exec', - 'gio mount -e "' + uri + '"'); - } else { - mountKeys.set_string('Desktop Entry', 'Actions', 'unmount;'); - mountKeys.set_string('Desktop Action unmount', 'Name', __('Unmount')); - mountKeys.set_string('Desktop Action unmount', 'Exec', - 'gio mount -u "' + uri + '"'); - } - let mountAppInfo = Gio.DesktopAppInfo.new_from_keyfile(mountKeys); - const mountApp = makeLocationApp({ - appInfo: mountAppInfo, - location: escapedUri, - }); - this._mountApps.push(mountApp); - this.emit('changed'); - } - - _onMountRemoved(monitor, mount) { - for (let i = 0; i < this._mountApps.length; i++) { - let app = this._mountApps[i]; - if (app.get_name() == mount.get_name()) { - const [mountApp] = this._mountApps.splice(i, 1); - mountApp.destroy(); - } - } - this.emit('changed'); - } - - getApps() { - // When we have both a volume app and a mount app, we prefer - // the mount app. - let apps = new Map(); - this._volumeApps.map(function(app) { - apps.set(app.get_name(), app); - }); - this._mountApps.map(function(app) { - apps.set(app.get_name(), app); - }); - - return [...apps.values()]; - } -} -Signals.addSignalMethods(Removables.prototype); - -function getRunningApps() { - const dockManager = Docking.DockManager.getDefault(); - const locationApps = []; - - if (dockManager.removables) - locationApps.push(...dockManager.removables.getApps()); - - if (dockManager.trash) - locationApps.push(dockManager.trash.getApp()); - - return locationApps.filter(a => a.state === Shell.AppState.RUNNING); -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/glossy.svg b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/glossy.svg deleted file mode 100644 index 55b71ba..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/glossy.svg +++ /dev/null @@ -1,139 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/highlight_stacked_bg.svg b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/highlight_stacked_bg.svg deleted file mode 100644 index 19be5a9..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/highlight_stacked_bg.svg +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/highlight_stacked_bg_h.svg b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/highlight_stacked_bg_h.svg deleted file mode 100644 index eeaa869..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/highlight_stacked_bg_h.svg +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - image/svg+xml - - - - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/logo.svg b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/logo.svg deleted file mode 100644 index eebd0b1..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/media/logo.svg +++ /dev/null @@ -1,528 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dash to Dock - Michele - - - - - - - - - - - - - - - - - - - - - - diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/metadata.json b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/metadata.json deleted file mode 100644 index 5aa5350..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/metadata.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "A dock for the Gnome Shell. This extension moves the dash out of the overview transforming it in a dock for an easier launching of applications and a faster switching between windows and desktops. Side and bottom placement options are available.", - "gettext-domain": "dashtodock", - "name": "Dash to Dock", - "original-author": "micxgx@gmail.com", - "shell-version": [ - "40", - "41" - ], - "url": "https://micheleg.github.io/dash-to-dock/", - "uuid": "dash-to-dock@micxgx.gmail.com", - "version": 71 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/prefs.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/prefs.js deleted file mode 100644 index 532eef4..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/prefs.js +++ /dev/null @@ -1,1029 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -imports.gi.versions.Gtk = '4.0'; -imports.gi.versions.Gdk = '4.0'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; -const Gdk = imports.gi.Gdk; -const Signals = imports.signals; - -// Use __ () and N__() for the extension gettext domain, and reuse -// the shell domain with the default _() and N_() -const Gettext = imports.gettext.domain('dashtodock'); -const __ = Gettext.gettext; -const N__ = function (e) { return e }; - -try { - imports.misc.extensionUtils; -} catch (e) { - const resource = Gio.Resource.load( - '/usr/share/gnome-shell/org.gnome.Extensions.src.gresource'); - resource._register(); - imports.searchPath.push('resource:///org/gnome/Extensions/js'); -} - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const SCALE_UPDATE_TIMEOUT = 500; -const DEFAULT_ICONS_SIZES = [128, 96, 64, 48, 32, 24, 16]; - -const TransparencyMode = { - DEFAULT: 0, - FIXED: 1, - DYNAMIC: 3 -}; - -const RunningIndicatorStyle = { - DEFAULT: 0, - DOTS: 1, - SQUARES: 2, - DASHES: 3, - SEGMENTED: 4, - SOLID: 5, - CILIORA: 6, - METRO: 7 -}; - -class MonitorsConfig { - static XML_INTERFACE = - '\ - \ - \ - \ - \ - \ - \ - \ - \ - \ - '; - - static ProxyWrapper = Gio.DBusProxy.makeProxyWrapper(MonitorsConfig.XML_INTERFACE); - - constructor() { - this._monitorsConfigProxy = new MonitorsConfig.ProxyWrapper( - Gio.DBus.session, - "org.gnome.Mutter.DisplayConfig", - "/org/gnome/Mutter/DisplayConfig" - ); - - // Connecting to a D-Bus signal - this._monitorsConfigProxy.connectSignal("MonitorsChanged", - () => this._updateResources()); - - this._primaryMonitor = null; - this._monitors = []; - this._logicalMonitors = []; - - this._updateResources(); - } - - _updateResources() { - this._monitorsConfigProxy.GetCurrentStateRemote((resources, err) => { - if (err) { - logError(err); - return; - } - - const [_serial, monitors, logicalMonitors] = resources; - let index = 0; - for (const monitor of monitors) { - const [monitorSpecs, _modes, props] = monitor; - const [connector, vendor, product, serial] = monitorSpecs; - this._monitors.push({ - index: index++, - active: false, - connector, vendor, product, serial, - displayName: props['display-name'].unpack(), - }); - } - - for (const logicalMonitor of logicalMonitors) { - const [_x, _y, _scale, _transform, isPrimary, monitorsSpecs] = - logicalMonitor; - - // We only care about the first one really - for (const monitorSpecs of monitorsSpecs) { - const [connector, vendor, product, serial] = monitorSpecs; - const monitor = this._monitors.find(m => - m.connector === connector && m.vendor === vendor && - m.product === product && m.serial === serial); - - if (monitor) { - monitor.active = true; - monitor.isPrimary = isPrimary; - if (monitor.isPrimary) - this._primaryMonitor = monitor; - break; - } - } - } - - const activeMonitors = this._monitors.filter(m => m.active); - if (activeMonitors.length > 1 && logicalMonitors.length == 1) { - // We're in cloning mode, so let's just activate the primary monitor - this._monitors.forEach(m => (m.active = false)); - this._primaryMonitor.active = true; - } - - this._updateMonitorsIndexes(); - this.emit('updated'); - }); - } - - _updateMonitorsIndexes() { - // This function ensures that we follow the old Gdk indexing strategy - // for monitors, it can be removed when we don't care about breaking - // old user configurations or external apps configuring this extension - // such as ubuntu's gnome-control-center. - const { index: primaryMonitorIndex } = this._primaryMonitor; - for (const monitor of this._monitors) { - let { index } = monitor; - // The The dock uses the Gdk index for monitors, where the primary monitor - // always has index 0, so let's follow what dash-to-dock does in docking.js - // (as part of _createDocks), but using inverted math - index -= primaryMonitorIndex; - - if (index < 0) - index += this._monitors.length; - - monitor.index = index; - } - } - - get primaryMonitor() { - return this._primaryMonitor; - } - - get monitors() { - return this._monitors; - } -} -Signals.addSignalMethods(MonitorsConfig.prototype); - -function setShortcut(settings) { - const shortcutText = settings.get_string('shortcut-text'); - const [success, key, mods] = Gtk.accelerator_parse(shortcutText); - - if (success && Gtk.accelerator_valid(key, mods)) { - let shortcut = Gtk.accelerator_name(key, mods); - settings.set_strv('shortcut', [shortcut]); - } else { - settings.set_strv('shortcut', []); - } -} - -var Settings = GObject.registerClass({ - Implements: [Gtk.BuilderScope], -}, class DashToDock_Settings extends GObject.Object { - - _init() { - super._init(); - - if (Me) - this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.dash-to-dock'); - else - this._settings = new Gio.Settings({schema_id: 'org.gnome.shell.extensions.dash-to-dock'}); - - this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL); - - this._builder = new Gtk.Builder(); - this._builder.set_scope(this); - if (Me) { - this._builder.set_translation_domain(Me.metadata['gettext-domain']); - this._builder.add_from_file(Me.path + '/Settings.ui'); - } else { - this._builder.add_from_file('./Settings.ui'); - } - - this.widget = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER }); - this._notebook = this._builder.get_object('settings_notebook'); - this.widget.set_child(this._notebook); - - // Set a reasonable initial window height - this.widget.connect('realize', () => { - const window = this.widget.get_root(); - window.set_size_request(-1, 750); - }); - - // Timeout to delay the update of the settings - this._dock_size_timeout = 0; - this._icon_size_timeout = 0; - this._opacity_timeout = 0; - - this._monitorsConfig = new MonitorsConfig(); - this._bindSettings(); - } - - vfunc_create_closure(builder, handlerName, flags, connectObject) { - if (flags & Gtk.BuilderClosureFlags.SWAPPED) - throw new Error('Unsupported template signal flag "swapped"'); - - if (typeof this[handlerName] === 'undefined') - throw new Error(`${handlerName} is undefined`); - - return this[handlerName].bind(connectObject || this); - } - - dock_display_combo_changed_cb(combo) { - if (!this._monitors?.length) - return; - - const preferredMonitor = this._monitors[combo.get_active()].index; - this._settings.set_int('preferred-monitor', preferredMonitor); - } - - position_top_button_toggled_cb(button) { - if (button.get_active()) - this._settings.set_enum('dock-position', 0); - } - - position_right_button_toggled_cb(button) { - if (button.get_active()) - this._settings.set_enum('dock-position', 1); - } - - position_bottom_button_toggled_cb(button) { - if (button.get_active()) - this._settings.set_enum('dock-position', 2); - } - - position_left_button_toggled_cb(button) { - if (button.get_active()) - this._settings.set_enum('dock-position', 3); - } - - icon_size_combo_changed_cb(combo) { - this._settings.set_int('dash-max-icon-size', this._allIconSizes[combo.get_active()]); - } - - dock_size_scale_value_changed_cb(scale) { - // Avoid settings the size continuously - if (this._dock_size_timeout > 0) - GLib.source_remove(this._dock_size_timeout); - const id = this._dock_size_timeout = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, SCALE_UPDATE_TIMEOUT, () => { - if (id === this._dock_size_timeout) { - this._settings.set_double('height-fraction', scale.get_value()); - this._dock_size_timeout = 0; - return GLib.SOURCE_REMOVE; - } - }); - } - - icon_size_scale_value_changed_cb(scale) { - // Avoid settings the size consinuosly - if (this._icon_size_timeout > 0) - GLib.source_remove(this._icon_size_timeout); - this._icon_size_timeout = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, SCALE_UPDATE_TIMEOUT, () => { - log(scale.get_value()); - this._settings.set_int('dash-max-icon-size', scale.get_value()); - this._icon_size_timeout = 0; - return GLib.SOURCE_REMOVE; - }); - } - preview_size_scale_format_value_cb(scale, value) { - return value == 0 ? 'auto' : value; - } - preview_size_scale_value_changed_cb(scale) { - this._settings.set_double('preview-size-scale', scale.get_value()); - } - custom_opacity_scale_value_changed_cb(scale) { - // Avoid settings the opacity consinuosly as it's change is animated - if (this._opacity_timeout > 0) - GLib.source_remove(this._opacity_timeout); - this._opacity_timeout = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, SCALE_UPDATE_TIMEOUT, () => { - this._settings.set_double('background-opacity', scale.get_value()); - this._opacity_timeout = 0; - return GLib.SOURCE_REMOVE; - }); - } - min_opacity_scale_value_changed_cb(scale) { - // Avoid settings the opacity consinuosly as it's change is animated - if (this._opacity_timeout > 0) - GLib.source_remove(this._opacity_timeout); - this._opacity_timeout = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, SCALE_UPDATE_TIMEOUT, () => { - this._settings.set_double('min-alpha', scale.get_value()); - this._opacity_timeout = 0; - return GLib.SOURCE_REMOVE; - }); - } - max_opacity_scale_value_changed_cb(scale) { - // Avoid settings the opacity consinuosly as it's change is animated - if (this._opacity_timeout > 0) - GLib.source_remove(this._opacity_timeout); - this._opacity_timeout = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, SCALE_UPDATE_TIMEOUT, () => { - this._settings.set_double('max-alpha', scale.get_value()); - this._opacity_timeout = 0; - return GLib.SOURCE_REMOVE; - }); - } - - all_windows_radio_button_toggled_cb(button) { - if (button.get_active()) - this._settings.set_enum('intellihide-mode', 0); - } - focus_application_windows_radio_button_toggled_cb(button) { - if (button.get_active()) - this._settings.set_enum('intellihide-mode', 1); - } - maximized_windows_radio_button_toggled_cb(button) { - if (button.get_active()) - this._settings.set_enum('intellihide-mode', 2); - } - - _updateMonitorsSettings() { - // Monitor options - const preferredMonitor = this._settings.get_int('preferred-monitor'); - const dockMonitorCombo = this._builder.get_object('dock_monitor_combo'); - - this._monitors = []; - dockMonitorCombo.remove_all(); - - // Add connected monitors - for (const monitor of this._monitorsConfig.monitors) { - if (!monitor.active && monitor.index !== preferredMonitor) - continue; - - if (monitor.isPrimary) { - dockMonitorCombo.append_text( - /* Translators: This will be followed by Display Name - Connector. */ - __('Primary monitor: ') + monitor.displayName + ' - ' + - monitor.connector); - } else { - dockMonitorCombo.append_text( - /* Translators: Followed by monitor index, Display Name - Connector. */ - __('Secondary monitor ') + (monitor.index + 1) + ' - ' + - monitor.displayName + ' - ' + monitor.connector); - } - - this._monitors.push(monitor); - - if (monitor.index === preferredMonitor) - dockMonitorCombo.set_active(this._monitors.length - 1); - } - } - - _bindSettings() { - // Position and size panel - - this._updateMonitorsSettings(); - this._monitorsConfig.connect('updated', () => this._updateMonitorsSettings()); - - // Position option - let position = this._settings.get_enum('dock-position'); - - switch (position) { - case 0: - this._builder.get_object('position_top_button').set_active(true); - break; - case 1: - this._builder.get_object('position_right_button').set_active(true); - break; - case 2: - this._builder.get_object('position_bottom_button').set_active(true); - break; - case 3: - this._builder.get_object('position_left_button').set_active(true); - break; - } - - if (this._rtl) { - /* Left is Right in rtl as a setting */ - this._builder.get_object('position_left_button').set_label(__('Right')); - this._builder.get_object('position_right_button').set_label(__('Left')); - } - - // Intelligent autohide options - this._settings.bind('dock-fixed', - this._builder.get_object('intelligent_autohide_switch'), - 'active', - Gio.SettingsBindFlags.INVERT_BOOLEAN); - this._settings.bind('dock-fixed', - this._builder.get_object('intelligent_autohide_button'), - 'sensitive', - Gio.SettingsBindFlags.INVERT_BOOLEAN); - this._settings.bind('autohide', - this._builder.get_object('autohide_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('autohide-in-fullscreen', - this._builder.get_object('autohide_enable_in_fullscreen_checkbutton'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('require-pressure-to-show', - this._builder.get_object('require_pressure_checkbutton'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('intellihide', - this._builder.get_object('intellihide_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('animation-time', - this._builder.get_object('animation_duration_spinbutton'), - 'value', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('hide-delay', - this._builder.get_object('hide_timeout_spinbutton'), - 'value', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-delay', - this._builder.get_object('show_timeout_spinbutton'), - 'value', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('pressure-threshold', - this._builder.get_object('pressure_threshold_spinbutton'), - 'value', - Gio.SettingsBindFlags.DEFAULT); - - //this._builder.get_object('animation_duration_spinbutton').set_value(this._settings.get_double('animation-time')); - - // Create dialog for intelligent autohide advanced settings - this._builder.get_object('intelligent_autohide_button').connect('clicked', () => { - - let dialog = new Gtk.Dialog({ - title: __('Intelligent autohide customization'), - transient_for: this.widget.get_root(), - use_header_bar: true, - modal: true - }); - - // GTK+ leaves positive values for application-defined response ids. - // Use +1 for the reset action - dialog.add_button(__('Reset to defaults'), 1); - - let box = this._builder.get_object('intelligent_autohide_advanced_settings_box'); - dialog.get_content_area().append(box); - - this._settings.bind('intellihide', - this._builder.get_object('intellihide_mode_box'), - 'sensitive', - Gio.SettingsBindFlags.GET); - - // intellihide mode - - let intellihideModeRadioButtons = [ - this._builder.get_object('all_windows_radio_button'), - this._builder.get_object('focus_application_windows_radio_button'), - this._builder.get_object('maximized_windows_radio_button') - ]; - - intellihideModeRadioButtons[this._settings.get_enum('intellihide-mode')].set_active(true); - - this._settings.bind('autohide', - this._builder.get_object('require_pressure_checkbutton'), - 'sensitive', - Gio.SettingsBindFlags.GET); - - this._settings.bind('autohide', - this._builder.get_object('autohide_enable_in_fullscreen_checkbutton'), - 'sensitive', - Gio.SettingsBindFlags.GET); - - this._settings.bind('require-pressure-to-show', - this._builder.get_object('show_timeout_spinbutton'), - 'sensitive', - Gio.SettingsBindFlags.INVERT_BOOLEAN); - this._settings.bind('require-pressure-to-show', - this._builder.get_object('show_timeout_label'), - 'sensitive', - Gio.SettingsBindFlags.INVERT_BOOLEAN); - this._settings.bind('require-pressure-to-show', - this._builder.get_object('pressure_threshold_spinbutton'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('require-pressure-to-show', - this._builder.get_object('pressure_threshold_label'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT); - - dialog.connect('response', (dialog, id) => { - if (id == 1) { - // restore default settings for the relevant keys - let keys = ['intellihide', 'autohide', 'intellihide-mode', 'autohide-in-fullscreen', 'require-pressure-to-show', - 'animation-time', 'show-delay', 'hide-delay', 'pressure-threshold']; - keys.forEach(function (val) { - this._settings.set_value(val, this._settings.get_default_value(val)); - }, this); - intellihideModeRadioButtons[this._settings.get_enum('intellihide-mode')].set_active(true); - } else { - // remove the settings box so it doesn't get destroyed; - dialog.get_content_area().remove(box); - dialog.destroy(); - } - return; - }); - - dialog.present(); - - }); - - // size options - const dock_size_scale = this._builder.get_object('dock_size_scale'); - dock_size_scale.set_value(this._settings.get_double('height-fraction')); - dock_size_scale.add_mark(0.9, Gtk.PositionType.TOP, null); - dock_size_scale.set_format_value_func((_, value) => { - return Math.round(value * 100) + ' %'; - }); - let icon_size_scale = this._builder.get_object('icon_size_scale'); - icon_size_scale.set_range(8, DEFAULT_ICONS_SIZES[0]); - icon_size_scale.set_value(this._settings.get_int('dash-max-icon-size')); - DEFAULT_ICONS_SIZES.forEach(function (val) { - icon_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString()); - }); - icon_size_scale.set_format_value_func((_, value) => { - return value + ' px'; - }); - this._builder.get_object('preview_size_scale').set_value(this._settings.get_double('preview-size-scale')); - - // Corrent for rtl languages - if (this._rtl) { - // Flip value position: this is not done automatically - dock_size_scale.set_value_pos(Gtk.PositionType.LEFT); - icon_size_scale.set_value_pos(Gtk.PositionType.LEFT); - // I suppose due to a bug, having a more than one mark and one above a value of 100 - // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable - // and then manually inverting it - icon_size_scale.set_flippable(false); - icon_size_scale.set_inverted(true); - } - - this._settings.bind('icon-size-fixed', this._builder.get_object('icon_size_fixed_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('extend-height', this._builder.get_object('dock_size_extend_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('extend-height', this._builder.get_object('dock_size_scale'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN); - - this._settings.bind('multi-monitor', - this._builder.get_object('dock_monitor_combo'), - 'sensitive', - Gio.SettingsBindFlags.INVERT_BOOLEAN); - - - // Apps panel - - this._settings.bind('show-running', - this._builder.get_object('show_running_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('isolate-workspaces', - this._builder.get_object('application_button_isolation_button'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('isolate-monitors', - this._builder.get_object('application_button_monitor_isolation_button'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-windows-preview', - this._builder.get_object('windows_preview_button'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('multi-monitor', - this._builder.get_object('multi_monitor_button'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-favorites', - this._builder.get_object('show_favorite_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-trash', - this._builder.get_object('show_trash_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-mounts', - this._builder.get_object('show_mounts_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('isolate-locations', - this._builder.get_object('isolate_locations_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - const isolateLocationsBindings = ['show_trash_switch', 'show_mounts_switch']; - const updateIsolateLocations = () => { - this._builder.get_object('isolate_locations_row').sensitive = - isolateLocationsBindings.some(s => this._builder.get_object(s).active); - }; - updateIsolateLocations(); - isolateLocationsBindings.forEach(s => this._builder.get_object(s).connect( - 'notify::active', () => updateIsolateLocations())); - this._settings.bind('show-show-apps-button', - this._builder.get_object('show_applications_button_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-apps-at-top', - this._builder.get_object('application_button_first_button'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-show-apps-button', - this._builder.get_object('application_button_first_button'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('animate-show-apps', - this._builder.get_object('application_button_animation_button'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('show-show-apps-button', - this._builder.get_object('application_button_animation_button'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('scroll-to-focused-application', - this._builder.get_object('scroll_to_icon_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - - - // Behavior panel - - this._settings.bind('hot-keys', - this._builder.get_object('hot_keys_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('hot-keys', - this._builder.get_object('overlay_button'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT); - - this._builder.get_object('click_action_combo').set_active(this._settings.get_enum('click-action')); - this._builder.get_object('click_action_combo').connect('changed', (widget) => { - this._settings.set_enum('click-action', widget.get_active()); - }); - - this._builder.get_object('scroll_action_combo').set_active(this._settings.get_enum('scroll-action')); - this._builder.get_object('scroll_action_combo').connect('changed', (widget) => { - this._settings.set_enum('scroll-action', widget.get_active()); - }); - - this._builder.get_object('shift_click_action_combo').connect('changed', (widget) => { - this._settings.set_enum('shift-click-action', widget.get_active()); - }); - - this._builder.get_object('middle_click_action_combo').connect('changed', (widget) => { - this._settings.set_enum('middle-click-action', widget.get_active()); - }); - this._builder.get_object('shift_middle_click_action_combo').connect('changed', (widget) => { - this._settings.set_enum('shift-middle-click-action', widget.get_active()); - }); - - // Create dialog for number overlay options - this._builder.get_object('overlay_button').connect('clicked', () => { - - let dialog = new Gtk.Dialog({ - title: __('Show dock and application numbers'), - transient_for: this.widget.get_root(), - use_header_bar: true, - modal: true - }); - - // GTK+ leaves positive values for application-defined response ids. - // Use +1 for the reset action - dialog.add_button(__('Reset to defaults'), 1); - - let box = this._builder.get_object('box_overlay_shortcut'); - dialog.get_content_area().append(box); - - this._builder.get_object('overlay_switch').set_active(this._settings.get_boolean('hotkeys-overlay')); - this._builder.get_object('show_dock_switch').set_active(this._settings.get_boolean('hotkeys-show-dock')); - - // We need to update the shortcut 'strv' when the text is modified - this._settings.connect('changed::shortcut-text', () => setShortcut(this._settings)); - this._settings.bind('shortcut-text', - this._builder.get_object('shortcut_entry'), - 'text', - Gio.SettingsBindFlags.DEFAULT); - - this._settings.bind('hotkeys-overlay', - this._builder.get_object('overlay_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('hotkeys-show-dock', - this._builder.get_object('show_dock_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('shortcut-timeout', - this._builder.get_object('timeout_spinbutton'), - 'value', - Gio.SettingsBindFlags.DEFAULT); - - dialog.connect('response', (dialog, id) => { - if (id == 1) { - // restore default settings for the relevant keys - let keys = ['shortcut-text', 'hotkeys-overlay', 'hotkeys-show-dock', 'shortcut-timeout']; - keys.forEach(function (val) { - this._settings.set_value(val, this._settings.get_default_value(val)); - }, this); - } else { - // remove the settings box so it doesn't get destroyed; - dialog.get_content_area().remove(box); - dialog.destroy(); - } - return; - }); - - dialog.present(); - }); - - // Create dialog for middle-click options - this._builder.get_object('middle_click_options_button').connect('clicked', () => { - - let dialog = new Gtk.Dialog({ - title: __('Customize middle-click behavior'), - transient_for: this.widget.get_root(), - use_header_bar: true, - modal: true - }); - - // GTK+ leaves positive values for application-defined response ids. - // Use +1 for the reset action - dialog.add_button(__('Reset to defaults'), 1); - - let box = this._builder.get_object('box_middle_click_options'); - dialog.get_content_area().append(box); - - this._builder.get_object('shift_click_action_combo').set_active(this._settings.get_enum('shift-click-action')); - - this._builder.get_object('middle_click_action_combo').set_active(this._settings.get_enum('middle-click-action')); - - this._builder.get_object('shift_middle_click_action_combo').set_active(this._settings.get_enum('shift-middle-click-action')); - - this._settings.bind('shift-click-action', - this._builder.get_object('shift_click_action_combo'), - 'active-id', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('middle-click-action', - this._builder.get_object('middle_click_action_combo'), - 'active-id', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('shift-middle-click-action', - this._builder.get_object('shift_middle_click_action_combo'), - 'active-id', - Gio.SettingsBindFlags.DEFAULT); - - dialog.connect('response', (dialog, id) => { - if (id == 1) { - // restore default settings for the relevant keys - let keys = ['shift-click-action', 'middle-click-action', 'shift-middle-click-action']; - keys.forEach(function (val) { - this._settings.set_value(val, this._settings.get_default_value(val)); - }, this); - this._builder.get_object('shift_click_action_combo').set_active(this._settings.get_enum('shift-click-action')); - this._builder.get_object('middle_click_action_combo').set_active(this._settings.get_enum('middle-click-action')); - this._builder.get_object('shift_middle_click_action_combo').set_active(this._settings.get_enum('shift-middle-click-action')); - } else { - // remove the settings box so it doesn't get destroyed; - dialog.get_content_area().remove(box); - dialog.destroy(); - } - return; - }); - - dialog.present(); - - }); - - // Appearance Panel - - this._settings.bind('apply-custom-theme', this._builder.get_object('customize_theme'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN | Gio.SettingsBindFlags.GET); - this._settings.bind('apply-custom-theme', this._builder.get_object('builtin_theme_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('custom-theme-shrink', this._builder.get_object('shrink_dash_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - - // Running indicators - this._builder.get_object('running_indicators_combo').set_active( - this._settings.get_enum('running-indicator-style') - ); - this._builder.get_object('running_indicators_combo').connect( - 'changed', - (widget) => { - this._settings.set_enum('running-indicator-style', widget.get_active()); - } - ); - - if (this._settings.get_enum('running-indicator-style') == RunningIndicatorStyle.DEFAULT) - this._builder.get_object('running_indicators_advance_settings_button').set_sensitive(false); - - this._settings.connect('changed::running-indicator-style', () => { - if (this._settings.get_enum('running-indicator-style') == RunningIndicatorStyle.DEFAULT) - this._builder.get_object('running_indicators_advance_settings_button').set_sensitive(false); - else - this._builder.get_object('running_indicators_advance_settings_button').set_sensitive(true); - }); - - // Create dialog for running indicators advanced settings - this._builder.get_object('running_indicators_advance_settings_button').connect('clicked', () => { - - let dialog = new Gtk.Dialog({ - title: __('Customize running indicators'), - transient_for: this.widget.get_root(), - use_header_bar: true, - modal: true - }); - - let box = this._builder.get_object('running_dots_advance_settings_box'); - dialog.get_content_area().append(box); - - this._settings.bind('running-indicator-dominant-color', - this._builder.get_object('dominant_color_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - - this._settings.bind('custom-theme-customize-running-dots', - this._builder.get_object('dot_style_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('custom-theme-customize-running-dots', - this._builder.get_object('dot_style_settings_box'), - 'sensitive', Gio.SettingsBindFlags.DEFAULT); - - let rgba = new Gdk.RGBA(); - rgba.parse(this._settings.get_string('custom-theme-running-dots-color')); - this._builder.get_object('dot_color_colorbutton').set_rgba(rgba); - - this._builder.get_object('dot_color_colorbutton').connect('notify::rgba', (button) => { - let css = button.rgba.to_string(); - - this._settings.set_string('custom-theme-running-dots-color', css); - }); - - rgba.parse(this._settings.get_string('custom-theme-running-dots-border-color')); - this._builder.get_object('dot_border_color_colorbutton').set_rgba(rgba); - - this._builder.get_object('dot_border_color_colorbutton').connect('notify::rgba', (button) => { - let css = button.rgba.to_string(); - - this._settings.set_string('custom-theme-running-dots-border-color', css); - }); - - this._settings.bind('custom-theme-running-dots-border-width', - this._builder.get_object('dot_border_width_spin_button'), - 'value', - Gio.SettingsBindFlags.DEFAULT); - - - dialog.connect('response', (dialog, id) => { - // remove the settings box so it doesn't get destroyed; - dialog.get_content_area().remove(box); - dialog.destroy(); - return; - }); - - dialog.present(); - - }); - - this._settings.bind('custom-background-color', this._builder.get_object('custom_background_color_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('custom-background-color', this._builder.get_object('custom_background_color'), 'sensitive', Gio.SettingsBindFlags.DEFAULT); - - let rgba = new Gdk.RGBA(); - rgba.parse(this._settings.get_string('background-color')); - this._builder.get_object('custom_background_color').set_rgba(rgba); - - this._builder.get_object('custom_background_color').connect('notify::rgba', (button) => { - let css = button.rgba.to_string(); - - this._settings.set_string('background-color', css); - }); - - // Opacity - this._builder.get_object('customize_opacity_combo').set_active_id( - this._settings.get_enum('transparency-mode').toString() - ); - this._builder.get_object('customize_opacity_combo').connect( - 'changed', - (widget) => { - this._settings.set_enum('transparency-mode', parseInt(widget.get_active_id())); - } - ); - - const custom_opacity_scale = this._builder.get_object('custom_opacity_scale'); - custom_opacity_scale.set_value(this._settings.get_double('background-opacity')); - custom_opacity_scale.set_format_value_func((_, value) => { - return Math.round(value * 100) + '%'; - }); - - if (this._settings.get_enum('transparency-mode') !== TransparencyMode.FIXED) - this._builder.get_object('custom_opacity_scale').set_sensitive(false); - - this._settings.connect('changed::transparency-mode', () => { - if (this._settings.get_enum('transparency-mode') !== TransparencyMode.FIXED) - this._builder.get_object('custom_opacity_scale').set_sensitive(false); - else - this._builder.get_object('custom_opacity_scale').set_sensitive(true); - }); - - if (this._settings.get_enum('transparency-mode') !== TransparencyMode.DYNAMIC) { - this._builder.get_object('dynamic_opacity_button').set_sensitive(false); - } - - this._settings.connect('changed::transparency-mode', () => { - if (this._settings.get_enum('transparency-mode') !== TransparencyMode.DYNAMIC) { - this._builder.get_object('dynamic_opacity_button').set_sensitive(false); - } - else { - this._builder.get_object('dynamic_opacity_button').set_sensitive(true); - } - }); - - // Create dialog for transparency advanced settings - this._builder.get_object('dynamic_opacity_button').connect('clicked', () => { - - let dialog = new Gtk.Dialog({ - title: __('Customize opacity'), - transient_for: this.widget.get_root(), - use_header_bar: true, - modal: true - }); - - let box = this._builder.get_object('advanced_transparency_dialog'); - dialog.get_content_area().append(box); - - this._settings.bind( - 'customize-alphas', - this._builder.get_object('customize_alphas_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT - ); - this._settings.bind( - 'customize-alphas', - this._builder.get_object('min_alpha_scale'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT - ); - this._settings.bind( - 'customize-alphas', - this._builder.get_object('max_alpha_scale'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT - ); - - const min_alpha_scale = this._builder.get_object('min_alpha_scale'); - const max_alpha_scale = this._builder.get_object('max_alpha_scale'); - min_alpha_scale.set_value( - this._settings.get_double('min-alpha') - ); - min_alpha_scale.set_format_value_func((_, value) => { - return Math.round(value * 100) + ' %'; - }); - max_alpha_scale.set_format_value_func((_, value) => { - return Math.round(value * 100) + ' %'; - }); - - max_alpha_scale.set_value( - this._settings.get_double('max-alpha') - ); - - dialog.connect('response', (dialog, id) => { - // remove the settings box so it doesn't get destroyed; - dialog.get_content_area().remove(box); - dialog.destroy(); - return; - }); - - dialog.present(); - }); - - - this._settings.bind('unity-backlit-items', - this._builder.get_object('unity_backlit_items_switch'), - 'active', Gio.SettingsBindFlags.DEFAULT - ); - - this._settings.bind('force-straight-corner', - this._builder.get_object('force_straight_corner_switch'), - 'active', Gio.SettingsBindFlags.DEFAULT); - - // About Panel - - if (Me) - this._builder.get_object('extension_version').set_label(Me.metadata.version.toString()); - else - this._builder.get_object('extension_version').set_label('Unknown'); - } -}); - -function init() { - ExtensionUtils.initTranslations(); -} - -function buildPrefsWidget() { - let settings = new Settings(); - let widget = settings.widget; - return widget; -} - -if (!Me) { - GLib.setenv('GSETTINGS_SCHEMA_DIR', './schemas', true); - Gtk.init(); - - const loop = GLib.MainLoop.new(null, false); - const win = new Gtk.Window(); - win.set_child(buildPrefsWidget()); - win.connect('close-request', () => loop.quit()); - win.present(); - - loop.run(); -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/schemas/gschemas.compiled b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/schemas/gschemas.compiled deleted file mode 100644 index a519241..0000000 Binary files a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/schemas/gschemas.compiled and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml deleted file mode 100644 index 75099ba..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml +++ /dev/null @@ -1,566 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'BOTTOM' - Dock position - Dock is shown on the Left, Right, Top or Bottom side of the screen. - - - 0.2 - Animation time - Sets the time duration of the autohide effect. - - - 0.25 - Show delay - Sets the delay after the mouse reaches the screen border before showing the dock. - - - 0.20 - Show delay - Sets the delay after the mouse left the dock before hiding it. - - - false - Set a custom dash background background color - Sets the color for the dash background. - - - "#ffffff" - Dash background color. - Customize the background color of the dash. - - - 'DEFAULT' - Transparency mode for the dock - FIXED: constant transparency. DYNAMIC: dock takes the opaque style only when windows are close to it. - - - 'DEFAULT' - ... - DEFAULT: .... DOTS: .... - - - false - Use application icon dominant color for the indicator color - - - - false - Manually set the min and max opacity - For the dynamic mode, the min/max opacity values will be given by 'min-alpha' and 'max-alpha'. - - - 0.2 - Opacity of the dash background when free-floating - Sets the opacity of the dash background when no windows are close. - - - 0.8 - Opacity of the dash background when windows are close. - Sets the opacity of the dash background when windows are close. - - - 0.8 - Opacity of the dash background - Sets the opacity of the dash background when in autohide mode. - - - true - Dock dodges windows - Enable or disable intellihide mode - - - 'FOCUS_APPLICATION_WINDOWS' - Define which windows are considered for intellihide. - - - - true - Dock shown on mouse over - Enable or disable autohide mode - - - true - Require pressure to show dash - Enable or disable requiring pressure to show the dash - - - 100 - Pressure threshold - Sets how much pressure is needed to show the dash. - - - false - Enable autohide in fullscreen mode. - Enable autohide in fullscreen mode. - - - false - Dock always visible - Dock is always visible - - - true - Switch workspace by scrolling over the dock - Add the possibility to switch workspace by mouse scrolling over the dock. - - - 48 - Maximum dash icon size - Set the allowed maximum dash icon size. Allowed range: 16..64. - - - 0 - Preview size scale - Set the allowed maximum dash preview size scale. Allowed range: 0,00..1,00. - - - false - Fixed icon size - Keep the icon size fixed by scrolling the dock. - - - false - Apply custom theme - Apply customization to the dash appearance - - - false - TODO - TODO - - - false - Customize the style of the running application indicators. - Customize the style of the running application indicators. - - - "#ffffff" - Running application indicators color - Customize the color of the running application indicators. - - - "#ffffff" - Running application indicators border color. - Customize the border color of the running application indicators. - - - 0 - Running application indicators border width. - Customize the border width of the running application indicators. - - - true - Show running apps - Show or hide running applications icons in the dash - - - false - Provide workspace isolation - Dash shows only windows from the currentworkspace - - - false - Provide monitor isolation - Dash shows only windows from the monitor - - - true - Scroll to focused application - Ensure that the focused application icon is always visible in the dash - - - true - Show preview of the open windows - Replace open windows list with windows previews - - - true - Show favorites apps - Show or hide favorite applications icons in the dash - - - true - Show trash can - Show or hide the trash can icon in the dash - - - true - Show mounted volumes and devices - Show or hide mounted volume and device icons in the dash - - - true - Isolate volumes, devices and trash windows - Consider volume, devices and trash as different application windows and not part of the file manager - - - true - Show applications button - Show applications button in the dash - - - false - Show application button on the left - Show application button on the left of the dash - - - true - Animate Show Applications from the desktop - Animate Show Applications from the desktop - - - true - Basic compatibility with bolt extensions - Make the extension work properly when bolt extensions is enabled - - - 0.90 - Dock max height (fraction of available space) - - - false - Extend the dock container to all the available height - - - -1 - Monitor on which putting the dock - Set on which monitor to put the dock, use -1 for the primary one - - - false - Enable multi-monitor docks - Show a dock on every monitor - - - true - Minimize on shift+click - - - true - Activate only one window - - - 'cycle-windows' - Action when clicking on a running app - Set the action that is executed when clicking on the icon of a running application - - - 'do-nothing' - Action when scrolling app - Set the action that is executed when scrolling on the application icon - - - 'minimize' - Action when shift+clicking on a running app - Set the action that is executed when shift+clicking on the icon of a running application - - - 'launch' - Action when clicking on a running app - Set the action that is executed when middle-clicking on the icon of a running application - - - 'launch' - Action when clicking on a running app - Set the action that is executed when shift+middle-clicking on the icon of a running application - - - true - Super Hot-Keys - Launch and switch between dash items using Super+(0-9) - - - true - Show the dock when using the hotkeys - The dock will be quickly shown so that the number-overlay is visible and app activation is easier - - - "<Super>q" - Keybinding to show the dock and the number overlay. - Behavior depends on hotkeys-show-dock and hotkeys-overlay. - - - q']]]> - Keybinding to show the dock and the number overlay. - Behavior depends on hotkeys-show-dock and hotkeys-overlay. - - - 2 - Timeout to hide the dock - Sets the time duration before the dock is hidden again. - - - true - Show the dock when using the hotkeys - The dock will be quickly shown so that the number-overlay is visible and app activation is easier - - - 1']]]> - Keybinding to launch 1st dash app - - Keybinding to launch 1st app. - - - - 2']]]> - Keybinding to launch 2nd dash app - - Keybinding to launch 2nd app. - - - - 3']]]> - Keybinding to launch 3rd dash app - - Keybinding to launch 3rd app. - - - - 4']]]> - Keybinding to launch 4th dash app - - Keybinding to launch 4th app. - - - - 5']]]> - Keybinding to launch 5th dash app - - Keybinding to launch 5th app. - - - - 6']]]> - Keybinding to launch 6th dash app - - Keybinding to launch 6th app. - - - - 7']]]> - Keybinding to launch 7th dash app - - Keybinding to launch 7th app. - - - - 8']]]> - Keybinding to launch 8th dash app - - Keybinding to launch 8th app. - - - - 9']]]> - Keybinding to launch 9th dash app - - Keybinding to launch 9th app. - - - - 0']]]> - Keybinding to launch 10th dash app - - Keybinding to launch 10th app. - - - - 1']]]> - Keybinding to trigger 1st dash app with shift behavior - - Keybinding to trigger 1st app with shift behavior. - - - - 2']]]> - Keybinding to trigger 2nd dash app with shift behavior - - Keybinding to trigger 2nd app with shift behavior. - - - - 3']]]> - Keybinding to trigger 3rd dash app with shift behavior - - Keybinding to trigger 3rd app with shift behavior. - - - - 4']]]> - Keybinding to trigger 4th dash app with shift behavior - - Keybinding to trigger 4th app with shift behavior. - - - - 5']]]> - Keybinding to trigger 5th dash app with shift behavior - - Keybinding to trigger 5th app with shift behavior. - - - - 6']]]> - Keybinding to trigger 6th dash app with shift behavior - - Keybinding to trigger 6th app with shift behavior. - - - - 7']]]> - Keybinding to trigger 7th dash app with shift behavior - - Keybinding to trigger 7th app with shift behavior. - - - - 8']]]> - Keybinding to trigger 8th dash app with shift behavior - - Keybinding to trigger 8th app with shift behavior. - - - - 9']]]> - Keybinding to trigger 9th dash app with shift behavior - - Keybinding to trigger 9th app with shift behavior. - - - - 0']]]> - Keybinding to trigger 10th dash app with shift behavior - - Keybinding to trigger 10th app with shift behavior. - - - - 1']]]> - Keybinding to trigger 1st dash app - - Keybinding to either show or launch the 1st application in the dash. - - - - 2']]]> - Keybinding to trigger 2nd dash app - - Keybinding to either show or launch the 2nd application in the dash. - - - - 3']]]> - Keybinding to trigger 3rd dash app - - Keybinding to either show or launch the 3rd application in the dash. - - - - 4']]]> - Keybinding to trigger 4th dash app - - Keybinding to either show or launch the 4th application in the dash. - - - - 5']]]> - Keybinding to trigger 5th dash app - - Keybinding to either show or launch the 5th application in the dash. - - - - 6']]]> - Keybinding to trigger 6th dash app - - Keybinding to either show or launch the 6th application in the dash. - - - - 7']]]> - Keybinding to trigger 7th dash app - - Keybinding to either show or launch the 7th application in the dash. - - - - 8']]]> - Keybinding to trigger 8th dash app - - Keybinding to either show or launch the 8th application in the dash. - - - - 9']]]> - Keybinding to trigger 9th dash app - - Keybinding to either show or launch the 9th application in the dash. - - - - 0']]]> - Keybinding to trigger 10th dash app - - Keybinding to either show or launch the 10th application in the dash. - - - - false - Force straight corners in dash - Make the borders in the dash non rounded - - - false - Enable unity7 like glossy backlit items - Emulate the unity7 backlit glossy items behaviour - - - diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/stylesheet.css b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/stylesheet.css deleted file mode 100644 index 52ee72d..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/stylesheet.css +++ /dev/null @@ -1,528 +0,0 @@ -#dashtodockContainer.bottom #dash { - margin: 0px; - padding: 0px; } - #dashtodockContainer.bottom #dash .dash-background { - margin: 0; - margin-bottom: 4px; - padding: 0; } - #dashtodockContainer.bottom #dash .dash-separator { - margin-bottom: 0; } - #dashtodockContainer.bottom #dash #dashtodockDashContainer { - padding: 10px; - padding-bottom: 0; - padding-top: 0; } - #dashtodockContainer.bottom #dash .dash-item-container .app-well-app, - #dashtodockContainer.bottom #dash .dash-item-container .show-apps { - padding: 2px; - padding-bottom: 14px; - padding-top: 10px; } - -#dashtodockContainer.bottom.shrink #dash .dash-background { - margin-bottom: 1px; - padding: 3px; - border-radius: 12px; } - -#dashtodockContainer.bottom.shrink #dash #dashtodockDashContainer { - padding: 3px; } - -#dashtodockContainer.bottom.shrink #dash .dash-item-container .app-well-app, -#dashtodockContainer.bottom.shrink #dash .dash-item-container .show-apps { - padding: 1px; - padding-bottom: 4px; - padding-top: 3px; } - -#dashtodockContainer.bottom.shrink.fixed #dash .dash-background { - margin-top: 1px; } - -#dashtodockContainer.bottom.shrink.fixed #dash .dash-item-container .app-well-app, -#dashtodockContainer.bottom.shrink.fixed #dash .dash-item-container .show-apps { - padding-top: 4px; } - -#dashtodockContainer.bottom.fixed #dash .dash-background { - margin-top: 4px; } - -#dashtodockContainer.bottom.fixed #dash .dash-item-container .app-well-app, -#dashtodockContainer.bottom.fixed #dash .dash-item-container .show-apps { - padding-top: 14px; } - -#dashtodockContainer.top #dash { - margin: 0px; - padding: 0px; } - #dashtodockContainer.top #dash .dash-background { - margin: 0; - margin-top: 4px; - padding: 0; } - #dashtodockContainer.top #dash .dash-separator { - margin-bottom: 0; } - #dashtodockContainer.top #dash #dashtodockDashContainer { - padding: 10px; - padding-top: 0; - padding-bottom: 0; } - #dashtodockContainer.top #dash .dash-item-container .app-well-app, - #dashtodockContainer.top #dash .dash-item-container .show-apps { - padding: 2px; - padding-top: 14px; - padding-bottom: 10px; } - -#dashtodockContainer.top.shrink #dash .dash-background { - margin-top: 1px; - padding: 3px; - border-radius: 12px; } - -#dashtodockContainer.top.shrink #dash #dashtodockDashContainer { - padding: 3px; } - -#dashtodockContainer.top.shrink #dash .dash-item-container .app-well-app, -#dashtodockContainer.top.shrink #dash .dash-item-container .show-apps { - padding: 1px; - padding-top: 4px; - padding-bottom: 3px; } - -#dashtodockContainer.top.shrink.fixed #dash .dash-background { - margin-bottom: 1px; } - -#dashtodockContainer.top.shrink.fixed #dash .dash-item-container .app-well-app, -#dashtodockContainer.top.shrink.fixed #dash .dash-item-container .show-apps { - padding-bottom: 4px; } - -#dashtodockContainer.top.fixed #dash .dash-background { - margin-bottom: 4px; } - -#dashtodockContainer.top.fixed #dash .dash-item-container .app-well-app, -#dashtodockContainer.top.fixed #dash .dash-item-container .show-apps { - padding-bottom: 14px; } - -#dashtodockContainer.left #dash { - margin: 0px; - padding: 0px; } - #dashtodockContainer.left #dash .dash-background { - margin: 0; - margin-left: 4px; - padding: 0; } - #dashtodockContainer.left #dash .dash-separator { - height: 1px; - margin: 7px 0; - background-color: rgba(238, 238, 236, 0.3); } - #dashtodockContainer.left #dash #dashtodockDashContainer { - padding: 10px; - padding-left: 0; - padding-right: 0; } - #dashtodockContainer.left #dash .dash-item-container .app-well-app, - #dashtodockContainer.left #dash .dash-item-container .show-apps { - padding: 2px; - padding-left: 14px; - padding-right: 10px; } - -#dashtodockContainer.left.shrink #dash .dash-background { - margin-left: 1px; - padding: 3px; - border-radius: 12px; } - -#dashtodockContainer.left.shrink #dash #dashtodockDashContainer { - padding: 3px; } - -#dashtodockContainer.left.shrink #dash .dash-item-container .app-well-app, -#dashtodockContainer.left.shrink #dash .dash-item-container .show-apps { - padding: 1px; - padding-left: 4px; - padding-right: 3px; } - -#dashtodockContainer.left.shrink.fixed #dash .dash-background { - margin-right: 1px; } - -#dashtodockContainer.left.shrink.fixed #dash .dash-item-container .app-well-app, -#dashtodockContainer.left.shrink.fixed #dash .dash-item-container .show-apps { - padding-right: 4px; } - -#dashtodockContainer.left.fixed #dash .dash-background { - margin-right: 4px; } - -#dashtodockContainer.left.fixed #dash .dash-item-container .app-well-app, -#dashtodockContainer.left.fixed #dash .dash-item-container .show-apps { - padding-right: 14px; } - -#dashtodockContainer.right #dash { - margin: 0px; - padding: 0px; } - #dashtodockContainer.right #dash .dash-background { - margin: 0; - margin-right: 4px; - padding: 0; } - #dashtodockContainer.right #dash .dash-separator { - height: 1px; - margin: 7px 0; - background-color: rgba(238, 238, 236, 0.3); } - #dashtodockContainer.right #dash #dashtodockDashContainer { - padding: 10px; - padding-right: 0; - padding-left: 0; } - #dashtodockContainer.right #dash .dash-item-container .app-well-app, - #dashtodockContainer.right #dash .dash-item-container .show-apps { - padding: 2px; - padding-right: 14px; - padding-left: 10px; } - -#dashtodockContainer.right.shrink #dash .dash-background { - margin-right: 1px; - padding: 3px; - border-radius: 12px; } - -#dashtodockContainer.right.shrink #dash #dashtodockDashContainer { - padding: 3px; } - -#dashtodockContainer.right.shrink #dash .dash-item-container .app-well-app, -#dashtodockContainer.right.shrink #dash .dash-item-container .show-apps { - padding: 1px; - padding-right: 4px; - padding-left: 3px; } - -#dashtodockContainer.right.shrink.fixed #dash .dash-background { - margin-left: 1px; } - -#dashtodockContainer.right.shrink.fixed #dash .dash-item-container .app-well-app, -#dashtodockContainer.right.shrink.fixed #dash .dash-item-container .show-apps { - padding-left: 4px; } - -#dashtodockContainer.right.fixed #dash .dash-background { - margin-left: 4px; } - -#dashtodockContainer.right.fixed #dash .dash-item-container .app-well-app, -#dashtodockContainer.right.fixed #dash .dash-item-container .show-apps { - padding-left: 14px; } - -/* In extended mode we need to use the first and last .dash-item-container's - * to apply the padding on the dock, to ensure that the actual first or last - * child show-apps item will actually include the padding area so that it will - * be clickable up to the dock edge, and make Fitts happy. - * I don't think the same should happen for normal icons, so in the other side - * the padding will be applied via the scrolled area, given we can't get the - * parent of the first/last app-well-app icon to apply a rule there. - */ -#dashtodockContainer.extended.bottom #dash .dash-background { - margin: 0; - border-radius: 0; } - -#dashtodockContainer.extended.bottom #dash #dashtodockDashContainer { - padding: 0; - padding-bottom: 0; - padding-top: 0; } - #dashtodockContainer.extended.bottom #dash #dashtodockDashContainer > :first-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.bottom #dash #dashtodockDashContainer > :first-child .show-apps { - padding-left: 8px; } - #dashtodockContainer.extended.bottom #dash #dashtodockDashContainer #dashtodockDashScrollview:first-child { - padding-left: 8px; } - #dashtodockContainer.extended.bottom #dash #dashtodockDashContainer > :last-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.bottom #dash #dashtodockDashContainer > :last-child .show-apps { - padding-right: 8px; } - #dashtodockContainer.extended.bottom #dash #dashtodockDashContainer #dashtodockDashScrollview:last-child { - padding-right: 8px; } - -#dashtodockContainer.extended.bottom #dash .dash-item-container .app-well-app, -#dashtodockContainer.extended.bottom #dash .dash-item-container .show-apps { - padding-bottom: 10px; } - -#dashtodockContainer.extended.bottom.shrink #dash #dashtodockDashContainer { - padding: 0; } - #dashtodockContainer.extended.bottom.shrink #dash #dashtodockDashContainer > :first-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.bottom.shrink #dash #dashtodockDashContainer > :first-child .show-apps { - padding-left: 2px; } - #dashtodockContainer.extended.bottom.shrink #dash #dashtodockDashContainer #dashtodockDashScrollview:first-child { - padding-left: 2px; } - #dashtodockContainer.extended.bottom.shrink #dash #dashtodockDashContainer > :last-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.bottom.shrink #dash #dashtodockDashContainer > :last-child .show-apps { - padding-right: 2px; } - #dashtodockContainer.extended.bottom.shrink #dash #dashtodockDashContainer #dashtodockDashScrollview:last-child { - padding-right: 2px; } - -#dashtodockContainer.extended.bottom.shrink #dash .dash-item-container .app-well-app, -#dashtodockContainer.extended.bottom.shrink #dash .dash-item-container .show-apps { - padding-bottom: 3px; } - -#dashtodockContainer.extended.bottom.shrink.fixed #dash .dash-background { - margin-top: 0; } - -#dashtodockContainer.extended.top #dash .dash-background { - margin: 0; - border-radius: 0; } - -#dashtodockContainer.extended.top #dash #dashtodockDashContainer { - padding: 0; - padding-top: 0; - padding-bottom: 0; } - #dashtodockContainer.extended.top #dash #dashtodockDashContainer > :first-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.top #dash #dashtodockDashContainer > :first-child .show-apps { - padding-left: 8px; } - #dashtodockContainer.extended.top #dash #dashtodockDashContainer #dashtodockDashScrollview:first-child { - padding-left: 8px; } - #dashtodockContainer.extended.top #dash #dashtodockDashContainer > :last-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.top #dash #dashtodockDashContainer > :last-child .show-apps { - padding-right: 8px; } - #dashtodockContainer.extended.top #dash #dashtodockDashContainer #dashtodockDashScrollview:last-child { - padding-right: 8px; } - -#dashtodockContainer.extended.top #dash .dash-item-container .app-well-app, -#dashtodockContainer.extended.top #dash .dash-item-container .show-apps { - padding-top: 10px; } - -#dashtodockContainer.extended.top.shrink #dash #dashtodockDashContainer { - padding: 0; } - #dashtodockContainer.extended.top.shrink #dash #dashtodockDashContainer > :first-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.top.shrink #dash #dashtodockDashContainer > :first-child .show-apps { - padding-left: 2px; } - #dashtodockContainer.extended.top.shrink #dash #dashtodockDashContainer #dashtodockDashScrollview:first-child { - padding-left: 2px; } - #dashtodockContainer.extended.top.shrink #dash #dashtodockDashContainer > :last-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.top.shrink #dash #dashtodockDashContainer > :last-child .show-apps { - padding-right: 2px; } - #dashtodockContainer.extended.top.shrink #dash #dashtodockDashContainer #dashtodockDashScrollview:last-child { - padding-right: 2px; } - -#dashtodockContainer.extended.top.shrink #dash .dash-item-container .app-well-app, -#dashtodockContainer.extended.top.shrink #dash .dash-item-container .show-apps { - padding-top: 3px; } - -#dashtodockContainer.extended.top.shrink.fixed #dash .dash-background { - margin-bottom: 0; } - -#dashtodockContainer.extended.left #dash .dash-background { - margin: 0; - border-radius: 0; } - -#dashtodockContainer.extended.left #dash #dashtodockDashContainer { - padding: 0; - padding-left: 0; - padding-right: 0; } - #dashtodockContainer.extended.left #dash #dashtodockDashContainer > :first-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.left #dash #dashtodockDashContainer > :first-child .show-apps { - padding-top: 8px; } - #dashtodockContainer.extended.left #dash #dashtodockDashContainer #dashtodockDashScrollview:first-child { - padding-top: 8px; } - #dashtodockContainer.extended.left #dash #dashtodockDashContainer > :last-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.left #dash #dashtodockDashContainer > :last-child .show-apps { - padding-bottom: 8px; } - #dashtodockContainer.extended.left #dash #dashtodockDashContainer #dashtodockDashScrollview:last-child { - padding-bottom: 8px; } - -#dashtodockContainer.extended.left #dash .dash-item-container .app-well-app, -#dashtodockContainer.extended.left #dash .dash-item-container .show-apps { - padding-left: 10px; } - -#dashtodockContainer.extended.left.shrink #dash #dashtodockDashContainer { - padding: 0; } - #dashtodockContainer.extended.left.shrink #dash #dashtodockDashContainer > :first-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.left.shrink #dash #dashtodockDashContainer > :first-child .show-apps { - padding-top: 2px; } - #dashtodockContainer.extended.left.shrink #dash #dashtodockDashContainer #dashtodockDashScrollview:first-child { - padding-top: 2px; } - #dashtodockContainer.extended.left.shrink #dash #dashtodockDashContainer > :last-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.left.shrink #dash #dashtodockDashContainer > :last-child .show-apps { - padding-bottom: 2px; } - #dashtodockContainer.extended.left.shrink #dash #dashtodockDashContainer #dashtodockDashScrollview:last-child { - padding-bottom: 2px; } - -#dashtodockContainer.extended.left.shrink #dash .dash-item-container .app-well-app, -#dashtodockContainer.extended.left.shrink #dash .dash-item-container .show-apps { - padding-left: 3px; } - -#dashtodockContainer.extended.left.shrink.fixed #dash .dash-background { - margin-right: 0; } - -#dashtodockContainer.extended.right #dash .dash-background { - margin: 0; - border-radius: 0; } - -#dashtodockContainer.extended.right #dash #dashtodockDashContainer { - padding: 0; - padding-right: 0; - padding-left: 0; } - #dashtodockContainer.extended.right #dash #dashtodockDashContainer > :first-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.right #dash #dashtodockDashContainer > :first-child .show-apps { - padding-top: 8px; } - #dashtodockContainer.extended.right #dash #dashtodockDashContainer #dashtodockDashScrollview:first-child { - padding-top: 8px; } - #dashtodockContainer.extended.right #dash #dashtodockDashContainer > :last-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.right #dash #dashtodockDashContainer > :last-child .show-apps { - padding-bottom: 8px; } - #dashtodockContainer.extended.right #dash #dashtodockDashContainer #dashtodockDashScrollview:last-child { - padding-bottom: 8px; } - -#dashtodockContainer.extended.right #dash .dash-item-container .app-well-app, -#dashtodockContainer.extended.right #dash .dash-item-container .show-apps { - padding-right: 10px; } - -#dashtodockContainer.extended.right.shrink #dash #dashtodockDashContainer { - padding: 0; } - #dashtodockContainer.extended.right.shrink #dash #dashtodockDashContainer > :first-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.right.shrink #dash #dashtodockDashContainer > :first-child .show-apps { - padding-top: 2px; } - #dashtodockContainer.extended.right.shrink #dash #dashtodockDashContainer #dashtodockDashScrollview:first-child { - padding-top: 2px; } - #dashtodockContainer.extended.right.shrink #dash #dashtodockDashContainer > :last-child { - /* Use this instead of #dashtodockDashScrollview rule to apply the - * padding via the last app-icon item */ } - #dashtodockContainer.extended.right.shrink #dash #dashtodockDashContainer > :last-child .show-apps { - padding-bottom: 2px; } - #dashtodockContainer.extended.right.shrink #dash #dashtodockDashContainer #dashtodockDashScrollview:last-child { - padding-bottom: 2px; } - -#dashtodockContainer.extended.right.shrink #dash .dash-item-container .app-well-app, -#dashtodockContainer.extended.right.shrink #dash .dash-item-container .show-apps { - padding-right: 3px; } - -#dashtodockContainer.extended.right.shrink.fixed #dash .dash-background { - margin-left: 0; } - -#dashtodockContainer.top.shrink #dash .dash-background { - margin-top: 4px; - margin-bottom: 0; } - -#dashtodockContainer.straight-corner #dash .dash-background, -#dashtodockContainer.shrink.straight-corner #dash .dash-background { - border-radius: 0px; } - -/* Scrollview style */ -.bottom #dashtodockDashScrollview, -.top #dashtodockDashScrollview { - -st-hfade-offset: 24px; } - -.left #dashtodockDashScrollview, -.right #dashtodockDashScrollview { - -st-vfade-offset: 24px; } - -#dashtodockContainer.running-dots .dash-item-container > StButton, -#dashtodockContainer.dashtodock .dash-item-container > StButton { - transition-duration: 250; - background-size: contain; } - -/* Running and focused application style */ -#dashtodockContainer.running-dots .app-well-app.running > .overview-icon, -#dashtodockContainer.dashtodock .app-well-app.running > .overview-icon { - background-image: none; } - -#dashtodockContainer.running-dots .app-well-app.focused .overview-icon, -#dashtodockContainer.dashtodock .app-well-app.focused .overview-icon { - background-color: rgba(238, 238, 236, 0.2); } - -#dashtodockContainer.dashtodock #dash .dash-background { - background: #2e3436; } - -#dashtodockContainer.dashtodock .progress-bar { - /* Customization of the progress bar style, e.g.: - -progress-bar-background: rgba(0.8, 0.8, 0.8, 1); - -progress-bar-border: rgba(0.9, 0.9, 0.9, 1); - */ } - -#dashtodockContainer.top #dash .placeholder, -#dashtodockContainer.bottom #dash .placeholder { - width: 32px; - height: 1px; } - -/* - * This is applied to a dummy actor. Only the alpha value for the background and border color - * and the transition-duration are used - */ -#dashtodockContainer.dummy-opaque { - background-color: rgba(0, 0, 0, 0.8); - border-color: rgba(0, 0, 0, 0.4); - transition-duration: 300ms; } - -/* - * This is applied to a dummy actor. Only the alpha value for the background and border color - * and the transition-duration are used - */ -#dashtodockContainer.dummy-transparent { - background-color: rgba(0, 0, 0, 0.2); - border-color: rgba(0, 0, 0, 0.1); - transition-duration: 500ms; } - -#dashtodockContainer .number-overlay { - color: white; - background-color: rgba(0, 0, 0, 0.8); - text-align: center; } - -#dashtodockContainer .notification-badge { - color: white; - background-color: red; - padding: 0.2em 0.5em; - border-radius: 1em; - font-weight: bold; - text-align: center; - margin: 2px; } - -#dashtodockPreviewSeparator.popup-separator-menu-item-horizontal { - width: 1px; - height: auto; - border-right-width: 1px; - margin: 32px 0px; } - -.dashtodock-app-well-preview-menu-item { - padding: 1em 1em 0.5em 1em; } - -#dashtodockContainer .metro .overview-icon { - border-radius: 0px; } - -#dashtodockContainer.bottom .metro.running2.focused, -#dashtodockContainer.top .metro.running2.focused { - background-image: url("./media/highlight_stacked_bg.svg"); - background-position: 0px 0px; - background-size: contain; } - -#dashtodockContainer.left .metro.running2.focused, -#dashtodockContainer.right .metro.running2.focused { - background-image: url("./media/highlight_stacked_bg_h.svg"); - background-position: 0px 0px; - background-size: contain; } - -#dashtodockContainer.bottom .metro.running3.focused, -#dashtodockContainer.top .metro.running3.focused { - background-image: url("./media/highlight_stacked_bg.svg"); - background-position: 0px 0px; - background-size: contain; } - -#dashtodockContainer.left .metro.running3.focused, -#dashtodockContainer.right .metro.running3.focused { - background-image: url("./media/highlight_stacked_bg_h.svg"); - background-position: 0px 0px; - background-size: contain; } - -#dashtodockContainer.bottom .metro.running4.focused, -#dashtodockContainer.top .metro.running4.focused { - background-image: url("./media/highlight_stacked_bg.svg"); - background-position: 0px 0px; - background-size: contain; } - -#dashtodockContainer.left .metro.running4.focused, -#dashtodockContainer.right .metro.running4.focused { - background-image: url("./media/highlight_stacked_bg_h.svg"); - background-position: 0px 0px; - background-size: contain; } diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/theming.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/theming.js deleted file mode 100644 index eba0370..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/theming.js +++ /dev/null @@ -1,561 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const Signals = imports.signals; -const Meta = imports.gi.Meta; -const Shell = imports.gi.Shell; -const St = imports.gi.St; -const Clutter = imports.gi.Clutter; - -const AppDisplay = imports.ui.appDisplay; -const AppFavorites = imports.ui.appFavorites; -const Dash = imports.ui.dash; -const DND = imports.ui.dnd; -const IconGrid = imports.ui.iconGrid; -const Main = imports.ui.main; -const PopupMenu = imports.ui.popupMenu; -const Util = imports.misc.util; -const Workspace = imports.ui.workspace; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Docking = Me.imports.docking; -const Utils = Me.imports.utils; - -/* - * DEFAULT: transparency given by theme - * FIXED: constant transparency chosen by user - * DYNAMIC: apply 'transparent' style when no windows are close to the dock - * */ -const TransparencyMode = { - DEFAULT: 0, - FIXED: 1, - DYNAMIC: 3 -}; - -/** - * Manage theme customization and custom theme support - */ -var ThemeManager = class DashToDock_ThemeManager { - - constructor(dock) { - this._signalsHandler = new Utils.GlobalSignalsHandler(this); - this._bindSettingsChanges(); - this._actor = dock; - this._dash = dock.dash; - - // initialize colors with generic values - this._customizedBackground = {red: 0, green: 0, blue: 0, alpha: 0}; - this._customizedBorder = {red: 0, green: 0, blue: 0, alpha: 0}; - this._transparency = new Transparency(dock); - - this._signalsHandler.add([ - // When theme changes re-obtain default background color - St.ThemeContext.get_for_stage (global.stage), - 'changed', - this.updateCustomTheme.bind(this) - ], [ - // update :overview pseudoclass - Main.overview, - 'showing', - this._onOverviewShowing.bind(this) - ], [ - Main.overview, - 'hiding', - this._onOverviewHiding.bind(this) - ]); - - this._updateCustomStyleClasses(); - - // destroy themeManager when the managed actor is destroyed (e.g. extension unload) - // in order to disconnect signals - this._signalsHandler.add(this._actor, 'destroy', () => this.destroy()); - } - - destroy() { - this.emit('destroy'); - this._transparency.destroy(); - this._destroyed = true; - } - - _onOverviewShowing() { - this._actor.add_style_pseudo_class('overview'); - } - - _onOverviewHiding() { - this._actor.remove_style_pseudo_class('overview'); - } - - _updateDashOpacity() { - let newAlpha = Docking.DockManager.settings.get_double('background-opacity'); - - let [backgroundColor, borderColor] = this._getDefaultColors(); - - if (backgroundColor==null) - return; - - // Get the background and border alphas. We check the background alpha - // for a minimum of .001 to prevent division by 0 errors - let backgroundAlpha = Math.max(Math.round(backgroundColor.alpha/2.55)/100, .001); - let borderAlpha = Math.round(borderColor.alpha/2.55)/100; - - // The border and background alphas should remain in sync - // We also limit the borderAlpha to a maximum of 1 (full opacity) - borderAlpha = Math.min((borderAlpha/backgroundAlpha)*newAlpha, 1); - - this._customizedBackground = 'rgba(' + - backgroundColor.red + ',' + - backgroundColor.green + ',' + - backgroundColor.blue + ',' + - newAlpha + ')'; - - this._customizedBorder = 'rgba(' + - borderColor.red + ',' + - borderColor.green + ',' + - borderColor.blue + ',' + - borderAlpha + ')'; - - } - - _getDefaultColors() { - // Prevent shell crash if the actor is not on the stage. - // It happens enabling/disabling repeatedly the extension - if (!this._dash._container.get_stage()) - return [null, null]; - - // Remove custom style - let oldStyle = this._dash._container.get_style(); - this._dash._container.set_style(null); - - let themeNode = this._dash._container.get_theme_node(); - this._dash._container.set_style(oldStyle); - - let backgroundColor = themeNode.get_background_color(); - - // Just in case the theme has different border colors .. - // We want to find the inside border-color of the dock because it is - // the side most visible to the user. We do this by finding the side - // opposite the position - let position = Utils.getPosition(); - let side = position + 2; - if (side > 3) - side = Math.abs(side - 4); - - let borderColor = themeNode.get_border_color(side); - - return [backgroundColor, borderColor]; - } - - _updateDashColor() { - // Retrieve the color. If needed we will adjust it before passing it to - // this._transparency. - let [backgroundColor, borderColor] = this._getDefaultColors(); - - if (backgroundColor==null) - return; - - let settings = Docking.DockManager.settings; - - if (settings.get_boolean('custom-background-color')) { - // When applying a custom color, we need to check the alpha value, - // if not the opacity will always be overridden by the color below. - // Note that if using 'dynamic' transparency modes, - // the opacity will be set by the opaque/transparent styles anyway. - let newAlpha = Math.round(backgroundColor.alpha/2.55)/100; - - backgroundColor = settings.get_string('background-color'); - // backgroundColor is a string like rgb(0,0,0) - const [ret, color] = Clutter.Color.from_string(backgroundColor); - if (!ret) { - logError(new Error(`${backgroundColor} is not a valid color string`)); - return; - } - - if (settings.get_enum('transparency-mode') == TransparencyMode.FIXED) { - newAlpha = settings.get_double('background-opacity'); - this._customizedBackground = - `rgba(${color.red}, ${color.blue}, ${color.green}, ${newAlpha})`; - } else { - this._customizedBackground = backgroundColor; - } - - this._customizedBorder = this._customizedBackground; - - color.alpha = newAlpha * 255; - this._transparency.setColor(color); - } else { - // backgroundColor is a Clutter.Color object - this._transparency.setColor(backgroundColor); - } - } - - _updateCustomStyleClasses() { - let settings = Docking.DockManager.settings; - - if (settings.get_boolean('apply-custom-theme')) - this._actor.add_style_class_name('dashtodock'); - else - this._actor.remove_style_class_name('dashtodock'); - - if (settings.get_boolean('custom-theme-shrink')) - this._actor.add_style_class_name('shrink'); - else - this._actor.remove_style_class_name('shrink'); - - if (settings.get_enum('running-indicator-style') !== 0) - this._actor.add_style_class_name('running-dots'); - else - this._actor.remove_style_class_name('running-dots'); - - // If not the built-in theme option is not selected - if (!settings.get_boolean('apply-custom-theme')) { - if (settings.get_boolean('force-straight-corner')) - this._actor.add_style_class_name('straight-corner'); - else - this._actor.remove_style_class_name('straight-corner'); - } else { - this._actor.remove_style_class_name('straight-corner'); - } - } - - updateCustomTheme() { - if (this._destroyed) - throw new Error(`Impossible to update a destroyed ${this.constructor.name}`); - this._updateCustomStyleClasses(); - this._updateDashOpacity(); - this._updateDashColor(); - this._adjustTheme(); - this.emit('updated'); - } - - /** - * Reimported back and adapted from atomdock - */ - _adjustTheme() { - // Prevent shell crash if the actor is not on the stage. - // It happens enabling/disabling repeatedly the extension - if (!this._dash._background.get_stage()) - return; - - let settings = Docking.DockManager.settings; - - // Remove prior style edits - this._dash._background.set_style(null); - this._transparency.disable(); - - // If built-in theme is enabled do nothing else - if (settings.get_boolean('apply-custom-theme')) - return; - - let newStyle = ''; - let position = Utils.getPosition(settings); - - // obtain theme border settings - let themeNode = this._dash._background.get_theme_node(); - let borderColor = themeNode.get_border_color(St.Side.TOP); - let borderWidth = themeNode.get_border_width(St.Side.TOP); - - // We're copying border and corner styles to left border and top-left - // corner, also removing bottom border and bottom-right corner styles - let borderInner = ''; - let borderMissingStyle = ''; - - if (this._rtl && (position != St.Side.RIGHT)) - borderMissingStyle = 'border-right: ' + borderWidth + 'px solid ' + - borderColor.to_string() + ';'; - else if (!this._rtl && (position != St.Side.LEFT)) - borderMissingStyle = 'border-left: ' + borderWidth + 'px solid ' + - borderColor.to_string() + ';'; - - newStyle = borderMissingStyle; - - if (newStyle) { - // I do call set_style possibly twice so that only the background gets the transition. - // The transition-property css rules seems to be unsupported - this._dash._background.set_style(newStyle); - } - - // Customize background - let fixedTransparency = settings.get_enum('transparency-mode') == TransparencyMode.FIXED; - let defaultTransparency = settings.get_enum('transparency-mode') == TransparencyMode.DEFAULT; - if (!defaultTransparency && !fixedTransparency) { - this._transparency.enable(); - } - else if (!defaultTransparency || settings.get_boolean('custom-background-color')) { - newStyle = newStyle + 'background-color:'+ this._customizedBackground + '; ' + - 'border-color:'+ this._customizedBorder + '; ' + - 'transition-delay: 0s; transition-duration: 0.250s;'; - this._dash._background.set_style(newStyle); - } - } - - _bindSettingsChanges() { - let keys = ['transparency-mode', - 'customize-alphas', - 'min-alpha', - 'max-alpha', - 'background-opacity', - 'custom-background-color', - 'background-color', - 'apply-custom-theme', - 'custom-theme-shrink', - 'custom-theme-running-dots', - 'extend-height', - 'force-straight-corner']; - - this._signalsHandler.add(...keys.map(key => [ - Docking.DockManager.settings, - `changed::${key}`, - () => this.updateCustomTheme(), - ])); - } -}; -Signals.addSignalMethods(ThemeManager.prototype); - -/** - * The following class is based on the following upstream commit: - * https://git.gnome.org/browse/gnome-shell/commit/?id=447bf55e45b00426ed908b1b1035f472c2466956 - * Transparency when free-floating - */ -var Transparency = class DashToDock_Transparency { - - constructor(dock) { - this._dash = dock.dash; - this._actor = this._dash._container; - this._backgroundActor = this._dash._background; - this._dockActor = dock; - this._dock = dock; - this._panel = Main.panel; - this._position = Utils.getPosition(); - - // All these properties are replaced with the ones in the .dummy-opaque and .dummy-transparent css classes - this._backgroundColor = '0,0,0'; - this._transparentAlpha = '0.2'; - this._opaqueAlpha = '1'; - this._transparentAlphaBorder = '0.1'; - this._opaqueAlphaBorder = '0.5'; - this._transparentTransition = '0ms'; - this._opaqueTransition = '0ms'; - this._base_actor_style = ""; - - this._signalsHandler = new Utils.GlobalSignalsHandler(); - this._trackedWindows = new Map(); - } - - enable() { - // ensure I never double-register/inject - // although it should never happen - this.disable(); - - this._base_actor_style = this._actor.get_style(); - if (this._base_actor_style == null) { - this._base_actor_style = ""; - } - - this._signalsHandler.addWithLabel('transparency', [ - global.window_group, - 'actor-added', - this._onWindowActorAdded.bind(this) - ], [ - global.window_group, - 'actor-removed', - this._onWindowActorRemoved.bind(this) - ], [ - global.window_manager, - 'switch-workspace', - this._updateSolidStyle.bind(this) - ], [ - Main.overview, - 'hiding', - this._updateSolidStyle.bind(this) - ], [ - Main.overview, - 'showing', - this._updateSolidStyle.bind(this) - ]); - - // Window signals - global.window_group.get_children().filter(function(child) { - // An irrelevant window actor ('Gnome-shell') produces an error when the signals are - // disconnected, therefore do not add signals to it. - return child instanceof Meta.WindowActor && - child.get_meta_window().get_wm_class() !== 'Gnome-shell'; - }).forEach(function(win) { - this._onWindowActorAdded(null, win); - }, this); - - if (this._actor.get_stage()) - this._updateSolidStyle(); - - this._updateStyles(); - this._updateSolidStyle(); - - this.emit('transparency-enabled'); - } - - disable() { - // ensure I never double-register/inject - // although it should never happen - this._signalsHandler.removeWithLabel('transparency'); - - for (let key of this._trackedWindows.keys()) - this._trackedWindows.get(key).forEach(id => { - key.disconnect(id); - }); - this._trackedWindows.clear(); - - this.emit('transparency-disabled'); - } - - destroy() { - this.disable(); - this._signalsHandler.destroy(); - } - - _onWindowActorAdded(container, metaWindowActor) { - let signalIds = []; - ['notify::allocation', 'notify::visible'].forEach(s => { - signalIds.push(metaWindowActor.connect(s, this._updateSolidStyle.bind(this))); - }); - this._trackedWindows.set(metaWindowActor, signalIds); - } - - _onWindowActorRemoved(container, metaWindowActor) { - if (!this._trackedWindows.get(metaWindowActor)) - return; - - this._trackedWindows.get(metaWindowActor).forEach(id => { - metaWindowActor.disconnect(id); - }); - this._trackedWindows.delete(metaWindowActor); - this._updateSolidStyle(); - } - - _updateSolidStyle() { - let isNear = this._dockIsNear(); - if (isNear) { - this._backgroundActor.set_style(this._opaque_style); - this._dockActor.remove_style_class_name('transparent'); - this._dockActor.add_style_class_name('opaque'); - } - else { - this._backgroundActor.set_style(this._transparent_style); - this._dockActor.remove_style_class_name('opaque'); - this._dockActor.add_style_class_name('transparent'); - } - - this.emit('solid-style-updated', isNear); - } - - _dockIsNear() { - if (this._dockActor.has_style_pseudo_class('overview')) - return false; - /* Get all the windows in the active workspace that are in the primary monitor and visible */ - let activeWorkspace = global.workspace_manager.get_active_workspace(); - let dash = this._dash; - let windows = activeWorkspace.list_windows().filter(function(metaWindow) { - return metaWindow.get_monitor() === dash._monitorIndex && - metaWindow.showing_on_its_workspace() && - metaWindow.get_window_type() != Meta.WindowType.DESKTOP; - }); - - /* Check if at least one window is near enough to the panel. - * If the dock is hidden, we need to account for the space it would take - * up when it slides out. This is avoid an ugly transition. - * */ - let factor = 0; - if (!Docking.DockManager.settings.dockFixed && - this._dock.getDockState() == Docking.State.HIDDEN) - factor = 1; - let [leftCoord, topCoord] = this._actor.get_transformed_position(); - let threshold; - if (this._position === St.Side.LEFT) - threshold = leftCoord + this._actor.get_width() * (factor + 1); - else if (this._position === St.Side.RIGHT) - threshold = leftCoord - this._actor.get_width() * factor; - else if (this._position === St.Side.TOP) - threshold = topCoord + this._actor.get_height() * (factor + 1); - else - threshold = topCoord - this._actor.get_height() * factor; - - let scale = St.ThemeContext.get_for_stage(global.stage).scale_factor; - let isNearEnough = windows.some((metaWindow) => { - let coord; - if (this._position === St.Side.LEFT) { - coord = metaWindow.get_frame_rect().x; - return coord < threshold + 5 * scale; - } - else if (this._position === St.Side.RIGHT) { - coord = metaWindow.get_frame_rect().x + metaWindow.get_frame_rect().width; - return coord > threshold - 5 * scale; - } - else if (this._position === St.Side.TOP) { - coord = metaWindow.get_frame_rect().y; - return coord < threshold + 5 * scale; - } - else { - coord = metaWindow.get_frame_rect().y + metaWindow.get_frame_rect().height; - return coord > threshold - 5 * scale; - } - }); - - return isNearEnough; - } - - _updateStyles() { - this._getAlphas(); - - this._transparent_style = this._base_actor_style + - 'background-color: rgba(' + - this._backgroundColor + ', ' + this._transparentAlpha + ');' + - 'border-color: rgba(' + - this._backgroundColor + ', ' + this._transparentAlphaBorder + ');' + - 'transition-duration: ' + this._transparentTransition + 'ms;'; - - this._opaque_style = this._base_actor_style + - 'background-color: rgba(' + - this._backgroundColor + ', ' + this._opaqueAlpha + ');' + - 'border-color: rgba(' + - this._backgroundColor + ',' + this._opaqueAlphaBorder + ');' + - 'transition-duration: ' + this._opaqueTransition + 'ms;'; - - this.emit('styles-updated'); - } - - setColor(color) { - this._backgroundColor = color.red + ',' + color.green + ',' + color.blue; - this._updateStyles(); - } - - _getAlphas() { - // Create dummy object and add to the uiGroup to get it to the stage - let dummyObject = new St.Bin({ - name: 'dashtodockContainer', - }); - Main.uiGroup.add_child(dummyObject); - - dummyObject.add_style_class_name('dummy-opaque'); - let themeNode = dummyObject.get_theme_node(); - this._opaqueAlpha = themeNode.get_background_color().alpha / 255; - this._opaqueAlphaBorder = themeNode.get_border_color(0).alpha / 255; - this._opaqueTransition = themeNode.get_transition_duration(); - - dummyObject.add_style_class_name('dummy-transparent'); - themeNode = dummyObject.get_theme_node(); - this._transparentAlpha = themeNode.get_background_color().alpha / 255; - this._transparentAlphaBorder = themeNode.get_border_color(0).alpha / 255; - this._transparentTransition = themeNode.get_transition_duration(); - - Main.uiGroup.remove_child(dummyObject); - - let settings = Docking.DockManager.settings; - - if (settings.get_boolean('customize-alphas')) { - this._opaqueAlpha = settings.get_double('max-alpha'); - this._opaqueAlphaBorder = this._opaqueAlpha / 2; - this._transparentAlpha = settings.get_double('min-alpha'); - this._transparentAlphaBorder = this._transparentAlpha / 2; - } - } -}; -Signals.addSignalMethods(Transparency.prototype); diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/utils.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/utils.js deleted file mode 100644 index 0beaa75..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/utils.js +++ /dev/null @@ -1,416 +0,0 @@ - -const Gi = imports._gi; - -const Clutter = imports.gi.Clutter; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; -const Meta = imports.gi.Meta; -const St = imports.gi.St; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Docking = Me.imports.docking; - -var SignalsHandlerFlags = { - NONE: 0, - CONNECT_AFTER: 1 -}; - -/** - * Simplify global signals and function injections handling - * abstract class - */ -const BasicHandler = class DashToDock_BasicHandler { - - constructor(parentObject) { - this._storage = new Object(); - - if (parentObject) { - if (!(parentObject.connect instanceof Function)) - throw new TypeError('Not a valid parent object'); - - if (!(parentObject instanceof GObject.Object) || - GObject.signal_lookup('destroy', parentObject.constructor.$gtype)) { - this._parentObject = parentObject; - this._destroyId = parentObject.connect('destroy', () => this.destroy()); - } - } - } - - add(...args) { - // Convert arguments object to array, concatenate with generic - // Call addWithLabel with ags as if they were passed arguments - this.addWithLabel('generic', ...args); - } - - destroy() { - this._parentObject?.disconnect(this._destroyId); - this._parentObject = null; - - for( let label in this._storage ) - this.removeWithLabel(label); - } - - addWithLabel(label, ...args) { - let argsArray = [...args]; - if (argsArray.every(arg => !Array.isArray(arg))) - argsArray = [argsArray]; - - if (this._storage[label] == undefined) - this._storage[label] = new Array(); - - // Skip first element of the arguments - for (const argArray of argsArray) { - if (argArray.length < 3) - throw new Error('Unexpected number of arguments'); - let item = this._storage[label]; - try { - item.push(this._create(...argArray)); - } catch (e) { - logError(e); - } - } - } - - removeWithLabel(label) { - if (this._storage[label]) { - for (let i = 0; i < this._storage[label].length; i++) - this._remove(this._storage[label][i]); - - delete this._storage[label]; - } - } - - // Virtual methods to be implemented by subclass - - /** - * Create single element to be stored in the storage structure - */ - _create(_object, _element, _callback) { - throw new GObject.NotImplementedError(`_create in ${this.constructor.name}`); - } - - /** - * Correctly delete single element - */ - _remove(_item) { - throw new GObject.NotImplementedError(`_remove in ${this.constructor.name}`); - } -}; - -/** - * Manage global signals - */ -var GlobalSignalsHandler = class DashToDock_GlobalSignalHandler extends BasicHandler { - - _create(object, event, callback, flags = SignalsHandlerFlags.NONE) { - if (!object) - throw new Error('Impossible to connect to an invalid object'); - - let after = flags == SignalsHandlerFlags.CONNECT_AFTER; - let connector = after ? object.connect_after : object.connect; - - if (!connector) { - throw new Error(`Requested to connect to signal '${event}', ` + - `but no implementation for 'connect${after ? '_after' : ''}' `+ - `found in ${object.constructor.name}`); - } - - let id = connector.call(object, event, callback); - - return [object, id]; - } - - _remove(item) { - const [object, id] = item; - object.disconnect(id); - } -}; - -/** - * Color manipulation utilities - */ -var ColorUtils = class DashToDock_ColorUtils { - - // Darken or brigthen color by a fraction dlum - // Each rgb value is modified by the same fraction. - // Return "#rrggbb" string - static ColorLuminance(r, g, b, dlum) { - let rgbString = '#'; - - rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(r*(1+dlum), 0), 255)), 2); - rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(g*(1+dlum), 0), 255)), 2); - rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(b*(1+dlum), 0), 255)), 2); - - return rgbString; - } - - // Convert decimal to an hexadecimal string adding the desired padding - static _decimalToHex(d, padding) { - let hex = d.toString(16); - while (hex.length < padding) - hex = '0'+ hex; - return hex; - } - - // Convert hsv ([0-1, 0-1, 0-1]) to rgb ([0-255, 0-255, 0-255]). - // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV - // here with h = [0,1] instead of [0, 360] - // Accept either (h,s,v) independently or {h:h, s:s, v:v} object. - // Return {r:r, g:g, b:b} object. - static HSVtoRGB(h, s, v) { - if (arguments.length === 1) { - s = h.s; - v = h.v; - h = h.h; - } - - let r,g,b; - let c = v*s; - let h1 = h*6; - let x = c*(1 - Math.abs(h1 % 2 - 1)); - let m = v - c; - - if (h1 <=1) - r = c + m, g = x + m, b = m; - else if (h1 <=2) - r = x + m, g = c + m, b = m; - else if (h1 <=3) - r = m, g = c + m, b = x + m; - else if (h1 <=4) - r = m, g = x + m, b = c + m; - else if (h1 <=5) - r = x + m, g = m, b = c + m; - else - r = c + m, g = m, b = x + m; - - return { - r: Math.round(r * 255), - g: Math.round(g * 255), - b: Math.round(b * 255) - }; - } - - // Convert rgb ([0-255, 0-255, 0-255]) to hsv ([0-1, 0-1, 0-1]). - // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV - // here with h = [0,1] instead of [0, 360] - // Accept either (r,g,b) independently or {r:r, g:g, b:b} object. - // Return {h:h, s:s, v:v} object. - static RGBtoHSV(r, g, b) { - if (arguments.length === 1) { - r = r.r; - g = r.g; - b = r.b; - } - - let h,s,v; - - let M = Math.max(r, g, b); - let m = Math.min(r, g, b); - let c = M - m; - - if (c == 0) - h = 0; - else if (M == r) - h = ((g-b)/c) % 6; - else if (M == g) - h = (b-r)/c + 2; - else - h = (r-g)/c + 4; - - h = h/6; - v = M/255; - if (M !== 0) - s = c/M; - else - s = 0; - - return { - h: h, - s: s, - v: v - }; - } -}; - -/** - * Manage function injection: both instances and prototype can be overridden - * and restored - */ -var InjectionsHandler = class DashToDock_InjectionsHandler extends BasicHandler { - - _create(object, name, injectedFunction) { - let original = object[name]; - - if (!(original instanceof Function)) - throw new Error(`Virtual function ${name} is not available for ${prototype}`); - - object[name] = function(...args) { return injectedFunction.call(this, original, ...args) }; - return [object, name, original]; - } - - _remove(item) { - const [object, name, original] = item; - object[name] = original; - } -}; - -/** - * Manage vfunction injection: both instances and prototype can be overridden - * and restored - */ -var VFuncInjectionsHandler = class DashToDock_VFuncInjectionsHandler extends BasicHandler { - - _create(prototype, name, injectedFunction) { - const original = prototype[`vfunc_${name}`]; - if (!(original instanceof Function)) - throw new Error(`Virtual function ${name} is not available for ${prototype}`); - prototype[Gi.hook_up_vfunc_symbol](name, injectedFunction); - return [prototype, name]; - } - - _remove(item) { - const [prototype, name] = item; - const originalVFunc = prototype[`vfunc_${name}`]; - try { - // This may fail if trying to reset to a never-overridden vfunc - // as gjs doesn't consider it a function, even if it's true that - // originalVFunc instanceof Function. - prototype[Gi.hook_up_vfunc_symbol](name, originalVFunc); - } catch { - try { - prototype[Gi.hook_up_vfunc_symbol](name, function (...args) { - return originalVFunc.call(this, ...args); - }); - } catch (e) { - logError(e, `Removing vfunc_${name}`); - } - } - } -}; - -/** - * Manage properties injection: both instances and prototype can be overridden - * and restored - */ -var PropertyInjectionsHandler = class DashToDock_PropertyInjectionsHandler extends BasicHandler { - - _create(instance, name, injectedPropertyDescriptor) { - if (!(name in instance)) - throw new Error(`Object ${instance} has no '${name}' property`); - - const prototype = instance.constructor.prototype; - const originalPropertyDescriptor = Object.getOwnPropertyDescriptor(prototype, name) ?? - Object.getOwnPropertyDescriptor(instance, name); - - Object.defineProperty(instance, name, { - ...originalPropertyDescriptor, - ...injectedPropertyDescriptor, - ...{ configurable: true }, - }); - return [instance, name, originalPropertyDescriptor]; - } - - _remove(item) { - const [instance, name, originalPropertyDescriptor] = item; - if (originalPropertyDescriptor) - Object.defineProperty(instance, name, originalPropertyDescriptor); - else - delete instance[name]; - } -}; - -/** - * Return the actual position reverseing left and right in rtl - */ -function getPosition() { - let position = Docking.DockManager.settings.get_enum('dock-position'); - if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) { - if (position == St.Side.LEFT) - position = St.Side.RIGHT; - else if (position == St.Side.RIGHT) - position = St.Side.LEFT; - } - return position; -} - -function getPreviewScale() { - return Docking.DockManager.settings.get_double('preview-size-scale'); -} - -function drawRoundedLine(cr, x, y, width, height, isRoundLeft, isRoundRight, stroke, fill) { - if (height > width) { - y += Math.floor((height - width) / 2.0); - height = width; - } - - height = 2.0 * Math.floor(height / 2.0); - - var leftRadius = isRoundLeft ? height / 2.0 : 0.0; - var rightRadius = isRoundRight ? height / 2.0 : 0.0; - - cr.moveTo(x + width - rightRadius, y); - cr.lineTo(x + leftRadius, y); - if (isRoundLeft) - cr.arcNegative(x + leftRadius, y + leftRadius, leftRadius, -Math.PI/2, Math.PI/2); - else - cr.lineTo(x, y + height); - cr.lineTo(x + width - rightRadius, y + height); - if (isRoundRight) - cr.arcNegative(x + width - rightRadius, y + rightRadius, rightRadius, Math.PI/2, -Math.PI/2); - else - cr.lineTo(x + width, y); - cr.closePath(); - - if (fill != null) { - cr.setSource(fill); - cr.fillPreserve(); - } - if (stroke != null) - cr.setSource(stroke); - cr.stroke(); -} - -/** - * Convert a signal handler with n value parameters (that is, excluding the - * signal source parameter) to an array of n handlers that are each responsible - * for receiving one of the n values and calling the original handler with the - * most up-to-date arguments. - */ -function splitHandler(handler) { - if (handler.length > 30) { - throw new Error("too many parameters"); - } - const count = handler.length - 1; - let missingValueBits = (1 << count) - 1; - const values = Array.from({ length: count }); - return values.map((_ignored, i) => { - const mask = ~(1 << i); - return (obj, value) => { - values[i] = value; - missingValueBits &= mask; - if (missingValueBits === 0) { - handler(obj, ...values); - } - }; - }); -} - -var IconTheme = class DashToDockIconTheme { - constructor() { - const settings = St.Settings.get(); - this._iconTheme = new Gtk.IconTheme(); - this._iconTheme.set_custom_theme(settings.gtkIconTheme); - this._changesId = settings.connect('notify::gtk-icon-theme', () => { - this._iconTheme.set_custom_theme(settings.gtkIconTheme); - }); - } - - get iconTheme() { - return this._iconTheme; - } - - destroy() { - St.Settings.get().disconnect(this._changesId); - this._iconTheme = null; - } -} diff --git a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/windowPreview.js b/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/windowPreview.js deleted file mode 100644 index e33f5df..0000000 --- a/.local/share/gnome-shell/extensions/dash-to-dock@micxgx.gmail.com/windowPreview.js +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Credits: - * This file is based on code from the Dash to Panel extension by Jason DeRose - * and code from the Taskbar extension by Zorin OS - * Some code was also adapted from the upstream Gnome Shell source code. - */ -const Clutter = imports.gi.Clutter; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const St = imports.gi.St; -const Main = imports.ui.main; - -const BoxPointer = imports.ui.boxpointer; -const Params = imports.misc.params; -const PopupMenu = imports.ui.popupMenu; -const Workspace = imports.ui.workspace; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Utils = Me.imports.utils; - -const PREVIEW_MAX_WIDTH = 250; -const PREVIEW_MAX_HEIGHT = 150; - -const PREVIEW_ANIMATION_DURATION = 250; - -var WindowPreviewMenu = class DashToDock_WindowPreviewMenu extends PopupMenu.PopupMenu { - - constructor(source) { - super(source, 0.5, Utils.getPosition()); - - // We want to keep the item hovered while the menu is up - this.blockSourceEvents = true; - - this._source = source; - this._app = this._source.app; - let monitorIndex = this._source.monitorIndex; - - this.actor.add_style_class_name('app-well-menu'); - this.actor.add_style_class_name('app-menu'); - this.actor.set_style('max-width: ' + (Main.layoutManager.monitors[monitorIndex].width - 22) + 'px; ' + - 'max-height: ' + (Main.layoutManager.monitors[monitorIndex].height - 22) + 'px;'); - this.actor.hide(); - - // Chain our visibility and lifecycle to that of the source - this._mappedId = this._source.connect('notify::mapped', () => { - if (!this._source.mapped) - this.close(); - }); - this._destroyId = this._source.connect('destroy', this.destroy.bind(this)); - - Main.uiGroup.add_actor(this.actor); - - this.connect('destroy', this._onDestroy.bind(this)); - } - - _redisplay() { - if (this._previewBox) - this._previewBox.destroy(); - this._previewBox = new WindowPreviewList(this._source); - this.addMenuItem(this._previewBox); - this._previewBox._redisplay(); - } - - popup() { - let windows = this._source.getInterestingWindows(); - if (windows.length > 0) { - this._redisplay(); - this.open(BoxPointer.PopupAnimation.FULL); - this.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); - this._source.emit('sync-tooltip'); - } - } - - _onDestroy() { - if (this._mappedId) - this._source.disconnect(this._mappedId); - - if (this._destroyId) - this._source.disconnect(this._destroyId); - } -}; - -var WindowPreviewList = class DashToDock_WindowPreviewList extends PopupMenu.PopupMenuSection { - - constructor(source) { - super(); - this.actor = new St.ScrollView({ - name: 'dashtodockWindowScrollview', - hscrollbar_policy: St.PolicyType.NEVER, - vscrollbar_policy: St.PolicyType.NEVER, - enable_mouse_scrolling: true - }); - - this.actor.connect('scroll-event', this._onScrollEvent.bind(this)); - - let position = Utils.getPosition(); - this.isHorizontal = position == St.Side.BOTTOM || position == St.Side.TOP; - this.box.set_vertical(!this.isHorizontal); - this.box.set_name('dashtodockWindowList'); - this.actor.add_actor(this.box); - this.actor._delegate = this; - - this._shownInitially = false; - - this._source = source; - this.app = source.app; - - this._redisplayId = Main.initializeDeferredWork(this.actor, this._redisplay.bind(this)); - - this.actor.connect('destroy', this._onDestroy.bind(this)); - this._stateChangedId = this.app.connect('windows-changed', - this._queueRedisplay.bind(this)); - } - - _queueRedisplay () { - Main.queueDeferredWork(this._redisplayId); - } - - _onScrollEvent(actor, event) { - // Event coordinates are relative to the stage but can be transformed - // as the actor will only receive events within his bounds. - let stage_x, stage_y, ok, event_x, event_y, actor_w, actor_h; - [stage_x, stage_y] = event.get_coords(); - [ok, event_x, event_y] = actor.transform_stage_point(stage_x, stage_y); - [actor_w, actor_h] = actor.get_size(); - - // If the scroll event is within a 1px margin from - // the relevant edge of the actor, let the event propagate. - if (event_y >= actor_h - 2) - return Clutter.EVENT_PROPAGATE; - - // Skip to avoid double events mouse - if (event.is_pointer_emulated()) - return Clutter.EVENT_STOP; - - let adjustment, delta; - - if (this.isHorizontal) - adjustment = this.actor.get_hscroll_bar().get_adjustment(); - else - adjustment = this.actor.get_vscroll_bar().get_adjustment(); - - let increment = adjustment.step_increment; - - switch ( event.get_scroll_direction() ) { - case Clutter.ScrollDirection.UP: - delta = -increment; - break; - case Clutter.ScrollDirection.DOWN: - delta = +increment; - break; - case Clutter.ScrollDirection.SMOOTH: - let [dx, dy] = event.get_scroll_delta(); - delta = dy*increment; - delta += dx*increment; - break; - - } - - adjustment.set_value(adjustment.get_value() + delta); - - return Clutter.EVENT_STOP; - } - - _onDestroy() { - this.app.disconnect(this._stateChangedId); - this._stateChangedId = 0; - } - - _createPreviewItem(window) { - let preview = new WindowPreviewMenuItem(window); - return preview; - } - - _redisplay () { - let children = this._getMenuItems().filter(function(actor) { - return actor._window; - }); - - // Windows currently on the menu - let oldWin = children.map(function(actor) { - return actor._window; - }); - - // All app windows with a static order - let newWin = this._source.getInterestingWindows().sort(function(a, b) { - return a.get_stable_sequence() > b.get_stable_sequence(); - }); - - let addedItems = []; - let removedActors = []; - - let newIndex = 0; - let oldIndex = 0; - - while (newIndex < newWin.length || oldIndex < oldWin.length) { - // No change at oldIndex/newIndex - if (oldWin[oldIndex] && - oldWin[oldIndex] == newWin[newIndex]) { - oldIndex++; - newIndex++; - continue; - } - - // Window removed at oldIndex - if (oldWin[oldIndex] && - newWin.indexOf(oldWin[oldIndex]) == -1) { - removedActors.push(children[oldIndex]); - oldIndex++; - continue; - } - - // Window added at newIndex - if (newWin[newIndex] && - oldWin.indexOf(newWin[newIndex]) == -1) { - addedItems.push({ item: this._createPreviewItem(newWin[newIndex]), - pos: newIndex }); - newIndex++; - continue; - } - - // Window moved - let insertHere = newWin[newIndex + 1] && - newWin[newIndex + 1] == oldWin[oldIndex]; - let alreadyRemoved = removedActors.reduce(function(result, actor) { - let removedWin = actor._window; - return result || removedWin == newWin[newIndex]; - }, false); - - if (insertHere || alreadyRemoved) { - addedItems.push({ item: this._createPreviewItem(newWin[newIndex]), - pos: newIndex + removedActors.length }); - newIndex++; - } else { - removedActors.push(children[oldIndex]); - oldIndex++; - } - } - - for (let i = 0; i < addedItems.length; i++) - this.addMenuItem(addedItems[i].item, - addedItems[i].pos); - - for (let i = 0; i < removedActors.length; i++) { - let item = removedActors[i]; - if (this._shownInitially) - item._animateOutAndDestroy(); - else - item.actor.destroy(); - } - - // Skip animations on first run when adding the initial set - // of items, to avoid all items zooming in at once - let animate = this._shownInitially; - - if (!this._shownInitially) - this._shownInitially = true; - - for (let i = 0; i < addedItems.length; i++) - addedItems[i].item.show(animate); - - // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744 - // Without it, StBoxLayout may use a stale size cache - this.box.queue_relayout(); - - if (newWin.length < 1) - this._getTopMenu().close(~0); - - // As for upstream: - // St.ScrollView always requests space horizontally for a possible vertical - // scrollbar if in AUTOMATIC mode. Doing better would require implementation - // of width-for-height in St.BoxLayout and St.ScrollView. This looks bad - // when we *don't* need it, so turn off the scrollbar when that's true. - // Dynamic changes in whether we need it aren't handled properly. - let needsScrollbar = this._needsScrollbar(); - let scrollbar_policy = needsScrollbar ? - St.PolicyType.AUTOMATIC : St.PolicyType.NEVER; - if (this.isHorizontal) - this.actor.hscrollbar_policy = scrollbar_policy; - else - this.actor.vscrollbar_policy = scrollbar_policy; - - if (needsScrollbar) - this.actor.add_style_pseudo_class('scrolled'); - else - this.actor.remove_style_pseudo_class('scrolled'); - } - - _needsScrollbar() { - let topMenu = this._getTopMenu(); - let topThemeNode = topMenu.actor.get_theme_node(); - if (this.isHorizontal) { - let [topMinWidth, topNaturalWidth] = topMenu.actor.get_preferred_width(-1); - let topMaxWidth = topThemeNode.get_max_width(); - return topMaxWidth >= 0 && topNaturalWidth >= topMaxWidth; - } else { - let [topMinHeight, topNaturalHeight] = topMenu.actor.get_preferred_height(-1); - let topMaxHeight = topThemeNode.get_max_height(); - return topMaxHeight >= 0 && topNaturalHeight >= topMaxHeight; - } - - } - - isAnimatingOut() { - return this.actor.get_children().reduce(function(result, actor) { - return result || actor.animatingOut; - }, false); - } -}; - -var WindowPreviewMenuItem = GObject.registerClass( -class WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem { - _init(window, params) { - super._init(params); - - this._window = window; - this._destroyId = 0; - this._windowAddedId = 0; - [this._width, this._height, this._scale] = this._getWindowPreviewSize(); // This gets the actual windows size for the preview - - // We don't want this: it adds spacing on the left of the item. - this.remove_child(this._ornamentLabel); - this.add_style_class_name('dashtodock-app-well-preview-menu-item'); - - // Now we don't have to set PREVIEW_MAX_WIDTH and PREVIEW_MAX_HEIGHT as preview size - that made all kinds of windows either stretched or squished (aspect ratio problem) - this._cloneBin = new St.Bin(); - this._cloneBin.set_size(this._width*this._scale, this._height*this._scale); - - // TODO: improve the way the closebutton is layout. Just use some padding - // for the moment. - this._cloneBin.set_style('padding-bottom: 0.5em'); - - this.closeButton = new St.Button({ style_class: 'window-close', - x_expand: true, - y_expand: true}); - this.closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); - this.closeButton.set_x_align(Clutter.ActorAlign.END); - this.closeButton.set_y_align(Clutter.ActorAlign.START); - - - this.closeButton.opacity = 0; - this.closeButton.connect('clicked', this._closeWindow.bind(this)); - - let overlayGroup = new Clutter.Actor({layout_manager: new Clutter.BinLayout(), y_expand: true }); - - overlayGroup.add_actor(this._cloneBin); - overlayGroup.add_actor(this.closeButton); - - let label = new St.Label({ text: window.get_title()}); - label.set_style('max-width: '+PREVIEW_MAX_WIDTH +'px'); - let labelBin = new St.Bin({ child: label, - x_align: Clutter.ActorAlign.CENTER, - }); - - this._windowTitleId = this._window.connect('notify::title', () => { - label.set_text(this._window.get_title()); - }); - - let box = new St.BoxLayout({ vertical: true, - reactive:true, - x_expand:true }); - box.add(overlayGroup); - box.add(labelBin); - this.add_actor(box); - - this._cloneTexture(window); - - this.connect('destroy', this._onDestroy.bind(this)); - } - - _getWindowPreviewSize() { - let mutterWindow = this._window.get_compositor_private(); - let [width, height] = mutterWindow.get_size(); - - let scale; - - if (Utils.getPreviewScale()) { - scale = Utils.getPreviewScale(); - } else { - // a simple example with 1680x1050: - // * 250/1680 = 0,1488 - // * 150/1050 = 0,1429 - // => scale is 0,1429 - scale = Math.min(1.0, PREVIEW_MAX_WIDTH/width, PREVIEW_MAX_HEIGHT/height) - } - - // width and height that we wanna multiply by scale - return [width, height, scale]; - } - - _cloneTexture(metaWin){ - - let mutterWindow = metaWin.get_compositor_private(); - - // Newly-created windows are added to a workspace before - // the compositor finds out about them... - // Moreover sometimes they return an empty texture, thus as a workarounf also check for it size - if (!mutterWindow || !mutterWindow.get_texture() || !mutterWindow.get_size()[0]) { - this._cloneTextureId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { - // Check if there's still a point in getting the texture, - // otherwise this could go on indefinitely - if (metaWin.get_workspace()) - this._cloneTexture(metaWin); - this._cloneTextureId = 0; - return GLib.SOURCE_REMOVE; - }); - GLib.Source.set_name_by_id(this._cloneTextureId, '[dash-to-dock] this._cloneTexture'); - return; - } - - let clone = new Clutter.Clone ({ source: mutterWindow, - reactive: true, - width: this._width * this._scale, - height: this._height * this._scale }); - - // when the source actor is destroyed, i.e. the window closed, first destroy the clone - // and then destroy the menu item (do this animating out) - this._destroyId = mutterWindow.connect('destroy', () => { - clone.destroy(); - this._destroyId = 0; // avoid to try to disconnect this signal from mutterWindow in _onDestroy(), - // as the object was just destroyed - this._animateOutAndDestroy(); - }); - - this._clone = clone; - this._mutterWindow = mutterWindow; - this._cloneBin.set_child(this._clone); - - this._clone.connect('destroy', () => { - if (this._destroyId) { - mutterWindow.disconnect(this._destroyId); - this._destroyId = 0; - } - this._clone = null; - }) - } - - _windowCanClose() { - return this._window.can_close() && - !this._hasAttachedDialogs(); - } - - _closeWindow(actor) { - this._workspace = this._window.get_workspace(); - - // This mechanism is copied from the workspace.js upstream code - // It forces window activation if the windows don't get closed, - // for instance because asking user confirmation, by monitoring the opening of - // such additional confirmation window - this._windowAddedId = this._workspace.connect('window-added', - this._onWindowAdded.bind(this)); - - this.deleteAllWindows(); - } - - deleteAllWindows() { - // Delete all windows, starting from the bottom-most (most-modal) one - //let windows = this._window.get_compositor_private().get_children(); - let windows = this._clone.get_children(); - for (let i = windows.length - 1; i >= 1; i--) { - let realWindow = windows[i].source; - let metaWindow = realWindow.meta_window; - - metaWindow.delete(global.get_current_time()); - } - - this._window.delete(global.get_current_time()); - } - - _onWindowAdded(workspace, win) { - let metaWindow = this._window; - - if (win.get_transient_for() == metaWindow) { - workspace.disconnect(this._windowAddedId); - this._windowAddedId = 0; - - // use an idle handler to avoid mapping problems - - // see comment in Workspace._windowAdded - let activationEvent = Clutter.get_current_event(); - let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { - this.emit('activate', activationEvent); - return GLib.SOURCE_REMOVE; - }); - GLib.Source.set_name_by_id(id, '[dash-to-dock] this.emit'); - } - } - - _hasAttachedDialogs() { - // count trasient windows - let n=0; - this._window.foreach_transient(function(){n++;}); - return n>0; - } - - vfunc_key_focus_in() { - super.vfunc_key_focus_in(); - this._showCloseButton(); - } - - vfunc_key_focus_out() { - super.vfunc_key_focus_out(); - this._hideCloseButton(); - } - - vfunc_enter_event(crossingEvent) { - this._showCloseButton(); - return super.vfunc_enter_event(crossingEvent); - } - - vfunc_leave_event(crossingEvent) { - this._hideCloseButton(); - return super.vfunc_leave_event(crossingEvent); - } - - _idleToggleCloseButton() { - this._idleToggleCloseId = 0; - - this._hideCloseButton(); - - return GLib.SOURCE_REMOVE; - } - - _showCloseButton() { - - if (this._windowCanClose()) { - this.closeButton.show(); - this.closeButton.remove_all_transitions(); - this.closeButton.ease({ - opacity: 255, - duration: Workspace.WINDOW_OVERLAY_FADE_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD - }); - } - } - - _hideCloseButton() { - if (this.closeButton.has_pointer || - this.get_children().some(a => a.has_pointer)) - return; - - this.closeButton.remove_all_transitions(); - this.closeButton.ease({ - opacity: 0, - duration: Workspace.WINDOW_OVERLAY_FADE_TIME, - mode: Clutter.AnimationMode.EASE_IN_QUAD - }); - } - - show(animate) { - let fullWidth = this.get_width(); - - this.opacity = 0; - this.set_width(0); - - let time = animate ? PREVIEW_ANIMATION_DURATION : 0; - this.remove_all_transitions(); - this.ease({ - opacity: 255, - width: fullWidth, - duration: time, - mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD, - }); - } - - _animateOutAndDestroy() { - this.remove_all_transitions(); - this.ease({ - opacity: 0, - duration: PREVIEW_ANIMATION_DURATION, - }); - - this.ease({ - width: 0, - height: 0, - duration: PREVIEW_ANIMATION_DURATION, - delay: PREVIEW_ANIMATION_DURATION, - onComplete: () => this.destroy() - }); - } - - activate() { - this._getTopMenu().close(); - Main.activateWindow(this._window); - } - - _onDestroy() { - if (this._cloneTextureId) { - GLib.source_remove(this._cloneTextureId); - this._cloneTextureId = 0; - } - - if (this._windowAddedId > 0) { - this._workspace.disconnect(this._windowAddedId); - this._windowAddedId = 0; - } - - if (this._destroyId > 0) { - this._mutterWindow.disconnect(this._destroyId); - this._destroyId = 0; - } - - if (this._windowTitleId > 0) { - this._window.disconnect(this._windowTitleId); - this._windowTitleId = 0; - } - } -}); diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/COPYING b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/COPYING deleted file mode 100644 index 6183b77..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/COPYING +++ /dev/null @@ -1,13 +0,0 @@ -GPL v2; Copyright (c) 2017 Evan Welsh - -Dynamic Panel Transparency is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, version 2 only. - -Dynamic Panel Transparency is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Dynamic Panel Transparency. If not, see . diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/LICENSE b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/LICENSE deleted file mode 100644 index 6ccd897..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/LICENSE +++ /dev/null @@ -1,130 +0,0 @@ -GNU GENERAL PUBLIC LICENSE - -Version 2, June 1991 - -Copyright (C) 1989, 1991 Free Software Foundation, Inc. -51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. -Preamble - -The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. - -When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. - -To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. - -For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. - -We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. - -Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. - -Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. - -The precise terms and conditions for copying, distribution and modification follow. - -TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - -0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. - -1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. - -You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. - -2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: - -a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. -b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. -c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) -These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. - -3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: - -a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, -b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, -c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) -The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. - -If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. - -4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. - -5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. - -6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. - -7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. - -This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. - -8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. - -9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. - -10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. - -NO WARRANTY - -11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - -12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -END OF TERMS AND CONDITIONS - -How to Apply These Terms to Your New Programs - -If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. - -To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - -one line to give the program's name and an idea of what it does. -Copyright (C) yyyy name of author - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this when it starts in an interactive mode: - -Gnomovision version 69, Copyright (C) year name of author -Gnomovision comes with ABSOLUTELY NO WARRANTY; for details -type `show w'. This is free software, and you are welcome -to redistribute it under certain conditions; type `show c' -for details. -The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: - -Yoyodyne, Inc., hereby disclaims all copyright -interest in the program `Gnomovision' -(which makes passes at compilers) written -by James Hacker. - -signature of Ty Coon, 1 April 1989 -Ty Coon, President of Vice -This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/convenience.js b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/convenience.js deleted file mode 100644 index 24b851b..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/convenience.js +++ /dev/null @@ -1,110 +0,0 @@ -/* exported initTranslations, getSettings, getSchemaObj */ - -/* - Copyright (c) 2011-2012, Giovanni Campagna - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the GNOME nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -const Gettext = imports.gettext; - -const Gio = imports.gi.Gio; - -const Config = imports.misc.config; -const ExtensionUtils = imports.misc.extensionUtils; - -/** - * initTranslations: - * @domain: (optional): the gettext domain to use - * - * Initialize Gettext to load translations from extensionsdir/locale. - * If @domain is not provided, it will be taken from metadata['gettext-domain'] - */ -function initTranslations(domain) { - let extension = ExtensionUtils.getCurrentExtension(); - - domain = domain || extension.metadata['gettext-domain']; - - // check if this extension was built with "make zip-file", and thus - // has the locale files in a subfolder - // otherwise assume that extension has been installed in the - // same prefix as gnome-shell - let localeDir = extension.dir.get_child('locale'); - - if (localeDir.query_exists(null)) { - Gettext.bindtextdomain(domain, localeDir.get_path()); - } else { - Gettext.bindtextdomain(domain, Config.LOCALEDIR); - } -} - -/** - * getSettings: - * @schema: (optional): the GSettings schema id - * - * Builds and return a GSettings schema for @schema, using schema files - * in extensionsdir/schemas. If @schema is not provided, it is taken from - * metadata['settings-schema']. - */ -function getSettings(schema) { - let schemaObj = getSchemaObj(schema); - - return new Gio.Settings({ settings_schema: schemaObj }); -} - -/** - * Seperated from getSettings to allow for custom paths. - * - * @param {string} schema - the GSettings schema id (default from extension.metadata) - * - * @returns {Object} A GSettingsSchema found based on the given schema path. - */ -function getSchemaObj(schema, defaultSource = false) { - let extension = ExtensionUtils.getCurrentExtension(); - - schema = schema || extension.metadata['settings-schema']; - - const GioSSS = Gio.SettingsSchemaSource; - - // check if this extension was built with "make zip-file", and thus - // has the schema files in a subfolder - // otherwise assume that extension has been installed in the - // same prefix as gnome-shell (and therefore schemas are available - // in the standard folders) - let schemaDir = extension.dir.get_child('schemas'); - let schemaSource = null; - - if (schemaDir.query_exists(null) && !defaultSource) { - schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), GioSSS.get_default(), false); - } else { - schemaSource = GioSSS.get_default(); - } - - let schemaObj = schemaSource.lookup(schema, true); - - if (!schemaObj) { - throw new Error('Schema ' + schema + ' could not be found for extension ' + extension.metadata.uuid + '. Please check your installation.'); - } - - return schemaObj; -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/dynamic-panel-transparency.pot b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/dynamic-panel-transparency.pot deleted file mode 100644 index 7a3ef00..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/dynamic-panel-transparency.pot +++ /dev/null @@ -1,162 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:22-0700\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: prefs.js:89 -msgid "default" -msgstr "" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "" - -#: prefs.ui:9 -msgid "Website" -msgstr "" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "" - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "" - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "" - -#: prefs.ui:1027 -msgid "Background" -msgstr "" - -#: prefs.ui:1037 -msgid "About" -msgstr "" diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/events.js b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/events.js deleted file mode 100644 index bacb080..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/events.js +++ /dev/null @@ -1,231 +0,0 @@ -/* exported init, cleanup, get_current_maximized_window */ - -const Mainloop = imports.mainloop; - -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; -const Shell = imports.gi.Shell; - -const Main = imports.ui.main; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); - -const Convenience = Me.imports.convenience; -const Extension = Me.imports.extension; -const Intellifade = Me.imports.intellifade; -const Settings = Me.imports.settings; -const Util = Me.imports.util; - -const Theming = Me.imports.theming; -const Transitions = Me.imports.transitions; - -/** - * Signal Connections - * js/ui/overview.js/hidden: occurs after the overview is hidden - * js/ui/overview.js/shown: occurs after the overview is open - * MetaScreen/restacked: occurs when the window Z-ordering changes - * window_group/actor-added: occurs when a window actor is added - * window_group/actor-removed: occurs when a window actor is removed - * wm/switch-workspace: occurs after a workspace is switched - */ - -/** - * Intialize. - * - */ -function init() { - this._wm_tracker = Shell.WindowTracker.get_default(); - - this._overviewHidingSig = Main.overview.connect('hiding', Util.strip_args(Intellifade.syncCheck).bind(this)); - - if (Settings.transition_with_overview()) { - this._overviewShownSig = Main.overview.connect('showing', _overviewShown.bind(this)); - } else { - this._overviewShownSig = Main.overview.connect('shown', _overviewShown.bind(this)); - } - - let windows = global.get_window_actors(); - - for (let window_actor of windows) { - /* Simulate window creation event, null container because _windowActorAdded doesn't utilize containers */ - _windowActorAdded(null, window_actor, false); - } - - this._workspaceSwitchSig = global.window_manager.connect_after('switch-workspace', _workspaceSwitched.bind(this)); - - const screen = global.screen || global.display; - - if (screen) { - this._windowRestackedSig = screen.connect_after('restacked', _windowRestacked.bind(this)); - } else { - log('[Dynamic Panel Transparency] Error could not register \'restacked\' event.'); - } - - this._windowActorAddedSig = global.window_group.connect('actor-added', _windowActorAdded.bind(this)); - this._windowActorRemovedSig = global.window_group.connect('actor-removed', _windowActorRemoved.bind(this)); - - this._appFocusedSig = this._wm_tracker.connect_after('notify::focus-app', _windowRestacked.bind(this)); -} - -function disconnect(obj, sig) { - try { - if (sig != null && obj) { - obj.disconnect(sig); - } - } catch (error) { - log('[Dynamic Panel Transparency] Failed to disconnect signal: ' + error); - } -} - -/** - * Don't want to hold onto anything that isn't ours. - * - */ -function cleanup() { - /* Disconnect Signals */ - if (this._windowUnminimizeSig) { - disconnect(global.window_manager, this._windowUnminimizeSig); - } - - disconnect(Main.overview, this._overviewShownSig); - disconnect(Main.overview, this._overviewHidingSig); - - disconnect(global.window_manager, this._workspaceSwitchSig); - - disconnect(global.window_group, this._windowActorAddedSig); - disconnect(global.window_group, this._windowActorRemovedSig); - - const screen = global.screen || global.display; - - if (screen) { - disconnect(screen, this._windowRestackedSig); - } else { - log('[Dynamic Panel Transparency] Error could not disconnect \'restacked\' event.'); - } - - disconnect(this._wm_tracker, this._appFocusedSig); - - let windows = global.get_window_actors(); - - for (let window_actor of windows) { - if (typeof (window_actor._dpt_signals) !== 'undefined') { - for (let signalId of window_actor._dpt_signals) { - disconnect(window_actor, signalId); - } - } - - delete window_actor._dpt_signals; - delete window_actor._dpt_tracking; - } - - /* Cleanup Signals */ - this._windowRestackedSig = null; - this._overviewShownSig = null; - this._overviewHidingSig = null; - this._windowActorRemovedSig = null; - this._workspaceSwitchSig = null; - this._windowActorAddedSig = null; - - this._wm_tracker = null; -} - -/* Event Handlers */ - -/** - * Called whenever the overview is shown. - * - */ -function _overviewShown() { - if (!Transitions.get_transparency_status().is_blank()) { - Transitions.blank_fade_out(); - } - - if (Settings.get_enable_text_color() && (Settings.get_enable_maximized_text_color() || Settings.get_enable_overview_text_color())) { - if (Settings.get_enable_overview_text_color()) { - Theming.remove_text_color(); - Theming.set_text_color('maximized'); - } else { - Theming.remove_text_color('maximized'); - Theming.set_text_color(); - } - } -} - -/** - * Called whenever a window actor is removed. - * - */ -function _windowActorRemoved(container, window_actor) { - if (typeof (window_actor._dpt_tracking) === 'undefined') { - return; - } - - /* Remove our tracking variable. */ - delete window_actor._dpt_tracking; - - if (typeof (window_actor._dpt_signals) !== 'undefined') { - for (let signalId of window_actor._dpt_signals) { - window_actor.disconnect(signalId); - } - } - - delete window_actor._dpt_signals; - - Intellifade.asyncCheck(); -} - -const { major, minor } = Util.get_shell_version(); - -/** - * Called whenever a window is created in the shell. - * - */ -function _windowActorAdded(window_group, window_actor, force = true) { - if (window_actor && (force || typeof (window_actor._dpt_tracking) === 'undefined')) { - window_actor._dpt_tracking = true; - - let ac_wId = -1; - - if (major >= 40 || minor > 36) { - ac_wId = window_actor.connect('notify::allocation', (function() { - Intellifade.asyncCheck(); - }).bind(this)); - } else { - ac_wId = window_actor.connect('allocation-changed', (function() { - Intellifade.asyncCheck(); - }).bind(this)); - } - - const v_wId = window_actor.connect('notify::visible', (function() { - Intellifade.asyncCheck(); - }).bind(this)); - window_actor._dpt_signals = [ac_wId, v_wId]; - - Intellifade.asyncCheck(); - } -} - -/** - * SPECIAL_CASE: Only update if we're using per-app settings or is desktop icons are enabled. - * - */ -function _windowRestacked() { - /* Don't allow restacks while the overview is transitioning. */ - if (!Main.overview.visible) { - /* Detect if desktop icons are enabled. */ - if (Settings.gs_show_desktop()) { - Intellifade.asyncCheck(); - } - } -} - -/** - * SPECIAL_CASE: Update logic requires the workspace that we'll be switching to. - * - */ -function _workspaceSwitched(wm, from, to, direction) { - /* Detect if desktop icons are enabled. */ - if (!Settings.gs_show_desktop()) { - Intellifade.syncCheck(); - } -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/extension.js b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/extension.js deleted file mode 100644 index 7a285a8..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/extension.js +++ /dev/null @@ -1,571 +0,0 @@ -/* exported init, enable, disable */ - -const Mainloop = imports.mainloop; - -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; -const St = imports.gi.St; - -const ExtensionSystem = imports.ui.extensionSystem; -const Main = imports.ui.main; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); - -const Convenience = Me.imports.convenience; -const Events = Me.imports.events; -const Intellifade = Me.imports.intellifade; -const Settings = Me.imports.settings; -const Util = Me.imports.util; - -const Theming = Me.imports.theming; -const Transitions = Me.imports.transitions; - -const SETTINGS_DELAY = 3000; - -/* Only way to prevent multiple runs apparently. Hacky-ness. */ -let modified = false; - -/* Initialize */ -function init() { } - -function enable() { - /* Initialize Settings */ - initialize_settings(); - - /* Initialize Utilities */ - Transitions.init(); - Theming.init(); - Intellifade.init(); - - /* Modify the panel. */ - modify_panel(); - - /* Start the event loop. */ - Events.init(); - - /* Simulate window changes. */ - Intellifade.forceSyncCheck(); - -} - -function disable() { - /* Do this first in case any of the upcoming methods fail. */ - unmodify_panel(); - - try { - /* Disconnect & Null Signals */ - Events.cleanup(); - - /* Cleanup Settings */ - Settings.unbind(); - Settings.cleanup(); - - /* Cleanup Transitions */ - Transitions.cleanup(); - - /* Cleanup Theming */ - Theming.cleanup(); - - /* Cleanup Intellifade */ - Intellifade.cleanup(); - } catch (error) { - log('[DPT] Encountered an error cleaning up extension: ' + error); - } - - /* Shouldn't be an issue, but let's make sure it isn't. */ - modified = false; - - return false; -} - -function modify_panel() { - /* Get Rid of the Panel's CSS Background */ - Theming.initialize_background_styles(); - - let text_shadow = Theming.register_text_shadow(Settings.get_text_shadow_color(), Settings.get_text_shadow_position()); - let icon_shadow = Theming.register_icon_shadow(Settings.get_icon_shadow_color(), Settings.get_icon_shadow_position()); - - /* Add Text Shadowing */ - if (Settings.add_text_shadow()) { - if (text_shadow !== null) { - Theming.add_text_shadow(); - } else { - log('[Dynamic Panel Transparency] Failed to enabled text shadowing.'); - } - } - - /* Add Icon Shadowing */ - if (Settings.add_icon_shadow()) { - if (icon_shadow !== null) { - Theming.add_icon_shadow(); - } else { - log('[Dynamic Panel Transparency] Failed to enabled icon shadowing.'); - } - } - - /* Register text color styling. */ - let [text, icon, arrow] = Theming.register_text_color(Settings.get_text_color()); // eslint-disable-line no-unused-vars - let [maximized_text, maximized_icon, maximized_arrow] = Theming.register_text_color(Settings.get_maximized_text_color(), 'maximized'); // eslint-disable-line no-unused-vars - - if (Settings.get_enable_text_color()) { - if (text !== null) { - Theming.set_text_color(); - } else { - log('[Dynamic Panel Transparency] Failed to enabled text coloring.'); - } - } -} - -function unmodify_panel() { - - /* Remove corner styling */ - Theming.clear_corner_color(); - - /* Remove Our Styling */ - Theming.reapply_panel_styling(); - Theming.reapply_panel_background_image(); - - Theming.remove_panel_transparency(); - - /* Remove shadowing */ - if (Theming.has_text_shadow()) { - Theming.remove_text_shadow(); - } - - if (Theming.has_icon_shadow()) { - Theming.remove_icon_shadow(); - } - - /* Remove text coloring */ - Theming.remove_text_color(); - - /* Remove maximized text coloring */ - Theming.remove_text_color('maximized'); -} - -// TODO: Merge handler code or hide it behind the backend. -function initialize_settings() { - /* Setup settings... */ - Settings.init(); - - /* Register settings... */ - Settings.add({ - key: 'hide-corners', - name: 'hide_corners', - type: 'b', - handler: (function() { - Transitions.update_corner_alpha(); - }.bind(this)) - }); - Settings.add({ - key: 'transition-speed', - name: 'transition_speed', - type: 'i', - handler: ( - /* Update the backend24 transition CSS. */ - function() { - Main.panel.remove_style_class_name('dpt-panel-transition-duration'); - - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - for (let i = Theming.stylesheets.length - 1; i >= 0; i--) { - let stylesheet = Theming.stylesheets[i]; - if (stylesheet.indexOf('transitions') !== -1 && stylesheet.endsWith('panel-transition-duration.dpt.css')) { - theme.unload_stylesheet(Util.get_file(stylesheet)); - Util.remove_file(stylesheet); - Theming.stylesheets.splice(i, 1); - } - } - - const id = this.panel_transition_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { // eslint-disable-line no-magic-numbers - if (id !== this.panel_transition_update_id) { - return false; - } - - /* Get Rid of the Panel's CSS */ - Theming.update_transition_css(); - - Intellifade.forceSyncCheck(); - - return false; - }).bind(this)); - }).bind(this) - }); - Settings.add({ - key: 'unmaximized-opacity', - name: 'unmaximized_opacity', - type: 'i', - getter: 'get_unmaximized_opacity', - handler: (function() { - const super_id = this.opacity_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { - if (super_id !== this.opacity_update_id) { - return false; - } - - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - for (let i = Theming.stylesheets.length - 1; i >= 0; i--) { - let stylesheet = Theming.stylesheets[i]; - if (stylesheet.indexOf('background') !== -1 && stylesheet.indexOf('panel-') !== -1) { - theme.unload_stylesheet(Util.get_file(stylesheet)); - Util.remove_file(stylesheet); - Theming.stylesheets.splice(i, 1); - } - } - - Theming.initialize_background_styles(); - - const id = this.panel_color_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { // eslint-disable-line no-magic-numbers - if (id !== this.panel_color_update_id) { - return false; - } - - /* Get Rid of the Panel's CSS Background */ - Theming.remove_background_color(); - - Intellifade.forceSyncCheck(); - - return false; - }).bind(this)); - - return false; - }).bind(this)); - }).bind(this) - }); - Settings.add({ - key: 'maximized-opacity', - name: 'maximized_opacity', - type: 'i', - getter: 'get_maximized_opacity', - handler: (function() { - const super_id = this.opacity_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { - if (super_id !== this.opacity_update_id) { - return false; - } - - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - for (let i = Theming.stylesheets.length - 1; i >= 0; i--) { - let stylesheet = Theming.stylesheets[i]; - if (stylesheet.indexOf('background') !== -1 && stylesheet.indexOf('panel-') !== -1) { - theme.unload_stylesheet(Util.get_file(stylesheet)); - Util.remove_file(stylesheet); - Theming.stylesheets.splice(i, 1); - } - } - - Theming.initialize_background_styles(); - - const id = this.panel_color_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { // eslint-disable-line no-magic-numbers - if (id !== this.panel_color_update_id) { - return false; - } - - /* Get Rid of the Panel's CSS Background */ - Intellifade.forceSyncCheck(); - - return false; - }).bind(this)); - - return false; - }).bind(this)); - }).bind(this) - }); - Settings.add({ - key: 'panel-color', - name: 'panel_color', - type: 'ai', - parser: Util.tuple_to_native_color, - handler: ( - /* Handler for 3.24+ */ - function() { - Theming.remove_background_color(); - - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - for (let i = Theming.stylesheets.length - 1; i >= 0; i--) { - let stylesheet = Theming.stylesheets[i]; - if (stylesheet.indexOf('background') !== -1 && stylesheet.indexOf('panel.dpt.css') !== -1) { - theme.unload_stylesheet(Util.get_file(stylesheet)); - Util.remove_file(stylesheet); - Theming.stylesheets.splice(i, 1); - } - } - Theming.register_background_color(Settings.get_panel_color(), 'custom'); - const id = this.panel_color_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { // eslint-disable-line no-magic-numbers - if (id !== this.panel_color_update_id) { - return false; - } - - /* Get Rid of the Panel's CSS Background */ - Theming.remove_background_color(); - - Intellifade.forceSyncCheck(); - - return false; - }).bind(this)); - /* Legacy Handler */ - }).bind(this) - }); - Settings.add({ - key: 'trigger-apps', - name: 'trigger_apps', - type: 'as' - }); - Settings.add({ - key: 'trigger-windows', - name: 'trigger_windows', - type: 'as' - }); - Settings.add({ - key: 'text-shadow', - name: 'text_shadow', - type: 'b', - getter: 'add_text_shadow', - handler: (function() { - if (Settings.add_text_shadow()) { - Theming.add_text_shadow(); - } else { - Theming.remove_text_shadow(); - } - }).bind(this) - }); - Settings.add({ - key: 'icon-shadow', - name: 'icon_shadow', - type: 'b', - getter: 'add_icon_shadow', - handler: (function() { - if (Settings.add_icon_shadow()) { - Theming.add_icon_shadow(); - } else { - Theming.remove_icon_shadow(); - } - }).bind(this) - }); - Settings.add({ - key: 'text-shadow-position', - name: 'text_shadow_position', - type: '(iii)', - handler: (function() { - Theming.remove_text_shadow(); - - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - for (let i = Theming.stylesheets.length - 1; i >= 0; i--) { - let stylesheet = Theming.stylesheets[i]; - if (stylesheet.indexOf('shadow') !== -1 && stylesheet.indexOf('text') !== -1) { - theme.unload_stylesheet(Util.get_file(stylesheet)); - Util.remove_file(stylesheet); - Theming.stylesheets.splice(i, 1); - } - } - let text_shadow = Theming.register_text_shadow(Settings.get_text_shadow_color(), Settings.get_text_shadow_position()); - const id = this.text_shadow_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { // eslint-disable-line no-magic-numbers - if (id !== this.text_shadow_update_id) { - return false; - } - - /* Add Text Shadowing */ - if (Settings.add_text_shadow()) { - if (text_shadow !== null) { - Theming.add_text_shadow(); - } else { - log('[Dynamic Panel Transparency] Failed to enabled text shadowing.'); - } - } - - Intellifade.forceSyncCheck(); - - return false; - }).bind(this)); - }).bind(this) - }); - Settings.add({ - key: 'icon-shadow-position', - name: 'icon_shadow_position', - type: '(iii)', - handler: (function() { - Theming.remove_icon_shadow(); - - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - for (let i = Theming.stylesheets.length - 1; i >= 0; i--) { - let stylesheet = Theming.stylesheets[i]; - if (stylesheet.indexOf('shadow') !== -1 && stylesheet.indexOf('icon') !== -1) { - theme.unload_stylesheet(Util.get_file(stylesheet)); - Util.remove_file(stylesheet); - Theming.stylesheets.splice(i, 1); - } - } - let icon_shadow = Theming.register_icon_shadow(Settings.get_icon_shadow_color(), Settings.get_icon_shadow_position()); - const id = this.icon_shadow_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { // eslint-disable-line no-magic-numbers - if (id !== this.icon_shadow_update_id) { - return false; - } - - /* Add Icon Shadowing */ - if (Settings.add_icon_shadow()) { - if (icon_shadow !== null) { - Theming.add_icon_shadow(); - } else { - log('[Dynamic Panel Transparency] Failed to enabled icon shadowing.'); - } - } - - Intellifade.forceSyncCheck(); - - return false; - }).bind(this)); - }).bind(this) - }); - Settings.add({ - key: 'icon-shadow-color', - name: 'icon_shadow_color', - type: '(iiid)', - parser: Util.tuple_to_native_color, - handler: (function() { - Theming.remove_icon_shadow(); - - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - for (let i = Theming.stylesheets.length - 1; i >= 0; i--) { - let stylesheet = Theming.stylesheets[i]; - if (stylesheet.indexOf('shadow') !== -1 && stylesheet.indexOf('icon') !== -1) { - theme.unload_stylesheet(Util.get_file(stylesheet)); - Util.remove_file(stylesheet); - Theming.stylesheets.splice(i, 1); - } - } - let icon_shadow = Theming.register_icon_shadow(Settings.get_icon_shadow_color(), Settings.get_icon_shadow_position()); - const id = this.icon_shadow_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { // eslint-disable-line no-magic-numbers - if (id !== this.icon_shadow_update_id) { - return false; - } - - /* Add Icon Shadowing */ - if (Settings.add_icon_shadow()) { - if (icon_shadow !== null) { - Theming.add_icon_shadow(); - } else { - log('[Dynamic Panel Transparency] Failed to enabled icon shadowing.'); - } - } - - Intellifade.forceSyncCheck(); - - return false; - }).bind(this)); - }).bind(this) - }); - Settings.add({ - key: 'text-shadow-color', - name: 'text_shadow_color', - type: '(iiid)', - parser: Util.tuple_to_native_color, - handler: (function() { - Theming.remove_text_shadow(); - - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - for (let i = Theming.stylesheets.length - 1; i >= 0; i--) { - let stylesheet = Theming.stylesheets[i]; - if (stylesheet.indexOf('shadow') !== -1 && stylesheet.indexOf('text') !== -1) { - theme.unload_stylesheet(Util.get_file(stylesheet)); - Util.remove_file(stylesheet); - Theming.stylesheets.splice(i, 1); - } - } - let text_shadow = Theming.register_text_shadow(Settings.get_text_shadow_color(), Settings.get_text_shadow_position()); - const id = this.text_shadow_update_id = Mainloop.timeout_add(SETTINGS_DELAY, (function() { // eslint-disable-line no-magic-numbers - if (id !== this.text_shadow_update_id) { - return false; - } - - /* Add Text Shadowing */ - if (Settings.add_text_shadow()) { - if (text_shadow !== null) { - Theming.add_text_shadow(); - } else { - log('[Dynamic Panel Transparency] Failed to enabled text shadowing.'); - } - } - - Intellifade.forceSyncCheck(); - - return false; - }).bind(this)); - }).bind(this) - }); - Settings.add({ - key: 'text-color', - name: 'text_color', - type: '(iii)', - parser: Util.tuple_to_native_color - }); - Settings.add({ - key: 'maximized-text-color', - name: 'maximized_text_color', - type: '(iii)', - parser: Util.tuple_to_native_color - }); - Settings.add({ - key: 'enable-maximized-text-color', - name: 'enable_maximized_text_color', - type: 'b', - handler: (function() { - Intellifade.forceSyncCheck(); - }).bind(this) - }); - Settings.add({ - key: 'remove-panel-styling', - name: 'remove_panel_styling', - getter: 'remove_panel_styling', - type: 'b' - }); - Settings.add({ - key: 'enable-overview-text-color', - name: 'enable_overview_text_color', - type: 'b' - }); - Settings.add({ - key: 'enable-text-color', - name: 'enable_text_color', - type: 'b', - handler: (function() { - if (Settings.get_enable_text_color()) { - Intellifade.forceSyncCheck(); - } else { - Theming.remove_text_color(); - Theming.remove_text_color('maximized'); - } - }).bind(this) - }); - Settings.add({ - key: 'enable-opacity', - name: 'enable_custom_opacity', - getter: 'enable_custom_opacity', - type: 'b' - }); - Settings.add({ - key: 'enable-background-color', - name: 'enable_custom_background_color', - getter: 'enable_custom_background_color', - type: 'b' - }); - Settings.add({ - key: 'transition-with-overview', - name: 'transition_with_overview', - getter: 'transition_with_overview', - type: 'b' - }); - Settings.add({ - key: 'transition-windows-touch', - name: 'transition_windows_touch', - getter: 'transition_when_windows_touch_panel', - type: 'b' - }); - - /* After we've given Settings the necessary information... let's bind it. */ - Settings.bind(); -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/intellifade.js b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/intellifade.js deleted file mode 100644 index a2ff64a..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/intellifade.js +++ /dev/null @@ -1,252 +0,0 @@ -/* exported init, cleanup, asyncCheck, syncCheck, forceAsyncCheck, forceSyncCheck, get_current_maximized_window */ - -const GLib = imports.gi.GLib; -const Mainloop = imports.mainloop; - -const Meta = imports.gi.Meta; -const Shell = imports.gi.Shell; -const St = imports.gi.St; - -const Main = imports.ui.main; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Settings = Me.imports.settings; -const Util = Me.imports.util; - -const Transitions = Me.imports.transitions; -const Theming = Me.imports.theming; - -/* Determines whether to continue the async loop checks. */ -let continueCheck = false; -/* Variable for current detected maximized window... */ -let maximized_window = null; -/* Run the next change regardless of the whether it is the same as the current status. */ -// TODO: Find a nicer way to override optimization code. -let override_optimization = false; -/* Current ID of the async loop (0 if no loop is running) */ -let timeoutId = 0; - -/* How often the asynchronous loop should run in milliseconds... */ -const ASYNC_UPDATE_FREQUENCY = 200; // ms - -function init() { - this._wm_tracker = Shell.WindowTracker.get_default(); - - _updateBounds(); -} - -function cleanup() { - this._wm_tracker = null; - - if (timeoutId > 0) { - Mainloop.source_remove(timeoutId); - } -} - -function forceSyncCheck() { - override_optimization = true; - syncCheck(); -} - -function syncCheck() { - /* Prevent any asynchronous checks from occuring in the loop. */ - continueCheck = false; - /* Stop the asynchronous loop... */ - if (timeoutId > 0) - Mainloop.source_remove(timeoutId); - /* Remove the old loop ID */ - timeoutId = 0; - /* Update bounds when a check is done in sync. */ - _updateBounds(); - /* Run a check. */ - _check(); -} - -function forceAsyncCheck() { - override_optimization = true; - asyncCheck(); -} - -function asyncCheck() { - if (timeoutId <= 0) { - _check(); - - timeoutId = Mainloop.timeout_add(ASYNC_UPDATE_FREQUENCY, (function() { - _check(); - - if (continueCheck) { - continueCheck = false; - return GLib.SOURCE_CONTINUE; - } else { - timeoutId = 0; - return GLib.SOURCE_REMOVE; - } - }).bind(this)); - } else { - continueCheck = true; - } - -} - - -function _updateBounds() { - const panel = Main.panel; - - this.panel_bounds = { - x: panel.get_x(), - y: panel.get_y(), - height: panel.get_height(), - width: panel.get_width(), - is_top: true - }; - - this.scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - - let [, pivot_y] = Main.layoutManager.panelBox.get_pivot_point(); - - // Adjust for bottom panel. - if (pivot_y < 0) { - this.panel_bounds.y = -pivot_y; - this.panel_bounds.is_top = false; - } -} - -/* Main extension logic. Modified to fit Gnome Shell 3.26 design patterns. */ - -// TODO: Cleanup use of variable flags. -function _check() { - if (Main.overview._shown) { - return; - } - - let workspace = null; - - const manager = global.screen || global.workspace_manager; - - if (manager) { - workspace = manager.get_active_workspace(); - } else { - log('[Dynamic Panel Transparency] Error could not get active workspace.'); - } - - let windows = workspace.list_windows(); - windows = global.display.sort_windows_by_stacking(windows); - - let focused_window = global.display.get_focus_window(); - - maximized_window = null; - - let add_transparency = true; - let force_transparency = false; - - /* Handle desktop icons (they're a window too) */ - if (focused_window && focused_window.get_window_type() === Meta.WindowType.DESKTOP) { - add_transparency = true; - maximized_window = focused_window; - } else { - // TODO: Always negative? Is pivot negative? - for (let i = windows.length - 1; i >= 0; i--) { - - let current_window = windows[i]; - - if (!current_window.showing_on_its_workspace() || !current_window.is_on_primary_monitor()) { - continue; - } - - /* Make sure the window is on the correct monitor, isn't minimized, isn't supposed to be excluded, and is actually maximized. */ - if (!Util.is_valid(current_window)) { - continue; - } - - if (current_window.maximized_vertically) { - /* Make sure the top-most window is selected */ - if (maximized_window === null && !force_transparency) { - maximized_window = current_window; - } - - add_transparency = false; - - break; - } - - let frame = current_window.get_frame_rect(); - - if (Main.layoutManager._rightPanelBarrier) { - let overlap = this.panel_bounds.x < frame.x + frame.width && - this.panel_bounds.x + this.panel_bounds.width > frame.x && - this.panel_bounds.y < frame.y + frame.height && - this.panel_bounds.height + this.panel_bounds.y > frame.y; - - if (overlap) { - force_transparency = true; - maximized_window = null; - - break; - } - } - - if (Settings.transition_when_windows_touch_panel()) { - let touching_panel = false; - - if (this.panel_bounds.is_top) { - touching_panel = frame.y >= (this.panel_bounds.y + this.panel_bounds.height) && - frame.y <= (this.panel_bounds.y + this.panel_bounds.height); - } else { - touching_panel = (frame.y + frame.height) >= (this.panel_bounds.y) && - (frame.y + frame.height) <= (this.panel_bounds.y); - } - - if (!force_transparency && touching_panel) { - add_transparency = false; - - if (maximized_window === null && !force_transparency) { - maximized_window = current_window; - } - - break; - } - } - } - } - - if (force_transparency) { - Transitions.fade_out(); - force_transparency = false; - /* Only change if the transparency isn't already correct or if override_optimization has been called */ - } else if (Transitions.get_transparency_status().is_blank()) { - if (add_transparency) { - Transitions.minimum_fade_in(); - } else { - Transitions.fade_in(); - } - } else if (override_optimization || (Transitions.get_transparency_status().is_transparent() !== add_transparency)) { - override_optimization = false; - - if (add_transparency) { - Transitions.fade_out(); - } else { - Transitions.fade_in(); - } - } - - /* Reset text coloring. */ - if (Settings.get_enable_text_color() && (Settings.get_enable_maximized_text_color() || Settings.get_enable_overview_text_color())) { - if (!add_transparency && Settings.get_enable_maximized_text_color()) { - Theming.remove_text_color(); - Theming.set_text_color('maximized'); - } else { - Theming.remove_text_color('maximized'); - Theming.set_text_color(); - } - } -} - -/** - * Returns the current visible maximized window as understood by the events' logic. - * The maximized window is not necessarily the highest window in the z-order. - * - * @returns {Object} The current visible maximized window. - */ -function get_current_maximized_window() { - return maximized_window; -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ar/LC_MESSAGES/dynamic-panel-transparency.mo b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ar/LC_MESSAGES/dynamic-panel-transparency.mo deleted file mode 100644 index 482bb5d..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ar/LC_MESSAGES/dynamic-panel-transparency.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ar/LC_MESSAGES/dynamic-panel-transparency.po b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ar/LC_MESSAGES/dynamic-panel-transparency.po deleted file mode 100644 index a254229..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ar/LC_MESSAGES/dynamic-panel-transparency.po +++ /dev/null @@ -1,231 +0,0 @@ -# Dynamic Panel Transparency Translation File -# Copyright (c) 2017 -# This file is distributed under the same license as the dynamic-panel-transparency package. -# -# Evan Welsh , 2017. -# Mosaab Alzoubi , 2016. -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:20-0700\n" -"PO-Revision-Date: 2016-12-21 12:48+0300\n" -"Last-Translator: Mosaab Alzoubi \n" -"Language-Team: Evan Welsh \n" -"Language: ar_SY\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Lokalize 2.0\n" - -#: prefs.js:89 -msgid "default" -msgstr "الافتراضي" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "شفافية أنيقة لشريطك." - -#: prefs.ui:9 -msgid "Website" -msgstr "الموقع" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "إعادة تشغيل غنوم ضرورية." - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "يجب إعادة تشغيل غنوم لتأخذ التغييرات مجراها. هل ترغب بذلك الآن؟" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "سرعة التلاشي" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "أبطل 'gtk-enable-animations'." - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "التلاشيات" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "تفعيل اللون المخصص للنصوص" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "اللون الأساسي" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "اللون الثانوي" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "الاستعمال عند تكبير النافذة" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "الاستعمال في نمط الاستعراض" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "تفعيل ظل النص" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "لون الظل" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "نصف قطري" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "التوازن الأفقي" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "التوازن العمودي" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "تفعيل ظل الرمز" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "المقدمة" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "إلغاء الشفافية في حالة عدم التكبير" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "إلغاء الشفافية في حالة التكبير" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "تفعيل إلغاء شفافية مخصص" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "لون الشريط" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "تفعيل لون خاص للشريط" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "أزل زوائد نمط الشريط" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "(أصلح التكاملات مع السمة.)" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "أخف الزوايا" - -#: prefs.ui:1027 -msgid "Background" -msgstr "الخلفية" - -#: prefs.ui:1037 -msgid "About" -msgstr "حول" - -#~ msgid "App Tweaks" -#~ msgstr "تطويعات التطبيق" - -#~ msgid "Add a Custom WM_CLASS" -#~ msgstr "أضف WM_CLASS مخصصة" - -#~ msgid "Advanced..." -#~ msgstr "متقدم..." - -#~ msgid "" -#~ "A WM_CLASS is a code that identifies a window. Use this setting if the " -#~ "window you want custom settings for is not part of an application. You " -#~ "can find a window's WM_CLASS with the command 'xprop WM_CLASS'. Enter the " -#~ "second result from 'xprop WM_CLASS' below without quotation marks." -#~ msgstr "" -#~ "إن WM_CLASS هو شيفرة تعرّف النافذة. استعمل هذه الوحدات إذا أردت تنفيذ " -#~ "إعدادات مخصصة ليست جزءًا من التطبيق. بإمكانك العثور عليها من خلال تنفيذ " -#~ "الأمر xprop WM_CLASS وأدخل هنا النتيجة الثانية للأمر بدون علامات التنصيص." - -#~ msgid "WM_CLASS cannot be blank." -#~ msgstr "لا يمكن أن يكون WM_CLASS فارغًا." - -#~ msgid "Enable background app tweaks" -#~ msgstr "فعّل تطويعات الخلفية" - -#~ msgid "Theme Source" -#~ msgstr "مصدر السمة" - -#~ msgid "Always trigger the panel." -#~ msgstr "دومًا علّم الشريط." - -#~ msgid "Force animation" -#~ msgstr "إجبار التحريك" - -#~ msgid "Transition Style" -#~ msgstr "نمط التلاشي" - -#~ msgid "Linear (default)" -#~ msgstr "خطي (الافتراضي)" - -#~ msgid "Sine" -#~ msgstr "جيبي" - -#~ msgid "Quadratic" -#~ msgstr "تربيعي" - -#~ msgid "Cubic" -#~ msgstr "تكعيبي" - -#~ msgid "Quartic" -#~ msgstr "رباعي" - -#~ msgid "Quintic" -#~ msgstr "خماسي" - -#~ msgid "Exponential" -#~ msgstr "أسي" - -#~ msgid "Circle" -#~ msgstr "دائري" - -#~ msgid "Elastic" -#~ msgstr "متمدد" - -#~ msgid "Bounce" -#~ msgstr "ارتدادي" diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/de/LC_MESSAGES/dynamic-panel-transparency.mo b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/de/LC_MESSAGES/dynamic-panel-transparency.mo deleted file mode 100644 index f40fff8..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/de/LC_MESSAGES/dynamic-panel-transparency.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/de/LC_MESSAGES/dynamic-panel-transparency.po b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/de/LC_MESSAGES/dynamic-panel-transparency.po deleted file mode 100644 index c07e975..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/de/LC_MESSAGES/dynamic-panel-transparency.po +++ /dev/null @@ -1,235 +0,0 @@ -# Dynamic Panel Transparency Translation File -# Copyright (c) 2017 -# This file is distributed under the same license as the dynamic-panel-transparency package. -# -# Evan Welsh , 2017. -# Jonatan Hatakeyama Zeidler , 2016. -msgid "" -msgstr "" -"Project-Id-Version: Dynamic Panel Transparany GNOME Shell Extension\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:20-0700\n" -"PO-Revision-Date: 2016-09-19 20:09+0200\n" -"Last-Translator: Jonatan Hatakeyama Zeidler \n" -"Language-Team: Evan Welsh \n" -"Language: de\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.7.1\n" -"X-Poedit-SourceCharset: UTF-8\n" - -#: prefs.js:89 -msgid "default" -msgstr "Vorgabe" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "Elegante Transparenz für die obere Leiste." - -#: prefs.ui:9 -msgid "Website" -msgstr "Webseite" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "Neustart der GNOME Shell erforderlich." - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "" -"Ein Neustart der GNOME Shell ist erforderlich, um einige der Änderungen " -"anzuwenden. Die GNOME Shell jetzt neustarten?" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "Übergangszeit" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "Überschreibt 'gtk-enable-animations'." - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "Übergang" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "Angepasste Textfarbe aktivieren" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "Hauptfarbe" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "Zweitfarbe" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "Nutzen, wenn ein Fenster maximiert ist" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "Nutzen, wenn ein Fenster sichtbar ist" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "Textschatten aktivieren" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "Schattenfarbe" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "Radius" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "Horizontaler Versatz" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "Vertikaler Versatz" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "Symbolschatten aktivieren" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "Vordergrund" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "Deckkraft nicht maximiert" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "Deckkraft maximiert" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "Angepasste Deckkraft aktivieren" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "Hintergrundfarbe" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "Angepasste Hintergrundfarbe aktivieren" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "Entfernt übertriebene Gestaltung der oberen Leiste" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "(Behebt Themeninkompatibilitäten.)" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "Ecken deaktivieren" - -#: prefs.ui:1027 -msgid "Background" -msgstr "Hintergrund" - -#: prefs.ui:1037 -msgid "About" -msgstr "Info" - -#~ msgid "App Tweaks" -#~ msgstr "Anwendungsoptimierung" - -#~ msgid "Add a Custom WM_CLASS" -#~ msgstr "Angepasste WM_CLASS hinzufügen\t" - -#~ msgid "Advanced..." -#~ msgstr "Fortgeschritten …" - -#~ msgid "" -#~ "A WM_CLASS is a code that identifies a window. Use this setting if the " -#~ "window you want custom settings for is not part of an application. You " -#~ "can find a window's WM_CLASS with the command 'xprop WM_CLASS'. Enter the " -#~ "second result from 'xprop WM_CLASS' below without quotation marks." -#~ msgstr "" -#~ "Eine WM_CLASS ist ein Code zur Identifizierung von Fenstern. Diese " -#~ "Einstellung ist nützlich, wenn das Fenster nicht Teil einer gelisteten " -#~ "Anwendung ist. Die WM_CLASS eines Fensters kann mit dem Befehl 'xprop " -#~ "WM_CLASS' herausgefunden werden. Bitte den zweiten Treffer des Befehls " -#~ "hier eintragen (Ohne Anführungsstriche)." - -#~ msgid "WM_CLASS cannot be blank." -#~ msgstr "WM_CLASS darf nicht leer sein." - -#~ msgid "Enable background app tweaks" -#~ msgstr "Anwendungsoptimierung aktivieren" - -#~ msgid "Theme Source" -#~ msgstr "Themenquelle" - -#~ msgid "Always trigger the panel." -#~ msgstr "Obere Leiste immer anpassen" - -#~ msgid "Force animation" -#~ msgstr "Animation erzwingen" - -#~ msgid "Transition Style" -#~ msgstr "Übergangsstil" - -#~ msgid "Linear (default)" -#~ msgstr "Linear (Vorgabe)" - -#~ msgid "Sine" -#~ msgstr "Sinus\t" - -#~ msgid "Quadratic" -#~ msgstr "Quadratisch" - -#~ msgid "Cubic" -#~ msgstr "Kubisch" - -#~ msgid "Quartic" -#~ msgstr "Biquadratisch" - -#~ msgid "Quintic" -#~ msgstr "Polynom fünften Grades" - -#~ msgid "Exponential" -#~ msgstr "Exponentiell" - -#~ msgid "Circle" -#~ msgstr "Kreisförmig" - -#~ msgid "Elastic" -#~ msgstr "Elastisch" - -#~ msgid "Bounce" -#~ msgstr "Prellend" diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/es/LC_MESSAGES/dynamic-panel-transparency.mo b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/es/LC_MESSAGES/dynamic-panel-transparency.mo deleted file mode 100644 index 3e6b1e5..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/es/LC_MESSAGES/dynamic-panel-transparency.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/es/LC_MESSAGES/dynamic-panel-transparency.po b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/es/LC_MESSAGES/dynamic-panel-transparency.po deleted file mode 100644 index 7050698..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/es/LC_MESSAGES/dynamic-panel-transparency.po +++ /dev/null @@ -1,233 +0,0 @@ -# Dynamic Panel Transparency Translation File -# Copyright (c) 2017 -# This file is distributed under the same license as the dynamic-panel-transparency package. -# -# Evan Welsh , 2017. -# Alonso Lara , 2017. -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:20-0700\n" -"PO-Revision-Date: 2017-03-04 13:48+0100\n" -"Last-Translator: Alonso Lara \n" -"Language-Team: Evan Welsh \n" -"Language: es\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: prefs.js:89 -msgid "default" -msgstr "por defecto" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "Transparencia con clase para tu panel." - -#: prefs.ui:9 -msgid "Website" -msgstr "Sitio Web" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "Se requiere reiniciar la línea de comandos." - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "" -"Se requiere reiniciar la línea de comandos para ver algunos de sus cambios. " -"¿Desea reiniciar ahora?" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "Velocidad de transición" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "Sobreescribe 'gtk-enable-animations'." - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "Transiciones" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "Acticar color de texto personalizado" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "Color primario" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "Color secundario" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "Usar cuando una ventana está maximizada" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "Usar cuando la vista general está visible" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "Activar sombras de texto" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "Color de la sombra" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "Radio" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "Desplazamiento horizontal" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "Desplazamiento vertical" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "Activar sombras de iconos" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "Primer plano" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "Opacidad sin maximizado" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "Opacidad con maximizado" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "Activar opacidad personalizada" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "Color del panel" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "Activar color del panel personalizado" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "Eliminar estilo sobrante del panel" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "(Corrigue incompatibilidades del tema.)" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "Ocultar esquinas" - -#: prefs.ui:1027 -msgid "Background" -msgstr "Fondo" - -#: prefs.ui:1037 -msgid "About" -msgstr "Acerca de" - -#~ msgid "App Tweaks" -#~ msgstr "Ajustes" - -#~ msgid "Add a Custom WM_CLASS" -#~ msgstr "Añadir un WM_CLASS personalizado" - -#~ msgid "Advanced..." -#~ msgstr "Avanzado..." - -#~ msgid "" -#~ "A WM_CLASS is a code that identifies a window. Use this setting if the " -#~ "window you want custom settings for is not part of an application. You " -#~ "can find a window's WM_CLASS with the command 'xprop WM_CLASS'. Enter the " -#~ "second result from 'xprop WM_CLASS' below without quotation marks." -#~ msgstr "" -#~ "Un WM_CLASS es un código que identifica una ventana. Use este ajuste si " -#~ "la ventana que desea personalizar no es parte de una aplicación. Puede " -#~ "localizar el WM_CLASS de una ventana mediante el comando 'xprop " -#~ "WM_CLASS'. Introduzca el segundo resultado de 'xprop WM_CLASS' sin " -#~ "comillas." - -#~ msgid "WM_CLASS cannot be blank." -#~ msgstr "WM_CLASS no puede estar en blanco." - -#~ msgid "Enable background app tweaks" -#~ msgstr "Activar ajustes de la aplicación de fondo" - -#~ msgid "Theme Source" -#~ msgstr "Fuente del tema" - -#~ msgid "Always trigger the panel." -#~ msgstr "Desencadenar siempre el panel" - -#~ msgid "Force animation" -#~ msgstr "Forzar animación" - -#~ msgid "Transition Style" -#~ msgstr "Estilo de transición" - -#~ msgid "Linear (default)" -#~ msgstr "Lineal (por defecto)" - -#~ msgid "Sine" -#~ msgstr "Senoidal" - -#~ msgid "Quadratic" -#~ msgstr "Cuadrática" - -#~ msgid "Cubic" -#~ msgstr "Cúbica" - -#~ msgid "Quartic" -#~ msgstr "Cuártica" - -#~ msgid "Quintic" -#~ msgstr "Quíntica" - -#~ msgid "Exponential" -#~ msgstr "Exponencial" - -#~ msgid "Circle" -#~ msgstr "Circular" - -#~ msgid "Elastic" -#~ msgstr "Elástica" - -#~ msgid "Bounce" -#~ msgstr "Rebotar" diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/fr/LC_MESSAGES/dynamic-panel-transparency.mo b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/fr/LC_MESSAGES/dynamic-panel-transparency.mo deleted file mode 100644 index cb94a38..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/fr/LC_MESSAGES/dynamic-panel-transparency.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/fr/LC_MESSAGES/dynamic-panel-transparency.po b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/fr/LC_MESSAGES/dynamic-panel-transparency.po deleted file mode 100644 index 9bbcc03..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/fr/LC_MESSAGES/dynamic-panel-transparency.po +++ /dev/null @@ -1,208 +0,0 @@ -# Dynamic Panel Transparency Translation File -# Copyright (c) 2017 -# This file is distributed under the same license as the dynamic-panel-transparency package. -# -# Evan Welsh , 2017. -# narzb <>, 2016. -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:20-0700\n" -"PO-Revision-Date: 2016-10-27 23:39+0200\n" -"Last-Translator: narzb <>\n" -"Language-Team: Evan Welsh \n" -"Language: fr_FR\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.9\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: prefs.js:89 -msgid "default" -msgstr "défaut" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "Transparence élégante pour votre Barre supérieure." - -#: prefs.ui:9 -msgid "Website" -msgstr "Site web" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "Redémarrage du shell requis." - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "" -"Un redémarrage est nécessaire pour visualiser certains de vos changements. " -"Voulez-vous redémarrer maintenant ?" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "Vitesse de transition" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "Outrepasser 'gtk-enable-animations'." - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "Vitesse de transition" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "Activer personnalisation couleur du texte" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "Couleur Principale" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "Couleur secondaire" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "Utiliser quand la fenêtre est maximisée" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "Utiliser dans la Vue d'ensemble" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "Activer l'ombre du texte" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "Couleur de l'ombre" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "Rayon" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "Décalage horizontal" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "Décalage vertical" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "Activer l'ombre de l'icône" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "Premier plan" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "Opacité fenêtre non maximisée" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "Opacité fenêtre maximisée" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "Activer la personnalisation de l'opacité" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "Couleur Barre supérieure" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "Activer personnalisation couleur Barre supérieure" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "(Réparer les incompatibilités de thèmes.)" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "Cacher les coins arrondis" - -#: prefs.ui:1027 -msgid "Background" -msgstr "Arrière-plan" - -#: prefs.ui:1037 -msgid "About" -msgstr "À propos" - -#~ msgid "App Tweaks" -#~ msgstr "Réglages applications" - -#~ msgid "Add a Custom WM_CLASS" -#~ msgstr "Ajouter un WM_CLASS personnalisé" - -#~ msgid "Advanced..." -#~ msgstr "Fonctionnalités avancées" - -#~ msgid "" -#~ "A WM_CLASS is a code that identifies a window. Use this setting if the " -#~ "window you want custom settings for is not part of an application. You " -#~ "can find a window's WM_CLASS with the command 'xprop WM_CLASS'. Enter the " -#~ "second result from 'xprop WM_CLASS' below without quotation marks." -#~ msgstr "" -#~ "WM_CLASS est un code qui identifie une fenêtre. Utilisez ce paramètre si " -#~ "la fenêtre que vous voulez personnaliser ne fait pas partie d'une " -#~ "application. Vous pouvez trouver le WM_CLASS d'une fenêtre avec la " -#~ "commande «xprop WM_CLASS». Entrez le deuxième résultat de «xprop " -#~ "WM_CLASS» ci-dessous sans guillemets." - -#~ msgid "WM_CLASS cannot be blank." -#~ msgstr "WM_CLASS ne peut pas être vide." - -#~ msgid "Enable background app tweaks" -#~ msgstr "Activer les réglages d'applications en arrière plan" - -#~ msgid "Theme Source" -#~ msgstr "Source du Thème" - -#~ msgid "Always trigger the panel." -#~ msgstr "Toujours déclencher la coloration de la Barre supérieure" - -#~ msgid "Force animation" -#~ msgstr "Forcer l'animation" - -#~ msgid "Transition Style" -#~ msgstr "Style de transition" - -#~ msgid "Linear (default)" -#~ msgstr "Linéaire (défaut)" diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/pt_BR/LC_MESSAGES/dynamic-panel-transparency.mo b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/pt_BR/LC_MESSAGES/dynamic-panel-transparency.mo deleted file mode 100644 index 1f5c3f9..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/pt_BR/LC_MESSAGES/dynamic-panel-transparency.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/pt_BR/LC_MESSAGES/dynamic-panel-transparency.po b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/pt_BR/LC_MESSAGES/dynamic-panel-transparency.po deleted file mode 100644 index 71efd2a..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/pt_BR/LC_MESSAGES/dynamic-panel-transparency.po +++ /dev/null @@ -1,236 +0,0 @@ -# Dynamic Panel Transparency Translation File -# Copyright (c) 2017 -# This file is distributed under the same license as the dynamic-panel-transparency package. -# -# Evan Welsh , 2017. -# Fábio Nogueira , 2016. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:20-0700\n" -"PO-Revision-Date: 2016-09-29 15:09-0300\n" -"Last-Translator: Fábio Nogueira \n" -"Language-Team: Evan Welsh \n" -"Language: pt_BR\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.9\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" - -#: prefs.js:89 -msgid "default" -msgstr "padrão" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "Transparência elegante para o seu painel." - -#: prefs.ui:9 -msgid "Website" -msgstr "Site" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "É necessário reiniciar o shell." - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "" -"É necessário reiniciar o shell para visualizar algumas de suas alterações. " -"Gostaria de reiniciar agora?" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "Velocidade de transição" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "Substitui o 'gtk-enable-animations'." - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "Transição" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "Ativar coloração customizada do texto" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "Cor primária" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "Cor secundária" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "Utilizar quando um janela for maximizada" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "Utilizar quando a visão geral estiver visível" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "Habilitar sombras ao texto" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "Cor da sombra" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "Raio" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "Deslocamento horizontal" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "Deslocamento vertical" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "Habilitar sombreamento do ícone" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "Primeiro plano" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "Opacidade desmaximizada" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "Opacidade máxima" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "Habilitar opacidade customizada" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "Esquema de cores" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "Habilitar painel customizado de cores" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "Retirar o excesso de estilo do painel" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "(Consertar temas incompatíveis.)" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "Ocultar os cantos" - -#: prefs.ui:1027 -msgid "Background" -msgstr "Segundo plano" - -#: prefs.ui:1037 -msgid "About" -msgstr "Sobre" - -#~ msgid "App Tweaks" -#~ msgstr "Aplicativo de ajustes" - -#~ msgid "Add a Custom WM_CLASS" -#~ msgstr "Adicionar uma WM_CLASS customizada" - -#~ msgid "Advanced..." -#~ msgstr "Avançado..." - -#~ msgid "" -#~ "A WM_CLASS is a code that identifies a window. Use this setting if the " -#~ "window you want custom settings for is not part of an application. You " -#~ "can find a window's WM_CLASS with the command 'xprop WM_CLASS'. Enter the " -#~ "second result from 'xprop WM_CLASS' below without quotation marks." -#~ msgstr "" -#~ "Uma WM_CLASS é um código que identiifica uma janela. Utilize esta " -#~ "configuração se a janela que deseja configurar de forma personalizada não " -#~ "for parte de uma aplicação. Você pode encontrar uma WM_CLASS da janela " -#~ "com o comando 'xprop WM_CLASS'. Digite o segundo resultado de 'xprop " -#~ "WM_CLASS' abaixo sem as aspas." - -#~ msgid "WM_CLASS cannot be blank." -#~ msgstr "WM_CLASS não pode ser em branco." - -#~ msgid "Enable background app tweaks" -#~ msgstr "Habilitar o aplicativo de ajustes em segundo plano" - -#~ msgid "Theme Source" -#~ msgstr "Origem do tema" - -#~ msgid "Always trigger the panel." -#~ msgstr "Sempre acionar o painel." - -#~ msgid "Force animation" -#~ msgstr "Forçar animação" - -#~ msgid "Transition Style" -#~ msgstr "Estilo de transição" - -#~ msgid "Linear (default)" -#~ msgstr "Linear (padrão)" - -#~ msgid "Sine" -#~ msgstr "Seno" - -#~ msgid "Quadratic" -#~ msgstr "Ao quadrado" - -#~ msgid "Cubic" -#~ msgstr "Ao cubo" - -#~ msgid "Quartic" -#~ msgstr "Quarta potência" - -#~ msgid "Quintic" -#~ msgstr "Quinta potência" - -#~ msgid "Exponential" -#~ msgstr "Exponencial" - -#~ msgid "Circle" -#~ msgstr "Círculo" - -#~ msgid "Elastic" -#~ msgstr "Elástico" - -#~ msgid "Bounce" -#~ msgstr "Pulo" diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ru/LC_MESSAGES/dynamic-panel-transparency.mo b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ru/LC_MESSAGES/dynamic-panel-transparency.mo deleted file mode 100644 index e9b790d..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ru/LC_MESSAGES/dynamic-panel-transparency.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ru/LC_MESSAGES/dynamic-panel-transparency.po b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ru/LC_MESSAGES/dynamic-panel-transparency.po deleted file mode 100644 index 1bdccaa..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/ru/LC_MESSAGES/dynamic-panel-transparency.po +++ /dev/null @@ -1,177 +0,0 @@ -# Dynamic Panel Transparency Translation File -# Copyright (c) 2017 -# This file is distributed under the same license as the dynamic-panel-transparency package. -# -# Evan Welsh , 2017. -# Alexey Varfolomeev , 2016. -msgid "" -msgstr "" -"Project-Id-Version: GNOME Shell Extension Dynamic Panel Transparency\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:20-0700\n" -"PO-Revision-Date: 2016-03-07 12:21+0300\n" -"Last-Translator: Alexey Varfolomeev \n" -"Language-Team: Evan Welsh \n" -"Language: ru\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 1.8.7\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: prefs.js:89 -msgid "default" -msgstr "по-умолчанию" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "" - -#: prefs.ui:9 -msgid "Website" -msgstr "" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "" - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "Скорость перехода" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "Переопределение 'gtk-enable-animations'." - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "Скорость перехода" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "Цвет панели" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "Добавить тень для текста" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "Цвет панели" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "Максимум прозрачности" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "Максимум прозрачности" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "Цвет панели" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "Скрыть углы" - -#: prefs.ui:1027 -msgid "Background" -msgstr "" - -#: prefs.ui:1037 -msgid "About" -msgstr "" - -#~ msgid "Theme Source" -#~ msgstr "Исходная тема" - -#~ msgid "Force animation" -#~ msgstr "Принудительная анимация" - -#~ msgid "Transition Style" -#~ msgstr "Скорость перехода" - -#~ msgid "Linear (default)" -#~ msgstr "по-умолчанию" diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr/LC_MESSAGES/dynamic-panel-transparency.mo b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr/LC_MESSAGES/dynamic-panel-transparency.mo deleted file mode 100644 index e5bbec1..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr/LC_MESSAGES/dynamic-panel-transparency.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr/LC_MESSAGES/dynamic-panel-transparency.po b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr/LC_MESSAGES/dynamic-panel-transparency.po deleted file mode 100644 index d3655d3..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr/LC_MESSAGES/dynamic-panel-transparency.po +++ /dev/null @@ -1,196 +0,0 @@ -# Dynamic Panel Transparency Translation File -# Copyright (c) 2017 -# This file is distributed under the same license as the dynamic-panel-transparency package. -# -# Evan Welsh , 2017. -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:20-0700\n" -"PO-Revision-Date: 2017-11-18 20:00+0100\n" -"Last-Translator: Слободан Терзић \n" -"Language-Team: Evan Welsh \n" -"Language: sr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.4\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: prefs.js:89 -msgid "default" -msgstr "поразумевана" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "Елегантна транспарентност вашег панела." - -#: prefs.ui:9 -msgid "Website" -msgstr "Домаћа страница" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "Неопходно је поновно покретање шкољке" - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "Неопходно је поново покренути шкољку. Желите ли да то учиним одмах?" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "Брзина прелаза" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "Премошћује „gtk-enable-animations“." - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "Прелаз при прегледу" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "Прелаз када прозор дотакне панел" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "Прелази" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "Прилагођено бојење текста" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "Примарна боја" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "Секундарна боја" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "Када је прозор максимизован" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "Када је видљив преглед" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "Сенчење текста" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "Боја сенке" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "Радијус" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "Хоризонтално одступање" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "Вертикално одступање" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "Сенчење иконе" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "Први план" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "Непрозирност немаксимизованог" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "Непрозирност максимизованог" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "Прилагођена непрозирност" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "Боја панела" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "Прилагођена боја панела" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "Уклони прекомерно стилизовање панела" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "(поправља несагласности у теми)" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "Скривени ћошкови" - -#: prefs.ui:1027 -msgid "Background" -msgstr "Позадина" - -#: prefs.ui:1037 -msgid "About" -msgstr "О проширењу" - -#~ msgid "App Tweaks" -#~ msgstr "Штеловање апликација" - -#~ msgid "Add a Custom WM_CLASS" -#~ msgstr "Додај прилагођену WM_CLASS" - -#~ msgid "Advanced..." -#~ msgstr "Напредно..." - -#~ msgid "" -#~ "A WM_CLASS is a code that identifies a window. Use this setting if the " -#~ "window you want custom settings for is not part of an application. You " -#~ "can find a window's WM_CLASS with the command 'xprop WM_CLASS'. Enter the " -#~ "second result from 'xprop WM_CLASS' below without quotation marks." -#~ msgstr "" -#~ "WM_CLASS је код који идентификује прозор. Користите ово подешавање " -#~ "уколико прозор чију поставку желите није део апликације. WM_CLASS прозора " -#~ "можете добити командом „xprop WM_CLASS“. Унесите други резултат добијен " -#~ "том наредбом, без наводника." - -#~ msgid "WM_CLASS cannot be blank." -#~ msgstr "WM_CLASS не може бити празна." - -#~ msgid "Enable background app tweaks" -#~ msgstr "Укључи штеловање позадинске апликације" - -#~ msgid "Theme Source" -#~ msgstr "Основа теме" - -#~ msgid "Always trigger the panel." -#~ msgstr "Увек окини панел." diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr@latin/LC_MESSAGES/dynamic-panel-transparency.mo b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr@latin/LC_MESSAGES/dynamic-panel-transparency.mo deleted file mode 100644 index 7b08022..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr@latin/LC_MESSAGES/dynamic-panel-transparency.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr@latin/LC_MESSAGES/dynamic-panel-transparency.po b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr@latin/LC_MESSAGES/dynamic-panel-transparency.po deleted file mode 100644 index 80897c0..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/sr@latin/LC_MESSAGES/dynamic-panel-transparency.po +++ /dev/null @@ -1,196 +0,0 @@ -# Dynamic Panel Transparency Translation File -# Copyright (c) 2017 -# This file is distributed under the same license as the dynamic-panel-transparency package. -# -# Evan Welsh , 2017. -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:20-0700\n" -"PO-Revision-Date: 2017-11-18 20:01+0100\n" -"Last-Translator: Слободан Терзић \n" -"Language-Team: Evan Welsh \n" -"Language: sr\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.4\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" - -#: prefs.js:89 -msgid "default" -msgstr "porazumevana" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "Elegantna transparentnost vašeg panela." - -#: prefs.ui:9 -msgid "Website" -msgstr "Domaća stranica" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "Neophodno je ponovno pokretanje školjke" - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "Neophodno je ponovo pokrenuti školjku. Želite li da to učinim odmah?" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "Brzina prelaza" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "Premošćuje „gtk-enable-animations“." - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "Prelaz pri pregledu" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "Prelaz kada prozor dotakne panel" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "Prelazi" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "Prilagođeno bojenje teksta" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "Primarna boja" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "Sekundarna boja" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "Kada je prozor maksimizovan" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "Kada je vidljiv pregled" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "Senčenje teksta" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "Boja senke" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "Radijus" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "Horizontalno odstupanje" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "Vertikalno odstupanje" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "Senčenje ikone" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "Prvi plan" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "Neprozirnost nemaksimizovanog" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "Neprozirnost maksimizovanog" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "Prilagođena neprozirnost" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "Boja panela" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "Prilagođena boja panela" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "Ukloni prekomerno stilizovanje panela" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "(popravlja nesaglasnosti u temi)" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "Skriveni ćoškovi" - -#: prefs.ui:1027 -msgid "Background" -msgstr "Pozadina" - -#: prefs.ui:1037 -msgid "About" -msgstr "O proširenju" - -#~ msgid "App Tweaks" -#~ msgstr "Štelovanje aplikacija" - -#~ msgid "Add a Custom WM_CLASS" -#~ msgstr "Dodaj prilagođenu WM_CLASS" - -#~ msgid "Advanced..." -#~ msgstr "Napredno..." - -#~ msgid "" -#~ "A WM_CLASS is a code that identifies a window. Use this setting if the " -#~ "window you want custom settings for is not part of an application. You " -#~ "can find a window's WM_CLASS with the command 'xprop WM_CLASS'. Enter the " -#~ "second result from 'xprop WM_CLASS' below without quotation marks." -#~ msgstr "" -#~ "WM_CLASS je kod koji identifikuje prozor. Koristite ovo podešavanje " -#~ "ukoliko prozor čiju postavku želite nije deo aplikacije. WM_CLASS prozora " -#~ "možete dobiti komandom „xprop WM_CLASS“. Unesite drugi rezultat dobijen " -#~ "tom naredbom, bez navodnika." - -#~ msgid "WM_CLASS cannot be blank." -#~ msgstr "WM_CLASS ne može biti prazna." - -#~ msgid "Enable background app tweaks" -#~ msgstr "Uključi štelovanje pozadinske aplikacije" - -#~ msgid "Theme Source" -#~ msgstr "Osnova teme" - -#~ msgid "Always trigger the panel." -#~ msgstr "Uvek okini panel." diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/zh_CN/LC_MESSAGES/dynamic-panel-transparency.mo b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/zh_CN/LC_MESSAGES/dynamic-panel-transparency.mo deleted file mode 100644 index 053d127..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/zh_CN/LC_MESSAGES/dynamic-panel-transparency.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/zh_CN/LC_MESSAGES/dynamic-panel-transparency.po b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/zh_CN/LC_MESSAGES/dynamic-panel-transparency.po deleted file mode 100644 index 26fc0fb..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/locale/zh_CN/LC_MESSAGES/dynamic-panel-transparency.po +++ /dev/null @@ -1,232 +0,0 @@ -# Dynamic Panel Transparency Translation File -# Copyright (c) 2017 -# This file is distributed under the same license as the dynamic-panel-transparency package. -# -# Evan Welsh , 2017. -# Dingzhong Chen , 2016. -# -msgid "" -msgstr "" -"Project-Id-Version: \n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-04-03 11:20-0700\n" -"PO-Revision-Date: 2016-10-01 15:53+0800\n" -"Last-Translator: Dingzhong Chen \n" -"Language-Team: Chinese (China) \n" -"Language: zh_CN\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"X-Generator: Gtranslator 2.91.7\n" -"Plural-Forms: nplurals=1; plural=0;\n" - -#: prefs.js:89 -msgid "default" -msgstr "默认" - -#: prefs.ui:7 -msgid "Classy transparency for your panel." -msgstr "给你的面板加上优雅的透明感。" - -#: prefs.ui:9 -msgid "Website" -msgstr "网站" - -#: prefs.ui:72 -msgid "Shell Restart Required." -msgstr "需要重启 Shell。" - -#. Meant to ask the user if they would like to restart right now or later in a yes/no format. -#: prefs.ui:73 -msgid "" -"A shell restart is required to view some of your changes. Do you want to " -"restart now?" -msgstr "为了观看你的一些更改的效果需要重启 shell。想现在就重启吗?" - -#. How long the transition will take. -#: prefs.ui:134 -msgid "Transition Speed" -msgstr "切换速度" - -#: prefs.ui:160 prefs.ui:183 -msgid "Overrides 'gtk-enable-animations'." -msgstr "改写 'gtk-enable-animations'。" - -#. Whether the panel transitions should happen with the overview transitions or after. -#: prefs.ui:171 -msgid "Transition with the overview" -msgstr "" - -#. Whether the panel should transition when a window touches it or only when a window is actually maximized. -#: prefs.ui:194 -msgid "Transition when windows touch the panel" -msgstr "" - -#: prefs.ui:210 -msgid "Transitions" -msgstr "切换" - -#. Allows the user to set their own text color. -#: prefs.ui:257 -msgid "Enable custom text coloring" -msgstr "启用自定义文字颜色" - -#. The main color to be used. -#: prefs.ui:281 prefs.ui:294 -msgid "Primary Color" -msgstr "主色" - -#. Another color for special functions. -#: prefs.ui:307 prefs.ui:319 -msgid "Secondary Color" -msgstr "副色" - -#: prefs.ui:334 -msgid "Use when a window is maximized" -msgstr "窗口最大化时使用" - -#: prefs.ui:352 -msgid "Use when the overview is visible" -msgstr "概览视图时使用" - -#: prefs.ui:409 -msgid "Enable text shadowing" -msgstr "启用文字阴影" - -#: prefs.ui:442 prefs.ui:496 prefs.ui:609 prefs.ui:663 -msgid "Shadow Color" -msgstr "阴影颜色" - -#: prefs.ui:508 prefs.ui:675 -msgid "Radius" -msgstr "半径" - -#: prefs.ui:520 prefs.ui:687 -msgid "Horizontal Offset" -msgstr "水平偏移" - -#: prefs.ui:532 prefs.ui:699 -msgid "Vertical Offset" -msgstr "垂直偏移" - -#: prefs.ui:576 -msgid "Enable icon shadowing" -msgstr "启用图标阴影" - -#: prefs.ui:734 -msgid "Foreground" -msgstr "前景" - -#. Opacity of the panel when no window is maximized. -#: prefs.ui:785 -msgid "Unmaximized Opacity" -msgstr "非最大化的不透明度" - -#. Opacity of the panel when a window is maximized. -#: prefs.ui:829 -msgid "Maximized Opacity" -msgstr "最大化的不透明度" - -#. Allows the user to set their own opacity. -#: prefs.ui:850 -msgid "Enable custom opacity" -msgstr "启用自定义不透明度" - -#. The panel's background color. -#: prefs.ui:902 prefs.ui:915 -msgid "Panel Color" -msgstr "面板颜色" - -#. Allows the user to set their own background color for the panel. -#: prefs.ui:935 -msgid "Enable custom panel color" -msgstr "启用自定义面板颜色" - -#. Removes any extra styling certain themes may have. Fixes theme issues. -#: prefs.ui:983 -msgid "Remove excess panel styling" -msgstr "移除过度的面板修饰风格" - -#: prefs.ui:990 -msgid "(Fixes theme incompatibilities.)" -msgstr "(修复主题的不兼容性。)" - -#. Hides the panel corners. -#: prefs.ui:1008 -msgid "Hide corners" -msgstr "隐藏圆角" - -#: prefs.ui:1027 -msgid "Background" -msgstr "背景" - -#: prefs.ui:1037 -msgid "About" -msgstr "关于" - -#~ msgid "App Tweaks" -#~ msgstr "应用优化" - -#~ msgid "Add a Custom WM_CLASS" -#~ msgstr "添加自定义 WM_CLASS" - -#~ msgid "Advanced..." -#~ msgstr "高级…" - -#~ msgid "" -#~ "A WM_CLASS is a code that identifies a window. Use this setting if the " -#~ "window you want custom settings for is not part of an application. You " -#~ "can find a window's WM_CLASS with the command 'xprop WM_CLASS'. Enter the " -#~ "second result from 'xprop WM_CLASS' below without quotation marks." -#~ msgstr "" -#~ "WM_CLASS 是用于标识窗口的代码。使用此项设置,如果您想自定义设置的窗口不是" -#~ "应用程序的一部分。您可以用命令 'xprop WM_CLASS' 来查找窗口的 WM_CLASS。输" -#~ "入 'xprop WM_CLASS' 下面的第二个结果,不带引号。" - -#~ msgid "WM_CLASS cannot be blank." -#~ msgstr "WM_CLASS 无法为空。" - -#~ msgid "Enable background app tweaks" -#~ msgstr "启用后台应用优化" - -#~ msgid "Theme Source" -#~ msgstr "主题来源" - -#~ msgid "Always trigger the panel." -#~ msgstr "总是触发面板。" - -#~ msgid "Force animation" -#~ msgstr "强制动画" - -#~ msgid "Transition Style" -#~ msgstr "切换风格" - -#~ msgid "Linear (default)" -#~ msgstr "线性(默认)" - -#~ msgid "Sine" -#~ msgstr "正弦" - -#~ msgid "Quadratic" -#~ msgstr "平方" - -#~ msgid "Cubic" -#~ msgstr "立方" - -#~ msgid "Quartic" -#~ msgstr "四阶" - -#~ msgid "Quintic" -#~ msgstr "五阶" - -#~ msgid "Exponential" -#~ msgstr "指数" - -#~ msgid "Circle" -#~ msgstr "循环" - -#~ msgid "Elastic" -#~ msgstr "弹性" - -#~ msgid "Bounce" -#~ msgstr "跳动" diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/metadata.json b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/metadata.json deleted file mode 100644 index 22ebcf5..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/metadata.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Miss dynamic panel transparency in 3.32 and up? Try the original dynamic panel with much more customization! This extension will fade your top panel to nothingness when there are no maximized windows present! Never again will the panel be abruptly darkened.\n\nMay be incompatible with some extensions that make extensive changes to the panel.\n\nIf your theme isn't working correctly with this extension enable 'Remove Excessive Panel Styling' in the Background section of preferences. This particularly impacts the default *Ubuntu* theme!", - "gettext-domain": "dynamic-panel-transparency", - "name": "Dynamic Panel Transparency", - "settings-schema": "org.gnome.shell.extensions.dynamic-panel-transparency", - "shell-version": [ - "40" - ], - "url": "https://github.com/ewlsh/dynamic-panel-transparency/", - "uuid": "dynamic-panel-transparency@rockon999.github.io", - "version": 35 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/prefs.js b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/prefs.js deleted file mode 100644 index c65e454..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/prefs.js +++ /dev/null @@ -1,370 +0,0 @@ -/* exported init, buildPrefsWidget */ - -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gdk = imports.gi.Gdk; -const Gio = imports.gi.Gio; -const Gtk = imports.gi.Gtk; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); - -const Convenience = Me.imports.convenience; -const Util = Me.imports.util; - -const Gettext = imports.gettext.domain('dynamic-panel-transparency'); -const _ = Gettext.gettext; - -const gtk30_ = imports.gettext.domain('gtk30').gettext; - -/* Settings Keys */ -const SETTINGS_ENABLE_BACKGROUND_COLOR = 'enable-background-color'; -const SETTINGS_ENABLE_MAXIMIZED_TEXT_COLOR = 'enable-maximized-text-color'; -const SETTINGS_ENABLE_OPACITY = 'enable-opacity'; -const SETTINGS_ENABLE_OVERVIEW_TEXT_COLOR = 'enable-overview-text-color'; -const SETTINGS_ENABLE_TEXT_COLOR = 'enable-text-color'; -const SETTINGS_HIDE_CORNERS = 'hide-corners'; -const SETTINGS_ICON_SHADOW = 'icon-shadow'; -const SETTINGS_ICON_SHADOW_COLOR = 'icon-shadow-color'; -const SETTINGS_ICON_SHADOW_POSITION = 'icon-shadow-position'; -const SETTINGS_MAXIMIZED_OPACITY = 'maximized-opacity'; -const SETTINGS_MAXIMIZED_TEXT_COLOR = 'maximized-text-color'; -const SETTINGS_PANEL_COLOR = 'panel-color'; -const SETTINGS_REMOVE_PANEL_STYLING = 'remove-panel-styling'; -const SETTINGS_TEXT_COLOR = 'text-color'; -const SETTINGS_TEXT_SHADOW = 'text-shadow'; -const SETTINGS_TEXT_SHADOW_COLOR = 'text-shadow-color'; -const SETTINGS_TEXT_SHADOW_POSITION = 'text-shadow-position'; -const SETTINGS_TRANSITION_SPEED = 'transition-speed'; -const SETTINGS_TRANSITION_WITH_OVERVIEW = 'transition-with-overview'; -const SETTINGS_TRANSITION_WINDOWS_TOUCH = 'transition-windows-touch'; -const SETTINGS_UNMAXIMIZED_OPACITY = 'unmaximized-opacity'; - -const Page = { TRANSITIONS: 0, FOREGROUND: 1, BACKGROUND: 2, ABOUT: 3 }; -Object.freeze(Page); - -/* Color Array Indices */ -const RED = 0; -const GREEN = 1; -const BLUE = 2; -const ALPHA = 3; - -/* Shadow Positioning Indices */ -const HORIZONTAL_OFFSET = 0; -const VERTICAL_OFFSET = 1; -const BLUR_RADIUS = 2; - -/* UI spacing & similar values. */ -const WEBSITE_LABEL_BOTTOM_MARGIN = 50; -const WEBSITE_LABEL_TOP_MARGIN = 20; - -/* Color Scaling Factor (Byte to Decimal) */ -const SCALE_FACTOR = 255.9999999; - -function init() { - Convenience.initTranslations(); -} - -/* UI Setup */ -function buildPrefsWidget() { - /* Stores settings until the user applies them. */ - - /* Get Settings */ - let settings = Convenience.getSettings(); - /* Create a UI Builder */ - let builder = new Gtk.Builder(); - /* Setup Translation */ - builder.set_translation_domain(Me.metadata['gettext-domain']); - /* Get UI File */ - builder.add_from_file(Me.path + '/prefs.ui'); - - /* Main Widget (Grid) */ - let main_widget = builder.get_object('main_box'); - - { - /* Transition speed control */ - let speed_scale = builder.get_object('speed_scale'); - /* Init value. */ - speed_scale.adjustment.set_value(settings.get_int(SETTINGS_TRANSITION_SPEED)); - /* Add default marking. */ - speed_scale.add_mark(settings.get_default_value(SETTINGS_TRANSITION_SPEED).unpack(), Gtk.PositionType.BOTTOM, _("default")); - /* Add formatting */ - speed_scale.set_format_value_func((scale, value) => { - return value + 'ms'; - }); - speed_scale.connect('value-changed', (function(widget) { - settings.set_value(SETTINGS_TRANSITION_SPEED, new GLib.Variant('i', widget.adjustment.get_value())); - }).bind(this)); - - let transition_windows_touch = builder.get_object('transition_windows_touch_check'); - transition_windows_touch.set_active(settings.get_boolean(SETTINGS_TRANSITION_WINDOWS_TOUCH)); - - transition_windows_touch.connect('toggled', (function(widget) { - settings.set_value(SETTINGS_TRANSITION_WINDOWS_TOUCH, new GLib.Variant('b', widget.get_active())); - - }).bind(this)); - - let transition_with_overview = builder.get_object('transition_with_overview_check'); - transition_with_overview.set_active(settings.get_boolean(SETTINGS_TRANSITION_WITH_OVERVIEW)); - - transition_with_overview.connect('toggled', (function(widget) { - settings.set_value(SETTINGS_TRANSITION_WITH_OVERVIEW, new GLib.Variant('b', widget.get_active())); - - }).bind(this)); - } - - /* Setup foreground tab */ - { - let text_color_switch = builder.get_object('text_color_switch'); - let text_color_revealer = builder.get_object('text_color_revealer'); - - text_color_switch.set_active(settings.get_boolean(SETTINGS_ENABLE_TEXT_COLOR)); - text_color_switch.connect('state-set', (function(widget, state) { - settings.set_value(SETTINGS_ENABLE_TEXT_COLOR, new GLib.Variant('b', state)); - text_color_revealer.set_reveal_child(state); - - }).bind(this)); - - let maximized_text_color_switch = builder.get_object('maximized_text_color_check'); - maximized_text_color_switch.set_active(settings.get_boolean(SETTINGS_ENABLE_MAXIMIZED_TEXT_COLOR)); - - maximized_text_color_switch.connect('toggled', (function(widget) { - settings.set_value(SETTINGS_ENABLE_MAXIMIZED_TEXT_COLOR, new GLib.Variant('b', widget.get_active())); - }).bind(this)); - - let overview_text_color_switch = builder.get_object('overview_text_color_check'); - overview_text_color_switch.set_active(settings.get_boolean(SETTINGS_ENABLE_OVERVIEW_TEXT_COLOR)); - - overview_text_color_switch.connect('toggled', (function(widget) { - settings.set_value(SETTINGS_ENABLE_OVERVIEW_TEXT_COLOR, new GLib.Variant('b', widget.get_active())); - }).bind(this)); - - let remove_panel_styling_check = builder.get_object('remove_panel_styling_check'); - remove_panel_styling_check.set_active(settings.get_boolean(SETTINGS_REMOVE_PANEL_STYLING)); - - remove_panel_styling_check.connect('toggled', (function(widget) { - settings.set_value(SETTINGS_REMOVE_PANEL_STYLING, new GLib.Variant('b', widget.get_active())); - }).bind(this)); - - let maximized_text_color_btn = builder.get_object('maximized_text_color_btn'); - let maximized_text_color = settings.get_value(SETTINGS_MAXIMIZED_TEXT_COLOR).deep_unpack(); - - let css_color = 'rgba(' + maximized_text_color[RED] + ',' + maximized_text_color[GREEN] + ',' + maximized_text_color[BLUE] + ', 1.0)'; - let scaled_color = new Gdk.RGBA(); - - if (scaled_color.parse(css_color)) { - maximized_text_color_btn.set_rgba(scaled_color); - } - - maximized_text_color_btn.connect('color-set', (function(color_btn) { - let color = Util.gdk_to_css_color(color_btn.get_rgba()); - let rgb = [color.red, color.green, color.blue]; - - settings.set_value(SETTINGS_MAXIMIZED_TEXT_COLOR, new GLib.Variant('(iii)', rgb)); - }).bind(this)); - - let text_color_btn = builder.get_object('text_color_btn'); - let text_color = settings.get_value(SETTINGS_TEXT_COLOR).deep_unpack(); - - css_color = 'rgba(' + text_color[RED] + ',' + text_color[GREEN] + ',' + text_color[BLUE] + ', 1.0)'; - scaled_color = new Gdk.RGBA(); - - if (scaled_color.parse(css_color)) { - text_color_btn.set_rgba(scaled_color); - } - - text_color_btn.connect('color-set', (function(color_btn) { - let color = Util.gdk_to_css_color(color_btn.get_rgba()); - let rgb = [color.red, color.green, color.blue]; - - settings.set_value(SETTINGS_TEXT_COLOR, new GLib.Variant('(iii)', rgb)); - - }).bind(this)); - - let text_shadow_switch = builder.get_object('text_shadow_switch'); - let text_shadow_revealer = builder.get_object('text_shadow_revealer'); - - text_shadow_switch.set_active(settings.get_boolean(SETTINGS_TEXT_SHADOW)); - - text_shadow_switch.connect('state-set', (function(widget, state) { - settings.set_value(SETTINGS_TEXT_SHADOW, new GLib.Variant('b', state)); - text_shadow_revealer.set_reveal_child(state); - }).bind(this)); - - let text_shadow_vertical_offset = builder.get_object('text_shadow_vertical_offset'); - settings.set_value(SETTINGS_TEXT_SHADOW_POSITION, settings.get_value(SETTINGS_TEXT_SHADOW_POSITION)); - text_shadow_vertical_offset.set_value(settings.get_value(SETTINGS_TEXT_SHADOW_POSITION).deep_unpack()[VERTICAL_OFFSET]); - text_shadow_vertical_offset.connect('value-changed', (function(widget) { - let position = settings.get_value(SETTINGS_TEXT_SHADOW_POSITION).deep_unpack(); - position[VERTICAL_OFFSET] = widget.get_value_as_int(); - settings.set_value(SETTINGS_TEXT_SHADOW_POSITION, new GLib.Variant('(iii)', position)); - }).bind(this)); - - let text_shadow_horizontal_offset = builder.get_object('text_shadow_horizontal_offset'); - text_shadow_horizontal_offset.set_value(settings.get_value(SETTINGS_TEXT_SHADOW_POSITION).deep_unpack()[HORIZONTAL_OFFSET]); - text_shadow_horizontal_offset.connect('value-changed', (function(widget) { - let position = settings.get_value(SETTINGS_TEXT_SHADOW_POSITION).deep_unpack(); - position[HORIZONTAL_OFFSET] = widget.get_value_as_int(); - settings.set_value(SETTINGS_TEXT_SHADOW_POSITION, new GLib.Variant('(iii)', position)); - }).bind(this)); - - let text_shadow_radius = builder.get_object('text_shadow_radius'); - text_shadow_radius.set_value(settings.get_value(SETTINGS_TEXT_SHADOW_POSITION).deep_unpack()[BLUR_RADIUS]); - text_shadow_radius.connect('value-changed', (function(widget) { - let position = settings.get_value(SETTINGS_TEXT_SHADOW_POSITION).deep_unpack(); - position[BLUR_RADIUS] = widget.get_value_as_int(); - settings.set_value(SETTINGS_TEXT_SHADOW_POSITION, new GLib.Variant('(iii)', position)); - }).bind(this)); - - let text_shadow_color_btn = builder.get_object('text_shadow_color'); - text_shadow_color_btn.show_editor = true; - - let text_shadow_color = settings.get_value(SETTINGS_TEXT_SHADOW_COLOR).deep_unpack(); - - css_color = 'rgba(' + text_shadow_color[RED] + ',' + text_shadow_color[GREEN] + ',' + text_shadow_color[BLUE] + ',' + text_shadow_color[ALPHA].toFixed(2) + ')'; - scaled_color = new Gdk.RGBA(); - if (scaled_color.parse(css_color)) - text_shadow_color_btn.set_rgba(scaled_color); - - text_shadow_color_btn.connect('color-set', (function(color_btn) { - let color = Util.gdk_to_css_color(color_btn.get_rgba()); - let alpha = +(color_btn.get_rgba().alpha.toFixed(2)); - - let rgba = [color.red, color.green, color.blue, alpha]; - settings.set_value(SETTINGS_TEXT_SHADOW_COLOR, new GLib.Variant('(iiid)', rgba)); - }).bind(this)); - - let icon_shadow = builder.get_object('icon_shadow_switch'); - let icon_shadow_revealer = builder.get_object('icon_shadow_revealer'); - - icon_shadow.set_active(settings.get_boolean(SETTINGS_ICON_SHADOW)); - - icon_shadow.connect('state-set', (function(widget, state) { - settings.set_value(SETTINGS_ICON_SHADOW, new GLib.Variant('b', state)); - icon_shadow_revealer.set_reveal_child(state); - }).bind(this)); - - let icon_shadow_vertical_offset = builder.get_object('icon_shadow_vertical_offset'); - - settings.set_value(SETTINGS_ICON_SHADOW_POSITION, settings.get_value(SETTINGS_ICON_SHADOW_POSITION)); - icon_shadow_vertical_offset.set_value(settings.get_value(SETTINGS_ICON_SHADOW_POSITION).deep_unpack()[VERTICAL_OFFSET]); - icon_shadow_vertical_offset.connect('value-changed', (function(widget) { - let position = settings.get_value(SETTINGS_ICON_SHADOW_POSITION).deep_unpack(); - position[VERTICAL_OFFSET] = widget.get_value_as_int(); - settings.set_value(SETTINGS_ICON_SHADOW_POSITION, new GLib.Variant('(iii)', position)); - }).bind(this)); - let icon_shadow_horizontal_offset = builder.get_object('icon_shadow_horizontal_offset'); - icon_shadow_horizontal_offset.set_value(settings.get_value(SETTINGS_ICON_SHADOW_POSITION).deep_unpack()[HORIZONTAL_OFFSET]); - icon_shadow_horizontal_offset.connect('value-changed', (function(widget) { - let position = settings.get_value(SETTINGS_ICON_SHADOW_POSITION).deep_unpack(); - position[HORIZONTAL_OFFSET] = widget.get_value_as_int(); - settings.set_value(SETTINGS_ICON_SHADOW_POSITION, new GLib.Variant('(iii)', position)); - }).bind(this)); - let icon_shadow_radius = builder.get_object('icon_shadow_radius'); - icon_shadow_radius.set_value(settings.get_value(SETTINGS_ICON_SHADOW_POSITION).deep_unpack()[BLUR_RADIUS]); - icon_shadow_radius.connect('value-changed', (function(widget) { - let position = settings.get_value(SETTINGS_ICON_SHADOW_POSITION).deep_unpack(); - position[BLUR_RADIUS] = widget.get_value_as_int(); - settings.set_value(SETTINGS_ICON_SHADOW_POSITION, new GLib.Variant('(iii)', position)); - }).bind(this)); - - let icon_shadow_color_btn = builder.get_object('icon_shadow_color'); - icon_shadow_color_btn.show_editor = true; - - let icon_shadow_color = settings.get_value(SETTINGS_ICON_SHADOW_COLOR).deep_unpack(); - - css_color = 'rgba(' + icon_shadow_color[RED] + ',' + icon_shadow_color[GREEN] + ',' + icon_shadow_color[BLUE] + ',' + icon_shadow_color[ALPHA].toFixed(2) + ')'; - scaled_color = new Gdk.RGBA(); - if (scaled_color.parse(css_color)) { - icon_shadow_color_btn.set_rgba(scaled_color); - } - - icon_shadow_color_btn.connect('color-set', (function(color_btn) { - let color = Util.gdk_to_css_color(color_btn.get_rgba()); - let alpha = +(color_btn.get_rgba().alpha.toFixed(2)); - - let rgba = [color.red, color.green, color.blue, alpha]; - - settings.set_value(SETTINGS_ICON_SHADOW_COLOR, new GLib.Variant('(iiid)', rgba)); - }).bind(this)); - } - - /* Setup Background Tab */ - { - let background_color_switch = builder.get_object('background_color_switch'); - let opacity_switch = builder.get_object('opacity_switch'); - let background_color_revealer = builder.get_object('background_color_revealer'); - let opacity_revealer = builder.get_object('opacity_revealer'); - - background_color_switch.set_active(settings.get_boolean(SETTINGS_ENABLE_BACKGROUND_COLOR)); - background_color_switch.connect('state-set', (function(widget, state) { - settings.set_value(SETTINGS_ENABLE_BACKGROUND_COLOR, new GLib.Variant('b', state)); - background_color_revealer.set_reveal_child(state); - }).bind(this)); - - opacity_switch.set_active(settings.get_boolean(SETTINGS_ENABLE_OPACITY)); - opacity_switch.connect('state-set', (function(widget, state) { - settings.set_value(SETTINGS_ENABLE_OPACITY, new GLib.Variant('b', state)); - opacity_revealer.set_reveal_child(state); - - }).bind(this)); - - /* Maximum opacity control */ - let maximum_scale = builder.get_object('maximum_scale'); - /* Init value. */ - maximum_scale.adjustment.set_value(settings.get_int(SETTINGS_MAXIMIZED_OPACITY)); - /* Add formatting */ - maximum_scale.set_format_value_func((scale, value) => { - return (((value / SCALE_FACTOR) * 100).toFixed(0) + '%'); // eslint-disable-line no-magic-numbers - }); - maximum_scale.connect('value-changed', (function(widget) { - settings.set_value(SETTINGS_MAXIMIZED_OPACITY, new GLib.Variant('i', widget.adjustment.get_value())); - }).bind(this)); - - /* Minimum opacity control */ - let minimum_scale = builder.get_object('minimum_scale'); - /* Init value. */ - minimum_scale.adjustment.set_value(settings.get_int(SETTINGS_UNMAXIMIZED_OPACITY)); - /* Add formatting */ - minimum_scale.set_format_value_func((scale, value) => { - return ((value / SCALE_FACTOR) * 100).toFixed(0) + '%'; // eslint-disable-line no-magic-numbers - }); - minimum_scale.connect('value-changed', (function(widget) { - settings.set_value(SETTINGS_UNMAXIMIZED_OPACITY, new GLib.Variant('i', widget.adjustment.get_value())); - }).bind(this)); - - /* Convert & scale color. */ - let panel_color = settings.get_value(SETTINGS_PANEL_COLOR).deep_unpack(); - - let color_btn = builder.get_object('color_btn'); - let css_color = 'rgba(' + panel_color[RED] + ',' + panel_color[GREEN] + ',' + panel_color[BLUE] + ', 1.0)'; - - let scaled_color = new Gdk.RGBA(); - if (scaled_color.parse(css_color)) { - color_btn.set_rgba(scaled_color); - } - color_btn.connect('color-set', (function(color_btn) { - let color = Util.gdk_to_css_color(color_btn.get_rgba()); - let rgb = [color.red, color.green, color.blue]; - - settings.set_value(SETTINGS_PANEL_COLOR, new GLib.Variant('ai', rgb)); - }).bind(this)); - - let hide_corners = builder.get_object('hide_corners_check'); - hide_corners.set_active(settings.get_boolean(SETTINGS_HIDE_CORNERS)); - - hide_corners.connect('toggled', (function(widget) { - settings.set_value(SETTINGS_HIDE_CORNERS, new GLib.Variant('b', widget.get_active())); - }).bind(this)); - } - - let about_button = builder.get_object('about_button'); - let about_dialog = builder.get_object('about_dialog'); - about_dialog.set_version('v' + Me.metadata['version']); - about_button.connect('clicked', () => { - about_dialog.set_transient_for(main_widget.get_root()); - about_dialog.set_modal(true); - about_dialog.present(); - }); - - return main_widget; -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/prefs.ui b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/prefs.ui deleted file mode 100644 index b380149..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/prefs.ui +++ /dev/null @@ -1,1053 +0,0 @@ - - - - - Dynamic Panel Transparency - Version Unknown - Classy transparency for your panel. - https://github.com/ewlsh/dynamic-panel-transparency - Website - Evan Welsh (ewlsh) - Alexey Varfolomeev (varlesh) -Jonatan Hatakeyama Zeidler (jonnius) -Fábio Nogueira (frnogueira) -Mosaab Alzoubi (moceap) -Alonso Lara (AlonsoLP) -Dingzhong Chen (wsxy162) -narzb - - computer - gpl-2-0-only - - - 10 - 1 - 10 - - - 10 - 1 - 10 - - - 10 - 1 - 10 - - - 10 - 1 - 10 - - - 100 - 1 - 10 - - - 10 - 1 - 10 - - - 10 - 1 - 10 - - - - 255 - 1 - 10 - - - 255 - 1 - 10 - - - 0 - question - yes-no - Shell Restart Required. - A shell restart is required to view some of your changes. Do you want to restart now? - 1 - - - 0 - 0 - vertical - 2 - - - - - 5000 - 1 - 10 - - - 10 - 1 - 10 - - - 10 - 1 - 10 - - - 10 - 1 - 10 - - - 0 - vertical - - - 5 - 5 - 5 - 5 - - - - - 0 - - 5 - 5 - 5 - 5 - 5 - 5 - 1 - - - 0 - start - 5 - 5 - 5 - 5 - Transition Speed - 1 - - 0 - 0 - - - - - - 1 - 5 - 5 - 5 - 5 - 1 - speed_adjustment - 0 - - 1 - 0 - - - - - - Overrides 'gtk-enable-animations'. - start - - 5 - 5 - 5 - 5 - - - 0 - 3 - Transition with the overview - - - - 0 - 2 - 2 - - - - - - Overrides 'gtk-enable-animations'. - start - - 5 - 5 - 5 - 5 - - - 0 - 3 - Transition when windows touch the panel - - - - 0 - 1 - 2 - - - - - - - - 0 - 1 - Transitions - - - - - - - 1 - - - 0 - 20 - 20 - 20 - 20 - 1 - 5 - 10 - - - 0 - 1 - 0.029999999329447746 - - - 20 - 20 - 20 - 20 - 0 - 1 - 10 - 1 - - - end - - 1 - 0 - - - - - - 0 - start - - Enable custom text coloring - 1 - - 0 - 0 - - - - - - 0 - 1 - - - 0 - 5 - 5 - 5 - - - 0 - start - - 1 - Primary Color - 1 - - 0 - 0 - - - - - - 1 - end - 1 - Primary Color - - 1 - 0 - - - - - - 0 - start - - 1 - Secondary Color - - 0 - 1 - - - - - - 1 - end - 1 - Secondary Color - - 1 - 1 - - - - - - start - - - - 0 - 3 - Use when a window is maximized - - - - 0 - 2 - 2 - - - - - - start - - - - 0 - 3 - Use when the overview is visible - - - - 0 - 3 - 2 - - - - - - - 0 - 1 - 2 - - - - - - - - - - 0 - 0 - - - - - - 0 - 10 - 1 - 10 - - - 0 - - 1 - 0.05999999865889549 - - - 20 - 20 - 20 - 20 - 0 - 1 - 10 - 1 - - - 0 - start - - Enable text shadowing - - 0 - 0 - - - - - - end - - 1 - 0 - - - - - - 0 - 1 - - - 0 - 10 - 5 - 10 - 10 - 1 - 1 - - - 1 - end - Shadow Color - - 1 - 3 - - - - - - end - - 0 - text_radius_adjustment - 1 - 1 - - 1 - 2 - - - - - - end - - 0 - text_shadow_hz_adjustment - 1 - 1 - - 1 - 1 - - - - - - end - - 0 - text_shadow_vrt_adjustment - 1 - 1 - - 1 - 0 - - - - - - 0 - start - - Shadow Color - - 0 - 3 - - - - - - 0 - start - - Radius - - 0 - 2 - - - - - - 0 - start - - Horizontal Offset - - 0 - 1 - - - - - - 0 - start - - Vertical Offset - - 0 - 0 - - - - - - - 0 - 1 - 2 - - - - - - - - - - - - - 0 - - 1 - 0.05999999865889549 - - - 20 - 20 - 20 - 20 - 0 - 1 - 10 - 1 - - - 0 - start - - Enable icon shadowing - - 0 - 0 - - - - - - end - - 1 - 0 - - - - - - 0 - 1 - - - 0 - 10 - 5 - 10 - 10 - 1 - 1 - - - 1 - end - Shadow Color - - 1 - 3 - - - - - - end - - 0 - adjustment1 - 1 - 1 - - 1 - 2 - - - - - - end - - 0 - adjustment6 - 1 - 1 - - 1 - 1 - - - - - - end - - 0 - adjustment7 - 1 - 1 - - 1 - 0 - - - - - - 0 - start - - Shadow Color - - 0 - 3 - - - - - - 0 - start - - Radius - - 0 - 2 - - - - - - 0 - start - - Horizontal Offset - - 0 - 1 - - - - - - 0 - start - - Vertical Offset - - 0 - 0 - - - - - - - 0 - 1 - 2 - - - - - - - - - - - - 0 - 1 - - - - - - - - 0 - 1 - Foreground - - - - - - - 2 - - - 0 - 20 - 20 - 20 - 20 - 20 - 20 - vertical - - - 0 - 1 - 5 - 10 - - - 0 - 5 - 1 - - - 20 - 20 - 20 - 20 - 0 - - - 0 - 1 - 1 - - - 0 - 10 - - - 0 - start - 5 - 5 - Unmaximized Opacity - 1 - - 0 - 1 - - - - - - 1 - 5 - 5 - 12 - 1 - maximum_opacity_adjustment - 1 - - 1 - 0 - - - - - - 1 - 5 - 5 - 12 - 1 - minimum_opacity_adjustment - 1 - - 1 - 1 - - - - - - 0 - start - 5 - 5 - Maximized Opacity - 1 - - 0 - 0 - - - - - - - 0 - 1 - 2 - - - - - - 0 - start - Enable custom opacity - - 0 - 0 - - - - - - end - - 1 - 0 - - - - - - - - - - 0 - 0 - - - - - - 0 - 5 - 1 - - - 20 - 20 - 20 - 20 - 0 - - - 0 - 1 - 1 - - - 0 - - - 0 - start - 1 - Panel Color - 1 - - 0 - 0 - - - - - - 1 - end - 5 - Panel Color - - 1 - 0 - - - - - - - 0 - 1 - 2 - - - - - - 0 - start - Enable custom panel color - - 0 - 0 - - - - - - end - - 1 - 0 - - - - - - - - - - 0 - 1 - - - - - - - - 0 - start - 10 - 5 - 1 - 5 - 1 - 1 - - - - - 0 - 5 - - - 0 - Remove excess panel styling - 1 - - - - - 0 - (Fixes theme incompatibilities.) - - - - - - 0 - 0 - - - - - - start - - - 0 - 3 - Hide corners - 1 - - - - 0 - 1 - - - - - - - - - - xs - 0 - 1 - Background - - - - - - - - - end - About - 5 - 5 - 5 - 5 - - - - - - - - 100 - 1 - 10 - - diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/schemas/gschemas.compiled b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/schemas/gschemas.compiled deleted file mode 100644 index 71ad29d..0000000 Binary files a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/schemas/gschemas.compiled and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/schemas/org.gnome.shell.extensions.dynamic-panel-transparency.gschema.xml b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/schemas/org.gnome.shell.extensions.dynamic-panel-transparency.gschema.xml deleted file mode 100644 index 6a532e4..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/schemas/org.gnome.shell.extensions.dynamic-panel-transparency.gschema.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - 1000 - Transition Speed - How fast the panel fades in and out. - - - 255 - Maximized Opacity - The opacity of the panel when there are maximized windows [0-255]. - - - 0 - Unmaximized Opacity - The opacity of the panel when there are no maximized windows [0-255]. - - - true - Hide Corners - Hides the rounded corners of the panel. (improves fade aesthetic) - - - false - Force Animation - Overrides 'gtk-enable-animations' on installations where animations are disabled. - - - [0,0,0] - Panel Color - The background color of the panel. - - - false - Enable custom opacities - Whether to enable custom opacities or use the theme values. - - - false - Enable custom background color - Whether to enable custom coloring or use the theme value. - - - false - Add shadowing to text - Adds a shadowing effect to make the panel's text readable on light backgrounds. - - - false - Add shadowing to icons - Adds a shadowing effect to make the panel's icons visible on light backgrounds. - - - (0,3,5) - Text shadow position - The position of the text shadow. (h-offset, v-offset, radius) - - - (0,2,5) - Icon shadow position - The position of the icon shadow. (h-offset, v-offset, radius) - - - (0,0,0,0.5) - Color of shadowing for icons. - The color of the icon shadow. (red, green, blue, alpha) - - - (0,0,0,1.0) - Color of shadowing for text. - The color of the text shadow. (red, green, blue, alpha) - - - (255,255,255) - What color the panel text should be. - What color the panel text should be. - - - (255,255,255) - What color the maximized panel text should be. - What color the panel text should be when windows are maximized - - - false - Enable custom text color - Whether to enable custom primary text coloring or use the user's theme values. - - - false - Enable custom maximized text color - Whether to enable custom secondary text coloring when a window is maximized or not. - - - false - Enable custom overview text color - Whether to enable secondary custom text coloring when the overview is visible. - - - false - Remove incompatible theming - Whether certain usually incompatible theme styles should be removed. - - - 1 - Transition type - The transition function used on the panel - - - true - Transition with overview - Transition the panel at the same time as the overview - - - true - Transition when windows touch the panel - Transition when windows touch the panel - - - \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/settings.js b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/settings.js deleted file mode 100644 index 6360dc8..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/settings.js +++ /dev/null @@ -1,269 +0,0 @@ -/* exported init, cleanup, add, bind, unbind */ - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Params = imports.misc.params; - -const Convenience = Me.imports.convenience; -const Intellifade = Me.imports.intellifade; - -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; - -/* This might impair visibility of the code, but it makes my life a thousand times simpler */ -/* settings.js takes a key and watches for it to change in Gio.Settings & creates a getter for it. */ -/* Also can parse, handle, etc. a setting. */ - -const OVERRIDES_SCHEMA_ID = 'org.gnome.shell.extensions.dynamic-panel-transparency.appOverrides'; - -const GNOME_BACKGROUND_SCHEMA = 'org.gnome.desktop.wm.keybindings'; -const SETTINGS_SHOW_DESKTOP = 'show-desktop'; - -const GNOME_INTERFACE_SCHEMA = 'org.gnome.desktop.interface'; -const SETTINGS_ENABLE_ANIMATIONS = 'enable-animations'; - -function init() { - this._settings = Convenience.getSettings(); - this._background_settings = null; - this._interface_settings = null; - - /* Setup background settings. */ - - try { - let schemaObj = Convenience.getSchemaObj(GNOME_BACKGROUND_SCHEMA, true); - - if (schemaObj) { - this._background_settings = new Gio.Settings({ - settings_schema: schemaObj - }); - } - } catch (error) { } // eslint-disable-line - - try { - let schemaObj = Convenience.getSchemaObj(GNOME_INTERFACE_SCHEMA, true); - - if (schemaObj) { - this._interface_settings = new Gio.Settings({ - settings_schema: schemaObj - }); - } - } catch (error) { } // eslint-disable-line - - this._keys = []; - this._app_keys = {}; - this._overriden_keys = []; - - this.settingsBoundIds = []; - - this._show_desktop = null; - - if (this._background_settings) { - this._show_desktop = this._background_settings.get_strv(SETTINGS_SHOW_DESKTOP).length > 0; - - this.settingsBoundIds.push(this._background_settings.connect('changed::' + SETTINGS_SHOW_DESKTOP, (function() { - this._show_desktop = this._background_settings.get_strv(SETTINGS_SHOW_DESKTOP).length > 0; - }).bind(this))); - } - - if (this._interface_settings) { - this._enable_animations = this._interface_settings.get_boolean(SETTINGS_ENABLE_ANIMATIONS); - - this.settingsBoundIds.push(this._interface_settings.connect('changed::' + SETTINGS_ENABLE_ANIMATIONS, (function() { - this._enable_animations = this._interface_settings.get_boolean(SETTINGS_ENABLE_ANIMATIONS); - }).bind(this))); - } - - this.gs_show_desktop = function() { - return this._show_desktop; - }; - - this.gs_enable_animations = function() { - return this._enable_animations; - }; -} - -function cleanup() { - for (let i = 0; i < this._keys.length; ++i) { - let setting = this._keys[i]; - if (!setting.getter) { - this['get_' + setting.name] = null; - } else { - this[setting.getter] = null; - } - } - - this._keys = null; - this.settingsBoundIds = null; - this._settings = null; -} - -/* Settings Management */ -function add(params) { - let key = { - key: params.key, - name: params.name, - type: params.type, - parser: null, - getter: null, - handler: null - }; - - if (typeof (params.getter) !== 'undefined') - key.getter = params.getter; - if (typeof (params.handler) !== 'undefined') - key.handler = params.handler; - if (typeof (params.parser) !== 'undefined') - key.parser = params.parser; - - this._keys.push(key); -} - -function bind() { - this.settings_manager = new SettingsManager(this._settings, this._keys); - - for (let i = 0; i < this._keys.length; ++i) { - let setting = this._keys[i]; - - /* Watch for changes */ - this.settingsBoundIds.push(this._settings.connect('changed::' + setting.key, (function() { - this.settings_manager.update(setting); - }).bind(this))); - - if (setting.handler) { - this.settingsBoundIds.push(this._settings.connect('changed::' + setting.key, function() { - // TODO: Find a better way to handle settings being changed right as the extension starts up. - try { - setting.handler.call(this); - } catch (error) { - log('[Dynamic Panel Transparency] Error handling setting (' + setting.key + ') change.'); - log(error); - } - })); - } - - let parser = (setting.parser !== null ? setting.parser : function(input) { - return input; - }); - - let getter = function() { - return parser(this.settings_manager[setting.name]); - }; - - if (!setting.getter) { - this['get_' + setting.name] = getter; - } else { - this[setting.getter] = getter; - } - } -} - -function unbind() { - for (let i = 0; i < this.settingsBoundIds.length; ++i) { - this._settings.disconnect(this.settingsBoundIds[i]); - } -} - -/* Basic class to hold settings values */ -class SettingsManager { - constructor(settings, params) { - - this.values = []; - this.settings = settings; - - for (let i = 0; i < params.length; ++i) { - let setting = params[i]; - this.values.push(setting); - if (this.settings.list_keys().indexOf(setting.key) === -1 || !setting) - continue; - let variant = GLib.VariantType.new(setting.type); - if (variant.is_array() || variant.is_tuple()) { - this[setting.name] = this.settings.get_value(setting.key).deep_unpack(); - } else { - this[setting.name] = this.settings.get_value(setting.key).unpack(); - } - } - } - - update(setting) { - if (this.settings.list_keys().indexOf(setting.key) === -1) - return; - - let variant = GLib.VariantType.new(setting.type); - - if (variant.is_array() || variant.is_tuple()) { - this[setting.name] = this.settings.get_value(setting.key).deep_unpack(); - } else { - this[setting.name] = this.settings.get_value(setting.key).unpack(); - } - } -} - -class AppSettingsManager { - constructor(params, apps, path) { - this.values = []; - this.settings = {}; - this.settingsBoundIds = {}; - - for (let setting_key of Object.keys(params)) { - let setting = params[setting_key]; - this[setting.name] = {}; - - this.values.push(setting); - } - - for (let a = 0; a < apps.length; ++a) { - let app_id = apps[a]; - let app_path = path + app_id + '/'; - let sett = null; - - let obj = Convenience.getSchemaObj(OVERRIDES_SCHEMA_ID); - sett = new Gio.Settings({ path: app_path, settings_schema: obj }); - - this.settings[app_id] = sett; - - for (let setting_key of Object.keys(params)) { - let setting = params[setting_key]; - - if (!setting || this.settings[app_id].list_keys().indexOf(setting.key) === -1) { - continue; - } - - if (!this.settingsBoundIds[app_id]) { - this.settingsBoundIds[app_id] = []; - } - - this.settingsBoundIds[app_id].push(this.settings[app_id].connect('changed::' + setting.key, (function() { - this.update(setting, app_id); - }).bind(this))); - - let variant = GLib.VariantType.new(setting.type); - - if (variant.is_array() || variant.is_tuple()) { - this[setting.name][app_id] = this.settings[app_id].get_value(setting.key).deep_unpack(); - } else { - this[setting.name][app_id] = this.settings[app_id].get_value(setting.key).unpack(); - } - } - } - } - - update(setting, app_id) { - if (!setting || this.settings[app_id].list_keys().indexOf(setting.key) === -1) - return; - let variant = GLib.VariantType.new(setting.type); - if (!this[setting.name]) - this[setting.name] = {}; - if (variant.is_array() || variant.is_tuple()) { - this[setting.name][app_id] = this.settings[app_id].get_value(setting.key).deep_unpack(); - } else { - this[setting.name][app_id] = this.settings[app_id].get_value(setting.key).unpack(); - } - } - - unbind() { - for (let app_id of Object.keys(this.settings)) { - for (let id of this.settingsBoundIds[app_id]) { - this.settings[app_id].disconnect(id); - } - } - } -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/background/panel-custom.dpt.css b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/background/panel-custom.dpt.css deleted file mode 100644 index 78c4946..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/background/panel-custom.dpt.css +++ /dev/null @@ -1,2 +0,0 @@ -.dpt-panel-custom-unmaximized { background-color: rgba(36, 31, 49, 0.12); } -.dpt-panel-custom-maximized { background-color: rgba(36, 31, 49, 0.35); } \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/background/panel.dpt.css b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/background/panel.dpt.css deleted file mode 100644 index 8ddcde9..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/background/panel.dpt.css +++ /dev/null @@ -1,2 +0,0 @@ -.dpt-panel-unmaximized { background-color: rgba(0, 0, 0, 0.12); } -.dpt-panel-maximized { background-color: rgba(0, 0, 0, 0.35); } \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-icon-shadow.dpt.css b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-icon-shadow.dpt.css deleted file mode 100644 index 385c12f..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-icon-shadow.dpt.css +++ /dev/null @@ -1,2 +0,0 @@ -.dpt-panel-icon-shadow .system-status-icon { icon-shadow: 0px 2px 5px rgba(0, 0, 0, 0.50); } -.dpt-panel-arrow-shadow .popup-menu-arrow { icon-shadow: 0px 2px 5px rgba(0, 0, 0, 0.50); } \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-maximized-text-color.dpt.css b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-maximized-text-color.dpt.css deleted file mode 100644 index 53aa225..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-maximized-text-color.dpt.css +++ /dev/null @@ -1,3 +0,0 @@ -.dpt-panel-maximized-text-color .panel-button { color: rgb(255, 255, 255); } -.dpt-panel-maximized-icon-color .system-status-icon { color: rgb(255, 255, 255); } -.dpt-panel-maximized-arrow-color .popup-menu-arrow { color: rgb(255, 255, 255); } \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-text-color.dpt.css b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-text-color.dpt.css deleted file mode 100644 index a968f40..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-text-color.dpt.css +++ /dev/null @@ -1,3 +0,0 @@ -.dpt-panel-text-color .panel-button { color: rgb(255, 255, 255); } -.dpt-panel-icon-color .system-status-icon { color: rgb(255, 255, 255); } -.dpt-panel-arrow-color .popup-menu-arrow { color: rgb(255, 255, 255); } \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-text-shadow.dpt.css b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-text-shadow.dpt.css deleted file mode 100644 index 74b2b10..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/foreground/panel-text-shadow.dpt.css +++ /dev/null @@ -1 +0,0 @@ -.dpt-panel-text-shadow .panel-button { text-shadow: 0px 3px 5px rgba(0, 0, 0, 1.00); } \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/transitions/panel-transition-duration.dpt.css b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/transitions/panel-transition-duration.dpt.css deleted file mode 100644 index e2f6b67..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/styles/transitions/panel-transition-duration.dpt.css +++ /dev/null @@ -1 +0,0 @@ -.dpt-panel-transition-duration { transition-duration: 1000ms; } \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/stylesheet.css b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/stylesheet.css deleted file mode 100644 index 702169d..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/stylesheet.css +++ /dev/null @@ -1,22 +0,0 @@ -/* Used to remove odd effects when full transparency is needed. */ - -.panel-transparency { - background-color: rgba(0, 0, 0, 0); -} - -.panel-effect-transparency { - box-shadow: none; - border: none; - /* Gnome Shell specific CSS */ - background-gradient-direction: none; - background-gradient-start: none; - background-gradient-end: none; -} - -/* Used to remove backgrounds when full transparency is needed. */ - -.panel-background-image-transparency { - border-image: none; - background-image: none; -} - diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/theming.js b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/theming.js deleted file mode 100644 index ef88d6e..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/theming.js +++ /dev/null @@ -1,505 +0,0 @@ -/* exported init, cleanup, remove_maximized_background_color, remove_unmaximized_background_color, set_maximized_background_color, set_unmaximized_background_color, remove_background_color, register_text_shadow, add_text_shadow, register_icon_shadow, add_icon_shadow, has_text_shadow, has_icon_shadow, remove_text_shadow, remove_icon_shadow, register_text_color, set_text_color, remove_text_color, set_panel_color, set_corner_color, clear_corner_color, get_background_image_color, get_background_color, get_maximized_opacity, get_unmaximized_opacity, strip_panel_styling, reapply_panel_styling, strip_panel_background_image, reapply_panel_background_image, strip_panel_background, reapply_panel_background, set_background_alpha */ - -const St = imports.gi.St; - -const Main = imports.ui.main; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Params = imports.misc.params; - -const Settings = Me.imports.settings; -const Util = Me.imports.util; - -const GdkPixbuf = imports.gi.GdkPixbuf; -const GLib = imports.gi.GLib; - -/* Convenience constant for the shell panel. */ -const Panel = Main.panel; - -/* Constants for theme opacity detection. */ -const THEME_OPACITY_THRESHOLD = 50; - -/* Constants for color averaging. */ -const SATURATION_WEIGHT = 1.5; -const WEIGHT_THRESHOLD = 1.0; -const ALPHA_THRESHOLD = 24; - -/* Scale factor for color conversion. */ -const SCALE_FACTOR = 255.9999999; - -/** - * @typedef {Object} Color - Represents a standard color object - * @property {number} red - Red value ranging from 0-255. - * @property {number} green - Green value ranging from 0-255. - * @property {number} blue - Blue value ranging from 0-255. - * @property {number} [alpha=1.0] - Alpha value ranging from 0-1.0 with support for two decimal places. - */ - -/** - * Intialize. - * - */ -function init() { - this.stylesheets = []; - this.styles = []; - - this.background_styles = []; - - update_transition_css(); -} - -/** - * Used to release any held assets of theming. - * - */ -function cleanup() { - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - for (let style of this.styles) { - Panel.remove_style_class_name(style); - } - - for (let style of this.background_styles) { - Panel.remove_style_class_name(style); - } - - for (let sheet of this.stylesheets) { - theme.unload_stylesheet(Util.get_file(sheet)); - Util.remove_file(sheet); - } - - this.background_styles = null; - this.stylesheets = null; - this.styles = null; -} - -/** - * Registers a shadow stylesheet for text in the panel. - * - * @param {Color} text_color - Object representing an RGBA color. - * @param {Number[]} text_position - Integer array containing horizontal offset, vertical offset, radius. (in that order) - */ -function register_text_shadow(text_color, text_position) { - let text_color_css = 'rgba(' + text_color.red + ', ' + text_color.green + ', ' + text_color.blue + ', ' + text_color.alpha.toFixed(2) + ')'; - let text_position_css = '' + text_position[0] + 'px ' + text_position[1] + 'px ' + text_position[2] + 'px'; - - register_style('dpt-panel-text-shadow'); - - return apply_stylesheet_css('.dpt-panel-text-shadow .panel-button { text-shadow: ' + text_position_css + ' ' + text_color_css + '; }', 'foreground/panel-text-shadow'); -} - -/** - * Adds the currently registered shadow stylesheet to the text in the panel. - * - * @param {Color} text_color - Object representing an RGBA color. - * @param {Number[]} text_position - Integer array containing horizontal offset, vertical offset, radius. (in that order) - */ -function add_text_shadow() { - Panel.add_style_class_name('dpt-panel-text-shadow'); -} - -/** - * Register a shadow stylesheet for icons in the panel. - * - * @param {Color} icon_color - Object representing an RGBA color. - * @param {Number[]} icon_position - Integer array containing horizontal offset, vertical offset, radius. (in that order) - */ -function register_icon_shadow(icon_color, icon_position) { - let icon_color_css = 'rgba(' + icon_color.red + ', ' + icon_color.green + ', ' + icon_color.blue + ', ' + icon_color.alpha.toFixed(2) + ')'; - let icon_position_css = '' + icon_position[0] + 'px ' + icon_position[1] + 'px ' + icon_position[2] + 'px'; - - let stylesheet = apply_stylesheet_css('.dpt-panel-icon-shadow .system-status-icon { icon-shadow: ' + icon_position_css + ' ' + icon_color_css + '; }\n.dpt-panel-arrow-shadow .popup-menu-arrow { icon-shadow: ' + icon_position_css + ' ' + icon_color_css + '; }', 'foreground/panel-icon-shadow'); - - register_style('dpt-panel-icon-shadow'); - register_style('dpt-panel-arrow-shadow'); - - return stylesheet; -} - -/** - * Adds the currently register shadow stylesheet to icons in the panel. - * - */ -function add_icon_shadow() { - Panel.add_style_class_name('dpt-panel-icon-shadow'); - Panel.add_style_class_name('dpt-panel-arrow-shadow'); -} - -/** - * Determines if the panel currently has text shadowing applied. - * - * @returns {Boolean} If the panel has text shadowing. - */ -function has_text_shadow() { - return Panel.has_style_class_name('dpt-panel-text-shadow'); -} - -/** - * Determines if the panel currently has icon shadowing applied. - * - * @returns {Boolean} If the panel has icon shadowing. - */ -function has_icon_shadow() { - return (Panel.has_style_class_name('dpt-panel-icon-shadow') || Panel.has_style_class_name('dpt-panel-arrow-shadow')); -} - -/** - * Removes any text shadowing; deregistering the stylesheet and removing the css. - * - */ -function remove_text_shadow() { - Panel.remove_style_class_name('dpt-panel-text-shadow'); -} - -/** - * Removes any icon shadowing; deregistering the stylesheet and removing the css. - * - */ -function remove_icon_shadow() { - Panel.remove_style_class_name('dpt-panel-icon-shadow'); - Panel.remove_style_class_name('dpt-panel-arrow-shadow'); -} - -/** - * Registers text & icon coloring. - * - * @param {Color} color - Object containing an RGB color value. - * @param {string} prefix - What prefix to apply to the stylesheet. '-' is the default. - */ -function register_text_color(color, prefix) { - let color_css = 'color: rgb(' + color.red + ', ' + color.green + ', ' + color.blue + ');'; - - if (prefix) { - prefix = '-' + prefix + '-'; - } else { - prefix = '-'; - } - - let stylesheet = apply_stylesheet_css('.dpt-panel' + prefix + 'text-color .panel-button { ' + color_css + ' }\n.dpt-panel' + prefix + 'icon-color .system-status-icon { ' + color_css + ' }\n.dpt-panel' + prefix + 'arrow-color .popup-menu-arrow { ' + color_css + ' }', 'foreground/panel' + prefix + 'text-color'); - - register_style('dpt-panel' + prefix + 'text-color'); - register_style('dpt-panel' + prefix + 'icon-color'); - register_style('dpt-panel' + prefix + 'arrow-color'); - - return stylesheet; -} - -/** - * Sets which registered text color stylesheet to use for the text coloring. @see register_text_color - * - * @param {string} prefix - What stylesheet prefix to retrieve. '-' is the default. - */ -function set_text_color(prefix) { - if (prefix) { - prefix = '-' + prefix + '-'; - } else { - prefix = '-'; - } - - Panel.add_style_class_name('dpt-panel' + prefix + 'text-color'); - Panel.add_style_class_name('dpt-panel' + prefix + 'icon-color'); - Panel.add_style_class_name('dpt-panel' + prefix + 'arrow-color'); -} - -/** - * Remove a registered text color stylesheet from the panel. @see set_text_color - * - * @param {string} prefix - What stylesheet prefix to retrieve. '-' is the default. - */ -function remove_text_color(prefix) { - if (prefix) { - prefix = '-' + prefix + '-'; - } else { - prefix = '-'; - } - - Panel.remove_style_class_name('dpt-panel' + prefix + 'text-color'); - Panel.remove_style_class_name('dpt-panel' + prefix + 'icon-color'); - Panel.remove_style_class_name('dpt-panel' + prefix + 'arrow-color'); -} - -/** - * Registers any custom style so that it can be removed when the extension is disabled. - * - * @param {string} style - The name of a CSS styling. - */ -function register_style(style) { - if (this.styles.indexOf(style) === -1) { - this.styles.push(style); - } -} - -/** - * Set's the panel corners' actors to a specific background color. - * - * @param {Color} color [color={}] - Object containing an RGBA color value. - */ -// TODO: Gnome needs CSS styling for the corners. -function set_corner_color(color) { - let panel_color = get_background_color(); - - color = Params.parse(color, { - red: panel_color.red, - green: panel_color.green, - blue: panel_color.blue, - alpha: 0 - }); - - let opacity = Util.clamp(color.alpha / SCALE_FACTOR, 0, 1).toFixed(2); - - /* I strongly dislike using a deprecated method (set_style) - * but this is a hold over from the older extension code and - * the only way to keep per-app coloring working with corners. */ - let coloring = '-panel-corner-background-color: rgba(' + color.red + ', ' + color.green + ', ' + color.blue + ', ' + opacity + ');' + - '' + '-panel-corner-border-color: transparent;'; - - // TODO: Update this code. We're using @deprecated code. - Panel._leftCorner.set_style(coloring); - Panel._rightCorner.set_style(coloring); -} - -/** - * Removes any corner styling this extension has applied. - * - */ -function clear_corner_color() { - Panel._leftCorner.set_style(null); - Panel._rightCorner.set_style(null); -} - -/** - * Returns the user's desired panel color from Settings. Handles theme detection again. - * DEPENDENCY: Settings - * - * @returns {Object} Object containing an RGBA color value. - */ -function get_background_color() { - if (!Settings.enable_custom_background_color()) { - return { - red: 0, - blue: 0, - green: 0 - }; - } - - return Settings.get_panel_color(); -} - -/** - * Returns the user's desired maximized panel opacity from Settings or their theme. - * DEPENDENCY: Settings - * TODO: Needs better system to determine when default theme opacities are too low. - * - * @returns {Number} Alpha value from 0-255. - */ -function get_maximized_opacity() { - let maximized_opacity = Settings.get_maximized_opacity(); - - if (!Settings.enable_custom_opacity()) { - return 255; - } else { - return maximized_opacity; - } -} - -/** - * Returns the user's desired unmaximized panel opacity from Settings or their theme. - * DEPENDENCY: Settings - * - * @returns {Number} Alpha value from 0-255. - */ -function get_unmaximized_opacity() { - if (Settings.enable_custom_opacity()) { - return Settings.get_unmaximized_opacity(); - } else { - return 50; - } -} - -/** - * Applies the style class 'panel-transparency' which makes the panel fully transparent. - * - */ -function apply_panel_transparency() { - Panel.add_style_class_name('panel-transparency'); -} - -/** - * Applies the style class 'panel-transparency' which makes the panel fully transparent. - * - */ -function remove_panel_transparency() { - Panel.remove_style_class_name('panel-transparency'); -} - -/** - * Applies the style class 'panel-effect-transparency' and removes the basic CSS preventing this extension's transitions. - * - */ -function strip_panel_styling() { - Panel.add_style_class_name('panel-effect-transparency'); -} - -/** - * Removes the style class 'panel-effect-transparency' and enables the stock CSS preventing this extension's transitions. - * - */ -function reapply_panel_styling() { - Panel.remove_style_class_name('panel-effect-transparency'); -} - -/** - * Applies the style class 'panel-background-image-transparency' and removes the basic CSS preventing this extension's transitions. - * - */ -function strip_panel_background_image() { - Panel.add_style_class_name('panel-background-image-transparency'); -} - -/** - * Removes the style class 'panel-background-image-transparency' and enables the stock CSS preventing this extension's transitions. - * - */ -function reapply_panel_background_image() { - Panel.remove_style_class_name('panel-background-image-transparency'); -} - -/** - * Writes CSS data to a file and loads the stylesheet into the Shell. - * - * @param {string} css - CSS data. - * @param {string} name - Name of the intended CSS stylesheet. - * - * @returns {string} Filename of the stylesheet. - */ -function apply_stylesheet_css(css, name) { - let file_name = GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell', 'extensions', Me.uuid, 'styles', name + '.dpt.css']); - - /* Write to the file. */ - if (!Util.write_to_file(file_name, css)) { - log('[Dynamic Panel Transparency] Could not access: ' + file_name + ''); - log('[Dynamic Panel Transparency] The extension will not function until access is granted.'); - return null; - } - - let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); - - if (theme.load_stylesheet(Util.get_file(file_name))) { - this.stylesheets.push(file_name); - } else { - log('[Dynamic Panel Transparency] Error Loading Temporary Stylesheet: ' + name); - return null; - } - - return file_name; -} - -/* Backend24 (3.24+) Specific Functions (Not backwards compatible) */ - -function initialize_background_styles() { - register_background_color(Settings.get_panel_color(), 'custom'); - register_background_color({ - red: 0, - green: 0, - blue: 0 - }); -} - -function cleanup_background_styles() { - remove_background_color(); -} - -function register_background_style(style) { - if (this.background_styles.indexOf(style) === -1) { - this.background_styles.push(style); - } -} - -function register_background_color(bg_color, prefix) { - let suffix = (prefix ? '-' + prefix : ''); - - if (prefix) { - prefix = '-' + prefix + '-'; - } else { - prefix = '-'; - } - - let maximized_opacity = Util.clamp(get_maximized_opacity() / SCALE_FACTOR, 0, 1).toFixed(2); - let unmaximized_opacity = Util.clamp(get_unmaximized_opacity() / SCALE_FACTOR, 0, 1).toFixed(2); - - let maximized_bg_color_css = 'rgba(' + bg_color.red + ', ' + bg_color.green + ', ' + bg_color.blue + ', ' + maximized_opacity + ')'; - let unmaximized_bg_color_css = 'rgba(' + bg_color.red + ', ' + bg_color.green + ', ' + bg_color.blue + ', ' + unmaximized_opacity + ')'; - - register_background_style('dpt-panel' + prefix + 'maximized'); - register_background_style('dpt-panel' + prefix + 'unmaximized'); - - let file_prefix = 'background/panel'; - - let panel = apply_stylesheet_css('.dpt-panel' + prefix + 'unmaximized { background-color: ' + unmaximized_bg_color_css + '; }\n.dpt-panel' + prefix + 'maximized { background-color: ' + maximized_bg_color_css + '; }', file_prefix + suffix); - - return panel; -} - -function set_unmaximized_background_color(prefix) { - if (prefix) { - prefix = '-' + prefix + '-'; - } else { - prefix = '-'; - } - - let style = 'dpt-panel' + prefix + 'unmaximized'; - - Panel.add_style_class_name(style); -} - -function set_maximized_background_color(prefix) { - if (prefix) { - prefix = '-' + prefix + '-'; - } else { - prefix = '-'; - } - - let style = 'dpt-panel' + prefix + 'maximized'; - - Panel.add_style_class_name(style); -} - -function remove_unmaximized_background_color(prefix) { - if (prefix) { - prefix = '-' + prefix + '-'; - } else { - prefix = '-'; - } - - Panel.remove_style_class_name('dpt-panel' + prefix + 'unmaximized'); -} - -function remove_maximized_background_color(prefix) { - if (prefix) { - prefix = '-' + prefix + '-'; - } else { - prefix = '-'; - } - - Panel.remove_style_class_name('dpt-panel' + prefix + 'maximized'); -} - -function remove_background_color() { - remove_unmaximized_background_color('custom'); - remove_unmaximized_background_color(); - - remove_maximized_background_color('custom'); - remove_maximized_background_color(); -} - -function update_transition_css() { - let duration_css = Settings.get_transition_speed(); - - let stylesheet = apply_stylesheet_css('.dpt-panel-transition-duration { transition-duration: ' + duration_css + 'ms; }', 'transitions/panel-transition-duration'); - - Panel.add_style_class_name('dpt-panel-transition-duration'); - - register_style('dpt-panel-transition-duration'); - - return stylesheet; -} diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/transitions.js b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/transitions.js deleted file mode 100644 index f395bec..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/transitions.js +++ /dev/null @@ -1,274 +0,0 @@ -/* exported init, cleanup, lock, unlock, get_animation_status, get_transparency_status, minimum_fade_in, update_transition_type */ -/* exported fade_in, fade_out, blank_fade_out */ - -const Mainloop = imports.mainloop; - -const St = imports.gi.St; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); - -const Settings = Me.imports.settings; -const Theming = Me.imports.theming; - -const Equations = imports.tweener.equations; - -const CORNER_UPDATE_FREQUENCY = 30; - -class TransparencyStatus { - constructor() { - this.transparent = false; - this.blank = false; - } - - is_transparent() { - return this.transparent; - } - - is_blank() { - return this.blank; - } - - set_transparent(transparent) { - this.transparent = transparent; - } - - set_blank(blank) { - this.blank = blank; - } -}; - -/** - * Intialize. - * - */ -function init() { - /* Objects to track where the transparency is and where it's going. */ - this.status = new TransparencyStatus(); - - this.corner_timeout_id = 0; -} - -/** - * Freeup any held assets on disable. - * - */ -function cleanup() { - this.status = null; - - this.corner_timeout_id = null; -} - -/** - * Get the current status of the panel's transparency. - * - * @returns {Object} Current transparency. @see TransparencyStatus - */ -function get_transparency_status() { - return this.status; -} - -/** - * Get any animation that the panel is currently doing. - * DEPRECATED. - * - * @returns {Object} Current animation status. @see AnimationStatus - */ -function get_animation_status() { - return { destination: null, action: null }; -} - -/** - * Fades the panel into the unmaximized (minimum) alpha. Used for closing the overview. - * - */ -function minimum_fade_in() { - /* The CSS backend doesn't need different starting/ending values */ - fade_out(); -} - -/** - * Fades the panel into the nmaximized (maximum) alpha. - * - */ -function fade_in() { - if (!Settings.remove_panel_styling()) { - Theming.reapply_panel_styling(); - Theming.reapply_panel_background_image(); - } - - Theming.remove_panel_transparency(); - - if (Settings.enable_custom_background_color()) { - Theming.set_maximized_background_color('custom'); - - Theming.remove_unmaximized_background_color(); - Theming.remove_unmaximized_background_color('custom'); - } else { - Theming.set_maximized_background_color(); - - Theming.remove_unmaximized_background_color(); - Theming.remove_unmaximized_background_color('custom'); - } - - if (!Settings.get_hide_corners()) { - let speed = St.Settings.get().slow_down_factor * Settings.get_transition_speed(); - - let maximized = Settings.get_maximized_opacity(); - let unmaximized = !this.status.is_transparent() ? maximized : Settings.get_unmaximized_opacity(); - - this.status.set_transparent(false); - this.status.set_blank(false); - - let count = 0; - - const id = this.corner_timeout_id = Mainloop.timeout_add(Math.floor(speed / CORNER_UPDATE_FREQUENCY), (function() { - if (id === this.corner_timeout_id && !this.status.is_transparent()) { - count++; - - let alpha = Equations.linear(Math.floor(count * (speed / CORNER_UPDATE_FREQUENCY)), unmaximized, maximized - unmaximized, speed); - - update_corner_alpha(alpha); - - if (count > CORNER_UPDATE_FREQUENCY) { - update_corner_alpha(maximized); - return false; - } - } else { - return false; - } - - return true; - }).bind(this)); - } else { - update_corner_alpha(); - } - - this.status.set_transparent(false); - this.status.set_blank(false); -} - -/** - * Fades the panel into the unmaximized (minimum) alpha. - * - */ -function fade_out() { - Theming.strip_panel_background_image(); - Theming.strip_panel_styling(); - - if (Settings.enable_custom_background_color()) { - Theming.set_unmaximized_background_color('custom'); - - Theming.remove_maximized_background_color(); - Theming.remove_maximized_background_color('custom'); - } else { - Theming.set_unmaximized_background_color(); - - Theming.remove_maximized_background_color(); - Theming.remove_maximized_background_color('custom'); - } - - Theming.remove_panel_transparency(); - - // TODO: Figure out how to write the panel corners in pure CSS. - if (!Settings.get_hide_corners()) { - let speed = St.Settings.get().slow_down_factor * Settings.get_transition_speed(); - - let unmaximized = Settings.get_unmaximized_opacity(); - let maximized = this.status.is_transparent() ? unmaximized : Settings.get_maximized_opacity(); - - /* Keep the status up to date */ - this.status.set_transparent(true); - this.status.set_blank(false); - - let count = 0; - - const id = this.corner_timeout_id = Mainloop.timeout_add(Math.floor(speed / CORNER_UPDATE_FREQUENCY), (function() { - if (id === this.corner_timeout_id && this.status.is_transparent()) { - count++; - - let alpha = Equations.linear(Math.floor(count * (speed / CORNER_UPDATE_FREQUENCY)), maximized, unmaximized - maximized, speed); - - update_corner_alpha(alpha); - - if (count > CORNER_UPDATE_FREQUENCY) { - update_corner_alpha(unmaximized); - return false; - } - } else { - return false; - } - return true; - }).bind(this)); - } else { - update_corner_alpha(); - } - - /* Keep the status up to date */ - this.status.set_transparent(true); - this.status.set_blank(false); -} - -/** - * Fades the panel's alpha to 0. Used for opening the overview & displaying the screenShield. - * - */ -function blank_fade_out() { - this.status.set_transparent(true); - this.status.set_blank(true); - - /* Completely remove every possible background style... */ - Theming.remove_background_color(); - - Theming.strip_panel_background_image(); - Theming.strip_panel_styling(); - - Theming.apply_panel_transparency(); - - // TODO: These corners... - if (!Settings.get_hide_corners()) { - let speed = St.Settings.get().slow_down_factor * Settings.get_transition_speed(); - - let maximized = Settings.get_maximized_opacity(); - - let count = 0; - - const id = this.corner_timeout_id = Mainloop.timeout_add(Math.floor(speed / CORNER_UPDATE_FREQUENCY), (function() { - if (id === this.corner_timeout_id && this.status.is_transparent()) { - count++; - - let alpha = Equations.linear(Math.floor(count * (speed / CORNER_UPDATE_FREQUENCY)), maximized, -maximized, speed); - - update_corner_alpha(alpha); - - if (count > CORNER_UPDATE_FREQUENCY) { - update_corner_alpha(0); - return false; - } - } else { - return false; - } - return true; - }).bind(this)); - } else { - update_corner_alpha(); - } -} - -/** - * Updates the alpha value of the corners' coloring. Slightly awkward overlap is unavoidable. - * - * @param {Number} alpha - Alpha value ranging from 0-255. - */ -function update_corner_alpha(alpha = null) { - if (alpha === null) { - if (Settings.get_hide_corners()) { - alpha = 0; - } else { - alpha = this.status.is_transparent() ? Theming.get_unmaximized_opacity() : Theming.get_maximized_opacity(); - } - } - - Theming.set_corner_color({ - alpha: alpha - }); -} diff --git a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/util.js b/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/util.js deleted file mode 100644 index 3ab2d32..0000000 --- a/.local/share/gnome-shell/extensions/dynamic-panel-transparency@rockon999.github.io/util.js +++ /dev/null @@ -1,240 +0,0 @@ -/* exported get_shell_version, is_undef, clamp, is_valid, match_colors, remove_file, get_file, write_to_file, gdk_to_css_color, clutter_to_native_color, tuple_to_native_color, deep_freeze, strip_args */ - -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; - -/* This import can't be a constant as it requires lazy initialization. */ -let Meta = null; - -/* Gnome Versioning */ -const MAJOR_VERSION = parseInt(imports.misc.config.PACKAGE_VERSION.split('.')[0], 10); -const MINOR_VERSION = parseInt(imports.misc.config.PACKAGE_VERSION.split('.')[1], 10); - -/* Permission setting for created files. */ -const PERMISSIONS_MODE = parseInt('0744', 8); - -/* Utility Variable Access */ - -/** - * Returns the current shell version. - * - * @returns {Object} The current shell version. - * - */ -function get_shell_version() { - return { major: MAJOR_VERSION, minor: MINOR_VERSION }; -} - -/* Utility Functions */ - -/** - * Evaluates parameter 'value' and returns either 'value' or 'min'/'max' if 'value' is outside of the range. - * - * @param {Number} value - Test value. - * @param {Number} min - Minimum value. - * @param {Number} max - Maximum value. - * - * @returns {Number} 'value' or the minimum or maximum. - * - */ -function clamp(value, min, max) { - return Math.min(Math.max(value, min), max); -} - -/** - * Determines if 'window' is a valid window to watch. - * Will not work outside the extension code. - * - * @param {Object} window - Window to check. - * - * @returns {Boolean} Whether 'window' is a valid window to watch. - * - */ -function is_valid(window) { - if (!Meta) { - Meta = imports.gi.Meta; - } - - let windowTypes = [ - Meta.WindowType.NORMAL, - Meta.WindowType.DIALOG, - Meta.WindowType.MODAL_DIALOG, - Meta.WindowType.TOOLBAR, - Meta.WindowType.MENU, - Meta.WindowType.UTILITY, - ]; - - let type = window.get_window_type(); - - return (windowTypes.indexOf(type) !== -1); -} - -/** - * Retrieves the GFile for a file path. - * - * @param {string} file_path - Path for a file. - * - * @returns {Object} GFile for the path or null if the path is not valid. - * - */ -function get_file(file_path) { - try { - return Gio.file_new_for_path(file_path); - } catch (error) { - log('[Dynamic Panel Transparency] Error getting file: ' + error); - } - - return null; -} - -/** - * Write the given string to a file path; creating the necessary files and directories. - * - * @param {string} file_path - Path for a file. - * @param {string} text - Text to write to the file. - * - * @returns {Boolean} Whether the file write was a success. - * - */ -function write_to_file(file_path, text) { - try { - let file = get_file(file_path); - let parent = file.get_parent(); - - if (GLib.mkdir_with_parents(parent.get_path(), PERMISSIONS_MODE) === 0) { - let success = file.replace_contents(text, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION, null); - return success[0]; - } - } catch (error) { - log('[Dynamic Panel Transparency] Error writing to file: ' + file_path); - log(error); - } - - return false; -} - -/** - * Deletes the given file_path. - * - * @param {string} file_path - Path for a file. - * - * @returns {Boolean} Whether the file deletion was a success. - * - */ -function remove_file(file_path) { - try { - let file = get_file(file_path); - let result = file.delete(null); - return result; - } catch (error) { - log('[Dynamic Panel Transparency] Error removing file: ' + file_path); - log(error); - } - - return false; -} - -/** - * Converts a GdkColor into a JS/CSS color object. - * - * @param {Object} color - GdkColor to convert. - * - * @returns {Object} Converted RGB color. - * - */ -function gdk_to_css_color(color) { - let red = Math.round(clamp((color.red * 255), 0, 255)); - let green = Math.round(clamp((color.green * 255), 0, 255)); - let blue = Math.round(clamp((color.blue * 255), 0, 255)); - - return { 'red': red, 'green': green, 'blue': blue }; -} - -/** - * Converts a ClutterColor into a JS/CSS color object. - * - * @param {Object} color - ClutterColor to convert. - * @param {Boolean} [alpha = false] - Whether to transfer the alpha value. - * - * @returns {Object} Converted RGB(A) color. - * - */ -function clutter_to_native_color(color, alpha = false) { - let output = { red: color.red, green: color.green, blue: color.blue }; - if (alpha) { - output.alpha = color.alpha; - } - return output; -} - -/** - * Converts a tuple from a GVariant (typically) into a JS/CSS color object. - * - * @param {Object} color - Tuple to convert. - * @param {Boolean} [alpha = false] - Whether to transfer the alpha value. - * - * @returns {Object} Converted RGB(A) color. - * - */ -function tuple_to_native_color(tuple) { - let color = { red: tuple[0], green: tuple[1], blue: tuple[2] }; - if (tuple.length === 4) { - color.alpha = tuple[3]; - } - return color; -} - -/** - * Compares two colors for equivalency. - * - * @param {Object} a - First color. - * @param {Object} a - Second color. - * @param {Boolean} [alpha = false] - Whether to check the alpha value. - * - * @returns {Boolean} Whether the two colors are equal. - * - */ -function match_colors(a, b, alpha = false) { - let result = (a.red === b.red); - result = result && (a.green === b.green); - result = result && (a.blue === b.blue); - if (alpha) { - result = result && (a.alpha === b.alpha); - } - return result; -} - -/** - * Freezes an Object's and its children. - * - * @param {Object} type - Object to freeze. - * @param {Boolean} [recursive = false] - Whether to recursively traverse the object's children. - * - */ -function deep_freeze(type, recursive = false) { - const freeze_children = function(obj) { - Object.keys(obj).forEach(function(value, index, arr) { - if (typeof (value) === 'object' && !Object.isFrozen(value)) { - Object.freeze(value); - if (recursive) { - freeze_children(value); - } - } - }); - }; - - Object.freeze(type); - freeze_children(type); -} - -/** - * Prevents any arguments from passing on. - * - * @param {Object} method - Method to call. - * - */ -function strip_args(method) { - return function() { - method.call(this); - }; -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/extension.js b/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/extension.js deleted file mode 100644 index d0c7407..0000000 --- a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/extension.js +++ /dev/null @@ -1,47 +0,0 @@ -const Meta = imports.gi.Meta; -const Main = imports.ui.main; -const Shell = imports.gi.Shell; - -const SHORTCUT_KEY = 'shortcut-key'; - -let settings = imports.misc.extensionUtils.getSettings(); - -var currentWorkspace = -1; -var lastWorkspace = -1; - -function goToLastWorkspace() { - if (lastWorkspace < 0) { - return; - } - - // keep global.screen for backwards compatibility - let ws = (global.screen || global.workspace_manager).get_workspace_by_index(lastWorkspace); - ws.activate(global.get_current_time()); -} - - -function init() { -} - -let signals = []; - -function enable() { - var ModeType = Shell.hasOwnProperty('ActionMode') ? Shell.ActionMode : Shell.KeyBindingMode; - Main.wm.addKeybinding(SHORTCUT_KEY, settings, Meta.KeyBindingFlags.NONE, ModeType.NORMAL | ModeType.OVERVIEW, goToLastWorkspace); - - signals.push((global.screen || global.workspace_manager).connect('workspace-switched', function(display, prev, current, direction) { - lastWorkspace = currentWorkspace; - currentWorkspace = current; - })); -} - -function disable() { - // clean up - Main.wm.removeKeybinding(SHORTCUT_KEY); - - let i = signals.length; - while (i--) { - (global.screen || global.workspace_manager).disconnect(signals.pop()); - } - -} diff --git a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/metadata.json b/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/metadata.json deleted file mode 100644 index 949a676..0000000 --- a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/metadata.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Quickly toggle between two workspaces with one key", - "name": "Go To Last Workspace", - "settings-schema": "org.gnome.shell.extensions.go-to-last-workspace", - "shell-version": [ - "3.28", - "3.30", - "3.34", - "3.32", - "3.36", - "3.38", - "40" - ], - "url": "https://github.com/arjan/gnome-shell-go-to-last-workspace", - "uuid": "gnome-shell-go-to-last-workspace@github.com", - "version": 7 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/prefs.js b/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/prefs.js deleted file mode 100644 index b13f191..0000000 --- a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/prefs.js +++ /dev/null @@ -1,82 +0,0 @@ -// Library imports -const GObject = imports.gi.GObject; -const Gdk = imports.gi.Gdk; -const Gtk = imports.gi.Gtk; -const ExtensionUtils = imports.misc.extensionUtils; - -// Globals -const pretty_names = { - "shortcut-key": "Go to last workspace", -}; - -function init() {} - -function buildPrefsWidget() { - let model = new Gtk.ListStore(); - - model.set_column_types([ - GObject.TYPE_STRING, - GObject.TYPE_STRING, - GObject.TYPE_INT, - GObject.TYPE_INT, - ]); - - let settings = ExtensionUtils.getSettings(); - - for (key in pretty_names) { - append_hotkey(model, settings, key, pretty_names[key]); - } - - let treeview = new Gtk.TreeView({ - model: model, - }); - - let col; - let cellrend; - cellrend = new Gtk.CellRendererText(); - col = new Gtk.TreeViewColumn({ - title: "Keybinding", - }); - col.pack_start(cellrend, true); - col.add_attribute(cellrend, "text", 1); - treeview.append_column(col); - - cellrend = new Gtk.CellRendererAccel({ - editable: true, - "accel-mode": Gtk.CellRendererAccelMode.GTK, - }); - cellrend.connect("accel-edited", function (rend, iter, key, mods) { - let value = Gtk.accelerator_name(key, mods); - log("change"); - log(value); - log(key); - log(mods); - let [success, iter1] = model.get_iter_from_string(iter); - if (!success) { - throw new Error("Something be broken, yo."); - } - let name = model.get_value(iter1, 0); - model.set(iter1, [2, 3], [mods, key]); - settings.set_strv(name, [value]); - }); - - col = new Gtk.TreeViewColumn({ - title: "Accel", - }); - - col.pack_end(cellrend, false); - col.add_attribute(cellrend, "accel-mods", 2); - col.add_attribute(cellrend, "accel-key", 3); - treeview.append_column(col); - treeview.expand_all(); - - return treeview; -} - -function append_hotkey(model, settings, name, pretty_name) { - let [_something, key, mods] = Gtk.accelerator_parse( - settings.get_strv(name)[0] - ); - let row = model.insert(-1); - model.set(row, [0, 1, 2, 3], [name, pretty_name, mods, key]); -} diff --git a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/schemas/gschemas.compiled b/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/schemas/gschemas.compiled deleted file mode 100644 index e2f9af0..0000000 Binary files a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/schemas/gschemas.compiled and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/schemas/org.gnome.shell.extensions.go-to-last-workspace.gschema.xml b/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/schemas/org.gnome.shell.extensions.go-to-last-workspace.gschema.xml deleted file mode 100644 index 9b654fc..0000000 --- a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/schemas/org.gnome.shell.extensions.go-to-last-workspace.gschema.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - escape']]]> - Keybinding switch to last workspace - - The keybinding used to switch to the last used workspace. - - - - diff --git a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/utils.js b/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/utils.js deleted file mode 100644 index bff9293..0000000 --- a/.local/share/gnome-shell/extensions/gnome-shell-go-to-last-workspace@github.com/utils.js +++ /dev/null @@ -1,46 +0,0 @@ -const Gio = imports.gi.Gio; -const Config = imports.misc.config; -const ExtensionUtils = imports.misc.extensionUtils; - -/** - * getSettings: - * @schema: (optional): the GSettings schema id - * - * Builds and return a GSettings schema for @schema, using schema files - * in extensionsdir/schemas. If @schema is not provided, it is taken from - * metadata['settings-schema']. - */ -function getSettings(schema) { - let extension = ExtensionUtils.getCurrentExtension(); - - schema = schema || extension.metadata["settings-schema"]; - - const GioSSS = Gio.SettingsSchemaSource; - - // check if this extension was built with "make zip-file", and thus - // has the schema files in a subfolder - // otherwise assume that extension has been installed in the - // same prefix as gnome-shell (and therefore schemas are available - // in the standard folders) - let schemaDir = extension.dir.get_child("schemas"); - let schemaSource; - if (schemaDir.query_exists(null)) - schemaSource = GioSSS.new_from_directory( - schemaDir.get_path(), - GioSSS.get_default(), - false - ); - else schemaSource = GioSSS.get_default(); - - let schemaObj = schemaSource.lookup(schema, true); - if (!schemaObj) - throw new Error( - "Schema " + - schema + - " could not be found for extension " + - extension.metadata.uuid + - ". Please check your installation." - ); - - return new Gio.Settings({ settings_schema: schemaObj }); -} diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/config.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/config.js deleted file mode 100644 index f9d5690..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/config.js +++ /dev/null @@ -1,19 +0,0 @@ -var PACKAGE_VERSION = 47; -var PACKAGE_URL = 'https://github.com/andyholmes/gnome-shell-extension-gsconnect'; -var PACKAGE_BUGREPORT = 'https://github.com/andyholmes/gnome-shell-extension-gsconnect/issues/new'; -var PACKAGE_DATADIR = '/usr/local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io'; -var PACKAGE_LOCALEDIR = '/usr/local/share/locale'; -var GSETTINGS_SCHEMA_DIR = '/usr/local/share/glib-2.0/schemas'; -var GNOME_SHELL_LIBDIR = '/usr/local/lib64'; - -var APP_ID = 'org.gnome.Shell.Extensions.GSConnect'; -var APP_PATH = '/org/gnome/Shell/Extensions/GSConnect'; - -var IS_USER = false; - -// External binary paths -var OPENSSL_PATH = 'openssl'; -var SSHADD_PATH = 'ssh-add'; -var SSHKEYGEN_PATH = 'ssh-keygen'; -var FFMPEG_PATH = 'ffmpeg'; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/extension.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/extension.js deleted file mode 100644 index abe14e0..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/extension.js +++ /dev/null @@ -1,455 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const Main = imports.ui.main; -const PanelMenu = imports.ui.panelMenu; -const PopupMenu = imports.ui.popupMenu; -const AggregateMenu = Main.panel.statusArea.aggregateMenu; - -// Bootstrap -const Extension = imports.misc.extensionUtils.getCurrentExtension(); -const Utils = Extension.imports.shell.utils; - -// eslint-disable-next-line no-redeclare -const _ = Extension._; -const Clipboard = Extension.imports.shell.clipboard; -const Config = Extension.imports.config; -const Device = Extension.imports.shell.device; -const Keybindings = Extension.imports.shell.keybindings; -const Notification = Extension.imports.shell.notification; -const Remote = Extension.imports.utils.remote; - -Extension.getIcon = Utils.getIcon; - - -/** - * A System Indicator used as the hub for spawning device indicators and - * indicating that the extension is active when there are none. - */ -const ServiceIndicator = GObject.registerClass({ - GTypeName: 'GSConnectServiceIndicator', -}, class ServiceIndicator extends PanelMenu.SystemIndicator { - - _init() { - super._init(); - - this._menus = {}; - - this._keybindings = new Keybindings.Manager(); - - // GSettings - this.settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup( - 'org.gnome.Shell.Extensions.GSConnect', - null - ), - path: '/org/gnome/shell/extensions/gsconnect/', - }); - - this._enabledId = this.settings.connect( - 'changed::enabled', - this._onEnabledChanged.bind(this) - ); - - this._panelModeId = this.settings.connect( - 'changed::show-indicators', - this._sync.bind(this) - ); - - // Service Proxy - this.service = new Remote.Service(); - - this._deviceAddedId = this.service.connect( - 'device-added', - this._onDeviceAdded.bind(this) - ); - - this._deviceRemovedId = this.service.connect( - 'device-removed', - this._onDeviceRemoved.bind(this) - ); - - this._serviceChangedId = this.service.connect( - 'notify::active', - this._onServiceChanged.bind(this) - ); - - // Service Indicator - this._indicator = this._addIndicator(); - this._indicator.gicon = Extension.getIcon( - 'org.gnome.Shell.Extensions.GSConnect-symbolic' - ); - this._indicator.visible = false; - - AggregateMenu._indicators.insert_child_at_index(this, 0); - AggregateMenu._gsconnect = this; - - // Service Menu - this._item = new PopupMenu.PopupSubMenuMenuItem(_('Mobile Devices'), true); - this._item.icon.gicon = this._indicator.gicon; - this._item.label.clutter_text.x_expand = true; - this.menu.addMenuItem(this._item); - - // Find current index of network menu - const menuItems = AggregateMenu.menu._getMenuItems(); - const networkMenuIndex = menuItems.indexOf(AggregateMenu._network.menu); - const menuIndex = networkMenuIndex > -1 ? networkMenuIndex : 3; - // Place our menu below the network menu - AggregateMenu.menu.addMenuItem(this.menu, menuIndex + 1); - - // Service Menu -> Devices Section - this.deviceSection = new PopupMenu.PopupMenuSection(); - this.deviceSection.actor.add_style_class_name('gsconnect-device-section'); - this.settings.bind( - 'show-indicators', - this.deviceSection.actor, - 'visible', - Gio.SettingsBindFlags.INVERT_BOOLEAN - ); - this._item.menu.addMenuItem(this.deviceSection); - - // Service Menu -> Separator - this._item.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - - // Service Menu -> "Turn On/Off" - this._enableItem = this._item.menu.addAction( - _('Turn On'), - this._enable.bind(this) - ); - - // Service Menu -> "Mobile Settings" - this._item.menu.addAction(_('Mobile Settings'), this._preferences); - - // Prime the service - this._initService(); - } - - async _initService() { - try { - if (this.settings.get_boolean('enabled')) - await this.service.start(); - else - await this.service.reload(); - } catch (e) { - logError(e, 'GSConnect'); - } - } - - _enable() { - try { - const enabled = this.settings.get_boolean('enabled'); - - // If the service state matches the enabled setting, we should - // toggle the service by toggling the setting - if (this.service.active === enabled) - this.settings.set_boolean('enabled', !enabled); - - // Otherwise, we should change the service to match the setting - else if (this.service.active) - this.service.stop(); - else - this.service.start(); - } catch (e) { - logError(e, 'GSConnect'); - } - } - - _preferences() { - Gio.Subprocess.new([`${Extension.path}/gsconnect-preferences`], 0); - } - - _sync() { - const available = this.service.devices.filter(device => { - return (device.connected && device.paired); - }); - const panelMode = this.settings.get_boolean('show-indicators'); - - // Hide status indicator if in Panel mode or no devices are available - this._indicator.visible = (!panelMode && available.length); - - // Show device indicators in Panel mode if available - for (const device of this.service.devices) { - const isAvailable = available.includes(device); - const indicator = Main.panel.statusArea[device.g_object_path]; - - indicator.visible = panelMode && isAvailable; - - const menu = this._menus[device.g_object_path]; - menu.actor.visible = !panelMode && isAvailable; - menu._title.actor.visible = !panelMode && isAvailable; - } - - // One connected device in User Menu mode - if (!panelMode && available.length === 1) { - const device = available[0]; - - // Hide the menu title and move it to the submenu item - this._menus[device.g_object_path]._title.actor.visible = false; - this._item.label.text = device.name; - - // Destroy any other device's signalStrength - if (this._item._signalStrength && this._item._signalStrength.device !== device) { - this._item._signalStrength.destroy(); - this._item._signalStrength = null; - } - - // Add the signalStrength to the submenu item - if (!this._item._signalStrength) { - this._item._signalStrength = new Device.SignalStrength({ - device: device, - opacity: 128, - }); - this._item.actor.insert_child_below( - this._item._signalStrength, - this._item._triangleBin - ); - } - - // Destroy any other device's battery - if (this._item._battery && this._item._battery.device !== device) { - this._item._battery.destroy(); - this._item._battery = null; - } - - // Add the battery to the submenu item - if (!this._item._battery) { - this._item._battery = new Device.Battery({ - device: device, - opacity: 128, - }); - this._item.actor.insert_child_below( - this._item._battery, - this._item._triangleBin - ); - } - } else { - if (available.length > 1) { - // TRANSLATORS: %d is the number of devices connected - this._item.label.text = Extension.ngettext( - '%d Connected', - '%d Connected', - available.length - ).format(available.length); - } else { - this._item.label.text = _('Mobile Devices'); - } - - // Destroy any battery in the submenu item - if (this._item._battery) { - this._item._battery.destroy(); - this._item._battery = null; - } - - // Destroy any signalStrength in the submenu item - if (this._item._signalStrength) { - this._item._signalStrength.destroy(); - this._item._signalStrength = null; - } - } - } - - _onDeviceChanged(device, changed, invalidated) { - try { - const properties = changed.deepUnpack(); - - if (properties.hasOwnProperty('Connected') || - properties.hasOwnProperty('Paired')) - this._sync(); - } catch (e) { - logError(e, 'GSConnect'); - } - } - - _onDeviceAdded(service, device) { - try { - // Device Indicator - const indicator = new Device.Indicator({device: device}); - Main.panel.addToStatusArea(device.g_object_path, indicator); - - // Device Menu - const menu = new Device.Menu({ - device: device, - menu_type: 'list', - }); - this._menus[device.g_object_path] = menu; - this.deviceSection.addMenuItem(menu); - - // Device Settings - device.settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup( - 'org.gnome.Shell.Extensions.GSConnect.Device', - true - ), - path: `/org/gnome/shell/extensions/gsconnect/device/${device.id}/`, - }); - - // Keyboard Shortcuts - device.__keybindingsChangedId = device.settings.connect( - 'changed::keybindings', - this._onDeviceKeybindingsChanged.bind(this, device) - ); - this._onDeviceKeybindingsChanged(device); - - // Watch the for status changes - device.__deviceChangedId = device.connect( - 'g-properties-changed', - this._onDeviceChanged.bind(this) - ); - - this._sync(); - } catch (e) { - logError(e, 'GSConnect'); - } - } - - _onDeviceRemoved(service, device, sync = true) { - try { - // Stop watching for status changes - if (device.__deviceChangedId) - device.disconnect(device.__deviceChangedId); - - // Release keybindings - if (device.__keybindingsChangedId) { - device.settings.disconnect(device.__keybindingsChangedId); - device._keybindings.map(id => this._keybindings.remove(id)); - } - - // Destroy the indicator - Main.panel.statusArea[device.g_object_path].destroy(); - - // Destroy the menu - this._menus[device.g_object_path].destroy(); - delete this._menus[device.g_object_path]; - - if (sync) - this._sync(); - } catch (e) { - logError(e, 'GSConnect'); - } - } - - _onDeviceKeybindingsChanged(device) { - try { - // Reset any existing keybindings - if (device.hasOwnProperty('_keybindings')) - device._keybindings.map(id => this._keybindings.remove(id)); - - device._keybindings = []; - - // Get the keybindings - const keybindings = device.settings.get_value('keybindings').deepUnpack(); - - // Apply the keybindings - for (const [action, accelerator] of Object.entries(keybindings)) { - const [, name, parameter] = Gio.Action.parse_detailed_name(action); - - const actionId = this._keybindings.add( - accelerator, - () => device.action_group.activate_action(name, parameter) - ); - - if (actionId !== 0) - device._keybindings.push(actionId); - } - } catch (e) { - logError(e, 'GSConnect'); - } - } - - async _onEnabledChanged(settings, key) { - try { - if (this.settings.get_boolean('enabled')) - await this.service.start(); - else - await this.service.stop(); - } catch (e) { - logError(e, 'GSConnect'); - } - } - - async _onServiceChanged(service, pspec) { - try { - if (this.service.active) { - // TRANSLATORS: A menu option to deactivate the extension - this._enableItem.label.text = _('Turn Off'); - } else { - // TRANSLATORS: A menu option to activate the extension - this._enableItem.label.text = _('Turn On'); - - // If it's enabled, we should try to restart now - if (this.settings.get_boolean('enabled')) - await this.service.start(); - } - } catch (e) { - logError(e, 'GSConnect'); - } - } - - destroy() { - // Unhook from Remote.Service - if (this.service) { - this.service.disconnect(this._serviceChangedId); - this.service.disconnect(this._deviceAddedId); - this.service.disconnect(this._deviceRemovedId); - - for (const device of this.service.devices) - this._onDeviceRemoved(this.service, device, false); - - this.service.destroy(); - } - - // Disconnect any keybindings - this._keybindings.destroy(); - - // Disconnect from any GSettings changes - this.settings.disconnect(this._enabledId); - this.settings.disconnect(this._panelModeId); - this.settings.run_dispose(); - - // Destroy the PanelMenu.SystemIndicator actors - this._item.destroy(); - this.menu.destroy(); - - delete AggregateMenu._gsconnect; - super.destroy(); - } -}); - - -var serviceIndicator = null; - - -function init() { - // If installed as a user extension, this will install the Desktop entry, - // DBus and systemd service files necessary for DBus activation and - // GNotifications. Since there's no uninit()/uninstall() hook for extensions - // and they're only used *by* GSConnect, they should be okay to leave. - Utils.installService(); - - // These modify the notification source for GSConnect's GNotifications and - // need to be active even when the extension is disabled (eg. lock screen). - // Since they *only* affect notifications from GSConnect, it should be okay - // to leave them applied. - Notification.patchGSConnectNotificationSource(); - Notification.patchGtkNotificationDaemon(); - - // This watches for the service to start and exports a custom clipboard - // portal for use on Wayland - Clipboard.watchService(); -} - - -function enable() { - serviceIndicator = new ServiceIndicator(); - Notification.patchGtkNotificationSources(); -} - - -function disable() { - serviceIndicator.destroy(); - serviceIndicator = null; - Notification.unpatchGtkNotificationSources(); -} diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/gsconnect-preferences b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/gsconnect-preferences deleted file mode 100755 index f66c742..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/gsconnect-preferences +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env gjs - -// -*- mode: js; -*- - -'use strict'; - -imports.gi.versions.Gdk = '3.0'; -imports.gi.versions.GdkPixbuf = '2.0'; -imports.gi.versions.Gio = '2.0'; -imports.gi.versions.GLib = '2.0'; -imports.gi.versions.GObject = '2.0'; -imports.gi.versions.Gtk = '3.0'; - -const Gdk = imports.gi.Gdk; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - - -// Bootstrap -function get_datadir() { - let m = /@(.+):\d+/.exec((new Error()).stack.split('\n')[1]); - return Gio.File.new_for_path(m[1]).get_parent().get_path(); -} - -imports.searchPath.unshift(get_datadir()); -imports.config.PACKAGE_DATADIR = imports.searchPath[0]; - - -// Local Imports -const Config = imports.config; -const Settings = imports.preferences.service; - - -/** - * Class representing the GSConnect service daemon. - */ -const Preferences = GObject.registerClass({ - GTypeName: 'GSConnectPreferences', -}, class Preferences extends Gtk.Application { - - _init() { - super._init({ - application_id: 'org.gnome.Shell.Extensions.GSConnect.Preferences', - resource_base_path: '/org/gnome/Shell/Extensions/GSConnect', - }); - - GLib.set_prgname('gsconnect-preferences'); - GLib.set_application_name(_('GSConnect Preferences')); - } - - vfunc_activate() { - if (this._window === undefined) { - this._window = new Settings.Window({ - application: this, - }); - } - - this._window.present(); - } - - vfunc_startup() { - super.vfunc_startup(); - - // Init some resources - let provider = new Gtk.CssProvider(); - provider.load_from_resource(`${Config.APP_PATH}/application.css`); - Gtk.StyleContext.add_provider_for_screen( - Gdk.Screen.get_default(), - provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ); - - let actions = [ - ['refresh', null], - ['connect', GLib.VariantType.new('s')], - ]; - - for (let [name, type] of actions) { - let action = new Gio.SimpleAction({ - name: name, - parameter_type: type, - }); - this.add_action(action); - } - } - - vfunc_activate_action(action_name, parameter) { - try { - let paramArray = []; - - if (parameter instanceof GLib.Variant) - paramArray[0] = parameter; - - this.get_dbus_connection().call( - 'org.gnome.Shell.Extensions.GSConnect', - '/org/gnome/Shell/Extensions/GSConnect', - 'org.freedesktop.Application', - 'ActivateAction', - GLib.Variant.new('(sava{sv})', [action_name, paramArray, {}]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - null - ); - } catch (e) { - logError(e); - } - } -}); - -(new Preferences()).run([imports.system.programInvocationName].concat(ARGV)); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ar/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ar/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 0f4ae63..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ar/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/be/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/be/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 5007f6c..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/be/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ca/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ca/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 9f8ab91..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ca/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/cs/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/cs/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 9682ec9..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/cs/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/da/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/da/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 3744b63..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/da/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/de/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/de/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 3739195..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/de/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/es/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/es/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index d67cd51..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/es/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/et/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/et/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index ecd34f7..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/et/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fa/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fa/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 1719e0c..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fa/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fi/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fi/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index a0b4e94..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fi/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 5176b23..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/fr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/gl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/gl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 3e94408..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/gl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/hu/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/hu/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index a89de62..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/hu/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/it/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/it/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 74b66b0..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/it/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/lt/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/lt/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 34f6f8e..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/lt/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_BE/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_BE/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index af70536..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_BE/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_NL/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_NL/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 31dfadd..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/nl_NL/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index f6a677d..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pl/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pt_BR/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pt_BR/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index c0cb2ed..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/pt_BR/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ru/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ru/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 71d9ec4..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/ru/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index ef4f627..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 5400f0a..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr@latin/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr@latin/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 3f9925e..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/sr@latin/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/tr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/tr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index a863791..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/tr/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/uk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/uk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 9ad5b6f..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/uk/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_CN/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_CN/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 6aea16b..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_CN/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_TW/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_TW/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo deleted file mode 100644 index 10f2db4..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/locale/zh_TW/LC_MESSAGES/org.gnome.Shell.Extensions.GSConnect.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/metadata.json b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/metadata.json deleted file mode 100644 index b3bc99a..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/metadata.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "GSConnect is a complete implementation of KDE Connect especially for GNOME Shell with Nautilus, Chrome and Firefox integration. It does not rely on the KDE Connect desktop application and will not work with it installed.\n\nKDE Connect allows devices to securely share content like notifications or files and other features like SMS messaging and remote control. The KDE Connect team has applications for Linux, BSD, Android, Sailfish and Windows.\n\nPlease report issues on Github!", - "name": "GSConnect", - "shell-version": [ - "41" - ], - "url": "https://github.com/andyholmes/gnome-shell-extension-gsconnect/wiki", - "uuid": "gsconnect@andyholmes.github.io", - "version": 48 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/nautilus-gsconnect.py b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/nautilus-gsconnect.py deleted file mode 100644 index aa13446..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/nautilus-gsconnect.py +++ /dev/null @@ -1,183 +0,0 @@ -""" -nautilus-gsconnect.py - A Nautilus extension for sending files via GSConnect. - -A great deal of credit and appreciation is owed to the indicator-kdeconnect -developers for the sister Python script 'kdeconnect-send-nautilus.py': - -https://github.com/Bajoja/indicator-kdeconnect/blob/master/data/extensions/kdeconnect-send-nautilus.py -""" - -import gettext -import os.path -import sys - -import gi -gi.require_version('Gio', '2.0') -gi.require_version('GLib', '2.0') -gi.require_version('GObject', '2.0') -from gi.repository import Gio, GLib, GObject - - -# Host application detection -# -# Nemo seems to reliably identify itself as 'nemo' in argv[0], so we -# can test for that. Nautilus detection is less reliable, so don't try. -# See https://github.com/linuxmint/nemo-extensions/issues/330 -if "nemo" in sys.argv[0].lower(): - # Host runtime is nemo-python - gi.require_version('Nemo', '3.0') - from gi.repository import Nemo as FileManager -else: - # Otherwise, just assume it's nautilus-python - gi.require_version('Nautilus', '3.0') - from gi.repository import Nautilus as FileManager - - -SERVICE_NAME = 'org.gnome.Shell.Extensions.GSConnect' -SERVICE_PATH = '/org/gnome/Shell/Extensions/GSConnect' - -# Init gettext translations -LOCALE_DIR = os.path.join(GLib.get_user_data_dir(), - 'gnome-shell', 'extensions', - 'gsconnect@andyholmes.github.io', 'locale') - -if not os.path.exists(LOCALE_DIR): - LOCALE_DIR = None - -try: - i18n = gettext.translation(SERVICE_NAME, - localedir=LOCALE_DIR) - _ = i18n.gettext - -except (IOError, OSError) as e: - print('GSConnect: {0}'.format(e.strerror)) - i18n = gettext.translation(SERVICE_NAME, - localedir=LOCALE_DIR, - fallback=True) - _ = i18n.gettext - - -class GSConnectShareExtension(GObject.Object, FileManager.MenuProvider): - """A context menu for sending files via GSConnect.""" - - def __init__(self): - """Initialize the DBus ObjectManager""" - - GObject.Object.__init__(self) - - self.devices = {} - - Gio.DBusProxy.new_for_bus(Gio.BusType.SESSION, - Gio.DBusProxyFlags.DO_NOT_AUTO_START, - None, - SERVICE_NAME, - SERVICE_PATH, - 'org.freedesktop.DBus.ObjectManager', - None, - self._init_async, - None) - - def _init_async(self, proxy, res, user_data): - proxy = proxy.new_for_bus_finish(res) - proxy.connect('notify::g-name-owner', self._on_name_owner_changed) - proxy.connect('g-signal', self._on_g_signal) - - self._on_name_owner_changed(proxy, None) - - def _on_g_signal(self, proxy, sender_name, signal_name, parameters): - # Wait until the service is ready - if proxy.props.g_name_owner is None: - return - - objects = parameters.unpack() - - if signal_name == 'InterfacesAdded': - for object_path, props in objects.items(): - props = props['org.gnome.Shell.Extensions.GSConnect.Device'] - - self.devices[object_path] = (props['Name'], - Gio.DBusActionGroup.get( - proxy.get_connection(), - SERVICE_NAME, - object_path)) - elif signal_name == 'InterfacesRemoved': - for object_path in objects: - try: - del self.devices[object_path] - except KeyError: - pass - - def _on_name_owner_changed(self, proxy, pspec): - # Wait until the service is ready - if proxy.props.g_name_owner is None: - self.devices = {} - else: - proxy.call('GetManagedObjects', - None, - Gio.DBusCallFlags.NO_AUTO_START, - -1, - None, - self._get_managed_objects, - None) - - def _get_managed_objects(self, proxy, res, user_data): - objects = proxy.call_finish(res)[0] - - for object_path, props in objects.items(): - props = props['org.gnome.Shell.Extensions.GSConnect.Device'] - - self.devices[object_path] = (props['Name'], - Gio.DBusActionGroup.get( - proxy.get_connection(), - SERVICE_NAME, - object_path)) - - def send_files(self, menu, files, action_group): - """Send *files* to *device_id*""" - - for file in files: - variant = GLib.Variant('(sb)', (file.get_uri(), False)) - action_group.activate_action('shareFile', variant) - - def get_file_items(self, window, files): - """Return a list of select files to be sent""" - - # Only accept regular files - for uri in files: - if uri.get_uri_scheme() != 'file' or uri.is_directory(): - return () - - # Enumerate capable devices - devices = [] - - for name, action_group in self.devices.values(): - if action_group.get_action_enabled('shareFile'): - devices.append([name, action_group]) - - # No capable devices; don't show menu entry - if not devices: - return () - - # Context Menu Item - menu = FileManager.MenuItem( - name='GSConnectShareExtension::Devices', - label=_('Send To Mobile Device') - ) - - # Context Submenu - submenu = FileManager.Menu() - menu.set_submenu(submenu) - - # Context Submenu Items - for name, action_group in devices: - item = FileManager.MenuItem( - name='GSConnectShareExtension::Device' + name, - label=name - ) - - item.connect('activate', self.send_files, files, action_group) - - submenu.append_item(item) - - return (menu,) - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/org.gnome.Shell.Extensions.GSConnect.gresource b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/org.gnome.Shell.Extensions.GSConnect.gresource deleted file mode 100644 index 233db30..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/org.gnome.Shell.Extensions.GSConnect.gresource and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/__init__.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/__init__.js deleted file mode 100644 index 355df3e..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/__init__.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -const Gettext = imports.gettext; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; - -const Config = imports.config; - - -// Ensure config.js is setup properly -const userDir = GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']); - -if (Config.PACKAGE_DATADIR.startsWith(userDir)) { - Config.IS_USER = true; - - Config.PACKAGE_LOCALEDIR = `${Config.PACKAGE_DATADIR}/locale`; - Config.GSETTINGS_SCHEMA_DIR = `${Config.PACKAGE_DATADIR}/schemas`; -} - - -// Init Gettext -String.prototype.format = imports.format.format; -Gettext.bindtextdomain(Config.APP_ID, Config.PACKAGE_LOCALEDIR); -globalThis._ = GLib.dgettext.bind(null, Config.APP_ID); -globalThis.ngettext = GLib.dngettext.bind(null, Config.APP_ID); - - -// Init GResources -Gio.Resource.load( - GLib.build_filenamev([Config.PACKAGE_DATADIR, `${Config.APP_ID}.gresource`]) -)._register(); - - -// Init GSchema -Config.GSCHEMA = Gio.SettingsSchemaSource.new_from_directory( - Config.GSETTINGS_SCHEMA_DIR, - Gio.SettingsSchemaSource.get_default(), - false -); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/device.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/device.js deleted file mode 100644 index e647907..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/device.js +++ /dev/null @@ -1,1108 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; -const Pango = imports.gi.Pango; - -const Config = imports.config; -const Keybindings = imports.preferences.keybindings; - - -// Build a list of plugins and shortcuts for devices -const DEVICE_PLUGINS = []; -const DEVICE_SHORTCUTS = {}; - -for (const name in imports.service.plugins) { - const module = imports.service.plugins[name]; - - // Plugins - DEVICE_PLUGINS.push(name); - - // Shortcuts (GActions without parameters) - for (const [name, action] of Object.entries(module.Metadata.actions)) { - if (action.parameter_type === null) - DEVICE_SHORTCUTS[name] = [action.icon_name, action.label]; - } -} - - -/** - * A Gtk.ListBoxHeaderFunc for sections that adds separators between each row. - * - * @param {Gtk.ListBoxRow} row - The current row - * @param {Gtk.ListBoxRow} before - The previous row - */ -function rowSeparators(row, before) { - const header = row.get_header(); - - if (before === null) { - if (header !== null) - header.destroy(); - - return; - } - - if (header === null) - row.set_header(new Gtk.Separator({visible: true})); -} - - -/** - * A Gtk.ListBoxSortFunc for SectionRow rows - * - * @param {Gtk.ListBoxRow} row1 - The first row - * @param {Gtk.ListBoxRow} row2 - The second row - * @return {number} -1, 0 or 1 - */ -function titleSortFunc(row1, row2) { - if (!row1.title || !row2.title) - return 0; - - return row1.title.localeCompare(row2.title); -} - - -/** - * A row for a section of settings - */ -const SectionRow = GObject.registerClass({ - GTypeName: 'GSConnectPreferencesSectionRow', - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/preferences-section-row.ui', - Children: ['icon-image', 'title-label', 'subtitle-label'], - Properties: { - 'gicon': GObject.ParamSpec.object( - 'gicon', - 'GIcon', - 'A GIcon for the row', - GObject.ParamFlags.READWRITE, - Gio.Icon.$gtype - ), - 'icon-name': GObject.ParamSpec.string( - 'icon-name', - 'Icon Name', - 'An icon name for the row', - GObject.ParamFlags.READWRITE, - null - ), - 'subtitle': GObject.ParamSpec.string( - 'subtitle', - 'Subtitle', - 'A subtitle for the row', - GObject.ParamFlags.READWRITE, - null - ), - 'title': GObject.ParamSpec.string( - 'title', - 'Title', - 'A title for the row', - GObject.ParamFlags.READWRITE, - null - ), - 'widget': GObject.ParamSpec.object( - 'widget', - 'Widget', - 'An action widget for the row', - GObject.ParamFlags.READWRITE, - Gtk.Widget.$gtype - ), - }, -}, class SectionRow extends Gtk.ListBoxRow { - - _init(params = {}) { - super._init(); - - // NOTE: we can't pass construct properties to _init() because the - // template children are not assigned until after it runs. - this.freeze_notify(); - Object.assign(this, params); - this.thaw_notify(); - } - - get icon_name() { - return this.icon_image.icon_name; - } - - set icon_name(icon_name) { - if (this.icon_name === icon_name) - return; - - this.icon_image.visible = !!icon_name; - this.icon_image.icon_name = icon_name; - this.notify('icon-name'); - } - - get gicon() { - return this.icon_image.gicon; - } - - set gicon(gicon) { - if (this.gicon === gicon) - return; - - this.icon_image.visible = !!gicon; - this.icon_image.gicon = gicon; - this.notify('gicon'); - } - - get title() { - return this.title_label.label; - } - - set title(text) { - if (this.title === text) - return; - - this.title_label.visible = !!text; - this.title_label.label = text; - this.notify('title'); - } - - get subtitle() { - return this.subtitle_label.label; - } - - set subtitle(text) { - if (this.subtitle === text) - return; - - this.subtitle_label.visible = !!text; - this.subtitle_label.label = text; - this.notify('subtitle'); - } - - get widget() { - if (this._widget === undefined) - this._widget = null; - - return this._widget; - } - - set widget(widget) { - if (this.widget === widget) - return; - - if (this.widget instanceof Gtk.Widget) - this.widget.destroy(); - - // Add the widget - this._widget = widget; - this.get_child().attach(widget, 2, 0, 1, 2); - this.notify('widget'); - } -}); - - -/** - * Command Editor Dialog - */ -const CommandEditor = GObject.registerClass({ - GTypeName: 'GSConnectPreferencesCommandEditor', - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/preferences-command-editor.ui', - Children: [ - 'cancel-button', 'save-button', - 'command-entry', 'name-entry', 'command-chooser', - ], -}, class CommandEditor extends Gtk.Dialog { - - _onBrowseCommand(entry, icon_pos, event) { - this.command_chooser.present(); - } - - _onCommandChosen(dialog, response_id) { - if (response_id === Gtk.ResponseType.OK) - this.command_entry.text = dialog.get_filename(); - - dialog.hide(); - } - - _onEntryChanged(entry, pspec) { - this.save_button.sensitive = (this.command_name && this.command_line); - } - - get command_line() { - return this.command_entry.text; - } - - set command_line(text) { - this.command_entry.text = text; - } - - get command_name() { - return this.name_entry.text; - } - - set command_name(text) { - this.name_entry.text = text; - } -}); - - -/** - * A widget for configuring a remote device. - */ -var Panel = GObject.registerClass({ - GTypeName: 'GSConnectPreferencesDevicePanel', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device being configured', - GObject.ParamFlags.READWRITE, - GObject.Object.$gtype - ), - }, - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/preferences-device-panel.ui', - Children: [ - 'sidebar', 'stack', 'infobar', - - // Sharing - 'sharing', 'sharing-page', - 'desktop-list', 'clipboard', 'clipboard-sync', 'mousepad', 'mpris', 'systemvolume', - 'share', 'share-list', 'receive-files', 'receive-directory', - - // Battery - 'battery', - 'battery-device-label', 'battery-device', 'battery-device-list', - 'battery-system-label', 'battery-system', 'battery-system-list', - 'battery-custom-notification-value', - - // RunCommand - 'runcommand', 'runcommand-page', - 'command-list', 'command-add', - - // Notifications - 'notification', 'notification-page', - 'notification-list', 'notification-apps', - - // Telephony - 'telephony', 'telephony-page', - 'ringing-list', 'ringing-volume', 'talking-list', 'talking-volume', - - // Shortcuts - 'shortcuts-page', - 'shortcuts-actions', 'shortcuts-actions-title', 'shortcuts-actions-list', - - // Advanced - 'advanced-page', - 'plugin-list', 'experimental-list', - - 'device-menu', - ], -}, class Panel extends Gtk.Grid { - - _init(device) { - super._init({ - device: device, - }); - - // GSettings - this.settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup( - 'org.gnome.Shell.Extensions.GSConnect.Device', - true - ), - path: `/org/gnome/shell/extensions/gsconnect/device/${device.id}/`, - }); - - // Infobar - this.device.bind_property( - 'paired', - this.infobar, - 'reveal-child', - (GObject.BindingFlags.SYNC_CREATE | - GObject.BindingFlags.INVERT_BOOLEAN) - ); - - this._setupActions(); - - // Settings Pages - this._sharingSettings(); - this._batterySettings(); - this._runcommandSettings(); - this._notificationSettings(); - this._telephonySettings(); - // -------------------------- - this._keybindingSettings(); - this._advancedSettings(); - - // Separate plugins and other settings - this.sidebar.set_header_func((row, before) => { - if (row.get_name() === 'shortcuts') - row.set_header(new Gtk.Separator({visible: true})); - }); - } - - get menu() { - if (this._menu === undefined) { - this._menu = this.device_menu; - this._menu.prepend_section(null, this.device.menu); - this.insert_action_group('device', this.device.action_group); - } - - return this._menu; - } - - get_incoming_supported(type) { - const incoming = this.settings.get_strv('incoming-capabilities'); - return incoming.includes(`kdeconnect.${type}`); - } - - get_outgoing_supported(type) { - const outgoing = this.settings.get_strv('outgoing-capabilities'); - return outgoing.includes(`kdeconnect.${type}`); - } - - _onKeynavFailed(widget, direction) { - if (direction === Gtk.DirectionType.UP && widget.prev) - widget.prev.child_focus(direction); - - else if (direction === Gtk.DirectionType.DOWN && widget.next) - widget.next.child_focus(direction); - - return true; - } - - _onSwitcherRowSelected(box, row) { - this.stack.set_visible_child_name(row.get_name()); - } - - _onSectionRowActivated(box, row) { - if (row.widget !== undefined) - row.widget.active = !row.widget.active; - } - - _onToggleRowActivated(box, row) { - const widget = row.get_child().get_child_at(1, 0); - widget.active = !widget.active; - } - - _onEncryptionInfo() { - const dialog = new Gtk.MessageDialog({ - buttons: Gtk.ButtonsType.OK, - text: _('Encryption Info'), - secondary_text: this.device.encryption_info, - modal: true, - transient_for: this.get_toplevel(), - }); - dialog.connect('response', (dialog) => dialog.destroy()); - dialog.present(); - } - - _deviceAction(action, parameter) { - this.action_group.activate_action(action.name, parameter); - } - - dispose() { - if (this._commandEditor !== undefined) - this._commandEditor.destroy(); - - // Device signals - this.device.action_group.disconnect(this._actionAddedId); - this.device.action_group.disconnect(this._actionRemovedId); - - // GSettings - for (const settings of Object.values(this._pluginSettings)) - settings.run_dispose(); - - this.settings.disconnect(this._keybindingsId); - this.settings.disconnect(this._disabledPluginsId); - this.settings.disconnect(this._supportedPluginsId); - this.settings.run_dispose(); - } - - pluginSettings(name) { - if (this._pluginSettings === undefined) - this._pluginSettings = {}; - - if (!this._pluginSettings.hasOwnProperty(name)) { - const meta = imports.service.plugins[name].Metadata; - - this._pluginSettings[name] = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup(meta.id, -1), - path: `${this.settings.path}plugin/${name}/`, - }); - } - - return this._pluginSettings[name]; - } - - _setupActions() { - this.actions = new Gio.SimpleActionGroup(); - this.insert_action_group('settings', this.actions); - - let settings = this.pluginSettings('battery'); - this.actions.add_action(settings.create_action('send-statistics')); - this.actions.add_action(settings.create_action('low-battery-notification')); - this.actions.add_action(settings.create_action('custom-battery-notification')); - this.actions.add_action(settings.create_action('custom-battery-notification-value')); - this.actions.add_action(settings.create_action('full-battery-notification')); - - settings = this.pluginSettings('clipboard'); - this.actions.add_action(settings.create_action('send-content')); - this.actions.add_action(settings.create_action('receive-content')); - - settings = this.pluginSettings('contacts'); - this.actions.add_action(settings.create_action('contacts-source')); - - settings = this.pluginSettings('mousepad'); - this.actions.add_action(settings.create_action('share-control')); - - settings = this.pluginSettings('mpris'); - this.actions.add_action(settings.create_action('share-players')); - - settings = this.pluginSettings('notification'); - this.actions.add_action(settings.create_action('send-notifications')); - this.actions.add_action(settings.create_action('send-active')); - - settings = this.pluginSettings('photo'); - this.actions.add_action(settings.create_action('share-camera')); - - settings = this.pluginSettings('sftp'); - this.actions.add_action(settings.create_action('automount')); - - settings = this.pluginSettings('share'); - this.actions.add_action(settings.create_action('receive-files')); - - settings = this.pluginSettings('sms'); - this.actions.add_action(settings.create_action('legacy-sms')); - - settings = this.pluginSettings('systemvolume'); - this.actions.add_action(settings.create_action('share-sinks')); - - settings = this.pluginSettings('telephony'); - this.actions.add_action(settings.create_action('ringing-volume')); - this.actions.add_action(settings.create_action('ringing-pause')); - this.actions.add_action(settings.create_action('talking-volume')); - this.actions.add_action(settings.create_action('talking-pause')); - this.actions.add_action(settings.create_action('talking-microphone')); - - // Pair Actions - const encryption_info = new Gio.SimpleAction({name: 'encryption-info'}); - encryption_info.connect('activate', this._onEncryptionInfo.bind(this)); - this.actions.add_action(encryption_info); - - const status_pair = new Gio.SimpleAction({name: 'pair'}); - status_pair.connect('activate', this._deviceAction.bind(this.device)); - this.settings.bind('paired', status_pair, 'enabled', 16); - this.actions.add_action(status_pair); - - const status_unpair = new Gio.SimpleAction({name: 'unpair'}); - status_unpair.connect('activate', this._deviceAction.bind(this.device)); - this.settings.bind('paired', status_unpair, 'enabled', 0); - this.actions.add_action(status_unpair); - } - - /** - * Sharing Settings - */ - _sharingSettings() { - // Share Plugin - const settings = this.pluginSettings('share'); - - settings.connect( - 'changed::receive-directory', - this._onReceiveDirectoryChanged.bind(this) - ); - this._onReceiveDirectoryChanged(settings, 'receive-directory'); - - // Visibility - this.desktop_list.foreach(row => { - const name = row.get_name(); - row.visible = this.get_outgoing_supported(`${name}.request`); - }); - - // Separators & Sorting - this.desktop_list.set_header_func(rowSeparators); - - this.desktop_list.set_sort_func((row1, row2) => { - row1 = row1.get_child().get_child_at(0, 0); - row2 = row2.get_child().get_child_at(0, 0); - return row1.label.localeCompare(row2.label); - }); - this.share_list.set_header_func(rowSeparators); - - // Scroll with keyboard focus - const sharing_box = this.sharing_page.get_child().get_child(); - sharing_box.set_focus_vadjustment(this.sharing_page.vadjustment); - - // Continue focus chain between lists - this.desktop_list.next = this.share_list; - this.share_list.prev = this.desktop_list; - } - - _onReceiveDirectoryChanged(settings, key) { - let receiveDir = settings.get_string(key); - - if (receiveDir.length === 0) { - receiveDir = GLib.get_user_special_dir( - GLib.UserDirectory.DIRECTORY_DOWNLOAD - ); - - // Account for some corner cases with a fallback - const homeDir = GLib.get_home_dir(); - - if (!receiveDir || receiveDir === homeDir) - receiveDir = GLib.build_filenamev([homeDir, 'Downloads']); - - settings.set_string(key, receiveDir); - } - - if (this.receive_directory.get_filename() !== receiveDir) - this.receive_directory.set_filename(receiveDir); - } - - _onReceiveDirectorySet(button) { - const settings = this.pluginSettings('share'); - const receiveDir = settings.get_string('receive-directory'); - const filename = button.get_filename(); - - if (filename !== receiveDir) - settings.set_string('receive-directory', filename); - } - - /** - * Battery Settings - */ - async _batterySettings() { - try { - this.battery_device_list.set_header_func(rowSeparators); - this.battery_system_list.set_header_func(rowSeparators); - const settings = this.pluginSettings('battery'); - const oldLevel = settings.get_uint('custom-battery-notification-value'); - this.battery_custom_notification_value.set_value(oldLevel); - - // If the device can't handle statistics we're done - if (!this.get_incoming_supported('battery')) { - this.battery_system_label.visible = false; - this.battery_system.visible = false; - return; - } - - // Check UPower for a battery - const hasBattery = await new Promise((resolve, reject) => { - Gio.DBus.system.call( - 'org.freedesktop.UPower', - '/org/freedesktop/UPower/devices/DisplayDevice', - 'org.freedesktop.DBus.Properties', - 'Get', - new GLib.Variant('(ss)', [ - 'org.freedesktop.UPower.Device', - 'IsPresent', - ]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - const variant = connection.call_finish(res); - const value = variant.deepUnpack()[0]; - const isPresent = value.get_boolean(); - - resolve(isPresent); - } catch (e) { - resolve(false); - } - } - ); - }); - - this.battery_system_label.visible = hasBattery; - this.battery_system.visible = hasBattery; - } catch (e) { - this.battery_system_label.visible = false; - this.battery_system.visible = false; - } - } - - _setCustomChargeLevel(spin) { - const settings = this.pluginSettings('battery'); - settings.set_uint('custom-battery-notification-value', spin.get_value_as_int()); - } - - /** - * RunCommand Page - */ - _runcommandSettings() { - // Scroll with keyboard focus - const runcommand_box = this.runcommand_page.get_child().get_child(); - runcommand_box.set_focus_vadjustment(this.runcommand_page.vadjustment); - - // Local Command List - const settings = this.pluginSettings('runcommand'); - this._commands = settings.get_value('command-list').recursiveUnpack(); - - this.command_list.set_sort_func(this._sortCommands); - this.command_list.set_header_func(rowSeparators); - - for (const uuid of Object.keys(this._commands)) - this._insertCommand(uuid); - } - - _sortCommands(row1, row2) { - if (!row1.title || !row2.title) - return 1; - - return row1.title.localeCompare(row2.title); - } - - _insertCommand(uuid) { - const row = new SectionRow({ - title: this._commands[uuid].name, - subtitle: this._commands[uuid].command, - activatable: false, - }); - row.set_name(uuid); - row.subtitle_label.ellipsize = Pango.EllipsizeMode.MIDDLE; - - const editButton = new Gtk.Button({ - image: new Gtk.Image({ - icon_name: 'document-edit-symbolic', - pixel_size: 16, - visible: true, - }), - tooltip_text: _('Edit'), - valign: Gtk.Align.CENTER, - vexpand: true, - visible: true, - }); - editButton.connect('clicked', this._onEditCommand.bind(this)); - editButton.get_accessible().set_name(_('Edit')); - row.get_child().attach(editButton, 2, 0, 1, 2); - - const deleteButton = new Gtk.Button({ - image: new Gtk.Image({ - icon_name: 'edit-delete-symbolic', - pixel_size: 16, - visible: true, - }), - tooltip_text: _('Remove'), - valign: Gtk.Align.CENTER, - vexpand: true, - visible: true, - }); - deleteButton.connect('clicked', this._onDeleteCommand.bind(this)); - deleteButton.get_accessible().set_name(_('Remove')); - row.get_child().attach(deleteButton, 3, 0, 1, 2); - - this.command_list.add(row); - } - - _onEditCommand(widget) { - if (this._commandEditor === undefined) { - this._commandEditor = new CommandEditor({ - modal: true, - transient_for: this.get_toplevel(), - use_header_bar: true, - }); - - this._commandEditor.connect( - 'response', - this._onSaveCommand.bind(this) - ); - - this._commandEditor.resize(1, 1); - } - - if (widget instanceof Gtk.Button) { - const row = widget.get_ancestor(Gtk.ListBoxRow.$gtype); - const uuid = row.get_name(); - - this._commandEditor.uuid = uuid; - this._commandEditor.command_name = this._commands[uuid].name; - this._commandEditor.command_line = this._commands[uuid].command; - } else { - this._commandEditor.uuid = GLib.uuid_string_random(); - this._commandEditor.command_name = ''; - this._commandEditor.command_line = ''; - } - - this._commandEditor.present(); - } - - _storeCommands() { - const variant = {}; - - for (const [uuid, command] of Object.entries(this._commands)) - variant[uuid] = new GLib.Variant('a{ss}', command); - - this.pluginSettings('runcommand').set_value( - 'command-list', - new GLib.Variant('a{sv}', variant) - ); - } - - _onDeleteCommand(button) { - const row = button.get_ancestor(Gtk.ListBoxRow.$gtype); - delete this._commands[row.get_name()]; - row.destroy(); - - this._storeCommands(); - } - - _onSaveCommand(dialog, response_id) { - if (response_id === Gtk.ResponseType.ACCEPT) { - this._commands[dialog.uuid] = { - name: dialog.command_name, - command: dialog.command_line, - }; - - this._storeCommands(); - - // - let row = null; - - for (const child of this.command_list.get_children()) { - if (child.get_name() === dialog.uuid) { - row = child; - break; - } - } - - if (row === null) { - this._insertCommand(dialog.uuid); - } else { - row.set_name(dialog.uuid); - row.title = dialog.command_name; - row.subtitle = dialog.command_line; - } - } - - dialog.hide(); - } - - /** - * Notification Settings - */ - _notificationSettings() { - const settings = this.pluginSettings('notification'); - - settings.bind( - 'send-notifications', - this.notification_apps, - 'sensitive', - Gio.SettingsBindFlags.DEFAULT - ); - - // Separators & Sorting - this.notification_list.set_header_func(rowSeparators); - - // Scroll with keyboard focus - const notification_box = this.notification_page.get_child().get_child(); - notification_box.set_focus_vadjustment(this.notification_page.vadjustment); - - // Continue focus chain between lists - this.notification_list.next = this.notification_apps; - this.notification_apps.prev = this.notification_list; - - this.notification_apps.set_sort_func(titleSortFunc); - this.notification_apps.set_header_func(rowSeparators); - - this._populateApplications(settings); - } - - _toggleNotification(widget) { - try { - const row = widget.get_ancestor(Gtk.ListBoxRow.$gtype); - const settings = this.pluginSettings('notification'); - let applications = {}; - - try { - applications = JSON.parse(settings.get_string('applications')); - } catch (e) { - applications = {}; - } - - applications[row.title].enabled = !applications[row.title].enabled; - row.widget.state = applications[row.title].enabled; - settings.set_string('applications', JSON.stringify(applications)); - - } catch (e) { - logError(e); - } - } - - - - _populateApplications(settings) { - const applications = this._queryApplications(settings); - - for (const name in applications) { - const row = new SectionRow({ - gicon: Gio.Icon.new_for_string(applications[name].iconName), - title: name, - height_request: 48, - widget: new Gtk.Switch({ - state: applications[name].enabled, - margin_start: 12, - margin_end: 12, - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - vexpand: true, - visible: true, - }), - }); - - row.widget.connect('notify::active', this._toggleNotification.bind(this)); - this.notification_apps.add(row); - } - } - - _queryApplications(settings) { - let applications = {}; - - try { - applications = JSON.parse(settings.get_string('applications')); - } catch (e) { - applications = {}; - } - - // Scan applications that statically declare to show notifications - const ignoreId = 'org.gnome.Shell.Extensions.GSConnect.desktop'; - - for (const appInfo of Gio.AppInfo.get_all()) { - if (appInfo.get_id() === ignoreId) - continue; - - if (!appInfo.get_boolean('X-GNOME-UsesNotifications')) - continue; - - const appName = appInfo.get_name(); - - if (appName === null || applications.hasOwnProperty(appName)) - continue; - - let icon = appInfo.get_icon(); - icon = (icon) ? icon.to_string() : 'application-x-executable'; - - applications[appName] = { - iconName: icon, - enabled: true, - }; - } - - settings.set_string('applications', JSON.stringify(applications)); - - return applications; - } - - /** - * Telephony Settings - */ - _telephonySettings() { - // Continue focus chain between lists - this.ringing_list.next = this.talking_list; - this.talking_list.prev = this.ringing_list; - - this.ringing_list.set_header_func(rowSeparators); - this.talking_list.set_header_func(rowSeparators); - } - - /** - * Keyboard Shortcuts - */ - _keybindingSettings() { - // Scroll with keyboard focus - const shortcuts_box = this.shortcuts_page.get_child().get_child(); - shortcuts_box.set_focus_vadjustment(this.shortcuts_page.vadjustment); - - // Filter & Sort - this.shortcuts_actions_list.set_filter_func(this._filterPluginKeybindings.bind(this)); - this.shortcuts_actions_list.set_header_func(rowSeparators); - this.shortcuts_actions_list.set_sort_func(titleSortFunc); - - // Init - for (const name in DEVICE_SHORTCUTS) - this._addPluginKeybinding(name); - - this._setPluginKeybindings(); - - // Watch for GAction and Keybinding changes - this._actionAddedId = this.device.action_group.connect( - 'action-added', - () => this.shortcuts_actions_list.invalidate_filter() - ); - this._actionRemovedId = this.device.action_group.connect( - 'action-removed', - () => this.shortcuts_actions_list.invalidate_filter() - ); - this._keybindingsId = this.settings.connect( - 'changed::keybindings', - this._setPluginKeybindings.bind(this) - ); - } - - _addPluginKeybinding(name) { - const [icon_name, label] = DEVICE_SHORTCUTS[name]; - - const widget = new Gtk.Label({ - label: _('Disabled'), - visible: true, - }); - widget.get_style_context().add_class('dim-label'); - - const row = new SectionRow({ - height_request: 48, - icon_name: icon_name, - title: label, - widget: widget, - }); - row.icon_image.pixel_size = 16; - row.action = name; - this.shortcuts_actions_list.add(row); - } - - _filterPluginKeybindings(row) { - return this.device.action_group.has_action(row.action); - } - - _setPluginKeybindings() { - const keybindings = this.settings.get_value('keybindings').deepUnpack(); - - this.shortcuts_actions_list.foreach(row => { - if (keybindings[row.action]) { - const accel = Gtk.accelerator_parse(keybindings[row.action]); - row.widget.label = Gtk.accelerator_get_label(...accel); - } else { - row.widget.label = _('Disabled'); - } - }); - } - - _onResetActionShortcuts(button) { - const keybindings = this.settings.get_value('keybindings').deepUnpack(); - - for (const action in keybindings) { - // Don't reset remote command shortcuts - if (!action.includes('::')) - delete keybindings[action]; - } - - this.settings.set_value( - 'keybindings', - new GLib.Variant('a{ss}', keybindings) - ); - } - - async _onShortcutRowActivated(box, row) { - try { - const keybindings = this.settings.get_value('keybindings').deepUnpack(); - let accel = keybindings[row.action] || null; - - accel = await Keybindings.getAccelerator(row.title, accel); - - if (accel) - keybindings[row.action] = accel; - else - delete keybindings[row.action]; - - this.settings.set_value( - 'keybindings', - new GLib.Variant('a{ss}', keybindings) - ); - } catch (e) { - logError(e); - } - } - - /** - * Advanced Page - */ - _advancedSettings() { - // Scroll with keyboard focus - const advanced_box = this.advanced_page.get_child().get_child(); - advanced_box.set_focus_vadjustment(this.advanced_page.vadjustment); - - // Sort & Separate - this.plugin_list.set_header_func(rowSeparators); - this.plugin_list.set_sort_func(titleSortFunc); - this.experimental_list.set_header_func(rowSeparators); - - // Continue focus chain between lists - this.plugin_list.next = this.experimental_list; - this.experimental_list.prev = this.plugin_list; - - this._disabledPluginsId = this.settings.connect( - 'changed::disabled-plugins', - this._onPluginsChanged.bind(this) - ); - this._supportedPluginsId = this.settings.connect( - 'changed::supported-plugins', - this._onPluginsChanged.bind(this) - ); - this._onPluginsChanged(this.settings, null); - - for (const name of DEVICE_PLUGINS) - this._addPlugin(name); - } - - _onPluginsChanged(settings, key) { - if (key === 'disabled-plugins' || this._disabledPlugins === undefined) - this._disabledPlugins = settings.get_strv('disabled-plugins'); - - if (key === 'supported-plugins' || this._supportedPlugins === undefined) - this._supportedPlugins = settings.get_strv('supported-plugins'); - - this._enabledPlugins = this._supportedPlugins.filter(name => { - return !this._disabledPlugins.includes(name); - }); - - if (key !== null) - this._updatePlugins(); - } - - _addPlugin(name) { - const plugin = imports.service.plugins[name]; - - const row = new SectionRow({ - height_request: 48, - title: plugin.Metadata.label, - subtitle: plugin.Metadata.description || '', - visible: this._supportedPlugins.includes(name), - widget: new Gtk.Switch({ - active: this._enabledPlugins.includes(name), - valign: Gtk.Align.CENTER, - vexpand: true, - visible: true, - }), - }); - row.widget.connect('notify::active', this._togglePlugin.bind(this)); - row.set_name(name); - - if (this.hasOwnProperty(name)) - this[name].visible = row.widget.active; - - this.plugin_list.add(row); - } - - _updatePlugins(settings, key) { - for (const row of this.plugin_list.get_children()) { - const name = row.get_name(); - - row.visible = this._supportedPlugins.includes(name); - row.widget.active = this._enabledPlugins.includes(name); - - if (this.hasOwnProperty(name)) - this[name].visible = row.widget.active; - } - } - - _togglePlugin(widget) { - try { - const name = widget.get_ancestor(Gtk.ListBoxRow.$gtype).get_name(); - const index = this._disabledPlugins.indexOf(name); - - // Either add or remove the plugin from the disabled list - if (index > -1) - this._disabledPlugins.splice(index, 1); - else - this._disabledPlugins.push(name); - - this.settings.set_strv('disabled-plugins', this._disabledPlugins); - } catch (e) { - logError(e); - } - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/keybindings.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/keybindings.js deleted file mode 100644 index 3fd8322..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/keybindings.js +++ /dev/null @@ -1,312 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - - -/* - * A list of modifier keysyms we ignore - */ -const _MODIFIERS = [ - Gdk.KEY_Alt_L, - Gdk.KEY_Alt_R, - Gdk.KEY_Caps_Lock, - Gdk.KEY_Control_L, - Gdk.KEY_Control_R, - Gdk.KEY_Meta_L, - Gdk.KEY_Meta_R, - Gdk.KEY_Num_Lock, - Gdk.KEY_Shift_L, - Gdk.KEY_Shift_R, - Gdk.KEY_Super_L, - Gdk.KEY_Super_R, -]; - -/** - * Response enum for ShortcutChooserDialog - */ -var ResponseType = { - CANCEL: Gtk.ResponseType.CANCEL, - SET: Gtk.ResponseType.APPLY, - UNSET: 2, -}; - - -/** - * A simplified version of the shortcut editor from GNOME Control Center - */ -var ShortcutChooserDialog = GObject.registerClass({ - GTypeName: 'GSConnectPreferencesShortcutEditor', - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/preferences-shortcut-editor.ui', - Children: [ - 'cancel-button', 'set-button', - 'stack', 'summary-label', - 'shortcut-label', 'conflict-label', - ], -}, class ShortcutChooserDialog extends Gtk.Dialog { - - _init(params) { - super._init({ - transient_for: Gio.Application.get_default().get_active_window(), - use_header_bar: true, - }); - - this._seat = Gdk.Display.get_default().get_default_seat(); - - // Current accelerator or %null - this.accelerator = params.accelerator; - - // TRANSLATORS: Summary of a keyboard shortcut function - // Example: Enter a new shortcut to change Messaging - this.summary = _('Enter a new shortcut to change %s').format( - params.summary - ); - } - - get accelerator() { - return this.shortcut_label.accelerator; - } - - set accelerator(value) { - this.shortcut_label.accelerator = value; - } - - get summary() { - return this.summary_label.label; - } - - set summary(value) { - this.summary_label.label = value; - } - - vfunc_key_press_event(event) { - let keyvalLower = Gdk.keyval_to_lower(event.keyval); - let realMask = event.state & Gtk.accelerator_get_default_mod_mask(); - - // TODO: Critical: 'WIDGET_REALIZED_FOR_EVENT (widget, event)' failed - if (_MODIFIERS.includes(keyvalLower)) - return true; - - // Normalize Tab - if (keyvalLower === Gdk.KEY_ISO_Left_Tab) - keyvalLower = Gdk.KEY_Tab; - - // Put shift back if it changed the case of the key, not otherwise. - if (keyvalLower !== event.keyval) - realMask |= Gdk.ModifierType.SHIFT_MASK; - - // HACK: we don't want to use SysRq as a keybinding (but we do want - // Alt+Print), so we avoid translation from Alt+Print to SysRq - if (keyvalLower === Gdk.KEY_Sys_Req && (realMask & Gdk.ModifierType.MOD1_MASK) !== 0) - keyvalLower = Gdk.KEY_Print; - - // A single Escape press cancels the editing - if (realMask === 0 && keyvalLower === Gdk.KEY_Escape) { - this.response(ResponseType.CANCEL); - return false; - } - - // Backspace disables the current shortcut - if (realMask === 0 && keyvalLower === Gdk.KEY_BackSpace) { - this.response(ResponseType.UNSET); - return false; - } - - // CapsLock isn't supported as a keybinding modifier, so keep it from - // confusing us - realMask &= ~Gdk.ModifierType.LOCK_MASK; - - if (keyvalLower !== 0 && realMask !== 0) { - this._ungrab(); - - // Set the accelerator property/label - this.accelerator = Gtk.accelerator_name(keyvalLower, realMask); - - // TRANSLATORS: When a keyboard shortcut is unavailable - // Example: [Ctrl]+[S] is already being used - this.conflict_label.label = _('%s is already being used').format( - Gtk.accelerator_get_label(keyvalLower, realMask) - ); - - // Show Cancel button and switch to confirm/conflict page - this.cancel_button.visible = true; - this.stack.visible_child_name = 'confirm'; - - this._check(); - } - - return true; - } - - async _check() { - try { - const available = await checkAccelerator(this.accelerator); - this.set_button.visible = available; - this.conflict_label.visible = !available; - } catch (e) { - logError(e); - this.response(ResponseType.CANCEL); - } - } - - _grab() { - const success = this._seat.grab( - this.get_window(), - Gdk.SeatCapabilities.KEYBOARD, - true, // owner_events - null, // cursor - null, // event - null - ); - - if (success !== Gdk.GrabStatus.SUCCESS) - return this.response(ResponseType.CANCEL); - - if (!this._seat.get_keyboard() && !this._seat.get_pointer()) - return this.response(ResponseType.CANCEL); - - this.grab_add(); - } - - _ungrab() { - this._seat.ungrab(); - this.grab_remove(); - } - - // Override to use our own ungrab process - response(response_id) { - this.hide(); - this._ungrab(); - - return super.response(response_id); - } - - // Override with a non-blocking version of Gtk.Dialog.run() - run() { - this.show(); - - // Wait a bit before attempting grab - GLib.timeout_add(GLib.PRIORITY_DEFAULT, 100, () => { - this._grab(); - return GLib.SOURCE_REMOVE; - }); - } -}); - - -/** - * Check the availability of an accelerator using GNOME Shell's DBus interface. - * - * @param {string} accelerator - An accelerator - * @param {number} [modeFlags] - Mode Flags - * @param {number} [grabFlags] - Grab Flags - * @param {boolean} %true if available, %false on error or unavailable - */ -async function checkAccelerator(accelerator, modeFlags = 0, grabFlags = 0) { - try { - let result = false; - - // Try to grab the accelerator - const action = await new Promise((resolve, reject) => { - Gio.DBus.session.call( - 'org.gnome.Shell', - '/org/gnome/Shell', - 'org.gnome.Shell', - 'GrabAccelerator', - new GLib.Variant('(suu)', [accelerator, modeFlags, grabFlags]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); - - // If successful, use the result of ungrabbing as our return - if (action !== 0) { - result = await new Promise((resolve, reject) => { - Gio.DBus.session.call( - 'org.gnome.Shell', - '/org/gnome/Shell', - 'org.gnome.Shell', - 'UngrabAccelerator', - new GLib.Variant('(u)', [action]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); - } - - return result; - } catch (e) { - logError(e); - return false; - } -} - - -/** - * Show a dialog to get a keyboard shortcut from a user. - * - * @param {string} summary - A description of the keybinding's function - * @param {string} accelerator - An accelerator as taken by Gtk.ShortcutLabel - * @return {string} An accelerator or %null if it should be unset. - */ -async function getAccelerator(summary, accelerator = null) { - try { - const dialog = new ShortcutChooserDialog({ - summary: summary, - accelerator: accelerator, - }); - - accelerator = await new Promise((resolve, reject) => { - dialog.connect('response', (dialog, response) => { - switch (response) { - case ResponseType.SET: - accelerator = dialog.accelerator; - break; - - case ResponseType.UNSET: - accelerator = null; - break; - - case ResponseType.CANCEL: - // leave the accelerator as passed in - break; - } - - dialog.destroy(); - - resolve(accelerator); - }); - - dialog.run(); - }); - - return accelerator; - } catch (e) { - logError(e); - return accelerator; - } -} - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/service.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/service.js deleted file mode 100644 index d75f4f9..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/preferences/service.js +++ /dev/null @@ -1,657 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const GdkPixbuf = imports.gi.GdkPixbuf; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const Config = imports.config; -const Device = imports.preferences.device; -const Remote = imports.utils.remote; - - -/* - * Header for support logs - */ -const LOG_HEADER = new GLib.Bytes(` -GSConnect: ${Config.PACKAGE_VERSION} (${Config.IS_USER ? 'user' : 'system'}) -GJS: ${imports.system.version} -Session: ${GLib.getenv('XDG_SESSION_TYPE')} -OS: ${GLib.get_os_info('PRETTY_NAME')} --------------------------------------------------------------------------------- -`); - - -/** - * Generate a support log. - * - * @param {string} time - Start time as a string (24-hour notation) - */ -async function generateSupportLog(time) { - try { - const [file, stream] = Gio.File.new_tmp('gsconnect.XXXXXX'); - const logFile = stream.get_output_stream(); - - await new Promise((resolve, reject) => { - logFile.write_bytes_async(LOG_HEADER, 0, null, (file, res) => { - try { - resolve(file.write_bytes_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - // FIXME: BSD??? - const proc = new Gio.Subprocess({ - flags: (Gio.SubprocessFlags.STDOUT_PIPE | - Gio.SubprocessFlags.STDERR_MERGE), - argv: ['journalctl', '--no-host', '--since', time], - }); - proc.init(null); - - logFile.splice_async( - proc.get_stdout_pipe(), - Gio.OutputStreamSpliceFlags.CLOSE_TARGET, - GLib.PRIORITY_DEFAULT, - null, - (source, res) => { - try { - source.splice_finish(res); - } catch (e) { - logError(e); - } - } - ); - - await new Promise((resolve, reject) => { - proc.wait_check_async(null, (proc, res) => { - try { - resolve(proc.wait_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - const uri = file.get_uri(); - Gio.AppInfo.launch_default_for_uri_async(uri, null, null, null); - } catch (e) { - logError(e); - } -} - - -/** - * "Connect to..." Dialog - */ -var ConnectDialog = GObject.registerClass({ - GTypeName: 'GSConnectConnectDialog', - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/connect-dialog.ui', - Children: [ - 'cancel-button', 'connect-button', - 'lan-grid', 'lan-ip', 'lan-port', - ], -}, class ConnectDialog extends Gtk.Dialog { - - _init(params = {}) { - super._init(Object.assign({ - use_header_bar: true, - }, params)); - } - - vfunc_response(response_id) { - if (response_id === Gtk.ResponseType.OK) { - try { - let address; - - // Lan host/port entered - if (this.lan_ip.text) { - const host = this.lan_ip.text; - const port = this.lan_port.value; - address = GLib.Variant.new_string(`lan://${host}:${port}`); - } else { - return false; - } - - this.application.activate_action('connect', address); - } catch (e) { - logError(e); - } - } - - this.destroy(); - return false; - } -}); - - -function rowSeparators(row, before) { - const header = row.get_header(); - - if (before === null) { - if (header !== null) - header.destroy(); - - return; - } - - if (header === null) - row.set_header(new Gtk.Separator({visible: true})); -} - - -var Window = GObject.registerClass({ - GTypeName: 'GSConnectPreferencesWindow', - Properties: { - 'display-mode': GObject.ParamSpec.string( - 'display-mode', - 'Display Mode', - 'Display devices in either the Panel or User Menu', - GObject.ParamFlags.READWRITE, - null - ), - }, - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/preferences-window.ui', - Children: [ - // HeaderBar - 'headerbar', 'infobar', 'stack', - 'service-menu', 'service-edit', 'refresh-button', - 'device-menu', 'prev-button', - - // Popover - 'rename-popover', 'rename', 'rename-label', 'rename-entry', 'rename-submit', - - // Focus Box - 'service-window', 'service-box', - - // Device List - 'device-list', 'device-list-spinner', 'device-list-placeholder', - ], -}, class PreferencesWindow extends Gtk.ApplicationWindow { - - _init(params = {}) { - super._init(params); - - // Service Settings - this.settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup( - 'org.gnome.Shell.Extensions.GSConnect', - true - ), - }); - - // Service Proxy - this.service = new Remote.Service(); - - this._deviceAddedId = this.service.connect( - 'device-added', - this._onDeviceAdded.bind(this) - ); - - this._deviceRemovedId = this.service.connect( - 'device-removed', - this._onDeviceRemoved.bind(this) - ); - - this._serviceChangedId = this.service.connect( - 'notify::active', - this._onServiceChanged.bind(this) - ); - - // HeaderBar (Service Name) - this.headerbar.title = this.settings.get_string('name'); - this.rename_entry.text = this.headerbar.title; - - // Scroll with keyboard focus - this.service_box.set_focus_vadjustment(this.service_window.vadjustment); - - // Device List - this.device_list.set_header_func(rowSeparators); - - // Discoverable InfoBar - this.settings.bind( - 'discoverable', - this.infobar, - 'reveal-child', - Gio.SettingsBindFlags.INVERT_BOOLEAN - ); - this.add_action(this.settings.create_action('discoverable')); - - // Application Menu - this._initMenu(); - - // Broadcast automatically every 5 seconds if there are no devices yet - this._refreshSource = GLib.timeout_add_seconds( - GLib.PRIORITY_DEFAULT, - 5, - this._refresh.bind(this) - ); - - // Restore window size/maximized/position - this._restoreGeometry(); - - // Prime the service - this._initService(); - } - - get display_mode() { - if (this.settings.get_boolean('show-indicators')) - return 'panel'; - - return 'user-menu'; - } - - set display_mode(mode) { - this.settings.set_boolean('show-indicators', (mode === 'panel')); - } - - vfunc_delete_event(event) { - if (this.service) { - this.service.disconnect(this._deviceAddedId); - this.service.disconnect(this._deviceRemovedId); - this.service.disconnect(this._serviceChangedId); - this.service.destroy(); - this.service = null; - } - - this._saveGeometry(); - GLib.source_remove(this._refreshSource); - - return false; - } - - async _initService() { - try { - this.refresh_button.grab_focus(); - - this._onServiceChanged(this.service, null); - await this.service.reload(); - } catch (e) { - logError(e, 'GSConnect'); - } - } - - _initMenu() { - // Panel/User Menu mode - const displayMode = new Gio.PropertyAction({ - name: 'display-mode', - property_name: 'display-mode', - object: this, - }); - this.add_action(displayMode); - - // About Dialog - const aboutDialog = new Gio.SimpleAction({name: 'about'}); - aboutDialog.connect('activate', this._aboutDialog.bind(this)); - this.add_action(aboutDialog); - - // "Connect to..." Dialog - const connectDialog = new Gio.SimpleAction({name: 'connect'}); - connectDialog.connect('activate', this._connectDialog.bind(this)); - this.add_action(connectDialog); - - // "Generate Support Log" GAction - const generateSupportLog = new Gio.SimpleAction({name: 'support-log'}); - generateSupportLog.connect('activate', this._generateSupportLog.bind(this)); - this.add_action(generateSupportLog); - - // "Help" GAction - const help = new Gio.SimpleAction({name: 'help'}); - help.connect('activate', this._help); - this.add_action(help); - } - - _refresh() { - if (this.service.active && this.device_list.get_children().length < 1) { - this.device_list_spinner.active = true; - this.service.activate_action('refresh', null); - } else { - this.device_list_spinner.active = false; - } - - return GLib.SOURCE_CONTINUE; - } - - /* - * Window State - */ - _restoreGeometry() { - this._windowState = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup( - 'org.gnome.Shell.Extensions.GSConnect.WindowState', - true - ), - path: '/org/gnome/shell/extensions/gsconnect/preferences/', - }); - - // Size - const [width, height] = this._windowState.get_value('window-size').deepUnpack(); - - if (width && height) - this.set_default_size(width, height); - - // Maximized State - if (this._windowState.get_boolean('window-maximized')) - this.maximize(); - } - - _saveGeometry() { - const state = this.get_window().get_state(); - - // Maximized State - const maximized = (state & Gdk.WindowState.MAXIMIZED); - this._windowState.set_boolean('window-maximized', maximized); - - // Leave the size at the value before maximizing - if (maximized || (state & Gdk.WindowState.FULLSCREEN)) - return; - - // Size - const size = this.get_size(); - this._windowState.set_value('window-size', new GLib.Variant('(ii)', size)); - } - - /** - * About Dialog - */ - _aboutDialog() { - if (this._about === undefined) { - this._about = new Gtk.AboutDialog({ - application: Gio.Application.get_default(), - authors: [ - 'Andy Holmes ', - 'Bertrand Lacoste ', - 'Frank Dana ', - ], - comments: _('A complete KDE Connect implementation for GNOME'), - logo: GdkPixbuf.Pixbuf.new_from_resource_at_scale( - '/org/gnome/Shell/Extensions/GSConnect/icons/org.gnome.Shell.Extensions.GSConnect.svg', - 128, - 128, - true - ), - program_name: 'GSConnect', - // TRANSLATORS: eg. 'Translator Name ' - translator_credits: _('translator-credits'), - version: Config.PACKAGE_VERSION.toString(), - website: Config.PACKAGE_URL, - license_type: Gtk.License.GPL_2_0, - modal: true, - transient_for: this, - }); - - // Persist - this._about.connect('response', (dialog) => dialog.hide_on_delete()); - this._about.connect('delete-event', (dialog) => dialog.hide_on_delete()); - } - - this._about.present(); - } - - /** - * Connect to..." Dialog - */ - _connectDialog() { - new ConnectDialog({ - application: Gio.Application.get_default(), - modal: true, - transient_for: this, - }); - } - - /* - * "Generate Support Log" GAction - */ - _generateSupportLog() { - const dialog = new Gtk.MessageDialog({ - text: _('Generate Support Log'), - secondary_text: _('Debug messages are being logged. Take any steps necessary to reproduce a problem then review the log.'), - }); - dialog.add_button(_('Cancel'), Gtk.ResponseType.CANCEL); - dialog.add_button(_('Review Log'), Gtk.ResponseType.OK); - - // Enable debug logging and mark the current time - this.settings.set_boolean('debug', true); - const now = GLib.DateTime.new_now_local().format('%R'); - - dialog.connect('response', (dialog, response_id) => { - // Disable debug logging and destroy the dialog - this.settings.set_boolean('debug', false); - dialog.destroy(); - - // Only generate a log if instructed - if (response_id === Gtk.ResponseType.OK) - generateSupportLog(now); - }); - - dialog.show_all(); - } - - /* - * "Help" GAction - */ - _help(action, parameter) { - const uri = `${Config.PACKAGE_URL}/wiki/Help`; - Gio.AppInfo.launch_default_for_uri_async(uri, null, null, null); - } - - /* - * HeaderBar Callbacks - */ - _onPrevious(button, event) { - // HeaderBar (Service) - this.prev_button.visible = false; - this.device_menu.visible = false; - - this.refresh_button.visible = true; - this.service_edit.visible = true; - this.service_menu.visible = true; - - this.headerbar.title = this.settings.get_string('name'); - this.headerbar.subtitle = null; - - // Panel - this.stack.visible_child_name = 'service'; - this._setDeviceMenu(); - } - - _onEditServiceName(button, event) { - this.rename_entry.text = this.headerbar.title; - this.rename_entry.has_focus = true; - } - - _onSetServiceName(widget) { - if (this.rename_entry.text.length) { - this.headerbar.title = this.rename_entry.text; - this.settings.set_string('name', this.rename_entry.text); - } - - this.service_edit.active = false; - this.service_edit.grab_focus(); - } - - /* - * Context Switcher - */ - _getTypeLabel(device) { - switch (device.type) { - case 'laptop': - return _('Laptop'); - case 'phone': - return _('Smartphone'); - case 'tablet': - return _('Tablet'); - case 'tv': - return _('Television'); - default: - return _('Desktop'); - } - } - - _setDeviceMenu(panel = null) { - this.device_menu.insert_action_group('device', null); - this.device_menu.insert_action_group('settings', null); - this.device_menu.set_menu_model(null); - - if (panel === null) - return; - - this.device_menu.insert_action_group('device', panel.device.action_group); - this.device_menu.insert_action_group('settings', panel.actions); - this.device_menu.set_menu_model(panel.menu); - } - - _onDeviceChanged(statusLabel, device, pspec) { - switch (false) { - case device.paired: - statusLabel.label = _('Unpaired'); - break; - - case device.connected: - statusLabel.label = _('Disconnected'); - break; - - default: - statusLabel.label = _('Connected'); - } - } - - _createDeviceRow(device) { - const row = new Gtk.ListBoxRow({ - height_request: 52, - selectable: false, - visible: true, - }); - row.set_name(device.id); - - const grid = new Gtk.Grid({ - column_spacing: 12, - margin_left: 20, - margin_right: 20, - margin_bottom: 8, - margin_top: 8, - visible: true, - }); - row.add(grid); - - const icon = new Gtk.Image({ - gicon: new Gio.ThemedIcon({name: device.icon_name}), - icon_size: Gtk.IconSize.BUTTON, - visible: true, - }); - grid.attach(icon, 0, 0, 1, 1); - - const title = new Gtk.Label({ - halign: Gtk.Align.START, - hexpand: true, - valign: Gtk.Align.CENTER, - vexpand: true, - visible: true, - }); - grid.attach(title, 1, 0, 1, 1); - - const status = new Gtk.Label({ - halign: Gtk.Align.END, - hexpand: true, - valign: Gtk.Align.CENTER, - vexpand: true, - visible: true, - }); - grid.attach(status, 2, 0, 1, 1); - - // Keep name up to date - device.bind_property( - 'name', - title, - 'label', - GObject.BindingFlags.SYNC_CREATE - ); - - // Keep status up to date - device.connect( - 'notify::connected', - this._onDeviceChanged.bind(null, status) - ); - device.connect( - 'notify::paired', - this._onDeviceChanged.bind(null, status) - ); - this._onDeviceChanged(status, device, null); - - return row; - } - - _onDeviceAdded(service, device) { - try { - if (!this.stack.get_child_by_name(device.id)) { - // Add the device preferences - const prefs = new Device.Panel(device); - this.stack.add_titled(prefs, device.id, device.name); - - // Add a row to the device list - prefs.row = this._createDeviceRow(device); - this.device_list.add(prefs.row); - } - } catch (e) { - logError(e); - } - } - - _onDeviceRemoved(service, device) { - try { - const prefs = this.stack.get_child_by_name(device.id); - - if (prefs === null) - return; - - if (prefs === this.stack.get_visible_child()) - this._onPrevious(); - - prefs.row.destroy(); - prefs.row = null; - - prefs.dispose(); - prefs.destroy(); - } catch (e) { - logError(e); - } - } - - _onDeviceSelected(box, row) { - try { - if (row === null) - return this._onPrevious(); - - // Transition the panel - const name = row.get_name(); - const prefs = this.stack.get_child_by_name(name); - - this.stack.visible_child = prefs; - this._setDeviceMenu(prefs); - - // HeaderBar (Device) - this.refresh_button.visible = false; - this.service_edit.visible = false; - this.service_menu.visible = false; - - this.prev_button.visible = true; - this.device_menu.visible = true; - - this.headerbar.title = prefs.device.name; - this.headerbar.subtitle = this._getTypeLabel(prefs.device); - } catch (e) { - logError(e); - } - } - - _onServiceChanged(service, pspec) { - if (this.service.active) - this.device_list_placeholder.label = _('Searching for devices…'); - else - this.device_list_placeholder.label = _('Waiting for service…'); - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/prefs.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/prefs.js deleted file mode 100644 index 89760dd..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/prefs.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const Gtk = imports.gi.Gtk; - -// Bootstrap -const Extension = imports.misc.extensionUtils.getCurrentExtension(); -const Utils = Extension.imports.shell.utils; - -function init() { - Utils.installService(); -} - -function buildPrefsWidget() { - // Destroy the window once the mainloop starts - const widget = new Gtk.Box(); - - GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { - widget.get_root().destroy(); - return false; - }); - - Gio.Subprocess.new([`${Extension.path}/gsconnect-preferences`], 0); - - return widget; -} - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/schemas/gschemas.compiled b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/schemas/gschemas.compiled deleted file mode 100644 index 182908d..0000000 Binary files a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/schemas/gschemas.compiled and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/schemas/org.gnome.Shell.Extensions.GSConnect.gschema.xml b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/schemas/org.gnome.Shell.Extensions.GSConnect.gschema.xml deleted file mode 100644 index b369373..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/schemas/org.gnome.Shell.Extensions.GSConnect.gschema.xml +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - true - - - false - - - - - "" - - - "" - - - [] - - - false - - - true - - - - - - - (0, 0) - - - false - - - - - - - "" - - - {} - - - ["sms", "ring", "mount", "commands", "share", "photo", "keyboard"] - - - "" - - - false - - - "smartphone" - - - [] - - - [] - - - [] - - - [] - - - "" - - - - - - false - - - true - - - false - Enables custom battery notification - - - - 80 - - - false - - - - - false - - - false - - - - - true - - - - - - true - - - - - true - - - - - true - - - true - - - '{}' - - - - - true - - - "" - - - - - - - {} - - - - - true - - - - - true - - - "" - - - - - false - - - - - true - - - - - "lower" - - - false - - - "mute" - - - true - - - true - - - - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/__init__.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/__init__.js deleted file mode 100644 index 3320f49..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/__init__.js +++ /dev/null @@ -1,401 +0,0 @@ -'use strict'; - -const ByteArray = imports.byteArray; -const Gettext = imports.gettext; - -const Gio = imports.gi.Gio; -const GIRepository = imports.gi.GIRepository; -const GLib = imports.gi.GLib; - -const Config = imports.config; - - -// User Directories -Config.CACHEDIR = GLib.build_filenamev([GLib.get_user_cache_dir(), 'gsconnect']); -Config.CONFIGDIR = GLib.build_filenamev([GLib.get_user_config_dir(), 'gsconnect']); -Config.RUNTIMEDIR = GLib.build_filenamev([GLib.get_user_runtime_dir(), 'gsconnect']); - - -// Ensure config.js is setup properly -const userDir = GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']); - -if (Config.PACKAGE_DATADIR.startsWith(userDir)) { - Config.IS_USER = true; - - Config.GSETTINGS_SCHEMA_DIR = `${Config.PACKAGE_DATADIR}/schemas`; - Config.PACKAGE_LOCALEDIR = `${Config.PACKAGE_DATADIR}/locale`; - - // Infer libdir by assuming gnome-shell shares a common prefix with gjs; - // assume the parent directory if it's not there - let libdir = GIRepository.Repository.get_search_path().find(path => { - return path.endsWith('/gjs/girepository-1.0'); - }).replace('/gjs/girepository-1.0', ''); - - const gsdir = GLib.build_filenamev([libdir, 'gnome-shell']); - - if (!GLib.file_test(gsdir, GLib.FileTest.IS_DIR)) { - const currentDir = `/${GLib.path_get_basename(libdir)}`; - libdir = libdir.replace(currentDir, ''); - } - - Config.GNOME_SHELL_LIBDIR = libdir; -} - - -// Init Gettext -String.prototype.format = imports.format.format; -Gettext.bindtextdomain(Config.APP_ID, Config.PACKAGE_LOCALEDIR); -globalThis._ = GLib.dgettext.bind(null, Config.APP_ID); -globalThis.ngettext = GLib.dngettext.bind(null, Config.APP_ID); - - -// Init GResources -Gio.Resource.load( - GLib.build_filenamev([Config.PACKAGE_DATADIR, `${Config.APP_ID}.gresource`]) -)._register(); - - -// Init GSchema -Config.GSCHEMA = Gio.SettingsSchemaSource.new_from_directory( - Config.GSETTINGS_SCHEMA_DIR, - Gio.SettingsSchemaSource.get_default(), - false -); - - -// Load DBus interfaces -Config.DBUS = (() => { - const bytes = Gio.resources_lookup_data( - GLib.build_filenamev([Config.APP_PATH, `${Config.APP_ID}.xml`]), - Gio.ResourceLookupFlags.NONE - ); - - const xml = ByteArray.toString(bytes.toArray()); - const dbus = Gio.DBusNodeInfo.new_for_xml(xml); - dbus.nodes.forEach(info => info.cache_build()); - - return dbus; -})(); - - -// Init User Directories -for (const path of [Config.CACHEDIR, Config.CONFIGDIR, Config.RUNTIMEDIR]) - GLib.mkdir_with_parents(path, 0o755); - - -/** - * Check if we're in a Wayland session (mostly for input synthesis) - * https://wiki.gnome.org/Accessibility/Wayland#Bugs.2FIssues_We_Must_Address - */ -globalThis.HAVE_REMOTEINPUT = GLib.getenv('GDMSESSION') !== 'ubuntu-wayland'; -globalThis.HAVE_WAYLAND = GLib.getenv('XDG_SESSION_TYPE') === 'wayland'; - - -/** - * A custom debug function that logs at LEVEL_MESSAGE to avoid the need for env - * variables to be set. - * - * @param {Error|string} message - A string or Error to log - * @param {string} [prefix] - An optional prefix for the warning - */ -const _debugCallerMatch = new RegExp(/([^@]*)@([^:]*):([^:]*)/); -// eslint-disable-next-line func-style -const _debugFunc = function (error, prefix = null) { - let caller, message; - - if (error.stack) { - caller = error.stack.split('\n')[0]; - message = `${error.message}\n${error.stack}`; - } else { - caller = (new Error()).stack.split('\n')[1]; - message = JSON.stringify(error, null, 2); - } - - if (prefix) - message = `${prefix}: ${message}`; - - const [, func, file, line] = _debugCallerMatch.exec(caller); - const script = file.replace(Config.PACKAGE_DATADIR, ''); - - GLib.log_structured('GSConnect', GLib.LogLevelFlags.LEVEL_MESSAGE, { - 'MESSAGE': `[${script}:${func}:${line}]: ${message}`, - 'SYSLOG_IDENTIFIER': 'org.gnome.Shell.Extensions.GSConnect', - 'CODE_FILE': file, - 'CODE_FUNC': func, - 'CODE_LINE': line, - }); -}; - -// Swap the function out for a no-op anonymous function for speed -const settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup(Config.APP_ID, true), -}); - -settings.connect('changed::debug', (settings, key) => { - globalThis.debug = settings.get_boolean(key) ? _debugFunc : () => {}; -}); - -if (settings.get_boolean('debug')) - globalThis.debug = _debugFunc; -else - globalThis.debug = () => {}; - - -/** - * A simple (for now) pre-comparison sanitizer for phone numbers - * See: https://github.com/KDE/kdeconnect-kde/blob/master/smsapp/conversationlistmodel.cpp#L200-L210 - * - * @return {string} Return the string stripped of leading 0, and ' ()-+' - */ -String.prototype.toPhoneNumber = function () { - const strippedNumber = this.replace(/^0*|[ ()+-]/g, ''); - - if (strippedNumber.length) - return strippedNumber; - - return this; -}; - - -/** - * A simple equality check for phone numbers based on `toPhoneNumber()` - * - * @param {string} number - A phone number string to compare - * @return {boolean} If `this` and @number are equivalent phone numbers - */ -String.prototype.equalsPhoneNumber = function (number) { - const a = this.toPhoneNumber(); - const b = number.toPhoneNumber(); - - return (a.endsWith(b) || b.endsWith(a)); -}; - - -/** - * An implementation of `rm -rf` in Gio - * - * @param {Gio.File|string} file - a GFile or filepath - */ -Gio.File.rm_rf = function (file) { - try { - if (typeof file === 'string') - file = Gio.File.new_for_path(file); - - try { - const iter = file.enumerate_children( - 'standard::name', - Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, - null - ); - - let info; - - while ((info = iter.next_file(null))) - Gio.File.rm_rf(iter.get_child(info)); - - iter.close(null); - } catch (e) { - // Silence errors - } - - file.delete(null); - } catch (e) { - // Silence errors - } -}; - - -/** - * Extend GLib.Variant with a static method to recursively pack a variant - * - * @param {*} [obj] - May be a GLib.Variant, Array, standard Object or literal. - * @return {GLib.Variant} The resulting GVariant - */ -function _full_pack(obj) { - let packed; - const type = typeof obj; - - switch (true) { - case (obj instanceof GLib.Variant): - return obj; - - case (type === 'string'): - return GLib.Variant.new('s', obj); - - case (type === 'number'): - return GLib.Variant.new('d', obj); - - case (type === 'boolean'): - return GLib.Variant.new('b', obj); - - case (obj instanceof Uint8Array): - return GLib.Variant.new('ay', obj); - - case (obj === null): - return GLib.Variant.new('mv', null); - - case (typeof obj.map === 'function'): - return GLib.Variant.new( - 'av', - obj.filter(e => e !== undefined).map(e => _full_pack(e)) - ); - - case (obj instanceof Gio.Icon): - return obj.serialize(); - - case (type === 'object'): - packed = {}; - - for (const [key, val] of Object.entries(obj)) { - if (val !== undefined) - packed[key] = _full_pack(val); - } - - return GLib.Variant.new('a{sv}', packed); - - default: - throw Error(`Unsupported type '${type}': ${obj}`); - } -} - -GLib.Variant.full_pack = _full_pack; - - -/** - * Extend GLib.Variant with a method to recursively deepUnpack() a variant - * - * @param {*} [obj] - May be a GLib.Variant, Array, standard Object or literal. - * @return {*} The resulting object - */ -function _full_unpack(obj) { - obj = (obj === undefined) ? this : obj; - const unpacked = {}; - - switch (true) { - case (obj === null): - return obj; - - case (obj instanceof GLib.Variant): - return _full_unpack(obj.deepUnpack()); - - case (obj instanceof Uint8Array): - return obj; - - case (typeof obj.map === 'function'): - return obj.map(e => _full_unpack(e)); - - case (typeof obj === 'object'): - for (const [key, value] of Object.entries(obj)) { - // Try to detect and deserialize GIcons - try { - if (key === 'icon' && value.get_type_string() === '(sv)') - unpacked[key] = Gio.Icon.deserialize(value); - else - unpacked[key] = _full_unpack(value); - } catch (e) { - unpacked[key] = _full_unpack(value); - } - } - - return unpacked; - - default: - return obj; - } -} - -GLib.Variant.prototype.full_unpack = _full_unpack; - - -/** - * Creates a GTlsCertificate from the PEM-encoded data in @cert_path and - * @key_path. If either are missing a new pair will be generated. - * - * Additionally, the private key will be added using ssh-add to allow sftp - * connections using Gio. - * - * See: https://github.com/KDE/kdeconnect-kde/blob/master/core/kdeconnectconfig.cpp#L119 - * - * @param {string} certPath - Absolute path to a x509 certificate in PEM format - * @param {string} keyPath - Absolute path to a private key in PEM format - * @param {string} commonName - A unique common name for the certificate - * @return {Gio.TlsCertificate} A TLS certificate - */ -Gio.TlsCertificate.new_for_paths = function (certPath, keyPath, commonName = null) { - // Check if the certificate/key pair already exists - const certExists = GLib.file_test(certPath, GLib.FileTest.EXISTS); - const keyExists = GLib.file_test(keyPath, GLib.FileTest.EXISTS); - - // Create a new certificate and private key if necessary - if (!certExists || !keyExists) { - // If we weren't passed a common name, generate a random one - if (!commonName) - commonName = GLib.uuid_string_random(); - - const proc = new Gio.Subprocess({ - argv: [ - Config.OPENSSL_PATH, 'req', - '-new', '-x509', '-sha256', - '-out', certPath, - '-newkey', 'rsa:4096', '-nodes', - '-keyout', keyPath, - '-days', '3650', - '-subj', `/O=andyholmes.github.io/OU=GSConnect/CN=${commonName}`, - ], - flags: (Gio.SubprocessFlags.STDOUT_SILENCE | - Gio.SubprocessFlags.STDERR_SILENCE), - }); - proc.init(null); - proc.wait_check(null); - } - - return Gio.TlsCertificate.new_from_files(certPath, keyPath); -}; - -Object.defineProperties(Gio.TlsCertificate.prototype, { - /** - * Compute a SHA256 fingerprint of the certificate. - * See: https://gitlab.gnome.org/GNOME/glib/issues/1290 - * - * @return {string} A SHA256 fingerprint of the certificate. - */ - 'sha256': { - value: function () { - if (!this.__fingerprint) { - const proc = new Gio.Subprocess({ - argv: [Config.OPENSSL_PATH, 'x509', '-noout', '-fingerprint', '-sha256', '-inform', 'pem'], - flags: Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE, - }); - proc.init(null); - - const stdout = proc.communicate_utf8(this.certificate_pem, null)[1]; - this.__fingerprint = /[a-zA-Z0-9:]{95}/.exec(stdout)[0]; - } - - return this.__fingerprint; - }, - enumerable: false, - }, - - /** - * The common name of the certificate. - */ - 'common_name': { - get: function () { - if (!this.__common_name) { - const proc = new Gio.Subprocess({ - argv: [Config.OPENSSL_PATH, 'x509', '-noout', '-subject', '-inform', 'pem'], - flags: Gio.SubprocessFlags.STDIN_PIPE | Gio.SubprocessFlags.STDOUT_PIPE, - }); - proc.init(null); - - const stdout = proc.communicate_utf8(this.certificate_pem, null)[1]; - this.__common_name = /(?:cn|CN) ?= ?([^,\n]*)/.exec(stdout)[1]; - } - - return this.__common_name; - }, - enumerable: true, - }, -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/backends/lan.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/backends/lan.js deleted file mode 100644 index f0d911e..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/backends/lan.js +++ /dev/null @@ -1,985 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Config = imports.config; -const Core = imports.service.core; - - -/** - * TCP Port Constants - */ -const DEFAULT_PORT = 1716; -const TRANSFER_MIN = 1739; -const TRANSFER_MAX = 1764; - - -/* - * One-time check for Linux/FreeBSD socket options - */ -var _LINUX_SOCKETS = true; - -try { - // This should throw on FreeBSD - Gio.Socket.new( - Gio.SocketFamily.IPV4, - Gio.SocketType.STREAM, - Gio.SocketProtocol.TCP - ).get_option(6, 5); -} catch (e) { - _LINUX_SOCKETS = false; -} - - -/** - * Configure a socket connection for the KDE Connect protocol. - * - * @param {Gio.SocketConnection} connection - The connection to configure - */ -function _configureSocket(connection) { - try { - if (_LINUX_SOCKETS) { - connection.socket.set_option(6, 4, 10); // TCP_KEEPIDLE - connection.socket.set_option(6, 5, 5); // TCP_KEEPINTVL - connection.socket.set_option(6, 6, 3); // TCP_KEEPCNT - - // FreeBSD constants - // https://github.com/freebsd/freebsd/blob/master/sys/netinet/tcp.h#L159 - } else { - connection.socket.set_option(6, 256, 10); // TCP_KEEPIDLE - connection.socket.set_option(6, 512, 5); // TCP_KEEPINTVL - connection.socket.set_option(6, 1024, 3); // TCP_KEEPCNT - } - - // Do this last because an error setting the keepalive options would - // result in a socket that never times out - connection.socket.set_keepalive(true); - } catch (e) { - debug(e, 'Configuring Socket'); - } -} - - -/** - * Lan.ChannelService consists of two parts: - * - * The TCP Listener listens on a port and constructs a Channel object from the - * incoming Gio.TcpConnection. - * - * The UDP Listener listens on a port for incoming JSON identity packets which - * include the TCP port, while the IP address is taken from the UDP packet - * itself. We respond by opening a TCP connection to that address. - */ -var ChannelService = GObject.registerClass({ - GTypeName: 'GSConnectLanChannelService', - Properties: { - 'certificate': GObject.ParamSpec.object( - 'certificate', - 'Certificate', - 'The TLS certificate', - GObject.ParamFlags.READWRITE, - Gio.TlsCertificate.$gtype - ), - 'port': GObject.ParamSpec.uint( - 'port', - 'Port', - 'The port used by the service', - GObject.ParamFlags.READWRITE, - 0, GLib.MAXUINT16, - DEFAULT_PORT - ), - }, -}, class LanChannelService extends Core.ChannelService { - - _init(params = {}) { - super._init(params); - - // Track hosts we identify to directly, allowing them to ignore the - // discoverable state of the service. - this._allowed = new Set(); - - // - this._tcp = null; - this._udp4 = null; - this._udp6 = null; - - // Monitor network status - this._networkMonitor = Gio.NetworkMonitor.get_default(); - this._networkAvailable = false; - this._networkChangedId = 0; - } - - get certificate() { - if (this._certificate === undefined) - this._certificate = null; - - return this._certificate; - } - - set certificate(certificate) { - if (this.certificate === certificate) - return; - - this._certificate = certificate; - this.notify('certificate'); - } - - get channels() { - if (this._channels === undefined) - this._channels = new Map(); - - return this._channels; - } - - get port() { - if (this._port === undefined) - this._port = DEFAULT_PORT; - - return this._port; - } - - set port(port) { - if (this.port === port) - return; - - this._port = port; - this.notify('port'); - } - - _onNetworkChanged(monitor, network_available) { - if (this._networkAvailable === network_available) - return; - - this._networkAvailable = network_available; - this.broadcast(); - } - - _initCertificate() { - if (GLib.find_program_in_path(Config.OPENSSL_PATH) === null) { - const error = new Error(); - error.name = _('OpenSSL not found'); - error.url = `${Config.PACKAGE_URL}/wiki/Error#openssl-not-found`; - throw error; - } - - const certPath = GLib.build_filenamev([ - Config.CONFIGDIR, - 'certificate.pem', - ]); - const keyPath = GLib.build_filenamev([ - Config.CONFIGDIR, - 'private.pem', - ]); - - // Ensure a certificate exists with our id as the common name - this._certificate = Gio.TlsCertificate.new_for_paths(certPath, keyPath, - this.id); - - // If the service ID doesn't match the common name, this is probably a - // certificate from an older version and we should amend ours to match - if (this.id !== this._certificate.common_name) - this._id = this._certificate.common_name; - } - - _initTcpListener() { - try { - this._tcp = new Gio.SocketService(); - this._tcp.add_inet_port(this.port, null); - this._tcp.connect('incoming', this._onIncomingChannel.bind(this)); - } catch (e) { - this._tcp = null; - - throw e; - } - } - - async _onIncomingChannel(listener, connection) { - try { - const host = connection.get_remote_address().address.to_string(); - - // Create a channel - const channel = new Channel({ - backend: this, - certificate: this.certificate, - host: host, - port: this.port, - }); - - // Accept the connection - await channel.accept(connection); - channel.identity.body.tcpHost = channel.host; - channel.identity.body.tcpPort = this.port; - channel.allowed = this._allowed.has(host); - - this.channel(channel); - } catch (e) { - debug(e); - } - } - - _initUdpListener() { - // Default broadcast address - this._udp_address = Gio.InetSocketAddress.new_from_string( - '255.255.255.255', - this.port - ); - - try { - this._udp6 = Gio.Socket.new( - Gio.SocketFamily.IPV6, - Gio.SocketType.DATAGRAM, - Gio.SocketProtocol.UDP - ); - this._udp6.set_broadcast(true); - - // Bind the socket - const inetAddr = Gio.InetAddress.new_any(Gio.SocketFamily.IPV6); - const sockAddr = Gio.InetSocketAddress.new(inetAddr, this.port); - this._udp6.bind(sockAddr, false); - - // Input stream - this._udp6_stream = new Gio.DataInputStream({ - base_stream: new Gio.UnixInputStream({ - fd: this._udp6.fd, - close_fd: false, - }), - }); - - // Watch socket for incoming packets - this._udp6_source = this._udp6.create_source(GLib.IOCondition.IN, null); - this._udp6_source.set_callback(this._onIncomingIdentity.bind(this, this._udp6)); - this._udp6_source.attach(null); - } catch (e) { - this._udp6 = null; - } - - // Our IPv6 socket also supports IPv4; we're all done - if (this._udp6 && this._udp6.speaks_ipv4()) { - this._udp4 = null; - return; - } - - try { - this._udp4 = Gio.Socket.new( - Gio.SocketFamily.IPV4, - Gio.SocketType.DATAGRAM, - Gio.SocketProtocol.UDP - ); - this._udp4.set_broadcast(true); - - // Bind the socket - const inetAddr = Gio.InetAddress.new_any(Gio.SocketFamily.IPV4); - const sockAddr = Gio.InetSocketAddress.new(inetAddr, this.port); - this._udp4.bind(sockAddr, false); - - // Input stream - this._udp4_stream = new Gio.DataInputStream({ - base_stream: new Gio.UnixInputStream({ - fd: this._udp4.fd, - close_fd: false, - }), - }); - - // Watch input socket for incoming packets - this._udp4_source = this._udp4.create_source(GLib.IOCondition.IN, null); - this._udp4_source.set_callback(this._onIncomingIdentity.bind(this, this._udp4)); - this._udp4_source.attach(null); - } catch (e) { - this._udp4 = null; - - // We failed to get either an IPv4 or IPv6 socket to bind - if (this._udp6 === null) - throw e; - } - } - - _onIncomingIdentity(socket) { - let host, data, packet; - - // Try to peek the remote address - try { - host = socket.receive_message( - [], - Gio.SocketMsgFlags.PEEK, - null - )[1].address.to_string(); - } catch (e) { - logError(e); - } - - // Whether or not we peeked the address, we need to read the packet - try { - if (socket === this._udp6) - data = this._udp6_stream.read_line_utf8(null)[0]; - else - data = this._udp4_stream.read_line_utf8(null)[0]; - - // Discard the packet if we failed to peek the address - if (host === undefined) - return; - - packet = new Core.Packet(data); - packet.body.tcpHost = host; - this._onIdentity(packet); - } catch (e) { - logError(e); - } - - return GLib.SOURCE_CONTINUE; - } - - async _onIdentity(packet) { - try { - // Bail if the deviceId is missing - if (!packet.body.hasOwnProperty('deviceId')) - return; - - // Silently ignore our own broadcasts - if (packet.body.deviceId === this.identity.body.deviceId) - return; - - debug(packet); - - // Create a new channel - const channel = new Channel({ - backend: this, - certificate: this.certificate, - host: packet.body.tcpHost, - port: packet.body.tcpPort, - identity: packet, - }); - - // Check if channel is already open with this address - if (this.channels.has(channel.address)) - return; - - this._channels.set(channel.address, channel); - - // Open a TCP connection - const connection = await new Promise((resolve, reject) => { - const address = Gio.InetSocketAddress.new_from_string( - packet.body.tcpHost, - packet.body.tcpPort - ); - const client = new Gio.SocketClient({enable_proxy: false}); - - client.connect_async(address, null, (client, res) => { - try { - resolve(client.connect_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - // Connect the channel and attach it to the device on success - await channel.open(connection); - - this.channel(channel); - } catch (e) { - logError(e); - } - } - - /** - * Broadcast an identity packet - * - * If @address is not %null it may specify an IPv4 or IPv6 address to send - * the identity packet directly to, otherwise it will be broadcast to the - * default address, 255.255.255.255. - * - * @param {string} [address] - An optional target IPv4 or IPv6 address - */ - broadcast(address = null) { - try { - if (!this._networkAvailable) - return; - - // Try to parse strings as : - if (typeof address === 'string') { - const [host, portstr] = address.split(':'); - const port = parseInt(portstr) || this.port; - address = Gio.InetSocketAddress.new_from_string(host, port); - } - - // If we succeed, remember this host - if (address instanceof Gio.InetSocketAddress) { - this._allowed.add(address.address.to_string()); - - // Broadcast to the network if no address is specified - } else { - debug('Broadcasting to LAN'); - address = this._udp_address; - } - - // Broadcast on each open socket - if (this._udp6 !== null) - this._udp6.send_to(address, this.identity.serialize(), null); - - if (this._udp4 !== null) - this._udp4.send_to(address, this.identity.serialize(), null); - } catch (e) { - debug(e, address); - } - } - - buildIdentity() { - // Chain-up, then add the TCP port - super.buildIdentity(); - this.identity.body.tcpPort = this.port; - } - - start() { - if (this.active) - return; - - // Ensure a certificate exists - if (this.certificate === null) - this._initCertificate(); - - // Start TCP/UDP listeners - try { - if (this._tcp === null) - this._initTcpListener(); - - if (this._udp4 === null && this._udp6 === null) - this._initUdpListener(); - } catch (e) { - // Known case of another application using the protocol defined port - if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.ADDRESS_IN_USE)) { - e.name = _('Port already in use'); - e.url = `${Config.PACKAGE_URL}/wiki/Error#port-already-in-use`; - } - - throw e; - } - - // Monitor network changes - if (this._networkChangedId === 0) { - this._networkAvailable = this._networkMonitor.network_available; - this._networkChangedId = this._networkMonitor.connect( - 'network-changed', - this._onNetworkChanged.bind(this) - ); - } - - this._active = true; - this.notify('active'); - } - - stop() { - if (this._networkChangedId) { - this._networkMonitor.disconnect(this._networkChangedId); - this._networkChangedId = 0; - this._networkAvailable = false; - } - - if (this._tcp !== null) { - this._tcp.stop(); - this._tcp.close(); - this._tcp = null; - } - - if (this._udp6 !== null) { - this._udp6_source.destroy(); - this._udp6_stream.close(null); - this._udp6.close(); - this._udp6 = null; - } - - if (this._udp4 !== null) { - this._udp4_source.destroy(); - this._udp4_stream.close(null); - this._udp4.close(); - this._udp4 = null; - } - - for (const channel of this.channels.values()) - channel.close(); - - this._active = false; - this.notify('active'); - } - - destroy() { - try { - this.stop(); - } catch (e) { - debug(e); - } - } -}); - - -/** - * Lan Channel - * - * This class essentially just extends Core.Channel to set TCP socket options - * and negotiate TLS encrypted connections. - */ -var Channel = GObject.registerClass({ - GTypeName: 'GSConnectLanChannel', -}, class LanChannel extends Core.Channel { - - _init(params) { - super._init(); - Object.assign(this, params); - } - - get address() { - return `lan://${this.host}:${this.port}`; - } - - get certificate() { - if (this._certificate === undefined) - this._certificate = null; - - return this._certificate; - } - - set certificate(certificate) { - this._certificate = certificate; - } - - get peer_certificate() { - if (this._connection instanceof Gio.TlsConnection) - return this._connection.get_peer_certificate(); - - return null; - } - - get host() { - if (this._host === undefined) - this._host = null; - - return this._host; - } - - set host(host) { - this._host = host; - } - - get port() { - if (this._port === undefined) { - if (this.identity && this.identity.body.tcpPort) - this._port = this.identity.body.tcpPort; - else - return DEFAULT_PORT; - } - - return this._port; - } - - set port(port) { - this._port = port; - } - - /** - * Handshake Gio.TlsConnection - * - * @param {Gio.TlsConnection} connection - A TLS connection - * @return {Promise} A promise for the operation - */ - _handshake(connection) { - return new Promise((resolve, reject) => { - connection.validation_flags = Gio.TlsCertificateFlags.EXPIRED; - connection.authentication_mode = Gio.TlsAuthenticationMode.REQUIRED; - - connection.handshake_async( - GLib.PRIORITY_DEFAULT, - this.cancellable, - (connection, res) => { - try { - resolve(connection.handshake_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - - /** - * Authenticate a TLS connection. - * - * @param {Gio.TlsConnection} connection - A TLS connection - * @return {Promise} A promise for the operation - */ - async _authenticate(connection) { - // Standard TLS Handshake - await this._handshake(connection); - - // Get a settings object for the device - let settings; - - if (this.device) { - settings = this.device.settings; - } else { - const id = this.identity.body.deviceId; - settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup( - 'org.gnome.Shell.Extensions.GSConnect.Device', - true - ), - path: `/org/gnome/shell/extensions/gsconnect/device/${id}/`, - }); - } - - // If we have a certificate for this deviceId, we can verify it - const cert_pem = settings.get_string('certificate-pem'); - - if (cert_pem !== '') { - let certificate = null; - let verified = false; - - try { - certificate = Gio.TlsCertificate.new_from_pem(cert_pem, -1); - verified = certificate.is_same(connection.peer_certificate); - } catch (e) { - logError(e); - } - - /* The certificate is incorrect for one of two reasons, but both - * result in us resetting the certificate and unpairing the device. - * - * If the certificate failed to load, it is probably corrupted or - * otherwise invalid. In this case, if we try to continue we will - * certainly crash the Android app. - * - * If the certificate did not match what we expected the obvious - * thing to do is to notify the user, however experience tells us - * this is a result of the user doing something masochistic like - * nuking the Android app data or copying settings between machines. - */ - if (verified === false) { - if (this.device) { - this.device.unpair(); - } else { - settings.reset('paired'); - settings.reset('certificate-pem'); - } - - const name = this.identity.body.deviceName; - throw new Error(`${name}: Authentication Failure`); - } - } - - return connection; - } - - /** - * Wrap the connection in Gio.TlsClientConnection and initiate handshake - * - * @param {Gio.TcpConnection} connection - The unauthenticated connection - * @return {Gio.TlsClientConnection} The authenticated connection - */ - _encryptClient(connection) { - _configureSocket(connection); - - connection = Gio.TlsClientConnection.new( - connection, - connection.socket.remote_address - ); - connection.set_certificate(this.certificate); - - return this._authenticate(connection); - } - - /** - * Wrap the connection in Gio.TlsServerConnection and initiate handshake - * - * @param {Gio.TcpConnection} connection - The unauthenticated connection - * @return {Gio.TlsServerConnection} The authenticated connection - */ - _encryptServer(connection) { - _configureSocket(connection); - - connection = Gio.TlsServerConnection.new(connection, this.certificate); - - // We're the server so we trust-on-first-use and verify after - const _id = connection.connect('accept-certificate', (connection) => { - connection.disconnect(_id); - return true; - }); - - return this._authenticate(connection); - } - - /** - * Read the identity packet from the new connection - * - * @param {Gio.SocketConnection} connection - An unencrypted socket - * @return {Promise} A promise for the operation - */ - _receiveIdent(connection) { - return new Promise((resolve, reject) => { - // In principle this disposable wrapper could buffer more than the - // identity packet, but in practice the remote device shouldn't send - // any more data until the TLS connection is negotiated. - const stream = new Gio.DataInputStream({ - base_stream: connection.input_stream, - close_base_stream: false, - }); - - stream.read_line_async( - GLib.PRIORITY_DEFAULT, - this.cancellable, - (stream, res) => { - try { - const data = stream.read_line_finish_utf8(res)[0]; - stream.close(null); - - // Store the identity as an object property - this.identity = new Core.Packet(data); - - // Reject connections without a deviceId - if (!this.identity.body.deviceId) - throw new Error('missing deviceId'); - - resolve(); - } catch (e) { - reject(e); - } - } - ); - }); - } - - /** - * Write our identity packet to the new connection - * - * @param {Gio.SocketConnection} connection - An unencrypted socket - * @return {Promise} A promise for the operation - */ - _sendIdent(connection) { - return new Promise((resolve, reject) => { - connection.get_output_stream().write_all_async( - this.backend.identity.serialize(), - GLib.PRIORITY_DEFAULT, - this.cancellable, - (stream, res) => { - try { - resolve(stream.write_all_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - - /** - * Negotiate an incoming connection - * - * @param {Gio.TcpConnection} connection - The incoming connection - */ - async accept(connection) { - debug(`${this.address} (${this.uuid})`); - - try { - this._connection = connection; - this.backend.channels.set(this.address, this); - - await this._receiveIdent(this._connection); - this._connection = await this._encryptClient(connection); - } catch (e) { - this.close(); - throw e; - } - } - - /** - * Negotiate an outgoing connection - * - * @param {Gio.SocketConnection} connection - The remote connection - */ - async open(connection) { - debug(`${this.address} (${this.uuid})`); - - try { - this._connection = connection; - this.backend.channels.set(this.address, this); - - await this._sendIdent(this._connection); - this._connection = await this._encryptServer(connection); - } catch (e) { - this.close(); - throw e; - } - } - - /** - * Close all streams associated with this channel, silencing any errors - */ - close() { - if (this.closed) - return; - - debug(`${this.address} (${this.uuid})`); - this._closed = true; - this.notify('closed'); - - this.backend.channels.delete(this.address); - this.cancellable.cancel(); - - if (this._connection) - this._connection.close_async(GLib.PRIORITY_DEFAULT, null, null); - - if (this.input_stream) - this.input_stream.close_async(GLib.PRIORITY_DEFAULT, null, null); - - if (this.output_stream) - this.output_stream.close_async(GLib.PRIORITY_DEFAULT, null, null); - } - - async download(packet, target, cancellable = null) { - const openConnection = new Promise((resolve, reject) => { - const client = new Gio.SocketClient({enable_proxy: false}); - - const address = Gio.InetSocketAddress.new_from_string( - this.host, - packet.payloadTransferInfo.port - ); - - client.connect_async(address, cancellable, (client, res) => { - try { - resolve(client.connect_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - let connection = await openConnection; - connection = await this._encryptClient(connection); - const source = connection.get_input_stream(); - - // Start the transfer - const transferredSize = await this._transfer(source, target, cancellable); - - // If we get less than expected, we've certainly got corruption - if (transferredSize < packet.payloadSize) { - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.FAILED, - message: `Incomplete: ${transferredSize}/${packet.payloadSize}`, - }); - - // TODO: sometimes kdeconnect-android under-reports a file's size - // https://github.com/GSConnect/gnome-shell-extension-gsconnect/issues/1157 - } else if (transferredSize > packet.payloadSize) { - logError(new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.FAILED, - message: `Extra Data: ${transferredSize - packet.payloadSize}`, - })); - } - } - - async upload(packet, source, size, cancellable = null) { - // Start listening on the first available port between 1739-1764 - const listener = new Gio.SocketListener(); - let port = TRANSFER_MIN; - - while (port <= TRANSFER_MAX) { - try { - listener.add_inet_port(port, null); - break; - } catch (e) { - if (port < TRANSFER_MAX) { - port++; - continue; - } else { - throw e; - } - } - } - - // Listen for the incoming connection - const acceptConnection = new Promise((resolve, reject) => { - listener.accept_async( - cancellable, - (listener, res, source_object) => { - try { - resolve(listener.accept_finish(res)[0]); - } catch (e) { - reject(e); - } - } - ); - }); - - // Notify the device we're ready - packet.body.payloadHash = this.checksum; - packet.payloadSize = size; - packet.payloadTransferInfo = {port: port}; - this.sendPacket(new Core.Packet(packet)); - - // Accept the connection and configure the channel - let connection = await acceptConnection; - connection = await this._encryptServer(connection); - const target = connection.get_output_stream(); - - // Start the transfer - const transferredSize = await this._transfer(source, target, cancellable); - - if (transferredSize !== size) { - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.PARTIAL_INPUT, - message: 'Transfer incomplete', - }); - } - } - - _transfer(source, target, cancellable) { - return new Promise((resolve, reject) => { - target.splice_async( - source, - (Gio.OutputStreamSpliceFlags.CLOSE_SOURCE | - Gio.OutputStreamSpliceFlags.CLOSE_TARGET), - GLib.PRIORITY_DEFAULT, - cancellable, - (target, res) => { - try { - resolve(target.splice_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - - async rejectTransfer(packet) { - try { - if (!packet || !packet.hasPayload()) - return; - - if (packet.payloadTransferInfo.port === undefined) - return; - - let connection = await new Promise((resolve, reject) => { - const client = new Gio.SocketClient({enable_proxy: false}); - - const address = Gio.InetSocketAddress.new_from_string( - this.host, - packet.payloadTransferInfo.port - ); - - client.connect_async(address, null, (client, res) => { - try { - resolve(client.connect_finish(res)); - } catch (e) { - resolve(); - } - }); - }); - - connection = await this._encryptClient(connection); - connection.close_async(GLib.PRIORITY_DEFAULT, null, null); - } catch (e) { - debug(e, this.device.name); - } - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/__init__.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/__init__.js deleted file mode 100644 index 2aa5e61..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/__init__.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - - -/* - * Singleton Tracker - */ -const Default = new Map(); - - -/** - * Acquire a reference to a component. Calls to this function should always be - * followed by a call to `release()`. - * - * @param {string} name - The module name - * @return {*} The default instance of a component - */ -function acquire(name) { - let component; - - try { - let info = Default.get(name); - - if (info === undefined) { - const module = imports.service.components[name]; - - info = { - instance: new module.Component(), - refcount: 0, - }; - - Default.set(name, info); - } - - info.refcount++; - component = info.instance; - } catch (e) { - debug(e, name); - } - - return component; -} - - -/** - * Release a reference on a component. If the caller was the last reference - * holder, the component will be freed. - * - * @param {string} name - The module name - * @return {null} A %null value, useful for overriding a traced variable - */ -function release(name) { - try { - const info = Default.get(name); - - if (info.refcount === 1) { - info.instance.destroy(); - Default.delete(name); - } - - info.refcount--; - } catch (e) { - debug(e, name); - } - - return null; -} - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/atspi.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/atspi.js deleted file mode 100644 index 6ddd180..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/atspi.js +++ /dev/null @@ -1,312 +0,0 @@ -'use strict'; - -imports.gi.versions.Atspi = '2.0'; - -const Atspi = imports.gi.Atspi; -const Gdk = imports.gi.Gdk; - - -/** - * Printable ASCII range - */ -const _ASCII = /[\x20-\x7E]/; - - -/** - * Modifier Keycode Defaults - */ -const XKeycode = { - Alt_L: 0x40, - Control_L: 0x25, - Shift_L: 0x32, - Super_L: 0x85, -}; - - -/** - * A thin wrapper around Atspi for X11 sessions without Pipewire support. - */ -var Controller = class { - constructor() { - // Atspi.init() return 2 on fail, but still marks itself as inited. We - // uninit before throwing an error otherwise any future call to init() - // will appear successful and other calls will cause GSConnect to exit. - // See: https://gitlab.gnome.org/GNOME/at-spi2-core/blob/master/atspi/atspi-misc.c - if (Atspi.init() === 2) { - this.destroy(); - throw new Error('Failed to start AT-SPI'); - } - - try { - this._display = Gdk.Display.get_default(); - this._seat = this._display.get_default_seat(); - this._pointer = this._seat.get_pointer(); - } catch (e) { - this.destroy(); - throw e; - } - - // Try to read modifier keycodes from Gdk - try { - const keymap = Gdk.Keymap.get_for_display(this._display); - let modifier; - - modifier = keymap.get_entries_for_keyval(Gdk.KEY_Alt_L)[1][0]; - XKeycode.Alt_L = modifier.keycode; - - modifier = keymap.get_entries_for_keyval(Gdk.KEY_Control_L)[1][0]; - XKeycode.Control_L = modifier.keycode; - - modifier = keymap.get_entries_for_keyval(Gdk.KEY_Shift_L)[1][0]; - XKeycode.Shift_L = modifier.keycode; - - modifier = keymap.get_entries_for_keyval(Gdk.KEY_Super_L)[1][0]; - XKeycode.Super_L = modifier.keycode; - } catch (e) { - debug('using default modifier keycodes'); - } - } - - /* - * Pointer events - */ - clickPointer(button) { - try { - const [, x, y] = this._pointer.get_position(); - const monitor = this._display.get_monitor_at_point(x, y); - const scale = monitor.get_scale_factor(); - Atspi.generate_mouse_event(scale * x, scale * y, `b${button}c`); - } catch (e) { - logError(e); - } - } - - doubleclickPointer(button) { - try { - const [, x, y] = this._pointer.get_position(); - const monitor = this._display.get_monitor_at_point(x, y); - const scale = monitor.get_scale_factor(); - Atspi.generate_mouse_event(scale * x, scale * y, `b${button}d`); - } catch (e) { - logError(e); - } - } - - movePointer(dx, dy) { - try { - const [, x, y] = this._pointer.get_position(); - const monitor = this._display.get_monitor_at_point(x, y); - const scale = monitor.get_scale_factor(); - Atspi.generate_mouse_event(scale * dx, scale * dy, 'rel'); - } catch (e) { - logError(e); - } - } - - pressPointer(button) { - try { - const [, x, y] = this._pointer.get_position(); - const monitor = this._display.get_monitor_at_point(x, y); - const scale = monitor.get_scale_factor(); - Atspi.generate_mouse_event(scale * x, scale * y, `b${button}p`); - } catch (e) { - logError(e); - } - } - - releasePointer(button) { - try { - const [, x, y] = this._pointer.get_position(); - const monitor = this._display.get_monitor_at_point(x, y); - const scale = monitor.get_scale_factor(); - Atspi.generate_mouse_event(scale * x, scale * y, `b${button}r`); - } catch (e) { - logError(e); - } - } - - scrollPointer(dx, dy) { - if (dy > 0) - this.clickPointer(4); - else if (dy < 0) - this.clickPointer(5); - } - - /* - * Phony virtual keyboard helpers - */ - _modeLock(keycode) { - Atspi.generate_keyboard_event( - keycode, - null, - Atspi.KeySynthType.PRESS - ); - } - - _modeUnlock(keycode) { - Atspi.generate_keyboard_event( - keycode, - null, - Atspi.KeySynthType.RELEASE - ); - } - - /* - * Simulate a printable-ASCII character. - * - */ - _pressASCII(key, modifiers) { - try { - // Press Modifiers - if (modifiers & Gdk.ModifierType.MOD1_MASK) - this._modeLock(XKeycode.Alt_L); - if (modifiers & Gdk.ModifierType.CONTROL_MASK) - this._modeLock(XKeycode.Control_L); - if (modifiers & Gdk.ModifierType.SHIFT_MASK) - this._modeLock(XKeycode.Shift_L); - if (modifiers & Gdk.ModifierType.SUPER_MASK) - this._modeLock(XKeycode.Super_L); - - Atspi.generate_keyboard_event( - 0, - key, - Atspi.KeySynthType.STRING - ); - - // Release Modifiers - if (modifiers & Gdk.ModifierType.MOD1_MASK) - this._modeUnlock(XKeycode.Alt_L); - if (modifiers & Gdk.ModifierType.CONTROL_MASK) - this._modeUnlock(XKeycode.Control_L); - if (modifiers & Gdk.ModifierType.SHIFT_MASK) - this._modeUnlock(XKeycode.Shift_L); - if (modifiers & Gdk.ModifierType.SUPER_MASK) - this._modeUnlock(XKeycode.Super_L); - } catch (e) { - logError(e); - } - } - - _pressKeysym(keysym, modifiers) { - try { - // Press Modifiers - if (modifiers & Gdk.ModifierType.MOD1_MASK) - this._modeLock(XKeycode.Alt_L); - if (modifiers & Gdk.ModifierType.CONTROL_MASK) - this._modeLock(XKeycode.Control_L); - if (modifiers & Gdk.ModifierType.SHIFT_MASK) - this._modeLock(XKeycode.Shift_L); - if (modifiers & Gdk.ModifierType.SUPER_MASK) - this._modeLock(XKeycode.Super_L); - - Atspi.generate_keyboard_event( - keysym, - null, - Atspi.KeySynthType.PRESSRELEASE | Atspi.KeySynthType.SYM - ); - - // Release Modifiers - if (modifiers & Gdk.ModifierType.MOD1_MASK) - this._modeUnlock(XKeycode.Alt_L); - if (modifiers & Gdk.ModifierType.CONTROL_MASK) - this._modeUnlock(XKeycode.Control_L); - if (modifiers & Gdk.ModifierType.SHIFT_MASK) - this._modeUnlock(XKeycode.Shift_L); - if (modifiers & Gdk.ModifierType.SUPER_MASK) - this._modeUnlock(XKeycode.Super_L); - } catch (e) { - logError(e); - } - } - - /** - * Simulate the composition of a unicode character with: - * Control+Shift+u, [hex], Return - * - * @param {number} key - An XKeycode - * @param {number} modifiers - A modifier mask - */ - _pressUnicode(key, modifiers) { - try { - if (modifiers > 0) - log('GSConnect: ignoring modifiers for unicode keyboard event'); - - // TODO: Using Control and Shift keysym is not working (it triggers - // key release). Probably using LOCKMODIFIERS will not work either - // as unlocking the modifier will not trigger a release - - // Activate compose sequence - this._modeLock(XKeycode.Control_L); - this._modeLock(XKeycode.Shift_L); - - this.pressreleaseKeysym(Gdk.KEY_U); - - this._modeUnlock(XKeycode.Control_L); - this._modeUnlock(XKeycode.Shift_L); - - // Enter the unicode sequence - const ucode = key.charCodeAt(0).toString(16); - let keysym; - - for (let h = 0, len = ucode.length; h < len; h++) { - keysym = Gdk.unicode_to_keyval(ucode.charAt(h).codePointAt(0)); - this.pressreleaseKeysym(keysym); - } - - // Finish the compose sequence - this.pressreleaseKeysym(Gdk.KEY_Return); - } catch (e) { - logError(e); - } - } - - /* - * Keyboard Events - */ - pressKeysym(keysym) { - Atspi.generate_keyboard_event( - keysym, - null, - Atspi.KeySynthType.PRESS | Atspi.KeySynthType.SYM - ); - } - - releaseKeysym(keysym) { - Atspi.generate_keyboard_event( - keysym, - null, - Atspi.KeySynthType.RELEASE | Atspi.KeySynthType.SYM - ); - } - - pressreleaseKeysym(keysym) { - Atspi.generate_keyboard_event( - keysym, - null, - Atspi.KeySynthType.PRESSRELEASE | Atspi.KeySynthType.SYM - ); - } - - pressKey(input, modifiers) { - // We were passed a keysym - if (typeof input === 'number') - this._pressKeysym(input, modifiers); - - // Regular ASCII - else if (_ASCII.test(input)) - this._pressASCII(input, modifiers); - - // Unicode - else - this._pressUnicode(input, modifiers); - } - - destroy() { - try { - Atspi.exit(); - } catch (e) { - // Silence errors - } - } -}; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/clipboard.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/clipboard.js deleted file mode 100644 index fab6fda..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/clipboard.js +++ /dev/null @@ -1,283 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const GLib = imports.gi.GLib; -const Gtk = imports.gi.Gtk; -const Gio = imports.gi.Gio; -const GObject = imports.gi.GObject; - - -const DBUS_NAME = 'org.gnome.Shell.Extensions.GSConnect.Clipboard'; -const DBUS_PATH = '/org/gnome/Shell/Extensions/GSConnect/Clipboard'; - - -var Clipboard = GObject.registerClass({ - GTypeName: 'GSConnectClipboard', - Properties: { - 'text': GObject.ParamSpec.string( - 'text', - 'Text Content', - 'The current text content of the clipboard', - GObject.ParamFlags.READWRITE, - '' - ), - }, -}, class Clipboard extends GObject.Object { - - _init() { - super._init(); - - this._cancellable = new Gio.Cancellable(); - this._clipboard = null; - - this._ownerChangeId = 0; - this._nameWatcherId = Gio.bus_watch_name( - Gio.BusType.SESSION, - DBUS_NAME, - Gio.BusNameWatcherFlags.NONE, - this._onNameAppeared.bind(this), - this._onNameVanished.bind(this) - ); - } - - get text() { - if (this._text === undefined) - this._text = ''; - - return this._text; - } - - set text(content) { - if (this.text === content) - return; - - this._text = content; - this.notify('text'); - - if (typeof content !== 'string') - return; - - if (this._clipboard instanceof Gtk.Clipboard) - this._clipboard.set_text(content, -1); - - if (this._clipboard instanceof Gio.DBusProxy) - this._proxySetText(content); - } - - async _onNameAppeared(connection, name, name_owner) { - try { - // Cleanup the GtkClipboard - if (this._clipboard && this._ownerChangeId > 0) { - this._clipboard.disconnect(this._ownerChangeId); - this._ownerChangeId = 0; - } - - // Create a proxy for the remote clipboard - this._clipboard = new Gio.DBusProxy({ - g_bus_type: Gio.BusType.SESSION, - g_name: DBUS_NAME, - g_object_path: DBUS_PATH, - g_interface_name: DBUS_NAME, - g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES, - }); - - await new Promise((resolve, reject) => { - this._clipboard.init_async( - GLib.PRIORITY_DEFAULT, - this._cancellable, - (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - this._ownerChangeId = this._clipboard.connect( - 'g-signal', - this._onOwnerChange.bind(this) - ); - - this._onOwnerChange(); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - debug(e); - this._onNameVanished(null, null); - } - } - } - - _onNameVanished(connection, name) { - if (this._clipboard && this._ownerChangeId > 0) { - this._clipboard.disconnect(this._ownerChangeId); - this._clipboardChangedId = 0; - } - - const display = Gdk.Display.get_default(); - this._clipboard = Gtk.Clipboard.get_default(display); - - this._ownerChangeId = this._clipboard.connect( - 'owner-change', - this._onOwnerChange.bind(this) - ); - - this._onOwnerChange(); - } - - async _onOwnerChange() { - try { - if (this._clipboard instanceof Gtk.Clipboard) - await this._gtkUpdateText(); - - else if (this._clipboard instanceof Gio.DBusProxy) - await this._proxyUpdateText(); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - debug(e); - } - } - - _applyUpdate(text) { - if (typeof text !== 'string' || this.text === text) - return; - - this._text = text; - this.notify('text'); - } - - /* - * Proxy Clipboard - */ - _proxyGetMimetypes() { - return new Promise((resolve, reject) => { - this._clipboard.call( - 'GetMimetypes', - null, - Gio.DBusCallFlags.NO_AUTO_START, - -1, - this._cancellable, - (proxy, res) => { - try { - const reply = proxy.call_finish(res); - resolve(reply.deepUnpack()[0]); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); - } - - _proxyGetText() { - return new Promise((resolve, reject) => { - this._clipboard.call( - 'GetText', - null, - Gio.DBusCallFlags.NO_AUTO_START, - -1, - this._cancellable, - (proxy, res) => { - try { - const reply = proxy.call_finish(res); - resolve(reply.deepUnpack()[0]); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); - } - - _proxySetText(text) { - this._clipboard.call( - 'SetText', - new GLib.Variant('(s)', [text]), - Gio.DBusCallFlags.NO_AUTO_START, - -1, - this._cancellable, - (proxy, res) => { - try { - proxy.call_finish(res); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - debug(e); - } - } - ); - } - - async _proxyUpdateText() { - const mimetypes = await this._proxyGetMimetypes(); - - // Special case for a cleared clipboard - if (mimetypes.length === 0) - return this._applyUpdate(''); - - // Special case to ignore copied files - if (mimetypes.includes('text/uri-list')) - return; - - const text = await this._proxyGetText(); - - this._applyUpdate(text); - } - - /* - * GtkClipboard - */ - _gtkGetMimetypes() { - return new Promise((resolve, reject) => { - this._clipboard.request_targets((clipboard, atoms) => resolve(atoms)); - }); - } - - _gtkGetText() { - return new Promise((resolve, reject) => { - this._clipboard.request_text((clipboard, text) => resolve(text)); - }); - } - - async _gtkUpdateText() { - const mimetypes = await this._gtkGetMimetypes(); - - // Special case for a cleared clipboard - if (mimetypes.length === 0) - return this._applyUpdate(''); - - // Special case to ignore copied files - if (mimetypes.includes('text/uri-list')) - return; - - const text = await this._gtkGetText(); - - this._applyUpdate(text); - } - - destroy() { - if (this._cancellable.is_cancelled()) - return; - - this._cancellable.cancel(); - - if (this._clipboard && this._ownerChangeId > 0) { - this._clipboard.disconnect(this._ownerChangeId); - this._ownerChangedId = 0; - } - - if (this._nameWatcherId > 0) { - Gio.bus_unwatch_name(this._nameWatcherId); - this._nameWatcherId = 0; - } - } -}); - - -/** - * The service class for this component - */ -var Component = Clipboard; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/contacts.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/contacts.js deleted file mode 100644 index a76898d..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/contacts.js +++ /dev/null @@ -1,703 +0,0 @@ -'use strict'; - -const ByteArray = imports.byteArray; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Config = imports.config; - -var HAVE_EDS = true; -var EBook = null; -var EBookContacts = null; -var EDataServer = null; - -try { - EBook = imports.gi.EBook; - EBookContacts = imports.gi.EBookContacts; - EDataServer = imports.gi.EDataServer; -} catch (e) { - HAVE_EDS = false; -} - - -/** - * A store for contacts - */ -var Store = GObject.registerClass({ - GTypeName: 'GSConnectContactsStore', - Properties: { - 'context': GObject.ParamSpec.string( - 'context', - 'Context', - 'Used as the cache directory, relative to Config.CACHEDIR', - GObject.ParamFlags.CONSTRUCT_ONLY | GObject.ParamFlags.READWRITE, - null - ), - }, - Signals: { - 'contact-added': { - flags: GObject.SignalFlags.RUN_FIRST, - param_types: [GObject.TYPE_STRING], - }, - 'contact-removed': { - flags: GObject.SignalFlags.RUN_FIRST, - param_types: [GObject.TYPE_STRING], - }, - 'contact-changed': { - flags: GObject.SignalFlags.RUN_FIRST, - param_types: [GObject.TYPE_STRING], - }, - }, -}, class Store extends GObject.Object { - - _init(context = null) { - super._init({ - context: context, - }); - - this._cacheData = {}; - this._edsPrepared = false; - } - - /** - * Parse an EContact and add it to the store. - * - * @param {EBookContacts.Contact} econtact - an EContact to parse - * @param {string} [origin] - an optional origin string - */ - async _parseEContact(econtact, origin = 'desktop') { - try { - const contact = { - id: econtact.id, - name: _('Unknown Contact'), - numbers: [], - origin: origin, - timestamp: 0, - }; - - // Try to get a contact name - if (econtact.full_name) - contact.name = econtact.full_name; - - // Parse phone numbers - const nums = econtact.get_attributes(EBookContacts.ContactField.TEL); - - for (const attr of nums) { - const number = { - value: attr.get_value(), - type: 'unknown', - }; - - if (attr.has_type('CELL')) - number.type = 'cell'; - else if (attr.has_type('HOME')) - number.type = 'home'; - else if (attr.has_type('WORK')) - number.type = 'work'; - - contact.numbers.push(number); - } - - // Try and get a contact photo - const photo = econtact.photo; - - if (photo) { - if (photo.type === EBookContacts.ContactPhotoType.INLINED) { - const data = photo.get_inlined()[0]; - contact.avatar = await this.storeAvatar(data); - - } else if (photo.type === EBookContacts.ContactPhotoType.URI) { - const uri = econtact.photo.get_uri(); - contact.avatar = uri.replace('file://', ''); - } - } - - this.add(contact, false); - } catch (e) { - logError(e, `Failed to parse VCard contact ${econtact.id}`); - } - } - - /* - * EDS Helpers - */ - _getEBookClient(source, cancellable = null) { - return new Promise((resolve, reject) => { - EBook.BookClient.connect(source, 0, cancellable, (source, res) => { - try { - resolve(EBook.BookClient.connect_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - } - - _getEBookView(client, query = '', cancellable = null) { - return new Promise((resolve, reject) => { - client.get_view(query, cancellable, (client, res) => { - try { - resolve(client.get_view_finish(res)[1]); - } catch (e) { - reject(e); - } - }); - }); - } - - _getEContacts(client, query = '', cancellable = null) { - return new Promise((resolve, reject) => { - client.get_contacts(query, cancellable, (client, res) => { - try { - resolve(client.get_contacts_finish(res)[1]); - } catch (e) { - debug(e); - resolve([]); - } - }); - }); - } - - _getESourceRegistry(cancellable = null) { - return new Promise((resolve, reject) => { - EDataServer.SourceRegistry.new(cancellable, (registry, res) => { - try { - resolve(EDataServer.SourceRegistry.new_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - } - - /* - * AddressBook DBus callbacks - */ - _onObjectsAdded(connection, sender, path, iface, signal, params) { - try { - const adds = params.get_child_value(0).get_strv(); - - // NOTE: sequential pairs of vcard, id - for (let i = 0, len = adds.length; i < len; i += 2) { - try { - const vcard = adds[i]; - const econtact = EBookContacts.Contact.new_from_vcard(vcard); - this._parseEContact(econtact); - } catch (e) { - debug(e); - } - } - } catch (e) { - debug(e); - } - } - - _onObjectsRemoved(connection, sender, path, iface, signal, params) { - try { - const changes = params.get_child_value(0).get_strv(); - - for (const id of changes) { - try { - this.remove(id, false); - } catch (e) { - debug(e); - } - } - } catch (e) { - debug(e); - } - } - - _onObjectsModified(connection, sender, path, iface, signal, params) { - try { - const changes = params.get_child_value(0).get_strv(); - - // NOTE: sequential pairs of vcard, id - for (let i = 0, len = changes.length; i < len; i += 2) { - try { - const vcard = changes[i]; - const econtact = EBookContacts.Contact.new_from_vcard(vcard); - this._parseEContact(econtact); - } catch (e) { - debug(e); - } - } - } catch (e) { - debug(e); - } - } - - /* - * SourceRegistryWatcher callbacks - */ - async _onAppeared(watcher, source) { - try { - // Get an EBookClient and EBookView - const uid = source.get_uid(); - const client = await this._getEBookClient(source); - const view = await this._getEBookView(client, 'exists "tel"'); - - // Watch the view for changes to the address book - const connection = view.get_connection(); - const objectPath = view.get_object_path(); - - view._objectsAddedId = connection.signal_subscribe( - null, - 'org.gnome.evolution.dataserver.AddressBookView', - 'ObjectsAdded', - objectPath, - null, - Gio.DBusSignalFlags.NONE, - this._onObjectsAdded.bind(this) - ); - - view._objectsRemovedId = connection.signal_subscribe( - null, - 'org.gnome.evolution.dataserver.AddressBookView', - 'ObjectsRemoved', - objectPath, - null, - Gio.DBusSignalFlags.NONE, - this._onObjectsRemoved.bind(this) - ); - - view._objectsModifiedId = connection.signal_subscribe( - null, - 'org.gnome.evolution.dataserver.AddressBookView', - 'ObjectsModified', - objectPath, - null, - Gio.DBusSignalFlags.NONE, - this._onObjectsModified.bind(this) - ); - - view.start(); - - // Store the EBook in a map - this._ebooks.set(uid, { - source: source, - client: client, - view: view, - }); - } catch (e) { - debug(e); - } - } - - _onDisappeared(watcher, source) { - try { - const uid = source.get_uid(); - const ebook = this._ebooks.get(uid); - - if (ebook === undefined) - return; - - // Disconnect the EBookView - if (ebook.view) { - const connection = ebook.view.get_connection(); - connection.signal_unsubscribe(ebook.view._objectsAddedId); - connection.signal_unsubscribe(ebook.view._objectsRemovedId); - connection.signal_unsubscribe(ebook.view._objectsModifiedId); - - ebook.view.stop(); - } - - this._ebooks.delete(uid); - } catch (e) { - debug(e); - } - } - - async _initEvolutionDataServer() { - try { - if (this._edsPrepared) - return; - - this._edsPrepared = true; - this._ebooks = new Map(); - - // Get the current EBooks - const registry = await this._getESourceRegistry(); - - for (const source of registry.list_sources('Address Book')) - await this._onAppeared(null, source); - - // Watch for new and removed sources - this._watcher = new EDataServer.SourceRegistryWatcher({ - registry: registry, - extension_name: 'Address Book', - }); - - this._appearedId = this._watcher.connect( - 'appeared', - this._onAppeared.bind(this) - ); - this._disappearedId = this._watcher.connect( - 'disappeared', - this._onDisappeared.bind(this) - ); - } catch (e) { - const service = Gio.Application.get_default(); - - if (service !== null) - service.notify_error(e); - else - logError(e); - } - } - - *[Symbol.iterator]() { - const contacts = Object.values(this._cacheData); - - for (let i = 0, len = contacts.length; i < len; i++) - yield contacts[i]; - } - - get contacts() { - return Object.values(this._cacheData); - } - - get context() { - if (this._context === undefined) - this._context = null; - - return this._context; - } - - set context(context) { - this._context = context; - this._cacheDir = Gio.File.new_for_path(Config.CACHEDIR); - - if (context !== null) - this._cacheDir = this._cacheDir.get_child(context); - - GLib.mkdir_with_parents(this._cacheDir.get_path(), 448); - this._cacheFile = this._cacheDir.get_child('contacts.json'); - } - - /** - * Save a ByteArray to file and return the path - * - * @param {ByteArray} contents - An image ByteArray - * @return {string|undefined} File path or %undefined on failure - */ - storeAvatar(contents) { - return new Promise((resolve, reject) => { - const md5 = GLib.compute_checksum_for_data( - GLib.ChecksumType.MD5, - contents - ); - const file = this._cacheDir.get_child(`${md5}`); - - if (file.query_exists(null)) { - resolve(file.get_path()); - } else { - file.replace_contents_bytes_async( - new GLib.Bytes(contents), - null, - false, - Gio.FileCreateFlags.REPLACE_DESTINATION, - null, - (file, res) => { - try { - file.replace_contents_finish(res); - resolve(file.get_path()); - } catch (e) { - debug(e, 'Storing avatar'); - resolve(undefined); - } - } - ); - } - }); - } - - /** - * Query the Store for a contact by name and/or number. - * - * @param {Object} query - A query object - * @param {string} [query.name] - The contact's name - * @param {string} query.number - The contact's number - * @return {Object} A contact object - */ - query(query) { - // First look for an existing contact by number - const contacts = this.contacts; - const matches = []; - const qnumber = query.number.toPhoneNumber(); - - for (let i = 0, len = contacts.length; i < len; i++) { - const contact = contacts[i]; - - for (const num of contact.numbers) { - const cnumber = num.value.toPhoneNumber(); - - if (qnumber.endsWith(cnumber) || cnumber.endsWith(qnumber)) { - // If no query name or exact match, return immediately - if (!query.name || query.name === contact.name) - return contact; - - // Otherwise we might find an exact name match that shares - // the number with another contact - matches.push(contact); - } - } - } - - // Return the first match (pretty much what Android does) - if (matches.length > 0) - return matches[0]; - - // No match; return a mock contact with a unique ID - let id = GLib.uuid_string_random(); - - while (this._cacheData.hasOwnProperty(id)) - id = GLib.uuid_string_random(); - - return { - id: id, - name: query.name || query.number, - numbers: [{value: query.number, type: 'unknown'}], - origin: 'gsconnect', - }; - } - - get_contact(position) { - if (this._cacheData[position] !== undefined) - return this._cacheData[position]; - - return null; - } - - /** - * Add a contact, checking for validity - * - * @param {Object} contact - A contact object - * @param {boolean} write - Write to disk - */ - add(contact, write = true) { - // Ensure the contact has a unique id - if (!contact.id) { - let id = GLib.uuid_string_random(); - - while (this._cacheData[id]) - id = GLib.uuid_string_random(); - - contact.id = id; - } - - // Ensure the contact has an origin - if (!contact.origin) - contact.origin = 'gsconnect'; - - // This is an updated contact - if (this._cacheData[contact.id]) { - this._cacheData[contact.id] = contact; - this.emit('contact-changed', contact.id); - - // This is a new contact - } else { - this._cacheData[contact.id] = contact; - this.emit('contact-added', contact.id); - } - - // Write if requested - if (write) - this.save(); - } - - /** - * Remove a contact by id - * - * @param {string} id - The id of the contact to delete - * @param {boolean} write - Write to disk - */ - remove(id, write = true) { - // Only remove if the contact actually exists - if (this._cacheData[id]) { - delete this._cacheData[id]; - this.emit('contact-removed', id); - - // Write if requested - if (write) - this.save(); - } - } - - /** - * Lookup a contact for each address object in @addresses and return a - * dictionary of address (eg. phone number) to contact object. - * - * { "555-5555": { "name": "...", "numbers": [], ... } } - * - * @param {Object[]} addresses - A list of address objects - * @return {Object} A dictionary of phone numbers and contacts - */ - lookupAddresses(addresses) { - const contacts = {}; - - // Lookup contacts for each address - for (let i = 0, len = addresses.length; i < len; i++) { - const address = addresses[i].address; - - contacts[address] = this.query({ - number: address, - }); - } - - return contacts; - } - - async clear() { - try { - const contacts = this.contacts; - - for (let i = 0, len = contacts.length; i < len; i++) - await this.remove(contacts[i].id, false); - - await this.save(); - } catch (e) { - debug(e); - } - } - - /** - * Update the contact store from a dictionary of our custom contact objects. - * - * @param {Object} json - an Object of contact Objects - */ - async update(json = {}) { - try { - let contacts = Object.values(json); - - for (let i = 0, len = contacts.length; i < len; i++) { - const new_contact = contacts[i]; - const contact = this._cacheData[new_contact.id]; - - if (!contact || new_contact.timestamp !== contact.timestamp) - await this.add(new_contact, false); - } - - // Prune contacts - contacts = this.contacts; - - for (let i = 0, len = contacts.length; i < len; i++) { - const contact = contacts[i]; - - if (!json[contact.id]) - await this.remove(contact.id, false); - } - - await this.save(); - } catch (e) { - debug(e, 'Updating contacts'); - } - } - - /** - * Fetch and update the contact store from its source. - * - * The default function initializes the EDS server, or logs a debug message - * if EDS is unavailable. Derived classes should request an update from the - * remote source. - */ - async fetch() { - try { - if (this.context === null && HAVE_EDS) - await this._initEvolutionDataServer(); - else - throw new Error('Evolution Data Server not available'); - } catch (e) { - debug(e); - } - } - - /** - * Load the contacts from disk. - */ - async load() { - try { - this._cacheData = await new Promise((resolve, reject) => { - this._cacheFile.load_contents_async(null, (file, res) => { - try { - const contents = file.load_contents_finish(res)[1]; - - resolve(JSON.parse(ByteArray.toString(contents))); - } catch (e) { - reject(e); - } - }); - }); - } catch (e) { - debug(e); - } finally { - this.notify('context'); - } - } - - /** - * Save the contacts to disk. - */ - async save() { - // EDS is handling storage - if (this.context === null && HAVE_EDS) - return; - - if (this.__cache_lock) { - this.__cache_queue = true; - return; - } - - try { - this.__cache_lock = true; - - await new Promise((resolve, reject) => { - this._cacheFile.replace_contents_bytes_async( - new GLib.Bytes(JSON.stringify(this._cacheData, null, 2)), - null, - false, - Gio.FileCreateFlags.REPLACE_DESTINATION, - null, - (file, res) => { - try { - resolve(file.replace_contents_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } catch (e) { - debug(e); - } finally { - this.__cache_lock = false; - - if (this.__cache_queue) { - this.__cache_queue = false; - this.save(); - } - } - } - - destroy() { - if (this._watcher !== undefined) { - this._watcher.disconnect(this._appearedId); - this._watcher.disconnect(this._disappearedId); - this._watcher = undefined; - - for (const ebook of this._ebooks.values()) - this._onDisappeared(null, ebook.source); - - this._edsPrepared = false; - } - } -}); - - -/** - * The service class for this component - */ -var Component = Store; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/input.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/input.js deleted file mode 100644 index 2ee1d7a..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/input.js +++ /dev/null @@ -1,641 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - - -const SESSION_TIMEOUT = 15; - - -const RemoteSession = GObject.registerClass({ - GTypeName: 'GSConnectRemoteSession', - Implements: [Gio.DBusInterface], - Signals: { - 'closed': { - flags: GObject.SignalFlags.RUN_FIRST, - }, - }, -}, class RemoteSession extends Gio.DBusProxy { - - _init(objectPath) { - super._init({ - g_bus_type: Gio.BusType.SESSION, - g_name: 'org.gnome.Mutter.RemoteDesktop', - g_object_path: objectPath, - g_interface_name: 'org.gnome.Mutter.RemoteDesktop.Session', - g_flags: Gio.DBusProxyFlags.NONE, - }); - - this._started = false; - } - - vfunc_g_signal(sender_name, signal_name, parameters) { - if (signal_name === 'Closed') - this.emit('closed'); - } - - _call(name, parameters = null) { - if (!this._started) - return; - - this.call(name, parameters, Gio.DBusCallFlags.NONE, -1, null, null); - } - - get session_id() { - try { - return this.get_cached_property('SessionId').unpack(); - } catch (e) { - return null; - } - } - - async start() { - try { - if (this._started) - return; - - // Initialize the proxy - await new Promise((resolve, reject) => { - this.init_async( - GLib.PRIORITY_DEFAULT, - null, - (proxy, res) => { - try { - proxy.init_finish(res); - resolve(); - } catch (e) { - reject(e); - } - } - ); - }); - - // Start the session - await new Promise((resolve, reject) => { - this.call( - 'Start', - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (proxy, res) => { - try { - resolve(proxy.call_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - this._started = true; - } catch (e) { - this.destroy(); - - Gio.DBusError.strip_remote_error(e); - throw e; - } - } - - stop() { - if (this._started) { - this._started = false; - this.call('Stop', null, Gio.DBusCallFlags.NONE, -1, null, null); - } - } - - _translateButton(button) { - switch (button) { - case Gdk.BUTTON_PRIMARY: - return 0x110; - - case Gdk.BUTTON_MIDDLE: - return 0x112; - - case Gdk.BUTTON_SECONDARY: - return 0x111; - - case 4: - return 0; // FIXME - - case 5: - return 0x10F; // up - } - } - - movePointer(dx, dy) { - this._call( - 'NotifyPointerMotionRelative', - GLib.Variant.new('(dd)', [dx, dy]) - ); - } - - pressPointer(button) { - button = this._translateButton(button); - - this._call( - 'NotifyPointerButton', - GLib.Variant.new('(ib)', [button, true]) - ); - } - - releasePointer(button) { - button = this._translateButton(button); - - this._call( - 'NotifyPointerButton', - GLib.Variant.new('(ib)', [button, false]) - ); - } - - clickPointer(button) { - button = this._translateButton(button); - - this._call( - 'NotifyPointerButton', - GLib.Variant.new('(ib)', [button, true]) - ); - - this._call( - 'NotifyPointerButton', - GLib.Variant.new('(ib)', [button, false]) - ); - } - - doubleclickPointer(button) { - this.clickPointer(button); - this.clickPointer(button); - } - - scrollPointer(dx, dy) { - // NOTE: NotifyPointerAxis only seems to work on Wayland, but maybe - // NotifyPointerAxisDiscrete is the better choice anyways - if (HAVE_WAYLAND) { - this._call( - 'NotifyPointerAxis', - GLib.Variant.new('(ddu)', [dx, dy, 0]) - ); - this._call( - 'NotifyPointerAxis', - GLib.Variant.new('(ddu)', [0, 0, 1]) - ); - } else if (dy > 0) { - this._call( - 'NotifyPointerAxisDiscrete', - GLib.Variant.new('(ui)', [Gdk.ScrollDirection.UP, 1]) - ); - } else if (dy < 0) { - this._call( - 'NotifyPointerAxisDiscrete', - GLib.Variant.new('(ui)', [Gdk.ScrollDirection.UP, -1]) - ); - } - } - - /* - * Keyboard Events - */ - pressKeysym(keysym) { - this._call( - 'NotifyKeyboardKeysym', - GLib.Variant.new('(ub)', [keysym, true]) - ); - } - - releaseKeysym(keysym) { - this._call( - 'NotifyKeyboardKeysym', - GLib.Variant.new('(ub)', [keysym, false]) - ); - } - - pressreleaseKeysym(keysym) { - this._call( - 'NotifyKeyboardKeysym', - GLib.Variant.new('(ub)', [keysym, true]) - ); - this._call( - 'NotifyKeyboardKeysym', - GLib.Variant.new('(ub)', [keysym, false]) - ); - } - - /* - * High-level keyboard input - */ - pressKey(input, modifiers) { - // Press Modifiers - if (modifiers & Gdk.ModifierType.MOD1_MASK) - this.pressKeysym(Gdk.KEY_Alt_L); - if (modifiers & Gdk.ModifierType.CONTROL_MASK) - this.pressKeysym(Gdk.KEY_Control_L); - if (modifiers & Gdk.ModifierType.SHIFT_MASK) - this.pressKeysym(Gdk.KEY_Shift_L); - if (modifiers & Gdk.ModifierType.SUPER_MASK) - this.pressKeysym(Gdk.KEY_Super_L); - - if (typeof input === 'string') { - const keysym = Gdk.unicode_to_keyval(input.codePointAt(0)); - this.pressreleaseKeysym(keysym); - } else { - this.pressreleaseKeysym(input); - } - - // Release Modifiers - if (modifiers & Gdk.ModifierType.MOD1_MASK) - this.releaseKeysym(Gdk.KEY_Alt_L); - if (modifiers & Gdk.ModifierType.CONTROL_MASK) - this.releaseKeysym(Gdk.KEY_Control_L); - if (modifiers & Gdk.ModifierType.SHIFT_MASK) - this.releaseKeysym(Gdk.KEY_Shift_L); - if (modifiers & Gdk.ModifierType.SUPER_MASK) - this.releaseKeysym(Gdk.KEY_Super_L); - } - - destroy() { - if (this.__disposed === undefined) { - this.__disposed = true; - GObject.signal_handlers_destroy(this); - } - } -}); - - -class Controller { - constructor() { - this._nameAppearedId = 0; - this._session = null; - this._sessionCloseId = 0; - this._sessionExpiry = 0; - this._sessionExpiryId = 0; - this._sessionStarting = false; - - // Watch for the RemoteDesktop portal - this._nameWatcherId = Gio.bus_watch_name( - Gio.BusType.SESSION, - 'org.gnome.Mutter.RemoteDesktop', - Gio.BusNameWatcherFlags.NONE, - this._onNameAppeared.bind(this), - this._onNameVanished.bind(this) - ); - } - - get connection() { - if (this._connection === undefined) - this._connection = null; - - return this._connection; - } - - /** - * Check if this is a Wayland session, specifically for distributions that - * don't ship pipewire support (eg. Debian/Ubuntu). - * - * FIXME: this is a super ugly hack that should go away - * - * @return {boolean} %true if wayland is not supported - */ - _checkWayland() { - if (HAVE_WAYLAND) { - // eslint-disable-next-line no-global-assign - HAVE_REMOTEINPUT = false; - const service = Gio.Application.get_default(); - - if (service === null) - return true; - - // First we're going to disabled the affected plugins on all devices - for (const device of service.manager.devices.values()) { - const supported = device.settings.get_strv('supported-plugins'); - let index; - - if ((index = supported.indexOf('mousepad')) > -1) - supported.splice(index, 1); - - if ((index = supported.indexOf('presenter')) > -1) - supported.splice(index, 1); - - device.settings.set_strv('supported-plugins', supported); - } - - // Second we need each backend to rebuild its identity packet and - // broadcast the amended capabilities to the network - for (const backend of service.manager.backends.values()) - backend.buildIdentity(); - - service.manager.identify(); - - return true; - } - - return false; - } - - _onNameAppeared(connection, name, name_owner) { - try { - this._connection = connection; - } catch (e) { - logError(e); - } - } - - _onNameVanished(connection, name) { - try { - if (this._session !== null) - this._onSessionClosed(this._session); - } catch (e) { - logError(e); - } - } - - _onSessionClosed(session) { - // Disconnect from the session - if (this._sessionClosedId > 0) { - session.disconnect(this._sessionClosedId); - this._sessionClosedId = 0; - } - - // Destroy the session - session.destroy(); - this._session = null; - } - - _onSessionExpired() { - // If the session has been used recently, schedule a new expiry - const remainder = Math.floor(this._sessionExpiry - (Date.now() / 1000)); - - if (remainder > 0) { - this._sessionExpiryId = GLib.timeout_add_seconds( - GLib.PRIORITY_DEFAULT, - remainder, - this._onSessionExpired.bind(this) - ); - - return GLib.SOURCE_REMOVE; - } - - // Otherwise if there's an active session, close it - if (this._session !== null) - this._session.stop(); - - // Reset the GSource Id - this._sessionExpiryId = 0; - - return GLib.SOURCE_REMOVE; - } - - _createRemoteDesktopSession() { - if (this.connection === null) - return Promise.reject(new Error('No DBus connection')); - - return new Promise((resolve, reject) => { - this.connection.call( - 'org.gnome.Mutter.RemoteDesktop', - '/org/gnome/Mutter/RemoteDesktop', - 'org.gnome.Mutter.RemoteDesktop', - 'CreateSession', - null, - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); - } - - _createScreenCastSession(sessionId) { - if (this.connection === null) - return Promise.reject(new Error('No DBus connection')); - - return new Promise((resolve, reject) => { - const options = new GLib.Variant('(a{sv})', [{ - 'disable-animations': GLib.Variant.new_boolean(false), - 'remote-desktop-session-id': GLib.Variant.new_string(sessionId), - }]); - - this.connection.call( - 'org.gnome.Mutter.ScreenCast', - '/org/gnome/Mutter/ScreenCast', - 'org.gnome.Mutter.ScreenCast', - 'CreateSession', - options, - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); - } - - async _ensureAdapter() { - try { - // Update the timestamp of the last event - this._sessionExpiry = Math.floor((Date.now() / 1000) + SESSION_TIMEOUT); - - // Session is active - if (this._session !== null) - return; - - // Mutter's RemoteDesktop is not available, fall back to Atspi - if (this.connection === null) { - debug('Falling back to Atspi'); - - // If we got here in Wayland, we need to re-adjust and bail - if (this._checkWayland()) - return; - - const fallback = imports.service.components.atspi; - this._session = new fallback.Controller(); - - // Mutter is available and there isn't another session starting - } else if (this._sessionStarting === false) { - this._sessionStarting = true; - - debug('Creating Mutter RemoteDesktop session'); - - // This takes three steps: creating the remote desktop session, - // starting the session, and creating a screencast session for - // the remote desktop session. - const objectPath = await this._createRemoteDesktopSession(); - - this._session = new RemoteSession(objectPath); - await this._session.start(); - - await this._createScreenCastSession(this._session.session_id); - - // Watch for the session ending - this._sessionClosedId = this._session.connect( - 'closed', - this._onSessionClosed.bind(this) - ); - - if (this._sessionExpiryId === 0) { - this._sessionExpiryId = GLib.timeout_add_seconds( - GLib.PRIORITY_DEFAULT, - SESSION_TIMEOUT, - this._onSessionExpired.bind(this) - ); - } - - this._sessionStarting = false; - } - } catch (e) { - logError(e); - - if (this._session !== null) { - this._session.destroy(); - this._session = null; - } - - this._sessionStarting = false; - } - } - - /* - * Pointer Events - */ - movePointer(dx, dy) { - try { - if (dx === 0 && dy === 0) - return; - - this._ensureAdapter(); - this._session.movePointer(dx, dy); - } catch (e) { - debug(e); - } - } - - pressPointer(button) { - try { - this._ensureAdapter(); - this._session.pressPointer(button); - } catch (e) { - debug(e); - } - } - - releasePointer(button) { - try { - this._ensureAdapter(); - this._session.releasePointer(button); - } catch (e) { - debug(e); - } - } - - clickPointer(button) { - try { - this._ensureAdapter(); - this._session.clickPointer(button); - } catch (e) { - debug(e); - } - } - - doubleclickPointer(button) { - try { - this._ensureAdapter(); - this._session.doubleclickPointer(button); - } catch (e) { - debug(e); - } - } - - scrollPointer(dx, dy) { - if (dx === 0 && dy === 0) - return; - - try { - this._ensureAdapter(); - this._session.scrollPointer(dx, dy); - } catch (e) { - debug(e); - } - } - - /* - * Keyboard Events - */ - pressKeysym(keysym) { - try { - this._ensureAdapter(); - this._session.pressKeysym(keysym); - } catch (e) { - debug(e); - } - } - - releaseKeysym(keysym) { - try { - this._ensureAdapter(); - this._session.releaseKeysym(keysym); - } catch (e) { - debug(e); - } - } - - pressreleaseKeysym(keysym) { - try { - this._ensureAdapter(); - this._session.pressreleaseKeysym(keysym); - } catch (e) { - debug(e); - } - } - - /* - * High-level keyboard input - */ - pressKey(input, modifiers) { - try { - this._ensureAdapter(); - this._session.pressKey(input, modifiers); - } catch (e) { - debug(e); - } - } - - destroy() { - if (this._session !== null) { - // Disconnect from the session - if (this._sessionClosedId > 0) { - this._session.disconnect(this._sessionClosedId); - this._sessionClosedId = 0; - } - - this._session.destroy(); - this._session = null; - } - - if (this._nameWatcherId > 0) { - Gio.bus_unwatch_name(this._nameWatcherId); - this._nameWatcherId = 0; - } - } -} - - -/** - * The service class for this component - */ -var Component = Controller; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/mpris.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/mpris.js deleted file mode 100644 index df9c5ff..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/mpris.js +++ /dev/null @@ -1,1029 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - - -var Player = GObject.registerClass({ - GTypeName: 'GSConnectMediaPlayerInterface', - Properties: { - // Application Properties - 'CanQuit': GObject.ParamSpec.boolean( - 'CanQuit', - 'Can Quit', - 'Whether the client can call the Quit method.', - GObject.ParamFlags.READABLE, - false - ), - 'Fullscreen': GObject.ParamSpec.boolean( - 'Fullscreen', - 'Fullscreen', - 'Whether the player is in fullscreen mode.', - GObject.ParamFlags.READWRITE, - false - ), - 'CanSetFullscreen': GObject.ParamSpec.boolean( - 'CanSetFullscreen', - 'Can Set Fullscreen', - 'Whether the client can set the Fullscreen property.', - GObject.ParamFlags.READABLE, - false - ), - 'CanRaise': GObject.ParamSpec.boolean( - 'CanRaise', - 'Can Raise', - 'Whether the client can call the Raise method.', - GObject.ParamFlags.READABLE, - false - ), - 'HasTrackList': GObject.ParamSpec.boolean( - 'HasTrackList', - 'Has Track List', - 'Whether the player has a track list.', - GObject.ParamFlags.READABLE, - false - ), - 'Identity': GObject.ParamSpec.string( - 'Identity', - 'Identity', - 'The application name.', - GObject.ParamFlags.READABLE, - null - ), - 'DesktopEntry': GObject.ParamSpec.string( - 'DesktopEntry', - 'DesktopEntry', - 'The basename of an installed .desktop file.', - GObject.ParamFlags.READABLE, - null - ), - 'SupportedUriSchemes': GObject.param_spec_variant( - 'SupportedUriSchemes', - 'Supported URI Schemes', - 'The URI schemes supported by the media player.', - new GLib.VariantType('as'), - null, - GObject.ParamFlags.READABLE - ), - 'SupportedMimeTypes': GObject.param_spec_variant( - 'SupportedMimeTypes', - 'Supported MIME Types', - 'The mime-types supported by the media player.', - new GLib.VariantType('as'), - null, - GObject.ParamFlags.READABLE - ), - - // Player Properties - 'PlaybackStatus': GObject.ParamSpec.string( - 'PlaybackStatus', - 'Playback Status', - 'The current playback status.', - GObject.ParamFlags.READABLE, - null - ), - 'LoopStatus': GObject.ParamSpec.string( - 'LoopStatus', - 'Loop Status', - 'The current loop status.', - GObject.ParamFlags.READWRITE, - null - ), - 'Rate': GObject.ParamSpec.double( - 'Rate', - 'Rate', - 'The current playback rate.', - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 1.0 - ), - 'MinimumRate': GObject.ParamSpec.double( - 'MinimumRate', - 'Minimum Rate', - 'The minimum playback rate.', - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 1.0 - ), - 'MaximimRate': GObject.ParamSpec.double( - 'MaximumRate', - 'Maximum Rate', - 'The maximum playback rate.', - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 1.0 - ), - 'Shuffle': GObject.ParamSpec.boolean( - 'Shuffle', - 'Shuffle', - 'Whether track changes are linear.', - GObject.ParamFlags.READWRITE, - null - ), - 'Metadata': GObject.param_spec_variant( - 'Metadata', - 'Metadata', - 'The metadata of the current element.', - new GLib.VariantType('a{sv}'), - null, - GObject.ParamFlags.READABLE - ), - 'Volume': GObject.ParamSpec.double( - 'Volume', - 'Volume', - 'The volume level.', - GObject.ParamFlags.READWRITE, - 0.0, 1.0, - 1.0 - ), - 'Position': GObject.ParamSpec.int64( - 'Position', - 'Position', - 'The current track position in microseconds.', - GObject.ParamFlags.READABLE, - 0, Number.MAX_SAFE_INTEGER, - 0 - ), - 'CanGoNext': GObject.ParamSpec.boolean( - 'CanGoNext', - 'Can Go Next', - 'Whether the client can call the Next method.', - GObject.ParamFlags.READABLE, - false - ), - 'CanGoPrevious': GObject.ParamSpec.boolean( - 'CanGoPrevious', - 'Can Go Previous', - 'Whether the client can call the Previous method.', - GObject.ParamFlags.READABLE, - false - ), - 'CanPlay': GObject.ParamSpec.boolean( - 'CanPlay', - 'Can Play', - 'Whether playback can be started using Play or PlayPause.', - GObject.ParamFlags.READABLE, - false - ), - 'CanPause': GObject.ParamSpec.boolean( - 'CanPause', - 'Can Pause', - 'Whether playback can be paused using Play or PlayPause.', - GObject.ParamFlags.READABLE, - false - ), - 'CanSeek': GObject.ParamSpec.boolean( - 'CanSeek', - 'Can Seek', - 'Whether the client can control the playback position using Seek and SetPosition.', - GObject.ParamFlags.READABLE, - false - ), - 'CanControl': GObject.ParamSpec.boolean( - 'CanControl', - 'Can Control', - 'Whether the media player may be controlled over this interface.', - GObject.ParamFlags.READABLE, - false - ), - }, - Signals: { - 'Seeked': { - flags: GObject.SignalFlags.RUN_FIRST, - param_types: [GObject.TYPE_INT64], - }, - }, -}, class Player extends GObject.Object { - - /* - * The org.mpris.MediaPlayer2 Interface - */ - get CanQuit() { - if (this._CanQuit === undefined) - this._CanQuit = false; - - return this._CanQuit; - } - - get CanRaise() { - if (this._CanRaise === undefined) - this._CanRaise = false; - - return this._CanRaise; - } - - get CanSetFullscreen() { - if (this._CanFullscreen === undefined) - this._CanFullscreen = false; - - return this._CanFullscreen; - } - - get DesktopEntry() { - if (this._DesktopEntry === undefined) - return 'org.gnome.Shell.Extensions.GSConnect'; - - return this._DesktopEntry; - } - - get Fullscreen() { - if (this._Fullscreen === undefined) - this._Fullscreen = false; - - return this._Fullscreen; - } - - set Fullscreen(mode) { - if (this.Fullscreen === mode) - return; - - this._Fullscreen = mode; - this.notify('Fullscreen'); - } - - get HasTrackList() { - if (this._HasTrackList === undefined) - this._HasTrackList = false; - - return this._HasTrackList; - } - - get Identity() { - if (this._Identity === undefined) - this._Identity = ''; - - return this._Identity; - } - - get SupportedMimeTypes() { - if (this._SupportedMimeTypes === undefined) - this._SupportedMimeTypes = []; - - return this._SupportedMimeTypes; - } - - get SupportedUriSchemes() { - if (this._SupportedUriSchemes === undefined) - this._SupportedUriSchemes = []; - - return this._SupportedUriSchemes; - } - - Quit() { - throw new GObject.NotImplementedError(); - } - - Raise() { - throw new GObject.NotImplementedError(); - } - - /* - * The org.mpris.MediaPlayer2.Player Interface - */ - get CanControl() { - if (this._CanControl === undefined) - this._CanControl = false; - - return this._CanControl; - } - - get CanGoNext() { - if (this._CanGoNext === undefined) - this._CanGoNext = false; - - return this._CanGoNext; - } - - get CanGoPrevious() { - if (this._CanGoPrevious === undefined) - this._CanGoPrevious = false; - - return this._CanGoPrevious; - } - - get CanPause() { - if (this._CanPause === undefined) - this._CanPause = false; - - return this._CanPause; - } - - get CanPlay() { - if (this._CanPlay === undefined) - this._CanPlay = false; - - return this._CanPlay; - } - - get CanSeek() { - if (this._CanSeek === undefined) - this._CanSeek = false; - - return this._CanSeek; - } - - get LoopStatus() { - if (this._LoopStatus === undefined) - this._LoopStatus = 'None'; - - return this._LoopStatus; - } - - set LoopStatus(status) { - if (this.LoopStatus === status) - return; - - this._LoopStatus = status; - this.notify('LoopStatus'); - } - - get MaximumRate() { - if (this._MaximumRate === undefined) - this._MaximumRate = 1.0; - - return this._MaximumRate; - } - - get Metadata() { - if (this._Metadata === undefined) { - this._Metadata = { - 'xesam:artist': [_('Unknown')], - 'xesam:album': _('Unknown'), - 'xesam:title': _('Unknown'), - 'mpris:length': 0, - }; - } - - return this._Metadata; - } - - get MinimumRate() { - if (this._MinimumRate === undefined) - this._MinimumRate = 1.0; - - return this._MinimumRate; - } - - get PlaybackStatus() { - if (this._PlaybackStatus === undefined) - this._PlaybackStatus = 'Stopped'; - - return this._PlaybackStatus; - } - - get Position() { - if (this._Position === undefined) - this._Position = 0; - - return this._Position; - } - - get Rate() { - if (this._Rate === undefined) - this._Rate = 1.0; - - return this._Rate; - } - - set Rate(rate) { - if (this.Rate === rate) - return; - - this._Rate = rate; - this.notify('Rate'); - } - - get Shuffle() { - if (this._Shuffle === undefined) - this._Shuffle = false; - - return this._Shuffle; - } - - set Shuffle(mode) { - if (this.Shuffle === mode) - return; - - this._Shuffle = mode; - this.notify('Shuffle'); - } - - get Volume() { - if (this._Volume === undefined) - this._Volume = 1.0; - - return this._Volume; - } - - set Volume(level) { - if (this.Volume === level) - return; - - this._Volume = level; - this.notify('Volume'); - } - - Next() { - throw new GObject.NotImplementedError(); - } - - OpenUri(uri) { - throw new GObject.NotImplementedError(); - } - - Previous() { - throw new GObject.NotImplementedError(); - } - - Pause() { - throw new GObject.NotImplementedError(); - } - - Play() { - throw new GObject.NotImplementedError(); - } - - PlayPause() { - throw new GObject.NotImplementedError(); - } - - Seek(offset) { - throw new GObject.NotImplementedError(); - } - - SetPosition(trackId, position) { - throw new GObject.NotImplementedError(); - } - - Stop() { - throw new GObject.NotImplementedError(); - } -}); - - -/** - * An aggregate of the org.mpris.MediaPlayer2 and org.mpris.MediaPlayer2.Player - * interfaces. - */ -const PlayerProxy = GObject.registerClass({ - GTypeName: 'GSConnectMPRISPlayer', -}, class PlayerProxy extends Player { - - _init(name) { - super._init(); - - this._application = new Gio.DBusProxy({ - g_bus_type: Gio.BusType.SESSION, - g_name: name, - g_object_path: '/org/mpris/MediaPlayer2', - g_interface_name: 'org.mpris.MediaPlayer2', - }); - - this._applicationChangedId = this._application.connect( - 'g-properties-changed', - this._onPropertiesChanged.bind(this) - ); - - this._player = new Gio.DBusProxy({ - g_bus_type: Gio.BusType.SESSION, - g_name: name, - g_object_path: '/org/mpris/MediaPlayer2', - g_interface_name: 'org.mpris.MediaPlayer2.Player', - }); - - this._playerChangedId = this._player.connect( - 'g-properties-changed', - this._onPropertiesChanged.bind(this) - ); - - this._playerSignalId = this._player.connect( - 'g-signal', - this._onSignal.bind(this) - ); - - this._cancellable = new Gio.Cancellable(); - } - - _onSignal(proxy, sender_name, signal_name, parameters) { - try { - if (signal_name !== 'Seeked') - return; - - this.emit('Seeked', parameters.deepUnpack()[0]); - } catch (e) { - debug(e, proxy.g_name); - } - } - - _call(proxy, name, parameters = null) { - proxy.call( - name, - parameters, - Gio.DBusCallFlags.NO_AUTO_START, - -1, - this._cancellable, - (proxy, result) => { - try { - proxy.call_finish(result); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - debug(e, proxy.g_name); - } - } - ); - } - - _get(proxy, name, fallback = null) { - try { - return proxy.get_cached_property(name).recursiveUnpack(); - } catch (e) { - return fallback; - } - } - - _set(proxy, name, value) { - try { - proxy.set_cached_property(name, value); - - proxy.call( - 'org.freedesktop.DBus.Properties.Set', - new GLib.Variant('(ssv)', [proxy.g_interface_name, name, value]), - Gio.DBusCallFlags.NO_AUTO_START, - -1, - this._cancellable, - (proxy, result) => { - try { - proxy.call_finish(result); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - debug(e, proxy.g_name); - } - } - ); - } catch (e) { - debug(e, proxy.g_name); - } - } - - _onPropertiesChanged(proxy, changed, invalidated) { - try { - this.freeze_notify(); - - for (const name in changed.deepUnpack()) - this.notify(name); - - this.thaw_notify(); - } catch (e) { - debug(e, proxy.g_name); - } - } - - initPromise() { - const application = new Promise((resolve, reject) => { - this._application.init_async(0, this._cancellable, (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - const player = new Promise((resolve, reject) => { - this._player.init_async(0, this._cancellable, (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - return Promise.all([application, player]); - } - - /* - * The org.mpris.MediaPlayer2 Interface - */ - get CanQuit() { - return this._get(this._application, 'CanQuit', false); - } - - get CanRaise() { - return this._get(this._application, 'CanRaise', false); - } - - get CanSetFullscreen() { - return this._get(this._application, 'CanSetFullscreen', false); - } - - get DesktopEntry() { - return this._get(this._application, 'DesktopEntry', null); - } - - get Fullscreen() { - return this._get(this._application, 'Fullscreen', false); - } - - set Fullscreen(mode) { - this._set(this._application, 'Fullscreen', new GLib.Variant('b', mode)); - } - - get HasTrackList() { - return this._get(this._application, 'HasTrackList', false); - } - - get Identity() { - return this._get(this._application, 'Identity', _('Unknown')); - } - - get SupportedMimeTypes() { - return this._get(this._application, 'SupportedMimeTypes', []); - } - - get SupportedUriSchemes() { - return this._get(this._application, 'SupportedUriSchemes', []); - } - - Quit() { - this._call(this._application, 'Quit'); - } - - Raise() { - this._call(this._application, 'Raise'); - } - - /* - * The org.mpris.MediaPlayer2.Player Interface - */ - get CanControl() { - return this._get(this._player, 'CanControl', false); - } - - get CanGoNext() { - return this._get(this._player, 'CanGoNext', false); - } - - get CanGoPrevious() { - return this._get(this._player, 'CanGoPrevious', false); - } - - get CanPause() { - return this._get(this._player, 'CanPause', false); - } - - get CanPlay() { - return this._get(this._player, 'CanPlay', false); - } - - get CanSeek() { - return this._get(this._player, 'CanSeek', false); - } - - get LoopStatus() { - return this._get(this._player, 'LoopStatus', 'None'); - } - - set LoopStatus(status) { - this._set(this._player, 'LoopStatus', new GLib.Variant('s', status)); - } - - get MaximumRate() { - return this._get(this._player, 'MaximumRate', 1.0); - } - - get Metadata() { - if (this._metadata === undefined) { - this._metadata = { - 'xesam:artist': [_('Unknown')], - 'xesam:album': _('Unknown'), - 'xesam:title': _('Unknown'), - 'mpris:length': 0, - }; - } - - return this._get(this._player, 'Metadata', this._metadata); - } - - get MinimumRate() { - return this._get(this._player, 'MinimumRate', 1.0); - } - - get PlaybackStatus() { - return this._get(this._player, 'PlaybackStatus', 'Stopped'); - } - - // g-properties-changed is not emitted for this property - get Position() { - try { - const reply = this._player.call_sync( - 'org.freedesktop.DBus.Properties.Get', - new GLib.Variant('(ss)', [ - 'org.mpris.MediaPlayer2.Player', - 'Position', - ]), - Gio.DBusCallFlags.NONE, - -1, - null - ); - - return reply.recursiveUnpack()[0]; - } catch (e) { - return 0; - } - } - - get Rate() { - return this._get(this._player, 'Rate', 1.0); - } - - set Rate(rate) { - this._set(this._player, 'Rate', new GLib.Variant('d', rate)); - } - - get Shuffle() { - return this._get(this._player, 'Shuffle', false); - } - - set Shuffle(mode) { - this._set(this._player, 'Shuffle', new GLib.Variant('b', mode)); - } - - get Volume() { - return this._get(this._player, 'Volume', 1.0); - } - - set Volume(level) { - this._set(this._player, 'Volume', new GLib.Variant('d', level)); - } - - Next() { - this._call(this._player, 'Next'); - } - - OpenUri(uri) { - this._call(this._player, 'OpenUri', new GLib.Variant('(s)', [uri])); - } - - Previous() { - this._call(this._player, 'Previous'); - } - - Pause() { - this._call(this._player, 'Pause'); - } - - Play() { - this._call(this._player, 'Play'); - } - - PlayPause() { - this._call(this._player, 'PlayPause'); - } - - Seek(offset) { - this._call(this._player, 'Seek', new GLib.Variant('(x)', [offset])); - } - - SetPosition(trackId, position) { - this._call(this._player, 'SetPosition', - new GLib.Variant('(ox)', [trackId, position])); - } - - Stop() { - this._call(this._player, 'Stop'); - } - - destroy() { - if (this._cancellable.is_cancelled()) - return; - - this._cancellable.cancel(); - this._application.disconnect(this._applicationChangedId); - this._player.disconnect(this._playerChangedId); - this._player.disconnect(this._playerSignalId); - } -}); - - -/** - * A manager for media players - */ -var Manager = GObject.registerClass({ - GTypeName: 'GSConnectMPRISManager', - Signals: { - 'player-added': { - param_types: [GObject.TYPE_OBJECT], - }, - 'player-removed': { - param_types: [GObject.TYPE_OBJECT], - }, - 'player-changed': { - param_types: [GObject.TYPE_OBJECT], - }, - 'player-seeked': { - param_types: [GObject.TYPE_OBJECT, GObject.TYPE_INT64], - }, - }, -}, class Manager extends GObject.Object { - - _init() { - super._init(); - - // Asynchronous setup - this._cancellable = new Gio.Cancellable(); - this._connection = Gio.DBus.session; - this._players = new Map(); - this._paused = new Map(); - - this._nameOwnerChangedId = Gio.DBus.session.signal_subscribe( - 'org.freedesktop.DBus', - 'org.freedesktop.DBus', - 'NameOwnerChanged', - '/org/freedesktop/DBus', - 'org.mpris.MediaPlayer2', - Gio.DBusSignalFlags.MATCH_ARG0_NAMESPACE, - this._onNameOwnerChanged.bind(this) - ); - - this._loadPlayers(); - } - - async _loadPlayers() { - try { - const names = await new Promise((resolve, reject) => { - this._connection.call( - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus', - 'ListNames', - null, - null, - Gio.DBusCallFlags.NONE, - -1, - this._cancellable, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); - - for (let i = 0, len = names.length; i < len; i++) { - const name = names[i]; - - if (!name.startsWith('org.mpris.MediaPlayer2')) - continue; - - if (!name.includes('GSConnect')) - this._addPlayer(name); - } - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - } - } - - _onNameOwnerChanged(connection, sender, object, iface, signal, parameters) { - const [name, oldOwner, newOwner] = parameters.deepUnpack(); - - if (name.includes('GSConnect')) - return; - - if (newOwner.length) - this._addPlayer(name); - else if (oldOwner.length) - this._removePlayer(name); - } - - async _addPlayer(name) { - try { - if (!this._players.has(name)) { - const player = new PlayerProxy(name); - await player.initPromise(); - - player.connect('notify', - (player) => this.emit('player-changed', player)); - - player.connect('Seeked', this.emit.bind(this, 'player-seeked')); - - this._players.set(name, player); - this.emit('player-added', player); - } - } catch (e) { - debug(e, name); - } - } - - _removePlayer(name) { - try { - const player = this._players.get(name); - - if (player !== undefined) { - this._paused.delete(name); - this._players.delete(name); - this.emit('player-removed', player); - - player.destroy(); - } - } catch (e) { - debug(e, name); - } - } - - /** - * Check for a player by its Identity. - * - * @param {string} identity - A player name - * @return {boolean} %true if the player was found - */ - hasPlayer(identity) { - for (const player of this._players.values()) { - if (player.Identity === identity) - return true; - } - - return false; - } - - /** - * Get a player by its Identity. - * - * @param {string} identity - A player name - * @return {GSConnectMPRISPlayer|null} A player or %null - */ - getPlayer(identity) { - for (const player of this._players.values()) { - if (player.Identity === identity) - return player; - } - - return null; - } - - /** - * Get a list of player identities. - * - * @return {string[]} A list of player identities - */ - getIdentities() { - const identities = []; - - for (const player of this._players.values()) { - const identity = player.Identity; - - if (identity) - identities.push(identity); - } - - return identities; - } - - /** - * A convenience function for pausing all players currently playing. - */ - pauseAll() { - for (const [name, player] of this._players) { - if (player.PlaybackStatus === 'Playing' && player.CanPause) { - player.Pause(); - this._paused.set(name, player); - } - } - } - - /** - * A convenience function for restarting all players paused with pauseAll(). - */ - unpauseAll() { - for (const player of this._paused.values()) { - if (player.PlaybackStatus === 'Paused' && player.CanPlay) - player.Play(); - } - - this._paused.clear(); - } - - destroy() { - if (this._cancellable.is_cancelled()) - return; - - this._cancellable.cancel(); - this._connection.signal_unsubscribe(this._nameOwnerChangedId); - - this._paused.clear(); - this._players.forEach(player => player.destroy()); - this._players.clear(); - } -}); - - -/** - * The service class for this component - */ -var Component = Manager; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/notification.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/notification.js deleted file mode 100644 index 43c89ef..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/notification.js +++ /dev/null @@ -1,440 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GjsPrivate = imports.gi.GjsPrivate; -const GObject = imports.gi.GObject; - -const DBus = imports.service.utils.dbus; - - -const _nodeInfo = Gio.DBusNodeInfo.new_for_xml(` - - - - - - - - - - - - - - - - - - - - - - - - - -`); - - -const FDO_IFACE = _nodeInfo.lookup_interface('org.freedesktop.Notifications'); -const FDO_MATCH = "interface='org.freedesktop.Notifications',member='Notify',type='method_call'"; - -const GTK_IFACE = _nodeInfo.lookup_interface('org.gtk.Notifications'); -const GTK_MATCH = "interface='org.gtk.Notifications',member='AddNotification',type='method_call'"; - - -/** - * A class for snooping Freedesktop (libnotify) and Gtk (GNotification) - * notifications and forwarding them to supporting devices. - */ -const Listener = GObject.registerClass({ - GTypeName: 'GSConnectNotificationListener', - Signals: { - 'notification-added': { - flags: GObject.SignalFlags.RUN_LAST, - param_types: [GLib.Variant.$gtype], - }, - }, -}, class Listener extends GObject.Object { - - _init() { - super._init(); - - // Respect desktop notification settings - this._settings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.notifications', - }); - - // Watch for new application policies - this._settingsId = this._settings.connect( - 'changed::application-children', - this._onSettingsChanged.bind(this) - ); - - // Cache for appName->desktop-id lookups - this._names = {}; - - // Asynchronous setup - this._init_async(); - } - - get applications() { - if (this._applications === undefined) - this._onSettingsChanged(); - - return this._applications; - } - - /** - * Update application notification settings - */ - _onSettingsChanged() { - this._applications = {}; - - for (const app of this._settings.get_strv('application-children')) { - const appSettings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.notifications.application', - path: `/org/gnome/desktop/notifications/application/${app}/`, - }); - - const appInfo = Gio.DesktopAppInfo.new( - appSettings.get_string('application-id') - ); - - if (appInfo !== null) - this._applications[appInfo.get_name()] = appSettings; - } - } - - _listNames() { - return new Promise((resolve, reject) => { - this._session.call( - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus', - 'ListNames', - null, - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); - } - - _getNameOwner(name) { - return new Promise((resolve, reject) => { - this._session.call( - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus', - 'GetNameOwner', - new GLib.Variant('(s)', [name]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); - } - - /** - * Try and find a well-known name for @sender on the session bus - * - * @param {string} sender - A DBus unique name (eg. :1.2282) - * @param {string} appName - @appName passed to Notify() (Optional) - * @return {string} A well-known name or %null - */ - async _getAppId(sender, appName) { - try { - // Get a list of well-known names, ignoring @sender - const names = await this._listNames(); - names.splice(names.indexOf(sender), 1); - - // Make a short list for substring matches (fractal/org.gnome.Fractal) - const appLower = appName.toLowerCase(); - - const shortList = names.filter(name => { - return name.toLowerCase().includes(appLower); - }); - - // Run the short list first - for (const name of shortList) { - const nameOwner = await this._getNameOwner(name); - - if (nameOwner === sender) - return name; - - names.splice(names.indexOf(name), 1); - } - - // Run the full list - for (const name of names) { - const nameOwner = await this._getNameOwner(name); - - if (nameOwner === sender) - return name; - } - - return null; - } catch (e) { - debug(e); - return null; - } - } - - /** - * Try and find the application name for @sender - * - * @param {string} sender - A DBus unique name - * @param {string} [appName] - `appName` supplied by Notify() - * @return {string} A well-known name or %null - */ - async _getAppName(sender, appName = null) { - // Check the cache first - if (appName && this._names.hasOwnProperty(appName)) - return this._names[appName]; - - try { - const appId = await this._getAppId(sender, appName); - const appInfo = Gio.DesktopAppInfo.new(`${appId}.desktop`); - this._names[appName] = appInfo.get_name(); - appName = appInfo.get_name(); - } catch (e) { - // Silence errors - } - - return appName; - } - - /** - * Callback for AddNotification()/Notify() - * - * @param {DBus.Interface} iface - The DBus interface - * @param {string} name - The DBus method name - * @param {GLib.Variant} parameters - The method parameters - * @param {Gio.DBusMethodInvocation} invocation - The method invocation info - */ - async _onHandleMethodCall(iface, name, parameters, invocation) { - try { - // Check if notifications are disabled in desktop settings - if (!this._settings.get_boolean('show-banners')) - return; - - parameters = parameters.full_unpack(); - - // GNotification - if (name === 'AddNotification') { - this.AddNotification(...parameters); - - // libnotify - } else if (name === 'Notify') { - const message = invocation.get_message(); - - if (this._fdoNameOwner === undefined) { - this._fdoNameOwner = await this._getNameOwner( - 'org.freedesktop.Notifications'); - } - - if (this._fdoNameOwner !== message.get_destination()) - return; - - // Try to brute-force an application name using DBus - if (!this.applications.hasOwnProperty(parameters[0])) { - const sender = message.get_sender(); - parameters[0] = await this._getAppName(sender, parameters[0]); - } - - this.Notify(...parameters); - } - } catch (e) { - debug(e); - } - } - - /** - * Export interfaces for proxying notifications and become a monitor - * - * @return {Promise} A promise for the operation - */ - _monitorConnection() { - return new Promise((resolve, reject) => { - // libnotify Interface - this._fdoNotifications = new GjsPrivate.DBusImplementation({ - g_interface_info: FDO_IFACE, - }); - this._fdoMethodCallId = this._fdoNotifications.connect( - 'handle-method-call', - this._onHandleMethodCall.bind(this) - ); - this._fdoNotifications.export( - this._monitor, - '/org/freedesktop/Notifications' - ); - - this._fdoNameOwnerChangedId = this._session.signal_subscribe( - 'org.freedesktop.DBus', - 'org.freedesktop.DBus', - 'NameOwnerChanged', - '/org/freedesktop/DBus', - 'org.freedesktop.Notifications', - Gio.DBusSignalFlags.MATCH_ARG0_NAMESPACE, - this._onFdoNameOwnerChanged.bind(this) - ); - - // GNotification Interface - this._gtkNotifications = new GjsPrivate.DBusImplementation({ - g_interface_info: GTK_IFACE, - }); - this._gtkMethodCallId = this._gtkNotifications.connect( - 'handle-method-call', - this._onHandleMethodCall.bind(this) - ); - this._gtkNotifications.export( - this._monitor, - '/org/gtk/Notifications' - ); - - // Become a monitor for Fdo & Gtk notifications - this._monitor.call( - 'org.freedesktop.DBus', - '/org/freedesktop/DBus', - 'org.freedesktop.DBus.Monitoring', - 'BecomeMonitor', - new GLib.Variant('(asu)', [[FDO_MATCH, GTK_MATCH], 0]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - resolve(connection.call_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - - async _init_async() { - try { - this._session = await DBus.getConnection(); - this._monitor = await DBus.newConnection(); - await this._monitorConnection(); - } catch (e) { - const service = Gio.Application.get_default(); - - if (service !== null) - service.notify_error(e); - else - logError(e); - } - } - - _onFdoNameOwnerChanged(connection, sender, object, iface, signal, parameters) { - this._fdoNameOwner = parameters.deepUnpack()[2]; - } - - _sendNotification(notif) { - // Check if this application is disabled in desktop settings - const appSettings = this.applications[notif.appName]; - - if (appSettings && !appSettings.get_boolean('enable')) - return; - - // Send the notification to each supporting device - // TODO: avoid the overhead of the GAction framework with a signal? - const variant = GLib.Variant.full_pack(notif); - this.emit('notification-added', variant); - } - - Notify(appName, replacesId, iconName, summary, body, actions, hints, timeout) { - // Ignore notifications without an appName - if (!appName) - return; - - this._sendNotification({ - appName: appName, - id: `fdo|null|${replacesId}`, - title: summary, - text: body, - ticker: `${summary}: ${body}`, - isClearable: (replacesId !== 0), - icon: iconName, - }); - } - - AddNotification(application, id, notification) { - // Ignore our own notifications or we'll cause a notification loop - if (application === 'org.gnome.Shell.Extensions.GSConnect') - return; - - const appInfo = Gio.DesktopAppInfo.new(`${application}.desktop`); - - // Try to get an icon for the notification - if (!notification.hasOwnProperty('icon')) - notification.icon = appInfo.get_icon() || undefined; - - this._sendNotification({ - appName: appInfo.get_name(), - id: `gtk|${application}|${id}`, - title: notification.title, - text: notification.body, - ticker: `${notification.title}: ${notification.body}`, - isClearable: true, - icon: notification.icon, - }); - } - - destroy() { - try { - if (this._fdoNotifications) { - this._fdoNotifications.disconnect(this._fdoMethodCallId); - this._fdoNotifications.unexport(); - this._session.signal_unsubscribe(this._fdoNameOwnerChangedId); - } - - if (this._gtkNotifications) { - this._gtkNotifications.disconnect(this._gtkMethodCallId); - this._gtkNotifications.unexport(); - } - - if (this._settings) { - this._settings.disconnect(this._settingsId); - this._settings.run_dispose(); - } - - // TODO: Gio.IOErrorEnum: The connection is closed - // this._monitor.close_sync(null); - - GObject.signal_handlers_destroy(this); - } catch (e) { - debug(e); - } - } -}); - - -/** - * The service class for this component - */ -var Component = Listener; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/pulseaudio.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/pulseaudio.js deleted file mode 100644 index d6016bf..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/pulseaudio.js +++ /dev/null @@ -1,265 +0,0 @@ -'use strict'; - -const Tweener = imports.tweener.tweener; - -const GIRepository = imports.gi.GIRepository; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Config = imports.config; - - -// Add gnome-shell's typelib dir to the search path -const typelibDir = GLib.build_filenamev([Config.GNOME_SHELL_LIBDIR, 'gnome-shell']); -GIRepository.Repository.prepend_search_path(typelibDir); -GIRepository.Repository.prepend_library_path(typelibDir); - -const Gvc = imports.gi.Gvc; - - -/** - * Extend Gvc.MixerStream with a property for returning a user-visible name - */ -Object.defineProperty(Gvc.MixerStream.prototype, 'display_name', { - get: function () { - try { - if (!this.get_ports().length) - return this.description; - - return `${this.get_port().human_port} (${this.description})`; - } catch (e) { - return this.description; - } - }, -}); - - -/** - * A convenience wrapper for Gvc.MixerStream - */ -class Stream { - constructor(mixer, stream) { - this._mixer = mixer; - this._stream = stream; - - this._max = mixer.get_vol_max_norm(); - } - - get muted() { - return this._stream.is_muted; - } - - set muted(bool) { - this._stream.change_is_muted(bool); - } - - // Volume is a double in the range 0-1 - get volume() { - return Math.floor(100 * this._stream.volume / this._max) / 100; - } - - set volume(num) { - this._stream.volume = Math.floor(num * this._max); - this._stream.push_volume(); - } - - /** - * Gradually raise or lower the stream volume to @value - * - * @param {number} value - A number in the range 0-1 - * @param {number} [duration] - Duration to fade in seconds - */ - fade(value, duration = 1) { - Tweener.removeTweens(this); - - if (this._stream.volume > value) { - this._mixer.fading = true; - - Tweener.addTween(this, { - volume: value, - time: duration, - transition: 'easeOutCubic', - onComplete: () => { - this._mixer.fading = false; - }, - }); - } else if (this._stream.volume < value) { - this._mixer.fading = true; - - Tweener.addTween(this, { - volume: value, - time: duration, - transition: 'easeInCubic', - onComplete: () => { - this._mixer.fading = false; - }, - }); - } - } -} - - -/** - * A subclass of Gvc.MixerControl with convenience functions for controlling the - * default input/output volumes. - * - * The Mixer class uses GNOME Shell's Gvc library to control the system volume - * and offers a few convenience functions. - */ -const Mixer = GObject.registerClass({ - GTypeName: 'GSConnectAudioMixer', -}, class Mixer extends Gvc.MixerControl { - _init(params) { - super._init({name: 'GSConnect'}); - - this._previousVolume = undefined; - this._volumeMuted = false; - this._microphoneMuted = false; - - this.open(); - } - - get fading() { - if (this._fading === undefined) - this._fading = false; - - return this._fading; - } - - set fading(bool) { - if (this.fading === bool) - return; - - this._fading = bool; - - if (this.fading) - this.emit('stream-changed', this._output._stream.id); - } - - get input() { - if (this._input === undefined) - this.vfunc_default_source_changed(); - - return this._input; - } - - get output() { - if (this._output === undefined) - this.vfunc_default_sink_changed(); - - return this._output; - } - - vfunc_default_sink_changed(id) { - try { - const sink = this.get_default_sink(); - this._output = (sink) ? new Stream(this, sink) : null; - } catch (e) { - logError(e); - } - } - - vfunc_default_source_changed(id) { - try { - const source = this.get_default_source(); - this._input = (source) ? new Stream(this, source) : null; - } catch (e) { - logError(e); - } - } - - vfunc_state_changed(new_state) { - try { - if (new_state === Gvc.MixerControlState.READY) { - this.vfunc_default_sink_changed(null); - this.vfunc_default_source_changed(null); - } - } catch (e) { - logError(e); - } - } - - /** - * Store the current output volume then lower it to %15 - * - * @param {number} duration - Duration in seconds to fade - */ - lowerVolume(duration = 1) { - try { - if (this.output.volume > 0.15) { - this._previousVolume = Number(this.output.volume); - this.output.fade(0.15, duration); - } - } catch (e) { - logError(e); - } - } - - /** - * Mute the output volume (speakers) - */ - muteVolume() { - try { - if (this.output.muted) - return; - - this.output.muted = true; - this._volumeMuted = true; - } catch (e) { - logError(e); - } - } - - /** - * Mute the input volume (microphone) - */ - muteMicrophone() { - try { - if (this.input.muted) - return; - - this.input.muted = true; - this._microphoneMuted = true; - } catch (e) { - logError(e); - } - } - - /** - * Restore all mixer levels to their previous state - */ - restore() { - try { - // If we muted the microphone, unmute it before restoring the volume - if (this._microphoneMuted) { - this.input.muted = false; - this._microphoneMuted = false; - } - - // If we muted the volume, unmute it before restoring the volume - if (this._volumeMuted) { - this.output.muted = false; - this._volumeMuted = false; - } - - // If a previous volume is defined, raise it back up to that level - if (this._previousVolume !== undefined) { - this.output.fade(this._previousVolume); - this._previousVolume = undefined; - } - } catch (e) { - logError(e); - } - } - - destroy() { - this.close(); - } -}); - - -/** - * The service class for this component - */ -var Component = Mixer; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/session.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/session.js deleted file mode 100644 index b906e9b..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/session.js +++ /dev/null @@ -1,116 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; - - -const Session = class { - constructor() { - this._connection = Gio.DBus.system; - this._session = null; - - this._initAsync(); - } - - async _initAsync() { - try { - const userName = GLib.get_user_name(); - const sessions = await this._listSessions(); - let sessionPath = '/org/freedesktop/login1/session/auto'; - - // eslint-disable-next-line no-unused-vars - for (const [num, uid, name, seat, objectPath] of sessions) { - if (name === userName) { - sessionPath = objectPath; - break; - } - } - - this._session = await this._getSession(sessionPath); - } catch (e) { - this._session = null; - logError(e); - } - } - - get idle() { - if (this._session === null) - return false; - - return this._session.get_cached_property('IdleHint').unpack(); - } - - get locked() { - if (this._session === null) - return false; - - return this._session.get_cached_property('LockedHint').unpack(); - } - - get active() { - // Active if not idle and not locked - return !(this.idle || this.locked); - } - - _listSessions() { - return new Promise((resolve, reject) => { - this._connection.call( - 'org.freedesktop.login1', - '/org/freedesktop/login1', - 'org.freedesktop.login1.Manager', - 'ListSessions', - null, - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (connection, res) => { - try { - res = connection.call_finish(res); - resolve(res.deepUnpack()[0]); - } catch (e) { - reject(e); - } - } - ); - }); - } - - async _getSession(objectPath) { - const session = new Gio.DBusProxy({ - g_connection: this._connection, - g_name: 'org.freedesktop.login1', - g_object_path: objectPath, - g_interface_name: 'org.freedesktop.login1.Session', - }); - - // Initialize the proxy - await new Promise((resolve, reject) => { - session.init_async( - GLib.PRIORITY_DEFAULT, - null, - (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); - - return session; - } - - destroy() { - this._session = null; - } -}; - - -/** - * The service class for this component - */ -var Component = Session; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/sound.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/sound.js deleted file mode 100644 index 4afd647..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/sound.js +++ /dev/null @@ -1,185 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; - - -/* - * Used to ensure 'audible-bell' is enabled for fallback - */ -const WM_SETTINGS = new Gio.Settings({ - schema_id: 'org.gnome.desktop.wm.preferences', - path: '/org/gnome/desktop/wm/preferences/', -}); - - -var Player = class Player { - - constructor() { - this._playing = new Set(); - } - - get backend() { - if (this._backend === undefined) { - // Prefer GSound - try { - this._gsound = new imports.gi.GSound.Context(); - this._gsound.init(null); - this._backend = 'gsound'; - - // Try falling back to libcanberra, otherwise just re-run the test - // in case one or the other is installed later - } catch (e) { - if (GLib.find_program_in_path('canberra-gtk-play') !== null) { - this._canberra = new Gio.SubprocessLauncher({ - flags: Gio.SubprocessFlags.NONE, - }); - this._backend = 'libcanberra'; - } else { - return null; - } - } - } - - return this._backend; - } - - _canberraPlaySound(name, cancellable) { - return new Promise((resolve, reject) => { - const proc = this._canberra.spawnv(['canberra-gtk-play', '-i', name]); - - proc.wait_check_async(cancellable, (proc, res) => { - try { - resolve(proc.wait_check_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - } - - async _canberraLoopSound(name, cancellable) { - while (!cancellable.is_cancelled()) - await this._canberraPlaySound(name, cancellable); - } - - _gsoundPlaySound(name, cancellable) { - return new Promise((resolve, reject) => { - this._gsound.play_full( - {'event.id': name}, - cancellable, - (source, res) => { - try { - resolve(source.play_full_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - - async _gsoundLoopSound(name, cancellable) { - while (!cancellable.is_cancelled()) - await this._gsoundPlaySound(name, cancellable); - } - - _gdkPlaySound(name, cancellable) { - if (this._display === undefined) - this._display = Gdk.Display.get_default(); - - let count = 0; - - GLib.timeout_add(GLib.PRIORITY_DEFAULT, 200, () => { - try { - if (count++ < 4 && !cancellable.is_cancelled()) { - this._display.beep(); - return GLib.SOURCE_CONTINUE; - } - - return GLib.SOURCE_REMOVE; - } catch (e) { - logError(e); - return GLib.SOURCE_REMOVE; - } - }); - - return !cancellable.is_cancelled(); - } - - _gdkLoopSound(name, cancellable) { - this._gdkPlaySound(name, cancellable); - GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - 1500, - this._gdkPlaySound.bind(this, name, cancellable) - ); - } - - async playSound(name, cancellable) { - try { - if (!(cancellable instanceof Gio.Cancellable)) - cancellable = new Gio.Cancellable(); - - this._playing.add(cancellable); - - switch (this.backend) { - case 'gsound': - await this._gsoundPlaySound(name, cancellable); - break; - - case 'canberra': - await this._canberraPlaySound(name, cancellable); - break; - - default: - await this._gdkPlaySound(name, cancellable); - } - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - } finally { - this._playing.delete(cancellable); - } - } - - async loopSound(name, cancellable) { - try { - if (!(cancellable instanceof Gio.Cancellable)) - cancellable = new Gio.Cancellable(); - - this._playing.add(cancellable); - - switch (this.backend) { - case 'gsound': - await this._gsoundLoopSound(name, cancellable); - break; - - case 'canberra': - await this._canberraLoopSound(name, cancellable); - break; - - default: - await this._gdkLoopSound(name, cancellable); - } - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - logError(e); - } finally { - this._playing.delete(cancellable); - } - } - - destroy() { - for (const cancellable of this._playing) - cancellable.cancel(); - } -}; - - -/** - * The service class for this component - */ -var Component = Player; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/upower.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/upower.js deleted file mode 100644 index 20cc20b..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/components/upower.js +++ /dev/null @@ -1,226 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - - -/** - * The warning level of a battery. - * - * @readonly - * @enum {number} - */ -const DeviceLevel = { - UNKNOWN: 0, - NONE: 1, - DISCHARGING: 2, - LOW: 3, - CRITICAL: 4, - ACTION: 5, - NORMAL: 6, - HIGH: 7, - FULL: 8, - LAST: 9, -}; - -/** - * The device state. - * - * @readonly - * @enum {number} - */ -const DeviceState = { - UNKNOWN: 0, - CHARGING: 1, - DISCHARGING: 2, - EMPTY: 3, - FULLY_CHARGED: 4, - PENDING_CHARGE: 5, - PENDING_DISCHARGE: 6, - LAST: 7, -}; - - -/** - * A class representing the system battery. - */ -var Battery = GObject.registerClass({ - GTypeName: 'GSConnectSystemBattery', - Signals: { - 'changed': { - flags: GObject.SignalFlags.RUN_FIRST, - }, - }, - Properties: { - 'charging': GObject.ParamSpec.boolean( - 'charging', - 'Charging', - 'The current charging state.', - GObject.ParamFlags.READABLE, - false - ), - 'level': GObject.ParamSpec.int( - 'level', - 'Level', - 'The current power level.', - GObject.ParamFlags.READABLE, - -1, 100, - -1 - ), - 'threshold': GObject.ParamSpec.uint( - 'threshold', - 'Threshold', - 'The current threshold state.', - GObject.ParamFlags.READABLE, - 0, 1, - 0 - ), - }, -}, class Battery extends GObject.Object { - - _init() { - super._init(); - - this._cancellable = new Gio.Cancellable(); - this._proxy = null; - this._propertiesChangedId = 0; - - this._loadUPower(); - } - - async _loadUPower() { - try { - this._proxy = new Gio.DBusProxy({ - g_bus_type: Gio.BusType.SYSTEM, - g_name: 'org.freedesktop.UPower', - g_object_path: '/org/freedesktop/UPower/devices/DisplayDevice', - g_interface_name: 'org.freedesktop.UPower.Device', - g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START, - }); - - await new Promise((resolve, reject) => { - this._proxy.init_async( - GLib.PRIORITY_DEFAULT, - this._cancellable, - (proxy, res) => { - try { - resolve(proxy.init_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - this._propertiesChangedId = this._proxy.connect( - 'g-properties-changed', - this._onPropertiesChanged.bind(this) - ); - - this._initProperties(this._proxy); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) { - const service = Gio.Application.get_default(); - - if (service !== null) - service.notify_error(e); - else - logError(e); - } - - this._proxy = null; - } - } - - _initProperties(proxy) { - if (proxy.g_name_owner === null) - return; - - const percentage = proxy.get_cached_property('Percentage').unpack(); - const state = proxy.get_cached_property('State').unpack(); - const level = proxy.get_cached_property('WarningLevel').unpack(); - - this._level = Math.floor(percentage); - this._charging = (state !== DeviceState.DISCHARGING); - this._threshold = (!this.charging && level >= DeviceLevel.LOW); - - this.emit('changed'); - } - - _onPropertiesChanged(proxy, changed, invalidated) { - let emitChanged = false; - const properties = changed.deepUnpack(); - - if (properties.hasOwnProperty('Percentage')) { - emitChanged = true; - - const value = proxy.get_cached_property('Percentage').unpack(); - this._level = Math.floor(value); - this.notify('level'); - } - - if (properties.hasOwnProperty('State')) { - emitChanged = true; - - const value = proxy.get_cached_property('State').unpack(); - this._charging = (value !== DeviceState.DISCHARGING); - this.notify('charging'); - } - - if (properties.hasOwnProperty('WarningLevel')) { - emitChanged = true; - - const value = proxy.get_cached_property('WarningLevel').unpack(); - this._threshold = (!this.charging && value >= DeviceLevel.LOW); - this.notify('threshold'); - } - - if (emitChanged) - this.emit('changed'); - } - - get charging() { - if (this._charging === undefined) - this._charging = false; - - return this._charging; - } - - get is_present() { - return (this._proxy && this._proxy.g_name_owner); - } - - get level() { - if (this._level === undefined) - this._level = -1; - - return this._level; - } - - get threshold() { - if (this._threshold === undefined) - this._threshold = 0; - - return this._threshold; - } - - destroy() { - if (this._cancellable.is_cancelled()) - return; - - this._cancellable.cancel(); - - if (this._proxy && this._propertiesChangedId > 0) { - this._proxy.disconnect(this._propertiesChangedId); - this._propertiesChangedId = 0; - } - } -}); - - -/** - * The service class for this component - */ -var Component = Battery; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/core.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/core.js deleted file mode 100644 index ac948fa..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/core.js +++ /dev/null @@ -1,738 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - - -/** - * Get the local device type. - * - * @return {string} A device type string - */ -function _getDeviceType() { - try { - let type = GLib.file_get_contents('/sys/class/dmi/id/chassis_type')[1]; - - type = Number(imports.byteArray.toString(type)); - - if ([8, 9, 10, 14].includes(type)) - return 'laptop'; - - return 'desktop'; - } catch (e) { - return 'desktop'; - } -} - - -/** - * The packet class is a simple Object-derived class, offering some conveniences - * for working with KDE Connect packets. - */ -var Packet = class Packet { - - constructor(data = null) { - this.id = 0; - this.type = undefined; - this.body = {}; - - if (typeof data === 'string') - Object.assign(this, JSON.parse(data)); - else if (data !== null) - Object.assign(this, data); - } - - [Symbol.toPrimitive](hint) { - this.id = Date.now(); - - if (hint === 'string') - return `${JSON.stringify(this)}\n`; - - if (hint === 'number') - return `${JSON.stringify(this)}\n`.length; - - return true; - } - - get [Symbol.toStringTag]() { - return `Packet:${this.type}`; - } - - /** - * Deserialize and return a new Packet from an Object or string. - * - * @param {Object|string} data - A string or dictionary to deserialize - * @return {Core.Packet} A new packet object - */ - static deserialize(data) { - return new Packet(data); - } - - /** - * Serialize the packet as a single line with a terminating new-line (`\n`) - * character, ready to be written to a channel. - * - * @return {string} A serialized packet - */ - serialize() { - this.id = Date.now(); - return `${JSON.stringify(this)}\n`; - } - - /** - * Update the packet from a dictionary or string of JSON - * - * @param {Object|string} source - Source data - */ - update(source) { - try { - if (typeof data === 'string') - Object.assign(this, JSON.parse(source)); - else - Object.assign(this, source); - } catch (e) { - throw Error(`Malformed data: ${e.message}`); - } - } - - /** - * Check if the packet has a payload. - * - * @return {boolean} %true if @packet has a payload - */ - hasPayload() { - if (!this.hasOwnProperty('payloadSize')) - return false; - - if (!this.hasOwnProperty('payloadTransferInfo')) - return false; - - return (Object.keys(this.payloadTransferInfo).length > 0); - } -}; - - -/** - * Channel objects handle KDE Connect packet exchange and data transfers for - * devices. The implementation is responsible for all negotiation of the - * underlying protocol. - */ -var Channel = GObject.registerClass({ - GTypeName: 'GSConnectChannel', - Properties: { - 'closed': GObject.ParamSpec.boolean( - 'closed', - 'Closed', - 'Whether the channel has been closed', - GObject.ParamFlags.READABLE, - false - ), - }, -}, class Channel extends GObject.Object { - - get address() { - throw new GObject.NotImplementedError(); - } - - get backend() { - if (this._backend === undefined) - this._backend = null; - - return this._backend; - } - - set backend(backend) { - this._backend = backend; - } - - get cancellable() { - if (this._cancellable === undefined) - this._cancellable = new Gio.Cancellable(); - - return this._cancellable; - } - - get closed() { - if (this._closed === undefined) - this._closed = false; - - return this._closed; - } - - get input_stream() { - if (this._input_stream === undefined) { - if (this._connection instanceof Gio.IOStream) - return this._connection.get_input_stream(); - - return null; - } - - return this._input_stream; - } - - set input_stream(stream) { - this._input_stream = stream; - } - - get output_stream() { - if (this._output_stream === undefined) { - if (this._connection instanceof Gio.IOStream) - return this._connection.get_output_stream(); - - return null; - } - - return this._output_stream; - } - - set output_stream(stream) { - this._output_stream = stream; - } - - get uuid() { - if (this._uuid === undefined) - this._uuid = GLib.uuid_string_random(); - - return this._uuid; - } - - set uuid(uuid) { - this._uuid = uuid; - } - - /** - * Close the channel. - */ - close() { - throw new GObject.NotImplementedError(); - } - - /** - * Read a packet. - * - * @param {Gio.Cancellable} [cancellable] - A cancellable - * @return {Promise} The packet - */ - readPacket(cancellable = null) { - if (cancellable === null) - cancellable = this.cancellable; - - if (!(this.input_stream instanceof Gio.DataInputStream)) { - this.input_stream = new Gio.DataInputStream({ - base_stream: this.input_stream, - }); - } - - return new Promise((resolve, reject) => { - this.input_stream.read_line_async( - GLib.PRIORITY_DEFAULT, - cancellable, - (stream, res) => { - try { - const data = stream.read_line_finish_utf8(res)[0]; - - if (data === null) { - throw new Gio.IOErrorEnum({ - message: 'End of stream', - code: Gio.IOErrorEnum.CONNECTION_CLOSED, - }); - } - - resolve(new Packet(data)); - } catch (e) { - reject(e); - } - } - ); - }); - } - - /** - * Send a packet. - * - * @param {Core.Packet} packet - The packet to send - * @param {Gio.Cancellable} [cancellable] - A cancellable - * @return {Promise} %true if successful - */ - sendPacket(packet, cancellable = null) { - if (cancellable === null) - cancellable = this.cancellable; - - return new Promise((resolve, reject) => { - this.output_stream.write_all_async( - packet.serialize(), - GLib.PRIORITY_DEFAULT, - cancellable, - (stream, res) => { - try { - resolve(stream.write_all_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - - /** - * Reject a transfer. - * - * @param {Core.Packet} packet - A packet with payload info - */ - rejectTransfer(packet) { - throw new GObject.NotImplementedError(); - } - - /** - * Download a payload from a device. Typically implementations will override - * this with an async function. - * - * @param {Core.Packet} packet - A packet - * @param {Gio.OutputStream} target - The target stream - * @param {Gio.Cancellable} [cancellable] - A cancellable for the upload - */ - download(packet, target, cancellable = null) { - throw new GObject.NotImplementedError(); - } - - - /** - * Upload a payload to a device. Typically implementations will override - * this with an async function. - * - * @param {Core.Packet} packet - The packet describing the transfer - * @param {Gio.InputStream} source - The source stream - * @param {number} size - The payload size - * @param {Gio.Cancellable} [cancellable] - A cancellable for the upload - */ - upload(packet, source, size, cancellable = null) { - throw new GObject.NotImplementedError(); - } -}); - - -/** - * ChannelService implementations provide Channel objects, emitting the - * ChannelService::channel signal when a new connection has been accepted. - */ -var ChannelService = GObject.registerClass({ - GTypeName: 'GSConnectChannelService', - Properties: { - 'active': GObject.ParamSpec.boolean( - 'active', - 'Active', - 'Whether the service is active', - GObject.ParamFlags.READABLE, - false - ), - 'id': GObject.ParamSpec.string( - 'id', - 'ID', - 'The hostname or other network unique id', - GObject.ParamFlags.READWRITE, - null - ), - 'name': GObject.ParamSpec.string( - 'name', - 'Name', - 'The name of the backend', - GObject.ParamFlags.READWRITE, - null - ), - }, - Signals: { - 'channel': { - flags: GObject.SignalFlags.RUN_LAST, - param_types: [Channel.$gtype], - return_type: GObject.TYPE_BOOLEAN, - }, - }, -}, class ChannelService extends GObject.Object { - - get active() { - if (this._active === undefined) - this._active = false; - - return this._active; - } - - get name() { - if (this._name === undefined) - this._name = GLib.get_host_name(); - - return this._name; - } - - set name(name) { - if (this.name === name) - return; - - this._name = name; - this.notify('name'); - } - - get id() { - if (this._id === undefined) - this._id = GLib.uuid_string_random(); - - return this._id; - } - - set id(id) { - if (this.id === id) - return; - - this._id = id; - } - - get identity() { - if (this._identity === undefined) - this.buildIdentity(); - - return this._identity; - } - - /** - * Broadcast directly to @address or the whole network if %null - * - * @param {string} [address] - A string address - */ - broadcast(address = null) { - throw new GObject.NotImplementedError(); - } - - /** - * Rebuild the identity packet used to identify the local device. An - * implementation may override this to make modifications to the default - * capabilities if necessary (eg. bluez without SFTP support). - */ - buildIdentity() { - this._identity = new Packet({ - id: 0, - type: 'kdeconnect.identity', - body: { - deviceId: this.id, - deviceName: this.name, - deviceType: _getDeviceType(), - protocolVersion: 7, - incomingCapabilities: [], - outgoingCapabilities: [], - }, - }); - - for (const name in imports.service.plugins) { - // Exclude mousepad/presenter capability in unsupported sessions - if (!HAVE_REMOTEINPUT && ['mousepad', 'presenter'].includes(name)) - continue; - - const meta = imports.service.plugins[name].Metadata; - - for (const type of meta.incomingCapabilities) - this._identity.body.incomingCapabilities.push(type); - - for (const type of meta.outgoingCapabilities) - this._identity.body.outgoingCapabilities.push(type); - } - } - - /** - * Emit Core.ChannelService::channel - * - * @param {Core.Channel} channel - The new channel - */ - channel(channel) { - if (!this.emit('channel', channel)) - channel.close(); - } - - /** - * Start the channel service. Implementations should throw an error if the - * service fails to meet any of its requirements for opening or accepting - * connections. - */ - start() { - throw new GObject.NotImplementedError(); - } - - /** - * Stop the channel service. - */ - stop() { - throw new GObject.NotImplementedError(); - } - - /** - * Destroy the channel service. - */ - destroy() { - } -}); - - -/** - * A class representing a file transfer. - */ -var Transfer = GObject.registerClass({ - GTypeName: 'GSConnectTransfer', - Properties: { - 'channel': GObject.ParamSpec.object( - 'channel', - 'Channel', - 'The channel that owns this transfer', - GObject.ParamFlags.READWRITE, - Channel.$gtype - ), - 'completed': GObject.ParamSpec.boolean( - 'completed', - 'Completed', - 'Whether the transfer has completed', - GObject.ParamFlags.READABLE, - false - ), - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device that created this transfer', - GObject.ParamFlags.READWRITE, - GObject.Object.$gtype - ), - }, -}, class Transfer extends GObject.Object { - - _init(params = {}) { - super._init(params); - - this._cancellable = new Gio.Cancellable(); - this._items = []; - } - - get channel() { - if (this._channel === undefined) - this._channel = null; - - return this._channel; - } - - set channel(channel) { - if (this.channel === channel) - return; - - this._channel = channel; - } - - get completed() { - if (this._completed === undefined) - this._completed = false; - - return this._completed; - } - - get device() { - if (this._device === undefined) - this._device = null; - - return this._device; - } - - set device(device) { - if (this.device === device) - return; - - this._device = device; - } - - get uuid() { - if (this._uuid === undefined) - this._uuid = GLib.uuid_string_random(); - - return this._uuid; - } - - /** - * Ensure there is a stream for the transfer item. - * - * @param {Object} item - A transfer item - * @param {Gio.Cancellable} [cancellable] - A cancellable - */ - async _ensureStream(item, cancellable = null) { - // This is an upload from a remote device - if (item.packet.hasPayload()) { - if (item.target instanceof Gio.OutputStream) - return; - - if (item.file instanceof Gio.File) { - item.target = await new Promise((resolve, reject) => { - item.file.replace_async( - null, - false, - Gio.FileCreateFlags.REPLACE_DESTINATION, - GLib.PRIORITY_DEFAULT, - this._cancellable, - (file, res) => { - try { - resolve(file.replace_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } - } else { - if (item.source instanceof Gio.InputStream) - return; - - if (item.file instanceof Gio.File) { - const read = new Promise((resolve, reject) => { - item.file.read_async( - GLib.PRIORITY_DEFAULT, - cancellable, - (file, res) => { - try { - resolve(file.read_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - const query = new Promise((resolve, reject) => { - item.file.query_info_async( - Gio.FILE_ATTRIBUTE_STANDARD_SIZE, - Gio.FileQueryInfoFlags.NONE, - GLib.PRIORITY_DEFAULT, - cancellable, - (file, res) => { - try { - resolve(file.query_info_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - const [stream, info] = await Promise.all([read, query]); - item.source = stream; - item.size = info.get_size(); - } - } - } - - /** - * Add a file to the transfer. - * - * @param {Core.Packet} packet - A packet - * @param {Gio.File} file - A file to transfer - */ - addFile(packet, file) { - const item = { - packet: new Packet(packet), - file: file, - source: null, - target: null, - }; - - this._items.push(item); - } - - /** - * Add a filepath to the transfer. - * - * @param {Core.Packet} packet - A packet - * @param {string} path - A filepath to transfer - */ - addPath(packet, path) { - const item = { - packet: new Packet(packet), - file: Gio.File.new_for_path(path), - source: null, - target: null, - }; - - this._items.push(item); - } - - /** - * Add a stream to the transfer. - * - * @param {Core.Packet} packet - A packet - * @param {Gio.InputStream|Gio.OutputStream} stream - A stream to transfer - * @param {number} [size] - Payload size - */ - addStream(packet, stream, size = 0) { - const item = { - packet: new Packet(packet), - file: null, - source: null, - target: null, - size: size, - }; - - if (stream instanceof Gio.InputStream) - item.source = stream; - else if (stream instanceof Gio.OutputStream) - item.target = stream; - - this._items.push(item); - } - - /** - * Execute a transfer operation. Implementations may override this, while - * the default uses g_output_stream_splice(). - * - * @param {Gio.Cancellable} [cancellable] - A cancellable - */ - async start(cancellable = null) { - let error = null; - - try { - let item; - - // If a cancellable is passed in, chain to its signal - if (cancellable instanceof Gio.Cancellable) - cancellable.connect(() => this._cancellable.cancel()); - - while ((item = this._items.shift())) { - // If created for a device, ignore connection changes by - // ensuring we have the most recent channel - if (this.device !== null) - this._channel = this.device.channel; - - // TODO: transfer queueing? - if (this.channel === null || this.channel.closed) { - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.CONNECTION_CLOSED, - message: 'Channel is closed', - }); - } - - await this._ensureStream(item, this._cancellable); - - if (item.packet.hasPayload()) { - await this.channel.download(item.packet, item.target, - this._cancellable); - } else { - await this.channel.upload(item.packet, item.source, - item.size, this._cancellable); - } - } - } catch (e) { - error = e; - } finally { - this._completed = true; - this.notify('completed'); - } - - if (error !== null) - throw error; - } - - cancel() { - if (this._cancellable.is_cancelled() === false) - this._cancellable.cancel(); - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/daemon.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/daemon.js deleted file mode 100755 index 30bd8c4..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/daemon.js +++ /dev/null @@ -1,728 +0,0 @@ -#!/usr/bin/env gjs - -'use strict'; - -// Allow TLSv1.0 certificates -// See https://github.com/andyholmes/gnome-shell-extension-gsconnect/issues/930 -imports.gi.GLib.setenv('G_TLS_GNUTLS_PRIORITY', 'NORMAL:%COMPAT:+VERS-TLS1.0', true); - -imports.gi.versions.Gdk = '3.0'; -imports.gi.versions.GdkPixbuf = '2.0'; -imports.gi.versions.Gio = '2.0'; -imports.gi.versions.GIRepository = '2.0'; -imports.gi.versions.GLib = '2.0'; -imports.gi.versions.GObject = '2.0'; -imports.gi.versions.Gtk = '3.0'; -imports.gi.versions.Pango = '1.0'; - -const Gdk = imports.gi.Gdk; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - - -// Bootstrap -function get_datadir() { - const m = /@(.+):\d+/.exec((new Error()).stack.split('\n')[1]); - return Gio.File.new_for_path(m[1]).get_parent().get_parent().get_path(); -} - -imports.searchPath.unshift(get_datadir()); -imports.config.PACKAGE_DATADIR = imports.searchPath[0]; - - -// Local Imports -const Config = imports.config; -const Manager = imports.service.manager; -const ServiceUI = imports.service.ui.service; - - -/** - * Class representing the GSConnect service daemon. - */ -const Service = GObject.registerClass({ - GTypeName: 'GSConnectService', -}, class Service extends Gtk.Application { - - _init() { - super._init({ - application_id: 'org.gnome.Shell.Extensions.GSConnect', - flags: Gio.ApplicationFlags.HANDLES_OPEN, - resource_base_path: '/org/gnome/Shell/Extensions/GSConnect', - }); - - GLib.set_prgname('gsconnect'); - GLib.set_application_name('GSConnect'); - - // Command-line - this._initOptions(); - } - - get settings() { - if (this._settings === undefined) { - this._settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup(Config.APP_ID, true), - }); - } - - return this._settings; - } - - /* - * GActions - */ - _initActions() { - const actions = [ - ['connect', this._identify.bind(this), new GLib.VariantType('s')], - ['device', this._device.bind(this), new GLib.VariantType('(ssbv)')], - ['error', this._error.bind(this), new GLib.VariantType('a{ss}')], - ['preferences', this._preferences, null], - ['quit', () => this.quit(), null], - ['refresh', this._identify.bind(this), null], - ]; - - for (const [name, callback, type] of actions) { - const action = new Gio.SimpleAction({ - name: name, - parameter_type: type, - }); - action.connect('activate', callback); - this.add_action(action); - } - } - - /** - * A wrapper for Device GActions. This is used to route device notification - * actions to their device, since GNotifications need an 'app' level action. - * - * @param {Gio.Action} action - The GAction - * @param {GLib.Variant} parameter - The activation parameter - */ - _device(action, parameter) { - try { - parameter = parameter.unpack(); - - // Select the appropriate device(s) - let devices; - const id = parameter[0].unpack(); - - if (id === '*') - devices = this.manager.devices.values(); - else - devices = [this.manager.devices.get(id)]; - - // Unpack the action data and activate the action - const name = parameter[1].unpack(); - const target = parameter[2].unpack() ? parameter[3].unpack() : null; - - for (const device of devices) - device.activate_action(name, target); - } catch (e) { - logError(e); - } - } - - _error(action, parameter) { - try { - const error = parameter.deepUnpack(); - - // If there's a URL, we have better information in the Wiki - if (error.url !== undefined) { - Gio.AppInfo.launch_default_for_uri_async( - error.url, - null, - null, - null - ); - return; - } - - const dialog = new ServiceUI.ErrorDialog(error); - dialog.present(); - } catch (e) { - logError(e); - } - } - - _identify(action, parameter) { - try { - let uri = null; - - if (parameter instanceof GLib.Variant) - uri = parameter.unpack(); - - this.manager.identify(uri); - } catch (e) { - logError(e); - } - } - - _preferences() { - Gio.Subprocess.new( - [`${Config.PACKAGE_DATADIR}/gsconnect-preferences`], - Gio.SubprocessFlags.NONE - ); - } - - /** - * Report a service-level error - * - * @param {Object} error - An Error or object with name, message and stack - */ - notify_error(error) { - try { - // Always log the error - logError(error); - - // Create an new notification - let id, body, priority; - const notif = new Gio.Notification(); - const icon = new Gio.ThemedIcon({name: 'dialog-error'}); - let target = null; - - if (error.name === undefined) - error.name = 'Error'; - - if (error.url !== undefined) { - id = error.url; - body = _('Click for help troubleshooting'); - priority = Gio.NotificationPriority.URGENT; - - target = new GLib.Variant('a{ss}', { - name: error.name.trim(), - message: error.message.trim(), - stack: error.stack.trim(), - url: error.url, - }); - } else { - id = error.message.trim(); - body = _('Click for more information'); - priority = Gio.NotificationPriority.HIGH; - - target = new GLib.Variant('a{ss}', { - name: error.name.trim(), - message: error.message.trim(), - stack: error.stack.trim(), - }); - } - - notif.set_title(`GSConnect: ${error.name.trim()}`); - notif.set_body(body); - notif.set_icon(icon); - notif.set_priority(priority); - notif.set_default_action_and_target('app.error', target); - - this.send_notification(id, notif); - } catch (e) { - logError(e); - } - } - - vfunc_activate() { - super.vfunc_activate(); - } - - vfunc_startup() { - super.vfunc_startup(); - - this.hold(); - - // Watch *this* file and stop the service if it's updated/uninstalled - this._serviceMonitor = Gio.File.new_for_path( - `${Config.PACKAGE_DATADIR}/service/daemon.js` - ).monitor(Gio.FileMonitorFlags.WATCH_MOVES, null); - this._serviceMonitor.connect('changed', () => this.quit()); - - // Init some resources - const provider = new Gtk.CssProvider(); - provider.load_from_resource(`${Config.APP_PATH}/application.css`); - Gtk.StyleContext.add_provider_for_screen( - Gdk.Screen.get_default(), - provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ); - - // Ensure our handlers are registered - try { - const appInfo = Gio.DesktopAppInfo.new(`${Config.APP_ID}.desktop`); - appInfo.add_supports_type('x-scheme-handler/sms'); - appInfo.add_supports_type('x-scheme-handler/tel'); - } catch (e) { - debug(e); - } - - // GActions & GSettings - this._initActions(); - - this.manager.start(); - } - - vfunc_dbus_register(connection, object_path) { - if (!super.vfunc_dbus_register(connection, object_path)) - return false; - - this.manager = new Manager.Manager({ - connection: connection, - object_path: object_path, - }); - - return true; - } - - vfunc_dbus_unregister(connection, object_path) { - this.manager.destroy(); - - super.vfunc_dbus_unregister(connection, object_path); - } - - vfunc_open(files, hint) { - super.vfunc_open(files, hint); - - for (const file of files) { - let action, parameter, title; - - try { - switch (file.get_uri_scheme()) { - case 'sms': - title = _('Send SMS'); - action = 'uriSms'; - parameter = new GLib.Variant('s', file.get_uri()); - break; - - case 'tel': - title = _('Dial Number'); - action = 'shareUri'; - parameter = new GLib.Variant('s', file.get_uri()); - break; - - case 'file': - title = _('Share File'); - action = 'shareFile'; - parameter = new GLib.Variant('(sb)', [file.get_uri(), false]); - break; - - default: - throw new Error(`Unsupported URI: ${file.get_uri()}`); - } - - // Show chooser dialog - new ServiceUI.DeviceChooser({ - title: title, - action_name: action, - action_target: parameter, - }); - } catch (e) { - logError(e, `GSConnect: Opening ${file.get_uri()}`); - } - } - } - - vfunc_shutdown() { - // Dispose GSettings - if (this._settings !== undefined) - this.settings.run_dispose(); - - this.manager.stop(); - - // Exhaust the event loop to ensure any pending operations complete - const context = GLib.MainContext.default(); - - while (context.iteration(false)) - continue; - - // Force a GC to prevent any more calls back into JS, then chain-up - imports.system.gc(); - super.vfunc_shutdown(); - } - - /* - * CLI - */ - _initOptions() { - /* - * Device Listings - */ - this.add_main_option( - 'list-devices', - 'l'.charCodeAt(0), - GLib.OptionFlags.NONE, - GLib.OptionArg.NONE, - _('List available devices'), - null - ); - - this.add_main_option( - 'list-all', - 'a'.charCodeAt(0), - GLib.OptionFlags.NONE, - GLib.OptionArg.NONE, - _('List all devices'), - null - ); - - this.add_main_option( - 'device', - 'd'.charCodeAt(0), - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING, - _('Target Device'), - '' - ); - - /** - * Pairing - */ - this.add_main_option( - 'pair', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.NONE, - _('Pair'), - null - ); - - this.add_main_option( - 'unpair', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.NONE, - _('Unpair'), - null - ); - - /* - * Messaging - */ - this.add_main_option( - 'message', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING_ARRAY, - _('Send SMS'), - '' - ); - - this.add_main_option( - 'message-body', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING, - _('Message Body'), - '' - ); - - /* - * Notifications - */ - this.add_main_option( - 'notification', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING, - _('Send Notification'), - '' - ); - - this.add_main_option( - 'notification-appname', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING, - _('Notification App Name'), - '<name>' - ); - - this.add_main_option( - 'notification-body', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING, - _('Notification Body'), - '<text>' - ); - - this.add_main_option( - 'notification-icon', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING, - _('Notification Icon'), - '<icon-name>' - ); - - this.add_main_option( - 'notification-id', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING, - _('Notification ID'), - '<id>' - ); - - this.add_main_option( - 'photo', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.NONE, - _('Photo'), - null - ); - - this.add_main_option( - 'ping', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.NONE, - _('Ping'), - null - ); - - this.add_main_option( - 'ring', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.NONE, - _('Ring'), - null - ); - - /* - * Sharing - */ - this.add_main_option( - 'share-file', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.FILENAME_ARRAY, - _('Share File'), - '<filepath|URI>' - ); - - this.add_main_option( - 'share-link', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING_ARRAY, - _('Share Link'), - '<URL>' - ); - - this.add_main_option( - 'share-text', - 0, - GLib.OptionFlags.NONE, - GLib.OptionArg.STRING, - _('Share Text'), - '<text>' - ); - - /* - * Misc - */ - this.add_main_option( - 'version', - 'v'.charCodeAt(0), - GLib.OptionFlags.NONE, - GLib.OptionArg.NONE, - _('Show release version'), - null - ); - } - - _cliAction(id, name, parameter = null) { - const parameters = []; - - if (parameter instanceof GLib.Variant) - parameters[0] = parameter; - - id = id.replace(/\W+/g, '_'); - - Gio.DBus.session.call_sync( - 'org.gnome.Shell.Extensions.GSConnect', - `/org/gnome/Shell/Extensions/GSConnect/Device/${id}`, - 'org.gtk.Actions', - 'Activate', - GLib.Variant.new('(sava{sv})', [name, parameters, {}]), - null, - Gio.DBusCallFlags.NONE, - -1, - null - ); - } - - _cliListDevices(full = true) { - const result = Gio.DBus.session.call_sync( - 'org.gnome.Shell.Extensions.GSConnect', - '/org/gnome/Shell/Extensions/GSConnect', - 'org.freedesktop.DBus.ObjectManager', - 'GetManagedObjects', - null, - null, - Gio.DBusCallFlags.NONE, - -1, - null - ); - - const variant = result.unpack()[0].unpack(); - let device; - - for (let object of Object.values(variant)) { - object = object.recursiveUnpack(); - device = object['org.gnome.Shell.Extensions.GSConnect.Device']; - - if (full) - print(`${device.Id}\t${device.Name}\t${device.Connected}\t${device.Paired}`); - else if (device.Connected && device.Paired) - print(device.Id); - } - } - - _cliMessage(id, options) { - if (!options.contains('message-body')) - throw new TypeError('missing --message-body option'); - - // TODO: currently we only support single-recipient messaging - const addresses = options.lookup_value('message', null).deepUnpack(); - const body = options.lookup_value('message-body', null).deepUnpack(); - - this._cliAction( - id, - 'sendSms', - GLib.Variant.new('(ss)', [addresses[0], body]) - ); - } - - _cliNotify(id, options) { - const title = options.lookup_value('notification', null).unpack(); - let body = ''; - let icon = null; - let nid = `${Date.now()}`; - let appName = 'GSConnect CLI'; - - if (options.contains('notification-id')) - nid = options.lookup_value('notification-id', null).unpack(); - - if (options.contains('notification-body')) - body = options.lookup_value('notification-body', null).unpack(); - - if (options.contains('notification-appname')) - appName = options.lookup_value('notification-appname', null).unpack(); - - if (options.contains('notification-icon')) { - icon = options.lookup_value('notification-icon', null).unpack(); - icon = Gio.Icon.new_for_string(icon); - } else { - icon = new Gio.ThemedIcon({ - name: 'org.gnome.Shell.Extensions.GSConnect', - }); - } - - const notification = new GLib.Variant('a{sv}', { - appName: GLib.Variant.new_string(appName), - id: GLib.Variant.new_string(nid), - title: GLib.Variant.new_string(title), - text: GLib.Variant.new_string(body), - ticker: GLib.Variant.new_string(`${title}: ${body}`), - time: GLib.Variant.new_string(`${Date.now()}`), - isClearable: GLib.Variant.new_boolean(true), - icon: icon.serialize(), - }); - - this._cliAction(id, 'sendNotification', notification); - } - - _cliShareFile(device, options) { - const files = options.lookup_value('share-file', null).deepUnpack(); - - for (let file of files) { - file = imports.byteArray.toString(file); - this._cliAction(device, 'shareFile', GLib.Variant.new('(sb)', [file, false])); - } - } - - _cliShareLink(device, options) { - const uris = options.lookup_value('share-link', null).unpack(); - - for (const uri of uris) - this._cliAction(device, 'shareUri', uri); - } - - _cliShareText(device, options) { - const text = options.lookup_value('share-text', null).unpack(); - - this._cliAction(device, 'shareText', GLib.Variant.new_string(text)); - } - - vfunc_handle_local_options(options) { - try { - if (options.contains('version')) { - print(`GSConnect ${Config.PACKAGE_VERSION}`); - return 0; - } - - this.register(null); - - if (options.contains('list-devices')) { - this._cliListDevices(false); - return 0; - } - - if (options.contains('list-all')) { - this._cliListDevices(true); - return 0; - } - - // We need a device for anything else; exit since this is probably - // the daemon being started. - if (!options.contains('device')) - return -1; - - const id = options.lookup_value('device', null).unpack(); - - // Pairing - if (options.contains('pair')) { - this._cliAction(id, 'pair'); - return 0; - } - - if (options.contains('unpair')) { - this._cliAction(id, 'unpair'); - return 0; - } - - // Plugins - if (options.contains('message')) - this._cliMessage(id, options); - - if (options.contains('notification')) - this._cliNotify(id, options); - - if (options.contains('photo')) - this._cliAction(id, 'photo'); - - if (options.contains('ping')) - this._cliAction(id, 'ping', GLib.Variant.new_string('')); - - if (options.contains('ring')) - this._cliAction(id, 'ring'); - - if (options.contains('share-file')) - this._cliShareFile(id, options); - - if (options.contains('share-link')) - this._cliShareLink(id, options); - - if (options.contains('share-text')) - this._cliShareText(id, options); - - return 0; - } catch (e) { - logError(e); - return 1; - } - } -}); - -(new Service()).run([imports.system.programInvocationName].concat(ARGV)); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/device.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/device.js deleted file mode 100644 index eb0e915..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/device.js +++ /dev/null @@ -1,1051 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Config = imports.config; -const Components = imports.service.components; -const Core = imports.service.core; - - -/** - * An object representing a remote device. - * - * Device class is subclassed from Gio.SimpleActionGroup so it implements the - * GActionGroup and GActionMap interfaces, like Gio.Application. - * - */ -var Device = GObject.registerClass({ - GTypeName: 'GSConnectDevice', - Properties: { - 'connected': GObject.ParamSpec.boolean( - 'connected', - 'Connected', - 'Whether the device is connected', - GObject.ParamFlags.READABLE, - false - ), - 'contacts': GObject.ParamSpec.object( - 'contacts', - 'Contacts', - 'The contacts store for this device', - GObject.ParamFlags.READABLE, - GObject.Object - ), - 'encryption-info': GObject.ParamSpec.string( - 'encryption-info', - 'Encryption Info', - 'A formatted string with the local and remote fingerprints', - GObject.ParamFlags.READABLE, - null - ), - 'icon-name': GObject.ParamSpec.string( - 'icon-name', - 'Icon Name', - 'Icon name representing the device', - GObject.ParamFlags.READABLE, - null - ), - 'id': GObject.ParamSpec.string( - 'id', - 'Id', - 'The device hostname or other network unique id', - GObject.ParamFlags.READABLE, - '' - ), - 'name': GObject.ParamSpec.string( - 'name', - 'Name', - 'The device name', - GObject.ParamFlags.READABLE, - null - ), - 'paired': GObject.ParamSpec.boolean( - 'paired', - 'Paired', - 'Whether the device is paired', - GObject.ParamFlags.READABLE, - false - ), - 'type': GObject.ParamSpec.string( - 'type', - 'Type', - 'The device type', - GObject.ParamFlags.READABLE, - null - ), - }, -}, class Device extends Gio.SimpleActionGroup { - - _init(identity) { - super._init(); - - this._id = identity.body.deviceId; - - // GLib.Source timeout id's for pairing requests - this._incomingPairRequest = 0; - this._outgoingPairRequest = 0; - - // Maps of name->Plugin, packet->Plugin, uuid->Transfer - this._plugins = new Map(); - this._handlers = new Map(); - this._procs = new Set(); - this._transfers = new Map(); - - this._outputLock = false; - this._outputQueue = []; - - // GSettings - this.settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup( - 'org.gnome.Shell.Extensions.GSConnect.Device', - true - ), - path: `/org/gnome/shell/extensions/gsconnect/device/${this.id}/`, - }); - - // Watch for changes to supported and disabled plugins - this._disabledPluginsChangedId = this.settings.connect( - 'changed::disabled-plugins', - this._onAllowedPluginsChanged.bind(this) - ); - this._supportedPluginsChangedId = this.settings.connect( - 'changed::supported-plugins', - this._onAllowedPluginsChanged.bind(this) - ); - - this._registerActions(); - this.menu = new Gio.Menu(); - - // Parse identity if initialized with a proper packet, otherwise load - if (identity.id !== undefined) - this._handleIdentity(identity); - else - this._loadPlugins(); - } - - get channel() { - if (this._channel === undefined) - this._channel = null; - - return this._channel; - } - - get connected() { - if (this._connected === undefined) - this._connected = false; - - return this._connected; - } - - get connection_type() { - const lastConnection = this.settings.get_string('last-connection'); - - return lastConnection.split('://')[0]; - } - - get contacts() { - const contacts = this._plugins.get('contacts'); - - if (contacts && contacts.settings.get_boolean('contacts-source')) - return contacts._store; - - if (this._contacts === undefined) - this._contacts = Components.acquire('contacts'); - - return this._contacts; - } - - // FIXME: backend should do this stuff - get encryption_info() { - let remoteFingerprint = _('Not available'); - let localFingerprint = _('Not available'); - - // Bluetooth connections have no certificate so we use the host address - if (this.connection_type === 'bluetooth') { - // TRANSLATORS: Bluetooth address for remote device - return _('Bluetooth device at %s').format('???'); - - // If the device is connected use the certificate from the connection - } else if (this.connected) { - remoteFingerprint = this.channel.peer_certificate.sha256(); - - // Otherwise pull it out of the settings - } else if (this.paired) { - remoteFingerprint = Gio.TlsCertificate.new_from_pem( - this.settings.get_string('certificate-pem'), - -1 - ).sha256(); - } - - // FIXME: another ugly reach-around - let lanBackend; - - if (this.service !== null) - lanBackend = this.service.manager.backends.get('lan'); - - if (lanBackend && lanBackend.certificate) - localFingerprint = lanBackend.certificate.sha256(); - - // TRANSLATORS: Label for TLS Certificate fingerprint - // - // Example: - // - // Google Pixel Fingerprint: - // 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 - return _('%s Fingerprint:').format(this.name) + '\n' + - remoteFingerprint + '\n\n' + - _('%s Fingerprint:').format('GSConnect') + '\n' + - localFingerprint; - } - - get id() { - return this._id; - } - - get name() { - return this.settings.get_string('name'); - } - - get paired() { - return this.settings.get_boolean('paired'); - } - - get icon_name() { - switch (this.type) { - case 'laptop': - return 'laptop-symbolic'; - case 'phone': - return 'smartphone-symbolic'; - case 'tablet': - return 'tablet-symbolic'; - case 'tv': - return 'tv-symbolic'; - case 'desktop': - default: - return 'computer-symbolic'; - } - } - - get service() { - if (this._service === undefined) - this._service = Gio.Application.get_default(); - - return this._service; - } - - get type() { - return this.settings.get_string('type'); - } - - _handleIdentity(packet) { - this.freeze_notify(); - - // If we're connected, record the reconnect URI - if (this.channel !== null) - this.settings.set_string('last-connection', this.channel.address); - - // The type won't change, but it might not be properly set yet - if (this.type !== packet.body.deviceType) { - this.settings.set_string('type', packet.body.deviceType); - this.notify('type'); - this.notify('icon-name'); - } - - // The name may change so we check and notify if so - if (this.name !== packet.body.deviceName) { - this.settings.set_string('name', packet.body.deviceName); - this.notify('name'); - } - - // Packets - const incoming = packet.body.incomingCapabilities.sort(); - const outgoing = packet.body.outgoingCapabilities.sort(); - const inc = this.settings.get_strv('incoming-capabilities'); - const out = this.settings.get_strv('outgoing-capabilities'); - - // Only write GSettings if something has changed - if (incoming.join('') !== inc.join('') || outgoing.join('') !== out.join('')) { - this.settings.set_strv('incoming-capabilities', incoming); - this.settings.set_strv('outgoing-capabilities', outgoing); - } - - // Determine supported plugins by matching incoming to outgoing types - const supported = []; - - for (const name in imports.service.plugins) { - // Exclude mousepad/presenter plugins in unsupported sessions - if (!HAVE_REMOTEINPUT && ['mousepad', 'presenter'].includes(name)) - continue; - - const meta = imports.service.plugins[name].Metadata; - - // If we can handle packets it sends or send packets it can handle - if (meta.incomingCapabilities.some(t => outgoing.includes(t)) || - meta.outgoingCapabilities.some(t => incoming.includes(t))) - supported.push(name); - } - - // Only write GSettings if something has changed - const currentSupported = this.settings.get_strv('supported-plugins'); - - if (currentSupported.join('') !== supported.sort().join('')) - this.settings.set_strv('supported-plugins', supported); - - this.thaw_notify(); - } - - /** - * Set the channel and start sending/receiving packets. If %null is passed - * the device becomes disconnected. - * - * @param {Core.Channel} [channel] - The new channel - */ - setChannel(channel = null) { - if (this.channel === channel) - return; - - if (this.channel !== null) - this.channel.close(); - - this._channel = channel; - - // If we've disconnected empty the queue, otherwise restart the read - // loop and update the device metadata - if (this.channel === null) { - this._outputQueue.length = 0; - } else { - this._handleIdentity(this.channel.identity); - this._readLoop(channel); - } - - // The connected state didn't change - if (this.connected === !!this.channel) - return; - - // Notify and trigger plugins - this._connected = !!this.channel; - this.notify('connected'); - this._triggerPlugins(); - } - - async _readLoop(channel) { - try { - let packet = null; - - while ((packet = await this.channel.readPacket())) { - debug(packet, this.name); - this.handlePacket(packet); - } - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - debug(e, this.name); - - if (this.channel === channel) - this.setChannel(null); - } - } - - _processExit(proc, result) { - try { - proc.wait_check_finish(result); - } catch (e) { - debug(e); - } - - this.delete(proc); - } - - /** - * Launch a subprocess for the device. If the device becomes unpaired, it is - * assumed the device is no longer trusted and all subprocesses will be - * killed. - * - * @param {string[]} args - process arguments - * @param {Gio.Cancellable} [cancellable] - optional cancellable - * @return {Gio.Subprocess} The subprocess - */ - launchProcess(args, cancellable = null) { - if (this._launcher === undefined) { - const application = GLib.build_filenamev([ - Config.PACKAGE_DATADIR, - 'service', - 'daemon.js', - ]); - - this._launcher = new Gio.SubprocessLauncher(); - this._launcher.setenv('GSCONNECT', application, false); - this._launcher.setenv('GSCONNECT_DEVICE_ID', this.id, false); - this._launcher.setenv('GSCONNECT_DEVICE_NAME', this.name, false); - this._launcher.setenv('GSCONNECT_DEVICE_ICON', this.icon_name, false); - this._launcher.setenv( - 'GSCONNECT_DEVICE_DBUS', - `${Config.APP_PATH}/Device/${this.id.replace(/\W+/g, '_')}`, - false - ); - } - - // Create and track the process - const proc = this._launcher.spawnv(args); - proc.wait_check_async(cancellable, this._processExit.bind(this._procs)); - this._procs.add(proc); - - return proc; - } - - /** - * Handle a packet and pass it to the appropriate plugin. - * - * @param {Core.Packet} packet - The incoming packet object - * @return {undefined} no return value - */ - handlePacket(packet) { - try { - if (packet.type === 'kdeconnect.pair') - return this._handlePair(packet); - - // The device must think we're paired; inform it we are not - if (!this.paired) - return this.unpair(); - - const handler = this._handlers.get(packet.type); - - if (handler !== undefined) - handler.handlePacket(packet); - else - debug(`Unsupported packet type (${packet.type})`, this.name); - } catch (e) { - debug(e, this.name); - } - } - - /** - * Send a packet to the device. - * - * @param {Object} packet - An object of packet data... - */ - async sendPacket(packet) { - try { - if (!this.connected) - return; - - if (!this.paired && packet.type !== 'kdeconnect.pair') - return; - - this._outputQueue.push(new Core.Packet(packet)); - - if (this._outputLock) - return; - - this._outputLock = true; - let next; - - while ((next = this._outputQueue.shift())) { - await this.channel.sendPacket(next); - debug(next, this.name); - } - - this._outputLock = false; - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - debug(e, this.name); - - this._outputLock = false; - } - } - - /** - * Actions - */ - _registerActions() { - // Pairing notification actions - const acceptPair = new Gio.SimpleAction({name: 'pair'}); - acceptPair.connect('activate', this.pair.bind(this)); - this.add_action(acceptPair); - - const rejectPair = new Gio.SimpleAction({name: 'unpair'}); - rejectPair.connect('activate', this.unpair.bind(this)); - this.add_action(rejectPair); - - // Transfer notification actions - const cancelTransfer = new Gio.SimpleAction({ - name: 'cancelTransfer', - parameter_type: new GLib.VariantType('s'), - }); - cancelTransfer.connect('activate', this.cancelTransfer.bind(this)); - this.add_action(cancelTransfer); - - const openPath = new Gio.SimpleAction({ - name: 'openPath', - parameter_type: new GLib.VariantType('s'), - }); - openPath.connect('activate', this.openPath); - this.add_action(openPath); - - // Preference helpers - const clearCache = new Gio.SimpleAction({ - name: 'clearCache', - parameter_type: null, - }); - clearCache.connect('activate', this._clearCache.bind(this)); - this.add_action(clearCache); - } - - /** - * Get the position of a GMenuItem with @actionName in the top level of the - * device menu. - * - * @param {string} actionName - An action name with scope (eg. device.foo) - * @return {number} An 0-based index or -1 if not found - */ - getMenuAction(actionName) { - for (let i = 0, len = this.menu.get_n_items(); i < len; i++) { - try { - const val = this.menu.get_item_attribute_value(i, 'action', null); - - if (val.unpack() === actionName) - return i; - } catch (e) { - continue; - } - } - - return -1; - } - - /** - * Add a GMenuItem to the top level of the device menu - * - * @param {Gio.MenuItem} menuItem - A GMenuItem - * @param {number} [index] - The position to place the item - * @return {number} The position the item was placed - */ - addMenuItem(menuItem, index = -1) { - try { - if (index > -1) { - this.menu.insert_item(index, menuItem); - return index; - } - - this.menu.append_item(menuItem); - return this.menu.get_n_items(); - } catch (e) { - debug(e, this.name); - return -1; - } - } - - /** - * Add a Device GAction to the top level of the device menu - * - * @param {Gio.Action} action - A GAction - * @param {number} [index] - The position to place the item - * @param {string} label - A label for the item - * @param {string} icon_name - A themed icon name for the item - * @return {number} The position the item was placed - */ - addMenuAction(action, index = -1, label, icon_name) { - try { - const item = new Gio.MenuItem(); - - if (label) - item.set_label(label); - - if (icon_name) - item.set_icon(new Gio.ThemedIcon({name: icon_name})); - - item.set_attribute_value( - 'hidden-when', - new GLib.Variant('s', 'action-disabled') - ); - - item.set_detailed_action(`device.${action.name}`); - - return this.addMenuItem(item, index); - } catch (e) { - debug(e, this.name); - return -1; - } - } - - /** - * Remove a GAction from the top level of the device menu by action name - * - * @param {string} actionName - A GAction name, including scope - * @return {number} The position the item was removed from or -1 - */ - removeMenuAction(actionName) { - try { - const index = this.getMenuAction(actionName); - - if (index > -1) - this.menu.remove(index); - - return index; - } catch (e) { - debug(e, this.name); - return -1; - } - } - - /** - * Withdraw a device notification. - * - * @param {string} id - Id for the notification to withdraw - */ - hideNotification(id) { - if (this.service === null) - return; - - this.service.withdraw_notification(`${this.id}|${id}`); - } - - /** - * Show a device notification. - * - * @param {Object} params - A dictionary of notification parameters - * @param {number} [params.id] - A UNIX epoch timestamp (ms) - * @param {string} [params.title] - A title - * @param {string} [params.body] - A body - * @param {Gio.Icon} [params.icon] - An icon - * @param {Gio.NotificationPriority} [params.priority] - The priority - * @param {Array} [params.actions] - A dictionary of action parameters - * @param {Array} [params.buttons] - An Array of buttons - */ - showNotification(params) { - if (this.service === null) - return; - - // KDE Connect on Android can sometimes give an undefined for params.body - Object.keys(params) - .forEach(key => params[key] === undefined && delete params[key]); - - params = Object.assign({ - id: Date.now(), - title: this.name, - body: '', - icon: new Gio.ThemedIcon({name: this.icon_name}), - priority: Gio.NotificationPriority.NORMAL, - action: null, - buttons: [], - }, params); - - const notif = new Gio.Notification(); - notif.set_title(params.title); - notif.set_body(params.body); - notif.set_icon(params.icon); - notif.set_priority(params.priority); - - // Default Action - if (params.action) { - const hasParameter = (params.action.parameter !== null); - - if (!hasParameter) - params.action.parameter = new GLib.Variant('s', ''); - - notif.set_default_action_and_target( - 'app.device', - new GLib.Variant('(ssbv)', [ - this.id, - params.action.name, - hasParameter, - params.action.parameter, - ]) - ); - } - - // Buttons - for (const button of params.buttons) { - const hasParameter = (button.parameter !== null); - - if (!hasParameter) - button.parameter = new GLib.Variant('s', ''); - - notif.add_button_with_target( - button.label, - 'app.device', - new GLib.Variant('(ssbv)', [ - this.id, - button.action, - hasParameter, - button.parameter, - ]) - ); - } - - this.service.send_notification(`${this.id}|${params.id}`, notif); - } - - /** - * Cancel an ongoing file transfer. - * - * @param {Gio.Action} action - The GAction - * @param {GLib.Variant} parameter - The activation parameter - */ - cancelTransfer(action, parameter) { - try { - const uuid = parameter.unpack(); - const transfer = this._transfers.get(uuid); - - if (transfer === undefined) - return; - - this._transfers.delete(uuid); - transfer.cancel(); - } catch (e) { - logError(e, this.name); - } - } - - /** - * Create a transfer object. - * - * @return {Core.Transfer} A new transfer - */ - createTransfer() { - const transfer = new Core.Transfer({device: this}); - - // Track the transfer - this._transfers.set(transfer.uuid, transfer); - - transfer.connect('notify::completed', (transfer) => { - this._transfers.delete(transfer.uuid); - }); - - return transfer; - } - - /** - * Reject the transfer payload described by @packet. - * - * @param {Core.Packet} packet - A packet - * @return {Promise} A promise for the operation - */ - rejectTransfer(packet) { - if (!packet || !packet.hasPayload()) - return; - - return this.channel.rejectTransfer(packet); - } - - openPath(action, parameter) { - const path = parameter.unpack(); - - // Normalize paths to URIs, assuming local file - const uri = path.includes('://') ? path : `file://${path}`; - Gio.AppInfo.launch_default_for_uri_async(uri, null, null, null); - } - - _clearCache(action, parameter) { - for (const plugin of this._plugins.values()) { - try { - plugin.clearCache(); - } catch (e) { - debug(e, this.name); - } - } - } - - /** - * Pair request handler - * - * @param {Core.Packet} packet - A complete kdeconnect.pair packet - */ - _handlePair(packet) { - // A pair has been requested/confirmed - if (packet.body.pair) { - // The device is accepting our request - if (this._outgoingPairRequest) { - this._setPaired(true); - this._loadPlugins(); - - // The device thinks we're unpaired - } else if (this.paired) { - this._setPaired(true); - this.sendPacket({ - type: 'kdeconnect.pair', - body: {pair: true}, - }); - this._triggerPlugins(); - - // The device is requesting pairing - } else { - this._notifyPairRequest(); - } - // Device is requesting unpairing/rejecting our request - } else { - this._setPaired(false); - this._unloadPlugins(); - } - } - - /** - * Notify the user of an incoming pair request and set a 30s timeout - */ - _notifyPairRequest() { - // Reset any active request - this._resetPairRequest(); - - this.showNotification({ - id: 'pair-request', - // TRANSLATORS: eg. Pair Request from Google Pixel - title: _('Pair Request from %s').format(this.name), - body: this.encryption_info, - icon: new Gio.ThemedIcon({name: 'channel-insecure-symbolic'}), - priority: Gio.NotificationPriority.URGENT, - buttons: [ - { - action: 'unpair', - label: _('Reject'), - parameter: null, - }, - { - action: 'pair', - label: _('Accept'), - parameter: null, - }, - ], - }); - - // Start a 30s countdown - this._incomingPairRequest = GLib.timeout_add_seconds( - GLib.PRIORITY_DEFAULT, - 30, - this._setPaired.bind(this, false) - ); - } - - /** - * Reset pair request timeouts and withdraw any notifications - */ - _resetPairRequest() { - this.hideNotification('pair-request'); - - if (this._incomingPairRequest) { - GLib.source_remove(this._incomingPairRequest); - this._incomingPairRequest = 0; - } - - if (this._outgoingPairRequest) { - GLib.source_remove(this._outgoingPairRequest); - this._outgoingPairRequest = 0; - } - } - - /** - * Set the internal paired state of the device and emit ::notify - * - * @param {boolean} paired - The paired state to set - */ - _setPaired(paired) { - this._resetPairRequest(); - - // For TCP connections we store or reset the TLS Certificate - if (this.connection_type === 'lan') { - if (paired) { - this.settings.set_string( - 'certificate-pem', - this.channel.peer_certificate.certificate_pem - ); - } else { - this.settings.reset('certificate-pem'); - } - } - - // If we've become unpaired, stop all subprocesses and transfers - if (!paired) { - for (const proc of this._procs) - proc.force_exit(); - - this._procs.clear(); - - for (const transfer of this._transfers.values()) - transfer.close(); - - this._transfers.clear(); - } - - this.settings.set_boolean('paired', paired); - this.notify('paired'); - } - - /** - * Send or accept an incoming pair request; also exported as a GAction - */ - pair() { - try { - // If we're accepting an incoming pair request, set the internal - // paired state and send the confirmation before loading plugins. - if (this._incomingPairRequest) { - this._setPaired(true); - - this.sendPacket({ - type: 'kdeconnect.pair', - body: {pair: true}, - }); - - this._loadPlugins(); - - // If we're initiating an outgoing pair request, be sure the timer - // is reset before sending the request and setting a 30s timeout. - } else if (!this.paired) { - this._resetPairRequest(); - - this.sendPacket({ - type: 'kdeconnect.pair', - body: {pair: true}, - }); - - this._outgoingPairRequest = GLib.timeout_add_seconds( - GLib.PRIORITY_DEFAULT, - 30, - this._setPaired.bind(this, false) - ); - } - } catch (e) { - logError(e, this.name); - } - } - - /** - * Unpair or reject an incoming pair request; also exported as a GAction - */ - unpair() { - try { - if (this.connected) { - this.sendPacket({ - type: 'kdeconnect.pair', - body: {pair: false}, - }); - } - - this._setPaired(false); - this._unloadPlugins(); - } catch (e) { - logError(e, this.name); - } - } - - /* - * Plugin Functions - */ - _onAllowedPluginsChanged(settings) { - const disabled = this.settings.get_strv('disabled-plugins'); - const supported = this.settings.get_strv('supported-plugins'); - const allowed = supported.filter(name => !disabled.includes(name)); - - // Unload any plugins that are disabled or unsupported - this._plugins.forEach(plugin => { - if (!allowed.includes(plugin.name)) - this._unloadPlugin(plugin.name); - }); - - // Make sure we change the contacts store if the plugin was disabled - if (!allowed.includes('contacts')) - this.notify('contacts'); - - // Load allowed plugins - for (const name of allowed) - this._loadPlugin(name); - } - - _loadPlugin(name) { - let handler, plugin; - - try { - if (this.paired && !this._plugins.has(name)) { - // Instantiate the handler - handler = imports.service.plugins[name]; - plugin = new handler.Plugin(this); - - // Register packet handlers - for (const packetType of handler.Metadata.incomingCapabilities) - this._handlers.set(packetType, plugin); - - // Register plugin - this._plugins.set(name, plugin); - - // Run the connected()/disconnected() handler - if (this.connected) - plugin.connected(); - else - plugin.disconnected(); - } - } catch (e) { - if (plugin !== undefined) - plugin.destroy(); - - if (this.service !== null) - this.service.notify_error(e); - else - logError(e, this.name); - } - } - - async _loadPlugins() { - const disabled = this.settings.get_strv('disabled-plugins'); - - for (const name of this.settings.get_strv('supported-plugins')) { - if (!disabled.includes(name)) - await this._loadPlugin(name); - } - } - - _unloadPlugin(name) { - let handler, plugin; - - try { - if (this._plugins.has(name)) { - // Unregister packet handlers - handler = imports.service.plugins[name]; - - for (const type of handler.Metadata.incomingCapabilities) - this._handlers.delete(type); - - // Unregister plugin - plugin = this._plugins.get(name); - this._plugins.delete(name); - plugin.destroy(); - } - } catch (e) { - logError(e, this.name); - } - } - - async _unloadPlugins() { - for (const name of this._plugins.keys()) - await this._unloadPlugin(name); - } - - _triggerPlugins() { - for (const plugin of this._plugins.values()) { - if (this.connected) - plugin.connected(); - else - plugin.disconnected(); - } - } - - destroy() { - // Drop the default contacts store if we were using it - if (this._contacts !== undefined) - this._contacts = Components.release('contacts'); - - // Close the channel if still connected - if (this.channel !== null) - this.channel.close(); - - // Synchronously destroy plugins - this._plugins.forEach(plugin => plugin.destroy()); - this._plugins.clear(); - - // Dispose GSettings - this.settings.disconnect(this._disabledPluginsChangedId); - this.settings.disconnect(this._supportedPluginsChangedId); - this.settings.run_dispose(); - - GObject.signal_handlers_destroy(this); - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/manager.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/manager.js deleted file mode 100644 index b254837..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/manager.js +++ /dev/null @@ -1,500 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Config = imports.config; -const DBus = imports.service.utils.dbus; -const Device = imports.service.device; - -const DEVICE_NAME = 'org.gnome.Shell.Extensions.GSConnect.Device'; -const DEVICE_PATH = '/org/gnome/Shell/Extensions/GSConnect/Device'; -const DEVICE_IFACE = Config.DBUS.lookup_interface(DEVICE_NAME); - - -/** - * A manager for devices. - */ -var Manager = GObject.registerClass({ - GTypeName: 'GSConnectManager', - Properties: { - 'active': GObject.ParamSpec.boolean( - 'active', - 'Active', - 'Whether the manager is active', - GObject.ParamFlags.READABLE, - false - ), - 'discoverable': GObject.ParamSpec.boolean( - 'discoverable', - 'Discoverable', - 'Whether the service responds to discovery requests', - GObject.ParamFlags.READWRITE, - false - ), - 'id': GObject.ParamSpec.string( - 'id', - 'Id', - 'The hostname or other network unique id', - GObject.ParamFlags.READWRITE, - null - ), - 'name': GObject.ParamSpec.string( - 'name', - 'Name', - 'The name announced to the network', - GObject.ParamFlags.READWRITE, - 'GSConnect' - ), - }, -}, class Manager extends Gio.DBusObjectManagerServer { - - _init(params = {}) { - super._init(params); - - this._exported = new WeakMap(); - this._reconnectId = 0; - - this._settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup(Config.APP_ID, true), - }); - this._initSettings(); - } - - get active() { - if (this._active === undefined) - this._active = false; - - return this._active; - } - - get backends() { - if (this._backends === undefined) - this._backends = new Map(); - - return this._backends; - } - - get devices() { - if (this._devices === undefined) - this._devices = new Map(); - - return this._devices; - } - - get discoverable() { - if (this._discoverable === undefined) - this._discoverable = this.settings.get_boolean('discoverable'); - - return this._discoverable; - } - - set discoverable(value) { - if (this.discoverable === value) - return; - - this._discoverable = value; - this.notify('discoverable'); - - // FIXME: This whole thing just keeps getting uglier - const application = Gio.Application.get_default(); - - if (application === null) - return; - - if (this.discoverable) { - Gio.Application.prototype.withdraw_notification.call( - application, - 'discovery-warning' - ); - } else { - const notif = new Gio.Notification(); - notif.set_title(_('Discovery Disabled')); - notif.set_body(_('Discovery has been disabled due to the number of devices on this network.')); - notif.set_icon(new Gio.ThemedIcon({name: 'dialog-warning'})); - notif.set_priority(Gio.NotificationPriority.HIGH); - notif.set_default_action('app.preferences'); - - Gio.Application.prototype.withdraw_notification.call( - application, - 'discovery-warning', - notif - ); - } - } - - get id() { - if (this._id === undefined) - this._id = this.settings.get_string('id'); - - return this._id; - } - - set id(value) { - if (this.id === value) - return; - - this._id = value; - this.notify('id'); - } - - get name() { - if (this._name === undefined) - this._name = this.settings.get_string('name'); - - return this._name; - } - - set name(value) { - if (this.name === value) - return; - - this._name = value; - this.notify('name'); - - // Broadcast changes to the network - for (const backend of this.backends.values()) { - backend.name = this.name; - backend.buildIdentity(); - } - - this.identify(); - } - - get settings() { - if (this._settings === undefined) { - this._settings = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup(Config.APP_ID, true), - }); - } - - return this._settings; - } - - vfunc_notify(pspec) { - if (pspec.name !== 'connection') - return; - - if (this.connection !== null) - this._exportDevices(); - else - this._unexportDevices(); - } - - /* - * GSettings - */ - _initSettings() { - // Initialize the ID and name of the service - if (this.settings.get_string('id').length === 0) - this.settings.set_string('id', GLib.uuid_string_random()); - - if (this.settings.get_string('name').length === 0) - this.settings.set_string('name', GLib.get_host_name()); - - // Bound Properties - this.settings.bind('discoverable', this, 'discoverable', 0); - this.settings.bind('id', this, 'id', 0); - this.settings.bind('name', this, 'name', 0); - } - - /* - * Backends - */ - _onChannel(backend, channel) { - try { - let device = this.devices.get(channel.identity.body.deviceId); - - switch (true) { - // Proceed if this is an existing device... - case (device !== undefined): - break; - - // Or the connection is allowed... - case this.discoverable || channel.allowed: - device = this._ensureDevice(channel.identity); - break; - - // ...otherwise bail - default: - debug(`${channel.identity.body.deviceName}: not allowed`); - return false; - } - - device.setChannel(channel); - return true; - } catch (e) { - logError(e, backend.name); - return false; - } - } - - _loadBackends() { - for (const name in imports.service.backends) { - try { - // Try to create the backend and track it if successful - const module = imports.service.backends[name]; - const backend = new module.ChannelService({ - id: this.id, - name: this.name, - }); - this.backends.set(name, backend); - - // Connect to the backend - backend.__channelId = backend.connect( - 'channel', - this._onChannel.bind(this) - ); - - // Now try to start the backend, allowing us to retry if we fail - backend.start(); - } catch (e) { - if (Gio.Application.get_default()) - Gio.Application.get_default().notify_error(e); - } - } - } - - /* - * Devices - */ - _loadDevices() { - // Load cached devices - for (const id of this.settings.get_strv('devices')) { - const device = new Device.Device({body: {deviceId: id}}); - this._exportDevice(device); - this.devices.set(id, device); - } - } - - _exportDevice(device) { - if (this.connection === null) - return; - - const info = { - object: null, - interface: null, - actions: 0, - menu: 0, - }; - - const objectPath = `${DEVICE_PATH}/${device.id.replace(/\W+/g, '_')}`; - - // Export an object path for the device - info.object = new Gio.DBusObjectSkeleton({ - g_object_path: objectPath, - }); - this.export(info.object); - - // Export GActions & GMenu - info.actions = Gio.DBus.session.export_action_group(objectPath, device); - info.menu = Gio.DBus.session.export_menu_model(objectPath, device.menu); - - // Export the Device interface - info.interface = new DBus.Interface({ - g_instance: device, - g_interface_info: DEVICE_IFACE, - }); - info.object.add_interface(info.interface); - - this._exported.set(device, info); - } - - _exportDevices() { - if (this.connection === null) - return; - - for (const device of this.devices.values()) - this._exportDevice(device); - } - - _unexportDevice(device) { - const info = this._exported.get(device); - - if (info === undefined) - return; - - // Unexport GActions and GMenu - Gio.DBus.session.unexport_action_group(info.actions); - Gio.DBus.session.unexport_menu_model(info.menu); - - // Unexport the Device interface and object - info.interface.flush(); - info.object.remove_interface(info.interface); - info.object.flush(); - this.unexport(info.object.g_object_path); - - this._exported.delete(device); - } - - _unexportDevices() { - for (const device of this.devices.values()) - this._unexportDevice(device); - } - - /** - * Return a device for @packet, creating it and adding it to the list of - * of known devices if it doesn't exist. - * - * @param {Core.Packet} packet - An identity packet for the device - * @return {Device.Device} A device object - */ - _ensureDevice(packet) { - let device = this.devices.get(packet.body.deviceId); - - if (device === undefined) { - debug(`Adding ${packet.body.deviceName}`); - - // TODO: Remove when all clients support bluetooth-like discovery - // - // If this is the third unpaired device to connect, we disable - // discovery to avoid choking on networks with many devices - const unpaired = Array.from(this.devices.values()).filter(dev => { - return !dev.paired; - }); - - if (unpaired.length === 3) - this.discoverable = false; - - device = new Device.Device(packet); - this._exportDevice(device); - this.devices.set(device.id, device); - - // Notify - this.settings.set_strv('devices', Array.from(this.devices.keys())); - } - - return device; - } - - /** - * Permanently remove a device. - * - * Removes the device from the list of known devices, deletes all GSettings - * and files. - * - * @param {string} id - The id of the device to delete - */ - _removeDevice(id) { - // Delete all GSettings - const settings_path = `/org/gnome/shell/extensions/gsconnect/${id}/`; - GLib.spawn_command_line_async(`dconf reset -f ${settings_path}`); - - // Delete the cache - const cache = GLib.build_filenamev([Config.CACHEDIR, id]); - Gio.File.rm_rf(cache); - - // Forget the device - this.devices.delete(id); - this.settings.set_strv('devices', Array.from(this.devices.keys())); - } - - /** - * A GSourceFunc that tries to reconnect to each paired device, while - * pruning unpaired devices that have disconnected. - * - * @return {boolean} Always %true - */ - _reconnect() { - for (const [id, device] of this.devices) { - if (device.connected) - continue; - - if (device.paired) { - this.identify(device.settings.get_string('last-connection')); - continue; - } - - this._unexportDevice(device); - this._removeDevice(id); - device.destroy(); - } - - return GLib.SOURCE_CONTINUE; - } - - /** - * Identify to an address or broadcast to the network. - * - * @param {string} [uri] - An address URI or %null to broadcast - */ - identify(uri = null) { - try { - // If we're passed a parameter, try and find a backend for it - if (uri !== null) { - const [scheme, address] = uri.split('://'); - - const backend = this.backends.get(scheme); - - if (backend !== undefined) - backend.broadcast(address); - - // If we're not discoverable, only try to reconnect known devices - } else if (!this.discoverable) { - this._reconnect(); - - // Otherwise have each backend broadcast to it's network - } else { - this.backends.forEach(backend => backend.broadcast()); - } - } catch (e) { - logError(e); - } - } - - /** - * Start managing devices. - */ - start() { - if (this.active) - return; - - this._loadDevices(); - this._loadBackends(); - - if (this._reconnectId === 0) { - this._reconnectId = GLib.timeout_add_seconds( - GLib.PRIORITY_LOW, - 5, - this._reconnect.bind(this) - ); - } - - this._active = true; - this.notify('active'); - } - - /** - * Stop managing devices. - */ - stop() { - if (!this.active) - return; - - if (this._reconnectId > 0) { - GLib.Source.remove(this._reconnectId); - this._reconnectId = 0; - } - - this._unexportDevices(); - - this.backends.forEach(backend => backend.destroy()); - this.backends.clear(); - - this.devices.forEach(device => device.destroy()); - this.devices.clear(); - - this._active = false; - this.notify('active'); - } - - /** - * Stop managing devices and free any resources. - */ - destroy() { - this.stop(); - this.set_connection(null); - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/nativeMessagingHost.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/nativeMessagingHost.js deleted file mode 100755 index 5635f33..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/nativeMessagingHost.js +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env gjs - -'use strict'; - -imports.gi.versions.Gio = '2.0'; -imports.gi.versions.GLib = '2.0'; -imports.gi.versions.GObject = '2.0'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const System = imports.system; - - -const NativeMessagingHost = GObject.registerClass({ - GTypeName: 'GSConnectNativeMessagingHost', -}, class NativeMessagingHost extends Gio.Application { - - _init() { - super._init({ - application_id: 'org.gnome.Shell.Extensions.GSConnect.NativeMessagingHost', - flags: Gio.ApplicationFlags.NON_UNIQUE, - }); - } - - get devices() { - if (this._devices === undefined) - this._devices = {}; - - return this._devices; - } - - vfunc_activate() { - super.vfunc_activate(); - } - - vfunc_startup() { - super.vfunc_startup(); - this.hold(); - - // IO Channels - this._stdin = new Gio.DataInputStream({ - base_stream: new Gio.UnixInputStream({fd: 0}), - byte_order: Gio.DataStreamByteOrder.HOST_ENDIAN, - }); - - this._stdout = new Gio.DataOutputStream({ - base_stream: new Gio.UnixOutputStream({fd: 1}), - byte_order: Gio.DataStreamByteOrder.HOST_ENDIAN, - }); - - const source = this._stdin.base_stream.create_source(null); - source.set_callback(this.receive.bind(this)); - source.attach(null); - - // Device Manager - try { - this._manager = Gio.DBusObjectManagerClient.new_for_bus_sync( - Gio.BusType.SESSION, - Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START, - 'org.gnome.Shell.Extensions.GSConnect', - '/org/gnome/Shell/Extensions/GSConnect', - null, - null - ); - } catch (e) { - logError(e); - this.quit(); - } - - // Add currently managed devices - for (const object of this._manager.get_objects()) { - for (const iface of object.get_interfaces()) - this._onInterfaceAdded(this._manager, object, iface); - } - - // Watch for new and removed devices - this._manager.connect( - 'interface-added', - this._onInterfaceAdded.bind(this) - ); - this._manager.connect( - 'object-removed', - this._onObjectRemoved.bind(this) - ); - - // Watch for device property changes - this._manager.connect( - 'interface-proxy-properties-changed', - this.sendDeviceList.bind(this) - ); - - // Watch for service restarts - this._manager.connect( - 'notify::name-owner', - this.sendDeviceList.bind(this) - ); - - this.send({ - type: 'connected', - data: (this._manager.name_owner !== null), - }); - } - - receive() { - try { - // Read the message - const length = this._stdin.read_int32(null); - const bytes = this._stdin.read_bytes(length, null).toArray(); - const message = JSON.parse(imports.byteArray.toString(bytes)); - - // A request for a list of devices - if (message.type === 'devices') { - this.sendDeviceList(); - - // A request to invoke an action - } else if (message.type === 'share') { - let actionName; - const device = this.devices[message.data.device]; - - if (device) { - if (message.data.action === 'share') - actionName = 'shareUri'; - else if (message.data.action === 'telephony') - actionName = 'shareSms'; - - device.actions.activate_action( - actionName, - new GLib.Variant('s', message.data.url) - ); - } - } - - return GLib.SOURCE_CONTINUE; - } catch (e) { - this.quit(); - } - } - - send(message) { - try { - const data = JSON.stringify(message); - this._stdout.put_int32(data.length, null); - this._stdout.put_string(data, null); - } catch (e) { - this.quit(); - } - } - - sendDeviceList() { - // Inform the WebExtension we're disconnected from the service - if (this._manager && this._manager.name_owner === null) - return this.send({type: 'connected', data: false}); - - // Collect all the devices with supported actions - const available = []; - - for (const device of Object.values(this.devices)) { - const share = device.actions.get_action_enabled('shareUri'); - const telephony = device.actions.get_action_enabled('shareSms'); - - if (share || telephony) { - available.push({ - id: device.g_object_path, - name: device.name, - type: device.type, - share: share, - telephony: telephony, - }); - } - } - - this.send({type: 'devices', data: available}); - } - - _proxyGetter(name) { - try { - return this.get_cached_property(name).unpack(); - } catch (e) { - return null; - } - } - - _onInterfaceAdded(manager, object, iface) { - Object.defineProperties(iface, { - 'name': { - get: this._proxyGetter.bind(iface, 'Name'), - enumerable: true, - }, - // TODO: phase this out for icon-name - 'type': { - get: this._proxyGetter.bind(iface, 'Type'), - enumerable: true, - }, - }); - - iface.actions = Gio.DBusActionGroup.get( - iface.g_connection, - iface.g_name, - iface.g_object_path - ); - - this.devices[iface.g_object_path] = iface; - this.sendDeviceList(); - } - - _onObjectRemoved(manager, object) { - delete this.devices[object.g_object_path]; - this.sendDeviceList(); - } -}); - -// NOTE: must not pass ARGV -(new NativeMessagingHost()).run([System.programInvocationName]); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugin.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugin.js deleted file mode 100644 index 164abfa..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugin.js +++ /dev/null @@ -1,258 +0,0 @@ -'use strict'; - -const ByteArray = imports.byteArray; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Config = imports.config; - - -/** - * Base class for device plugins. - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectPlugin', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device that owns this plugin', - GObject.ParamFlags.READABLE, - GObject.Object - ), - 'name': GObject.ParamSpec.string( - 'name', - 'Name', - 'The device name', - GObject.ParamFlags.READABLE, - null - ), - }, -}, class Plugin extends GObject.Object { - - _init(device, name, meta = null) { - super._init(); - - this._device = device; - this._name = name; - this._meta = meta; - - if (this._meta === null) - this._meta = imports.service.plugins[name].Metadata; - - // GSettings - const schema = Config.GSCHEMA.lookup(this._meta.id, false); - - if (schema !== null) { - this.settings = new Gio.Settings({ - settings_schema: schema, - path: `${device.settings.path}plugin/${name}/`, - }); - } - - // GActions - this._gactions = []; - - if (this._meta.actions) { - const menu = this.device.settings.get_strv('menu-actions'); - - for (const name in this._meta.actions) { - const info = this._meta.actions[name]; - this._registerAction(name, menu.indexOf(name), info); - } - } - } - - get cancellable() { - if (this._cancellable === undefined) - this._cancellable = new Gio.Cancellable(); - - return this._cancellable; - } - - get device() { - return this._device; - } - - get name() { - return this._name; - } - - _activateAction(action, parameter) { - try { - let args = null; - - if (parameter instanceof GLib.Variant) - args = parameter.full_unpack(); - - if (Array.isArray(args)) - this[action.name](...args); - else - this[action.name](args); - } catch (e) { - logError(e, action.name); - } - } - - _registerAction(name, menuIndex, info) { - try { - // Device Action - const action = new Gio.SimpleAction({ - name: name, - parameter_type: info.parameter_type, - enabled: false, - }); - action.connect('activate', this._activateAction.bind(this)); - - this.device.add_action(action); - - // Menu - if (menuIndex > -1) { - this.device.addMenuAction( - action, - menuIndex, - info.label, - info.icon_name - ); - } - - this._gactions.push(action); - } catch (e) { - logError(e, `${this.device.name}: ${this.name}`); - } - } - - /** - * Called when the device connects. - */ - connected() { - // Enabled based on device capabilities, which might change - const incoming = this.device.settings.get_strv('incoming-capabilities'); - const outgoing = this.device.settings.get_strv('outgoing-capabilities'); - - for (const action of this._gactions) { - const info = this._meta.actions[action.name]; - - if (info.incoming.every(type => outgoing.includes(type)) && - info.outgoing.every(type => incoming.includes(type))) - action.set_enabled(true); - } - } - - /** - * Called when the device disconnects. - */ - disconnected() { - for (const action of this._gactions) - action.set_enabled(false); - } - - /** - * Called when a packet is received that the plugin is a handler for. - * - * @param {Core.Packet} packet - A KDE Connect packet - */ - handlePacket(packet) { - throw new GObject.NotImplementedError(); - } - - /** - * Cache JSON parseable properties on this object for persistence. The - * filename ~/.cache/gsconnect/<device-id>/<plugin-name>.json will be used - * to store the properties and values. - * - * Calling cacheProperties() opens a JSON cache file and reads any stored - * properties and values onto the current instance. When destroy() - * is called the properties are automatically stored in the same file. - * - * @param {Array} names - A list of this object's property names to cache - */ - async cacheProperties(names) { - try { - this._cacheProperties = names; - - // Ensure the device's cache directory exists - const cachedir = GLib.build_filenamev([ - Config.CACHEDIR, - this.device.id, - ]); - GLib.mkdir_with_parents(cachedir, 448); - - this._cacheFile = Gio.File.new_for_path( - GLib.build_filenamev([cachedir, `${this.name}.json`]) - ); - - // Read the cache from disk - await new Promise((resolve, reject) => { - this._cacheFile.load_contents_async(null, (file, res) => { - try { - const contents = file.load_contents_finish(res)[1]; - const cache = JSON.parse(ByteArray.toString(contents)); - Object.assign(this, cache); - - resolve(); - } catch (e) { - reject(e); - } - }); - }); - } catch (e) { - debug(e.message, `${this.device.name}: ${this.name}`); - } finally { - this.cacheLoaded(); - } - } - - /** - * An overridable function that is invoked when the on-disk cache is being - * cleared. Implementations should use this function to clear any in-memory - * cache data. - */ - clearCache() {} - - /** - * An overridable function that is invoked when the cache is done loading - */ - cacheLoaded() {} - - /** - * Unregister plugin actions, write the cache (if applicable) and destroy - * any dangling signal handlers. - */ - destroy() { - // Cancel any pending plugin operations - if (this._cancellable !== undefined) - this._cancellable.cancel(); - - for (const action of this._gactions) { - this.device.removeMenuAction(`device.${action.name}`); - this.device.remove_action(action.name); - } - - // Write the cache to disk synchronously - if (this._cacheFile !== undefined) { - try { - // Build the cache - const cache = {}; - - for (const name of this._cacheProperties) - cache[name] = this[name]; - - this._cacheFile.replace_contents( - JSON.stringify(cache, null, 2), - null, - false, - Gio.FileCreateFlags.REPLACE_DESTINATION, - null - ); - } catch (e) { - debug(e.message, `${this.device.name}: ${this.name}`); - } - } - - GObject.signal_handlers_destroy(this); - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/battery.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/battery.js deleted file mode 100644 index 6035220..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/battery.js +++ /dev/null @@ -1,429 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Components = imports.service.components; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Battery'), - description: _('Exchange battery information'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Battery', - incomingCapabilities: [ - 'kdeconnect.battery', - 'kdeconnect.battery.request', - ], - outgoingCapabilities: [ - 'kdeconnect.battery', - 'kdeconnect.battery.request', - ], - actions: {}, -}; - - -/** - * Battery Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/battery - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectBatteryPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'battery'); - - // Setup Cache; defaults are 90 minute charge, 1 day discharge - this._chargeState = [54, 0, -1]; - this._dischargeState = [864, 0, -1]; - this._thresholdLevel = 25; - - this.cacheProperties([ - '_chargeState', - '_dischargeState', - '_thresholdLevel', - ]); - - // Export battery state as GAction - this.__state = new Gio.SimpleAction({ - name: 'battery', - parameter_type: new GLib.VariantType('(bsii)'), - state: this.state, - }); - this.device.add_action(this.__state); - - // Local Battery (UPower) - this._upower = null; - this._sendStatisticsId = this.settings.connect( - 'changed::send-statistics', - this._onSendStatisticsChanged.bind(this) - ); - this._onSendStatisticsChanged(this.settings); - } - - get charging() { - if (this._charging === undefined) - this._charging = false; - - return this._charging; - } - - get icon_name() { - let icon; - - if (this.level === -1) - return 'battery-missing-symbolic'; - else if (this.level === 100) - return 'battery-full-charged-symbolic'; - else if (this.level < 3) - icon = 'battery-empty'; - else if (this.level < 10) - icon = 'battery-caution'; - else if (this.level < 30) - icon = 'battery-low'; - else if (this.level < 60) - icon = 'battery-good'; - else if (this.level >= 60) - icon = 'battery-full'; - - if (this.charging) - return `${icon}-charging-symbolic`; - - return `${icon}-symbolic`; - } - - get level() { - // This is what KDE Connect returns if the remote battery plugin is - // disabled or still being loaded - if (this._level === undefined) - this._level = -1; - - return this._level; - } - - get time() { - if (this._time === undefined) - this._time = 0; - - return this._time; - } - - get state() { - return new GLib.Variant( - '(bsii)', - [this.charging, this.icon_name, this.level, this.time] - ); - } - - cacheLoaded() { - this._initEstimate(); - this._sendState(); - } - - clearCache() { - this._chargeState = [54, 0, -1]; - this._dischargeState = [864, 0, -1]; - this._thresholdLevel = 25; - this._initEstimate(); - } - - connected() { - super.connected(); - - this._requestState(); - this._sendState(); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.battery': - this._receiveState(packet); - break; - - case 'kdeconnect.battery.request': - this._sendState(); - break; - } - } - - _onSendStatisticsChanged() { - if (this.settings.get_boolean('send-statistics')) - this._monitorState(); - else - this._unmonitorState(); - } - - /** - * Recalculate and update the estimated time remaining, but not the rate. - */ - _initEstimate() { - let rate, level; - - // elision of [rate, time, level] - if (this.charging) - [rate,, level] = this._chargeState; - else - [rate,, level] = this._dischargeState; - - if (!Number.isFinite(rate) || rate < 1) - rate = this.charging ? 864 : 90; - - if (!Number.isFinite(level) || level < 0) - level = this.level; - - // Update the time remaining - if (rate && this.charging) - this._time = Math.floor(rate * (100 - level)); - else if (rate && !this.charging) - this._time = Math.floor(rate * level); - - this.__state.state = this.state; - } - - /** - * Recalculate the (dis)charge rate and update the estimated time remaining. - */ - _updateEstimate() { - let rate, time, level; - const newTime = Math.floor(Date.now() / 1000); - const newLevel = this.level; - - // Load the state; ensure we have sane values for calculation - if (this.charging) - [rate, time, level] = this._chargeState; - else - [rate, time, level] = this._dischargeState; - - if (!Number.isFinite(rate) || rate < 1) - rate = this.charging ? 54 : 864; - - if (!Number.isFinite(time) || time <= 0) - time = newTime; - - if (!Number.isFinite(level) || level < 0) - level = newLevel; - - // Update the rate; use a weighted average to account for missed changes - // NOTE: (rate = seconds/percent) - const ldiff = this.charging ? newLevel - level : level - newLevel; - const tdiff = newTime - time; - const newRate = tdiff / ldiff; - - if (newRate && Number.isFinite(newRate)) - rate = Math.floor((rate * 0.4) + (newRate * 0.6)); - - // Store the state for the next recalculation - if (this.charging) - this._chargeState = [rate, newTime, newLevel]; - else - this._dischargeState = [rate, newTime, newLevel]; - - // Update the time remaining - if (rate && this.charging) - this._time = Math.floor(rate * (100 - newLevel)); - else if (rate && !this.charging) - this._time = Math.floor(rate * newLevel); - - this.__state.state = this.state; - } - - /** - * Notify the user the remote battery is full. - */ - _fullBatteryNotification() { - if (!this.settings.get_boolean('full-battery-notification')) - return; - - // Offer the option to ring the device, if available - let buttons = []; - - if (this.device.get_action_enabled('ring')) { - buttons = [{ - label: _('Ring'), - action: 'ring', - parameter: null, - }]; - } - - this.device.showNotification({ - id: 'battery|full', - // TRANSLATORS: eg. Google Pixel: Battery is full - title: _('%s: Battery is full').format(this.device.name), - // TRANSLATORS: when the battery is fully charged - body: _('Fully Charged'), - icon: Gio.ThemedIcon.new('battery-full-charged-symbolic'), - buttons: buttons, - }); - } - - /** - * Notify the user the remote battery is at custom charge level. - */ - _customBatteryNotification() { - if (!this.settings.get_boolean('custom-battery-notification')) - return; - - // Offer the option to ring the device, if available - let buttons = []; - - if (this.device.get_action_enabled('ring')) { - buttons = [{ - label: _('Ring'), - action: 'ring', - parameter: null, - }]; - } - - this.device.showNotification({ - id: 'battery|custom', - // TRANSLATORS: eg. Google Pixel: Battery has reached custom charge level - title: _('%s: Battery has reached custom charge level').format(this.device.name), - // TRANSLATORS: when the battery has reached custom charge level - body: _('%d%% Charged').format(this.level), - icon: Gio.ThemedIcon.new('battery-full-charged-symbolic'), - buttons: buttons, - }); - } - - /** - * Notify the user the remote battery is low. - */ - _lowBatteryNotification() { - if (!this.settings.get_boolean('low-battery-notification')) - return; - - // Offer the option to ring the device, if available - let buttons = []; - - if (this.device.get_action_enabled('ring')) { - buttons = [{ - label: _('Ring'), - action: 'ring', - parameter: null, - }]; - } - - this.device.showNotification({ - id: 'battery|low', - // TRANSLATORS: eg. Google Pixel: Battery is low - title: _('%s: Battery is low').format(this.device.name), - // TRANSLATORS: eg. 15% remaining - body: _('%d%% remaining').format(this.level), - icon: Gio.ThemedIcon.new('battery-caution-symbolic'), - buttons: buttons, - }); - } - - /** - * Handle a remote battery update. - * - * @param {Core.Packet} packet - A kdeconnect.battery packet - */ - _receiveState(packet) { - // Charging state changed - this._charging = packet.body.isCharging; - - // Level changed - if (this._level !== packet.body.currentCharge) { - this._level = packet.body.currentCharge; - - // If the level is above the threshold hide the notification - if (this._level > this._thresholdLevel) - this.device.hideNotification('battery|low'); - - // The level just changed to/from custom level while charging - if ((this._level === this.settings.get_uint('custom-battery-notification-value')) && this._charging) - this._customBatteryNotification(); - else - this.device.hideNotification('battery|custom'); - - // The level just changed to/from full - if (this._level === 100) - this._fullBatteryNotification(); - else - this.device.hideNotification('battery|full'); - } - - // Device considers the level low - if (packet.body.thresholdEvent > 0) { - this._lowBatteryNotification(); - this._thresholdLevel = this.level; - } - - this._updateEstimate(); - } - - /** - * Request the remote battery's current state - */ - _requestState() { - this.device.sendPacket({ - type: 'kdeconnect.battery.request', - body: {request: true}, - }); - } - - /** - * Report the local battery's current state - */ - _sendState() { - if (this._upower === null || !this._upower.is_present) - return; - - this.device.sendPacket({ - type: 'kdeconnect.battery', - body: { - currentCharge: this._upower.level, - isCharging: this._upower.charging, - thresholdEvent: this._upower.threshold, - }, - }); - } - - /* - * UPower monitoring methods - */ - _monitorState() { - try { - // Currently only true if the remote device is a desktop (rare) - const incoming = this.device.settings.get_strv('incoming-capabilities'); - - if (!incoming.includes('kdeconnect.battery')) - return; - - this._upower = Components.acquire('upower'); - - this._upowerId = this._upower.connect( - 'changed', - this._sendState.bind(this) - ); - - this._sendState(); - } catch (e) { - logError(e, this.device.name); - this._unmonitorState(); - } - } - - _unmonitorState() { - try { - if (this._upower === null) - return; - - this._upower.disconnect(this._upowerId); - this._upower = Components.release('upower'); - } catch (e) { - logError(e, this.device.name); - } - } - - destroy() { - this.device.remove_action('battery'); - this.settings.disconnect(this._sendStatisticsId); - this._unmonitorState(); - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/clipboard.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/clipboard.js deleted file mode 100644 index 49fa725..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/clipboard.js +++ /dev/null @@ -1,178 +0,0 @@ -'use strict'; - -const GObject = imports.gi.GObject; - -const Components = imports.service.components; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Clipboard'), - description: _('Share the clipboard content'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Clipboard', - incomingCapabilities: [ - 'kdeconnect.clipboard', - 'kdeconnect.clipboard.connect', - ], - outgoingCapabilities: [ - 'kdeconnect.clipboard', - 'kdeconnect.clipboard.connect', - ], - actions: { - clipboardPush: { - label: _('Clipboard Push'), - icon_name: 'edit-paste-symbolic', - - parameter_type: null, - incoming: [], - outgoing: ['kdeconnect.clipboard'], - }, - clipboardPull: { - label: _('Clipboard Pull'), - icon_name: 'edit-copy-symbolic', - - parameter_type: null, - incoming: ['kdeconnect.clipboard'], - outgoing: [], - }, - }, -}; - - -/** - * Clipboard Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/clipboard - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectClipboardPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'clipboard'); - - this._clipboard = Components.acquire('clipboard'); - - // Watch local clipboard for changes - this._textChangedId = this._clipboard.connect( - 'notify::text', - this._onLocalClipboardChanged.bind(this) - ); - - // Buffer content to allow selective sync - this._localBuffer = this._clipboard.text; - this._localTimestamp = 0; - this._remoteBuffer = null; - } - - connected() { - super.connected(); - - // TODO: if we're not auto-syncing local->remote, but we are doing the - // reverse, it's possible older remote content will end up - // overwriting newer local content. - if (!this.settings.get_boolean('send-content')) - return; - - if (this._localBuffer === null && this._localTimestamp === 0) - return; - - this.device.sendPacket({ - type: 'kdeconnect.clipboard.connect', - body: { - content: this._localBuffer, - timestamp: this._localTimestamp, - }, - }); - } - - handlePacket(packet) { - if (!packet.body.hasOwnProperty('content')) - return; - - switch (packet.type) { - case 'kdeconnect.clipboard': - this._handleContent(packet); - break; - - case 'kdeconnect.clipboard.connect': - this._handleConnectContent(packet); - break; - } - } - - _handleContent(packet) { - this._onRemoteClipboardChanged(packet.body.content); - } - - _handleConnectContent(packet) { - if (packet.body.hasOwnProperty('timestamp') && - packet.body.timestamp > this._localTimestamp) - this._onRemoteClipboardChanged(packet.body.content); - } - - /* - * Store the local clipboard content and forward it if enabled - */ - _onLocalClipboardChanged(clipboard, pspec) { - this._localBuffer = clipboard.text; - this._localTimestamp = Date.now(); - - if (this.settings.get_boolean('send-content')) - this.clipboardPush(); - } - - /* - * Store the remote clipboard content and apply it if enabled - */ - _onRemoteClipboardChanged(text) { - this._remoteBuffer = text; - - if (this.settings.get_boolean('receive-content')) - this.clipboardPull(); - } - - /** - * Copy to the remote clipboard; called by _onLocalClipboardChanged() - */ - clipboardPush() { - // Don't sync if the clipboard is empty or not text - if (this._localTimestamp === 0) - return; - - if (this._remoteBuffer !== this._localBuffer) { - this._remoteBuffer = this._localBuffer; - - // If the buffer is %null, the clipboard contains non-text content, - // so we neither clear the remote clipboard nor pass the content - if (this._localBuffer !== null) { - this.device.sendPacket({ - type: 'kdeconnect.clipboard', - body: { - content: this._localBuffer, - }, - }); - } - } - } - - /** - * Copy from the remote clipboard; called by _onRemoteClipboardChanged() - */ - clipboardPull() { - if (this._localBuffer !== this._remoteBuffer) { - this._localBuffer = this._remoteBuffer; - this._localTimestamp = Date.now(); - - this._clipboard.text = this._remoteBuffer; - } - } - - destroy() { - if (this._clipboard && this._textChangedId) { - this._clipboard.disconnect(this._textChangedId); - this._clipboard = Components.release('clipboard'); - } - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/connectivity_report.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/connectivity_report.js deleted file mode 100644 index d4b8eff..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/connectivity_report.js +++ /dev/null @@ -1,162 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Components = imports.service.components; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Connectivity Report'), - description: _('Display connectivity status'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.ConnectivityReport', - incomingCapabilities: [ - 'kdeconnect.connectivity_report', - ], - outgoingCapabilities: [ - 'kdeconnect.connectivity_report.request', - ], - actions: {}, -}; - - -/** - * Connectivity Report Plugin - * https://invent.kde.org/network/kdeconnect-kde/-/tree/master/plugins/connectivity_report - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectConnectivityReportPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'connectivity_report'); - - // Export connectivity state as GAction - this.__state = new Gio.SimpleAction({ - name: 'connectivityReport', - // ( - // cellular_network_type, - // cellular_network_type_icon, - // cellular_network_strength(0..4), - // cellular_network_strength_icon, - // ) - parameter_type: new GLib.VariantType('(ssis)'), - state: this.state, - }); - this.device.add_action(this.__state); - } - - get signal_strength() { - if (this._signalStrength === undefined) - this._signalStrength = -1; - - return this._signalStrength; - } - - get network_type() { - if (this._networkType === undefined) - this._networkType = ''; - - return this._networkType; - } - - get signal_strength_icon_name() { - if (this.signal_strength === 0) - return 'network-cellular-signal-none-symbolic'; // SIGNAL_STRENGTH_NONE_OR_UNKNOWN - else if (this.signal_strength === 1) - return 'network-cellular-signal-weak-symbolic'; // SIGNAL_STRENGTH_POOR - else if (this.signal_strength === 2) - return 'network-cellular-signal-ok-symbolic'; // SIGNAL_STRENGTH_MODERATE - else if (this.signal_strength === 3) - return 'network-cellular-signal-good-symbolic'; // SIGNAL_STRENGTH_GOOD - else if (this.signal_strength >= 4) - return 'network-cellular-signal-excellent-symbolic'; // SIGNAL_STRENGTH_GREAT - - return 'network-cellular-offline-symbolic'; // OFF (signal_strength == -1) - } - - get network_type_icon_name() { - if (this.network_type === 'GSM' || this.network_type === 'CDMA' || this.network_type === 'iDEN') - return 'network-cellular-2g-symbolic'; - else if (this.network_type === 'UMTS' || this.network_type === 'CDMA2000') - return 'network-cellular-3g-symbolic'; - else if (this.network_type === 'LTE') - return 'network-cellular-4g-symbolic'; - else if (this.network_type === 'EDGE') - return 'network-cellular-edge-symbolic'; - else if (this.network_type === 'GPRS') - return 'network-cellular-gprs-symbolic'; - else if (this.network_type === 'HSPA') - return 'network-cellular-hspa-symbolic'; - // FIXME: No icon for this! - // https://gitlab.gnome.org/GNOME/adwaita-icon-theme/-/issues/114 - else if (this.network_type === '5G') - return 'network-cellular-symbolic'; - - return 'network-cellular-symbolic'; - } - - get state() { - return new GLib.Variant( - '(ssis)', - [ - this.network_type, - this.network_type_icon_name, - this.signal_strength, - this.signal_strength_icon_name, - ] - ); - } - - connected() { - super.connected(); - - this._requestState(); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.connectivity_report': - this._receiveState(packet); - break; - } - } - - /** - * Handle a remote state update. - * - * @param {Core.Packet} packet - A kdeconnect.connectivity_report packet - */ - _receiveState(packet) { - if (packet.body.signalStrengths) { - // TODO: Only first SIM (subscriptionID) is supported at the moment - const subs = Object.keys(packet.body.signalStrengths); - const firstSub = Math.min.apply(null, subs); - const data = packet.body.signalStrengths[firstSub]; - - this._networkType = data.networkType; - this._signalStrength = data.signalStrength; - } - - // Update DBus state - this.__state.state = this.state; - } - - /** - * Request the remote device's connectivity state - */ - _requestState() { - this.device.sendPacket({ - type: 'kdeconnect.connectivity_report.request', - body: {}, - }); - } - - destroy() { - this.device.remove_action('connectivity_report'); - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/contacts.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/contacts.js deleted file mode 100644 index 8559272..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/contacts.js +++ /dev/null @@ -1,456 +0,0 @@ -'use strict'; - -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const PluginBase = imports.service.plugin; -const Contacts = imports.service.components.contacts; - -/* - * We prefer libebook's vCard parser if it's available - */ -var EBookContacts; - -try { - EBookContacts = imports.gi.EBookContacts; -} catch (e) { - EBookContacts = null; -} - - -var Metadata = { - label: _('Contacts'), - description: _('Access contacts of the paired device'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Contacts', - incomingCapabilities: [ - 'kdeconnect.contacts.response_uids_timestamps', - 'kdeconnect.contacts.response_vcards', - ], - outgoingCapabilities: [ - 'kdeconnect.contacts.request_all_uids_timestamps', - 'kdeconnect.contacts.request_vcards_by_uid', - ], - actions: {}, -}; - - -/* - * vCard 2.1 Patterns - */ -const VCARD_FOLDING = /\r\n |\r |\n |=\n/g; -const VCARD_SUPPORTED = /^fn|tel|photo|x-kdeconnect/i; -const VCARD_BASIC = /^([^:;]+):(.+)$/; -const VCARD_TYPED = /^([^:;]+);([^:]+):(.+)$/; -const VCARD_TYPED_KEY = /item\d{1,2}\./; -const VCARD_TYPED_META = /([a-z]+)=(.*)/i; - - -/** - * Contacts Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/contacts - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectContactsPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'contacts'); - - this._store = new Contacts.Store(device.id); - this._store.fetch = this._requestUids.bind(this); - - // Notify when the store is ready - this._contactsStoreReadyId = this._store.connect( - 'notify::context', - () => this.device.notify('contacts') - ); - - // Notify if the contacts source changes - this._contactsSourceChangedId = this.settings.connect( - 'changed::contacts-source', - () => this.device.notify('contacts') - ); - - // Load the cache - this._store.load(); - } - - clearCache() { - this._store.clear(); - } - - connected() { - super.connected(); - this._requestUids(); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.contacts.response_uids_timestamps': - this._handleUids(packet); - break; - - case 'kdeconnect.contacts.response_vcards': - this._handleVCards(packet); - break; - } - } - - _handleUids(packet) { - try { - const contacts = this._store.contacts; - const remote_uids = packet.body.uids; - let removed = false; - delete packet.body.uids; - - // Usually a failed request, so avoid wiping the cache - if (remote_uids.length === 0) - return; - - // Delete any contacts that were removed on the device - for (let i = 0, len = contacts.length; i < len; i++) { - const contact = contacts[i]; - - if (!remote_uids.includes(contact.id)) { - this._store.remove(contact.id, false); - removed = true; - } - } - - // Build a list of new or updated contacts - const uids = []; - - for (const [uid, timestamp] of Object.entries(packet.body)) { - const contact = this._store.get_contact(uid); - - if (!contact || contact.timestamp !== timestamp) - uids.push(uid); - } - - // Send a request for any new or updated contacts - if (uids.length) - this._requestVCards(uids); - - // If we removed any contacts, save the cache - if (removed) - this._store.save(); - } catch (e) { - logError(e); - } - } - - /** - * Decode a string encoded as "QUOTED-PRINTABLE" and return a regular string - * - * See: https://github.com/mathiasbynens/quoted-printable/blob/master/src/quoted-printable.js - * - * @param {string} input - The QUOTED-PRINTABLE string - * @return {string} The decoded string - */ - _decodeQuotedPrintable(input) { - return input - // https://tools.ietf.org/html/rfc2045#section-6.7, rule 3 - .replace(/[\t\x20]$/gm, '') - // Remove hard line breaks preceded by `=` - .replace(/=(?:\r\n?|\n|$)/g, '') - // https://tools.ietf.org/html/rfc2045#section-6.7, note 1. - .replace(/=([a-fA-F0-9]{2})/g, ($0, $1) => { - const codePoint = parseInt($1, 16); - return String.fromCharCode(codePoint); - }); - } - - /** - * Decode a string encoded as "UTF-8" and return a regular string - * - * See: https://github.com/kvz/locutus/blob/master/src/php/xml/utf8_decode.js - * - * @param {string} input - The UTF-8 string - * @return {string} The decoded string - */ - _decodeUTF8(input) { - try { - const output = []; - let i = 0; - let c1 = 0; - let seqlen = 0; - - while (i < input.length) { - c1 = input.charCodeAt(i) & 0xFF; - seqlen = 0; - - if (c1 <= 0xBF) { - c1 &= 0x7F; - seqlen = 1; - } else if (c1 <= 0xDF) { - c1 &= 0x1F; - seqlen = 2; - } else if (c1 <= 0xEF) { - c1 &= 0x0F; - seqlen = 3; - } else { - c1 &= 0x07; - seqlen = 4; - } - - for (let ai = 1; ai < seqlen; ++ai) - c1 = ((c1 << 0x06) | (input.charCodeAt(ai + i) & 0x3F)); - - if (seqlen === 4) { - c1 -= 0x10000; - output.push(String.fromCharCode(0xD800 | ((c1 >> 10) & 0x3FF))); - output.push(String.fromCharCode(0xDC00 | (c1 & 0x3FF))); - } else { - output.push(String.fromCharCode(c1)); - } - - i += seqlen; - } - - return output.join(''); - - // Fallback to old unfaithful - } catch (e) { - try { - return decodeURIComponent(escape(input)); - - // Say "chowdah" frenchie! - } catch (e) { - debug(e, `Failed to decode UTF-8 VCard field ${input}`); - return input; - } - } - } - - /** - * Parse a vCard (v2.1 only) and return a dictionary of the fields - * - * See: http://jsfiddle.net/ARTsinn/P2t2P/ - * - * @param {string} vcard_data - The raw VCard data - * @return {Object} dictionary of vCard data - */ - _parseVCard21(vcard_data) { - // vcard skeleton - const vcard = { - fn: _('Unknown Contact'), - tel: [], - }; - - // Remove line folding and split - const unfolded = vcard_data.replace(VCARD_FOLDING, ''); - const lines = unfolded.split(/\r\n|\r|\n/); - - for (let i = 0, len = lines.length; i < len; i++) { - const line = lines[i]; - let results, key, type, value; - - // Empty line or a property we aren't interested in - if (!line || !line.match(VCARD_SUPPORTED)) - continue; - - // Basic Fields (fn, x-kdeconnect-timestamp, etc) - if ((results = line.match(VCARD_BASIC))) { - [, key, value] = results; - vcard[key.toLowerCase()] = value; - continue; - } - - // Typed Fields (tel, adr, etc) - if ((results = line.match(VCARD_TYPED))) { - [, key, type, value] = results; - key = key.replace(VCARD_TYPED_KEY, '').toLowerCase(); - value = value.split(';'); - type = type.split(';'); - - // Type(s) - const meta = {}; - - for (let i = 0, len = type.length; i < len; i++) { - const res = type[i].match(VCARD_TYPED_META); - - if (res) - meta[res[1]] = res[2]; - else - meta[`type${i === 0 ? '' : i}`] = type[i].toLowerCase(); - } - - // Value(s) - if (vcard[key] === undefined) - vcard[key] = []; - - // Decode QUOTABLE-PRINTABLE - if (meta.ENCODING && meta.ENCODING === 'QUOTED-PRINTABLE') { - delete meta.ENCODING; - value = value.map(v => this._decodeQuotedPrintable(v)); - } - - // Decode UTF-8 - if (meta.CHARSET && meta.CHARSET === 'UTF-8') { - delete meta.CHARSET; - value = value.map(v => this._decodeUTF8(v)); - } - - // Special case for FN (full name) - if (key === 'fn') - vcard[key] = value[0]; - else - vcard[key].push({meta: meta, value: value}); - } - } - - return vcard; - } - - /** - * Parse a vCard (v2.1 only) using native JavaScript and add it to the - * contact store. - * - * @param {string} uid - The contact UID - * @param {string} vcard_data - The raw vCard data - */ - async _parseVCardNative(uid, vcard_data) { - try { - const vcard = this._parseVCard21(vcard_data); - - const contact = { - id: uid, - name: vcard.fn, - numbers: [], - origin: 'device', - timestamp: parseInt(vcard['x-kdeconnect-timestamp']), - }; - - // Phone Numbers - contact.numbers = vcard.tel.map(entry => { - let type = 'unknown'; - - if (entry.meta && entry.meta.type) - type = entry.meta.type; - - return {type: type, value: entry.value[0]}; - }); - - // Avatar - if (vcard.photo) { - const data = GLib.base64_decode(vcard.photo[0].value[0]); - contact.avatar = await this._store.storeAvatar(data); - } - - this._store.add(contact); - } catch (e) { - debug(e, `Failed to parse VCard contact ${uid}`); - } - } - - /** - * Parse a vCard using libebook and add it to the contact store. - * - * @param {string} uid - The contact UID - * @param {string} vcard_data - The raw vCard data - */ - async _parseVCard(uid, vcard_data) { - try { - const contact = { - id: uid, - name: _('Unknown Contact'), - numbers: [], - origin: 'device', - timestamp: 0, - }; - - const evcard = EBookContacts.VCard.new_from_string(vcard_data); - const attrs = evcard.get_attributes(); - - for (let i = 0, len = attrs.length; i < len; i++) { - const attr = attrs[i]; - let data, number; - - switch (attr.get_name().toLowerCase()) { - case 'fn': - contact.name = attr.get_value(); - break; - - case 'tel': - number = {value: attr.get_value(), type: 'unknown'}; - - if (attr.has_type('CELL')) - number.type = 'cell'; - else if (attr.has_type('HOME')) - number.type = 'home'; - else if (attr.has_type('WORK')) - number.type = 'work'; - - contact.numbers.push(number); - break; - - case 'x-kdeconnect-timestamp': - contact.timestamp = parseInt(attr.get_value()); - break; - - case 'photo': - data = GLib.base64_decode(attr.get_value()); - contact.avatar = await this._store.storeAvatar(data); - break; - } - } - - this._store.add(contact); - } catch (e) { - debug(e, `Failed to parse VCard contact ${uid}`); - } - } - - /** - * Handle an incoming list of contact vCards and pass them to the best - * available parser. - * - * @param {Core.Packet} packet - A `kdeconnect.contacts.response_vcards` - */ - _handleVCards(packet) { - try { - // We don't use this - delete packet.body.uids; - - // Parse each vCard and add the contact - for (const [uid, vcard] of Object.entries(packet.body)) { - if (EBookContacts) - this._parseVCard(uid, vcard); - else - this._parseVCardNative(uid, vcard); - } - } catch (e) { - logError(e, this.device.name); - } - } - - /** - * Request a list of contact UIDs with timestamps. - */ - _requestUids() { - this.device.sendPacket({ - type: 'kdeconnect.contacts.request_all_uids_timestamps', - }); - } - - /** - * Request the vCards for @uids. - * - * @param {string[]} uids - A list of contact UIDs - */ - _requestVCards(uids) { - this.device.sendPacket({ - type: 'kdeconnect.contacts.request_vcards_by_uid', - body: { - uids: uids, - }, - }); - } - - destroy() { - this._store.disconnect(this._contactsStoreReadyId); - this.settings.disconnect(this._contactsSourceChangedId); - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/findmyphone.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/findmyphone.js deleted file mode 100644 index 8362b2a..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/findmyphone.js +++ /dev/null @@ -1,245 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const Gio = imports.gi.Gio; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const Components = imports.service.components; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Find My Phone'), - description: _('Ring your paired device'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.FindMyPhone', - incomingCapabilities: ['kdeconnect.findmyphone.request'], - outgoingCapabilities: ['kdeconnect.findmyphone.request'], - actions: { - ring: { - label: _('Ring'), - icon_name: 'phonelink-ring-symbolic', - - parameter_type: null, - incoming: [], - outgoing: ['kdeconnect.findmyphone.request'], - }, - }, -}; - - -/** - * FindMyPhone Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/findmyphone - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectFindMyPhonePlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'findmyphone'); - - this._dialog = null; - this._player = Components.acquire('sound'); - this._mixer = Components.acquire('pulseaudio'); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.findmyphone.request': - this._handleRequest(); - break; - } - } - - /** - * Handle an incoming location request. - */ - _handleRequest() { - try { - // If this is a second request, stop announcing and return - if (this._dialog !== null) { - this._dialog.response(Gtk.ResponseType.DELETE_EVENT); - return; - } - - this._dialog = new Dialog({ - device: this.device, - plugin: this, - }); - - this._dialog.connect('response', () => { - this._dialog = null; - }); - } catch (e) { - this._cancelRequest(); - logError(e, this.device.name); - } - } - - /** - * Cancel any ongoing ringing and destroy the dialog. - */ - _cancelRequest() { - if (this._dialog !== null) - this._dialog.response(Gtk.ResponseType.DELETE_EVENT); - } - - /** - * Request that the remote device announce it's location - */ - ring() { - this.device.sendPacket({ - type: 'kdeconnect.findmyphone.request', - body: {}, - }); - } - - destroy() { - this._cancelRequest(); - - if (this._mixer !== undefined) - this._mixer = Components.release('pulseaudio'); - - if (this._player !== undefined) - this._player = Components.release('sound'); - - super.destroy(); - } -}); - - -/* - * Used to ensure 'audible-bell' is enabled for fallback - */ -const _WM_SETTINGS = new Gio.Settings({ - schema_id: 'org.gnome.desktop.wm.preferences', - path: '/org/gnome/desktop/wm/preferences/', -}); - - -/** - * A custom GtkMessageDialog for alerting of incoming requests - */ -const Dialog = GObject.registerClass({ - GTypeName: 'GSConnectFindMyPhoneDialog', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device associated with this window', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'plugin': GObject.ParamSpec.object( - 'plugin', - 'Plugin', - 'The plugin providing messages', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - }, -}, class Dialog extends Gtk.MessageDialog { - _init(params) { - super._init({ - buttons: Gtk.ButtonsType.CLOSE, - device: params.device, - image: new Gtk.Image({ - icon_name: 'phonelink-ring-symbolic', - pixel_size: 512, - halign: Gtk.Align.CENTER, - hexpand: true, - valign: Gtk.Align.CENTER, - vexpand: true, - visible: true, - }), - plugin: params.plugin, - urgency_hint: true, - }); - - this.set_keep_above(true); - this.maximize(); - this.message_area.destroy(); - - // If an output stream is available start fading the volume up - if (this.plugin._mixer && this.plugin._mixer.output) { - this._stream = this.plugin._mixer.output; - - this._previousMuted = this._stream.muted; - this._previousVolume = this._stream.volume; - - this._stream.muted = false; - this._stream.fade(0.85, 15); - - // Otherwise ensure audible-bell is enabled - } else { - this._previousBell = _WM_SETTINGS.get_boolean('audible-bell'); - _WM_SETTINGS.set_boolean('audible-bell', true); - } - - // Start the alarm - if (this.plugin._player !== undefined) - this.plugin._player.loopSound('phone-incoming-call', this.cancellable); - - // Show the dialog - this.show_all(); - } - - vfunc_key_press_event(event) { - this.response(Gtk.ResponseType.DELETE_EVENT); - - return Gdk.EVENT_STOP; - } - - vfunc_motion_notify_event(event) { - this.response(Gtk.ResponseType.DELETE_EVENT); - - return Gdk.EVENT_STOP; - } - - vfunc_response(response_id) { - // Stop the alarm - this.cancellable.cancel(); - - // Restore the mixer level - if (this._stream) { - this._stream.muted = this._previousMuted; - this._stream.fade(this._previousVolume); - - // Restore the audible-bell - } else { - _WM_SETTINGS.set_boolean('audible-bell', this._previousBell); - } - - this.destroy(); - } - - get cancellable() { - if (this._cancellable === undefined) - this._cancellable = new Gio.Cancellable(); - - return this._cancellable; - } - - get device() { - if (this._device === undefined) - this._device = null; - - return this._device; - } - - set device(device) { - this._device = device; - } - - get plugin() { - if (this._plugin === undefined) - this._plugin = null; - - return this._plugin; - } - - set plugin(plugin) { - this._plugin = plugin; - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/mousepad.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/mousepad.js deleted file mode 100644 index 5d8c89f..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/mousepad.js +++ /dev/null @@ -1,319 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const GObject = imports.gi.GObject; - -const Components = imports.service.components; -const {InputDialog} = imports.service.ui.mousepad; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Mousepad'), - description: _('Enables the paired device to act as a remote mouse and keyboard'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Mousepad', - incomingCapabilities: [ - 'kdeconnect.mousepad.echo', - 'kdeconnect.mousepad.request', - 'kdeconnect.mousepad.keyboardstate', - ], - outgoingCapabilities: [ - 'kdeconnect.mousepad.echo', - 'kdeconnect.mousepad.request', - 'kdeconnect.mousepad.keyboardstate', - ], - actions: { - keyboard: { - label: _('Keyboard'), - icon_name: 'input-keyboard-symbolic', - - parameter_type: null, - incoming: [ - 'kdeconnect.mousepad.echo', - 'kdeconnect.mousepad.keyboardstate', - ], - outgoing: ['kdeconnect.mousepad.request'], - }, - }, -}; - - -/** - * A map of "KDE Connect" keyvals to Gdk - */ -const KeyMap = new Map([ - [1, Gdk.KEY_BackSpace], - [2, Gdk.KEY_Tab], - [3, Gdk.KEY_Linefeed], - [4, Gdk.KEY_Left], - [5, Gdk.KEY_Up], - [6, Gdk.KEY_Right], - [7, Gdk.KEY_Down], - [8, Gdk.KEY_Page_Up], - [9, Gdk.KEY_Page_Down], - [10, Gdk.KEY_Home], - [11, Gdk.KEY_End], - [12, Gdk.KEY_Return], - [13, Gdk.KEY_Delete], - [14, Gdk.KEY_Escape], - [15, Gdk.KEY_Sys_Req], - [16, Gdk.KEY_Scroll_Lock], - [17, 0], - [18, 0], - [19, 0], - [20, 0], - [21, Gdk.KEY_F1], - [22, Gdk.KEY_F2], - [23, Gdk.KEY_F3], - [24, Gdk.KEY_F4], - [25, Gdk.KEY_F5], - [26, Gdk.KEY_F6], - [27, Gdk.KEY_F7], - [28, Gdk.KEY_F8], - [29, Gdk.KEY_F9], - [30, Gdk.KEY_F10], - [31, Gdk.KEY_F11], - [32, Gdk.KEY_F12], -]); - - -/** - * Mousepad Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/mousepad - * - * TODO: support outgoing mouse events? - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectMousepadPlugin', - Properties: { - 'state': GObject.ParamSpec.boolean( - 'state', - 'State', - 'Remote keyboard state', - GObject.ParamFlags.READABLE, - false - ), - }, -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'mousepad'); - - this._input = Components.acquire('input'); - - this._shareControlChangedId = this.settings.connect( - 'changed::share-control', - this._sendState.bind(this) - ); - } - - get state() { - if (this._state === undefined) - this._state = false; - - return this._state; - } - - connected() { - super.connected(); - - this._sendState(); - } - - disconnected() { - super.disconnected(); - - this._state = false; - this.notify('state'); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.mousepad.request': - this._handleInput(packet.body); - break; - - case 'kdeconnect.mousepad.echo': - this._handleEcho(packet.body); - break; - - case 'kdeconnect.mousepad.keyboardstate': - this._handleState(packet); - break; - } - } - - /** - * Handle a input event. - * - * @param {Object} input - The body of a `kdeconnect.mousepad.request` - */ - _handleInput(input) { - if (!this.settings.get_boolean('share-control')) - return; - - let keysym; - let modifiers = 0; - - // These are ordered, as much as possible, to create the shortest code - // path for high-frequency, low-latency events (eg. mouse movement) - switch (true) { - case input.hasOwnProperty('scroll'): - this._input.scrollPointer(input.dx, input.dy); - break; - - case (input.hasOwnProperty('dx') && input.hasOwnProperty('dy')): - this._input.movePointer(input.dx, input.dy); - break; - - case (input.hasOwnProperty('key') || input.hasOwnProperty('specialKey')): - // NOTE: \u0000 sometimes sent in advance of a specialKey packet - if (input.key && input.key === '\u0000') - return; - - // Modifiers - if (input.alt) - modifiers |= Gdk.ModifierType.MOD1_MASK; - - if (input.ctrl) - modifiers |= Gdk.ModifierType.CONTROL_MASK; - - if (input.shift) - modifiers |= Gdk.ModifierType.SHIFT_MASK; - - if (input.super) - modifiers |= Gdk.ModifierType.SUPER_MASK; - - // Regular key (printable ASCII or Unicode) - if (input.key) { - this._input.pressKey(input.key, modifiers); - this._sendEcho(input); - - // Special key (eg. non-printable ASCII) - } else if (input.specialKey && KeyMap.has(input.specialKey)) { - keysym = KeyMap.get(input.specialKey); - this._input.pressKey(keysym, modifiers); - this._sendEcho(input); - } - break; - - case input.hasOwnProperty('singleclick'): - this._input.clickPointer(Gdk.BUTTON_PRIMARY); - break; - - case input.hasOwnProperty('doubleclick'): - this._input.doubleclickPointer(Gdk.BUTTON_PRIMARY); - break; - - case input.hasOwnProperty('middleclick'): - this._input.clickPointer(Gdk.BUTTON_MIDDLE); - break; - - case input.hasOwnProperty('rightclick'): - this._input.clickPointer(Gdk.BUTTON_SECONDARY); - break; - - case input.hasOwnProperty('singlehold'): - this._input.pressPointer(Gdk.BUTTON_PRIMARY); - break; - - case input.hasOwnProperty('singlerelease'): - this._input.releasePointer(Gdk.BUTTON_PRIMARY); - break; - - default: - logError(new Error('Unknown input')); - } - } - - /** - * Handle an echo/ACK of a event we sent, displaying it the dialog entry. - * - * @param {Object} input - The body of a `kdeconnect.mousepad.echo` - */ - _handleEcho(input) { - if (!this._dialog || !this._dialog.visible) - return; - - // Skip modifiers - if (input.alt || input.ctrl || input.super) - return; - - if (input.key) { - this._dialog._isAck = true; - this._dialog.text.buffer.text += input.key; - this._dialog._isAck = false; - } else if (KeyMap.get(input.specialKey) === Gdk.KEY_BackSpace) { - this._dialog.text.emit('backspace'); - } - } - - /** - * Handle a state change from the remote keyboard. This is an indication - * that the remote keyboard is ready to accept input. - * - * @param {Object} packet - A `kdeconnect.mousepad.keyboardstate` packet - */ - _handleState(packet) { - this._state = !!packet.body.state; - this.notify('state'); - } - - /** - * Send an echo/ACK of @input, if requested - * - * @param {Object} input - The body of a 'kdeconnect.mousepad.request' - */ - _sendEcho(input) { - if (!input.sendAck) - return; - - delete input.sendAck; - input.isAck = true; - - this.device.sendPacket({ - type: 'kdeconnect.mousepad.echo', - body: input, - }); - } - - /** - * Send the local keyboard state - * - * @param {boolean} state - Whether we're ready to accept input - */ - _sendState() { - this.device.sendPacket({ - type: 'kdeconnect.mousepad.keyboardstate', - body: { - state: this.settings.get_boolean('share-control'), - }, - }); - } - - /** - * Open the Keyboard Input dialog - */ - keyboard() { - if (this._dialog === undefined) { - this._dialog = new InputDialog({ - device: this.device, - plugin: this, - }); - } - - this._dialog.present(); - } - - destroy() { - if (this._input !== undefined) - this._input = Components.release('input'); - - if (this._dialog !== undefined) - this._dialog.destroy(); - - this.settings.disconnect(this._shareControlChangedId); - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/mpris.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/mpris.js deleted file mode 100644 index 56b23b2..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/mpris.js +++ /dev/null @@ -1,902 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Components = imports.service.components; -const Config = imports.config; -const DBus = imports.service.utils.dbus; -const MPRIS = imports.service.components.mpris; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('MPRIS'), - description: _('Bidirectional remote media playback control'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.MPRIS', - incomingCapabilities: ['kdeconnect.mpris', 'kdeconnect.mpris.request'], - outgoingCapabilities: ['kdeconnect.mpris', 'kdeconnect.mpris.request'], - actions: {}, -}; - - -/** - * MPRIS Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/mpriscontrol - * - * See also: - * https://specifications.freedesktop.org/mpris-spec/latest/ - * https://github.com/GNOME/gnome-shell/blob/master/js/ui/mpris.js - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectMPRISPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'mpris'); - - this._players = new Map(); - this._transferring = new WeakSet(); - this._updating = new WeakSet(); - - this._mpris = Components.acquire('mpris'); - - this._playerAddedId = this._mpris.connect( - 'player-added', - this._sendPlayerList.bind(this) - ); - - this._playerRemovedId = this._mpris.connect( - 'player-removed', - this._sendPlayerList.bind(this) - ); - - this._playerChangedId = this._mpris.connect( - 'player-changed', - this._onPlayerChanged.bind(this) - ); - - this._playerSeekedId = this._mpris.connect( - 'player-seeked', - this._onPlayerSeeked.bind(this) - ); - } - - connected() { - super.connected(); - - this._requestPlayerList(); - this._sendPlayerList(); - } - - disconnected() { - super.disconnected(); - - for (const [identity, player] of this._players) { - this._players.delete(identity); - player.destroy(); - } - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.mpris': - this._handleUpdate(packet); - break; - - case 'kdeconnect.mpris.request': - this._handleRequest(packet); - break; - } - } - - /** - * Handle a remote player update. - * - * @param {Core.Packet} packet - A `kdeconnect.mpris` - */ - _handleUpdate(packet) { - try { - if (packet.body.hasOwnProperty('playerList')) - this._handlePlayerList(packet.body.playerList); - else if (packet.body.hasOwnProperty('player')) - this._handlePlayerUpdate(packet); - } catch (e) { - debug(e, this.device.name); - } - } - - /** - * Handle an updated list of remote players. - * - * @param {string[]} playerList - A list of remote player names - */ - _handlePlayerList(playerList) { - // Destroy removed players before adding new ones - for (const player of this._players.values()) { - if (!playerList.includes(player.Identity)) { - this._players.delete(player.Identity); - player.destroy(); - } - } - - for (const identity of playerList) { - if (!this._players.has(identity)) { - const player = new PlayerRemote(this.device, identity); - this._players.set(identity, player); - } - - // Always request player updates; packets are cheap - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: identity, - requestNowPlaying: true, - requestVolume: true, - }, - }); - } - } - - /** - * Handle an update for a remote player. - * - * @param {Object} packet - A `kdeconnect.mpris` packet - */ - _handlePlayerUpdate(packet) { - const player = this._players.get(packet.body.player); - - if (player === undefined) - return; - - if (packet.body.hasOwnProperty('transferringAlbumArt')) - player.handleAlbumArt(packet); - else - player.update(packet.body); - } - - /** - * Request a list of remote players. - */ - _requestPlayerList() { - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - requestPlayerList: true, - }, - }); - } - - /** - * Handle a request for player information or action. - * - * @param {Core.Packet} packet - a `kdeconnect.mpris.request` - * @return {undefined} no return value - */ - _handleRequest(packet) { - // A request for the list of players - if (packet.body.hasOwnProperty('requestPlayerList')) - return this._sendPlayerList(); - - // A request for an unknown player; send the list of players - if (!this._mpris.hasPlayer(packet.body.player)) - return this._sendPlayerList(); - - // An album art request - if (packet.body.hasOwnProperty('albumArtUrl')) - return this._sendAlbumArt(packet); - - // A player command - this._handleCommand(packet); - } - - /** - * Handle an incoming player command or information request - * - * @param {Core.Packet} packet - A `kdeconnect.mpris.request` - */ - async _handleCommand(packet) { - if (!this.settings.get_boolean('share-players')) - return; - - let player; - - try { - player = this._mpris.getPlayer(packet.body.player); - - if (player === undefined || this._updating.has(player)) - return; - - this._updating.add(player); - - // Player Actions - if (packet.body.hasOwnProperty('action')) { - switch (packet.body.action) { - case 'PlayPause': - case 'Play': - case 'Pause': - case 'Next': - case 'Previous': - case 'Stop': - player[packet.body.action](); - break; - - default: - debug(`unknown action: ${packet.body.action}`); - } - } - - // Player Properties - if (packet.body.hasOwnProperty('setLoopStatus')) - player.LoopStatus = packet.body.setLoopStatus; - - if (packet.body.hasOwnProperty('setShuffle')) - player.Shuffle = packet.body.setShuffle; - - if (packet.body.hasOwnProperty('setVolume')) - player.Volume = packet.body.setVolume / 100; - - if (packet.body.hasOwnProperty('Seek')) - await player.Seek(packet.body.Seek * 1000); - - if (packet.body.hasOwnProperty('SetPosition')) { - const offset = (packet.body.SetPosition * 1000) - player.Position; - await player.Seek(offset); - } - - // Information Request - let hasResponse = false; - - const response = { - type: 'kdeconnect.mpris', - body: { - player: packet.body.player, - }, - }; - - if (packet.body.hasOwnProperty('requestNowPlaying')) { - hasResponse = true; - - Object.assign(response.body, { - pos: Math.floor(player.Position / 1000), - isPlaying: (player.PlaybackStatus === 'Playing'), - canPause: player.CanPause, - canPlay: player.CanPlay, - canGoNext: player.CanGoNext, - canGoPrevious: player.CanGoPrevious, - canSeek: player.CanSeek, - loopStatus: player.LoopStatus, - shuffle: player.Shuffle, - - // default values for members that will be filled conditionally - albumArtUrl: '', - length: 0, - artist: '', - title: '', - album: '', - nowPlaying: '', - volume: 0, - }); - - const metadata = player.Metadata; - - if (metadata.hasOwnProperty('mpris:artUrl')) { - const file = Gio.File.new_for_uri(metadata['mpris:artUrl']); - response.body.albumArtUrl = file.get_uri(); - } - - if (metadata.hasOwnProperty('mpris:length')) { - const trackLen = Math.floor(metadata['mpris:length'] / 1000); - response.body.length = trackLen; - } - - if (metadata.hasOwnProperty('xesam:artist')) { - const artists = metadata['xesam:artist']; - response.body.artist = artists.join(', '); - } - - if (metadata.hasOwnProperty('xesam:title')) - response.body.title = metadata['xesam:title']; - - if (metadata.hasOwnProperty('xesam:album')) - response.body.album = metadata['xesam:album']; - - // Now Playing - if (response.body.artist && response.body.title) { - response.body.nowPlaying = [ - response.body.artist, - response.body.title, - ].join(' - '); - } else if (response.body.artist) { - response.body.nowPlaying = response.body.artist; - } else if (response.body.title) { - response.body.nowPlaying = response.body.title; - } else { - response.body.nowPlaying = _('Unknown'); - } - } - - if (packet.body.hasOwnProperty('requestVolume')) { - hasResponse = true; - response.body.volume = Math.floor(player.Volume * 100); - } - - if (hasResponse) - this.device.sendPacket(response); - } catch (e) { - debug(e, this.device.name); - } finally { - this._updating.delete(player); - } - } - - _onPlayerChanged(mpris, player) { - if (!this.settings.get_boolean('share-players')) - return; - - this._handleCommand({ - body: { - player: player.Identity, - requestNowPlaying: true, - requestVolume: true, - }, - }); - } - - _onPlayerSeeked(mpris, player, offset) { - // TODO: although we can handle full seeked signals, kdeconnect-android - // does not, and expects a position update instead - this.device.sendPacket({ - type: 'kdeconnect.mpris', - body: { - player: player.Identity, - pos: Math.floor(player.Position / 1000), - // Seek: Math.floor(offset / 1000), - }, - }); - } - - async _sendAlbumArt(packet) { - let player; - - try { - // Reject concurrent requests for album art - player = this._mpris.getPlayer(packet.body.player); - - if (player === undefined || this._transferring.has(player)) - return; - - // Ensure the requested albumArtUrl matches the current mpris:artUrl - const metadata = player.Metadata; - - if (!metadata.hasOwnProperty('mpris:artUrl')) - return; - - const file = Gio.File.new_for_uri(metadata['mpris:artUrl']); - const request = Gio.File.new_for_uri(packet.body.albumArtUrl); - - if (file.get_uri() !== request.get_uri()) - throw RangeError(`invalid URI "${packet.body.albumArtUrl}"`); - - // Transfer the album art - this._transferring.add(player); - - const transfer = this.device.createTransfer(); - - transfer.addFile({ - type: 'kdeconnect.mpris', - body: { - transferringAlbumArt: true, - player: packet.body.player, - albumArtUrl: packet.body.albumArtUrl, - }, - }, file); - - await transfer.start(); - } catch (e) { - debug(e, this.device.name); - } finally { - this._transferring.delete(player); - } - } - - /** - * Send the list of player identities and indicate whether we support - * transferring album art - */ - _sendPlayerList() { - let playerList = []; - - if (this.settings.get_boolean('share-players')) - playerList = this._mpris.getIdentities(); - - this.device.sendPacket({ - type: 'kdeconnect.mpris', - body: { - playerList: playerList, - supportAlbumArtPayload: true, - }, - }); - } - - destroy() { - if (this._mpris !== undefined) { - this._mpris.disconnect(this._playerAddedId); - this._mpris.disconnect(this._playerRemovedId); - this._mpris.disconnect(this._playerChangedId); - this._mpris.disconnect(this._playerSeekedId); - this._mpris = Components.release('mpris'); - } - - for (const [identity, player] of this._players) { - this._players.delete(identity); - player.destroy(); - } - - super.destroy(); - } -}); - - -/* - * A class for mirroring a remote Media Player on DBus - */ -const MPRISIface = Config.DBUS.lookup_interface('org.mpris.MediaPlayer2'); -const MPRISPlayerIface = Config.DBUS.lookup_interface('org.mpris.MediaPlayer2.Player'); - - -const PlayerRemote = GObject.registerClass({ - GTypeName: 'GSConnectMPRISPlayerRemote', -}, class PlayerRemote extends MPRIS.Player { - - _init(device, identity) { - super._init(); - - this._device = device; - this._Identity = identity; - this._isPlaying = false; - - this._artist = null; - this._title = null; - this._album = null; - this._length = 0; - this._artUrl = null; - - this._ownerId = 0; - this._connection = null; - this._applicationIface = null; - this._playerIface = null; - } - - _getFile(albumArtUrl) { - const hash = GLib.compute_checksum_for_string(GLib.ChecksumType.MD5, - albumArtUrl, -1); - const path = GLib.build_filenamev([Config.CACHEDIR, hash]); - - return Gio.File.new_for_uri(`file://${path}`); - } - - _requestAlbumArt(state) { - if (this._artUrl === state.albumArtUrl) - return; - - const file = this._getFile(state.albumArtUrl); - - if (file.query_exists(null)) { - this._artUrl = file.get_uri(); - this._Metadata = undefined; - this.notify('Metadata'); - } else { - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - albumArtUrl: state.albumArtUrl, - }, - }); - } - } - - _updateMetadata(state) { - let metadataChanged = false; - - if (state.hasOwnProperty('artist')) { - if (this._artist !== state.artist) { - this._artist = state.artist; - metadataChanged = true; - } - } else if (this._artist) { - this._artist = null; - metadataChanged = true; - } - - if (state.hasOwnProperty('title')) { - if (this._title !== state.title) { - this._title = state.title; - metadataChanged = true; - } - } else if (this._title) { - this._title = null; - metadataChanged = true; - } - - if (state.hasOwnProperty('album')) { - if (this._album !== state.album) { - this._album = state.album; - metadataChanged = true; - } - } else if (this._album) { - this._album = null; - metadataChanged = true; - } - - if (state.hasOwnProperty('length')) { - if (this._length !== state.length * 1000) { - this._length = state.length * 1000; - metadataChanged = true; - } - } else if (this._length) { - this._length = 0; - metadataChanged = true; - } - - if (state.hasOwnProperty('albumArtUrl')) { - this._requestAlbumArt(state); - } else if (this._artUrl) { - this._artUrl = null; - metadataChanged = true; - } - - if (metadataChanged) { - this._Metadata = undefined; - this.notify('Metadata'); - } - } - - async export() { - try { - if (this._connection === null) { - this._connection = await DBus.newConnection(); - - if (this._applicationIface === null) { - this._applicationIface = new DBus.Interface({ - g_instance: this, - g_connection: this._connection, - g_object_path: '/org/mpris/MediaPlayer2', - g_interface_info: MPRISIface, - }); - } - - if (this._playerIface === null) { - this._playerIface = new DBus.Interface({ - g_instance: this, - g_connection: this._connection, - g_object_path: '/org/mpris/MediaPlayer2', - g_interface_info: MPRISPlayerIface, - }); - } - } - - if (this._ownerId !== 0) - return; - - const name = [ - this.device.name, - this.Identity, - ].join('').replace(/[\W]*/g, ''); - - this._ownerId = Gio.bus_own_name_on_connection( - this._connection, - `org.mpris.MediaPlayer2.GSConnect.${name}`, - Gio.BusNameOwnerFlags.NONE, - null, - null - ); - } catch (e) { - debug(e, this.Identity); - } - } - - unexport() { - if (this._ownerId === 0) - return; - - Gio.bus_unown_name(this._ownerId); - this._ownerId = 0; - } - - /** - * Download album art for the current track of the remote player. - * - * @param {Core.Packet} packet - A `kdeconnect.mpris` packet - */ - async handleAlbumArt(packet) { - let file; - - try { - file = this._getFile(packet.body.albumArtUrl); - - // Transfer the album art - const transfer = this.device.createTransfer(); - transfer.addFile(packet, file); - - await transfer.start(); - - this._artUrl = file.get_uri(); - this._Metadata = undefined; - this.notify('Metadata'); - } catch (e) { - debug(e, this.device.name); - - if (file) - file.delete_async(GLib.PRIORITY_DEFAULT, null, null); - } - } - - /** - * Update the internal state of the media player. - * - * @param {Core.Packet} state - The body of a `kdeconnect.mpris` packet - */ - update(state) { - this.freeze_notify(); - - // Metadata - if (state.hasOwnProperty('nowPlaying')) - this._updateMetadata(state); - - // Playback Status - if (state.hasOwnProperty('isPlaying')) { - if (this._isPlaying !== state.isPlaying) { - this._isPlaying = state.isPlaying; - this.notify('PlaybackStatus'); - } - } - - if (state.hasOwnProperty('canPlay')) { - if (this.CanPlay !== state.canPlay) { - this._CanPlay = state.canPlay; - this.notify('CanPlay'); - } - } - - if (state.hasOwnProperty('canPause')) { - if (this.CanPause !== state.canPause) { - this._CanPause = state.canPause; - this.notify('CanPause'); - } - } - - if (state.hasOwnProperty('canGoNext')) { - if (this.CanGoNext !== state.canGoNext) { - this._CanGoNext = state.canGoNext; - this.notify('CanGoNext'); - } - } - - if (state.hasOwnProperty('canGoPrevious')) { - if (this.CanGoPrevious !== state.canGoPrevious) { - this._CanGoPrevious = state.canGoPrevious; - this.notify('CanGoPrevious'); - } - } - - if (state.hasOwnProperty('pos')) - this._Position = state.pos * 1000; - - if (state.hasOwnProperty('volume')) { - if (this.Volume !== state.volume / 100) { - this._Volume = state.volume / 100; - this.notify('Volume'); - } - } - - this.thaw_notify(); - - if (!this._isPlaying && !this.CanControl) - this.unexport(); - else - this.export(); - } - - /* - * Native properties - */ - get device() { - return this._device; - } - - /* - * The org.mpris.MediaPlayer2.Player Interface - */ - get CanControl() { - return (this.CanPlay || this.CanPause); - } - - get Metadata() { - if (this._Metadata === undefined) { - this._Metadata = {}; - - if (this._artist) { - this._Metadata['xesam:artist'] = new GLib.Variant('as', - [this._artist]); - } - - if (this._title) { - this._Metadata['xesam:title'] = new GLib.Variant('s', - this._title); - } - - if (this._album) { - this._Metadata['xesam:album'] = new GLib.Variant('s', - this._album); - } - - if (this._artUrl) { - this._Metadata['mpris:artUrl'] = new GLib.Variant('s', - this._artUrl); - } - - this._Metadata['mpris:length'] = new GLib.Variant('x', - this._length); - } - - return this._Metadata; - } - - get PlaybackStatus() { - if (this._isPlaying) - return 'Playing'; - - return 'Stopped'; - } - - get Volume() { - if (this._Volume === undefined) - this._Volume = 0.3; - - return this._Volume; - } - - set Volume(level) { - if (this._Volume === level) - return; - - this._Volume = level; - this.notify('Volume'); - - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - setVolume: Math.floor(this._Volume * 100), - }, - }); - } - - Next() { - if (!this.CanGoNext) - return; - - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - action: 'Next', - }, - }); - } - - Pause() { - if (!this.CanPause) - return; - - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - action: 'Pause', - }, - }); - } - - Play() { - if (!this.CanPlay) - return; - - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - action: 'Play', - }, - }); - } - - PlayPause() { - if (!this.CanPlay && !this.CanPause) - return; - - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - action: 'PlayPause', - }, - }); - } - - Previous() { - if (!this.CanGoPrevious) - return; - - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - action: 'Previous', - }, - }); - } - - Seek(offset) { - if (!this.CanSeek) - return; - - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - Seek: offset, - }, - }); - } - - SetPosition(trackId, position) { - debug(`${this._Identity}: SetPosition(${trackId}, ${position})`); - - if (!this.CanControl || !this.CanSeek) - return; - - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - SetPosition: position / 1000, - }, - }); - } - - Stop() { - if (!this.CanControl) - return; - - this.device.sendPacket({ - type: 'kdeconnect.mpris.request', - body: { - player: this.Identity, - action: 'Stop', - }, - }); - } - - destroy() { - this.unexport(); - - if (this._connection) { - this._connection.close(null, null); - this._connection = null; - - if (this._applicationIface) { - this._applicationIface.destroy(); - this._applicationIface = null; - } - - if (this._playerIface) { - this._playerIface.destroy(); - this._playerIface = null; - } - } - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/notification.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/notification.js deleted file mode 100644 index 3765388..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/notification.js +++ /dev/null @@ -1,713 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const Components = imports.service.components; -const Config = imports.config; -const PluginBase = imports.service.plugin; -const NotificationUI = imports.service.ui.notification; - - -var Metadata = { - label: _('Notifications'), - description: _('Share notifications with the paired device'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Notification', - incomingCapabilities: [ - 'kdeconnect.notification', - 'kdeconnect.notification.request', - ], - outgoingCapabilities: [ - 'kdeconnect.notification', - 'kdeconnect.notification.action', - 'kdeconnect.notification.reply', - 'kdeconnect.notification.request', - ], - actions: { - withdrawNotification: { - label: _('Cancel Notification'), - icon_name: 'preferences-system-notifications-symbolic', - - parameter_type: new GLib.VariantType('s'), - incoming: [], - outgoing: ['kdeconnect.notification'], - }, - closeNotification: { - label: _('Close Notification'), - icon_name: 'preferences-system-notifications-symbolic', - - parameter_type: new GLib.VariantType('s'), - incoming: [], - outgoing: ['kdeconnect.notification.request'], - }, - replyNotification: { - label: _('Reply Notification'), - icon_name: 'preferences-system-notifications-symbolic', - - parameter_type: new GLib.VariantType('(ssa{ss})'), - incoming: ['kdeconnect.notification'], - outgoing: ['kdeconnect.notification.reply'], - }, - sendNotification: { - label: _('Send Notification'), - icon_name: 'preferences-system-notifications-symbolic', - - parameter_type: new GLib.VariantType('a{sv}'), - incoming: [], - outgoing: ['kdeconnect.notification'], - }, - activateNotification: { - label: _('Activate Notification'), - icon_name: 'preferences-system-notifications-symbolic', - - parameter_type: new GLib.VariantType('(ss)'), - incoming: [], - outgoing: ['kdeconnect.notification.action'], - }, - }, -}; - - -// A regex for our custom notificaiton ids -const ID_REGEX = /^(fdo|gtk)\|([^|]+)\|(.*)$/; - -// A list of known SMS apps -const SMS_APPS = [ - // Popular apps that don't contain the string 'sms' - 'com.android.messaging', // AOSP - 'com.google.android.apps.messaging', // Google Messages - 'com.textra', // Textra - 'xyz.klinker.messenger', // Pulse - 'com.calea.echo', // Mood Messenger - 'com.moez.QKSMS', // QKSMS - 'rpkandrodev.yaata', // YAATA - 'com.tencent.mm', // WeChat - 'com.viber.voip', // Viber - 'com.kakao.talk', // KakaoTalk - 'com.concentriclivers.mms.com.android.mms', // AOSP Clone - 'fr.slvn.mms', // AOSP Clone - 'com.promessage.message', // - 'com.htc.sense.mms', // HTC Messages - - // Known not to work with sms plugin - 'org.thoughtcrime.securesms', // Signal Private Messenger - 'com.samsung.android.messaging', // Samsung Messages -]; - - -/** - * Try to determine if an notification is from an SMS app - * - * @param {Core.Packet} packet - A `kdeconnect.notification` - * @return {boolean} Whether the notification is from an SMS app - */ -function _isSmsNotification(packet) { - const id = packet.body.id; - - if (id.includes('sms')) - return true; - - for (let i = 0, len = SMS_APPS.length; i < len; i++) { - if (id.includes(SMS_APPS[i])) - return true; - } - - return false; -} - - -/** - * Remove a local libnotify or Gtk notification. - * - * @param {String|Number} id - Gtk (string) or libnotify id (uint32) - * @param {String|null} application - Application Id if Gtk or null - */ -function _removeNotification(id, application = null) { - let name, path, method, variant; - - if (application !== null) { - name = 'org.gtk.Notifications'; - method = 'RemoveNotification'; - path = '/org/gtk/Notifications'; - variant = new GLib.Variant('(ss)', [application, id]); - } else { - name = 'org.freedesktop.Notifications'; - path = '/org/freedesktop/Notifications'; - method = 'CloseNotification'; - variant = new GLib.Variant('(u)', [id]); - } - - Gio.DBus.session.call( - name, path, name, method, variant, null, - Gio.DBusCallFlags.NONE, -1, null, - (connection, res) => { - try { - connection.call_finish(res); - } catch (e) { - logError(e); - } - } - ); -} - - -/** - * Notification Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/notifications - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/sendnotifications - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectNotificationPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'notification'); - - this._listener = Components.acquire('notification'); - this._session = Components.acquire('session'); - - this._notificationAddedId = this._listener.connect( - 'notification-added', - this._onNotificationAdded.bind(this) - ); - - // Load application notification settings - this._applicationsChangedId = this.settings.connect( - 'changed::applications', - this._onApplicationsChanged.bind(this) - ); - this._onApplicationsChanged(this.settings, 'applications'); - this._applicationsChangedSkip = false; - } - - connected() { - super.connected(); - - this._requestNotifications(); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.notification': - this._handleNotification(packet); - break; - - // TODO - case 'kdeconnect.notification.action': - this._handleNotificationAction(packet); - break; - - // No Linux/BSD desktop notifications are repliable as yet - case 'kdeconnect.notification.reply': - debug(`Not implemented: ${packet.type}`); - break; - - case 'kdeconnect.notification.request': - this._handleNotificationRequest(packet); - break; - - default: - debug(`Unknown notification packet: ${packet.type}`); - } - } - - _onApplicationsChanged(settings, key) { - if (this._applicationsChangedSkip) - return; - - try { - const json = settings.get_string(key); - this._applications = JSON.parse(json); - } catch (e) { - debug(e, this.device.name); - - this._applicationsChangedSkip = true; - settings.set_string(key, '{}'); - this._applicationsChangedSkip = false; - } - } - - _onNotificationAdded(listener, notification) { - try { - const notif = notification.full_unpack(); - - // An unconfigured application - if (notif.appName && !this._applications[notif.appName]) { - this._applications[notif.appName] = { - iconName: 'system-run-symbolic', - enabled: true, - }; - - // Store the themed icons for the device preferences window - if (notif.icon === undefined) { - // Keep default - - } else if (typeof notif.icon === 'string') { - this._applications[notif.appName].iconName = notif.icon; - - } else if (notif.icon instanceof Gio.ThemedIcon) { - const iconName = notif.icon.get_names()[0]; - this._applications[notif.appName].iconName = iconName; - } - - this._applicationsChangedSkip = true; - this.settings.set_string( - 'applications', - JSON.stringify(this._applications) - ); - this._applicationsChangedSkip = false; - } - - // Sending notifications forbidden - if (!this.settings.get_boolean('send-notifications')) - return; - - // Sending when the session is active is forbidden - if (!this.settings.get_boolean('send-active') && this._session.active) - return; - - // Notifications disabled for this application - if (notif.appName && !this._applications[notif.appName].enabled) - return; - - this.sendNotification(notif); - } catch (e) { - debug(e, this.device.name); - } - } - - /** - * Handle an incoming notification or closed report. - * - * FIXME: upstream kdeconnect-android is tagging many notifications as - * `silent`, causing them to never be shown. Since we already handle - * duplicates in the Shell, we ignore that flag for now. - * - * @param {Core.Packet} packet - A `kdeconnect.notification` - */ - _handleNotification(packet) { - // A report that a remote notification has been dismissed - if (packet.body.hasOwnProperty('isCancel')) - this.device.hideNotification(packet.body.id); - - // A normal, remote notification - else - this._receiveNotification(packet); - } - - /** - * Handle an incoming request to activate a notification action. - * - * @param {Core.Packet} packet - A `kdeconnect.notification.action` - */ - _handleNotificationAction(packet) { - throw new GObject.NotImplementedError(); - } - - /** - * Handle an incoming request to close or list notifications. - * - * @param {Core.Packet} packet - A `kdeconnect.notification.request` - */ - _handleNotificationRequest(packet) { - // A request for our notifications. This isn't implemented and would be - // pretty hard to without communicating with GNOME Shell. - if (packet.body.hasOwnProperty('request')) - return; - - // A request to close a local notification - // - // TODO: kdeconnect-android doesn't send these, and will instead send a - // kdeconnect.notification packet with isCancel and an id of "0". - // - // For clients that do support it, we report notification ids in the - // form "type|application-id|notification-id" so we can close it with - // the appropriate service. - if (packet.body.hasOwnProperty('cancel')) { - const [, type, application, id] = ID_REGEX.exec(packet.body.cancel); - - if (type === 'fdo') - _removeNotification(parseInt(id)); - else if (type === 'gtk') - _removeNotification(id, application); - } - } - - /** - * Upload an icon from a GLib.Bytes object. - * - * @param {Core.Packet} packet - The packet for the notification - * @param {GLib.Bytes} bytes - The icon bytes - */ - _uploadBytesIcon(packet, bytes) { - const stream = Gio.MemoryInputStream.new_from_bytes(bytes); - this._uploadIconStream(packet, stream, bytes.get_size()); - } - - /** - * Upload an icon from a Gio.File object. - * - * @param {Core.Packet} packet - A `kdeconnect.notification` - * @param {Gio.File} file - A file object for the icon - */ - async _uploadFileIcon(packet, file) { - const read = new Promise((resolve, reject) => { - file.read_async(GLib.PRIORITY_DEFAULT, null, (file, res) => { - try { - resolve(file.read_finish(res)); - } catch (e) { - reject(e); - } - }); - }); - - const query = new Promise((resolve, reject) => { - file.query_info_async( - 'standard::size', - Gio.FileQueryInfoFlags.NONE, - GLib.PRIORITY_DEFAULT, - null, - (file, res) => { - try { - resolve(file.query_info_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - const [stream, info] = await Promise.all([read, query]); - - this._uploadIconStream(packet, stream, info.get_size()); - } - - /** - * A function for uploading GThemedIcons - * - * @param {Core.Packet} packet - The packet for the notification - * @param {Gio.ThemedIcon} icon - The GIcon to upload - */ - _uploadThemedIcon(packet, icon) { - const theme = Gtk.IconTheme.get_default(); - let file = null; - - for (const name of icon.names) { - // NOTE: kdeconnect-android doesn't support SVGs - const size = Math.max.apply(null, theme.get_icon_sizes(name)); - const info = theme.lookup_icon(name, size, Gtk.IconLookupFlags.NO_SVG); - - // Send the first icon we find from the options - if (info) { - file = Gio.File.new_for_path(info.get_filename()); - break; - } - } - - if (file) - this._uploadFileIcon(packet, file); - else - this.device.sendPacket(packet); - } - - /** - * All icon types end up being uploaded in this function. - * - * @param {Core.Packet} packet - The packet for the notification - * @param {Gio.InputStream} stream - A stream to read the icon bytes from - * @param {number} size - Size of the icon in bytes - */ - async _uploadIconStream(packet, stream, size) { - try { - const transfer = this.device.createTransfer(); - transfer.addStream(packet, stream, size); - - await transfer.start(); - } catch (e) { - debug(e); - - this.device.sendPacket(packet); - } - } - - /** - * Upload an icon from a GIcon or themed icon name. - * - * @param {Core.Packet} packet - A `kdeconnect.notification` - * @param {Gio.Icon|string|null} icon - An icon or %null - * @return {Promise} A promise for the operation - */ - _uploadIcon(packet, icon = null) { - // Normalize strings into GIcons - if (typeof icon === 'string') - icon = Gio.Icon.new_for_string(icon); - - if (icon instanceof Gio.ThemedIcon) - return this._uploadThemedIcon(packet, icon); - - if (icon instanceof Gio.FileIcon) - return this._uploadFileIcon(packet, icon.get_file()); - - if (icon instanceof Gio.BytesIcon) - return this._uploadBytesIcon(packet, icon.get_bytes()); - - return this.device.sendPacket(packet); - } - - /** - * Send a local notification to the remote device. - * - * @param {Object} notif - A dictionary of notification parameters - * @param {string} notif.appName - The notifying application - * @param {string} notif.id - The notification ID - * @param {string} notif.title - The notification title - * @param {string} notif.body - The notification body - * @param {string} notif.ticker - The notification title & body - * @param {boolean} notif.isClearable - If the notification can be closed - * @param {string|Gio.Icon} notif.icon - An icon name or GIcon - */ - async sendNotification(notif) { - try { - const icon = notif.icon || null; - delete notif.icon; - - await this._uploadIcon({ - type: 'kdeconnect.notification', - body: notif, - }, icon); - } catch (e) { - logError(e); - } - } - - async _downloadIcon(packet) { - try { - if (!packet.hasPayload()) - return null; - - // Save the file in the global cache - const path = GLib.build_filenamev([ - Config.CACHEDIR, - packet.body.payloadHash || `${Date.now()}`, - ]); - - // Check if we've already downloaded this icon - // NOTE: if we reject the transfer kdeconnect-android will resend - // the notification packet, which may cause problems wrt #789 - const file = Gio.File.new_for_path(path); - - if (file.query_exists(null)) - return new Gio.FileIcon({file: file}); - - // Open the target path and create a transfer - const transfer = this.device.createTransfer(); - - transfer.addFile(packet, file); - - try { - await transfer.start(); - - return new Gio.FileIcon({file: file}); - } catch (e) { - debug(e, this.device.name); - - file.delete_async(GLib.PRIORITY_DEFAULT, null, null); - return null; - } - } catch (e) { - debug(e, this.device.name); - return null; - } - } - - /** - * Receive an incoming notification. - * - * @param {Core.Packet} packet - A `kdeconnect.notification` - */ - async _receiveNotification(packet) { - try { - // Set defaults - let action = null; - let buttons = []; - let id = packet.body.id; - let title = packet.body.appName; - let body = `${packet.body.title}: ${packet.body.text}`; - let icon = await this._downloadIcon(packet); - - // Repliable Notification - if (packet.body.requestReplyId) { - id = `${packet.body.id}|${packet.body.requestReplyId}`; - action = { - name: 'replyNotification', - parameter: new GLib.Variant('(ssa{ss})', [ - packet.body.requestReplyId, - '', - { - appName: packet.body.appName, - title: packet.body.title, - text: packet.body.text, - }, - ]), - }; - } - - // Notification Actions - if (packet.body.actions) { - buttons = packet.body.actions.map(action => { - return { - label: action, - action: 'activateNotification', - parameter: new GLib.Variant('(ss)', [id, action]), - }; - }); - } - - // Special case for Missed Calls - if (packet.body.id.includes('MissedCall')) { - title = packet.body.title; - body = packet.body.text; - - if (icon === null) - icon = new Gio.ThemedIcon({name: 'call-missed-symbolic'}); - - // Special case for SMS notifications - } else if (_isSmsNotification(packet)) { - title = packet.body.title; - body = packet.body.text; - action = { - name: 'replySms', - parameter: new GLib.Variant('s', packet.body.title), - }; - - if (icon === null) - icon = new Gio.ThemedIcon({name: 'sms-symbolic'}); - - // Special case where 'appName' is the same as 'title' - } else if (packet.body.appName === packet.body.title) { - body = packet.body.text; - } - - // Use the device icon if we still don't have one - if (icon === null) - icon = new Gio.ThemedIcon({name: this.device.icon_name}); - - // Show the notification - this.device.showNotification({ - id: id, - title: title, - body: body, - icon: icon, - action: action, - buttons: buttons, - }); - } catch (e) { - logError(e); - } - } - - /** - * Request the remote notifications be sent - */ - _requestNotifications() { - this.device.sendPacket({ - type: 'kdeconnect.notification.request', - body: {request: true}, - }); - } - - /** - * Report that a local notification has been closed/dismissed. - * TODO: kdeconnect-android doesn't handle incoming isCancel packets. - * - * @param {string} id - The local notification id - */ - withdrawNotification(id) { - this.device.sendPacket({ - type: 'kdeconnect.notification', - body: { - isCancel: true, - id: id, - }, - }); - } - - /** - * Close a remote notification. - * TODO: ignore local notifications - * - * @param {string} id - The remote notification id - */ - closeNotification(id) { - this.device.sendPacket({ - type: 'kdeconnect.notification.request', - body: {cancel: id}, - }); - } - - /** - * Reply to a notification sent with a requestReplyId UUID - * - * @param {string} uuid - The requestReplyId for the repliable notification - * @param {string} message - The message to reply with - * @param {Object} notification - The original notification packet - */ - replyNotification(uuid, message, notification) { - // If this happens for some reason, things will explode - if (!uuid) - throw Error('Missing UUID'); - - // If the message has no content, open a dialog for the user to add one - if (!message) { - const dialog = new NotificationUI.ReplyDialog({ - device: this.device, - uuid: uuid, - notification: notification, - plugin: this, - }); - dialog.present(); - - // Otherwise just send the reply - } else { - this.device.sendPacket({ - type: 'kdeconnect.notification.reply', - body: { - requestReplyId: uuid, - message: message, - }, - }); - } - } - - /** - * Activate a remote notification action - * - * @param {string} id - The remote notification id - * @param {string} action - The notification action (label) - */ - activateNotification(id, action) { - this.device.sendPacket({ - type: 'kdeconnect.notification.action', - body: { - action: action, - key: id, - }, - }); - } - - destroy() { - this.settings.disconnect(this._applicationsChangedId); - - if (this._listener !== undefined) { - this._listener.disconnect(this._notificationAddedId); - this._listener = Components.release('notification'); - } - - if (this._session !== undefined) - this._session = Components.release('session'); - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/photo.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/photo.js deleted file mode 100644 index e417c70..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/photo.js +++ /dev/null @@ -1,241 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Config = imports.config; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Photo'), - description: _('Request the paired device to take a photo and transfer it to this PC'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Photo', - incomingCapabilities: [ - 'kdeconnect.photo', - 'kdeconnect.photo.request', - ], - outgoingCapabilities: [ - 'kdeconnect.photo', - 'kdeconnect.photo.request', - ], - actions: { - photo: { - label: _('Photo'), - icon_name: 'camera-photo-symbolic', - - parameter_type: null, - incoming: ['kdeconnect.photo'], - outgoing: ['kdeconnect.photo.request'], - }, - }, -}; - - -/** - * Photo Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/photo - * - * TODO: use Cheese? - * check for /dev/video* - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectPhotoPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'photo'); - - // A reusable launcher for silence procs - this._launcher = new Gio.SubprocessLauncher({ - flags: (Gio.SubprocessFlags.STDOUT_SILENCE | - Gio.SubprocessFlags.STDERR_SILENCE), - }); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.photo': - this._receivePhoto(packet); - break; - - case 'kdeconnect.photo.request': - this._sendPhoto(packet); - break; - } - } - - /** - * Ensure we have a directory set for storing files that exists. - * - * @return {string} An absolute directory path - */ - _ensureReceiveDirectory() { - if (this._receiveDir !== undefined) - return this._receiveDir; - - // Ensure a directory is set - this._receiveDir = this.settings.get_string('receive-directory'); - - if (this._receiveDir === '') { - this._receiveDir = GLib.get_user_special_dir( - GLib.UserDirectory.DIRECTORY_PICTURES - ); - - // Fallback to ~/Pictures - const homeDir = GLib.get_home_dir(); - - if (!this._receiveDir || this._receiveDir === homeDir) { - this._receiveDir = GLib.build_filenamev([homeDir, 'Pictures']); - this.settings.set_string('receive-directory', this._receiveDir); - } - } - - // Ensure the directory exists - if (!GLib.file_test(this._receiveDir, GLib.FileTest.IS_DIR)) - GLib.mkdir_with_parents(this._receiveDir, 448); - - return this._receiveDir; - } - - /** - * Get a GFile for @filename, while ensuring the directory exists and the - * file is unique. - * - * @param {string} filename - A filename (eg. `image.jpg`) - * @return {Gio.File} a file object - */ - _getFile(filename) { - const dirpath = this._ensureReceiveDirectory(); - const basepath = GLib.build_filenamev([dirpath, filename]); - let filepath = basepath; - let copyNum = 0; - - while (GLib.file_test(filepath, GLib.FileTest.EXISTS)) - filepath = `${basepath} (${++copyNum})`; - - return Gio.File.new_for_path(filepath); - } - - /** - * Receive a photo taken by the remote device. - * - * @param {Core.Packet} packet - a `kdeconnect.photo` - */ - async _receivePhoto(packet) { - let file, transfer; - - try { - // Remote device cancelled the photo operation - if (packet.body.hasOwnProperty('cancel')) - return; - - // Open the target path and create a transfer - file = this._getFile(packet.body.filename); - - transfer = this.device.createTransfer(); - transfer.addFile(packet, file); - - // Open the photo if successful, delete on failure - await transfer.start(); - - const uri = file.get_uri(); - Gio.AppInfo.launch_default_for_uri_async(uri, null, null, null); - } catch (e) { - debug(e, this.device.name); - - if (file) - file.delete_async(GLib.PRIORITY_DEFAULT, null, null); - } - } - - /** - * Take a photo using the Webcam and return the path. - * - * @param {Core.Packet} packet - A `kdeconnect.photo.request` - * @return {Promise<string>} A file path - */ - _takePhoto(packet) { - return new Promise((resolve, reject) => { - const time = GLib.DateTime.new_now_local().format('%T'); - const path = GLib.build_filenamev([GLib.get_tmp_dir(), `${time}.jpg`]); - const proc = this._launcher.spawnv([ - Config.FFMPEG_PATH, - '-f', 'video4linux2', - '-ss', '0:0:2', - '-i', '/dev/video0', - '-frames', '1', - path, - ]); - - proc.wait_check_async(null, (proc, res) => { - try { - proc.wait_check_finish(res); - resolve(path); - } catch (e) { - reject(e); - } - }); - }); - } - - /** - * Send a photo to the remote device. - * - * @param {Core.Packet} packet - A `kdeconnect.photo.request` - */ - async _sendPhoto(packet) { - if (this.settings.get_boolean('share-camera')) - return; - - let file, transfer; - - try { - // Take a photo - const path = await this._takePhoto(); - - if (path.startsWith('file://')) - file = Gio.File.new_for_uri(path); - else - file = Gio.File.new_for_path(path); - - // Create the transfer - transfer = this.device.createTransfer(); - - transfer.addFile({ - type: 'kdeconnect.photo', - body: { - filename: file.get_basename(), - }, - }, file); - - await transfer.start(); - } catch (e) { - debug(e, this.device.name); - - if (transfer) { - this.device.showNotification({ - id: transfer.uuid, - title: _('Transfer Failed'), - // TRANSLATORS: eg. Failed to send "photo.jpg" to Google Pixel - body: _('Failed to send “%s” to %s').format( - file.get_basename(), - this.device.name - ), - icon: new Gio.ThemedIcon({name: 'dialog-warning-symbolic'}), - }); - } - } - } - - /** - * Request the remote device begin a photo operation. - */ - photo() { - this.device.sendPacket({ - type: 'kdeconnect.photo.request', - body: {}, - }); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/ping.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/ping.js deleted file mode 100644 index f14cae7..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/ping.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Ping'), - description: _('Send and receive pings'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Ping', - incomingCapabilities: ['kdeconnect.ping'], - outgoingCapabilities: ['kdeconnect.ping'], - actions: { - ping: { - label: _('Ping'), - icon_name: 'dialog-information-symbolic', - - parameter_type: new GLib.VariantType('s'), - incoming: [], - outgoing: ['kdeconnect.ping'], - }, - }, -}; - - -/** - * Ping Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/ping - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectPingPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'ping'); - } - - handlePacket(packet) { - // Notification - const notif = { - title: this.device.name, - body: _('Ping'), - icon: new Gio.ThemedIcon({name: `${this.device.icon_name}`}), - }; - - if (packet.body.message) { - // TRANSLATORS: An optional message accompanying a ping, rarely if ever used - // eg. Ping: A message sent with ping - notif.body = _('Ping: %s').format(packet.body.message); - } - - this.device.showNotification(notif); - } - - ping(message = '') { - const packet = { - type: 'kdeconnect.ping', - body: {}, - }; - - if (message.length) - packet.body.message = message; - - this.device.sendPacket(packet); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/presenter.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/presenter.js deleted file mode 100644 index fca5eaf..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/presenter.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -const GObject = imports.gi.GObject; - -const Components = imports.service.components; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Presentation'), - description: _('Use the paired device as a presenter'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Presenter', - incomingCapabilities: ['kdeconnect.presenter'], - outgoingCapabilities: [], - actions: {}, -}; - - -/** - * Presenter Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/presenter - * https://github.com/KDE/kdeconnect-android/tree/master/src/org/kde/kdeconnect/Plugins/PresenterPlugin/ - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectPresenterPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'presenter'); - - this._input = Components.acquire('input'); - } - - handlePacket(packet) { - if (packet.body.hasOwnProperty('dx')) { - this._input.movePointer( - packet.body.dx * 1000, - packet.body.dy * 1000 - ); - } else if (packet.body.stop) { - // Currently unsupported and unnecessary as we just re-use the mouse - // pointer instead of showing an arbitrary window. - } - } - - destroy() { - if (this._input !== undefined) - this._input = Components.release('input'); - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/runcommand.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/runcommand.js deleted file mode 100644 index ee6288b..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/runcommand.js +++ /dev/null @@ -1,250 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Run Commands'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.RunCommand', - description: _('Run commands on your paired device or let the device run predefined commands on this PC'), - incomingCapabilities: [ - 'kdeconnect.runcommand', - 'kdeconnect.runcommand.request', - ], - outgoingCapabilities: [ - 'kdeconnect.runcommand', - 'kdeconnect.runcommand.request', - ], - actions: { - commands: { - label: _('Commands'), - icon_name: 'system-run-symbolic', - - parameter_type: new GLib.VariantType('s'), - incoming: ['kdeconnect.runcommand'], - outgoing: ['kdeconnect.runcommand.request'], - }, - executeCommand: { - label: _('Commands'), - icon_name: 'system-run-symbolic', - - parameter_type: new GLib.VariantType('s'), - incoming: ['kdeconnect.runcommand'], - outgoing: ['kdeconnect.runcommand.request'], - }, - }, -}; - - -/** - * RunCommand Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/remotecommands - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/runcommand - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectRunCommandPlugin', - Properties: { - 'remote-commands': GObject.param_spec_variant( - 'remote-commands', - 'Remote Command List', - 'A list of the device\'s remote commands', - new GLib.VariantType('a{sv}'), - null, - GObject.ParamFlags.READABLE - ), - }, -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'runcommand'); - - // Local Commands - this._commandListChangedId = this.settings.connect( - 'changed::command-list', - this._sendCommandList.bind(this) - ); - - // We cache remote commands so they can be used in the settings even - // when the device is offline. - this._remote_commands = {}; - this.cacheProperties(['_remote_commands']); - } - - get remote_commands() { - return this._remote_commands; - } - - connected() { - super.connected(); - - this._sendCommandList(); - this._requestCommandList(); - this._handleCommandList(this.remote_commands); - } - - clearCache() { - this._remote_commands = {}; - this.notify('remote-commands'); - } - - cacheLoaded() { - if (!this.device.connected) - return; - - this._sendCommandList(); - this._requestCommandList(); - this._handleCommandList(this.remote_commands); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.runcommand': - this._handleCommandList(packet.body.commandList); - break; - - case 'kdeconnect.runcommand.request': - if (packet.body.hasOwnProperty('key')) - this._handleCommand(packet.body.key); - - else if (packet.body.hasOwnProperty('requestCommandList')) - this._sendCommandList(); - - break; - } - } - - /** - * Handle a request to execute the local command with the UUID @key - * - * @param {string} key - The UUID of the local command - */ - _handleCommand(key) { - try { - const commands = this.settings.get_value('command-list'); - const commandList = commands.recursiveUnpack(); - - if (!commandList.hasOwnProperty(key)) { - throw new Gio.IOErrorEnum({ - code: Gio.IOErrorEnum.PERMISSION_DENIED, - message: `Unknown command: ${key}`, - }); - } - - this.device.launchProcess([ - '/bin/sh', - '-c', - commandList[key].command, - ]); - } catch (e) { - logError(e, this.device.name); - } - } - - /** - * Parse the response to a request for the remote command list. Remove the - * command menu if there are no commands, otherwise amend the menu. - * - * @param {string|Object[]} commandList - A list of remote commands - */ - _handleCommandList(commandList) { - // See: https://github.com/GSConnect/gnome-shell-extension-gsconnect/issues/1051 - if (typeof commandList === 'string') { - try { - commandList = JSON.parse(commandList); - } catch (e) { - commandList = {}; - } - } - - this._remote_commands = commandList; - this.notify('remote-commands'); - - const commandEntries = Object.entries(this.remote_commands); - - // If there are no commands, hide the menu by disabling the action - this.device.lookup_action('commands').enabled = (commandEntries.length > 0); - - // Commands Submenu - const submenu = new Gio.Menu(); - - for (const [uuid, info] of commandEntries) { - const item = new Gio.MenuItem(); - item.set_label(info.name); - item.set_icon( - new Gio.ThemedIcon({name: 'application-x-executable-symbolic'}) - ); - item.set_detailed_action(`device.executeCommand::${uuid}`); - submenu.append_item(item); - } - - // Commands Item - const item = new Gio.MenuItem(); - item.set_detailed_action('device.commands::menu'); - item.set_attribute_value( - 'hidden-when', - new GLib.Variant('s', 'action-disabled') - ); - item.set_icon(new Gio.ThemedIcon({name: 'system-run-symbolic'})); - item.set_label(_('Commands')); - item.set_submenu(submenu); - - // If the submenu item is already present it will be replaced - const menuActions = this.device.settings.get_strv('menu-actions'); - const index = menuActions.indexOf('commands'); - - if (index > -1) { - this.device.removeMenuAction('commands'); - this.device.addMenuItem(item, index); - } - } - - /** - * Send a request for the remote command list - */ - _requestCommandList() { - this.device.sendPacket({ - type: 'kdeconnect.runcommand.request', - body: {requestCommandList: true}, - }); - } - - /** - * Send the local command list - */ - _sendCommandList() { - const commands = this.settings.get_value('command-list').recursiveUnpack(); - const commandList = JSON.stringify(commands); - - this.device.sendPacket({ - type: 'kdeconnect.runcommand', - body: {commandList: commandList}, - }); - } - - /** - * Placeholder function for command action - */ - commands() {} - - /** - * Send a request to execute the remote command with the UUID @key - * - * @param {string} key - The UUID of the remote command - */ - executeCommand(key) { - this.device.sendPacket({ - type: 'kdeconnect.runcommand.request', - body: {key: key}, - }); - } - - destroy() { - this.settings.disconnect(this._commandListChangedId); - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/sftp.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/sftp.js deleted file mode 100644 index e5ab3fe..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/sftp.js +++ /dev/null @@ -1,565 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Config = imports.config; -const Lan = imports.service.backends.lan; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('SFTP'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.SFTP', - description: _('Browse the paired device filesystem'), - incomingCapabilities: ['kdeconnect.sftp'], - outgoingCapabilities: ['kdeconnect.sftp.request'], - actions: { - mount: { - label: _('Mount'), - icon_name: 'folder-remote-symbolic', - - parameter_type: null, - incoming: ['kdeconnect.sftp'], - outgoing: ['kdeconnect.sftp.request'], - }, - unmount: { - label: _('Unmount'), - icon_name: 'media-eject-symbolic', - - parameter_type: null, - incoming: ['kdeconnect.sftp'], - outgoing: ['kdeconnect.sftp.request'], - }, - }, -}; - - -const MAX_MOUNT_DIRS = 12; - - -/** - * SFTP Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/sftp - * https://github.com/KDE/kdeconnect-android/tree/master/src/org/kde/kdeconnect/Plugins/SftpPlugin - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectSFTPPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'sftp'); - - this._gmount = null; - this._mounting = false; - - // A reusable launcher for ssh processes - this._launcher = new Gio.SubprocessLauncher({ - flags: (Gio.SubprocessFlags.STDOUT_PIPE | - Gio.SubprocessFlags.STDERR_MERGE), - }); - - // Watch the volume monitor - this._volumeMonitor = Gio.VolumeMonitor.get(); - - this._mountAddedId = this._volumeMonitor.connect( - 'mount-added', - this._onMountAdded.bind(this) - ); - - this._mountRemovedId = this._volumeMonitor.connect( - 'mount-removed', - this._onMountRemoved.bind(this) - ); - } - - get gmount() { - if (this._gmount === null && this.device.connected) { - const host = this.device.channel.host; - - const regex = new RegExp( - `sftp://(${host}):(1739|17[4-5][0-9]|176[0-4])` - ); - - for (const mount of this._volumeMonitor.get_mounts()) { - const uri = mount.get_root().get_uri(); - - if (regex.test(uri)) { - this._gmount = mount; - this._addSubmenu(mount); - this._addSymlink(mount); - - break; - } - } - } - - return this._gmount; - } - - connected() { - super.connected(); - - // Only enable for Lan connections - if (this.device.channel instanceof Lan.Channel) { - if (this.settings.get_boolean('automount')) - this.mount(); - } else { - this.device.lookup_action('mount').enabled = false; - this.device.lookup_action('unmount').enabled = false; - } - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.sftp': - if (packet.body.hasOwnProperty('errorMessage')) - this._handleError(packet); - else - this._handleMount(packet); - - break; - } - } - - _onMountAdded(monitor, mount) { - if (this._gmount !== null || !this.device.connected) - return; - - const host = this.device.channel.host; - const regex = new RegExp(`sftp://(${host}):(1739|17[4-5][0-9]|176[0-4])`); - const uri = mount.get_root().get_uri(); - - if (!regex.test(uri)) - return; - - this._gmount = mount; - this._addSubmenu(mount); - this._addSymlink(mount); - } - - _onMountRemoved(monitor, mount) { - if (this.gmount !== mount) - return; - - this._gmount = null; - this._removeSubmenu(); - } - - async _listDirectories(mount) { - const file = mount.get_root(); - - const iter = await new Promise((resolve, reject) => { - file.enumerate_children_async( - Gio.FILE_ATTRIBUTE_STANDARD_NAME, - Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, - GLib.PRIORITY_DEFAULT, - this.cancellable, - (file, res) => { - try { - resolve(file.enumerate_children_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - const infos = await new Promise((resolve, reject) => { - iter.next_files_async( - MAX_MOUNT_DIRS, - GLib.PRIORITY_DEFAULT, - this.cancellable, - (iter, res) => { - try { - resolve(iter.next_files_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - iter.close_async(GLib.PRIORITY_DEFAULT, null, null); - - const directories = {}; - - for (const info of infos) { - const name = info.get_name(); - directories[name] = `${file.get_uri()}${name}/`; - } - - return directories; - } - - _onAskQuestion(op, message, choices) { - op.reply(Gio.MountOperationResult.HANDLED); - } - - _onAskPassword(op, message, user, domain, flags) { - op.reply(Gio.MountOperationResult.HANDLED); - } - - /** - * Handle an error reported by the remote device. - * - * @param {Core.Packet} packet - a `kdeconnect.sftp` - */ - _handleError(packet) { - this.device.showNotification({ - id: 'sftp-error', - title: _('%s reported an error').format(this.device.name), - body: packet.body.errorMessage, - icon: new Gio.ThemedIcon({name: 'dialog-error-symbolic'}), - priority: Gio.NotificationPriority.HIGH, - }); - } - - /** - * Mount the remote device using the provided information. - * - * @param {Core.Packet} packet - a `kdeconnect.sftp` - */ - async _handleMount(packet) { - try { - // Already mounted or mounting - if (this.gmount !== null || this._mounting) - return; - - this._mounting = true; - - // Ensure the private key is in the keyring - await this._addPrivateKey(); - - // Create a new mount operation - const op = new Gio.MountOperation({ - username: packet.body.user || null, - password: packet.body.password || null, - password_save: Gio.PasswordSave.NEVER, - }); - - op.connect('ask-question', this._onAskQuestion); - op.connect('ask-password', this._onAskPassword); - - // This is the actual call to mount the device - const host = this.device.channel.host; - const uri = `sftp://${host}:${packet.body.port}/`; - const file = Gio.File.new_for_uri(uri); - - await new Promise((resolve, reject) => { - file.mount_enclosing_volume(0, op, null, (file, res) => { - try { - resolve(file.mount_enclosing_volume_finish(res)); - } catch (e) { - // Special case when the GMount didn't unmount properly - // but is still on the same port and can be reused. - if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.ALREADY_MOUNTED)) { - resolve(true); - - // There's a good chance this is a host key verification - // error; regardless we'll remove the key for security. - } else { - this._removeHostKey(host); - reject(e); - } - } - }); - }); - } catch (e) { - logError(e, this.device.name); - } finally { - this._mounting = false; - } - } - - /** - * Add GSConnect's private key identity to the authentication agent so our - * identity can be verified by Android during private key authentication. - * - * @return {Promise} A promise for the operation - */ - _addPrivateKey() { - const ssh_add = this._launcher.spawnv([ - Config.SSHADD_PATH, - GLib.build_filenamev([Config.CONFIGDIR, 'private.pem']), - ]); - - return new Promise((resolve, reject) => { - ssh_add.communicate_utf8_async(null, null, (proc, res) => { - try { - const result = proc.communicate_utf8_finish(res)[1].trim(); - - if (proc.get_exit_status() !== 0) - debug(result, this.device.name); - - resolve(); - } catch (e) { - reject(e); - } - }); - }); - } - - /** - * Remove all host keys from ~/.ssh/known_hosts for @host in the port range - * used by KDE Connect (1739-1764). - * - * @param {string} host - A hostname or IP address - */ - async _removeHostKey(host) { - for (let port = 1739; port <= 1764; port++) { - try { - const ssh_keygen = this._launcher.spawnv([ - Config.SSHKEYGEN_PATH, - '-R', - `[${host}]:${port}`, - ]); - - await new Promise((resolve, reject) => { - ssh_keygen.communicate_utf8_async(null, null, (proc, res) => { - try { - const stdout = proc.communicate_utf8_finish(res)[1]; - const status = proc.get_exit_status(); - - if (status !== 0) { - throw new Gio.IOErrorEnum({ - code: Gio.io_error_from_errno(status), - message: `${GLib.strerror(status)}\n${stdout}`.trim(), - }); - } - - resolve(); - } catch (e) { - reject(e); - } - }); - }); - } catch (e) { - logError(e, this.device.name); - } - } - } - - /* - * Mount menu helpers - */ - _getUnmountSection() { - if (this._unmountSection === undefined) { - this._unmountSection = new Gio.Menu(); - - const unmountItem = new Gio.MenuItem(); - unmountItem.set_label(Metadata.actions.unmount.label); - unmountItem.set_icon(new Gio.ThemedIcon({ - name: Metadata.actions.unmount.icon_name, - })); - unmountItem.set_detailed_action('device.unmount'); - this._unmountSection.append_item(unmountItem); - } - - return this._unmountSection; - } - - _getFilesMenuItem() { - if (this._filesMenuItem === undefined) { - // Files menu icon - const emblem = new Gio.Emblem({ - icon: new Gio.ThemedIcon({name: 'emblem-default'}), - }); - - const mountedIcon = new Gio.EmblemedIcon({ - gicon: new Gio.ThemedIcon({name: 'folder-remote-symbolic'}), - }); - mountedIcon.add_emblem(emblem); - - // Files menu item - this._filesMenuItem = new Gio.MenuItem(); - this._filesMenuItem.set_detailed_action('device.mount'); - this._filesMenuItem.set_icon(mountedIcon); - this._filesMenuItem.set_label(_('Files')); - } - - return this._filesMenuItem; - } - - async _addSubmenu(mount) { - try { - const directories = await this._listDirectories(mount); - - // Submenu sections - const dirSection = new Gio.Menu(); - const unmountSection = this._getUnmountSection(); - - for (const [name, uri] of Object.entries(directories)) - dirSection.append(name, `device.openPath::${uri}`); - - // Files submenu - const filesSubmenu = new Gio.Menu(); - filesSubmenu.append_section(null, dirSection); - filesSubmenu.append_section(null, unmountSection); - - // Files menu item - const filesMenuItem = this._getFilesMenuItem(); - filesMenuItem.set_submenu(filesSubmenu); - - // Replace the existing menu item - const index = this.device.removeMenuAction('device.mount'); - this.device.addMenuItem(filesMenuItem, index); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) - debug(e, this.device.name); - - // Reset to allow retrying - this._gmount = null; - } - } - - _removeSubmenu() { - try { - const index = this.device.removeMenuAction('device.mount'); - const action = this.device.lookup_action('mount'); - - if (action !== null) { - this.device.addMenuAction( - action, - index, - Metadata.actions.mount.label, - Metadata.actions.mount.icon_name - ); - } - } catch (e) { - logError(e, this.device.name); - } - } - - /** - * Create a symbolic link referring to the device by name - * - * @param {Gio.Mount} mount - A GMount to link to - */ - async _addSymlink(mount) { - try { - const by_name_dir = Gio.File.new_for_path( - `${Config.RUNTIMEDIR}/by-name/` - ); - - try { - by_name_dir.make_directory_with_parents(null); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) - throw e; - } - - // Replace path separator with a Unicode lookalike: - let safe_device_name = this.device.name.replace('/', '∕'); - - if (safe_device_name === '.') - safe_device_name = '·'; - else if (safe_device_name === '..') - safe_device_name = '··'; - - const link_target = mount.get_root().get_path(); - const link = Gio.File.new_for_path( - `${by_name_dir.get_path()}/${safe_device_name}` - ); - - // Check for and remove any existing stale link - try { - const link_stat = await new Promise((resolve, reject) => { - link.query_info_async( - 'standard::symlink-target', - Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, - GLib.PRIORITY_DEFAULT, - null, - (link, res) => { - try { - resolve(link.query_info_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - - if (link_stat.get_symlink_target() === link_target) - return; - - await new Promise((resolve, reject) => { - link.delete_async( - GLib.PRIORITY_DEFAULT, - null, - (link, res) => { - try { - resolve(link.delete_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } catch (e) { - if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) - throw e; - } - - link.make_symbolic_link(link_target, null); - } catch (e) { - debug(e, this.device.name); - } - } - - /** - * Send a request to mount the remote device - */ - mount() { - if (this.gmount !== null) - return; - - this.device.sendPacket({ - type: 'kdeconnect.sftp.request', - body: { - startBrowsing: true, - }, - }); - } - - /** - * Remove the menu items, unmount the filesystem, replace the mount item - */ - async unmount() { - try { - if (this.gmount === null) - return; - - this._removeSubmenu(); - this._mounting = false; - - await new Promise((resolve, reject) => { - this.gmount.unmount_with_operation( - Gio.MountUnmountFlags.FORCE, - new Gio.MountOperation(), - null, - (mount, res) => { - try { - resolve(mount.unmount_with_operation_finish(res)); - } catch (e) { - reject(e); - } - } - ); - }); - } catch (e) { - debug(e, this.device.name); - } - } - - destroy() { - if (this._volumeMonitor) { - this._volumeMonitor.disconnect(this._mountAddedId); - this._volumeMonitor.disconnect(this._mountRemovedId); - this._volumeMonitor = null; - } - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/share.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/share.js deleted file mode 100644 index 30b53ef..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/share.js +++ /dev/null @@ -1,483 +0,0 @@ -'use strict'; - -const GdkPixbuf = imports.gi.GdkPixbuf; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const PluginBase = imports.service.plugin; -const URI = imports.service.utils.uri; - - -var Metadata = { - label: _('Share'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Share', - description: _('Share files and URLs between devices'), - incomingCapabilities: ['kdeconnect.share.request'], - outgoingCapabilities: ['kdeconnect.share.request'], - actions: { - share: { - label: _('Share'), - icon_name: 'send-to-symbolic', - - parameter_type: null, - incoming: [], - outgoing: ['kdeconnect.share.request'], - }, - shareFile: { - label: _('Share File'), - icon_name: 'document-send-symbolic', - - parameter_type: new GLib.VariantType('(sb)'), - incoming: [], - outgoing: ['kdeconnect.share.request'], - }, - shareText: { - label: _('Share Text'), - icon_name: 'send-to-symbolic', - - parameter_type: new GLib.VariantType('s'), - incoming: [], - outgoing: ['kdeconnect.share.request'], - }, - shareUri: { - label: _('Share Link'), - icon_name: 'send-to-symbolic', - - parameter_type: new GLib.VariantType('s'), - incoming: [], - outgoing: ['kdeconnect.share.request'], - }, - }, -}; - - -/** - * Share Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/share - * - * TODO: receiving 'text' TODO: Window with textview & 'Copy to Clipboard.. - * https://github.com/KDE/kdeconnect-kde/commit/28f11bd5c9a717fb9fbb3f02ddd6cea62021d055 - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectSharePlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'share'); - } - - handlePacket(packet) { - // TODO: composite jobs (lastModified, numberOfFiles, totalPayloadSize) - if (packet.body.hasOwnProperty('filename')) { - if (this.settings.get_boolean('receive-files')) - this._handleFile(packet); - else - this._refuseFile(packet); - } else if (packet.body.hasOwnProperty('text')) { - this._handleText(packet); - } else if (packet.body.hasOwnProperty('url')) { - this._handleUri(packet); - } - } - - _ensureReceiveDirectory() { - let receiveDir = this.settings.get_string('receive-directory'); - - // Ensure a directory is set - if (receiveDir.length === 0) { - receiveDir = GLib.get_user_special_dir( - GLib.UserDirectory.DIRECTORY_DOWNLOAD - ); - - // Fallback to ~/Downloads - const homeDir = GLib.get_home_dir(); - - if (!receiveDir || receiveDir === homeDir) - receiveDir = GLib.build_filenamev([homeDir, 'Downloads']); - - this.settings.set_string('receive-directory', receiveDir); - } - - // Ensure the directory exists - if (!GLib.file_test(receiveDir, GLib.FileTest.IS_DIR)) - GLib.mkdir_with_parents(receiveDir, 448); - - return receiveDir; - } - - _getFile(filename) { - const dirpath = this._ensureReceiveDirectory(); - const basepath = GLib.build_filenamev([dirpath, filename]); - let filepath = basepath; - let copyNum = 0; - - while (GLib.file_test(filepath, GLib.FileTest.EXISTS)) - filepath = `${basepath} (${++copyNum})`; - - return Gio.File.new_for_path(filepath); - } - - _refuseFile(packet) { - try { - this.device.rejectTransfer(packet); - - this.device.showNotification({ - id: `${Date.now()}`, - title: _('Transfer Failed'), - // TRANSLATORS: eg. Google Pixel is not allowed to upload files - body: _('%s is not allowed to upload files').format( - this.device.name - ), - icon: new Gio.ThemedIcon({name: 'dialog-error-symbolic'}), - }); - } catch (e) { - debug(e, this.device.name); - } - } - - async _handleFile(packet) { - try { - const file = this._getFile(packet.body.filename); - - // Create the transfer - const transfer = this.device.createTransfer(); - - transfer.addFile(packet, file); - - // Notify that we're about to start the transfer - this.device.showNotification({ - id: transfer.uuid, - title: _('Transferring File'), - // TRANSLATORS: eg. Receiving 'book.pdf' from Google Pixel - body: _('Receiving “%s” from %s').format( - packet.body.filename, - this.device.name - ), - buttons: [{ - label: _('Cancel'), - action: 'cancelTransfer', - parameter: new GLib.Variant('s', transfer.uuid), - }], - icon: new Gio.ThemedIcon({name: 'document-save-symbolic'}), - }); - - // We'll show a notification (success or failure) - let title, body, iconName; - let buttons = []; - - try { - await transfer.start(); - - title = _('Transfer Successful'); - // TRANSLATORS: eg. Received 'book.pdf' from Google Pixel - body = _('Received “%s” from %s').format( - packet.body.filename, - this.device.name - ); - buttons = [ - { - label: _('Open Folder'), - action: 'openPath', - parameter: new GLib.Variant('s', file.get_parent().get_uri()), - }, - { - label: _('Open File'), - action: 'openPath', - parameter: new GLib.Variant('s', file.get_uri()), - }, - ]; - iconName = 'document-save-symbolic'; - - if (packet.body.open) { - const uri = file.get_uri(); - Gio.AppInfo.launch_default_for_uri_async(uri, null, null, null); - } - } catch (e) { - debug(e, this.device.name); - - title = _('Transfer Failed'); - // TRANSLATORS: eg. Failed to receive 'book.pdf' from Google Pixel - body = _('Failed to receive “%s” from %s').format( - packet.body.filename, - this.device.name - ); - iconName = 'dialog-warning-symbolic'; - - // Clean up the downloaded file on failure - file.delete_async(GLib.PRIORITY_DEAFAULT, null, null); - } - - this.device.hideNotification(transfer.uuid); - this.device.showNotification({ - id: transfer.uuid, - title: title, - body: body, - buttons: buttons, - icon: new Gio.ThemedIcon({name: iconName}), - }); - } catch (e) { - logError(e, this.device.name); - } - } - - _handleUri(packet) { - const uri = packet.body.url; - Gio.AppInfo.launch_default_for_uri_async(uri, null, null, null); - } - - _handleText(packet) { - const dialog = new Gtk.MessageDialog({ - text: _('Text Shared By %s').format(this.device.name), - secondary_text: URI.linkify(packet.body.text), - secondary_use_markup: true, - buttons: Gtk.ButtonsType.CLOSE, - }); - dialog.message_area.get_children()[1].selectable = true; - dialog.set_keep_above(true); - dialog.connect('response', (dialog) => dialog.destroy()); - dialog.show(); - } - - /** - * Open the file chooser dialog for selecting a file or inputing a URI. - */ - share() { - const dialog = new FileChooserDialog(this.device); - dialog.show(); - } - - /** - * Share local file path or URI - * - * @param {string} path - Local file path or URI - * @param {boolean} open - Whether the file should be opened after transfer - */ - async shareFile(path, open = false) { - try { - let file = null; - - if (path.includes('://')) - file = Gio.File.new_for_uri(path); - else - file = Gio.File.new_for_path(path); - - // Create the transfer - const transfer = this.device.createTransfer(); - - transfer.addFile({ - type: 'kdeconnect.share.request', - body: { - filename: file.get_basename(), - open: open, - }, - }, file); - - // Notify that we're about to start the transfer - this.device.showNotification({ - id: transfer.uuid, - title: _('Transferring File'), - // TRANSLATORS: eg. Sending 'book.pdf' to Google Pixel - body: _('Sending “%s” to %s').format( - file.get_basename(), - this.device.name - ), - buttons: [{ - label: _('Cancel'), - action: 'cancelTransfer', - parameter: new GLib.Variant('s', transfer.uuid), - }], - icon: new Gio.ThemedIcon({name: 'document-send-symbolic'}), - }); - - // We'll show a notification (success or failure) - let title, body, iconName; - - try { - await transfer.start(); - - title = _('Transfer Successful'); - // TRANSLATORS: eg. Sent "book.pdf" to Google Pixel - body = _('Sent “%s” to %s').format( - file.get_basename(), - this.device.name - ); - iconName = 'document-send-symbolic'; - } catch (e) { - debug(e, this.device.name); - - title = _('Transfer Failed'); - // TRANSLATORS: eg. Failed to send "book.pdf" to Google Pixel - body = _('Failed to send “%s” to %s').format( - file.get_basename(), - this.device.name - ); - iconName = 'dialog-warning-symbolic'; - } - - this.device.hideNotification(transfer.uuid); - this.device.showNotification({ - id: transfer.uuid, - title: title, - body: body, - icon: new Gio.ThemedIcon({name: iconName}), - }); - } catch (e) { - debug(e, this.device.name); - } - } - - /** - * Share a string of text. Remote behaviour is undefined. - * - * @param {string} text - A string of unicode text - */ - shareText(text) { - this.device.sendPacket({ - type: 'kdeconnect.share.request', - body: {text: text}, - }); - } - - /** - * Share a URI. Generally the remote device opens it with the scheme default - * - * @param {string} uri - A URI to share - */ - shareUri(uri) { - if (GLib.uri_parse_scheme(uri) === 'file') { - this.shareFile(uri); - return; - } - - this.device.sendPacket({ - type: 'kdeconnect.share.request', - body: {url: uri}, - }); - } -}); - - -/** A simple FileChooserDialog for sharing files */ -var FileChooserDialog = GObject.registerClass({ - GTypeName: 'GSConnectShareFileChooserDialog', -}, class FileChooserDialog extends Gtk.FileChooserDialog { - - _init(device) { - super._init({ - // TRANSLATORS: eg. Send files to Google Pixel - title: _('Send files to %s').format(device.name), - select_multiple: true, - extra_widget: new Gtk.CheckButton({ - // TRANSLATORS: Mark the file to be opened once completed - label: _('Open when done'), - visible: true, - }), - use_preview_label: false, - }); - - this.device = device; - - // Align checkbox with sidebar - const box = this.get_content_area().get_children()[0].get_children()[0]; - const paned = box.get_children()[0]; - paned.bind_property( - 'position', - this.extra_widget, - 'margin-left', - GObject.BindingFlags.SYNC_CREATE - ); - - // Preview Widget - this.preview_widget = new Gtk.Image(); - this.preview_widget_active = false; - this.connect('update-preview', this._onUpdatePreview); - - // URI entry - this._uriEntry = new Gtk.Entry({ - placeholder_text: 'https://', - hexpand: true, - visible: true, - }); - this._uriEntry.connect('activate', this._sendLink.bind(this)); - - // URI/File toggle - this._uriButton = new Gtk.ToggleButton({ - image: new Gtk.Image({ - icon_name: 'web-browser-symbolic', - pixel_size: 16, - }), - valign: Gtk.Align.CENTER, - // TRANSLATORS: eg. Send a link to Google Pixel - tooltip_text: _('Send a link to %s').format(device.name), - visible: true, - }); - this._uriButton.connect('toggled', this._onUriButtonToggled.bind(this)); - - this.add_button(_('Cancel'), Gtk.ResponseType.CANCEL); - const sendButton = this.add_button(_('Send'), Gtk.ResponseType.OK); - sendButton.connect('clicked', this._sendLink.bind(this)); - - this.get_header_bar().pack_end(this._uriButton); - this.set_default_response(Gtk.ResponseType.OK); - } - - _onUpdatePreview(chooser) { - try { - const pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size( - chooser.get_preview_filename(), - chooser.get_scale_factor() * 128, - -1 - ); - chooser.preview_widget.pixbuf = pixbuf; - chooser.preview_widget.visible = true; - chooser.preview_widget_active = true; - } catch (e) { - chooser.preview_widget.visible = false; - chooser.preview_widget_active = false; - } - } - - _onUriButtonToggled(button) { - const header = this.get_header_bar(); - - // Show the URL entry - if (button.active) { - this.extra_widget.sensitive = false; - header.set_custom_title(this._uriEntry); - this.set_response_sensitive(Gtk.ResponseType.OK, true); - - // Hide the URL entry - } else { - header.set_custom_title(null); - this.set_response_sensitive( - Gtk.ResponseType.OK, - this.get_uris().length > 1 - ); - this.extra_widget.sensitive = true; - } - } - - _sendLink(widget) { - if (this._uriButton.active && this._uriEntry.text.length) - this.response(1); - } - - vfunc_response(response_id) { - if (response_id === Gtk.ResponseType.OK) { - for (const uri of this.get_uris()) { - const parameter = new GLib.Variant( - '(sb)', - [uri, this.extra_widget.active] - ); - this.device.activate_action('shareFile', parameter); - } - } else if (response_id === 1) { - const parameter = new GLib.Variant('s', this._uriEntry.text); - this.device.activate_action('shareUri', parameter); - } - - this.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/sms.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/sms.js deleted file mode 100644 index 8273f7e..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/sms.js +++ /dev/null @@ -1,527 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const PluginBase = imports.service.plugin; -const LegacyMessaging = imports.service.ui.legacyMessaging; -const Messaging = imports.service.ui.messaging; -const URI = imports.service.utils.uri; - - -var Metadata = { - label: _('SMS'), - description: _('Send and read SMS of the paired device and be notified of new SMS'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.SMS', - incomingCapabilities: [ - 'kdeconnect.sms.messages', - ], - outgoingCapabilities: [ - 'kdeconnect.sms.request', - 'kdeconnect.sms.request_conversation', - 'kdeconnect.sms.request_conversations', - ], - actions: { - // SMS Actions - sms: { - label: _('Messaging'), - icon_name: 'sms-symbolic', - - parameter_type: null, - incoming: [], - outgoing: ['kdeconnect.sms.request'], - }, - uriSms: { - label: _('New SMS (URI)'), - icon_name: 'sms-symbolic', - - parameter_type: new GLib.VariantType('s'), - incoming: [], - outgoing: ['kdeconnect.sms.request'], - }, - replySms: { - label: _('Reply SMS'), - icon_name: 'sms-symbolic', - - parameter_type: new GLib.VariantType('s'), - incoming: [], - outgoing: ['kdeconnect.sms.request'], - }, - sendMessage: { - label: _('Send Message'), - icon_name: 'sms-send', - - parameter_type: new GLib.VariantType('(aa{sv})'), - incoming: [], - outgoing: ['kdeconnect.sms.request'], - }, - sendSms: { - label: _('Send SMS'), - icon_name: 'sms-send', - - parameter_type: new GLib.VariantType('(ss)'), - incoming: [], - outgoing: ['kdeconnect.sms.request'], - }, - shareSms: { - label: _('Share SMS'), - icon_name: 'sms-send', - - parameter_type: new GLib.VariantType('s'), - incoming: [], - outgoing: ['kdeconnect.sms.request'], - }, - }, -}; - - -/** - * SMS Message event type. Currently all events are TEXT_MESSAGE. - * - * TEXT_MESSAGE: Has a "body" field which contains pure, human-readable text - */ -var MessageEvent = { - TEXT_MESSAGE: 0x1, -}; - - -/** - * SMS Message status. READ/UNREAD match the 'read' field from the Android App - * message packet. - * - * UNREAD: A message not marked as read - * READ: A message marked as read - */ -var MessageStatus = { - UNREAD: 0, - READ: 1, -}; - - -/** - * SMS Message direction. IN/OUT match the 'type' field from the Android App - * message packet. - * - * See: https://developer.android.com/reference/android/provider/Telephony.TextBasedSmsColumns.html - * - * IN: An incoming message - * OUT: An outgoing message - */ -var MessageBox = { - ALL: 0, - INBOX: 1, - SENT: 2, - DRAFT: 3, - OUTBOX: 4, - FAILED: 5, - QUEUED: 6, -}; - - -/** - * SMS Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/sms - * https://github.com/KDE/kdeconnect-android/tree/master/src/org/kde/kdeconnect/Plugins/SMSPlugin/ - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectSMSPlugin', - Properties: { - 'threads': GObject.param_spec_variant( - 'threads', - 'Conversation List', - 'A list of threads', - new GLib.VariantType('aa{sv}'), - null, - GObject.ParamFlags.READABLE - ), - }, -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'sms'); - - this.cacheProperties(['_threads']); - } - - get threads() { - if (this._threads === undefined) - this._threads = {}; - - return this._threads; - } - - get window() { - if (this.settings.get_boolean('legacy-sms')) { - return new LegacyMessaging.Dialog({ - device: this.device, - plugin: this, - }); - } - - if (this._window === undefined) { - this._window = new Messaging.Window({ - application: Gio.Application.get_default(), - device: this.device, - plugin: this, - }); - - this._window.connect('destroy', () => { - this._window = undefined; - }); - } - - return this._window; - } - - clearCache() { - this._threads = {}; - this.notify('threads'); - } - - cacheLoaded() { - this.notify('threads'); - } - - connected() { - super.connected(); - this._requestConversations(); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.sms.messages': - this._handleMessages(packet.body.messages); - break; - } - } - - /** - * Handle a digest of threads. - * - * @param {Object[]} messages - A list of message objects - * @param {string[]} thread_ids - A list of thread IDs as strings - */ - _handleDigest(messages, thread_ids) { - // Prune threads - for (const thread_id of Object.keys(this.threads)) { - if (!thread_ids.includes(thread_id)) - delete this.threads[thread_id]; - } - - // Request each new or newer thread - for (let i = 0, len = messages.length; i < len; i++) { - const message = messages[i]; - const cache = this.threads[message.thread_id]; - - if (cache === undefined) { - this._requestConversation(message.thread_id); - continue; - } - - // If this message is marked read, mark the rest as read - if (message.read === MessageStatus.READ) { - for (const msg of cache) - msg.read = MessageStatus.READ; - } - - // If we don't have a thread for this message or it's newer - // than the last message in the cache, request the thread - if (!cache.length || cache[cache.length - 1].date < message.date) - this._requestConversation(message.thread_id); - } - - this.notify('threads'); - } - - /** - * Handle a new single message - * - * @param {Object} message - A message object - */ - _handleMessage(message) { - let conversation = null; - - // If the window is open, try and find an active conversation - if (this._window) - conversation = this._window.getConversationForMessage(message); - - // If there's an active conversation, we should log the message now - if (conversation) - conversation.logNext(message); - } - - /** - * Parse a conversation (thread of messages) and sort them - * - * @param {Object[]} thread - A list of sms message objects from a thread - */ - _handleThread(thread) { - // If there are no addresses this will cause major problems... - if (!thread[0].addresses || !thread[0].addresses[0]) - return; - - const thread_id = thread[0].thread_id; - const cache = this.threads[thread_id] || []; - - // Handle each message - for (let i = 0, len = thread.length; i < len; i++) { - const message = thread[i]; - - // TODO: We only cache messages of a known MessageBox since we - // have no reliable way to determine its direction, let alone - // what to do with it. - if (message.type < 0 || message.type > 6) - continue; - - // If the message exists, just update it - const cacheMessage = cache.find(m => m.date === message.date); - - if (cacheMessage) { - Object.assign(cacheMessage, message); - } else { - cache.push(message); - this._handleMessage(message); - } - } - - // Sort the thread by ascending date and notify - this.threads[thread_id] = cache.sort((a, b) => a.date - b.date); - this.notify('threads'); - } - - /** - * Handle a response to telephony.request_conversation(s) - * - * @param {Object[]} messages - A list of sms message objects - */ - _handleMessages(messages) { - try { - // If messages is empty there's nothing to do... - if (messages.length === 0) - return; - - const thread_ids = []; - - // Perform some modification of the messages - for (let i = 0, len = messages.length; i < len; i++) { - const message = messages[i]; - - // COERCION: thread_id's to strings - message.thread_id = `${message.thread_id}`; - thread_ids.push(message.thread_id); - - // TODO: Remove bogus `insert-address-token` entries - let a = message.addresses.length; - - while (a--) { - if (message.addresses[a].address === undefined || - message.addresses[a].address === 'insert-address-token') - message.addresses.splice(a, 1); - } - } - - // If there's multiple thread_id's it's a summary of threads - if (thread_ids.some(id => id !== thread_ids[0])) - this._handleDigest(messages, thread_ids); - - // Otherwise this is single thread or new message - else - this._handleThread(messages); - } catch (e) { - debug(e, this.device.name); - } - } - - /** - * Request a list of messages from a single thread. - * - * @param {number} thread_id - The id of the thread to request - */ - _requestConversation(thread_id) { - this.device.sendPacket({ - type: 'kdeconnect.sms.request_conversation', - body: { - threadID: thread_id, - }, - }); - } - - /** - * Request a list of the last message in each unarchived thread. - */ - _requestConversations() { - this.device.sendPacket({ - type: 'kdeconnect.sms.request_conversations', - }); - } - - /** - * A notification action for replying to SMS messages (or missed calls). - * - * @param {string} hint - Could be either a contact name or phone number - */ - replySms(hint) { - this.window.present(); - // FIXME: causes problems now that non-numeric addresses are allowed - // this.window.address = hint.toPhoneNumber(); - } - - /** - * Send an SMS message - * - * @param {string} phoneNumber - The phone number to send the message to - * @param {string} messageBody - The message to send - */ - sendSms(phoneNumber, messageBody) { - this.device.sendPacket({ - type: 'kdeconnect.sms.request', - body: { - sendSms: true, - phoneNumber: phoneNumber, - messageBody: messageBody, - }, - }); - } - - /** - * Send a message - * - * @param {Object[]} addresses - A list of address objects - * @param {string} messageBody - The message text - * @param {number} [event] - An event bitmask - * @param {boolean} [forceSms] - Whether to force SMS - * @param {number} [subId] - The SIM card to use - */ - sendMessage(addresses, messageBody, event = 1, forceSms = false, subId = undefined) { - // TODO: waiting on support in kdeconnect-android - // if (this._version === 1) { - this.device.sendPacket({ - type: 'kdeconnect.sms.request', - body: { - sendSms: true, - phoneNumber: addresses[0].address, - messageBody: messageBody, - }, - }); - // } else if (this._version === 2) { - // this.device.sendPacket({ - // type: 'kdeconnect.sms.request', - // body: { - // version: 2, - // addresses: addresses, - // messageBody: messageBody, - // forceSms: forceSms, - // sub_id: subId - // } - // }); - // } - } - - /** - * Share a text content by SMS message. This is used by the WebExtension to - * share URLs from the browser, but could be used to initiate sharing of any - * text content. - * - * @param {string} url - The link to be shared - */ - shareSms(url) { - // Legacy Mode - if (this.settings.get_boolean('legacy-sms')) { - const window = this.window; - window.present(); - window.setMessage(url); - - // If there are active threads, show the chooser dialog - } else if (Object.values(this.threads).length > 0) { - const window = new Messaging.ConversationChooser({ - application: Gio.Application.get_default(), - device: this.device, - message: url, - plugin: this, - }); - - window.present(); - - // Otherwise show the window and wait for a contact to be chosen - } else { - this.window.present(); - this.window.setMessage(url, true); - } - } - - /** - * Open and present the messaging window - */ - sms() { - this.window.present(); - } - - /** - * This is the sms: URI scheme handler - * - * @param {string} uri - The URI the handle (sms:|sms://|sms:///) - */ - uriSms(uri) { - try { - uri = new URI.SmsURI(uri); - - // Lookup contacts - const addresses = uri.recipients.map(number => { - return {address: number.toPhoneNumber()}; - }); - const contacts = this.device.contacts.lookupAddresses(addresses); - - // Present the window and show the conversation - const window = this.window; - window.present(); - window.setContacts(contacts); - - // Set the outgoing message if the uri has a body variable - if (uri.body) - window.setMessage(uri.body); - } catch (e) { - debug(e, `${this.device.name}: "${uri}"`); - } - } - - _threadHasAddress(thread, addressObj) { - const number = addressObj.address.toPhoneNumber(); - - for (const taddressObj of thread[0].addresses) { - const tnumber = taddressObj.address.toPhoneNumber(); - - if (number.endsWith(tnumber) || tnumber.endsWith(number)) - return true; - } - - return false; - } - - /** - * Try to find a thread_id in @smsPlugin for @addresses. - * - * @param {Object[]} addresses - a list of address objects - * @return {string|null} a thread ID - */ - getThreadIdForAddresses(addresses = []) { - const threads = Object.values(this.threads); - - for (const thread of threads) { - if (addresses.length !== thread[0].addresses.length) - continue; - - if (addresses.every(addressObj => this._threadHasAddress(thread, addressObj))) - return thread[0].thread_id; - } - - return null; - } - - destroy() { - if (this._window !== undefined) - this._window.destroy(); - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/systemvolume.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/systemvolume.js deleted file mode 100644 index 758fcc3..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/systemvolume.js +++ /dev/null @@ -1,200 +0,0 @@ -'use strict'; - -const GObject = imports.gi.GObject; - -const Components = imports.service.components; -const Config = imports.config; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('System Volume'), - description: _('Enable the paired device to control the system volume'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.SystemVolume', - incomingCapabilities: ['kdeconnect.systemvolume.request'], - outgoingCapabilities: ['kdeconnect.systemvolume'], - actions: {}, -}; - - -/** - * SystemVolume Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/systemvolume - * https://github.com/KDE/kdeconnect-android/tree/master/src/org/kde/kdeconnect/Plugins/SystemvolumePlugin/ - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectSystemVolumePlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'systemvolume'); - - // Cache stream properties - this._cache = new WeakMap(); - - // Connect to the mixer - try { - this._mixer = Components.acquire('pulseaudio'); - - this._streamChangedId = this._mixer.connect( - 'stream-changed', - this._sendSink.bind(this) - ); - - this._outputAddedId = this._mixer.connect( - 'output-added', - this._sendSinkList.bind(this) - ); - - this._outputRemovedId = this._mixer.connect( - 'output-removed', - this._sendSinkList.bind(this) - ); - - // Modify the error to redirect to the wiki - } catch (e) { - e.name = _('PulseAudio not found'); - e.url = `${Config.PACKAGE_URL}/wiki/Error#pulseaudio-not-found`; - throw e; - } - } - - handlePacket(packet) { - switch (true) { - case packet.body.hasOwnProperty('requestSinks'): - this._sendSinkList(); - break; - - case packet.body.hasOwnProperty('name'): - this._changeSink(packet); - break; - } - } - - connected() { - super.connected(); - - this._sendSinkList(); - } - - /** - * Handle a request to change an output - * - * @param {Core.Packet} packet - a `kdeconnect.systemvolume.request` - */ - _changeSink(packet) { - let stream; - - for (const sink of this._mixer.get_sinks()) { - if (sink.name === packet.body.name) { - stream = sink; - break; - } - } - - // No sink with the given name - if (stream === undefined) { - this._sendSinkList(); - return; - } - - // Get a cache and store volume and mute states if changed - const cache = this._cache.get(stream) || {}; - - if (packet.body.hasOwnProperty('muted')) { - cache.muted = packet.body.muted; - this._cache.set(stream, cache); - stream.change_is_muted(packet.body.muted); - } - - if (packet.body.hasOwnProperty('volume')) { - cache.volume = packet.body.volume; - this._cache.set(stream, cache); - stream.volume = packet.body.volume; - stream.push_volume(); - } - } - - /** - * Update the cache for @stream - * - * @param {Gvc.MixerStream} stream - The stream to cache - * @return {Object} The updated cache object - */ - _updateCache(stream) { - const state = { - name: stream.name, - description: stream.display_name, - muted: stream.is_muted, - volume: stream.volume, - maxVolume: this._mixer.get_vol_max_norm(), - }; - - this._cache.set(stream, state); - - return state; - } - - /** - * Send the state of a local sink - * - * @param {Gvc.MixerControl} mixer - The mixer that owns the stream - * @param {number} id - The Id of the stream that changed - */ - _sendSink(mixer, id) { - // Avoid starving the packet channel when fading - if (this._mixer.fading) - return; - - // Check the cache - const stream = this._mixer.lookup_stream_id(id); - const cache = this._cache.get(stream) || {}; - - // If the port has changed we have to send the whole list to update the - // display name - if (!cache.display_name || cache.display_name !== stream.display_name) { - this._sendSinkList(); - return; - } - - // If only volume and/or mute are set, send a single update - if (cache.volume !== stream.volume || cache.muted !== stream.is_muted) { - // Update the cache - const state = this._updateCache(stream); - - // Send the stream update - this.device.sendPacket({ - type: 'kdeconnect.systemvolume', - body: state, - }); - } - } - - /** - * Send a list of local sinks - */ - _sendSinkList() { - const sinkList = this._mixer.get_sinks().map(sink => { - return this._updateCache(sink); - }); - - // Send the sinkList - this.device.sendPacket({ - type: 'kdeconnect.systemvolume', - body: { - sinkList: sinkList, - }, - }); - } - - destroy() { - if (this._mixer !== undefined) { - this._mixer.disconnect(this._streamChangedId); - this._mixer.disconnect(this._outputAddedId); - this._mixer.disconnect(this._outputRemovedId); - this._mixer = Components.release('pulseaudio'); - } - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/telephony.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/telephony.js deleted file mode 100644 index 7d1b44d..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/plugins/telephony.js +++ /dev/null @@ -1,241 +0,0 @@ -'use strict'; - -const GdkPixbuf = imports.gi.GdkPixbuf; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Components = imports.service.components; -const PluginBase = imports.service.plugin; - - -var Metadata = { - label: _('Telephony'), - description: _('Be notified about calls and adjust system volume during ringing/ongoing calls'), - id: 'org.gnome.Shell.Extensions.GSConnect.Plugin.Telephony', - incomingCapabilities: [ - 'kdeconnect.telephony', - ], - outgoingCapabilities: [ - 'kdeconnect.telephony.request', - 'kdeconnect.telephony.request_mute', - ], - actions: { - muteCall: { - // TRANSLATORS: Silence the actively ringing call - label: _('Mute Call'), - icon_name: 'audio-volume-muted-symbolic', - - parameter_type: null, - incoming: ['kdeconnect.telephony'], - outgoing: ['kdeconnect.telephony.request_mute'], - }, - }, -}; - - -/** - * Telephony Plugin - * https://github.com/KDE/kdeconnect-kde/tree/master/plugins/telephony - * https://github.com/KDE/kdeconnect-android/tree/master/src/org/kde/kdeconnect/Plugins/TelephonyPlugin - */ -var Plugin = GObject.registerClass({ - GTypeName: 'GSConnectTelephonyPlugin', -}, class Plugin extends PluginBase.Plugin { - - _init(device) { - super._init(device, 'telephony'); - - // Neither of these are crucial for the plugin to work - this._mpris = Components.acquire('mpris'); - this._mixer = Components.acquire('pulseaudio'); - } - - handlePacket(packet) { - switch (packet.type) { - case 'kdeconnect.telephony': - this._handleEvent(packet); - break; - } - } - - /** - * Change volume, microphone and media player state in response to an - * incoming or answered call. - * - * @param {string} eventType - 'ringing' or 'talking' - */ - _setMediaState(eventType) { - // Mixer Volume - if (this._mixer !== undefined) { - switch (this.settings.get_string(`${eventType}-volume`)) { - case 'restore': - this._mixer.restore(); - break; - - case 'lower': - this._mixer.lowerVolume(); - break; - - case 'mute': - this._mixer.muteVolume(); - break; - } - - if (eventType === 'talking' && this.settings.get_boolean('talking-microphone')) - this._mixer.muteMicrophone(); - } - - // Media Playback - if (this._mpris && this.settings.get_boolean(`${eventType}-pause`)) - this._mpris.pauseAll(); - } - - /** - * Restore volume, microphone and media player state (if changed), making - * sure to unpause before raising volume. - * - * TODO: there's a possibility we might revert a media/mixer state set for - * another device. - */ - _restoreMediaState() { - // Media Playback - if (this._mpris) - this._mpris.unpauseAll(); - - // Mixer Volume - if (this._mixer) - this._mixer.restore(); - } - - /** - * Load a Gdk.Pixbuf from base64 encoded data - * - * @param {string} data - Base64 encoded JPEG data - * @return {Gdk.Pixbuf|null} A contact photo - */ - _getThumbnailPixbuf(data) { - const loader = new GdkPixbuf.PixbufLoader(); - - try { - data = GLib.base64_decode(data); - loader.write(data); - loader.close(); - } catch (e) { - debug(e, this.device.name); - } - - return loader.get_pixbuf(); - } - - /** - * Handle a telephony event (ringing, talking), showing or hiding a - * notification and possibly adjusting the media/mixer state. - * - * @param {Core.Packet} packet - A `kdeconnect.telephony` - */ - _handleEvent(packet) { - // Only handle 'ringing' or 'talking' events; leave the notification - // plugin to handle 'missedCall' since they're often repliable - if (!['ringing', 'talking'].includes(packet.body.event)) - return; - - // This is the end of a telephony event - if (packet.body.isCancel) - this._cancelEvent(packet); - else - this._notifyEvent(packet); - } - - _cancelEvent(packet) { - // Ensure we have a sender - // TRANSLATORS: No name or phone number - let sender = _('Unknown Contact'); - - if (packet.body.contactName) - sender = packet.body.contactName; - else if (packet.body.phoneNumber) - sender = packet.body.phoneNumber; - - this.device.hideNotification(`${packet.body.event}|${sender}`); - this._restoreMediaState(); - } - - _notifyEvent(packet) { - let body; - let buttons = []; - let icon = null; - let priority = Gio.NotificationPriority.NORMAL; - - // Ensure we have a sender - // TRANSLATORS: No name or phone number - let sender = _('Unknown Contact'); - - if (packet.body.contactName) - sender = packet.body.contactName; - else if (packet.body.phoneNumber) - sender = packet.body.phoneNumber; - - // If there's a photo, use it as the notification icon - if (packet.body.phoneThumbnail) - icon = this._getThumbnailPixbuf(packet.body.phoneThumbnail); - - if (icon === null) - icon = new Gio.ThemedIcon({name: 'call-start-symbolic'}); - - // Notify based based on the event type - if (packet.body.event === 'ringing') { - this._setMediaState('ringing'); - - // TRANSLATORS: The phone is ringing - body = _('Incoming call'); - buttons = [{ - action: 'muteCall', - // TRANSLATORS: Silence the actively ringing call - label: _('Mute'), - parameter: null, - }]; - priority = Gio.NotificationPriority.URGENT; - } - - if (packet.body.event === 'talking') { - this.device.hideNotification(`ringing|${sender}`); - this._setMediaState('talking'); - - // TRANSLATORS: A phone call is active - body = _('Ongoing call'); - } - - this.device.showNotification({ - id: `${packet.body.event}|${sender}`, - title: sender, - body: body, - icon: icon, - priority: priority, - buttons: buttons, - }); - } - - /** - * Silence an incoming call and restore the previous mixer/media state, if - * applicable. - */ - muteCall() { - this.device.sendPacket({ - type: 'kdeconnect.telephony.request_mute', - body: {}, - }); - - this._restoreMediaState(); - } - - destroy() { - if (this._mixer !== undefined) - this._mixer = Components.release('pulseaudio'); - - if (this._mpris !== undefined) - this._mpris = Components.release('mpris'); - - super.destroy(); - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/__init__.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/__init__.js deleted file mode 100644 index c85aea9..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/__init__.js +++ /dev/null @@ -1,49 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const Gtk = imports.gi.Gtk; - -const Config = imports.config; - - -/* - * Window State - */ -Gtk.Window.prototype.restoreGeometry = function (context = 'default') { - this._windowState = new Gio.Settings({ - settings_schema: Config.GSCHEMA.lookup( - 'org.gnome.Shell.Extensions.GSConnect.WindowState', - true - ), - path: `/org/gnome/shell/extensions/gsconnect/${context}/`, - }); - - // Size - const [width, height] = this._windowState.get_value('window-size').deepUnpack(); - - if (width && height) - this.set_default_size(width, height); - - // Maximized State - if (this._windowState.get_boolean('window-maximized')) - this.maximize(); -}; - -Gtk.Window.prototype.saveGeometry = function () { - const state = this.get_window().get_state(); - - // Maximized State - const maximized = (state & Gdk.WindowState.MAXIMIZED); - this._windowState.set_boolean('window-maximized', maximized); - - // Leave the size at the value before maximizing - if (maximized || (state & Gdk.WindowState.FULLSCREEN)) - return; - - // Size - const size = this.get_size(); - this._windowState.set_value('window-size', new GLib.Variant('(ii)', size)); -}; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/contacts.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/contacts.js deleted file mode 100644 index 93467c8..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/contacts.js +++ /dev/null @@ -1,638 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const GdkPixbuf = imports.gi.GdkPixbuf; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - - -/** - * Return a random color - * - * @param {*} [salt] - If not %null, will be used as salt for generating a color - * @param {number} alpha - A value in the [0...1] range for the alpha channel - * @return {Gdk.RGBA} A new Gdk.RGBA object generated from the input - */ -function randomRGBA(salt = null, alpha = 1.0) { - let red, green, blue; - - if (salt !== null) { - const hash = new GLib.Variant('s', `${salt}`).hash(); - red = ((hash & 0xFF0000) >> 16) / 255; - green = ((hash & 0x00FF00) >> 8) / 255; - blue = (hash & 0x0000FF) / 255; - } else { - red = Math.random(); - green = Math.random(); - blue = Math.random(); - } - - return new Gdk.RGBA({red: red, green: green, blue: blue, alpha: alpha}); -} - - -/** - * Get the relative luminance of a RGB set - * See: https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef - * - * @param {Gdk.RGBA} rgba - A GdkRGBA object - * @return {number} The relative luminance of the color - */ -function relativeLuminance(rgba) { - const {red, green, blue} = rgba; - - const R = (red > 0.03928) ? red / 12.92 : Math.pow(((red + 0.055) / 1.055), 2.4); - const G = (green > 0.03928) ? green / 12.92 : Math.pow(((green + 0.055) / 1.055), 2.4); - const B = (blue > 0.03928) ? blue / 12.92 : Math.pow(((blue + 0.055) / 1.055), 2.4); - - return 0.2126 * R + 0.7152 * G + 0.0722 * B; -} - - -/** - * Get a GdkRGBA contrasted for the input - * See: https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef - * - * @param {Gdk.RGBA} rgba - A GdkRGBA object for the background color - * @return {Gdk.RGBA} A GdkRGBA object for the foreground color - */ -function getFgRGBA(rgba) { - const bgLuminance = relativeLuminance(rgba); - const lightContrast = (0.07275541795665634 + 0.05) / (bgLuminance + 0.05); - const darkContrast = (bgLuminance + 0.05) / (0.0046439628482972135 + 0.05); - - const value = (darkContrast > lightContrast) ? 0.06 : 0.94; - return new Gdk.RGBA({red: value, green: value, blue: value, alpha: 0.5}); -} - - -/** - * Get a GdkPixbuf for @path, allowing the corrupt JPEG's KDE Connect sometimes - * sends. This function is synchronous. - * - * @param {string} path - A local file path - * @param {number} size - Size in pixels - * @param {scale} [scale] - Scale factor for the size - * @return {Gdk.Pixbuf} A pixbuf - */ -function getPixbufForPath(path, size, scale = 1.0) { - let data, loader; - - // Catch missing avatar files - try { - data = GLib.file_get_contents(path)[1]; - } catch (e) { - debug(e, path); - return undefined; - } - - // Consider errors from partially corrupt JPEGs to be warnings - try { - loader = new GdkPixbuf.PixbufLoader(); - loader.write(data); - loader.close(); - } catch (e) { - debug(e, path); - } - - const pixbuf = loader.get_pixbuf(); - - // Scale to monitor - size = Math.floor(size * scale); - return pixbuf.scale_simple(size, size, GdkPixbuf.InterpType.HYPER); -} - -function getPixbufForIcon(name, size, scale, bgColor) { - const color = getFgRGBA(bgColor); - const theme = Gtk.IconTheme.get_default(); - const info = theme.lookup_icon_for_scale( - name, - size, - scale, - Gtk.IconLookupFlags.FORCE_SYMBOLIC - ); - - return info.load_symbolic(color, null, null, null)[0]; -} - - -/** - * Return a localized string for a phone number type - * See: http://www.ietf.org/rfc/rfc2426.txt - * - * @param {string} type - An RFC2426 phone number type - * @return {string} A localized string like 'Mobile' - */ -function getNumberTypeLabel(type) { - if (type.includes('fax')) - // TRANSLATORS: A fax number - return _('Fax'); - - if (type.includes('work')) - // TRANSLATORS: A work or office phone number - return _('Work'); - - if (type.includes('cell')) - // TRANSLATORS: A mobile or cellular phone number - return _('Mobile'); - - if (type.includes('home')) - // TRANSLATORS: A home phone number - return _('Home'); - - // TRANSLATORS: All other phone number types - return _('Other'); -} - -/** - * Get a display number from @contact for @address. - * - * @param {Object} contact - A contact object - * @param {string} address - A phone number - * @return {string} A (possibly) better display number for the address - */ -function getDisplayNumber(contact, address) { - const number = address.toPhoneNumber(); - - for (const contactNumber of contact.numbers) { - const cnumber = contactNumber.value.toPhoneNumber(); - - if (number.endsWith(cnumber) || cnumber.endsWith(number)) - return GLib.markup_escape_text(contactNumber.value, -1); - } - - return GLib.markup_escape_text(address, -1); -} - - -/** - * Contact Avatar - */ -const AvatarCache = new WeakMap(); - -var Avatar = GObject.registerClass({ - GTypeName: 'GSConnectContactAvatar', -}, class ContactAvatar extends Gtk.DrawingArea { - - _init(contact = null) { - super._init({ - height_request: 32, - width_request: 32, - valign: Gtk.Align.CENTER, - visible: true, - }); - - this.contact = contact; - } - - get rgba() { - if (this._rgba === undefined) { - if (this.contact) - this._rgba = randomRGBA(this.contact.name); - else - this._rgba = randomRGBA(GLib.uuid_string_random()); - } - - return this._rgba; - } - - get contact() { - if (this._contact === undefined) - this._contact = null; - - return this._contact; - } - - set contact(contact) { - if (this.contact === contact) - return; - - this._contact = contact; - this._surface = undefined; - this._rgba = undefined; - this._offset = 0; - } - - _loadSurface() { - // Get the monitor scale - const display = Gdk.Display.get_default(); - const monitor = display.get_monitor_at_window(this.get_window()); - const scale = monitor.get_scale_factor(); - - // If there's a contact with an avatar, try to load it - if (this.contact && this.contact.avatar) { - // Check the cache - this._surface = AvatarCache.get(this.contact); - - // Try loading the pixbuf - if (!this._surface) { - const pixbuf = getPixbufForPath( - this.contact.avatar, - this.width_request, - scale - ); - - if (pixbuf) { - this._surface = Gdk.cairo_surface_create_from_pixbuf( - pixbuf, - 0, - this.get_window() - ); - AvatarCache.set(this.contact, this._surface); - } - } - } - - // If we still don't have a surface, load a fallback - if (!this._surface) { - let iconName; - - // If we were given a contact, it's direct message otherwise group - if (this.contact) - iconName = 'avatar-default-symbolic'; - else - iconName = 'group-avatar-symbolic'; - - // Center the icon - this._offset = (this.width_request - 24) / 2; - - // Load the fallback - const pixbuf = getPixbufForIcon(iconName, 24, scale, this.rgba); - - this._surface = Gdk.cairo_surface_create_from_pixbuf( - pixbuf, - 0, - this.get_window() - ); - } - } - - vfunc_draw(cr) { - if (!this._surface) - this._loadSurface(); - - // Clip to a circle - const rad = this.width_request / 2; - cr.arc(rad, rad, rad, 0, 2 * Math.PI); - cr.clipPreserve(); - - // Fill the background if the the surface is offset - if (this._offset > 0) { - Gdk.cairo_set_source_rgba(cr, this.rgba); - cr.fill(); - } - - // Draw the avatar/icon - cr.setSourceSurface(this._surface, this._offset, this._offset); - cr.paint(); - - cr.$dispose(); - return Gdk.EVENT_PROPAGATE; - } -}); - - -/** - * A row for a contact address (usually a phone number). - */ -const AddressRow = GObject.registerClass({ - GTypeName: 'GSConnectContactsAddressRow', - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/contacts-address-row.ui', - Children: ['avatar', 'name-label', 'address-label', 'type-label'], -}, class AddressRow extends Gtk.ListBoxRow { - - _init(contact, index = 0) { - super._init(); - - this._index = index; - this._number = contact.numbers[index]; - this.contact = contact; - } - - get contact() { - if (this._contact === undefined) - this._contact = null; - - return this._contact; - } - - set contact(contact) { - if (this.contact === contact) - return; - - this._contact = contact; - - if (this._index === 0) { - this.avatar.contact = contact; - this.avatar.visible = true; - - this.name_label.label = GLib.markup_escape_text(contact.name, -1); - this.name_label.visible = true; - - this.address_label.margin_start = 0; - this.address_label.margin_end = 0; - } else { - this.avatar.visible = false; - this.name_label.visible = false; - - // TODO: rtl inverts margin-start so the number don't align - this.address_label.margin_start = 38; - this.address_label.margin_end = 38; - } - - this.address_label.label = GLib.markup_escape_text(this.number.value, -1); - - if (this.number.type !== undefined) - this.type_label.label = getNumberTypeLabel(this.number.type); - } - - get number() { - if (this._number === undefined) - return {value: 'unknown', type: 'unknown'}; - - return this._number; - } -}); - - -/** - * A widget for selecting contact addresses (usually phone numbers) - */ -var ContactChooser = GObject.registerClass({ - GTypeName: 'GSConnectContactChooser', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device associated with this window', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'store': GObject.ParamSpec.object( - 'store', - 'Store', - 'The contacts store', - GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT, - GObject.Object - ), - }, - Signals: { - 'number-selected': { - flags: GObject.SignalFlags.RUN_FIRST, - param_types: [GObject.TYPE_STRING], - }, - }, - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/contact-chooser.ui', - Children: ['entry', 'list', 'scrolled'], -}, class ContactChooser extends Gtk.Grid { - - _init(params) { - super._init(params); - - // Setup the contact list - this.list._entry = this.entry.text; - this.list.set_filter_func(this._filter); - this.list.set_sort_func(this._sort); - - // Make sure we're using the correct contacts store - this.device.bind_property( - 'contacts', - this, - 'store', - GObject.BindingFlags.SYNC_CREATE - ); - - // Cleanup on ::destroy - this.connect('destroy', this._onDestroy); - } - - get store() { - if (this._store === undefined) - this._store = null; - - return this._store; - } - - set store(store) { - if (this.store === store) - return; - - // Unbind the old store - if (this._store) { - // Disconnect from the store - this._store.disconnect(this._contactAddedId); - this._store.disconnect(this._contactRemovedId); - this._store.disconnect(this._contactChangedId); - - // Clear the contact list - const rows = this.list.get_children(); - - for (let i = 0, len = rows.length; i < len; i++) { - rows[i].destroy(); - // HACK: temporary mitigator for mysterious GtkListBox leak - imports.system.gc(); - } - } - - // Set the store - this._store = store; - - // Bind the new store - if (this._store) { - // Connect to the new store - this._contactAddedId = store.connect( - 'contact-added', - this._onContactAdded.bind(this) - ); - - this._contactRemovedId = store.connect( - 'contact-removed', - this._onContactRemoved.bind(this) - ); - - this._contactChangedId = store.connect( - 'contact-changed', - this._onContactChanged.bind(this) - ); - - // Populate the list - this._populate(); - } - } - - /* - * ContactStore Callbacks - */ - _onContactAdded(store, id) { - const contact = this.store.get_contact(id); - this._addContact(contact); - } - - _onContactRemoved(store, id) { - const rows = this.list.get_children(); - - for (let i = 0, len = rows.length; i < len; i++) { - const row = rows[i]; - - if (row.contact.id === id) { - row.destroy(); - // HACK: temporary mitigator for mysterious GtkListBox leak - imports.system.gc(); - } - } - } - - _onContactChanged(store, id) { - this._onContactRemoved(store, id); - this._onContactAdded(store, id); - } - - _onDestroy(chooser) { - chooser.store = null; - } - - _onSearchChanged(entry) { - this.list._entry = entry.text; - let dynamic = this.list.get_row_at_index(0); - - // If the entry contains string with 2 or more digits... - if (entry.text.replace(/\D/g, '').length >= 2) { - // ...ensure we have a dynamic contact for it - if (!dynamic || !dynamic.__tmp) { - dynamic = new AddressRow({ - // TRANSLATORS: A phone number (eg. "Send to 555-5555") - name: _('Send to %s').format(entry.text), - numbers: [{type: 'unknown', value: entry.text}], - }); - dynamic.__tmp = true; - this.list.add(dynamic); - - // ...or if we already do, then update it - } else { - const address = entry.text; - - // Update contact object - dynamic.contact.name = address; - dynamic.contact.numbers[0].value = address; - - // Update UI - dynamic.name_label.label = _('Send to %s').format(address); - dynamic.address_label.label = address; - } - - // ...otherwise remove any dynamic contact that's been created - } else if (dynamic && dynamic.__tmp) { - dynamic.destroy(); - } - - this.list.invalidate_filter(); - this.list.invalidate_sort(); - } - - // GtkListBox::row-activated - _onNumberSelected(box, row) { - if (row === null) - return; - - // Emit the number - const address = row.number.value; - this.emit('number-selected', address); - - // Reset the contact list - this.entry.text = ''; - this.list.select_row(null); - this.scrolled.vadjustment.value = 0; - } - - _filter(row) { - // Dynamic contact always shown - if (row.__tmp) - return true; - - const query = row.get_parent()._entry; - - // Show contact if text is substring of name - const queryName = query.toLocaleLowerCase(); - - if (row.contact.name.toLocaleLowerCase().includes(queryName)) - return true; - - // Show contact if text is substring of number - const queryNumber = query.toPhoneNumber(); - - if (queryNumber.length) { - for (const number of row.contact.numbers) { - if (number.value.toPhoneNumber().includes(queryNumber)) - return true; - } - - // Query is effectively empty - } else if (/^0+/.test(query)) { - return true; - } - - return false; - } - - _sort(row1, row2) { - if (row1.__tmp) - return -1; - - if (row2.__tmp) - return 1; - - return row1.contact.name.localeCompare(row2.contact.name); - } - - _populate() { - // Add each contact - const contacts = this.store.contacts; - - for (let i = 0, len = contacts.length; i < len; i++) - this._addContact(contacts[i]); - } - - _addContactNumber(contact, index) { - const row = new AddressRow(contact, index); - this.list.add(row); - - return row; - } - - _addContact(contact) { - try { - // HACK: fix missing contact names - if (contact.name === undefined) - contact.name = _('Unknown Contact'); - - if (contact.numbers.length === 1) - return this._addContactNumber(contact, 0); - - for (let i = 0, len = contact.numbers.length; i < len; i++) - this._addContactNumber(contact, i); - } catch (e) { - logError(e); - } - } - - /** - * Get a dictionary of number-contact pairs for each selected phone number. - * - * @return {Object[]} A dictionary of contacts - */ - getSelected() { - try { - const selected = {}; - - for (const row of this.list.get_selected_rows()) - selected[row.number.value] = row.contact; - - return selected; - } catch (e) { - logError(e); - return {}; - } - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/legacyMessaging.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/legacyMessaging.js deleted file mode 100644 index 91cfb24..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/legacyMessaging.js +++ /dev/null @@ -1,223 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const Contacts = imports.service.ui.contacts; -const Messaging = imports.service.ui.messaging; -const URI = imports.service.utils.uri; - - -var Dialog = GObject.registerClass({ - GTypeName: 'GSConnectLegacyMessagingDialog', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device associated with this window', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'plugin': GObject.ParamSpec.object( - 'plugin', - 'Plugin', - 'The plugin providing messages', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - }, - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/legacy-messaging-dialog.ui', - Children: [ - 'infobar', 'stack', - 'message-box', 'message-avatar', 'message-label', 'entry', - ], -}, class Dialog extends Gtk.Dialog { - - _init(params) { - super._init({ - application: Gio.Application.get_default(), - device: params.device, - plugin: params.plugin, - use_header_bar: true, - }); - - this.set_response_sensitive(Gtk.ResponseType.OK, false); - - // Dup some functions - this.headerbar = this.get_titlebar(); - this._setHeaderBar = Messaging.Window.prototype._setHeaderBar; - - // Info bar - this.device.bind_property( - 'connected', - this.infobar, - 'reveal-child', - GObject.BindingFlags.INVERT_BOOLEAN - ); - - // Message Entry/Send Button - this.device.bind_property( - 'connected', - this.entry, - 'sensitive', - GObject.BindingFlags.DEFAULT - ); - - this._connectedId = this.device.connect( - 'notify::connected', - this._onStateChanged.bind(this) - ); - - this._entryChangedId = this.entry.buffer.connect( - 'changed', - this._onStateChanged.bind(this) - ); - - // Set the message if given - if (params.message) { - this.message = params.message; - this.addresses = params.message.addresses; - - this.message_avatar.contact = this.device.contacts.query({ - number: this.addresses[0].address, - }); - this.message_label.label = URI.linkify(this.message.body); - this.message_box.visible = true; - - // Otherwise set the address(es) if we were passed those - } else if (params.addresses) { - this.addresses = params.addresses; - } - - // Load the contact list if we weren't supplied with an address - if (this.addresses.length === 0) { - this.contact_chooser = new Contacts.ContactChooser({ - device: this.device, - }); - this.stack.add_named(this.contact_chooser, 'contact-chooser'); - this.stack.child_set_property(this.contact_chooser, 'position', 0); - - this._numberSelectedId = this.contact_chooser.connect( - 'number-selected', - this._onNumberSelected.bind(this) - ); - - this.stack.visible_child_name = 'contact-chooser'; - } - - this.restoreGeometry('legacy-messaging-dialog'); - - this.connect('destroy', this._onDestroy); - } - - _onDestroy(dialog) { - if (dialog._numberSelectedId !== undefined) { - dialog.contact_chooser.disconnect(dialog._numberSelectedId); - dialog.contact_chooser.destroy(); - } - - dialog.entry.buffer.disconnect(dialog._entryChangedId); - dialog.device.disconnect(dialog._connectedId); - } - - vfunc_delete_event() { - this.saveGeometry(); - - return false; - } - - vfunc_response(response_id) { - if (response_id === Gtk.ResponseType.OK) { - // Refuse to send empty or whitespace only texts - if (!this.entry.buffer.text.trim()) - return; - - this.plugin.sendMessage( - this.addresses, - this.entry.buffer.text, - 1, - true - ); - } - - this.destroy(); - } - - get addresses() { - if (this._addresses === undefined) - this._addresses = []; - - return this._addresses; - } - - set addresses(addresses = []) { - this._addresses = addresses; - - // Set the headerbar - this._setHeaderBar(this._addresses); - - // Show the message editor - this.stack.visible_child_name = 'message-editor'; - this._onStateChanged(); - } - - get device() { - if (this._device === undefined) - this._device = null; - - return this._device; - } - - set device(device) { - this._device = device; - } - - get plugin() { - if (this._plugin === undefined) - this._plugin = null; - - return this._plugin; - } - - set plugin(plugin) { - this._plugin = plugin; - } - - _onActivateLink(label, uri) { - Gtk.show_uri_on_window( - this.get_toplevel(), - uri.includes('://') ? uri : `https://${uri}`, - Gtk.get_current_event_time() - ); - - return true; - } - - _onNumberSelected(chooser, number) { - const contacts = chooser.getSelected(); - - this.addresses = Object.keys(contacts).map(address => { - return {address: address}; - }); - } - - _onStateChanged() { - if (this.device.connected && - this.entry.buffer.text.trim() && - this.stack.visible_child_name === 'message-editor') - this.set_response_sensitive(Gtk.ResponseType.OK, true); - else - this.set_response_sensitive(Gtk.ResponseType.OK, false); - } - - /** - * Set the contents of the message entry - * - * @param {string} text - The message to place in the entry - */ - setMessage(text) { - this.entry.buffer.text = text; - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/messaging.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/messaging.js deleted file mode 100644 index 40a91ae..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/messaging.js +++ /dev/null @@ -1,1312 +0,0 @@ -'use strict'; - -const Tweener = imports.tweener.tweener; - -const Gdk = imports.gi.Gdk; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; -const Pango = imports.gi.Pango; - -const Contacts = imports.service.ui.contacts; -const Sms = imports.service.plugins.sms; -const URI = imports.service.utils.uri; - - -/* - * Useful time constants - */ -const TIME_SPAN_MINUTE = 60000; -const TIME_SPAN_HOUR = 3600000; -const TIME_SPAN_DAY = 86400000; -const TIME_SPAN_WEEK = 604800000; - - -// Less than an hour (eg. 42 minutes ago) -const _lthLong = new Intl.RelativeTimeFormat('default', { - numeric: 'auto', - style: 'long', -}); - -// Less than a day ago (eg. 11:42 PM) -const _ltdFormat = new Intl.DateTimeFormat('default', { - hour: 'numeric', - minute: 'numeric', -}); - -// Less than a week ago (eg. Monday) -const _ltwLong = new Intl.DateTimeFormat('default', { - weekday: 'long', -}); - -// Less than a week ago (eg. Mon) -const _ltwShort = new Intl.DateTimeFormat('default', { - weekday: 'short', -}); - -// Less than a year (eg. Oct 31) -const _ltyShort = new Intl.DateTimeFormat('default', { - day: 'numeric', - month: 'short', -}); - -// Less than a year (eg. October 31) -const _ltyLong = new Intl.DateTimeFormat('default', { - day: 'numeric', - month: 'long', -}); - -// Greater than a year (eg. October 31, 2019) -const _gtyLong = new Intl.DateTimeFormat('default', { - day: 'numeric', - month: 'long', - year: 'numeric', -}); - -// Greater than a year (eg. 10/31/2019) -const _gtyShort = new Intl.DateTimeFormat('default', { - day: 'numeric', - month: 'numeric', - year: 'numeric', -}); - -// Pretty close to strftime's %c -const _cFormat = new Intl.DateTimeFormat('default', { - year: 'numeric', - month: 'short', - day: 'numeric', - weekday: 'short', - hour: 'numeric', - minute: 'numeric', - second: 'numeric', - timeZoneName: 'short', -}); - - -/** - * Return a human-readable timestamp, formatted for longer contexts. - * - * @param {number} time - Milliseconds since the epoch (local time) - * @return {string} A localized timestamp similar to what Android Messages uses - */ -function getTime(time) { - const date = new Date(time); - const now = new Date(); - const diff = now - time; - - // Super recent - if (diff < TIME_SPAN_MINUTE) - // TRANSLATORS: Less than a minute ago - return _('Just now'); - - // Under an hour (TODO: these labels aren't updated) - if (diff < TIME_SPAN_HOUR) - return _lthLong.format(-Math.floor(diff / TIME_SPAN_MINUTE), 'minute'); - - // Yesterday, but less than 24 hours ago - if (diff < TIME_SPAN_DAY && now.getDay() !== date.getDay()) - // TRANSLATORS: Yesterday, but less than 24 hours (eg. Yesterday · 11:29 PM) - return _('Yesterday・%s').format(_ltdFormat.format(time)); - - // Less than a day ago - if (diff < TIME_SPAN_DAY) - return _ltdFormat.format(time); - - // Less than a week ago - if (diff < TIME_SPAN_WEEK) - return _ltwLong.format(time); - - // Sometime this year - if (date.getFullYear() === now.getFullYear()) - return _ltyLong.format(time); - - // Earlier than that - return _gtyLong.format(time); -} - - -/** - * Return a human-readable timestamp, formatted for shorter contexts. - * - * @param {number} time - Milliseconds since the epoch (local time) - * @return {string} A localized timestamp similar to what Android Messages uses - */ -function getShortTime(time) { - const date = new Date(time); - const now = new Date(); - const diff = now - time; - - if (diff < TIME_SPAN_MINUTE) - // TRANSLATORS: Less than a minute ago - return _('Just now'); - - if (diff < TIME_SPAN_HOUR) { - // TRANSLATORS: Time duration in minutes (eg. 15 minutes) - return ngettext( - '%d minute', - '%d minutes', - (diff / TIME_SPAN_MINUTE) - ).format(diff / TIME_SPAN_MINUTE); - } - - // Less than a day ago - if (diff < TIME_SPAN_DAY) - return _ltdFormat.format(time); - - // Less than a week ago - if (diff < TIME_SPAN_WEEK) - return _ltwShort.format(time); - - // Sometime this year - if (date.getFullYear() === now.getFullYear()) - return _ltyShort.format(time); - - // Earlier than that - return _gtyShort.format(time); -} - - -/** - * Return a human-readable timestamp, similar to `strftime()` with `%c`. - * - * @param {number} time - Milliseconds since the epoch (local time) - * @return {string} A localized timestamp - */ -function getDetailedTime(time) { - return _cFormat.format(time); -} - - -function setAvatarVisible(row, visible) { - const incoming = row.message.type === Sms.MessageBox.INBOX; - - // Adjust the margins - if (visible) { - row.grid.margin_start = incoming ? 6 : 56; - row.grid.margin_bottom = 6; - } else { - row.grid.margin_start = incoming ? 44 : 56; - row.grid.margin_bottom = 0; - } - - // Show hide the avatar - if (incoming) - row.avatar.visible = visible; -} - - -/** - * A ListBoxRow for a preview of a conversation - */ -const ConversationMessage = GObject.registerClass({ - GTypeName: 'GSConnectMessagingConversationMessage', - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/messaging-conversation-message.ui', - Children: ['grid', 'avatar', 'sender-label', 'message-label'], -}, class ConversationMessage extends Gtk.ListBoxRow { - _init(contact, message) { - super._init(); - - this.contact = contact; - this.message = message; - - // Sort properties - this.sender = message.addresses[0].address || 'unknown'; - this.message_label.label = URI.linkify(message.body); - this.message_label.tooltip_text = getDetailedTime(message.date); - - // Add avatar for incoming messages - if (message.type === Sms.MessageBox.INBOX) { - this.grid.margin_end = 18; - this.grid.halign = Gtk.Align.START; - - this.avatar.contact = this.contact; - this.avatar.visible = true; - - this.sender_label.label = contact.name; - this.sender_label.visible = true; - - this.message_label.get_style_context().add_class('message-in'); - this.message_label.halign = Gtk.Align.START; - } else { - this.message_label.get_style_context().add_class('message-out'); - } - } - - _onActivateLink(label, uri) { - Gtk.show_uri_on_window( - this.get_toplevel(), - uri.includes('://') ? uri : `https://${uri}`, - Gtk.get_current_event_time() - ); - - return true; - } - - get date() { - return this._message.date; - } - - get thread_id() { - return this._message.thread_id; - } - - get message() { - if (this._message === undefined) - this._message = null; - - return this._message; - } - - set message(message) { - this._message = message; - } -}); - - -/** - * A widget for displaying a conversation thread, with an entry for responding. - */ -const Conversation = GObject.registerClass({ - GTypeName: 'GSConnectMessagingConversation', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device associated with this conversation', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'plugin': GObject.ParamSpec.object( - 'plugin', - 'Plugin', - 'The plugin providing this conversation', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'has-pending': GObject.ParamSpec.boolean( - 'has-pending', - 'Has Pending', - 'Whether there are sent messages pending confirmation', - GObject.ParamFlags.READABLE, - false - ), - 'thread-id': GObject.ParamSpec.string( - 'thread-id', - 'Thread ID', - 'The current thread', - GObject.ParamFlags.READWRITE, - '' - ), - }, - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/messaging-conversation.ui', - Children: [ - 'entry', 'list', 'scrolled', - 'pending', 'pending-box', - ], -}, class MessagingConversation extends Gtk.Grid { - - _init(params) { - super._init({ - device: params.device, - plugin: params.plugin, - }); - Object.assign(this, params); - - this.device.bind_property( - 'connected', - this.entry, - 'sensitive', - GObject.BindingFlags.SYNC_CREATE - ); - - // If we're disconnected pending messages might not succeed, but we'll - // leave them until reconnect when we'll ask for an update - this._connectedId = this.device.connect( - 'notify::connected', - this._onConnected.bind(this) - ); - - // Pending messages - this.pending.message = { - date: Number.MAX_SAFE_INTEGER, - type: Sms.MessageBox.OUTBOX, - }; - - // Auto-scrolling - this._vadj = this.scrolled.get_vadjustment(); - this._scrolledId = this._vadj.connect( - 'value-changed', - this._holdPosition.bind(this) - ); - - // Message List - this.list.set_header_func(this._headerMessages); - this.list.set_sort_func(this._sortMessages); - this._populateMessages(); - - // Cleanup on ::destroy - this.connect('destroy', this._onDestroy); - } - - get addresses() { - if (this._addresses === undefined) - this._addresses = []; - - return this._addresses; - } - - set addresses(addresses) { - if (!addresses || addresses.length === 0) { - this._addresses = []; - this._contacts = {}; - return; - } - - // Lookup a contact for each address object, then loop back to correct - // each address carried by the message. - this._addresses = addresses; - - for (let i = 0, len = this.addresses.length; i < len; i++) { - // Lookup the contact - const address = this.addresses[i].address; - const contact = this.device.contacts.query({number: address}); - - // Get corrected address - let number = address.toPhoneNumber(); - - for (const contactNumber of contact.numbers) { - const cnumber = contactNumber.value.toPhoneNumber(); - - if (number.endsWith(cnumber) || cnumber.endsWith(number)) { - number = contactNumber.value; - break; - } - } - - // Store the final result - this.addresses[i].address = number; - this.contacts[address] = contact; - } - - // TODO: Mark the entry as insensitive for group messages - if (this.addresses.length > 1) { - this.entry.placeholder_text = _('Not available'); - this.entry.secondary_icon_name = null; - this.entry.secondary_icon_tooltip_text = null; - this.entry.sensitive = false; - this.entry.tooltip_text = null; - } - } - - get contacts() { - if (this._contacts === undefined) - this._contacts = {}; - - return this._contacts; - } - - get has_pending() { - if (this.pending_box === undefined) - return false; - - return (this.pending_box.get_children().length > 0); - } - - get plugin() { - if (this._plugin === undefined) - this._plugin = null; - - return this._plugin; - } - - set plugin(plugin) { - this._plugin = plugin; - } - - get thread_id() { - if (this._thread_id === undefined) - this._thread_id = null; - - return this._thread_id; - } - - set thread_id(thread_id) { - const thread = this.plugin.threads[thread_id]; - const message = (thread) ? thread[0] : null; - - if (message && this.addresses.length === 0) { - this.addresses = message.addresses; - this._thread_id = thread_id; - } - } - - _onConnected(device) { - if (device.connected) - this.pending_box.foreach(msg => msg.destroy()); - } - - _onDestroy(conversation) { - conversation.device.disconnect(conversation._connectedId); - conversation._vadj.disconnect(conversation._scrolledId); - - conversation.list.foreach(message => { - // HACK: temporary mitigator for mysterious GtkListBox leak - message.destroy(); - imports.system.gc(); - }); - } - - _onEdgeReached(scrolled_window, pos) { - // Try to load more messages - if (pos === Gtk.PositionType.TOP) - this.logPrevious(); - - // Release any hold to resume auto-scrolling - else if (pos === Gtk.PositionType.BOTTOM) - this._releasePosition(); - } - - _onEntryChanged(entry) { - entry.secondary_icon_sensitive = (entry.text.length); - } - - _onKeyPressEvent(entry, event) { - const keyval = event.get_keyval()[1]; - const state = event.get_state()[1]; - const mask = state & Gtk.accelerator_get_default_mod_mask(); - - if (keyval === Gdk.KEY_Return && (mask & Gdk.ModifierType.SHIFT_MASK)) { - entry.emit('insert-at-cursor', '\n'); - return true; - } - - return false; - } - - _onSendMessage(entry, signal_id, event) { - // Don't send empty texts - if (!this.entry.text.trim()) - return; - - // Send the message - this.plugin.sendMessage(this.addresses, this.entry.text); - - // Add a phony message in the pending box - const message = new Gtk.Label({ - label: URI.linkify(this.entry.text), - halign: Gtk.Align.END, - selectable: true, - use_markup: true, - visible: true, - wrap: true, - wrap_mode: Pango.WrapMode.WORD_CHAR, - xalign: 0, - }); - message.get_style_context().add_class('message-out'); - message.date = Date.now(); - message.type = Sms.MessageBox.SENT; - - // Notify to reveal the pending box - this.pending_box.add(message); - this.notify('has-pending'); - - // Clear the entry - this.entry.text = ''; - } - - _onSizeAllocate(listbox, allocation) { - const upper = this._vadj.get_upper(); - const pageSize = this._vadj.get_page_size(); - - // If the scrolled window hasn't been filled yet, load another message - if (upper <= pageSize) { - this.logPrevious(); - this.scrolled.get_child().check_resize(); - - // We've been asked to hold the position, so we'll reset the adjustment - // value and update the hold position - } else if (this.__pos) { - this._vadj.set_value(upper - this.__pos); - - // Otherwise we probably appended a message and should scroll to it - } else { - this._scrollPosition(Gtk.PositionType.BOTTOM); - } - } - - /** - * Create a message row, ensuring a contact object has been retrieved or - * generated for the message. - * - * @param {Object} message - A dictionary of message data - * @return {ConversationMessage} A message row - */ - _createMessageRow(message) { - // Ensure we have a contact - const sender = message.addresses[0].address || 'unknown'; - - if (this.contacts[sender] === undefined) { - this.contacts[sender] = this.device.contacts.query({ - number: sender, - }); - } - - return new ConversationMessage(this.contacts[sender], message); - } - - _populateMessages() { - this.__first = null; - this.__last = null; - this.__pos = 0; - this.__messages = []; - - // Try and find a thread_id for this number - if (this.thread_id === null && this.addresses.length) - this._thread_id = this.plugin.getThreadIdForAddresses(this.addresses); - - // Make a copy of the thread and fill the window with messages - if (this.plugin.threads[this.thread_id]) { - this.__messages = this.plugin.threads[this.thread_id].slice(0); - this.logPrevious(); - } - } - - _headerMessages(row, before) { - // Skip pending - if (row.get_name() === 'pending') - return; - - if (before === null) - return setAvatarVisible(row, true); - - // Add date header if the last message was more than an hour ago - let header = row.get_header(); - - if ((row.message.date - before.message.date) > TIME_SPAN_HOUR) { - if (!header) { - header = new Gtk.Label({visible: true, selectable: true}); - header.get_style_context().add_class('dim-label'); - row.set_header(header); - } - - header.label = getTime(row.message.date); - - // Also show the avatar - setAvatarVisible(row, true); - - row.sender_label.visible = row.message.addresses.length > 1; - - // Or if the previous sender was the same, hide its avatar - } else if (row.message.type === before.message.type && - row.sender.equalsPhoneNumber(before.sender)) { - setAvatarVisible(before, false); - setAvatarVisible(row, true); - - row.sender_label.visible = false; - - // otherwise show the avatar - } else { - setAvatarVisible(row, true); - } - } - - _holdPosition() { - this.__pos = this._vadj.get_upper() - this._vadj.get_value(); - } - - _releasePosition() { - this.__pos = 0; - } - - _scrollPosition(pos = Gtk.PositionType.BOTTOM, animate = true) { - let vpos = pos; - this._vadj.freeze_notify(); - - if (pos === Gtk.PositionType.BOTTOM) - vpos = this._vadj.get_upper() - this._vadj.get_page_size(); - - if (animate) { - Tweener.addTween(this._vadj, { - value: vpos, - time: 0.5, - transition: 'easeInOutCubic', - onComplete: () => this._vadj.thaw_notify(), - }); - } else { - GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { - this._vadj.set_value(vpos); - this._vadj.thaw_notify(); - }); - } - } - - _sortMessages(row1, row2) { - return (row1.message.date > row2.message.date) ? 1 : -1; - } - - /** - * Log the next message in the conversation. - * - * @param {Object} message - A message object - */ - logNext(message) { - try { - // TODO: Unsupported MessageBox - if (message.type !== Sms.MessageBox.INBOX && - message.type !== Sms.MessageBox.SENT) - throw TypeError(`invalid message box ${message.type}`); - - // Append the message - const row = this._createMessageRow(message); - this.list.add(row); - this.list.invalidate_headers(); - - // Remove the first pending message - if (this.has_pending && message.type === Sms.MessageBox.SENT) { - this.pending_box.get_children()[0].destroy(); - this.notify('has-pending'); - } - } catch (e) { - debug(e); - } - } - - /** - * Log the previous message in the thread - */ - logPrevious() { - try { - const message = this.__messages.pop(); - - if (!message) - return; - - // TODO: Unsupported MessageBox - if (message.type !== Sms.MessageBox.INBOX && - message.type !== Sms.MessageBox.SENT) - throw TypeError(`invalid message box ${message.type}`); - - // Prepend the message - const row = this._createMessageRow(message); - this.list.prepend(row); - this.list.invalidate_headers(); - } catch (e) { - debug(e); - } - } - - /** - * Set the contents of the message entry - * - * @param {string} text - The message to place in the entry - */ - setMessage(text) { - this.entry.text = text; - this.entry.emit('move-cursor', 0, text.length, false); - } -}); - - -/** - * A ListBoxRow for a preview of a conversation - */ -const ConversationSummary = GObject.registerClass({ - GTypeName: 'GSConnectMessagingConversationSummary', - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/messaging-conversation-summary.ui', - Children: ['avatar', 'name-label', 'time-label', 'body-label'], -}, class ConversationSummary extends Gtk.ListBoxRow { - _init(contacts, message) { - super._init(); - - this.contacts = contacts; - this.message = message; - } - - get date() { - return this._message.date; - } - - get thread_id() { - return this._message.thread_id; - } - - get message() { - return this._message; - } - - set message(message) { - this._message = message; - this._sender = message.addresses[0].address || 'unknown'; - - // Contact Name - let nameLabel = _('Unknown Contact'); - - // Update avatar for single-recipient messages - if (message.addresses.length === 1) { - this.avatar.contact = this.contacts[this._sender]; - nameLabel = GLib.markup_escape_text(this.avatar.contact.name, -1); - } else { - this.avatar.contact = null; - nameLabel = _('Group Message'); - const participants = []; - message.addresses.forEach((address) => { - participants.push(this.contacts[address.address].name); - }); - this.name_label.tooltip_text = participants.join(', '); - } - - // Contact Name & Message body - let bodyLabel = message.body.split(/\r|\n/)[0]; - bodyLabel = GLib.markup_escape_text(bodyLabel, -1); - - // Ignore the 'read' flag if it's an outgoing message - if (message.type === Sms.MessageBox.SENT) { - // TRANSLATORS: An outgoing message body in a conversation summary - bodyLabel = _('You: %s').format(bodyLabel); - - // Otherwise make it bold if it's unread - } else if (message.read === Sms.MessageStatus.UNREAD) { - nameLabel = `<b>${nameLabel}</b>`; - bodyLabel = `<b>${bodyLabel}</b>`; - } - - // Set the labels, body always smaller - this.name_label.label = nameLabel; - this.body_label.label = `<small>${bodyLabel}</small>`; - - // Time - const timeLabel = `<small>${getShortTime(message.date)}</small>`; - this.time_label.label = timeLabel; - } - - /** - * Update the relative time label. - */ - update() { - const timeLabel = `<small>${getShortTime(this.message.date)}</small>`; - this.time_label.label = timeLabel; - } -}); - - -/** - * A Gtk.ApplicationWindow for SMS conversations - */ -var Window = GObject.registerClass({ - GTypeName: 'GSConnectMessagingWindow', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device associated with this window', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'plugin': GObject.ParamSpec.object( - 'plugin', - 'Plugin', - 'The plugin providing messages', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'thread-id': GObject.ParamSpec.string( - 'thread-id', - 'Thread ID', - 'The current thread', - GObject.ParamFlags.READWRITE, - '' - ), - }, - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/messaging-window.ui', - Children: [ - 'headerbar', 'infobar', - 'thread-list', 'stack', - ], -}, class MessagingWindow extends Gtk.ApplicationWindow { - - _init(params) { - super._init(params); - this.headerbar.subtitle = this.device.name; - - this.insert_action_group('device', this.device); - - // Device Status - this.device.bind_property( - 'connected', - this.infobar, - 'reveal-child', - GObject.BindingFlags.INVERT_BOOLEAN - ); - - // Contacts - this.contact_chooser = new Contacts.ContactChooser({ - device: this.device, - }); - this.stack.add_named(this.contact_chooser, 'contact-chooser'); - - this._numberSelectedId = this.contact_chooser.connect( - 'number-selected', - this._onNumberSelected.bind(this) - ); - - // Threads - this.thread_list.set_sort_func(this._sortThreads); - - this._threadsChangedId = this.plugin.connect( - 'notify::threads', - this._onThreadsChanged.bind(this) - ); - - this._timestampThreadsId = GLib.timeout_add_seconds( - GLib.PRIORITY_DEFAULT_IDLE, - 60, - this._timestampThreads.bind(this) - ); - - this._sync(); - this._onThreadsChanged(); - this.restoreGeometry('messaging'); - } - - vfunc_delete_event(event) { - this.saveGeometry(); - - GLib.source_remove(this._timestampThreadsId); - this.contact_chooser.disconnect(this._numberSelectedId); - this.plugin.disconnect(this._threadsChangedId); - - return false; - } - - get plugin() { - return this._plugin || null; - } - - set plugin(plugin) { - this._plugin = plugin; - } - - get thread_id() { - return this.stack.visible_child_name; - } - - set thread_id(thread_id) { - thread_id = `${thread_id}`; // FIXME - - // Reset to the empty placeholder - if (!thread_id) { - this.thread_list.select_row(null); - this.stack.set_visible_child_name('placeholder'); - return; - } - - // Create a conversation widget if there isn't one - let conversation = this.stack.get_child_by_name(thread_id); - const thread = this.plugin.threads[thread_id]; - - if (conversation === null) { - if (!thread) { - debug(`Thread ID ${thread_id} not found`); - return; - } - - conversation = new Conversation({ - device: this.device, - plugin: this.plugin, - thread_id: thread_id, - }); - - this.stack.add_named(conversation, thread_id); - } - - // Figure out whether this is a multi-recipient thread - this._setHeaderBar(thread[0].addresses); - - // Select the conversation and entry active - this.stack.visible_child = conversation; - this.stack.visible_child.entry.has_focus = true; - - // There was a pending message waiting for a conversation to be chosen - if (this._pendingShare) { - conversation.setMessage(this._pendingShare); - this._pendingShare = null; - } - - this._thread_id = thread_id; - this.notify('thread_id'); - } - - _setHeaderBar(addresses = []) { - const address = addresses[0].address; - const contact = this.device.contacts.query({number: address}); - - if (addresses.length === 1) { - this.headerbar.title = contact.name; - this.headerbar.subtitle = Contacts.getDisplayNumber(contact, address); - } else { - const otherLength = addresses.length - 1; - - this.headerbar.title = contact.name; - this.headerbar.subtitle = ngettext( - 'And %d other contact', - 'And %d others', - otherLength - ).format(otherLength); - } - } - - _sync() { - this.device.contacts.fetch(); - this.plugin.connected(); - } - - _onNewConversation() { - this._sync(); - this.stack.set_visible_child_name('contact-chooser'); - this.thread_list.select_row(null); - this.contact_chooser.entry.has_focus = true; - } - - _onNumberSelected(chooser, number) { - const contacts = chooser.getSelected(); - const row = this._getRowForContacts(contacts); - - if (row) - row.emit('activate'); - else - this.setContacts(contacts); - } - - /** - * Threads - */ - _onThreadsChanged() { - // Get the last message in each thread - const messages = {}; - - for (const [thread_id, thread] of Object.entries(this.plugin.threads)) { - const message = thread[thread.length - 1]; - - // Skip messages without a body (eg. MMS messages without text) - if (message.body) - messages[thread_id] = thread[thread.length - 1]; - } - - // Update existing summaries and destroy old ones - for (const row of this.thread_list.get_children()) { - const message = messages[row.thread_id]; - - // If it's an existing conversation, update it - if (message) { - // Ensure there's a contact mapping - const sender = message.addresses[0].address || 'unknown'; - - if (row.contacts[sender] === undefined) { - row.contacts[sender] = this.device.contacts.query({ - number: sender, - }); - } - - row.message = message; - delete messages[row.thread_id]; - - // Otherwise destroy it - } else { - // Destroy the conversation widget - const conversation = this.stack.get_child_by_name(`${row.thread_id}`); - - if (conversation) { - conversation.destroy(); - imports.system.gc(); - } - - // Then the summary widget - row.destroy(); - // HACK: temporary mitigator for mysterious GtkListBox leak - imports.system.gc(); - } - } - - // What's left in the dictionary is new summaries - for (const message of Object.values(messages)) { - const contacts = this.device.contacts.lookupAddresses(message.addresses); - const conversation = new ConversationSummary(contacts, message); - this.thread_list.add(conversation); - } - - // Re-sort the summaries - this.thread_list.invalidate_sort(); - } - - // GtkListBox::row-activated - _onThreadSelected(box, row) { - // Show the conversation for this number (if applicable) - if (row) { - this.thread_id = row.thread_id; - - // Show the placeholder - } else { - this.headerbar.title = _('Messaging'); - this.headerbar.subtitle = this.device.name; - } - } - - _sortThreads(row1, row2) { - return (row1.date > row2.date) ? -1 : 1; - } - - _timestampThreads() { - if (this.visible) - this.thread_list.foreach(row => row.update()); - - return GLib.SOURCE_CONTINUE; - } - - /** - * Find the thread row for @contacts - * - * @param {Object[]} contacts - A contact group - * @return {ConversationSummary|null} The thread row or %null - */ - _getRowForContacts(contacts) { - const addresses = Object.keys(contacts).map(address => { - return {address: address}; - }); - - // Try to find a thread_id - const thread_id = this.plugin.getThreadIdForAddresses(addresses); - - for (const row of this.thread_list.get_children()) { - if (row.message.thread_id === thread_id) - return row; - } - - return null; - } - - setContacts(contacts) { - // Group the addresses - const addresses = []; - - for (const address of Object.keys(contacts)) - addresses.push({address: address}); - - // Try to find a thread ID for this address group - let thread_id = this.plugin.getThreadIdForAddresses(addresses); - - if (thread_id === null) - thread_id = GLib.uuid_string_random(); - else - thread_id = thread_id.toString(); - - // Try to find a thread row for the ID - const row = this._getRowForContacts(contacts); - - if (row !== null) { - this.thread_list.select_row(row); - return; - } - - // We're creating a new conversation - const conversation = new Conversation({ - device: this.device, - plugin: this.plugin, - addresses: addresses, - }); - - // Set the headerbar - this._setHeaderBar(addresses); - - // Select the conversation and entry active - this.stack.add_named(conversation, thread_id); - this.stack.visible_child = conversation; - this.stack.visible_child.entry.has_focus = true; - - // There was a pending message waiting for a conversation to be chosen - if (this._pendingShare) { - conversation.setMessage(this._pendingShare); - this._pendingShare = null; - } - - this._thread_id = thread_id; - this.notify('thread-id'); - } - - _includesAddress(addresses, addressObj) { - const number = addressObj.address.toPhoneNumber(); - - for (const haystackObj of addresses) { - const tnumber = haystackObj.address.toPhoneNumber(); - - if (number.endsWith(tnumber) || tnumber.endsWith(number)) - return true; - } - - return false; - } - - /** - * Try and find an existing conversation widget for @message. - * - * @param {Object} message - A message object - * @return {Conversation|null} A conversation widget or %null - */ - getConversationForMessage(message) { - // TODO: This shouldn't happen? - if (message === null) - return null; - - // First try to find a conversation by thread_id - const thread_id = `${message.thread_id}`; - const conversation = this.stack.get_child_by_name(thread_id); - - if (conversation !== null) - return conversation; - - // Try and find one by matching addresses, which is necessary if we've - // started a thread locally and haven't set the thread_id - const addresses = message.addresses; - - for (const conversation of this.stack.get_children()) { - if (conversation.addresses === undefined || - conversation.addresses.length !== addresses.length) - continue; - - const caddrs = conversation.addresses; - - // If we find a match, set `thread-id` on the conversation and the - // child property `name`. - if (addresses.every(addr => this._includesAddress(caddrs, addr))) { - conversation._thread_id = thread_id; - this.stack.child_set_property(conversation, 'name', thread_id); - - return conversation; - } - } - - return null; - } - - /** - * Set the contents of the message entry. If @pending is %false set the - * message of the currently selected conversation, otherwise mark the - * message to be set for the next selected conversation. - * - * @param {string} message - The message to place in the entry - * @param {boolean} pending - Wait for a conversation to be selected - */ - setMessage(message, pending = false) { - try { - if (pending) - this._pendingShare = message; - else - this.stack.visible_child.setMessage(message); - } catch (e) { - debug(e); - } - } -}); - - -/** - * A Gtk.ApplicationWindow for selecting from open conversations - */ -var ConversationChooser = GObject.registerClass({ - GTypeName: 'GSConnectConversationChooser', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device associated with this window', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'message': GObject.ParamSpec.string( - 'message', - 'Message', - 'The message to share', - GObject.ParamFlags.READWRITE, - '' - ), - 'plugin': GObject.ParamSpec.object( - 'plugin', - 'Plugin', - 'The plugin providing messages', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - }, -}, class ConversationChooser extends Gtk.ApplicationWindow { - - _init(params) { - super._init(Object.assign({ - title: _('Share Link'), - default_width: 300, - default_height: 200, - }, params)); - this.set_keep_above(true); - - // HeaderBar - this.headerbar = new Gtk.HeaderBar({ - title: _('Share Link'), - subtitle: this.message, - show_close_button: true, - tooltip_text: this.message, - }); - this.set_titlebar(this.headerbar); - - const newButton = new Gtk.Button({ - image: new Gtk.Image({icon_name: 'list-add-symbolic'}), - tooltip_text: _('New Conversation'), - always_show_image: true, - }); - newButton.connect('clicked', this._new.bind(this)); - this.headerbar.pack_start(newButton); - - // Threads - const scrolledWindow = new Gtk.ScrolledWindow({ - can_focus: false, - hexpand: true, - vexpand: true, - hscrollbar_policy: Gtk.PolicyType.NEVER, - }); - this.add(scrolledWindow); - - this.thread_list = new Gtk.ListBox({ - activate_on_single_click: false, - }); - this.thread_list.set_sort_func(Window.prototype._sortThreads); - this.thread_list.connect('row-activated', this._select.bind(this)); - scrolledWindow.add(this.thread_list); - - // Filter Setup - Window.prototype._onThreadsChanged.call(this); - this.show_all(); - } - - get plugin() { - return this._plugin || null; - } - - set plugin(plugin) { - this._plugin = plugin; - } - - _new(button) { - const message = this.message; - this.destroy(); - - this.plugin.sms(); - this.plugin.window._onNewConversation(); - this.plugin.window._pendingShare = message; - } - - _select(box, row) { - this.plugin.sms(); - this.plugin.window.thread_id = row.message.thread_id.toString(); - this.plugin.window.setMessage(this.message); - - this.destroy(); - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/mousepad.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/mousepad.js deleted file mode 100644 index 3d2e3e7..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/mousepad.js +++ /dev/null @@ -1,299 +0,0 @@ -'use strict'; - -const Gdk = imports.gi.Gdk; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - - -/** - * A map of Gdk to "KDE Connect" keyvals - */ -const ReverseKeyMap = new Map([ - [Gdk.KEY_BackSpace, 1], - [Gdk.KEY_Tab, 2], - [Gdk.KEY_Linefeed, 3], - [Gdk.KEY_Left, 4], - [Gdk.KEY_Up, 5], - [Gdk.KEY_Right, 6], - [Gdk.KEY_Down, 7], - [Gdk.KEY_Page_Up, 8], - [Gdk.KEY_Page_Down, 9], - [Gdk.KEY_Home, 10], - [Gdk.KEY_End, 11], - [Gdk.KEY_Return, 12], - [Gdk.KEY_Delete, 13], - [Gdk.KEY_Escape, 14], - [Gdk.KEY_Sys_Req, 15], - [Gdk.KEY_Scroll_Lock, 16], - [Gdk.KEY_F1, 21], - [Gdk.KEY_F2, 22], - [Gdk.KEY_F3, 23], - [Gdk.KEY_F4, 24], - [Gdk.KEY_F5, 25], - [Gdk.KEY_F6, 26], - [Gdk.KEY_F7, 27], - [Gdk.KEY_F8, 28], - [Gdk.KEY_F9, 29], - [Gdk.KEY_F10, 30], - [Gdk.KEY_F11, 31], - [Gdk.KEY_F12, 32], -]); - - -/* - * A list of keyvals we consider modifiers - */ -const MOD_KEYS = [ - Gdk.KEY_Alt_L, - Gdk.KEY_Alt_R, - Gdk.KEY_Caps_Lock, - Gdk.KEY_Control_L, - Gdk.KEY_Control_R, - Gdk.KEY_Meta_L, - Gdk.KEY_Meta_R, - Gdk.KEY_Num_Lock, - Gdk.KEY_Shift_L, - Gdk.KEY_Shift_R, - Gdk.KEY_Super_L, - Gdk.KEY_Super_R, -]; - - -/* - * Some convenience functions for checking keyvals for modifiers - */ -const isAlt = (key) => [Gdk.KEY_Alt_L, Gdk.KEY_Alt_R].includes(key); -const isCtrl = (key) => [Gdk.KEY_Control_L, Gdk.KEY_Control_R].includes(key); -const isShift = (key) => [Gdk.KEY_Shift_L, Gdk.KEY_Shift_R].includes(key); -const isSuper = (key) => [Gdk.KEY_Super_L, Gdk.KEY_Super_R].includes(key); - - -var InputDialog = GObject.registerClass({ - GTypeName: 'GSConnectMousepadInputDialog', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device associated with this window', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'plugin': GObject.ParamSpec.object( - 'plugin', - 'Plugin', - 'The mousepad plugin associated with this window', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - }, - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/mousepad-input-dialog.ui', - Children: [ - 'infobar', 'infobar-label', - 'shift-label', 'ctrl-label', 'alt-label', 'super-label', 'entry', - ], -}, class InputDialog extends Gtk.Dialog { - - _init(params) { - super._init(Object.assign({ - use_header_bar: true, - }, params)); - - const headerbar = this.get_titlebar(); - headerbar.title = _('Keyboard'); - headerbar.subtitle = this.device.name; - - // Main Box - const content = this.get_content_area(); - content.border_width = 0; - - // TRANSLATORS: Displayed when the remote keyboard is not ready to accept input - this.infobar_label.label = _('Remote keyboard on %s is not active').format(this.device.name); - - // Text Input - this.entry.buffer.connect( - 'insert-text', - this._onInsertText.bind(this) - ); - - this.infobar.connect('notify::reveal-child', this._onState.bind(this)); - this.plugin.bind_property('state', this.infobar, 'reveal-child', 6); - - this.show_all(); - } - - vfunc_delete_event(event) { - this._ungrab(); - return this.hide_on_delete(); - } - - vfunc_grab_broken_event(event) { - if (event.keyboard) - this._ungrab(); - - return false; - } - - vfunc_key_release_event(event) { - if (!this.plugin.state) - debug('ignoring remote keyboard state'); - - const keyvalLower = Gdk.keyval_to_lower(event.keyval); - const realMask = event.state & Gtk.accelerator_get_default_mod_mask(); - - this.alt_label.sensitive = !isAlt(keyvalLower) && (realMask & Gdk.ModifierType.MOD1_MASK); - this.ctrl_label.sensitive = !isCtrl(keyvalLower) && (realMask & Gdk.ModifierType.CONTROL_MASK); - this.shift_label.sensitive = !isShift(keyvalLower) && (realMask & Gdk.ModifierType.SHIFT_MASK); - this.super_label.sensitive = !isSuper(keyvalLower) && (realMask & Gdk.ModifierType.SUPER_MASK); - - return super.vfunc_key_release_event(event); - } - - vfunc_key_press_event(event) { - if (!this.plugin.state) - debug('ignoring remote keyboard state'); - - let keyvalLower = Gdk.keyval_to_lower(event.keyval); - let realMask = event.state & Gtk.accelerator_get_default_mod_mask(); - - this.alt_label.sensitive = isAlt(keyvalLower) || (realMask & Gdk.ModifierType.MOD1_MASK); - this.ctrl_label.sensitive = isCtrl(keyvalLower) || (realMask & Gdk.ModifierType.CONTROL_MASK); - this.shift_label.sensitive = isShift(keyvalLower) || (realMask & Gdk.ModifierType.SHIFT_MASK); - this.super_label.sensitive = isSuper(keyvalLower) || (realMask & Gdk.ModifierType.SUPER_MASK); - - // Wait for a real key before sending - if (MOD_KEYS.includes(keyvalLower)) - return false; - - // Normalize Tab - if (keyvalLower === Gdk.KEY_ISO_Left_Tab) - keyvalLower = Gdk.KEY_Tab; - - // Put shift back if it changed the case of the key, not otherwise. - if (keyvalLower !== event.keyval) - realMask |= Gdk.ModifierType.SHIFT_MASK; - - // HACK: we don't want to use SysRq as a keybinding (but we do want - // Alt+Print), so we avoid translation from Alt+Print to SysRq - if (keyvalLower === Gdk.KEY_Sys_Req && (realMask & Gdk.ModifierType.MOD1_MASK) !== 0) - keyvalLower = Gdk.KEY_Print; - - // CapsLock isn't supported as a keybinding modifier, so keep it from - // confusing us - realMask &= ~Gdk.ModifierType.LOCK_MASK; - - if (keyvalLower === 0) - return false; - - debug(`keyval: ${event.keyval}, mask: ${realMask}`); - - const request = { - alt: !!(realMask & Gdk.ModifierType.MOD1_MASK), - ctrl: !!(realMask & Gdk.ModifierType.CONTROL_MASK), - shift: !!(realMask & Gdk.ModifierType.SHIFT_MASK), - super: !!(realMask & Gdk.ModifierType.SUPER_MASK), - sendAck: true, - }; - - // specialKey - if (ReverseKeyMap.has(event.keyval)) { - request.specialKey = ReverseKeyMap.get(event.keyval); - - // key - } else { - const codePoint = Gdk.keyval_to_unicode(event.keyval); - request.key = String.fromCodePoint(codePoint); - } - - this.device.sendPacket({ - type: 'kdeconnect.mousepad.request', - body: request, - }); - - // Pass these key combinations rather than using the echo reply - if (request.alt || request.ctrl || request.super) - return super.vfunc_key_press_event(event); - - return false; - } - - vfunc_window_state_event(event) { - if (!this.plugin.state) - debug('ignoring remote keyboard state'); - - if (event.new_window_state & Gdk.WindowState.FOCUSED) - this._grab(); - else - this._ungrab(); - - return super.vfunc_window_state_event(event); - } - - _onInsertText(buffer, location, text, len) { - if (this._isAck) - return; - - debug(`insert-text: ${text} (chars ${[...text].length})`); - - for (const char of [...text]) { - if (!char) - continue; - - // TODO: modifiers? - this.device.sendPacket({ - type: 'kdeconnect.mousepad.request', - body: { - alt: false, - ctrl: false, - shift: false, - super: false, - sendAck: false, - key: char, - }, - }); - } - } - - _onState(widget) { - if (!this.plugin.state) - debug('ignoring remote keyboard state'); - - if (this.is_active) - this._grab(); - else - this._ungrab(); - } - - _grab() { - if (!this.visible || this._keyboard) - return; - - const seat = Gdk.Display.get_default().get_default_seat(); - const status = seat.grab( - this.get_window(), - Gdk.SeatCapabilities.KEYBOARD, - false, - null, - null, - null - ); - - if (status !== Gdk.GrabStatus.SUCCESS) { - logError(new Error('Grabbing keyboard failed')); - return; - } - - this._keyboard = seat.get_keyboard(); - this.grab_add(); - this.entry.has_focus = true; - } - - _ungrab() { - if (this._keyboard) { - this._keyboard.get_seat().ungrab(); - this._keyboard = null; - this.grab_remove(); - } - - this.entry.buffer.text = ''; - } -}); diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/notification.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/notification.js deleted file mode 100644 index c1d1f8a..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/notification.js +++ /dev/null @@ -1,174 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const URI = imports.service.utils.uri; - - -/** - * A dialog for repliable notifications. - */ -var ReplyDialog = GObject.registerClass({ - GTypeName: 'GSConnectNotificationReplyDialog', - Properties: { - 'device': GObject.ParamSpec.object( - 'device', - 'Device', - 'The device associated with this window', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'plugin': GObject.ParamSpec.object( - 'plugin', - 'Plugin', - 'The plugin that owns this notification', - GObject.ParamFlags.READWRITE, - GObject.Object - ), - 'uuid': GObject.ParamSpec.string( - 'uuid', - 'UUID', - 'The notification reply UUID', - GObject.ParamFlags.READWRITE, - null - ), - }, - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/notification-reply-dialog.ui', - Children: ['infobar', 'notification-title', 'notification-body', 'entry'], -}, class ReplyDialog extends Gtk.Dialog { - - _init(params) { - super._init({ - application: Gio.Application.get_default(), - device: params.device, - plugin: params.plugin, - uuid: params.uuid, - use_header_bar: true, - }); - - this.set_response_sensitive(Gtk.ResponseType.OK, false); - - // Info bar - this.device.bind_property( - 'connected', - this.infobar, - 'reveal-child', - GObject.BindingFlags.INVERT_BOOLEAN - ); - - // Notification Data - const headerbar = this.get_titlebar(); - headerbar.title = params.notification.appName; - headerbar.subtitle = this.device.name; - - this.notification_title.label = params.notification.title; - this.notification_body.label = URI.linkify(params.notification.text); - - // Message Entry/Send Button - this.device.bind_property( - 'connected', - this.entry, - 'sensitive', - GObject.BindingFlags.DEFAULT - ); - - this._connectedId = this.device.connect( - 'notify::connected', - this._onStateChanged.bind(this) - ); - - this._entryChangedId = this.entry.buffer.connect( - 'changed', - this._onStateChanged.bind(this) - ); - - this.restoreGeometry('notification-reply-dialog'); - - this.connect('destroy', this._onDestroy); - } - - _onDestroy(dialog) { - dialog.entry.buffer.disconnect(dialog._entryChangedId); - dialog.device.disconnect(dialog._connectedId); - } - - vfunc_delete_event() { - this.saveGeometry(); - - return false; - } - - vfunc_response(response_id) { - if (response_id === Gtk.ResponseType.OK) { - // Refuse to send empty or whitespace only messages - if (!this.entry.buffer.text.trim()) - return; - - this.plugin.replyNotification( - this.uuid, - this.entry.buffer.text - ); - } - - this.destroy(); - } - - get device() { - if (this._device === undefined) - this._device = null; - - return this._device; - } - - set device(device) { - this._device = device; - } - - get plugin() { - if (this._plugin === undefined) - this._plugin = null; - - return this._plugin; - } - - set plugin(plugin) { - this._plugin = plugin; - } - - get uuid() { - if (this._uuid === undefined) - this._uuid = null; - - return this._uuid; - } - - set uuid(uuid) { - this._uuid = uuid; - - // We must have a UUID - if (!uuid) { - this.destroy(); - debug('no uuid for repliable notification'); - } - } - - _onActivateLink(label, uri) { - Gtk.show_uri_on_window( - this.get_toplevel(), - uri.includes('://') ? uri : `https://${uri}`, - Gtk.get_current_event_time() - ); - - return true; - } - - _onStateChanged() { - if (this.device.connected && this.entry.buffer.text.trim()) - this.set_response_sensitive(Gtk.ResponseType.OK, true); - else - this.set_response_sensitive(Gtk.ResponseType.OK, false); - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/service.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/service.js deleted file mode 100644 index fa02710..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/ui/service.js +++ /dev/null @@ -1,248 +0,0 @@ -'use strict'; - -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const Config = imports.config; - - -/* - * Issue Header - */ -const ISSUE_HEADER = ` -GSConnect: ${Config.PACKAGE_VERSION} (${Config.IS_USER ? 'user' : 'system'}) -GJS: ${imports.system.version} -Session: ${GLib.getenv('XDG_SESSION_TYPE')} -OS: ${GLib.get_os_info('PRETTY_NAME')} -`; - - -/** - * A dialog for selecting a device - */ -var DeviceChooser = GObject.registerClass({ - GTypeName: 'GSConnectServiceDeviceChooser', - Properties: { - 'action-name': GObject.ParamSpec.string( - 'action-name', - 'Action Name', - 'The name of the associated action, like "sendFile"', - GObject.ParamFlags.READWRITE, - null - ), - 'action-target': GObject.param_spec_variant( - 'action-target', - 'Action Target', - 'The parameter for action invocations', - new GLib.VariantType('*'), - null, - GObject.ParamFlags.READWRITE - ), - }, - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/service-device-chooser.ui', - Children: ['device-list', 'cancel-button', 'select-button'], -}, class DeviceChooser extends Gtk.Dialog { - - _init(params = {}) { - super._init({ - use_header_bar: true, - application: Gio.Application.get_default(), - }); - this.set_keep_above(true); - - // HeaderBar - this.get_header_bar().subtitle = params.title; - - // Dialog Action - this.action_name = params.action_name; - this.action_target = params.action_target; - - // Device List - this.device_list.set_sort_func(this._sortDevices); - - this._devicesChangedId = this.application.settings.connect( - 'changed::devices', - this._onDevicesChanged.bind(this) - ); - this._onDevicesChanged(); - } - - vfunc_response(response_id) { - if (response_id === Gtk.ResponseType.OK) { - try { - const device = this.device_list.get_selected_row().device; - device.activate_action(this.action_name, this.action_target); - } catch (e) { - logError(e); - } - } - - this.destroy(); - } - - get action_name() { - if (this._action_name === undefined) - this._action_name = null; - - return this._action_name; - } - - set action_name(name) { - this._action_name = name; - } - - get action_target() { - if (this._action_target === undefined) - this._action_target = null; - - return this._action_target; - } - - set action_target(variant) { - this._action_target = variant; - } - - _onDeviceActivated(box, row) { - this.response(Gtk.ResponseType.OK); - } - - _onDeviceSelected(box) { - this.set_response_sensitive( - Gtk.ResponseType.OK, - (box.get_selected_row()) - ); - } - - _onDevicesChanged() { - // Collect known devices - const devices = {}; - - for (const [id, device] of this.application.manager.devices.entries()) - devices[id] = device; - - // Prune device rows - this.device_list.foreach(row => { - if (!devices.hasOwnProperty(row.name)) - row.destroy(); - else - delete devices[row.name]; - }); - - // Add new devices - for (const device of Object.values(devices)) { - const action = device.lookup_action(this.action_name); - - if (action === null) - continue; - - const row = new Gtk.ListBoxRow({ - visible: action.enabled, - }); - row.set_name(device.id); - row.device = device; - - action.bind_property( - 'enabled', - row, - 'visible', - Gio.SettingsBindFlags.DEFAULT - ); - - const grid = new Gtk.Grid({ - column_spacing: 12, - margin: 6, - visible: true, - }); - row.add(grid); - - const icon = new Gtk.Image({ - icon_name: device.icon_name, - pixel_size: 32, - visible: true, - }); - grid.attach(icon, 0, 0, 1, 1); - - const name = new Gtk.Label({ - label: device.name, - halign: Gtk.Align.START, - hexpand: true, - visible: true, - }); - grid.attach(name, 1, 0, 1, 1); - - this.device_list.add(row); - } - - if (this.device_list.get_selected_row() === null) - this.device_list.select_row(this.device_list.get_row_at_index(0)); - } - - _sortDevices(row1, row2) { - return row1.device.name.localeCompare(row2.device.name); - } -}); - - -/** - * A dialog for reporting an error. - */ -var ErrorDialog = GObject.registerClass({ - GTypeName: 'GSConnectServiceErrorDialog', - Template: 'resource:///org/gnome/Shell/Extensions/GSConnect/ui/service-error-dialog.ui', - Children: [ - 'error-stack', - 'expander-arrow', - 'gesture', - 'report-button', - 'revealer', - ], -}, class ErrorDialog extends Gtk.Window { - - _init(error) { - super._init({ - application: Gio.Application.get_default(), - title: `GSConnect: ${error.name}`, - }); - this.set_keep_above(true); - - this.error = error; - this.error_stack.buffer.text = `${error.message}\n\n${error.stack}`; - this.gesture.connect('released', this._onReleased.bind(this)); - } - - _onClicked(button) { - if (this.report_button === button) { - const uri = this._buildUri(this.error.message, this.error.stack); - Gio.AppInfo.launch_default_for_uri_async(uri, null, null, null); - } - - this.destroy(); - } - - _onReleased(gesture, n_press) { - if (n_press === 1) - this.revealer.reveal_child = !this.revealer.reveal_child; - } - - _onRevealChild(revealer, pspec) { - this.expander_arrow.icon_name = this.revealer.reveal_child - ? 'pan-down-symbolic' - : 'pan-end-symbolic'; - } - - _buildUri(message, stack) { - const body = `\`\`\`${ISSUE_HEADER}\n${stack}\n\`\`\``; - const titleQuery = encodeURIComponent(message).replace('%20', '+'); - const bodyQuery = encodeURIComponent(body).replace('%20', '+'); - const uri = `${Config.PACKAGE_BUGREPORT}?title=${titleQuery}&body=${bodyQuery}`; - - // Reasonable URI length limit - if (uri.length > 2000) - return uri.substr(0, 2000); - - return uri; - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/utils/dbus.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/utils/dbus.js deleted file mode 100644 index ab8f6fd..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/utils/dbus.js +++ /dev/null @@ -1,279 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GjsPrivate = imports.gi.GjsPrivate; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - - -/* - * Some utility methods - */ -function toDBusCase(string) { - return string.replace(/(?:^\w|[A-Z]|\b\w)/g, (ltr, offset) => { - return ltr.toUpperCase(); - }).replace(/[\s_-]+/g, ''); -} - -function toHyphenCase(string) { - return string.replace(/(?:[A-Z])/g, (ltr, offset) => { - return (offset > 0) ? `-${ltr.toLowerCase()}` : ltr.toLowerCase(); - }).replace(/[\s_]+/g, ''); -} - -function toUnderscoreCase(string) { - return string.replace(/(?:^\w|[A-Z]|_|\b\w)/g, (ltr, offset) => { - if (ltr === '_') - return ''; - - return (offset > 0) ? `_${ltr.toLowerCase()}` : ltr.toLowerCase(); - }).replace(/[\s-]+/g, ''); -} - - -/** - * DBus.Interface represents a DBus interface bound to an object instance, meant - * to be exported over DBus. - */ -var Interface = GObject.registerClass({ - GTypeName: 'GSConnectDBusInterface', - Implements: [Gio.DBusInterface], - Properties: { - 'g-instance': GObject.ParamSpec.object( - 'g-instance', - 'Instance', - 'The delegate GObject', - GObject.ParamFlags.READWRITE, - GObject.Object.$gtype - ), - }, -}, class Interface extends GjsPrivate.DBusImplementation { - - _init(params) { - super._init({ - g_instance: params.g_instance, - g_interface_info: params.g_interface_info, - }); - - // Cache member lookups - this._instanceHandlers = []; - this._instanceMethods = {}; - this._instanceProperties = {}; - - const info = this.get_info(); - this.connect('handle-method-call', this._call.bind(this._instance, info)); - this.connect('handle-property-get', this._get.bind(this._instance, info)); - this.connect('handle-property-set', this._set.bind(this._instance, info)); - - // Automatically forward known signals - const id = this._instance.connect('notify', this._notify.bind(this)); - this._instanceHandlers.push(id); - - for (const signal of info.signals) { - const type = `(${signal.args.map(arg => arg.signature).join('')})`; - const id = this._instance.connect( - signal.name, - this._emit.bind(this, signal.name, type) - ); - - this._instanceHandlers.push(id); - } - - // Export if connection and object path were given - if (params.g_connection && params.g_object_path) - this.export(params.g_connection, params.g_object_path); - } - - get g_instance() { - if (this._instance === undefined) - this._instance = null; - - return this._instance; - } - - set g_instance(instance) { - this._instance = instance; - } - - /** - * Invoke an instance's method for a DBus method call. - * - * @param {Gio.DBusInterfaceInfo} info - The DBus interface - * @param {DBus.Interface} iface - The DBus interface - * @param {string} name - The DBus method name - * @param {GLib.Variant} parameters - The method parameters - * @param {Gio.DBusMethodInvocation} invocation - The method invocation info - */ - async _call(info, iface, name, parameters, invocation) { - let retval; - - // Invoke the instance method - try { - const args = parameters.unpack().map(parameter => { - if (parameter.get_type_string() === 'h') { - const message = invocation.get_message(); - const fds = message.get_unix_fd_list(); - const idx = parameter.deepUnpack(); - return fds.get(idx); - } else { - return parameter.recursiveUnpack(); - } - }); - - retval = await this[name](...args); - } catch (e) { - if (e instanceof GLib.Error) { - invocation.return_gerror(e); - } else { - // likely to be a normal JS error - if (!e.name.includes('.')) - e.name = `org.gnome.gjs.JSError.${e.name}`; - - invocation.return_dbus_error(e.name, e.message); - } - - logError(e, `${this}: ${name}`); - return; - } - - // `undefined` is an empty tuple on DBus - if (retval === undefined) - retval = new GLib.Variant('()', []); - - // Return the instance result or error - try { - if (!(retval instanceof GLib.Variant)) { - const args = info.lookup_method(name).out_args; - retval = new GLib.Variant( - `(${args.map(arg => arg.signature).join('')})`, - (args.length === 1) ? [retval] : retval - ); - } - - invocation.return_value(retval); - } catch (e) { - invocation.return_dbus_error( - 'org.gnome.gjs.JSError.ValueError', - 'Service implementation returned an incorrect value type' - ); - - logError(e, `${this}: ${name}`); - } - } - - _nativeProp(obj, name) { - if (this._instanceProperties[name] === undefined) { - let propName = name; - - if (propName in obj) - this._instanceProperties[name] = propName; - - if (this._instanceProperties[name] === undefined) { - propName = toUnderscoreCase(name); - - if (propName in obj) - this._instanceProperties[name] = propName; - } - } - - return this._instanceProperties[name]; - } - - _emit(name, type, obj, ...args) { - this.emit_signal(name, new GLib.Variant(type, args)); - } - - _get(info, iface, name) { - const nativeValue = this[iface._nativeProp(this, name)]; - const propertyInfo = info.lookup_property(name); - - if (nativeValue === undefined || propertyInfo === null) - return null; - - return new GLib.Variant(propertyInfo.signature, nativeValue); - } - - _set(info, iface, name, value) { - const nativeValue = value.recursiveUnpack(); - - this[iface._nativeProp(this, name)] = nativeValue; - } - - _notify(obj, pspec) { - const name = toDBusCase(pspec.name); - const propertyInfo = this.get_info().lookup_property(name); - - if (propertyInfo === null) - return; - - this.emit_property_changed( - name, - new GLib.Variant( - propertyInfo.signature, - // Adjust for GJS's '-'/'_' conversion - this._instance[pspec.name.replace(/-/gi, '_')] - ) - ); - } - - destroy() { - try { - for (const id of this._instanceHandlers) - this._instance.disconnect(id); - this._instanceHandlers = []; - - this.flush(); - this.unexport(); - } catch (e) { - logError(e); - } - } -}); - - -/** - * Get the DBus connection on @busType - * - * @param {Gio.BusType} [busType] - a Gio.BusType constant - * @param {Gio.Cancellable} [cancellable] - an optional Gio.Cancellable - * @return {Promise<Gio.DBusConnection>} A DBus connection - */ -function getConnection(busType = Gio.BusType.SESSION, cancellable = null) { - return new Promise((resolve, reject) => { - Gio.bus_get(busType, cancellable, (connection, res) => { - try { - resolve(Gio.bus_get_finish(res)); - } catch (e) { - reject(e); - } - }); - }); -} - -/** - * Get a new, dedicated DBus connection on @busType - * - * @param {Gio.BusType} [busType] - a Gio.BusType constant - * @param {Gio.Cancellable} [cancellable] - an optional Gio.Cancellable - * @return {Promise<Gio.DBusConnection>} A new DBus connection - */ -function newConnection(busType = Gio.BusType.SESSION, cancellable = null) { - return new Promise((resolve, reject) => { - Gio.DBusConnection.new_for_address( - Gio.dbus_address_get_for_bus_sync(busType, cancellable), - Gio.DBusConnectionFlags.AUTHENTICATION_CLIENT | - Gio.DBusConnectionFlags.MESSAGE_BUS_CONNECTION, - null, - cancellable, - (connection, res) => { - try { - resolve(Gio.DBusConnection.new_for_address_finish(res)); - } catch (e) { - reject(e); - } - } - ); - - }); -} - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/utils/uri.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/utils/uri.js deleted file mode 100644 index 4741f64..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/service/utils/uri.js +++ /dev/null @@ -1,167 +0,0 @@ -'use strict'; - -const GLib = imports.gi.GLib; - - -/** - * The same regular expression used in GNOME Shell - * - * http://daringfireball.net/2010/07/improved_regex_for_matching_urls - */ -const _balancedParens = '\\((?:[^\\s()<>]+|(?:\\(?:[^\\s()<>]+\\)))*\\)'; -const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]'; -const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019]'; - -const _urlRegexp = new RegExp( - '(^|' + _leadingJunk + ')' + - '(' + - '(?:' + - '(?:http|https)://' + // scheme:// - '|' + - 'www\\d{0,3}[.]' + // www. - '|' + - '[a-z0-9.\\-]+[.][a-z]{2,4}/' + // foo.xx/ - ')' + - '(?:' + // one or more: - '[^\\s()<>]+' + // run of non-space non-() - '|' + // or - _balancedParens + // balanced parens - ')+' + - '(?:' + // end with: - _balancedParens + // balanced parens - '|' + // or - _notTrailingJunk + // last non-junk char - ')' + - ')', 'gi'); - - -/** - * sms/tel URI RegExp (https://tools.ietf.org/html/rfc5724) - * - * A fairly lenient regexp for sms: URIs that allows tel: numbers with chars - * from global-number, local-number (without phone-context) and single spaces. - * This allows passing numbers directly from libfolks or GData without - * pre-processing. It also makes an allowance for URIs passed from Gio.File - * that always come in the form "sms:///". - */ -const _smsParam = "[\\w.!~*'()-]+=(?:[\\w.!~*'()-]|%[0-9A-F]{2})*"; -const _telParam = ";[a-zA-Z0-9-]+=(?:[\\w\\[\\]/:&+$.!~*'()-]|%[0-9A-F]{2})+"; -const _lenientDigits = '[+]?(?:[0-9A-F*#().-]| (?! )|%20(?!%20))+'; -const _lenientNumber = `${_lenientDigits}(?:${_telParam})*`; - -const _smsRegex = new RegExp( - '^' + - 'sms:' + // scheme - '(?:[/]{2,3})?' + // Gio.File returns ":///" - '(' + // one or more... - _lenientNumber + // phone numbers - '(?:,' + _lenientNumber + ')*' + // separated by commas - ')' + - '(?:\\?(' + // followed by optional... - _smsParam + // parameters... - '(?:&' + _smsParam + ')*' + // separated by "&" (unescaped) - '))?' + - '$', 'g'); // fragments (#foo) not allowed - - -const _numberRegex = new RegExp( - '^' + - '(' + _lenientDigits + ')' + // phone number digits - '((?:' + _telParam + ')*)' + // followed by optional parameters - '$', 'g'); - - -/** - * Searches @str for URLs and returns an array of objects with %url - * properties showing the matched URL string, and %pos properties indicating - * the position within @str where the URL was found. - * - * @param {string} str - the string to search - * @return {Object[]} the list of match objects, as described above - */ -function findUrls(str) { - _urlRegexp.lastIndex = 0; - - const res = []; - let match; - - while ((match = _urlRegexp.exec(str))) { - const name = match[2]; - const url = GLib.uri_parse_scheme(name) ? name : `http://${name}`; - res.push({name, url, pos: match.index + match[1].length}); - } - - return res; -} - - -/** - * Return a string with URLs couched in <a> tags, parseable by Pango and - * using the same RegExp as GNOME Shell. - * - * @param {string} str - The string to be modified - * @param {string} [title] - An optional title (eg. alt text, tooltip) - * @return {string} the modified text - */ -function linkify(str, title = null) { - const text = GLib.markup_escape_text(str, -1); - - _urlRegexp.lastIndex = 0; - - if (title) { - return text.replace( - _urlRegexp, - `$1<a href="$2" title="${title}">$2</a>` - ); - } else { - return text.replace(_urlRegexp, '$1<a href="$2">$2</a>'); - } -} - - -/** - * A simple parsing class for sms: URI's (https://tools.ietf.org/html/rfc5724) - */ -var SmsURI = class URI { - constructor(uri) { - _smsRegex.lastIndex = 0; - const [, recipients, query] = _smsRegex.exec(uri); - - this.recipients = recipients.split(',').map(recipient => { - _numberRegex.lastIndex = 0; - const [, number, params] = _numberRegex.exec(recipient); - - if (params) { - for (const param of params.substr(1).split(';')) { - const [key, value] = param.split('='); - - // add phone-context to beginning of - if (key === 'phone-context' && value.startsWith('+')) - return value + unescape(number); - } - } - - return unescape(number); - }); - - if (query) { - for (const field of query.split('&')) { - const [key, value] = field.split('='); - - if (key === 'body') { - if (this.body) - throw URIError('duplicate "body" field'); - - this.body = value ? decodeURIComponent(value) : undefined; - } - } - } - } - - toString() { - const uri = `sms:${this.recipients.join(',')}`; - - return this.body ? `${uri}?body=${escape(this.body)}` : uri; - } -}; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/__init__.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/__init__.js deleted file mode 100644 index 9d4c0c2..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/__init__.js +++ /dev/null @@ -1,43 +0,0 @@ -'use strict'; - -const Gettext = imports.gettext; - -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; -const Gtk = imports.gi.Gtk; - -const Extension = imports.misc.extensionUtils.getCurrentExtension(); -const Config = Extension.imports.config; -Config.PACKAGE_DATADIR = Extension.path; - - -// Ensure config.js is setup properly -const userDir = GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']); - -if (Config.PACKAGE_DATADIR.startsWith(userDir)) { - Config.IS_USER = true; - - Config.GSETTINGS_SCHEMA_DIR = `${Extension.path}/schemas`; - Config.PACKAGE_LOCALEDIR = `${Extension.path}/locale`; -} - - -// Init Gettext -Gettext.bindtextdomain(Config.APP_ID, Config.PACKAGE_LOCALEDIR); -Extension._ = GLib.dgettext.bind(null, Config.APP_ID); -Extension.ngettext = GLib.dngettext.bind(null, Config.APP_ID); - - -// Init GResources -Gio.Resource.load( - GLib.build_filenamev([Config.PACKAGE_DATADIR, `${Config.APP_ID}.gresource`]) -)._register(); - - -// Init GSchema -Config.GSCHEMA = Gio.SettingsSchemaSource.new_from_directory( - Config.GSETTINGS_SCHEMA_DIR, - Gio.SettingsSchemaSource.get_default(), - false -); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/clipboard.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/clipboard.js deleted file mode 100644 index 2bc0b70..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/clipboard.js +++ /dev/null @@ -1,380 +0,0 @@ -'use strict'; - -const ByteArray = imports.byteArray; - -const Gio = imports.gi.Gio; -const GjsPrivate = imports.gi.GjsPrivate; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const Meta = imports.gi.Meta; - - -/* - * DBus Interface Info - */ -const DBUS_NAME = 'org.gnome.Shell.Extensions.GSConnect.Clipboard'; -const DBUS_PATH = '/org/gnome/Shell/Extensions/GSConnect/Clipboard'; -const DBUS_NODE = Gio.DBusNodeInfo.new_for_xml(` -<node> - <interface name="org.gnome.Shell.Extensions.GSConnect.Clipboard"> - <!-- Methods --> - <method name="GetMimetypes"> - <arg direction="out" type="as" name="mimetypes"/> - </method> - <method name="GetText"> - <arg direction="out" type="s" name="text"/> - </method> - <method name="SetText"> - <arg direction="in" type="s" name="text"/> - </method> - <method name="GetValue"> - <arg direction="in" type="s" name="mimetype"/> - <arg direction="out" type="ay" name="value"/> - </method> - <method name="SetValue"> - <arg direction="in" type="ay" name="value"/> - <arg direction="in" type="s" name="mimetype"/> - </method> - - <!-- Signals --> - <signal name="OwnerChange"/> - </interface> -</node> -`); -const DBUS_INFO = DBUS_NODE.lookup_interface(DBUS_NAME); - - -/* - * Text Mimetypes - */ -const TEXT_MIMETYPES = [ - 'text/plain;charset=utf-8', - 'UTF8_STRING', - 'text/plain', - 'STRING', -]; - - -/* GSConnectClipboardPortal: - * - * A simple clipboard portal, especially useful on Wayland where GtkClipboard - * doesn't work in the background. - */ -var Clipboard = GObject.registerClass({ - GTypeName: 'GSConnectShellClipboard', -}, class GSConnectShellClipboard extends GjsPrivate.DBusImplementation { - - _init(params = {}) { - super._init({ - g_interface_info: DBUS_INFO, - }); - - this._transferring = false; - - // Watch global selection - this._selection = global.display.get_selection(); - this._ownerChangedId = this._selection.connect( - 'owner-changed', - this._onOwnerChanged.bind(this) - ); - - // Prepare DBus interface - this._handleMethodCallId = this.connect( - 'handle-method-call', - this._onHandleMethodCall.bind(this) - ); - - this._nameId = Gio.DBus.own_name( - Gio.BusType.SESSION, - DBUS_NAME, - Gio.BusNameOwnerFlags.NONE, - this._onBusAcquired.bind(this), - null, - this._onNameLost.bind(this) - ); - } - - _onOwnerChanged(selection, type, source) { - /* We're only interested in the standard clipboard */ - if (type !== Meta.SelectionType.SELECTION_CLIPBOARD) - return; - - /* In Wayland an intermediate GMemoryOutputStream is used which triggers - * a second ::owner-changed emission, so we need to ensure we ignore - * that while the transfer is resolving. - */ - if (this._transferring) - return; - - this._transferring = true; - - /* We need to put our signal emission in an idle callback to ensure that - * Mutter's internal calls have finished resolving in the loop, or else - * we'll end up with the previous selection's content. - */ - GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => { - this.emit_signal('OwnerChange', null); - this._transferring = false; - - return GLib.SOURCE_REMOVE; - }); - } - - _onBusAcquired(connection, name) { - try { - this.export(connection, DBUS_PATH); - } catch (e) { - logError(e); - } - } - - _onNameLost(connection, name) { - try { - this.unexport(); - } catch (e) { - logError(e); - } - } - - async _onHandleMethodCall(iface, name, parameters, invocation) { - let retval; - - try { - const args = parameters.recursiveUnpack(); - - retval = await this[name](...args); - } catch (e) { - if (e instanceof GLib.Error) { - invocation.return_gerror(e); - } else { - if (!e.name.includes('.')) - e.name = `org.gnome.gjs.JSError.${e.name}`; - - invocation.return_dbus_error(e.name, e.message); - } - - return; - } - - if (retval === undefined) - retval = new GLib.Variant('()', []); - - try { - if (!(retval instanceof GLib.Variant)) { - const args = DBUS_INFO.lookup_method(name).out_args; - retval = new GLib.Variant( - `(${args.map(arg => arg.signature).join('')})`, - (args.length === 1) ? [retval] : retval - ); - } - - invocation.return_value(retval); - - // Without a response, the client will wait for timeout - } catch (e) { - invocation.return_dbus_error( - 'org.gnome.gjs.JSError.ValueError', - 'Service implementation returned an incorrect value type' - ); - } - } - - /** - * Get the available mimetypes of the current clipboard content - * - * @return {Promise<string[]>} A list of mime-types - */ - GetMimetypes() { - return new Promise((resolve, reject) => { - try { - const mimetypes = this._selection.get_mimetypes( - Meta.SelectionType.SELECTION_CLIPBOARD - ); - - resolve(mimetypes); - } catch (e) { - reject(e); - } - }); - } - - /** - * Get the text content of the clipboard - * - * @return {Promise<string>} Text content of the clipboard - */ - GetText() { - return new Promise((resolve, reject) => { - const mimetypes = this._selection.get_mimetypes( - Meta.SelectionType.SELECTION_CLIPBOARD); - - const mimetype = mimetypes.find(type => TEXT_MIMETYPES.includes(type)); - - if (mimetype !== undefined) { - const stream = Gio.MemoryOutputStream.new_resizable(); - - this._selection.transfer_async( - Meta.SelectionType.SELECTION_CLIPBOARD, - mimetype, -1, - stream, null, - (selection, res) => { - try { - selection.transfer_finish(res); - - const bytes = stream.steal_as_bytes(); - const bytearray = bytes.get_data(); - - resolve(ByteArray.toString(bytearray)); - } catch (e) { - reject(e); - } - } - ); - } else { - reject(new Error('text not available')); - } - }); - } - - /** - * Set the text content of the clipboard - * - * @param {string} text - text content to set - * @return {Promise} A promise for the operation - */ - SetText(text) { - return new Promise((resolve, reject) => { - try { - if (typeof text !== 'string') { - throw new Gio.DBusError({ - code: Gio.DBusError.INVALID_ARGS, - message: 'expected string', - }); - } - - const source = Meta.SelectionSourceMemory.new( - 'text/plain;charset=utf-8', GLib.Bytes.new(text)); - - this._selection.set_owner( - Meta.SelectionType.SELECTION_CLIPBOARD, source); - - resolve(); - } catch (e) { - reject(e); - } - }); - } - - /** - * Get the content of the clipboard with the type @mimetype. - * - * @param {string} mimetype - the mimetype to request - * @return {Promise<Uint8Array>} The content of the clipboard - */ - GetValue(mimetype) { - return new Promise((resolve, reject) => { - const stream = Gio.MemoryOutputStream.new_resizable(); - - this._selection.transfer_async( - Meta.SelectionType.SELECTION_CLIPBOARD, - mimetype, -1, - stream, null, - (selection, res) => { - try { - selection.transfer_finish(res); - - const bytes = stream.steal_as_bytes(); - - resolve(bytes.get_data()); - } catch (e) { - reject(e); - } - } - ); - }); - } - - /** - * Set the content of the clipboard to @value with the type @mimetype. - * - * @param {Uint8Array} value - the value to set - * @param {string} mimetype - the mimetype of the value - * @return {Promise} - A promise for the operation - */ - SetValue(value, mimetype) { - return new Promise((resolve, reject) => { - try { - const source = Meta.SelectionSourceMemory.new(mimetype, - GLib.Bytes.new(value)); - - this._selection.set_owner( - Meta.SelectionType.SELECTION_CLIPBOARD, source); - - resolve(); - } catch (e) { - reject(e); - } - }); - } - - destroy() { - if (this._selection && this._ownerChangedId > 0) { - this._selection.disconnect(this._ownerChangedId); - this._ownerChangedId = 0; - } - - if (this._nameId > 0) { - Gio.bus_unown_name(this._nameId); - this._nameId = 0; - } - - if (this._handleMethodCallId > 0) { - this.disconnect(this._handleMethodCallId); - this._handleMethodCallId = 0; - this.unexport(); - } - } -}); - - -var _portal = null; -var _portalId = 0; - -/** - * Watch for the service to start and export the clipboard portal when it does. - */ -function watchService() { - if (GLib.getenv('XDG_SESSION_TYPE') !== 'wayland') - return; - - if (_portalId > 0) - return; - - _portalId = Gio.bus_watch_name( - Gio.BusType.SESSION, - 'org.gnome.Shell.Extensions.GSConnect', - Gio.BusNameWatcherFlags.NONE, - () => { - if (_portal === null) - _portal = new Clipboard(); - }, - () => { - if (_portal !== null) { - _portal.destroy(); - _portal = null; - } - } - ); -} - -/** - * Stop watching the service and export the portal if currently running. - */ -function unwatchService() { - if (_portalId > 0) { - Gio.bus_unwatch_name(_portalId); - _portalId = 0; - } -} - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/device.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/device.js deleted file mode 100644 index 2bacd51..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/device.js +++ /dev/null @@ -1,379 +0,0 @@ -'use strict'; - -const Clutter = imports.gi.Clutter; -const GObject = imports.gi.GObject; -const St = imports.gi.St; - -const PanelMenu = imports.ui.panelMenu; -const PopupMenu = imports.ui.popupMenu; - -const Extension = imports.misc.extensionUtils.getCurrentExtension(); - -// eslint-disable-next-line no-redeclare -const _ = Extension._; -const GMenu = Extension.imports.shell.gmenu; -const Tooltip = Extension.imports.shell.tooltip; - - -/** - * A battery widget with an icon, text percentage and time estimate tooltip - */ -var Battery = GObject.registerClass({ - GTypeName: 'GSConnectShellDeviceBattery', -}, class Battery extends St.BoxLayout { - - _init(params) { - super._init({ - reactive: true, - style_class: 'gsconnect-device-battery', - track_hover: true, - }); - Object.assign(this, params); - - // Percent Label - this.label = new St.Label({ - y_align: Clutter.ActorAlign.CENTER, - }); - this.label.clutter_text.ellipsize = 0; - this.add_child(this.label); - - // Battery Icon - this.icon = new St.Icon({ - fallback_icon_name: 'battery-missing-symbolic', - icon_size: 16, - }); - this.add_child(this.icon); - - // Battery Estimate - this.tooltip = new Tooltip.Tooltip({ - parent: this, - text: null, - }); - - // Battery GAction - this._actionAddedId = this.device.action_group.connect( - 'action-added', - this._onActionChanged.bind(this) - ); - this._actionRemovedId = this.device.action_group.connect( - 'action-removed', - this._onActionChanged.bind(this) - ); - this._actionStateChangedId = this.device.action_group.connect( - 'action-state-changed', - this._onStateChanged.bind(this) - ); - - this._onActionChanged(this.device.action_group, 'battery'); - - // Cleanup on destroy - this.connect('destroy', this._onDestroy); - } - - _onActionChanged(action_group, action_name) { - if (action_name !== 'battery') - return; - - if (action_group.has_action('battery')) { - const value = action_group.get_action_state('battery'); - const [charging, icon_name, level, time] = value.deepUnpack(); - - this._state = { - charging: charging, - icon_name: icon_name, - level: level, - time: time, - }; - } else { - this._state = null; - } - - this._sync(); - } - - _onStateChanged(action_group, action_name, value) { - if (action_name !== 'battery') - return; - - const [charging, icon_name, level, time] = value.deepUnpack(); - - this._state = { - charging: charging, - icon_name: icon_name, - level: level, - time: time, - }; - - this._sync(); - } - - _getBatteryLabel() { - if (!this._state) - return null; - - const {charging, level, time} = this._state; - - if (level === 100) - // TRANSLATORS: When the battery level is 100% - return _('Fully Charged'); - - if (time === 0) - // TRANSLATORS: When no time estimate for the battery is available - // EXAMPLE: 42% (Estimating…) - return _('%d%% (Estimating…)').format(level); - - const total = time / 60; - const minutes = Math.floor(total % 60); - const hours = Math.floor(total / 60); - - if (charging) { - // TRANSLATORS: Estimated time until battery is charged - // EXAMPLE: 42% (1:15 Until Full) - return _('%d%% (%d\u2236%02d Until Full)').format( - level, - hours, - minutes - ); - } else { - // TRANSLATORS: Estimated time until battery is empty - // EXAMPLE: 42% (12:15 Remaining) - return _('%d%% (%d\u2236%02d Remaining)').format( - level, - hours, - minutes - ); - } - } - - _onDestroy(actor) { - actor.device.action_group.disconnect(actor._actionAddedId); - actor.device.action_group.disconnect(actor._actionRemovedId); - actor.device.action_group.disconnect(actor._actionStateChangedId); - } - - _sync() { - this.visible = !!this._state; - - if (!this.visible) - return; - - this.icon.icon_name = this._state.icon_name; - this.label.text = (this._state.level > -1) ? `${this._state.level}%` : ''; - this.tooltip.text = this._getBatteryLabel(); - } -}); - - -/** - * A cell signal strength widget with two icons - */ -var SignalStrength = GObject.registerClass({ - GTypeName: 'GSConnectShellDeviceSignalStrength', -}, class SignalStrength extends St.BoxLayout { - - _init(params) { - super._init({ - reactive: true, - style_class: 'gsconnect-device-signal-strength', - track_hover: true, - }); - Object.assign(this, params); - - // Network Type Icon - this.networkTypeIcon = new St.Icon({ - fallback_icon_name: 'network-cellular-symbolic', - icon_size: 16, - }); - this.add_child(this.networkTypeIcon); - - // Signal Strength Icon - this.signalStrengthIcon = new St.Icon({ - fallback_icon_name: 'network-cellular-offline-symbolic', - icon_size: 16, - }); - this.add_child(this.signalStrengthIcon); - - // Network Type Text - this.tooltip = new Tooltip.Tooltip({ - parent: this, - text: null, - }); - - // ConnectivityReport GAction - this._actionAddedId = this.device.action_group.connect( - 'action-added', - this._onActionChanged.bind(this) - ); - this._actionRemovedId = this.device.action_group.connect( - 'action-removed', - this._onActionChanged.bind(this) - ); - this._actionStateChangedId = this.device.action_group.connect( - 'action-state-changed', - this._onStateChanged.bind(this) - ); - - this._onActionChanged(this.device.action_group, 'connectivityReport'); - - // Cleanup on destroy - this.connect('destroy', this._onDestroy); - } - - _onActionChanged(action_group, action_name) { - if (action_name !== 'connectivityReport') - return; - - if (action_group.has_action('connectivityReport')) { - const value = action_group.get_action_state('connectivityReport'); - const [ - cellular_network_type, - cellular_network_type_icon, - cellular_network_strength, - cellular_network_strength_icon, - hotspot_name, - hotspot_bssid, - ] = value.deepUnpack(); - - this._state = { - cellular_network_type: cellular_network_type, - cellular_network_type_icon: cellular_network_type_icon, - cellular_network_strength: cellular_network_strength, - cellular_network_strength_icon: cellular_network_strength_icon, - hotspot_name: hotspot_name, - hotspot_bssid: hotspot_bssid, - }; - } else { - this._state = null; - } - - this._sync(); - } - - _onStateChanged(action_group, action_name, value) { - if (action_name !== 'connectivityReport') - return; - - const [ - cellular_network_type, - cellular_network_type_icon, - cellular_network_strength, - cellular_network_strength_icon, - hotspot_name, - hotspot_bssid, - ] = value.deepUnpack(); - - this._state = { - cellular_network_type: cellular_network_type, - cellular_network_type_icon: cellular_network_type_icon, - cellular_network_strength: cellular_network_strength, - cellular_network_strength_icon: cellular_network_strength_icon, - hotspot_name: hotspot_name, - hotspot_bssid: hotspot_bssid, - }; - - this._sync(); - } - - _onDestroy(actor) { - actor.device.action_group.disconnect(actor._actionAddedId); - actor.device.action_group.disconnect(actor._actionRemovedId); - actor.device.action_group.disconnect(actor._actionStateChangedId); - } - - _sync() { - this.visible = !!this._state; - - if (!this.visible) - return; - - this.networkTypeIcon.icon_name = this._state.cellular_network_type_icon; - this.signalStrengthIcon.icon_name = this._state.cellular_network_strength_icon; - this.tooltip.text = this._state.cellular_network_type; - } -}); - - -/** - * A PopupMenu used as an information and control center for a device - */ -var Menu = class Menu extends PopupMenu.PopupMenuSection { - - constructor(params) { - super(); - Object.assign(this, params); - - this.actor.add_style_class_name('gsconnect-device-menu'); - - // Title - this._title = new PopupMenu.PopupSeparatorMenuItem(this.device.name); - this.addMenuItem(this._title); - - // Title -> Name - this._title.label.style_class = 'gsconnect-device-name'; - this._title.label.clutter_text.ellipsize = 0; - this.device.bind_property( - 'name', - this._title.label, - 'text', - GObject.BindingFlags.SYNC_CREATE - ); - - // Title -> Cellular Signal Strength - this._signalStrength = new SignalStrength({device: this.device}); - this._title.actor.add_child(this._signalStrength); - - // Title -> Battery - this._battery = new Battery({device: this.device}); - this._title.actor.add_child(this._battery); - - // Actions - let actions; - - if (this.menu_type === 'icon') { - actions = new GMenu.IconBox({ - action_group: this.device.action_group, - model: this.device.menu, - }); - } else if (this.menu_type === 'list') { - actions = new GMenu.ListBox({ - action_group: this.device.action_group, - model: this.device.menu, - }); - } - - this.addMenuItem(actions); - } - - isEmpty() { - return false; - } -}; - - -/** - * An indicator representing a Device in the Status Area - */ -var Indicator = GObject.registerClass({ - GTypeName: 'GSConnectDeviceIndicator', -}, class Indicator extends PanelMenu.Button { - - _init(params) { - super._init(0.0, `${params.device.name} Indicator`, false); - Object.assign(this, params); - - // Device Icon - this._icon = new St.Icon({ - gicon: Extension.getIcon(this.device.icon_name), - style_class: 'system-status-icon gsconnect-device-indicator', - }); - this.add_child(this._icon); - - // Menu - const menu = new Menu({ - device: this.device, - menu_type: 'icon', - }); - this.menu.addMenuItem(menu); - } -}); - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/gmenu.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/gmenu.js deleted file mode 100644 index e3f1248..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/gmenu.js +++ /dev/null @@ -1,649 +0,0 @@ -'use strict'; - -const Atk = imports.gi.Atk; -const Clutter = imports.gi.Clutter; -const Gio = imports.gi.Gio; -const GObject = imports.gi.GObject; -const St = imports.gi.St; - -const PopupMenu = imports.ui.popupMenu; - -const Extension = imports.misc.extensionUtils.getCurrentExtension(); - -const Tooltip = Extension.imports.shell.tooltip; - - -/** - * Get a dictionary of a GMenuItem's attributes - * - * @param {Gio.MenuModel} model - The menu model containing the item - * @param {number} index - The index of the item in @model - * @return {Object} A dictionary of the item's attributes - */ -function getItemInfo(model, index) { - const info = { - target: null, - links: [], - }; - - // - let iter = model.iterate_item_attributes(index); - - while (iter.next()) { - const name = iter.get_name(); - let value = iter.get_value(); - - switch (name) { - case 'icon': - value = Gio.Icon.deserialize(value); - - if (value instanceof Gio.ThemedIcon) - value = Extension.getIcon(value.names[0]); - - info[name] = value; - break; - - case 'target': - info[name] = value; - break; - - default: - info[name] = value.unpack(); - } - } - - // Submenus & Sections - iter = model.iterate_item_links(index); - - while (iter.next()) { - info.links.push({ - name: iter.get_name(), - value: iter.get_value(), - }); - } - - return info; -} - - -/** - * - */ -var ListBox = class ListBox extends PopupMenu.PopupMenuSection { - - constructor(params) { - super(); - Object.assign(this, params); - - // Main Actor - this.actor = new St.BoxLayout({ - x_expand: true, - clip_to_allocation: true, - }); - this.actor._delegate = this; - - // Item Box - this.box.clip_to_allocation = true; - this.box.x_expand = true; - this.box.add_style_class_name('gsconnect-list-box'); - this.box.set_pivot_point(1, 1); - this.actor.add_child(this.box); - - // Submenu Container - this.sub = new St.BoxLayout({ - clip_to_allocation: true, - vertical: false, - visible: false, - x_expand: true, - }); - this.sub.set_pivot_point(1, 1); - this.sub._delegate = this; - this.actor.add_child(this.sub); - - // Handle transitions - this._boxTransitionsCompletedId = this.box.connect( - 'transitions-completed', - this._onTransitionsCompleted.bind(this) - ); - - this._subTransitionsCompletedId = this.sub.connect( - 'transitions-completed', - this._onTransitionsCompleted.bind(this) - ); - - // Handle keyboard navigation - this._submenuCloseKeyId = this.sub.connect( - 'key-press-event', - this._onSubmenuCloseKey.bind(this) - ); - - // Refresh the menu when mapped - this._mappedId = this.actor.connect( - 'notify::mapped', - this._onMapped.bind(this) - ); - - // Watch the model for changes - this._itemsChangedId = this.model.connect( - 'items-changed', - this._onItemsChanged.bind(this) - ); - this._onItemsChanged(); - } - - _onMapped(actor) { - if (actor.mapped) { - this._onItemsChanged(); - - // We use this instead of close() to avoid touching finalized objects - } else { - this.box.set_opacity(255); - this.box.set_width(-1); - this.box.set_height(-1); - this.box.visible = true; - - this._submenu = null; - this.sub.set_opacity(0); - this.sub.set_width(0); - this.sub.set_height(0); - this.sub.visible = false; - this.sub.get_children().map(menu => menu.hide()); - } - } - - _onSubmenuCloseKey(actor, event) { - if (this.submenu && event.get_key_symbol() === Clutter.KEY_Left) { - this.submenu.submenu_for.setActive(true); - this.submenu = null; - return Clutter.EVENT_STOP; - } - - return Clutter.EVENT_PROPAGATE; - } - - _onSubmenuOpenKey(actor, event) { - const item = actor._delegate; - - if (item.submenu && event.get_key_symbol() === Clutter.KEY_Right) { - this.submenu = item.submenu; - item.submenu.firstMenuItem.setActive(true); - } - - return Clutter.EVENT_PROPAGATE; - } - - _onGMenuItemActivate(item, event) { - this.emit('activate', item); - - if (item.submenu) { - this.submenu = item.submenu; - } else if (item.action_name) { - this.action_group.activate_action( - item.action_name, - item.action_target - ); - this.itemActivated(); - } - } - - _addGMenuItem(info) { - const item = new PopupMenu.PopupMenuItem(info.label); - this.addMenuItem(item); - - if (info.action !== undefined) { - item.action_name = info.action.split('.')[1]; - item.action_target = info.target; - - item.actor.visible = this.action_group.get_action_enabled( - item.action_name - ); - } - - // Modify the ::activate callback to invoke the GAction or submenu - item.disconnect(item._activateId); - item._activateId = item.connect( - 'activate', - this._onGMenuItemActivate.bind(this) - ); - - return item; - } - - _addGMenuSection(model) { - const section = new ListBox({ - model: model, - action_group: this.action_group, - }); - this.addMenuItem(section); - } - - _addGMenuSubmenu(model, item) { - // Add an expander arrow to the item - const arrow = PopupMenu.arrowIcon(St.Side.RIGHT); - arrow.x_align = Clutter.ActorAlign.END; - arrow.x_expand = true; - item.actor.add_child(arrow); - - // Mark it as an expandable and open on right-arrow - item.actor.add_accessible_state(Atk.StateType.EXPANDABLE); - - item.actor.connect( - 'key-press-event', - this._onSubmenuOpenKey.bind(this) - ); - - // Create the submenu - item.submenu = new ListBox({ - model: model, - action_group: this.action_group, - submenu_for: item, - _parent: this, - }); - item.submenu.actor.hide(); - - // Add to the submenu container - this.sub.add_child(item.submenu.actor); - } - - _onItemsChanged(model, position, removed, added) { - // Clear the menu - this.removeAll(); - this.sub.get_children().map(child => child.destroy()); - - for (let i = 0, len = this.model.get_n_items(); i < len; i++) { - const info = getItemInfo(this.model, i); - let item; - - // A regular item - if (info.hasOwnProperty('label')) - item = this._addGMenuItem(info); - - for (const link of info.links) { - // Submenu - if (link.name === 'submenu') { - this._addGMenuSubmenu(link.value, item); - - // Section - } else if (link.name === 'section') { - this._addGMenuSection(link.value); - - // len is length starting at 1 - if (i + 1 < len) - this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - } - } - } - - // If this is a submenu of another item... - if (this.submenu_for) { - // Prepend an "<= Go Back" item, bold with a unicode arrow - const prev = new PopupMenu.PopupMenuItem(this.submenu_for.label.text); - prev.label.style = 'font-weight: bold;'; - const prevArrow = PopupMenu.arrowIcon(St.Side.LEFT); - prev.replace_child(prev._ornamentLabel, prevArrow); - this.addMenuItem(prev, 0); - - // Modify the ::activate callback to close the submenu - prev.disconnect(prev._activateId); - - prev._activateId = prev.connect('activate', (item, event) => { - this.emit('activate', item); - this._parent.submenu = null; - }); - } - } - - _onTransitionsCompleted(actor) { - if (this.submenu) { - this.box.visible = false; - } else { - this.sub.visible = false; - this.sub.get_children().map(menu => menu.hide()); - } - } - - get submenu() { - return this._submenu || null; - } - - set submenu(submenu) { - // Get the current allocation to hold the menu width - const allocation = this.actor.allocation; - const width = Math.max(0, allocation.x2 - allocation.x1); - - // Prepare the appropriate child for tweening - if (submenu) { - this.sub.set_opacity(0); - this.sub.set_width(0); - this.sub.set_height(0); - this.sub.visible = true; - } else { - this.box.set_opacity(0); - this.box.set_width(0); - this.sub.set_height(0); - this.box.visible = true; - } - - // Setup the animation - this.box.save_easing_state(); - this.box.set_easing_mode(Clutter.AnimationMode.EASE_IN_OUT_CUBIC); - this.box.set_easing_duration(250); - - this.sub.save_easing_state(); - this.sub.set_easing_mode(Clutter.AnimationMode.EASE_IN_OUT_CUBIC); - this.sub.set_easing_duration(250); - - if (submenu) { - submenu.actor.show(); - - this.sub.set_opacity(255); - this.sub.set_width(width); - this.sub.set_height(-1); - - this.box.set_opacity(0); - this.box.set_width(0); - this.box.set_height(0); - } else { - this.box.set_opacity(255); - this.box.set_width(width); - this.box.set_height(-1); - - this.sub.set_opacity(0); - this.sub.set_width(0); - this.sub.set_height(0); - } - - // Reset the animation - this.box.restore_easing_state(); - this.sub.restore_easing_state(); - - // - this._submenu = submenu; - } - - destroy() { - this.actor.disconnect(this._mappedId); - this.box.disconnect(this._boxTransitionsCompletedId); - this.sub.disconnect(this._subTransitionsCompletedId); - this.sub.disconnect(this._submenuCloseKeyId); - this.model.disconnect(this._itemsChangedId); - - super.destroy(); - } -}; - - -/** - * A St.Button subclass for iconic GMenu items - */ -var IconButton = GObject.registerClass({ - GTypeName: 'GSConnectShellIconButton', -}, class Button extends St.Button { - - _init(params) { - super._init({ - style_class: 'gsconnect-icon-button', - can_focus: true, - }); - Object.assign(this, params); - - // Item attributes - if (params.info.hasOwnProperty('action')) - this.action_name = params.info.action.split('.')[1]; - - if (params.info.hasOwnProperty('target')) - this.action_target = params.info.target; - - if (params.info.hasOwnProperty('label')) { - this.tooltip = new Tooltip.Tooltip({ - parent: this, - markup: params.info.label, - }); - - this.accessible_name = params.info.label; - } - - if (params.info.hasOwnProperty('icon')) - this.child = new St.Icon({gicon: params.info.icon}); - - // Submenu - for (const link of params.info.links) { - if (link.name === 'submenu') { - this.add_accessible_state(Atk.StateType.EXPANDABLE); - this.toggle_mode = true; - this.connect('notify::checked', this._onChecked); - - this.submenu = new ListBox({ - model: link.value, - action_group: this.action_group, - _parent: this._parent, - }); - - this.submenu.actor.style_class = 'popup-sub-menu'; - this.submenu.actor.visible = false; - } - } - } - - // This is (reliably?) emitted before ::clicked - _onChecked(button) { - if (button.checked) { - button.add_accessible_state(Atk.StateType.EXPANDED); - button.add_style_pseudo_class('active'); - } else { - button.remove_accessible_state(Atk.StateType.EXPANDED); - button.remove_style_pseudo_class('active'); - } - } - - // This is (reliably?) emitted after notify::checked - vfunc_clicked(clicked_button) { - // Unless this has a submenu, activate the action and close the menu - if (!this.toggle_mode) { - this._parent._getTopMenu().close(); - - this.action_group.activate_action( - this.action_name, - this.action_target - ); - - // StButton.checked has already been toggled so we're opening - } else if (this.checked) { - this._parent.submenu = this.submenu; - - // If this is the active submenu being closed, animate-close it - } else if (this._parent.submenu === this.submenu) { - this._parent.submenu = null; - } - } -}); - - -var IconBox = class IconBox extends PopupMenu.PopupMenuSection { - - constructor(params) { - super(); - Object.assign(this, params); - - // Main Actor - this.actor = new St.BoxLayout({ - vertical: true, - x_expand: true, - }); - this.actor._delegate = this; - - // Button Box - this.box._delegate = this; - this.box.style_class = 'gsconnect-icon-box'; - this.box.vertical = false; - this.actor.add_child(this.box); - - // Submenu Container - this.sub = new St.BoxLayout({ - clip_to_allocation: true, - vertical: true, - x_expand: true, - }); - this.sub.connect('transitions-completed', this._onTransitionsCompleted); - this.sub._delegate = this; - this.actor.add_child(this.sub); - - // Track menu items so we can use ::items-changed - this._menu_items = new Map(); - - // PopupMenu - this._mappedId = this.actor.connect( - 'notify::mapped', - this._onMapped.bind(this) - ); - - // GMenu - this._itemsChangedId = this.model.connect( - 'items-changed', - this._onItemsChanged.bind(this) - ); - - // GActions - this._actionAddedId = this.action_group.connect( - 'action-added', - this._onActionChanged.bind(this) - ); - this._actionEnabledChangedId = this.action_group.connect( - 'action-enabled-changed', - this._onActionChanged.bind(this) - ); - this._actionRemovedId = this.action_group.connect( - 'action-removed', - this._onActionChanged.bind(this) - ); - } - - destroy() { - this.actor.disconnect(this._mappedId); - this.model.disconnect(this._itemsChangedId); - this.action_group.disconnect(this._actionAddedId); - this.action_group.disconnect(this._actionEnabledChangedId); - this.action_group.disconnect(this._actionRemovedId); - - super.destroy(); - } - - get submenu() { - return this._submenu || null; - } - - set submenu(submenu) { - if (submenu) { - for (const button of this.box.get_children()) { - if (button.submenu && this._submenu && button.submenu !== submenu) { - button.checked = false; - button.submenu.actor.hide(); - } - } - - this.sub.set_height(0); - submenu.actor.show(); - } - - this.sub.save_easing_state(); - this.sub.set_easing_duration(250); - this.sub.set_easing_mode(Clutter.AnimationMode.EASE_IN_OUT_CUBIC); - - this.sub.set_height(submenu ? submenu.actor.get_preferred_size()[1] : 0); - this.sub.restore_easing_state(); - - this._submenu = submenu; - } - - _onMapped(actor) { - if (!actor.mapped) { - this._submenu = null; - - for (const button of this.box.get_children()) - button.checked = false; - - for (const submenu of this.sub.get_children()) - submenu.hide(); - } - } - - _onActionChanged(group, name, enabled) { - const menuItem = this._menu_items.get(name); - - if (menuItem !== undefined) - menuItem.visible = group.get_action_enabled(name); - } - - _onItemsChanged(model, position, removed, added) { - // Remove items - while (removed > 0) { - const button = this.box.get_child_at_index(position); - const action_name = button.action_name; - - if (button.submenu) - button.submenu.destroy(); - - button.destroy(); - - this._menu_items.delete(action_name); - removed--; - } - - // Add items - for (let i = 0; i < added; i++) { - const index = position + i; - - // Create an iconic button - const button = new IconButton({ - action_group: this.action_group, - info: getItemInfo(model, index), - // NOTE: Because this doesn't derive from a PopupMenu class - // it lacks some things its parent will expect from it - _parent: this, - _delegate: null, - }); - - // Set the visibility based on the enabled state - if (button.action_name !== undefined) { - button.visible = this.action_group.get_action_enabled( - button.action_name - ); - } - - // If it has a submenu, add it as a sibling - if (button.submenu) - this.sub.add_child(button.submenu.actor); - - // Track the item if it has an action - if (button.action_name !== undefined) - this._menu_items.set(button.action_name, button); - - // Insert it in the box at the defined position - this.box.insert_child_at_index(button, index); - } - } - - _onTransitionsCompleted(actor) { - const menu = actor._delegate; - - for (const button of menu.box.get_children()) { - if (button.submenu && button.submenu !== menu.submenu) { - button.checked = false; - button.submenu.actor.hide(); - } - } - - menu.sub.set_height(-1); - } - - // PopupMenu.PopupMenuBase overrides - isEmpty() { - return (this.box.get_children().length === 0); - } - - _setParent(parent) { - super._setParent(parent); - this._onItemsChanged(this.model, 0, 0, this.model.get_n_items()); - } -}; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/keybindings.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/keybindings.js deleted file mode 100644 index 48cba6c..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/keybindings.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -const Config = imports.misc.config; -const Main = imports.ui.main; -const Meta = imports.gi.Meta; -const Shell = imports.gi.Shell; - - -/** - * Keybindings.Manager is a simple convenience class for managing keyboard - * shortcuts in GNOME Shell. You bind a shortcut using add(), which on success - * will return a non-zero action id that can later be used with remove() to - * unbind the shortcut. - * - * Accelerators are accepted in the form returned by Gtk.accelerator_name() and - * callbacks are invoked directly, so should be complete closures. - * - * References: - * https://developer.gnome.org/gtk3/stable/gtk3-Keyboard-Accelerators.html - * https://developer.gnome.org/meta/stable/MetaDisplay.html - * https://developer.gnome.org/meta/stable/meta-MetaKeybinding.html - * https://gitlab.gnome.org/GNOME/gnome-shell/blob/master/js/ui/windowManager.js#L1093-1112 - */ -var Manager = class Manager { - - constructor() { - this._keybindings = new Map(); - - this._acceleratorActivatedId = global.display.connect( - 'accelerator-activated', - this._onAcceleratorActivated.bind(this) - ); - } - - _onAcceleratorActivated(display, action, inputDevice, timestamp) { - try { - const binding = this._keybindings.get(action); - - if (binding !== undefined) - binding.callback(); - } catch (e) { - logError(e); - } - } - - /** - * Add a keybinding with callback - * - * @param {string} accelerator - An accelerator in the form '<Control>q' - * @param {Function} callback - A callback for the accelerator - * @return {number} A non-zero action id on success, or 0 on failure - */ - add(accelerator, callback) { - try { - const action = global.display.grab_accelerator(accelerator, 0); - - if (action === Meta.KeyBindingAction.NONE) - throw new Error(`Failed to add keybinding: '${accelerator}'`); - - const name = Meta.external_binding_name_for_action(action); - Main.wm.allowKeybinding(name, Shell.ActionMode.ALL); - this._keybindings.set(action, {name: name, callback: callback}); - - return action; - } catch (e) { - logError(e); - } - } - - /** - * Remove a keybinding - * - * @param {number} action - A non-zero action id returned by add() - */ - remove(action) { - try { - const binding = this._keybindings.get(action); - global.display.ungrab_accelerator(action); - Main.wm.allowKeybinding(binding.name, Shell.ActionMode.NONE); - this._keybindings.delete(action); - } catch (e) { - logError(new Error(`Failed to remove keybinding: ${e.message}`)); - } - } - - /** - * Remove all keybindings - */ - removeAll() { - for (const action of this._keybindings.keys()) - this.remove(action); - } - - /** - * Destroy the keybinding manager and remove all keybindings - */ - destroy() { - global.display.disconnect(this._acceleratorActivatedId); - this.removeAll(); - } -}; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/notification.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/notification.js deleted file mode 100644 index efacc62..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/notification.js +++ /dev/null @@ -1,439 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; -const St = imports.gi.St; - -const Main = imports.ui.main; -const MessageTray = imports.ui.messageTray; -const NotificationDaemon = imports.ui.notificationDaemon; - -const Extension = imports.misc.extensionUtils.getCurrentExtension(); - -// eslint-disable-next-line no-redeclare -const _ = Extension._; -const APP_ID = 'org.gnome.Shell.Extensions.GSConnect'; -const APP_PATH = '/org/gnome/Shell/Extensions/GSConnect'; - - -// deviceId Pattern (<device-id>|<remote-id>) -const DEVICE_REGEX = new RegExp(/^([^|]+)\|([\s\S]+)$/); - -// requestReplyId Pattern (<device-id>|<remote-id>)|<reply-id>) -const REPLY_REGEX = new RegExp(/^([^|]+)\|([\s\S]+)\|([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})$/, 'i'); - - -/** - * A slightly modified Notification Banner with an entry field - */ -const NotificationBanner = GObject.registerClass({ - GTypeName: 'GSConnectNotificationBanner', -}, class NotificationBanner extends MessageTray.NotificationBanner { - - _init(notification) { - super._init(notification); - - if (notification.requestReplyId !== undefined) - this._addReplyAction(); - } - - _addReplyAction() { - if (!this._buttonBox) { - this._buttonBox = new St.BoxLayout({ - style_class: 'notification-actions', - x_expand: true, - }); - this.setActionArea(this._buttonBox); - global.focus_manager.add_group(this._buttonBox); - } - - // Reply Button - const button = new St.Button({ - style_class: 'notification-button', - label: _('Reply'), - x_expand: true, - can_focus: true, - }); - - button.connect( - 'clicked', - this._onEntryRequested.bind(this) - ); - - this._buttonBox.add_child(button); - - // Reply Entry - this._replyEntry = new St.Entry({ - can_focus: true, - hint_text: _('Type a message'), - style_class: 'chat-response', - x_expand: true, - visible: false, - }); - - this._buttonBox.add_child(this._replyEntry); - } - - _onEntryRequested(button) { - this.focused = true; - - for (const child of this._buttonBox.get_children()) - child.visible = (child === this._replyEntry); - - // Release the notification focus with the entry focus - this._replyEntry.connect( - 'key-focus-out', - this._onEntryDismissed.bind(this) - ); - - this._replyEntry.clutter_text.connect( - 'activate', - this._onEntryActivated.bind(this) - ); - - this._replyEntry.grab_key_focus(); - } - - _onEntryDismissed(entry) { - this.focused = false; - this.emit('unfocused'); - } - - _onEntryActivated(clutter_text) { - // Refuse to send empty replies - if (clutter_text.text === '') - return; - - // Copy the text, then clear the entry - const text = clutter_text.text; - clutter_text.text = ''; - - const {deviceId, requestReplyId} = this.notification; - - const target = new GLib.Variant('(ssbv)', [ - deviceId, - 'replyNotification', - true, - new GLib.Variant('(ssa{ss})', [requestReplyId, text, {}]), - ]); - const platformData = NotificationDaemon.getPlatformData(); - - Gio.DBus.session.call( - APP_ID, - APP_PATH, - 'org.freedesktop.Application', - 'ActivateAction', - GLib.Variant.new('(sava{sv})', ['device', [target], platformData]), - null, - Gio.DBusCallFlags.NO_AUTO_START, - -1, - null, - (connection, res) => { - try { - connection.call_finish(res); - } catch (e) { - // Silence errors - } - } - ); - - this.close(); - } -}); - - -/** - * A custom notification source for spawning notifications and closing device - * notifications. This source isn't actually used, but it's methods are patched - * into existing sources. - */ -const Source = GObject.registerClass({ - GTypeName: 'GSConnectNotificationSource', -}, class Source extends NotificationDaemon.GtkNotificationDaemonAppSource { - - _closeGSConnectNotification(notification, reason) { - if (reason !== MessageTray.NotificationDestroyedReason.DISMISSED) - return; - - // Avoid sending the request multiple times - if (notification._remoteClosed || notification.remoteId === undefined) - return; - - notification._remoteClosed = true; - - const target = new GLib.Variant('(ssbv)', [ - notification.deviceId, - 'closeNotification', - true, - new GLib.Variant('s', notification.remoteId), - ]); - const platformData = NotificationDaemon.getPlatformData(); - - Gio.DBus.session.call( - APP_ID, - APP_PATH, - 'org.freedesktop.Application', - 'ActivateAction', - GLib.Variant.new('(sava{sv})', ['device', [target], platformData]), - null, - Gio.DBusCallFlags.NO_AUTO_START, - -1, - null, - (connection, res) => { - try { - connection.call_finish(res); - } catch (e) { - // If we fail, reset in case we can try again - notification._remoteClosed = false; - } - } - ); - } - - /* - * Override to control notification spawning - */ - addNotification(notificationId, notificationParams, showBanner) { - this._notificationPending = true; - - // Parse the id to determine if it's a repliable notification, device - // notification or a regular local notification - let idMatch, deviceId, requestReplyId, remoteId, localId; - - if ((idMatch = REPLY_REGEX.exec(notificationId))) { - [, deviceId, remoteId, requestReplyId] = idMatch; - localId = `${deviceId}|${remoteId}`; - - } else if ((idMatch = DEVICE_REGEX.exec(notificationId))) { - [, deviceId, remoteId] = idMatch; - localId = `${deviceId}|${remoteId}`; - - } else { - localId = notificationId; - } - - // Fix themed icons - if (notificationParams.icon) { - let gicon = Gio.Icon.deserialize(notificationParams.icon); - - if (gicon instanceof Gio.ThemedIcon) { - gicon = Extension.getIcon(gicon.names[0]); - notificationParams.icon = gicon.serialize(); - } - } - - let notification = this._notifications[localId]; - - // Check if this is a repeat - if (notification) { - notification.requestReplyId = requestReplyId; - - // Bail early If @notificationParams represents an exact repeat - const title = notificationParams.title.unpack(); - const body = notificationParams.body - ? notificationParams.body.unpack() - : null; - - if (notification.title === title && - notification.bannerBodyText === body) { - this._notificationPending = false; - return; - } - - notification.title = title; - notification.bannerBodyText = body; - - // Device Notification - } else if (idMatch) { - notification = this._createNotification(notificationParams); - - notification.deviceId = deviceId; - notification.remoteId = remoteId; - notification.requestReplyId = requestReplyId; - - notification.connect('destroy', (notification, reason) => { - this._closeGSConnectNotification(notification, reason); - delete this._notifications[localId]; - }); - - this._notifications[localId] = notification; - - // Service Notification - } else { - notification = this._createNotification(notificationParams); - notification.connect('destroy', (notification, reason) => { - delete this._notifications[localId]; - }); - this._notifications[localId] = notification; - } - - if (showBanner) - this.showNotification(notification); - else - this.pushNotification(notification); - - this._notificationPending = false; - } - - /* - * Override to raise the usual notification limit (3) - */ - pushNotification(notification) { - if (this.notifications.includes(notification)) - return; - - while (this.notifications.length >= 10) - this.notifications.shift().destroy(MessageTray.NotificationDestroyedReason.EXPIRED); - - notification.connect('destroy', this._onNotificationDestroy.bind(this)); - notification.connect('notify::acknowledged', this.countUpdated.bind(this)); - this.notifications.push(notification); - this.emit('notification-added', notification); - - this.countUpdated(); - } - - createBanner(notification) { - return new NotificationBanner(notification); - } -}); - - -/** - * If there is an active GtkNotificationDaemonAppSource for GSConnect when the - * extension is loaded, it has to be patched in place. - */ -function patchGSConnectNotificationSource() { - const source = Main.notificationDaemon._gtkNotificationDaemon._sources[APP_ID]; - - if (source !== undefined) { - // Patch in the subclassed methods - source._closeGSConnectNotification = Source.prototype._closeGSConnectNotification; - source.addNotification = Source.prototype.addNotification; - source.pushNotification = Source.prototype.pushNotification; - source.createBanner = Source.prototype.createBanner; - - // Connect to existing notifications - for (const notification of Object.values(source._notifications)) { - - const _id = notification.connect('destroy', (notification, reason) => { - source._closeGSConnectNotification(notification, reason); - notification.disconnect(_id); - }); - } - } -} - - -/** - * Wrap GtkNotificationDaemon._ensureAppSource() to patch GSConnect's app source - * https://gitlab.gnome.org/GNOME/gnome-shell/blob/master/js/ui/notificationDaemon.js#L742-755 - */ -const __ensureAppSource = NotificationDaemon.GtkNotificationDaemon.prototype._ensureAppSource; - -// eslint-disable-next-line func-style -const _ensureAppSource = function (appId) { - const source = __ensureAppSource.call(this, appId); - - if (source._appId === APP_ID) { - source._closeGSConnectNotification = Source.prototype._closeGSConnectNotification; - source.addNotification = Source.prototype.addNotification; - source.pushNotification = Source.prototype.pushNotification; - source.createBanner = Source.prototype.createBanner; - } - - return source; -}; - - -function patchGtkNotificationDaemon() { - NotificationDaemon.GtkNotificationDaemon.prototype._ensureAppSource = _ensureAppSource; -} - - -function unpatchGtkNotificationDaemon() { - NotificationDaemon.GtkNotificationDaemon.prototype._ensureAppSource = __ensureAppSource; -} - -/** - * We patch other Gtk notification sources so we can notify remote devices when - * notifications have been closed locally. - */ -const _addNotification = NotificationDaemon.GtkNotificationDaemonAppSource.prototype.addNotification; - -function patchGtkNotificationSources() { - // This should diverge as little as possible from the original - // eslint-disable-next-line func-style - const addNotification = function (notificationId, notificationParams, showBanner) { - this._notificationPending = true; - - if (this._notifications[notificationId]) - this._notifications[notificationId].destroy(MessageTray.NotificationDestroyedReason.REPLACED); - - const notification = this._createNotification(notificationParams); - notification.connect('destroy', (notification, reason) => { - this._withdrawGSConnectNotification(notification, reason); - delete this._notifications[notificationId]; - }); - this._notifications[notificationId] = notification; - - if (showBanner) - this.showNotification(notification); - else - this.pushNotification(notification); - - this._notificationPending = false; - }; - - // eslint-disable-next-line func-style - const _withdrawGSConnectNotification = function (id, notification, reason) { - if (reason !== MessageTray.NotificationDestroyedReason.DISMISSED) - return; - - // Avoid sending the request multiple times - if (notification._remoteWithdrawn) - return; - - notification._remoteWithdrawn = true; - - // Recreate the notification id as it would've been sent - const target = new GLib.Variant('(ssbv)', [ - '*', - 'withdrawNotification', - true, - new GLib.Variant('s', `gtk|${this._appId}|${id}`), - ]); - const platformData = NotificationDaemon.getPlatformData(); - - Gio.DBus.session.call( - APP_ID, - APP_PATH, - 'org.freedesktop.Application', - 'ActivateAction', - GLib.Variant.new('(sava{sv})', ['device', [target], platformData]), - null, - Gio.DBusCallFlags.NO_AUTO_START, - -1, - null, - (connection, res) => { - try { - connection.call_finish(res); - } catch (e) { - // If we fail, reset in case we can try again - notification._remoteWithdrawn = false; - } - } - ); - }; - - NotificationDaemon.GtkNotificationDaemonAppSource.prototype.addNotification = addNotification; - NotificationDaemon.GtkNotificationDaemonAppSource.prototype._withdrawGSConnectNotification = _withdrawGSConnectNotification; -} - - -function unpatchGtkNotificationSources() { - NotificationDaemon.GtkNotificationDaemonAppSource.prototype.addNotification = _addNotification; - delete NotificationDaemon.GtkNotificationDaemonAppSource.prototype._withdrawGSConnectNotification; -} - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/tooltip.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/tooltip.js deleted file mode 100644 index 4e97988..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/tooltip.js +++ /dev/null @@ -1,302 +0,0 @@ -'use strict'; - -const Clutter = imports.gi.Clutter; -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const Pango = imports.gi.Pango; -const St = imports.gi.St; - -const Main = imports.ui.main; - - -/** - * An StTooltip for ClutterActors - * - * Adapted from: https://github.com/RaphaelRochet/applications-overview-tooltip - * See also: https://github.com/GNOME/gtk/blob/master/gtk/gtktooltip.c - */ -var TOOLTIP_BROWSE_ID = 0; -var TOOLTIP_BROWSE_MODE = false; - -var Tooltip = class Tooltip { - - constructor(params) { - Object.assign(this, params); - - this._bin = null; - this._hoverTimeoutId = 0; - this._showing = false; - - this._destroyId = this.parent.connect( - 'destroy', - this.destroy.bind(this) - ); - - this._hoverId = this.parent.connect( - 'notify::hover', - this._onHover.bind(this) - ); - - this._buttonPressEventId = this.parent.connect( - 'button-press-event', - this._hide.bind(this) - ); - } - - get custom() { - if (this._custom === undefined) - this._custom = null; - - return this._custom; - } - - set custom(actor) { - this._custom = actor; - this._markup = null; - this._text = null; - - if (this._showing) - this._show(); - } - - get gicon() { - if (this._gicon === undefined) - this._gicon = null; - - return this._gicon; - } - - set gicon(gicon) { - this._gicon = gicon; - - if (this._showing) - this._show(); - } - - get icon() { - return (this.gicon) ? this.gicon.name : null; - } - - set icon(icon_name) { - if (!icon_name) - this.gicon = null; - else - this.gicon = new Gio.ThemedIcon({name: icon_name}); - } - - get markup() { - if (this._markup === undefined) - this._markup = null; - - return this._markup; - } - - set markup(text) { - this._markup = text; - this._text = null; - - if (this._showing) - this._show(); - } - - get text() { - if (this._text === undefined) - this._text = null; - - return this._text; - } - - set text(text) { - this._markup = null; - this._text = text; - - if (this._showing) - this._show(); - } - - get x_offset() { - if (this._x_offset === undefined) - this._x_offset = 0; - - return this._x_offset; - } - - set x_offset(offset) { - this._x_offset = (Number.isInteger(offset)) ? offset : 0; - } - - get y_offset() { - if (this._y_offset === undefined) - this._y_offset = 0; - - return this._y_offset; - } - - set y_offset(offset) { - this._y_offset = (Number.isInteger(offset)) ? offset : 0; - } - - _show() { - if (this.text === null && this.markup === null) - return this._hide(); - - if (this._bin === null) { - this._bin = new St.Bin({ - style_class: 'osd-window gsconnect-tooltip', - opacity: 232, - }); - - if (this.custom) { - this._bin.child = this.custom; - } else { - this._bin.child = new St.BoxLayout({vertical: false}); - - if (this.gicon) { - this._bin.child.icon = new St.Icon({ - gicon: this.gicon, - y_align: St.Align.START, - }); - this._bin.child.icon.set_y_align(Clutter.ActorAlign.START); - this._bin.child.add_child(this._bin.child.icon); - } - - this.label = new St.Label({text: this.markup || this.text}); - this.label.clutter_text.line_wrap = true; - this.label.clutter_text.line_wrap_mode = Pango.WrapMode.WORD; - this.label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; - this.label.clutter_text.use_markup = (this.markup); - this._bin.child.add_child(this.label); - } - - Main.layoutManager.uiGroup.add_child(this._bin); - Main.layoutManager.uiGroup.set_child_above_sibling(this._bin, null); - } else if (this.custom) { - this._bin.child = this.custom; - } else { - if (this._bin.child.icon) - this._bin.child.icon.destroy(); - - if (this.gicon) { - this._bin.child.icon = new St.Icon({gicon: this.gicon}); - this._bin.child.insert_child_at_index(this._bin.child.icon, 0); - } - - this.label.clutter_text.text = this.markup || this.text; - this.label.clutter_text.use_markup = (this.markup); - } - - // Position tooltip - let [x, y] = this.parent.get_transformed_position(); - x = (x + (this.parent.width / 2)) - Math.round(this._bin.width / 2); - - x += this.x_offset; - y += this.y_offset; - - // Show tooltip - if (this._showing) { - this._bin.ease({ - x: x, - y: y, - time: 0.15, - transition: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } else { - this._bin.set_position(x, y); - this._bin.ease({ - opacity: 232, - time: 0.15, - transition: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - - this._showing = true; - } - - // Enable browse mode - TOOLTIP_BROWSE_MODE = true; - - if (TOOLTIP_BROWSE_ID) { - GLib.source_remove(TOOLTIP_BROWSE_ID); - TOOLTIP_BROWSE_ID = 0; - } - - if (this._hoverTimeoutId) { - GLib.source_remove(this._hoverTimeoutId); - this._hoverTimeoutId = 0; - } - } - - _hide() { - if (this._bin) { - this._bin.ease({ - opacity: 0, - time: 0.10, - transition: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - Main.layoutManager.uiGroup.remove_actor(this._bin); - - if (this.custom) - this._bin.remove_child(this.custom); - - this._bin.destroy(); - this._bin = null; - }, - }); - } - - GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => { - TOOLTIP_BROWSE_MODE = false; - TOOLTIP_BROWSE_ID = 0; - return false; - }); - - if (this._hoverTimeoutId) { - GLib.source_remove(this._hoverTimeoutId); - this._hoverTimeoutId = 0; - } - - this._showing = false; - this._hoverTimeoutId = 0; - } - - _onHover() { - if (this.parent.hover) { - if (!this._hoverTimeoutId) { - if (this._showing) { - this._show(); - } else { - this._hoverTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - (TOOLTIP_BROWSE_MODE) ? 60 : 500, - () => { - this._show(); - this._hoverTimeoutId = 0; - return false; - } - ); - } - } - } else { - this._hide(); - } - } - - destroy() { - this.parent.disconnect(this._destroyId); - this.parent.disconnect(this._hoverId); - this.parent.disconnect(this._buttonPressEventId); - - if (this.custom) - this.custom.destroy(); - - if (this._bin) { - Main.layoutManager.uiGroup.remove_actor(this._bin); - this._bin.destroy(); - } - - if (this._hoverTimeoutId) { - GLib.source_remove(this._hoverTimeoutId); - this._hoverTimeoutId = 0; - } - } -}; - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/utils.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/utils.js deleted file mode 100644 index a16f73b..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/shell/utils.js +++ /dev/null @@ -1,218 +0,0 @@ -'use strict'; - -const ByteArray = imports.byteArray; - -const GLib = imports.gi.GLib; -const Gio = imports.gi.Gio; - -const Extension = imports.misc.extensionUtils.getCurrentExtension(); -const Config = Extension.imports.config; - - -/** - * Get a themed icon, using fallbacks from GSConnect's GResource when necessary. - * - * @param {string} name - A themed icon name - * @return {Gio.Icon} A themed icon - */ -function getIcon(name) { - if (getIcon._resource === undefined) { - // Setup the desktop icons - const settings = imports.gi.St.Settings.get(); - getIcon._desktop = new imports.gi.Gtk.IconTheme(); - getIcon._desktop.set_custom_theme(settings.gtk_icon_theme); - settings.connect('notify::gtk-icon-theme', (settings_, key_) => { - getIcon._desktop.set_custom_theme(settings_.gtk_icon_theme); - }); - - // Preload our fallbacks - const iconPath = 'resource://org/gnome/Shell/Extensions/GSConnect/icons'; - const iconNames = [ - 'org.gnome.Shell.Extensions.GSConnect', - 'org.gnome.Shell.Extensions.GSConnect-symbolic', - 'computer-symbolic', - 'laptop-symbolic', - 'smartphone-symbolic', - 'tablet-symbolic', - 'tv-symbolic', - 'phonelink-ring-symbolic', - 'sms-symbolic', - ]; - - getIcon._resource = {}; - - for (const iconName of iconNames) { - getIcon._resource[iconName] = new Gio.FileIcon({ - file: Gio.File.new_for_uri(`${iconPath}/${iconName}.svg`), - }); - } - } - - // Check the desktop icon theme - if (getIcon._desktop.has_icon(name)) - return new Gio.ThemedIcon({name: name}); - - // Check our GResource - if (getIcon._resource[name] !== undefined) - return getIcon._resource[name]; - - // Fallback to hoping it's in the theme somewhere - return new Gio.ThemedIcon({name: name}); -} - - -/** - * Get the contents of a GResource file, replacing `@PACKAGE_DATADIR@` where - * necessary. - * - * @param {string} relativePath - A path relative to GSConnect's resource path - * @return {string} The file contents as a string - */ -function getResource(relativePath) { - try { - const bytes = Gio.resources_lookup_data( - GLib.build_filenamev([Config.APP_PATH, relativePath]), - Gio.ResourceLookupFlags.NONE - ); - - const source = ByteArray.toString(bytes.toArray()); - - return source.replace('@PACKAGE_DATADIR@', Config.PACKAGE_DATADIR); - } catch (e) { - logError(e, 'GSConnect'); - return null; - } -} - - -/** - * Install file contents, to an absolute directory path. - * - * @param {string} dirname - An absolute directory path - * @param {string} basename - The file name - * @param {string} contents - The file contents - * @return {boolean} A success boolean - */ -function _installFile(dirname, basename, contents) { - try { - const filename = GLib.build_filenamev([dirname, basename]); - GLib.mkdir_with_parents(dirname, 0o755); - - return GLib.file_set_contents(filename, contents); - } catch (e) { - logError(e, 'GSConnect'); - return false; - } -} - -/** - * Install file contents from a GResource, to an absolute directory path. - * - * @param {string} dirname - An absolute directory path - * @param {string} basename - The file name - * @param {string} relativePath - A path relative to GSConnect's resource path - * @return {boolean} A success boolean - */ -function _installResource(dirname, basename, relativePath) { - try { - const contents = getResource(relativePath); - - return _installFile(dirname, basename, contents); - } catch (e) { - logError(e, 'GSConnect'); - return false; - } -} - - -/** - * Install the files necessary for the GSConnect service to run. - */ -function installService() { - const confDir = GLib.get_user_config_dir(); - const dataDir = GLib.get_user_data_dir(); - const homeDir = GLib.get_home_dir(); - - // DBus Service - const dbusDir = GLib.build_filenamev([dataDir, 'dbus-1', 'services']); - const dbusFile = `${Config.APP_ID}.service`; - - // Desktop Entry - const appDir = GLib.build_filenamev([dataDir, 'applications']); - const appFile = `${Config.APP_ID}.desktop`; - const appPrefsFile = `${Config.APP_ID}.Preferences.desktop`; - - // Application Icon - const iconDir = GLib.build_filenamev([dataDir, 'icons', 'hicolor', 'scalable', 'apps']); - const iconFull = `${Config.APP_ID}.svg`; - const iconSym = `${Config.APP_ID}-symbolic.svg`; - - // File Manager Extensions - const fileManagers = [ - [`${dataDir}/nautilus-python/extensions`, 'nautilus-gsconnect.py'], - [`${dataDir}/nemo-python/extensions`, 'nemo-gsconnect.py'], - ]; - - // WebExtension Manifests - const manifestFile = 'org.gnome.shell.extensions.gsconnect.json'; - const google = getResource(`webextension/${manifestFile}.google.in`); - const mozilla = getResource(`webextension/${manifestFile}.mozilla.in`); - const manifests = [ - [`${confDir}/chromium/NativeMessagingHosts/`, google], - [`${confDir}/google-chrome/NativeMessagingHosts/`, google], - [`${confDir}/google-chrome-beta/NativeMessagingHosts/`, google], - [`${confDir}/google-chrome-unstable/NativeMessagingHosts/`, google], - [`${confDir}/BraveSoftware/Brave-Browser/NativeMessagingHosts/`, google], - [`${homeDir}/.mozilla/native-messaging-hosts/`, mozilla], - [`${homeDir}/.config/microsoft-edge-dev/NativeMessagingHosts`, google], - [`${homeDir}/.config/microsoft-edge-beta/NativeMessagingHosts`, google], - ]; - - // If running as a user extension, ensure the DBus service, desktop entry, - // file manager scripts, and WebExtension manifests are installed. - if (Config.IS_USER) { - // DBus Service - if (!_installResource(dbusDir, dbusFile, `${dbusFile}.in`)) - throw Error('GSConnect: Failed to install DBus Service'); - - // Desktop Entries - _installResource(appDir, appFile, appFile); - _installResource(appDir, appPrefsFile, appPrefsFile); - - // Application Icon - _installResource(iconDir, iconFull, `icons/${iconFull}`); - _installResource(iconDir, iconSym, `icons/${iconSym}`); - - // File Manager Extensions - const target = `${Config.PACKAGE_DATADIR}/nautilus-gsconnect.py`; - - for (const [dir, name] of fileManagers) { - const script = Gio.File.new_for_path(GLib.build_filenamev([dir, name])); - - if (!script.query_exists(null)) { - GLib.mkdir_with_parents(dir, 0o755); - script.make_symbolic_link(target, null); - } - } - - // WebExtension Manifests - for (const [dirname, contents] of manifests) - _installFile(dirname, manifestFile, contents); - - // Otherwise, if running as a system extension, ensure anything previously - // installed when running as a user extension is removed. - } else { - GLib.unlink(GLib.build_filenamev([dbusDir, dbusFile])); - GLib.unlink(GLib.build_filenamev([appDir, appFile])); - GLib.unlink(GLib.build_filenamev([appDir, appPrefsFile])); - GLib.unlink(GLib.build_filenamev([iconDir, iconFull])); - GLib.unlink(GLib.build_filenamev([iconDir, iconSym])); - - for (const [dir, name] of fileManagers) - GLib.unlink(GLib.build_filenamev([dir, name])); - - for (const manifest of manifests) - GLib.unlink(GLib.build_filenamev([manifest[0], manifestFile])); - } -} - diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/stylesheet.css b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/stylesheet.css deleted file mode 100644 index 77d1cac..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/stylesheet.css +++ /dev/null @@ -1,122 +0,0 @@ - -/* Device Menu - -PopupMenu.PopupMenuSection.gsconnect-device-section - PopupMenu.PopupMenuSection.gsconnect-device-menu - PopupMenu.PopupSeparatorMenuItem - StLabel.gsconnect-device-name - StBoxLayout.gsconnect-device-battery - PopupMenu.PopupMenuSection - StBoxLayout.gsconnect-list-box - StBoxLayout (Submenu Container) -*/ -.gsconnect-device-section { -} - -/* Title Bar */ -.gsconnect-device-name { - font-weight: bold; -} - -.gsconnect-device-menu .popup-separator-menu-item { - margin-left: 0; - margin-right: 0; -} - -/* Battery Widget */ -.gsconnect-device-battery { - spacing: 3px; -} - -.gsconnect-device-battery StLabel { - font-size: 0.75em; -} - -.gsconnect-device-battery StIcon { - icon-size: 16px; -} - -/* Signal Strength Widget */ -.gsconnect-device-signal-strength { - spacing: 3px; -} - -.gsconnect-device-signal-strength StLabel { - font-size: 0.75em; -} - -.gsconnect-device-signal-strength StIcon { - icon-size: 16px; -} - -/* List Box */ -.gsconnect-list-box { -} - - -/* Device Panel Indicator - -PanelMenu.Button.gsconnect-device-indicator - PopupMenu.PopupMenu - PopupMenu.PopupMenuSection.gsconnect-device-menu - PopupMenu.PopupSeparatorMenuItem - StLabel.gsconnect-device-name - StBoxLayout.gsconnect-device-battery - PopupMenu.PopupMenuSection - StBoxLayout.gsconnect-icon-box - StBoxLayout (Submenu Container) - */ -.gsconnect-device-indicator { - -st-icon-style: symbolic; -} - -/* Icon Box */ -.gsconnect-icon-box { - margin: 0em 2em 0.5em; - spacing: 6px; -} - -.gsconnect-icon-button { - border-radius: 1em; - padding: 0.5em; -} - -.gsconnect-icon-button:hover, .gsconnect-icon-button:focus { - background-color: rgba(255, 255, 255, 0.125); -} - -.gsconnect-icon-button StIcon { - icon-size: 1em; -} - - -/* Tooltip - -StBin.gsconnect-tooltip (inherits from .osd-window) - StBoxLayout || [ Custom ClutterActor ] - StIcon - StLabel -*/ -.gsconnect-tooltip { - border-radius: 3px; - min-width: 0; - min-height: 0; - padding: 6px; -} - -.gsconnect-tooltip > StBoxLayout { - spacing: 6px; -} - -.gsconnect-tooltip StIcon { - icon-size: 16px; -} - -.gsconnect-tooltip StLabel { - font-weight: normal; - text-align: left; -} - -.gsconnect-tooltip StLabel:rtl { - text-align: right; -} diff --git a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/utils/remote.js b/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/utils/remote.js deleted file mode 100644 index 7a1c27b..0000000 --- a/.local/share/gnome-shell/extensions/gsconnect@andyholmes.github.io/utils/remote.js +++ /dev/null @@ -1,516 +0,0 @@ -'use strict'; - -const Gio = imports.gi.Gio; -const GLib = imports.gi.GLib; -const GObject = imports.gi.GObject; - -const SERVICE_NAME = 'org.gnome.Shell.Extensions.GSConnect'; -const SERVICE_PATH = '/org/gnome/Shell/Extensions/GSConnect'; -const DEVICE_NAME = 'org.gnome.Shell.Extensions.GSConnect.Device'; -const DEVICE_PATH = '/org/gnome/Shell/Extensions/GSConnect/Device'; - - -const _PROPERTIES = { - 'Connected': 'connected', - 'EncryptionInfo': 'encryption-info', - 'IconName': 'icon-name', - 'Id': 'id', - 'Name': 'name', - 'Paired': 'paired', - 'Type': 'type', -}; - - -function _proxyInit(proxy, cancellable = null) { - if (proxy.__initialized !== undefined) - return Promise.resolve(); - - return new Promise((resolve, reject) => { - proxy.init_async( - GLib.PRIORITY_DEFAULT, - cancellable, - (proxy, res) => { - try { - proxy.init_finish(res); - proxy.__initialized = true; - resolve(); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); -} - - -/** - * A simple proxy wrapper for devices exported over DBus. - */ -var Device = GObject.registerClass({ - GTypeName: 'GSConnectRemoteDevice', - Implements: [Gio.DBusInterface], - Properties: { - 'connected': GObject.ParamSpec.boolean( - 'connected', - 'Connected', - 'Whether the device is connected', - GObject.ParamFlags.READABLE, - null - ), - 'encryption-info': GObject.ParamSpec.string( - 'encryption-info', - 'Encryption Info', - 'A formatted string with the local and remote fingerprints', - GObject.ParamFlags.READABLE, - null - ), - 'icon-name': GObject.ParamSpec.string( - 'icon-name', - 'Icon Name', - 'Icon name representing the device', - GObject.ParamFlags.READABLE, - null - ), - 'id': GObject.ParamSpec.string( - 'id', - 'deviceId', - 'The device hostname or other unique id', - GObject.ParamFlags.READABLE, - '' - ), - 'name': GObject.ParamSpec.string( - 'name', - 'deviceName', - 'The device name', - GObject.ParamFlags.READABLE, - null - ), - 'paired': GObject.ParamSpec.boolean( - 'paired', - 'Paired', - 'Whether the device is paired', - GObject.ParamFlags.READABLE, - null - ), - 'type': GObject.ParamSpec.string( - 'type', - 'deviceType', - 'The device type', - GObject.ParamFlags.READABLE, - null - ), - }, -}, class Device extends Gio.DBusProxy { - - _init(service, object_path) { - this._service = service; - - super._init({ - g_connection: service.g_connection, - g_name: SERVICE_NAME, - g_object_path: object_path, - g_interface_name: DEVICE_NAME, - }); - } - - vfunc_g_properties_changed(changed, invalidated) { - try { - for (const name in changed.deepUnpack()) - this.notify(_PROPERTIES[name]); - } catch (e) { - logError(e); - } - } - - _get(name, fallback = null) { - try { - return this.get_cached_property(name).unpack(); - } catch (e) { - return fallback; - } - } - - get connected() { - return this._get('Connected', false); - } - - get encryption_info() { - return this._get('EncryptionInfo', ''); - } - - get icon_name() { - return this._get('IconName', 'computer'); - } - - get id() { - return this._get('Id', '0'); - } - - get name() { - return this._get('Name', 'Unknown'); - } - - get paired() { - return this._get('Paired', false); - } - - get service() { - return this._service; - } - - get type() { - return this._get('Type', 'desktop'); - } - - async start() { - try { - await _proxyInit(this); - - // For GActions & GMenu we pass the service's name owner to avoid - // any mixup with instances. - this.action_group = Gio.DBusActionGroup.get( - this.g_connection, - this.service.g_name_owner, - this.g_object_path - ); - - this.menu = Gio.DBusMenuModel.get( - this.g_connection, - this.service.g_name_owner, - this.g_object_path - ); - - // Poke the GMenu to ensure it's ready for us - await new Promise((resolve, reject) => { - this.g_connection.call( - SERVICE_NAME, - this.g_object_path, - 'org.gtk.Menus', - 'Start', - new GLib.Variant('(au)', [[0]]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (proxy, res) => { - try { - resolve(proxy.call_finish(res)); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); - } catch (e) { - this.destroy(); - throw e; - } - } - - destroy() { - GObject.signal_handlers_destroy(this); - } -}); - - -/** - * A simple proxy wrapper for the GSConnect service. - */ -var Service = GObject.registerClass({ - GTypeName: 'GSConnectRemoteService', - Implements: [Gio.DBusInterface], - Properties: { - 'active': GObject.ParamSpec.boolean( - 'active', - 'Active', - 'Whether the service is active', - GObject.ParamFlags.READABLE, - false - ), - }, - Signals: { - 'device-added': { - flags: GObject.SignalFlags.RUN_FIRST, - param_types: [Device.$gtype], - }, - 'device-removed': { - flags: GObject.SignalFlags.RUN_FIRST, - param_types: [Device.$gtype], - }, - }, -}, class Service extends Gio.DBusProxy { - - _init() { - super._init({ - g_bus_type: Gio.BusType.SESSION, - g_name: SERVICE_NAME, - g_object_path: SERVICE_PATH, - g_interface_name: 'org.freedesktop.DBus.ObjectManager', - g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START_AT_CONSTRUCTION, - }); - - this._active = false; - this._devices = new Map(); - this._starting = false; - - // Watch the service - this._nameOwnerChangedId = this.connect( - 'notify::g-name-owner', - this._onNameOwnerChanged.bind(this) - ); - } - - get active() { - return this._active; - } - - get devices() { - return Array.from(this._devices.values()); - } - - vfunc_g_signal(sender_name, signal_name, parameters) { - try { - // Don't emit signals until the ObjectManager has started - if (!this.active) - return; - - parameters = parameters.deepUnpack(); - - switch (true) { - case (signal_name === 'InterfacesAdded'): - this._onInterfacesAdded(...parameters); - break; - - case (signal_name === 'InterfacesRemoved'): - this._onInterfacesRemoved(...parameters); - break; - } - } catch (e) { - logError(e); - } - } - - /** - * org.freedesktop.DBus.ObjectManager.InterfacesAdded - * - * @param {string} object_path - Path interfaces have been added to - * @param {Object} interfaces - A dictionary of interface objects - */ - async _onInterfacesAdded(object_path, interfaces) { - try { - // An empty list means only the object has been added - if (Object.values(interfaces).length === 0) - return; - - // Skip existing proxies - if (this._devices.has(object_path)) - return; - - // Create a proxy - const device = new Device(this, object_path); - await device.start(); - - // Hold the proxy and emit ::device-added - this._devices.set(object_path, device); - this.emit('device-added', device); - } catch (e) { - logError(e, object_path); - } - } - - /** - * org.freedesktop.DBus.ObjectManager.InterfacesRemoved - * - * @param {string} object_path - Path interfaces have been removed from - * @param {string[]} interfaces - List of interface names removed - */ - _onInterfacesRemoved(object_path, interfaces) { - try { - // An empty interface list means the object is being removed - if (interfaces.length === 0) - return; - - // Get the proxy - const device = this._devices.get(object_path); - - if (device === undefined) - return; - - // Release the proxy and emit ::device-removed - this._devices.delete(object_path); - this.emit('device-removed', device); - - // Destroy the device and force disposal - device.destroy(); - } catch (e) { - logError(e, object_path); - } - } - - async _addDevices() { - const objects = await new Promise((resolve, reject) => { - this.call( - 'GetManagedObjects', - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (proxy, res) => { - try { - const variant = proxy.call_finish(res); - resolve(variant.deepUnpack()[0]); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); - - for (const [object_path, object] of Object.entries(objects)) - await this._onInterfacesAdded(object_path, object); - } - - _clearDevices() { - for (const [object_path, device] of this._devices) { - this._devices.delete(object_path); - this.emit('device-removed', device); - device.destroy(); - } - } - - async _onNameOwnerChanged() { - try { - // If the service stopped, remove each device and mark it inactive - if (this.g_name_owner === null) { - this._clearDevices(); - - this._active = false; - this.notify('active'); - - // If the service started, mark it active and add each device - } else { - this._active = true; - this.notify('active'); - - await this._addDevices(); - } - } catch (e) { - logError(e); - } - } - - /** - * Reload all devices without affecting the remote service. This amounts to - * removing and adding each device while emitting the appropriate signals. - */ - async reload() { - try { - if (this._starting === false) { - this._starting = true; - - this._clearDevices(); - await _proxyInit(this); - await this._onNameOwnerChanged(); - - this._starting = false; - } - } catch (e) { - this._starting = false; - throw e; - } - } - - /** - * Start the service - */ - async start() { - try { - if (this._starting === false && this.active === false) { - this._starting = true; - - await _proxyInit(this); - await this._onNameOwnerChanged(); - - // Activate the service if it's not already running - if (!this.active) { - await new Promise((resolve, reject) => { - this.g_connection.call( - SERVICE_NAME, - SERVICE_PATH, - 'org.freedesktop.Application', - 'Activate', - GLib.Variant.new('(a{sv})', [{}]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - (proxy, res) => { - try { - resolve(proxy.call_finish(res)); - } catch (e) { - Gio.DBusError.strip_remote_error(e); - reject(e); - } - } - ); - }); - } - - this._starting = false; - } - } catch (e) { - this._starting = false; - throw e; - } - } - - /** - * Stop the service - */ - stop() { - if (this.active) - this.activate_action('quit'); - } - - activate_action(name, parameter = null) { - try { - const paramArray = []; - - if (parameter instanceof GLib.Variant) - paramArray[0] = parameter; - - const connection = this.g_connection || Gio.DBus.session; - - connection.call( - SERVICE_NAME, - SERVICE_PATH, - 'org.freedesktop.Application', - 'ActivateAction', - GLib.Variant.new('(sava{sv})', [name, paramArray, {}]), - null, - Gio.DBusCallFlags.NONE, - -1, - null, - null - ); - } catch (e) { - logError(e); - } - } - - destroy() { - if (this._nameOwnerChangedId > 0) { - this.disconnect(this._nameOwnerChangedId); - this._nameOwnerChangedId = 0; - - this._clearDevices(); - this._active = false; - - GObject.signal_handlers_destroy(this); - } - } -}); - diff --git a/.local/share/gnome-shell/extensions/instantworkspaceswitcher@amalantony.net/extension.js b/.local/share/gnome-shell/extensions/instantworkspaceswitcher@amalantony.net/extension.js deleted file mode 100644 index 952abba..0000000 --- a/.local/share/gnome-shell/extensions/instantworkspaceswitcher@amalantony.net/extension.js +++ /dev/null @@ -1,47 +0,0 @@ -/* extension.js - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -/* exported init */ - -const WorkspaceAnimation = imports.ui.workspaceAnimation; - -class Extension { - constructor() { - this.oldAnimateSwitch = - WorkspaceAnimation.WorkspaceAnimationController.prototype.animateSwitch; - } - - enable() { - WorkspaceAnimation.WorkspaceAnimationController.prototype.animateSwitch = function ( - _from, - _to, - _direction, - onComplete - ) { - onComplete(); - }; - } - - disable() { - WorkspaceAnimation.WorkspaceAnimationController.prototype.animateSwitch = this.oldAnimateSwitch; - } -} - -function init() { - return new Extension(); -} diff --git a/.local/share/gnome-shell/extensions/instantworkspaceswitcher@amalantony.net/metadata.json b/.local/share/gnome-shell/extensions/instantworkspaceswitcher@amalantony.net/metadata.json deleted file mode 100644 index 56094ae..0000000 --- a/.local/share/gnome-shell/extensions/instantworkspaceswitcher@amalantony.net/metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Disables the workspace switch animation while preserving all other animations - instantly switch between workspaces with keyboard shortcuts.", - "name": "Disable Workspace Switch Animation for GNOME 40+", - "shell-version": [ - "40", - "41" - ], - "url": "https://github.com/amalantony/gnome-shell-extension-instant-workspace-switcher", - "uuid": "instantworkspaceswitcher@amalantony.net", - "version": 3 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/convenience.js b/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/convenience.js deleted file mode 100644 index bbc8608..0000000 --- a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/convenience.js +++ /dev/null @@ -1,93 +0,0 @@ -/* -*- mode: js; js-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* - Copyright (c) 2011-2012, Giovanni Campagna <scampa.giovanni@gmail.com> - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the GNOME nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -const Gettext = imports.gettext; -const Gio = imports.gi.Gio; - -const Config = imports.misc.config; -const ExtensionUtils = imports.misc.extensionUtils; - -/** - * initTranslations: - * @domain: (optional): the gettext domain to use - * - * Initialize Gettext to load translations from extensionsdir/locale. - * If @domain is not provided, it will be taken from metadata['gettext-domain'] - */ -function initTranslations(domain) { - let extension = ExtensionUtils.getCurrentExtension(); - - domain = domain || extension.metadata['gettext-domain']; - - // check if this extension was built with "make zip-file", and thus - // has the locale files in a subfolder - // otherwise assume that extension has been installed in the - // same prefix as gnome-shell - let localeDir = extension.dir.get_child('locale'); - if (localeDir.query_exists(null)) - Gettext.bindtextdomain(domain, localeDir.get_path()); - else - Gettext.bindtextdomain(domain, Config.LOCALEDIR); -} - -/** - * getSettings: - * @schema: (optional): the GSettings schema id - * - * Builds and return a GSettings schema for @schema, using schema files - * in extensionsdir/schemas. If @schema is not provided, it is taken from - * metadata['settings-schema']. - */ -function getSettings(schema) { - let extension = ExtensionUtils.getCurrentExtension(); - - schema = schema || extension.metadata['settings-schema']; - - const GioSSS = Gio.SettingsSchemaSource; - - // check if this extension was built with "make zip-file", and thus - // has the schema files in a subfolder - // otherwise assume that extension has been installed in the - // same prefix as gnome-shell (and therefore schemas are available - // in the standard folders) - let schemaDir = extension.dir.get_child('schemas'); - let schemaSource; - if (schemaDir.query_exists(null)) - schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), - GioSSS.get_default(), - false); - else - schemaSource = GioSSS.get_default(); - - let schemaObj = schemaSource.lookup(schema, true); - if (!schemaObj) - throw new Error('Schema ' + schema + ' could not be found for extension ' - + extension.metadata.uuid + '. Please check your installation.'); - - return new Gio.Settings({ settings_schema: schemaObj }); -} - diff --git a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/extension.js b/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/extension.js deleted file mode 100644 index 4913a2a..0000000 --- a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/extension.js +++ /dev/null @@ -1,71 +0,0 @@ -// gpl v3 -// Based on: -// https://github.com/maoschanz/Move-OSD-Windows-GNOME-Extension/issues/2 --> Thank you @maoschanz -// https://discourse.gnome.org/t/how-can-i-move-the-workspace-switcher-popup-to-the-right/6940 --> Thank you @GdH - -const Main = imports.ui.main; -const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Convenience = Me.imports.convenience; - -let initWSP; - -function init() { - Convenience.initTranslations(); - initWSP = WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype._show; -} - -//------------------------------------------------------------------------------ - -function injectToFunction(parent, name, func) { - let origin = parent[name]; - parent[name] = function() { - let ret; - ret = origin.apply(this, arguments); - if (ret === undefined) - ret = func.apply(this, arguments); - return ret; - } - return origin; -} - -function removeInjection(object, injection, name) { - if (injection[name] === undefined) - delete object[name]; - else - object[name] = injection[name]; -} - -let injections=[]; - -//------------------------------------------------------------------------------ - -function enable() { - let settings = Convenience.getSettings('org.gnome.shell.extensions.move-workspaceSwitcherPopup'); - - injections['_redisplay'] = injectToFunction( - WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype, '_redisplay', function() { - - if(settings.get_boolean('hide')) { - WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype._show = function() { return false }; - } else { - WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype._show = initWSP; - let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex); - let [, containerNatHeight] = this._container.get_preferred_height(global.screen_width); - let [, containerNatWidth] = this._container.get_preferred_width(containerNatHeight); - let h_percent = settings.get_int('horizontal'); - let v_percent = settings.get_int('vertical'); - - this._container.x = workArea.x + Math.floor((workArea.width - containerNatWidth) * (h_percent/100)); - this._container.y = workArea.y + Math.floor((workArea.height - containerNatHeight) * (v_percent/100)); - } - } - ); -} - -function disable() { - WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype._show = initWSP; - removeInjection(WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype, injections, '_redisplay'); -} diff --git a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/metadata.json b/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/metadata.json deleted file mode 100644 index fc7e78c..0000000 --- a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/metadata.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Change the position of the WorkspaceSwitcherPopup", - "gettext-domain": "move-workspaceswitcherpopup", - "name": "Move Workspace Switcher Popup", - "shell-version": [ - "3.36", - "3.38", - "40" - ], - "url": "https://github.com/GithubUser699/Move-workspaceSwitcherPopup-GNOME-Extension", - "uuid": "move-workspaceSwitcherPopup@GithubUser699.github.com", - "version": 3 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/prefs.js b/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/prefs.js deleted file mode 100644 index 047b3f4..0000000 --- a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/prefs.js +++ /dev/null @@ -1,140 +0,0 @@ - -const GObject = imports.gi.GObject; -const Gtk = imports.gi.Gtk; - -const Gettext = imports.gettext.domain('move-workspaceswitcherpopup'); -const _ = Gettext.gettext; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Convenience = Me.imports.convenience; - -//------------------------------------------------------------------------------ -const WSPSettingsWidget = GObject.registerClass( -class WSPSettingsWidget extends Gtk.Grid { - - _init() { - super._init({ - row_homogeneous: true, - margin_top: 25, - margin_bottom: 25, - margin_start: 25, - margin_end: 25, - row_spacing: 30, - column_spacing: 20, - halign: Gtk.Align.FILL, - visible: true - }); - - this.SETTINGS = Convenience.getSettings('org.gnome.shell.extensions.move-workspaceSwitcherPopup'); - - //---------------------------------------------------------------------- - - let horizontalPercentageLabel = new Gtk.Label({ - label: _("Horizontal position (percentage)"), - use_markup: true, - halign: Gtk.Align.START, - visible: true - }); - - let horizontalPercentage = new Gtk.Scale({ - orientation: Gtk.Orientation.HORIZONTAL, - draw_value: true, - has_origin: false, - digits: 0, - halign: Gtk.Align.FILL, - hexpand: true, - visible: true - }); - - horizontalPercentage.add_mark(50, Gtk.PositionType.BOTTOM, null); - horizontalPercentage.set_range(0, 100); - horizontalPercentage.set_value(this.SETTINGS.get_int('horizontal')); - horizontalPercentage.set_increments(1, 1); - - horizontalPercentage.connect('value-changed', function(w) { - var value = w.get_value(); - this.SETTINGS.set_int('horizontal', value); - }.bind(this)); - - //---------------------------------------------------------------------- - - let verticalPercentageLabel = new Gtk.Label({ - label: _("Vertical position (percentage)"), - use_markup: true, - halign: Gtk.Align.START, - visible: true - }); - - let verticalPercentage = new Gtk.Scale({ - orientation: Gtk.Orientation.VERTICAL, - draw_value: true, - has_origin: false, - value_pos: Gtk.PositionType.LEFT, - digits: 0, - valign: Gtk.Align.FILL, - halign: Gtk.Align.CENTER, - hexpand: false, - vexpand: true, - visible: true - }); - - verticalPercentage.add_mark(50, Gtk.PositionType.RIGHT, null); - verticalPercentage.set_range(0, 100); - verticalPercentage.set_value(this.SETTINGS.get_int('vertical')); - verticalPercentage.set_increments(1, 1); - - verticalPercentage.connect('value-changed', function(w) { - var value = w.get_value(); - this.SETTINGS.set_int('vertical', value); - }.bind(this)); - - //---------------------------------------------------------------------- - - let hideSwitchLabel = new Gtk.Label({ - label: _("Hide Workspace Switcher Popup Window"), - use_markup: true, - halign: Gtk.Align.START, - visible: true - }); - - let hideSwitch = new Gtk.Switch({ - visible: true, - hexpand: true, - halign: Gtk.Align.CENTER, - valign: Gtk.Align.CENTER - }); - - hideSwitch.set_state(false); - hideSwitch.set_halign(Gtk.Align.START) - hideSwitch.set_state(this.SETTINGS.get_boolean('hide')); - - hideSwitch.connect('notify::active', function(widget) { - this.SETTINGS.set_boolean('hide', widget.active); - }.bind(this)); - - //---------------------------------------------------------------------- - - this.attach(horizontalPercentageLabel, 0, 0, 1, 1); - this.attach(horizontalPercentage, 1, 0, 1, 1); - this.attach(verticalPercentageLabel, 0, 1, 1, 2); - this.attach(verticalPercentage, 1, 1, 1, 2); - this.attach(hideSwitchLabel, 0, 3, 1, 1); - this.attach(hideSwitch, 1, 3, 1, 1); - } -}); - -//------------------------------------------------------------------------------ - -function init() { - Convenience.initTranslations(); -} - -// This is like the "enable" in extension.js : something called each time the -// user tries to access the settings' window -function buildPrefsWidget() { - let widget = new WSPSettingsWidget(); - - return widget; -} - diff --git a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/schemas/gschemas.compiled b/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/schemas/gschemas.compiled deleted file mode 100644 index fc0b522..0000000 Binary files a/.local/share/gnome-shell/extensions/move-workspaceSwitcherPopup@GithubUser699.github.com/schemas/gschemas.compiled and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/notification-position@drugo.dev/extension.js b/.local/share/gnome-shell/extensions/notification-position@drugo.dev/extension.js deleted file mode 100644 index 6e790bb..0000000 --- a/.local/share/gnome-shell/extensions/notification-position@drugo.dev/extension.js +++ /dev/null @@ -1,57 +0,0 @@ -'use strict'; - -// This is a handy import we'll use to grab our extension's object -const Main = imports.ui.main; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -// Like `init()` below, code *here* in the top-level of your script is executed -// when your extension is loaded. You MUST NOT make any changes to GNOME Shell -// here and typically you should do nothing but assign variables. -const PADDING = 20; -const monitorWidth = Main.layoutManager.primaryMonitor.width; -const monitorHeight = Main.layoutManager.primaryMonitor.height; -const messageListWidth = Main.panel.statusArea.dateMenu._messageList.actor.width; -const messageListHeight = Main.panel.statusArea.dateMenu._messageList.actor.height; - -// This function is called once when your extension is loaded, not enabled. This -// is a good time to setup translations or anything else you only do once. -// -// You MUST NOT make any changes to GNOME Shell, connect any signals or add any -// MainLoop sources here. -function init() { - log(`initializing ${Me.metadata.name} version ${Me.metadata.version}`); -} - -function left() -{ - return - monitorWidth + messageListWidth + PADDING; -} - -function right() -{ - return monitorWidth - messageListWidth - PADDING; -} - -// This function could be called after your extension is enabled, which could -// be done from GNOME Tweaks, when you log in or when the screen is unlocked. -// -// This is when you setup any UI for your extension, change existing widgets, -// connect signals or modify GNOME Shell's behaviour. -function enable() { - log(`enabling ${Me.metadata.name} version ${Me.metadata.version}`); - - Main.messageTray._bannerBin.x = right(); -} - -// This function could be called after your extension is uninstalled, disabled -// in GNOME Tweaks, when you log out or when the screen locks. -// -// Anything you created, modifed or setup in enable() MUST be undone here. Not -// doing so is the most common reason extensions are rejected during review! -function disable() { - log(`disabling ${Me.metadata.name} version ${Me.metadata.version}`); - Main.messageTray._bannerBin.x = 0; - Main.messageTray._bannerBin.y = 0; -} - diff --git a/.local/share/gnome-shell/extensions/notification-position@drugo.dev/metadata.json b/.local/share/gnome-shell/extensions/notification-position@drugo.dev/metadata.json deleted file mode 100644 index 4543525..0000000 --- a/.local/share/gnome-shell/extensions/notification-position@drugo.dev/metadata.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Changes position of the notification banner from the default to the right side of the screen.", - "name": "Notification Banner Position", - "shell-version": [ - "3.36", - "3.38", - "40", - "41" - ], - "url": "https://github.com/brunodrugowick/notification-position-gnome-extension", - "uuid": "notification-position@drugo.dev", - "version": 5 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/base.js b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/base.js deleted file mode 100644 index f47c0fd..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/base.js +++ /dev/null @@ -1,729 +0,0 @@ -/******************************************************************************* - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see http://www.gnu.org/licenses/. - * ***************************************************************************** - * Original Author: Gopi Sankar Karmegam - ******************************************************************************/ -/* jshint moz:true */ - -const { GObject, GLib, Gvc } = imports.gi; - -const Signals = imports.signals; - -const PopupMenu = imports.ui.popupMenu; -const VolumeMenu = imports.ui.status.volume; -const Main = imports.ui.main; -const MessageTray = imports.ui.messageTray; - -const Config = imports.misc.config; -const ExtensionUtils = imports.misc.extensionUtils; -const Gettext = imports.gettext; - -const Me = ExtensionUtils.getCurrentExtension(); -const Lib = Me.imports.convenience; -const Prefs = Me.imports.prefs; - -ExtensionUtils.initTranslations(Me.metadata["gettext-domain"]); -const Domain = Gettext.domain(Me.metadata["gettext-domain"]); -const _ = Domain.gettext; -//const _ = Gettext.gettext; -const _d = Lib._log; - -const DISPLAY_OPTIONS = Prefs.DISPLAY_OPTIONS; -const SignalManager = Lib.SignalManager; - -var ProfileMenuItem = class ProfileMenuItem - extends PopupMenu.PopupMenuItem { - constructor(title, profileName) { - super(title); - this._init(title, profileName); - } - - _init(title, profileName) { - if (super._init) { - super._init(title); - } - _d("ProfileMenuItem: _init:" + title); - this.profileName = profileName; - this._ornamentLabel.set_style("min-width: 3em;margin-left: 3em;"); - this.setProfileActive(false); - } - - setProfileActive(active) { - if (active) { - this.setOrnament(PopupMenu.Ornament.DOT); - // this._ornamentLabel.text = "\u2727"; - this._ornamentLabel.text = "\u266A"; - if (this.add_style_pseudo_class) { - this.remove_style_pseudo_class('insensitive'); - } - else { - this.actor.remove_style_pseudo_class('insensitive'); - } - } - else { - this.setOrnament(PopupMenu.Ornament.NONE); - if (this.add_style_pseudo_class) { - this.add_style_pseudo_class('insensitive'); - } - else { - this.actor.add_style_pseudo_class('insensitive'); - } - } - } - - setVisibility(visibility) { - this.actor.visible = visibility; - } -} - -var SoundDeviceMenuItem = class SoundDeviceMenuItem extends PopupMenu.PopupImageMenuItem { - constructor(id, title, icon_name, profiles) { - super(title, icon_name); - this._init(id, title, icon_name, profiles); - } - - _init(id, title, icon_name, profiles) { - if (super._init) { - super._init(title, icon_name); - } - _d("SoundDeviceMenuItem: _init:" + title); - this.id = id; - this.title = title; - this.icon_name = icon_name; - this.profiles = (profiles) ? profiles : []; - - this.profilesitems = new Map(); - for (let profile of this.profiles) { - let profileName = profile.name; - if (!this.profilesitems.has(profileName)) { - let pItem = new ProfileMenuItem(_("Profile: ") + profile.human_name, profileName); - this.profilesitems.set(profileName, pItem); - pItem.connect('activate', () => { - _d("Activating Profile:" + id + profileName); - this.emit("profile-activated", this.id, profileName); - }); - } - } - - this.connect('activate', () => { - _d("Device Change request for " + id); - _d("Emitting Signal..."); - this.emit("device-activated", this.id); - }); - this.available = true; - this.activeProfile = ""; - this.activeDevice = false; - this.visible = false; - this._displayOption = DISPLAY_OPTIONS.INITIAL; - } - - isAvailable() { - return this.available; - } - - setAvailable(_ac) { - this.available = _ac; - } - - setActiveProfile(_p) { - if (_p && this.activeProfile != _p) { - if (this.profilesitems.has(this.activeProfile)) { - this.profilesitems.get(this.activeProfile).setProfileActive(false); - } - this.activeProfile = _p; - if (this.profilesitems.has(_p)) { - this.profilesitems.get(_p).setProfileActive(true); - } - } - } - - setVisibility(_v) { - this.actor.visible = _v; - if (!_v) { - this.profilesitems.forEach((p) => p.setVisibility(false)); - } - this.visible = _v; - }; - - setTitle(_t) { - _d("SoundDeviceMenuItem: " + "setTitle: " + this.title + "->" + _t); - this.title = _t; - this.label.text = _t; - } - - isVisible() { - return this.visible; - } - - setActiveDevice(_a) { - this.activeDevice = _a; - if (!_a) { - this.setOrnament(PopupMenu.Ornament.NONE); - } - else { - this.setOrnament(PopupMenu.Ornament.CHECK); - this._ornamentLabel.text = '\u266B'; - } - } - - setProfileVisibility(_v) { - this.profilesitems.forEach(p => - p.setVisibility(_v && this.canShowProfile())); - } - - canShowProfile() { - return (this.isVisible() && this.profilesitems.size >= 1); - } - - setDisplayOption(displayOption) { - _d("Setting Display Option to : " + displayOption); - this._displayOption = displayOption; - } - - getDisplayOption() { - return this._displayOption; - } -} - -if (parseFloat(Config.PACKAGE_VERSION) >= 3.34) { - ProfileMenuItem = GObject.registerClass({ GTypeName: 'ProfileMenuItem' }, ProfileMenuItem); - - SoundDeviceMenuItem = GObject.registerClass({ - GTypeName: "SoundDeviceMenuItem", - Signals: { - "device-activated": { - param_types: [GObject.TYPE_INT] - }, - "profile-activated": { - param_types: [GObject.TYPE_INT, GObject.TYPE_STRING] - } - } - }, SoundDeviceMenuItem); -} - -var SoundDeviceChooserBase = class SoundDeviceChooserBase { - - constructor(deviceType) { - _d("SDC: init"); - this.menuItem = new PopupMenu.PopupSubMenuMenuItem(_("Extension initialising..."), true); - this.deviceType = deviceType; - this._devices = new Map(); - let _control = this._getMixerControl(); - this._settings = ExtensionUtils.getSettings(); - _d("Constructor:" + deviceType); - - this._setLog(); - this._signalManager = new SignalManager(); - this._signalManager.addSignal(this._settings, "changed::" + Prefs.ENABLE_LOG, this._setLog.bind(this)); - - if (_control.get_state() == Gvc.MixerControlState.READY) { - this._onControlStateChanged(_control); - } - else { - this._controlStateChangeSignal = this._signalManager.addSignal(_control, "state-changed", this._onControlStateChanged.bind(this)); - } - - this._signalManager.addSignal(this.menuItem.menu, "open-state-changed", this._onSubmenuOpenStateChanged.bind(this)); - } - - _getMixerControl() { return VolumeMenu.getMixerControl(); } - - _setLog() { Lib.setLog(this._settings.get_boolean(Prefs.ENABLE_LOG)); } - - _onControlStateChanged(control) { - if (control.get_state() == Gvc.MixerControlState.READY) { - - this._signalManager.addSignal(control, this.deviceType + "-added", this._deviceAdded.bind(this)); - this._signalManager.addSignal(control, this.deviceType + "-removed", this._deviceRemoved.bind(this)); - this._signalManager.addSignal(control, "active-" + this.deviceType + "-update", this._deviceActivated.bind(this)); - - this._signalManager.addSignal(this._settings, "changed::" + Prefs.HIDE_ON_SINGLE_DEVICE, this._setChooserVisibility.bind(this)); - this._signalManager.addSignal(this._settings, "changed::" + Prefs.SHOW_PROFILES, this._setProfileVisibility.bind(this)); - this._signalManager.addSignal(this._settings, "changed::" + Prefs.ICON_THEME, this._setIcons.bind(this)); - this._signalManager.addSignal(this._settings, "changed::" + Prefs.HIDE_MENU_ICONS, this._setIcons.bind(this)); - this._signalManager.addSignal(this._settings, "changed::" + Prefs.PORT_SETTINGS, this._resetDevices.bind(this)); - this._signalManager.addSignal(this._settings, "changed::" + Prefs.OMIT_DEVICE_ORIGIN, this._refreshDeviceTitles.bind(this)); - - this._show_device_signal = Prefs["SHOW_" + this.deviceType.toUpperCase() + "_DEVICES"]; - - this._signalManager.addSignal(this._settings, "changed::" + this._show_device_signal, this._setVisibility.bind(this)); - - this._portsSettings = Prefs.getPortsFromSettings(this._settings); - - /** - * There is no direct way to get all the UI devices from - * mixercontrol. When enabled after shell loads, the signals - * will not be emitted, a simple hack to look for ids, until any - * uidevice is not found. The UI devices are always serialed - * from from 1 to n - */ - - let id = 0; - - let dummyDevice = new Gvc.MixerUIDevice(); - let maxId = dummyDevice.get_id(); - - _d("Max Id:" + maxId); - - while (++id < maxId) { - this._deviceAdded(control, id); - } - let defaultStream = this.getDefaultStream(control); - if (defaultStream) { - let defaultDevice = control.lookup_device_from_stream(defaultStream); - if (defaultDevice) { - this._deviceActivated(control, defaultDevice.get_id()); - } - } - - if (this._controlStateChangeSignal) { - this._controlStateChangeSignal.disconnect(); - delete this._controlStateChangeSignal; - } - this._setVisibility(); - } - } - - _onSubmenuOpenStateChanged(_menu, opened) { - _d(this.deviceType + "-Submenu is now open?: " + opened); - if (opened) { // Actions when submenu is opening - this._setActiveProfile(); - } - else { // Actions when submenu is closing - } - } - - _deviceAdded(control, id, dontcheck) { - let obj = this._devices.get(id); - let uidevice = this.lookupDeviceById(control, id); - - _d("Added - " + id); - - if (!obj) { - if (this._isDeviceInValid(uidevice)) { - return null; - } - - let title = this._getDeviceTitle(uidevice); - - let icon = uidevice.get_icon_name(); - if (icon == null || icon.trim() == "") - icon = this.getDefaultIcon(); - icon = this._getIcon(icon); - - obj = new SoundDeviceMenuItem(id, title, icon, Lib.getProfiles(control, uidevice)); - obj.connect("device-activated", (item, id) => this._changeDeviceBase(id)); - obj.connect("profile-activated", (item, id, name) => this._profileChangeCallback(id, name)); - - this.menuItem.menu.addMenuItem(obj); - obj.profilesitems.forEach(i => this.menuItem.menu.addMenuItem(i)); - - this._devices.set(id, obj); - } - else if (!obj.isAvailable()) - obj.setAvailable(true); - else - return; - - - _d("Device Name:" + obj.title); - - _d("Added: " + id + ":" + uidevice.description + ":" + uidevice.port_name + ":" + uidevice.origin); - - let stream = control.get_stream_from_device(uidevice); - if (stream) { - obj.setActiveProfile(uidevice.get_active_profile()); - } - - if (!dontcheck && !this._canShowDevice(control, uidevice, obj, uidevice.port_available)) { - _d("This device is hidden in settings, lets hide...") - this._deviceRemoved(control, id, true); - } - else { - this._setChooserVisibility(); - this._setVisibility(); - } - } - - _profileChangeCallback(id, profileName) { - let control = this._getMixerControl(); - let uidevice = this.lookupDeviceById(control, id); - if (!uidevice) { - this._deviceRemoved(control, id); - } - else { - _d("i am setting profile, " + profileName + ":" + uidevice.description + ":" + uidevice.port_name); - if (id != this._activeDeviceId) { - _d("Changing active device to " + uidevice.description + ":" + uidevice.port_name); - this._changeDeviceBase(id, control); - } - control.change_profile_on_selected_device(uidevice, profileName); - //this._setDeviceActiveProfile(control, this._devices.get(id)); //"Races" change_profile_...(...) and reports the old state - } - } - - _deviceRemoved(control, id, dontcheck) { - let obj = this._devices.get(id); - - if (obj && obj.isAvailable()) { - _d("Removed: " + id + ":" + obj.title); - /* - let uidevice = this.lookupDeviceById(control,id); - if (!dontcheck && this._canShowDevice(control, uidevice, obj, false)) { - _d('Device removed, but not hiding as its set to be shown always'); - return; - }*/ - obj.setVisibility(false); - obj.setAvailable(false); - - /* - if (this.deviceRemovedTimout) { - GLib.source_remove(this.deviceRemovedTimout); - this.deviceRemovedTimout = null; - } - */ - /** - * If the active uidevice is removed, then need to activate the - * first available uidevice. However for some cases like Headphones, - * when the uidevice is removed, Speakers are automatically - * activated. So, lets wait for sometime before activating. - */ - /* THIS MAY NOT BE NEEDED AS SHELL SEEMS TO ACTIVATE NEXT DEVICE - this.deviceRemovedTimout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1500, function() { - _d("Device Removed timeout"); - if (obj === this._activeDevice) { - let device = Object.keys(this._devices).map((id) => this._devices[id]).find(({active}) => active === true); - if(device){ - this._changeDeviceBase(device.id, this._getMixerControl()); - } - } - this.deviceRemovedTimout = null; - return false; - }.bind(this)); - */ - this._setChooserVisibility(); - this._setVisibility(); - } - } - - _deviceActivated(control, id) { - _d("Activated:- " + id); - let obj = this._devices.get(id); - if (!obj) { - _d("Activated device not found in the list of devices, try to add"); - this._deviceAdded(control, id); - obj = this._devices.get(id); - } - if (obj && id != this._activeDeviceId) { - _d("Activated: " + id + ":" + obj.title); - if (this._settings.get_boolean(Prefs.CANNOT_ACTIVATE_HIDDEN_DEVICE) - && obj.getDisplayOption() === DISPLAY_OPTIONS.HIDE_ALWAYS) { - _d("Preference does not allow this hidden device to be activated, fallback to the previous aka original device"); - let device = null; - - if (this._activeDeviceId) { - device = this._devices.get(this._activeDeviceId); - } - else { - device = Array.from(this._devices.values()).find(x => x.isAvailable()); - } - - if (device) { - _notify(Me.metadata["name"] + " " + _("Extension changed active sound device."), - _("Activated device is hidden in Port Settings.") + " \n" + - _("Deactivated Device: ") + obj.title + " \n" + _("Activated Device: ") + device.title + " \n" - + _("Disable in extension preferences to avoid this behaviour."), - device.icon_name); - this._changeDeviceBase(device.id, control); - } - else { - this._activateDeviceMenuItem(control, id, obj); - } - - } - else { - this._activateDeviceMenuItem(control, id, obj); - } - } - } - - _activateDeviceMenuItem(control, id, obj) { - let prevActiveDevce = this._activeDeviceId; - this._activeDeviceId = id; - if (prevActiveDevce) { - let prevObj = this._devices.get(prevActiveDevce); - if (prevObj) { - prevObj.setActiveDevice(false); - if (prevObj.getDisplayOption() === DISPLAY_OPTIONS.HIDE_ALWAYS) { - _d("Hiding previously activated device as it is set to hidden always"); - this._deviceRemoved(control, prevActiveDevce, true); - } - } - } - obj.setActiveDevice(true); - if (!obj.isAvailable()) { - _d("Activated device hidden, try to add"); - this._deviceAdded(control, id); - } - - this.menuItem.label.text = obj.title; - - if (!this._settings.get_boolean(Prefs.HIDE_MENU_ICONS)) { - this.menuItem.icon.icon_name = obj.icon_name; - } else { - this.menuItem.icon.gicon = null; - } - } - - _changeDeviceBase(id, control) { - if (!control) { - control = this._getMixerControl(); - } - let uidevice = this.lookupDeviceById(control, id); - if (uidevice) { - this.changeDevice(control, uidevice); - } - else { - this._deviceRemoved(control, id); - } - } - - _setActiveProfile() { - let control = this._getMixerControl(); - this._devices.forEach(device => { - if (device.isAvailable()) { - this._setDeviceActiveProfile(control, device); - } - }); - } - - _setDeviceActiveProfile(control, device) { - if (!device || !device.isAvailable()) { - return; - } - - let uidevice = this.lookupDeviceById(control, device.id); - if (!uidevice) { - this._deviceRemoved(control, device.id); - } - else { - let activeProfile = uidevice.get_active_profile(); - _d("Active Profile:" + activeProfile); - device.setActiveProfile(activeProfile); - } - } - - _getAvailableDevices() { - return Array.from(this._devices.values()).filter(x => x.isAvailable()); - } - - _getDeviceVisibility() { - let hideChooser = this._settings.get_boolean(Prefs.HIDE_ON_SINGLE_DEVICE); - if (hideChooser) { - return (this._getAvailableDevices().length > 1); - } - else { - return true; - } - } - - _setChooserVisibility() { - let visibility = this._getDeviceVisibility(); - this._getAvailableDevices().forEach(x => x.setVisibility(visibility)) - - //this.menuItem._triangleBin.visible = visibility; - //this.menuItem.actor.visible = visibility; - this._setProfileVisibility(); - } - - _setVisibility() { - if (!this._settings.get_boolean(this._show_device_signal)) - this.menuItem.actor.visible = false; - else - // if setting says to show device, check for any device, otherwise - // hide the "actor" - this.menuItem.actor.visible = this._getDeviceVisibility();//(Array.from(this._devices.values()).some(x => x.isAvailable())); - - this.emit('update-visibility', this.menuItem.actor.visible); - } - - _setProfileVisibility() { - let visibility = this._settings.get_boolean(Prefs.SHOW_PROFILES); - this._getAvailableDevices().forEach(device => device.setProfileVisibility(visibility)); - } - - _getIcon(name) { - let iconsType = this._settings.get_string(Prefs.ICON_THEME); - switch (iconsType) { - case Prefs.ICON_THEME_COLORED: - return name; - case Prefs.ICON_THEME_MONOCHROME: - return name + "-symbolic"; - default: - //return "none"; - return null; - } - } - - _setIcons() { - // Set the icons in the selection list - let control = this._getMixerControl(); - this._devices.forEach((device, id) => { - let uidevice = this.lookupDeviceById(control, id); - if (uidevice) { - let icon = uidevice.get_icon_name(); - if (icon == null || icon.trim() == "") - icon = this.getDefaultIcon(); - _d(icon + " _setIcons") - device.setIcon(this._getIcon(icon)); - } - }); - - // These indicate the active device, which is displayed directly in the - // Gnome menu, not in the list. - if (!this._settings.get_boolean(Prefs.HIDE_MENU_ICONS)) { - this.menuItem.icon.icon_name = this._getIcon(this._devices.get(this._activeDeviceId).icon_name); - } else { - this.menuItem.icon.icon_name = null; - } - } - - _getDeviceDisplayOption(control, uidevice, obj) { - let displayOption = DISPLAY_OPTIONS.DEFAULT; - if (uidevice && uidevice.port_name != null && uidevice.description != null) { - let stream = control.get_stream_from_device(uidevice); - let cardName = null; - if (stream) { - let cardId = stream.get_card_index(); - if (cardId != null) { - _d("Card Index:" + cardId); - let _card = Lib.getCard(cardId); - if (_card) { - cardName = _card.name; - } - else { - //card id found, but not available in list - return DISPLAY_OPTIONS.DEFAULT; - } - _d("Card Name:" + cardName); - } - } - - _d("P:" + uidevice.port_name + "==" + uidevice.description + "==" + cardName + "==" + uidevice.origin); - - let matchedPort = this._portsSettings.find(port => (port - && port.name == uidevice.port_name - && port.human_name == uidevice.description - && (!cardName || port.card_name == cardName) - && (cardName || port.card_description == uidevice.origin))); - - if (matchedPort) { - displayOption = matchedPort.display_option; - } - } - - obj && obj.setDisplayOption(displayOption); - - return displayOption; - } - - _canShowDevice(control, uidevice, obj, defaultValue) { - if (!uidevice || !this._portsSettings || uidevice.port_name == null - || uidevice.description == null || (this._activeDeviceId && this._activeDeviceId == uidevice.get_id())) { - return defaultValue; - } - - let displayOption = obj.getDisplayOption(); - if (displayOption === DISPLAY_OPTIONS.INITIAL) { - displayOption = this._getDeviceDisplayOption(control, uidevice, obj); - } - - if (displayOption === DISPLAY_OPTIONS.SHOW_ALWAYS) { - _d("Display Device due Preference:" + displayOption); - return true; - } - else if (displayOption === DISPLAY_OPTIONS.HIDE_ALWAYS) { - _d("Hide Device due Preference:" + displayOption); - return false; - } - else { - _d("Default Device due Preference:" + displayOption); - return defaultValue; - } - } - - _resetDevices() { - this._portsSettings = Prefs.getPortsFromSettings(this._settings); - let control = this._getMixerControl(); - this._devices.forEach((device, id) => { - device.setDisplayOption(DISPLAY_OPTIONS.INITIAL); - let uidevice = this.lookupDeviceById(control, id); - if (this._isDeviceInValid(uidevice)) - _d("Device is invalid"); - else if (this._canShowDevice(control, uidevice, device, uidevice.port_available)) - this._deviceAdded(control, id, true); - else - this._deviceRemoved(control, id, true); - }); - } - - _isDeviceInValid(uidevice) { - return (!uidevice || (uidevice.description != null && uidevice.description.match(/Dummy\s+(Output|Input)/gi))); - } - - _refreshDeviceTitles(){ - let control = this._getMixerControl(); - this._devices.forEach((device, id) => { - let uidevice = this.lookupDeviceById(control, id); - let title = this._getDeviceTitle(uidevice); - - device.setTitle(title); - }); - - let activeDevice = this._devices.get(this._activeDeviceId); - this.menuItem.label.text = activeDevice.title; - } - - _getDeviceTitle(uidevice) { - let title = uidevice.description; - if (!this._settings.get_boolean(Prefs.OMIT_DEVICE_ORIGIN) && uidevice.origin != "") - title += " - " + uidevice.origin; - - return title; - } - - destroy() { - this._signalManager.disconnectAll(); - if (this.deviceRemovedTimout) { - GLib.source_remove(this.deviceRemovedTimout); - this.deviceRemovedTimout = null; - } - if (this.activeProfileTimeout) { - GLib.source_remove(this.activeProfileTimeout); - this.activeProfileTimeout = null; - } - this.menuItem.destroy(); - } - -}; - -Signals.addSignalMethods(SoundDeviceChooserBase.prototype); - -function _notify(msg, details, icon_name) { - let source = new MessageTray.Source(Me.metadata["name"], icon_name); - Main.messageTray.add(source); - let notification = new MessageTray.Notification(source, msg, details); - //notification.setTransient(true); - source.showNotification(notification); -} diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/convenience.js b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/convenience.js deleted file mode 100644 index 85f711c..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/convenience.js +++ /dev/null @@ -1,352 +0,0 @@ -/******************************************************************************* - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - * ***************************************************************************** - * Original Author: Gopi Sankar Karmegam - ******************************************************************************/ -/* jshint moz:true */ - -const ByteArray = imports.byteArray; -const { Gio, GLib } = imports.gi; -const ExtensionUtils = imports.misc.extensionUtils; - -const Me = ExtensionUtils.getCurrentExtension(); -const Prefs = Me.imports.prefs; - -var DEBUG = false; - -var logWrap; -if (log != undefined) { - logWrap = log; -} -else { - logWrap = global.log -} - - -let cards; - -function getCard(card_index) { - if (!cards || Object.keys(cards).length == 0) { - refreshCards(); - } - return cards[card_index]; -} - -function getCardByName(card_name) { - if (!cards || Object.keys(cards).length == 0) { - refreshCards(); - } - return Object.keys(cards).map((index) => cards[index]).find(({ name }) => name === card_name); -} - -function getProfiles(control, uidevice) { - let stream = control.lookup_stream_id(uidevice.get_stream_id()); - if (stream) { - if (!cards || Object.keys(cards).length == 0 || !cards[stream.card_index]) { - refreshCards(); - } - if (cards && cards[stream.card_index]) { - _log("Getting profile form stream id " + uidevice.port_name); - let profiles; - if ((profiles = getProfilesForPort(uidevice.port_name, cards[stream.card_index]))) { - return profiles; - } - } - } - else { - /* Device is not active device, lets try match with port name */ - refreshCards(); - for (let card of Object.values(cards)) { - let profiles; - _log("Getting profile from cards " + uidevice.port_name + " for card id " + card.id); - if ((profiles = getProfilesForPort(uidevice.port_name, card))) { - return profiles; - } - } - } - return []; -} - -let ports; -function getPorts(refresh) { - if (!ports || ports.length == 0 || refresh) { - refreshCards(); - } - return ports; -} - -function isCmdFound(cmd) { - try { - let [result, out, err, exit_code] = GLib.spawn_command_line_sync(cmd); - return true; - } - catch (e) { - _log("ERROR: " + cmd + " execution failed. " + e); - return false; - } -} - -function refreshCards() { - cards = {}; - ports = []; - let _settings = ExtensionUtils.getSettings(); - let error = false; - let newProfLogic = _settings.get_boolean(Prefs.NEW_PROFILE_ID_DEPRECATED); - - /** This block should be removed in the next release along the setting schema correct */ - if (!newProfLogic) { - _settings.set_boolean(Prefs.NEW_PROFILE_ID, false); - _settings.reset(Prefs.NEW_PROFILE_ID_DEPRECATED); - } - else { - newProfLogic = _settings.get_boolean(Prefs.NEW_PROFILE_ID); - } - - if (newProfLogic) { - _log("New logic"); - let pyLocation = Me.dir.get_child("utils/pa_helper.py").get_path(); - let pythonExec = ["python", "python3", "python2"].find(cmd => isCmdFound(cmd)); - if (!pythonExec) { - _log("ERROR: Python not found. fallback to default mode"); - _settings.set_boolean(Prefs.NEW_PROFILE_ID, false); - Gio.Settings.sync(); - newProfLogic = false; - } - else { - try { - _log("Python found." + pythonExec); - let [result, out, err, exit_code] = GLib.spawn_command_line_sync(pythonExec + " " + pyLocation); - // _log("result" + result +" out"+out + " exit_code" + - // exit_code + "err" +err); - if (result && !exit_code) { - if (out instanceof Uint8Array) { - out = ByteArray.toString(out); - } - let obj = JSON.parse(out); - cards = obj["cards"]; - ports = obj["ports"]; - } - } - catch (e) { - error = true; - _log("ERROR: Python execution failed. fallback to default mode" + e); - _settings.set_boolean(Prefs.NEW_PROFILE_ID, false); - Gio.Settings.sync(); - } - } - } - //error = true; - if (!newProfLogic || error) { - _log("Old logic"); - try { - let env = GLib.get_environ(); - env = GLib.environ_setenv(env, "LANG", "C", true); - let [result, out, err, exit_code] = GLib.spawn_sync(null, ["pactl", "list", "cards"], env, GLib.SpawnFlags.SEARCH_PATH, null); - //_log(result+"--"+out+"--"+ err+"--"+ exit_code) - if (result && !exit_code) { - parseOutput(out); - } - } - catch (e) { - _log("ERROR: pactl execution failed. No ports/profiles will be displayed." + e); - } - } - //_log(Array.isArray(cards)); - //_log(JSON.stringify(cards)); - //_log(Array.isArray(ports)); - //_log(JSON.stringify(ports)); -} - -function parseOutput(out) { - let lines; - if (out instanceof Uint8Array) { - lines = ByteArray.toString(out).split("\n"); - } else { - lines = out.toString().split("\n"); - } - - let cardIndex; - let parseSection = "CARDS"; - let port; - let matches; - // _log("Unmatched line:" + out); - while (lines.length > 0) { - let line = lines.shift(); - - if ((matches = /^Card\s#(\d+)$/.exec(line))) { - cardIndex = matches[1]; - if (!cards[cardIndex]) { - cards[cardIndex] = { "index": cardIndex, "profiles": [], "ports": [] }; - } - } - else if ((matches = /^\t*Name:\s+(.*?)$/.exec(line)) && cards[cardIndex]) { - cards[cardIndex].name = matches[1]; - parseSection = "CARDS" - } - else if (line.match(/^\tProperties:$/) && parseSection == "CARDS") { - parseSection = "PROPS"; - } - else if (line.match(/^\t*Profiles:$/)) { - parseSection = "PROFILES"; - } - else if (line.match(/^\t*Ports:$/)) { - parseSection = "PORTS"; - } - else if (cards[cardIndex]) { - switch (parseSection) { - case "PROPS": - if ((matches = /alsa\.card_name\s+=\s+"(.*?)"/.exec(line))) { - cards[cardIndex].alsa_name = matches[1]; - } - else if ((matches = /device\.description\s+=\s+"(.*?)"/.exec(line))) { - cards[cardIndex].card_description = matches[1]; - } - break; - case "PROFILES": - if ((matches = /.*?((?:output|input)[^+]*?):\s(.*?)\s\(sinks:.*?(?:available:\s*(.*?))*\)/.exec(line))) { - let availability = matches[3] ? matches[3] : "yes" //If no availability in out, assume profile is available - - cards[cardIndex].profiles.push({ - "name": matches[1], - "human_name": matches[2], - "available": (availability === "yes") ? 1 : 0 - }); - } - break; - case "PORTS": - if ((matches = /\t*(.*?):\s(.*)\s\(.*?priority:/.exec(line))) { - port = { - "name": matches[1], - "human_name": matches[2], - "card_name": cards[cardIndex].name, - "card_description": cards[cardIndex].card_description - }; - cards[cardIndex].ports.push(port); - ports.push(port); - } - else if (port && (matches = /\t*Part of profile\(s\):\s(.*)/.exec(line))) { - let profileStr = matches[1]; - port.profiles = profileStr.split(", "); - port = null; - } - break; - } - } - } - if (ports) { - ports.forEach(p => { - p.direction = p.profiles - .filter(pr => pr.indexOf("+input:") == -1) - .some(pr => (pr.indexOf("output:") >= 0)) ? "Output" : "Input"; - }); - } -} - -var Signal = class Signal { - - constructor(signalSource, signalName, callback) { - this._signalSource = signalSource; - this._signalName = signalName; - this._signalCallback = callback; - } - - connect() { - this._signalId = this._signalSource.connect(this._signalName, this._signalCallback); - } - - disconnect() { - if (this._signalId) { - this._signalSource.disconnect(this._signalId); - this._signalId = null; - } - } -} - -var SignalManager = class SignalManager { - constructor() { - this._signalsBySource = new Map(); - } - - addSignal(signalSource, signalName, callback) { - let obj = null; - if (signalSource && signalName && callback) { - obj = new Signal(signalSource, signalName, callback); - obj.connect(); - - if (!this._signalsBySource.has(signalSource)) { - this._signalsBySource.set(signalSource, []); - } - this._signalsBySource.get(signalSource).push(obj) - //_log(this._signalsBySource.get(signalSource).length + "Signal length"); - } - return obj; - } - - disconnectAll() { - this._signalsBySource.forEach(signals => this._disconnectSignals(signals)); - } - - disconnectBySource(signalSource) { - if (this._signalsBySource.has(signalSource)) { - this._disconnectSignals(this._signalsBySource.get(signalSource)); - } - } - - _disconnectSignals(signals) { - while (signals.length) { - var signal = signals.shift(); - signal.disconnect(); - signal = null; - } - } -} - - -function getProfilesForPort(portName, card) { - if (card.ports) { - let port = card.ports.find(port => (portName === port.name)); - if (port) { - if (port.profiles) { - return card.profiles.filter(profile => ( - profile.name.indexOf("+input:") == -1 - && profile.available === 1 - && port.profiles.includes(profile.name) - )); - } - } - } - return null; -} - -function setLog(value) { - DEBUG = value; -} - -function _log(msg) { - if (DEBUG == true) { - // global.log("SDC Debug: " + msg); - logWrap("SDC Debug: " + msg); - } -} - -function dump(obj) { - var propValue; - for (var propName in obj) { - try { - propValue = obj[propName]; - _log(propName + "=" + propValue); - } - catch (e) { _log(propName + "!!!Error!!!"); } - } -} diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/extension.js b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/extension.js deleted file mode 100644 index 81f5774..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/extension.js +++ /dev/null @@ -1,267 +0,0 @@ -/******************************************************************************* - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - * ***************************************************************************** - * Original Author: Gopi Sankar Karmegam - ******************************************************************************/ -/* jshint moz:true */ - -const { GObject } = imports.gi; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Base = Me.imports.base; -const Lib = Me.imports.convenience; -const _d = Lib._log; -const SignalManager = Lib.SignalManager; -const Prefs = Me.imports.prefs; -const Main = imports.ui.main; -const PopupMenu = imports.ui.popupMenu; - -var SoundOutputDeviceChooser = class SoundOutputDeviceChooser - extends Base.SoundDeviceChooserBase { - constructor() { - super("output"); - } - lookupDeviceById(control, id) { - return control.lookup_output_id(id); - } - changeDevice(control, uidevice) { - control.change_output(uidevice); - } - getDefaultStream(control) { - return control.get_default_sink(); - } - getDefaultIcon() { - return "audio-card"; - } -}; - -var SoundInputDeviceChooser = class SoundInputDeviceChooser - extends Base.SoundDeviceChooserBase { - constructor() { - super("input"); - } - lookupDeviceById(control, id) { - return control.lookup_input_id(id); - } - changeDevice(control, uidevice) { - control.change_input(uidevice); - } - getDefaultStream(control) { - return control.get_default_source(); - } - getDefaultIcon() { - return "audio-input-microphone"; - } -}; - -var VolumeMenuInstance = class VolumeMenuInstance { - constructor(volumeMenu, settings) { - this._settings = settings; - - this._volumeMenu = volumeMenu; - this._input = this._volumeMenu._input; - - this._overrideFunctions(); - this._setSliderVisiblity(); - - this._signalManager = new SignalManager(); - this._signalManager.addSignal(this._settings, "changed::" - + Prefs.SHOW_INPUT_SLIDER, this._setSliderVisiblity.bind(this)); - } - _overrideFunctions() { - // Fix the indicator when using SHOW_INPUT_SLIDER. - // If not applied when SHOW_INPUT_SLIDER=True indication of mic being used will be on (even when not used) - this._volumeMenu._getInputVisibleOriginal = this._volumeMenu.getInputVisible; - this._volumeMenu._getInputVisibleCustom = function() { - return this._input._stream != null && this._input._showInput; - }; - this._volumeMenu.getInputVisible = this._volumeMenu._getInputVisibleCustom; - - this._input._updateVisibilityOriginal = this._input._updateVisibility; - this._input._updateVisibilityCustom = function() { - let old_state_visible = this.item.visible; - let visible = this._shouldBeVisible(); - - if(old_state_visible != visible){ - this.item.visible = visible; - } else { - this.item.notify('visible'); - } - }; - this._input._updateVisibility = this._input._updateVisibilityCustom; - - // Makes slider visible when SHOW_INPUT_SLIDER=True - this._input._showInputSlider = this._settings.get_boolean(Prefs.SHOW_INPUT_SLIDER); - this._input._shouldBeVisibleOriginal = this._input._shouldBeVisible; - this._input._shouldBeVisibleCustom = function() { - return this._showInputSlider && (this._stream != null) || this._shouldBeVisibleOriginal(); - }; - this._input._shouldBeVisible = this._input._shouldBeVisibleCustom; - } - _setSliderVisiblity() { - this._input._showInputSlider = this._settings.get_boolean(Prefs.SHOW_INPUT_SLIDER); - this._input._maybeShowInput(); - } - destroy() { - this._signalManager.disconnectAll(); - delete this._signalManager; - this._volumeMenu.getInputVisible = this._volumeMenu._getInputVisibleOriginal; - this._input._updateVisibility = this._input._updateVisibilityOriginal; - this._input._shouldBeVisible = this._input._shouldBeVisibleOriginal; - - this._input._maybeShowInput(); - - delete this._volumeMenu['_getInputVisibleOriginal']; - delete this._volumeMenu['_getInputVisibleCustom']; - delete this._input['_updateVisibilityOriginal']; - delete this._input['_updateVisibilityCustom']; - delete this._input['_shouldBeVisibleOriginal']; - delete this._input['_shouldBeVisibleCustom']; - delete this._input['_showInputSlider']; // variable - } -} - -var SDCInstance = class SDCInstance { - constructor() { - } - - enable() { - this._settings = ExtensionUtils.getSettings(); - this._signalManager = new SignalManager(); - this._aggregateMenu = Main.panel.statusArea.aggregateMenu; - this._volume = this._aggregateMenu._volume; - this._volumeMenu = this._volume._volumeMenu; - this._aggregateLayout = this._aggregateMenu.menu.box.get_layout_manager(); - let theme = imports.gi.Gtk.IconTheme.get_default(); - if (theme != null) { - let iconPath = Me.dir.get_child('icons'); - if (iconPath != null && iconPath.query_exists(null)) { - theme.append_search_path(iconPath.get_path()); - } - } - - if (this._outputInstance == null) { - this._outputInstance = new SoundOutputDeviceChooser(); - } - if (this._inputInstance == null) { - this._inputInstance = new SoundInputDeviceChooser(); - } - - if (this._volumeMenuInstance == null) { - this._volumeMenuInstance = new VolumeMenuInstance(this._volumeMenu, this._settings); - } - - this._addMenuItem(this._volumeMenu, this._volumeMenu._output.item, this._outputInstance.menuItem); - this._addMenuItem(this._volumeMenu, this._volumeMenu._input.item, this._inputInstance.menuItem); - this._expandVolMenu(); - - this._signalManager.addSignal(this._settings, "changed::" + Prefs.EXPAND_VOL_MENU, this._expandVolMenu.bind(this)); - this._signalManager.addSignal(this._settings, "changed::" + Prefs.INTEGRATE_WITH_SLIDER, this._switchSubmenuMenu.bind(this)); - this._signalManager.addSignal(this._outputInstance, "update-visibility", this._updateMenuVisibility.bind(this)); - this._signalManager.addSignal(this._inputInstance, "update-visibility", this._updateMenuVisibility.bind(this)); - - } - - _addMenuItem(_volumeMenu, checkItem, menuItem) { - let menuItems = _volumeMenu._getMenuItems(); - let i = menuItems.findIndex(elem => elem === checkItem); - if (i < 0) { - i = menuItems.length; - } - _volumeMenu.addMenuItem(menuItem, ++i); - this._integrateMenu(_volumeMenu, checkItem, menuItem, this._canIntegrateMenuItem(menuItem)); - } - - _canIntegrateMenuItem(menuItem) { - return menuItem.visible && this._settings.get_boolean(Prefs.INTEGRATE_WITH_SLIDER); - } - - _expandVolMenu() { - if (this._settings.get_boolean(Prefs.EXPAND_VOL_MENU)) { - this._aggregateLayout.addSizeChild(this._volumeMenu.actor); - } else { - this._revertVolMenuChanges(); - } - } - - _revertVolMenuChanges() { - this._aggregateLayout._sizeChildren = this._aggregateLayout._sizeChildren.filter(item => item !== this._volumeMenu.actor); - this._aggregateLayout.layout_changed(); - } - - _updateMenuVisibility(menuInstance) { - let canIntegrate = this._canIntegrateMenuItem(menuInstance.menuItem); - if(menuInstance instanceof SoundOutputDeviceChooser) { - this._integrateMenu(this._volumeMenu, this._volumeMenu._output.item, menuInstance.menuItem, canIntegrate); - } else { - this._integrateMenu(this._volumeMenu, this._volumeMenu._input.item, menuInstance.menuItem, canIntegrate); - } - } - - _switchSubmenuMenu() { - this._updateMenuVisibility(this._outputInstance, this._outputInstance.menuItem.visibile); - this._updateMenuVisibility(this._inputInstance, this._inputInstance.menuItem.visibile); - - } - - _integrateMenu(_volumeMenu, _sliderItem, selectorItem, canIntegrate) { - if(canIntegrate == true) { - _d("Integrating with Volume menu"); - if(_volumeMenu.box.contains(_sliderItem) == true){ - _volumeMenu.box.remove_child(_sliderItem); - } - _sliderItem.set_x_expand(true); - selectorItem.insert_child_above(_sliderItem, selectorItem.label); - selectorItem.label.hide(); - _sliderItem.get_next_sibling().hide(); //expander - selectorItem.icon.hide(); - } else { - _d("Not integrating with Volume menu") - if(selectorItem.contains(_sliderItem) == true) { - selectorItem.remove_child(_sliderItem); - } - _sliderItem.set_x_expand(false); - selectorItem.label.show(); - selectorItem.label.get_next_sibling().show(); //expander - selectorItem.icon.show(); - if(_volumeMenu.box.contains(_sliderItem) == false){ - _volumeMenu.box.insert_child_below(_sliderItem, selectorItem); - } - } - } - - disable() { - this._settings = null; - this._signalManager.disconnectAll(); - this._signalManager = null; - this._revertVolMenuChanges(); - if (this._outputInstance) { - this._outputInstance.destroy(); - this._outputInstance = null; - } - if (this._inputInstance) { - this._inputInstance.destroy(); - this._inputInstance = null; - } - if (this._volumeMenuInstance) { - this._volumeMenuInstance.destroy(); - this._volumeMenuInstance = null; - } - } -}; - -function init() { - ExtensionUtils.initTranslations(Me.metadata["gettext-domain"]); - return new SDCInstance(); -} diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/icons/blank.png b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/icons/blank.png deleted file mode 100644 index 23568c6..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/icons/blank.png and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/license b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/license deleted file mode 100644 index 94a9ed0..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/license +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - <program> Copyright (C) <year> <name of author> - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -<http://www.gnu.org/licenses/>. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/de_DE/LC_MESSAGES/sound-output-device-chooser.mo b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/de_DE/LC_MESSAGES/sound-output-device-chooser.mo deleted file mode 100644 index 4929de7..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/de_DE/LC_MESSAGES/sound-output-device-chooser.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/it_IT/LC_MESSAGES/sound-output-device-chooser.mo b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/it_IT/LC_MESSAGES/sound-output-device-chooser.mo deleted file mode 100644 index 63937ad..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/it_IT/LC_MESSAGES/sound-output-device-chooser.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/ko/LC_MESSAGES/sound-output-device-chooser.mo b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/ko/LC_MESSAGES/sound-output-device-chooser.mo deleted file mode 100644 index 570937d..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/ko/LC_MESSAGES/sound-output-device-chooser.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/nl/LC_MESSAGES/sound-output-device-chooser.mo b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/nl/LC_MESSAGES/sound-output-device-chooser.mo deleted file mode 100644 index bd5188e..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/nl/LC_MESSAGES/sound-output-device-chooser.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/pt_BR/LC_MESSAGES/sound-output-device-chooser.mo b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/pt_BR/LC_MESSAGES/sound-output-device-chooser.mo deleted file mode 100644 index 2a27c47..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/pt_BR/LC_MESSAGES/sound-output-device-chooser.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/pt_PT/LC_MESSAGES/sound-output-device-chooser.mo b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/pt_PT/LC_MESSAGES/sound-output-device-chooser.mo deleted file mode 100644 index 4b47f43..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/pt_PT/LC_MESSAGES/sound-output-device-chooser.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/sk/LC_MESSAGES/sound-output-device-chooser.mo b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/sk/LC_MESSAGES/sound-output-device-chooser.mo deleted file mode 100644 index 9c773a6..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/sk/LC_MESSAGES/sound-output-device-chooser.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/sv/LC_MESSAGES/sound-output-device-chooser.mo b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/sv/LC_MESSAGES/sound-output-device-chooser.mo deleted file mode 100644 index 2bb16f2..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/sv/LC_MESSAGES/sound-output-device-chooser.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/ta/LC_MESSAGES/sound-output-device-chooser.mo b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/ta/LC_MESSAGES/sound-output-device-chooser.mo deleted file mode 100644 index d3809ee..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/locale/ta/LC_MESSAGES/sound-output-device-chooser.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/metadata.json b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/metadata.json deleted file mode 100644 index 6172206..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/metadata.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Shows a list of sound output and input devices (similar to gnome sound settings) in the status menu below the volume slider. Various active ports like HDMI , Speakers etc. of the same device are also displayed for selection. V20+ needs python as dependency. If you want to continue with the old method without Python, use options to switch off New Port identification. But it works with only English", - "gettext-domain": "sound-output-device-chooser", - "name": "Sound Input & Output Device Chooser", - "original-author": "GopI", - "settings-schema": "org.gnome.shell.extensions.sound-output-device-chooser", - "shell-version": [ - "3.34", - "3.32", - "3.36", - "3.38", - "40", - "41" - ], - "url": "https://github.com/kgshank/gse-sound-output-device-chooser", - "uuid": "sound-output-device-chooser@kgshank.net", - "version": 40 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/prefs.js b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/prefs.js deleted file mode 100644 index 90ad206..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/prefs.js +++ /dev/null @@ -1,328 +0,0 @@ -/******************************************************************************* - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see <http://www.gnu.org/licenses/>. - * - * Original Author: Gopi Sankar Karmegam - ******************************************************************************/ -/* jshint moz:true */ - -const { Gio, GObject, Gtk } = imports.gi; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Lib = Me.imports.convenience; -const _d = Lib._log; -const SignalManager = Lib.SignalManager; - -const Gettext = imports.gettext; -const _ = Gettext.gettext; - -var HIDE_ON_SINGLE_DEVICE = "hide-on-single-device"; -var HIDE_MENU_ICONS = "hide-menu-icons"; -var SHOW_PROFILES = "show-profiles"; -var PORT_SETTINGS = "ports-settings"; -var SHOW_INPUT_SLIDER = "show-input-slider"; -var SHOW_INPUT_DEVICES = "show-input-devices"; -var SHOW_OUTPUT_DEVICES = "show-output-devices"; -var ENABLE_LOG = "enable-log"; -var NEW_PROFILE_ID_DEPRECATED = "new-profile-indentification"; -var NEW_PROFILE_ID = "new-profile-identification"; -var EXPAND_VOL_MENU = "expand-volume-menu"; -var CANNOT_ACTIVATE_HIDDEN_DEVICE = "cannot-activate-hidden-device"; -var OMIT_DEVICE_ORIGIN = "omit-device-origins"; -var INTEGRATE_WITH_SLIDER = "integrate-with-slider"; - -var ICON_THEME = "icon-theme"; -var ICON_THEME_COLORED = "colored"; -var ICON_THEME_MONOCHROME = "monochrome"; -var ICON_THEME_NONE = "none"; - -var DISPLAY_OPTIONS = { SHOW_ALWAYS: 1, HIDE_ALWAYS: 2, DEFAULT: 3, INITIAL: -1 }; - -const PORT_SETTINGS_VERSION = 3; - -function init() { - ExtensionUtils.initTranslations(); -} - -function getPortsFromSettings(_settings) { - //_d(_settings.get_string(PORT_SETTINGS)); - let obj = JSON.parse(_settings.get_string(PORT_SETTINGS)); - let currentSettingsVersion = PORT_SETTINGS_VERSION; - if (Array.isArray(obj)) { - currentSettingsVersion = 1; - } - else { - currentSettingsVersion = obj.version; - } - - if (currentSettingsVersion < PORT_SETTINGS_VERSION) { - obj = migratePortSettings(currentSettingsVersion, obj, _settings); - } - return obj.ports; -} - -function setPortsSettings(ports, _settings) { - let settingsObj = { "version": PORT_SETTINGS_VERSION }; - settingsObj.ports = ports; - //_d(JSON.stringify(settingsObj)); - _settings.set_string(PORT_SETTINGS, JSON.stringify(settingsObj)); - return settingsObj; -} - -function getPortDisplayName(port) { - return `${port.human_name} - ${port.card_description}`; -} - -function migratePortSettings(currVersion, currSettings, _settings) { - let ports = []; - let _lPorts = Lib.getPorts(true).slice(); - switch (currVersion) { - case 1: - for (let port of currSettings) { - for (var i = 0; i < _lPorts.length; i++) { - let _lPort = _lPorts[i]; - if (port.human_name == _lPort.human_name && port.name == _lPort.name) { - port.card_name = _lPort.card_name; - port.card_description = _lPort.card_description; - port.display_name = getPortDisplayName(_lPort); - _lPorts.splice(i, 1); - ports.push(port); - break; - } - } - } - break; - - case 2: - for (let port of currSettings.ports) { - for (var i = 0; i < _lPorts.length; i++) { - let _lPort = _lPorts[i]; - if (port.human_name == _lPort.human_name && port.name == _lPort.name && port.card_name == _lPort.card_name) { - port.card_description = _lPort.card_description; - _lPorts.splice(i, 1); - ports.push(port); - break; - } - } - } - break; - } - return setPortsSettings(ports, _settings); -} - -const SDCSettingsWidget = new GObject.Class({ - Name: "SDC.Prefs.Widget", - GTypeName: "SDCSettingsWidget", - Extends: Gtk.Box, - - _init: function(params) { - this.parent(params); - this.orientation = Gtk.Orientation.VERTICAL; - this.spacing = 0; - let uiFileSuffix = ""; - - if (Gtk.get_major_version() >= "4") { - uiFileSuffix = "40"; - this.__addFn = this.append; - this.__showFn = this.show; - } - else { - this.__addFn = x => this.pack_start(x, true, true, 0); - this.__showFn = this.show_all; - } - // creates the settings - this._settings = ExtensionUtils.getSettings(); - - Lib.setLog(this._settings.get_boolean(ENABLE_LOG)); - - // creates the ui builder and add the main resource file - let uiFilePath = Me.path + "/ui/prefs-dialog" + uiFileSuffix + ".glade"; - let builder = new Gtk.Builder(); - builder.set_translation_domain("sound-output-device-chooser"); - - if (builder.add_from_file(uiFilePath) == 0) { - _d("JS LOG: could not load the ui file: %s".format(uiFilePath)); - let label = new Gtk.Label({ - label: _("Could not load the preferences UI file"), - vexpand: true - }); - this.__addFn(label); - } else { - _d("JS LOG:_UI file receive and load: " + uiFilePath); - - let mainContainer = builder.get_object("main-container"); - - this.__addFn(mainContainer); - - this._signalManager = new SignalManager(); - - let showProfileSwitch = builder.get_object(SHOW_PROFILES); - let volMenuSwitch = builder.get_object(EXPAND_VOL_MENU); - let singleDeviceSwitch = builder.get_object(HIDE_ON_SINGLE_DEVICE); - let showInputSliderSwitch = builder.get_object(SHOW_INPUT_SLIDER); - let showInputDevicesSwitch = builder.get_object(SHOW_INPUT_DEVICES); - let showOutputDevicesSwitch = builder.get_object(SHOW_OUTPUT_DEVICES); - let hideMenuIconsSwitch = builder.get_object(HIDE_MENU_ICONS); - let iconThemeCombo = builder.get_object(ICON_THEME); - let logSwitch = builder.get_object(ENABLE_LOG); - let newProfileIdSwitch = builder.get_object(NEW_PROFILE_ID); - let cantActHiddSwitch = builder.get_object(CANNOT_ACTIVATE_HIDDEN_DEVICE); - let omitDeviceOrigin = builder.get_object(OMIT_DEVICE_ORIGIN); - let integrateWithSlider = builder.get_object(INTEGRATE_WITH_SLIDER); - - this._settings.bind(HIDE_ON_SINGLE_DEVICE, singleDeviceSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(SHOW_PROFILES, showProfileSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(EXPAND_VOL_MENU, volMenuSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(SHOW_INPUT_SLIDER, showInputSliderSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(SHOW_INPUT_DEVICES, showInputDevicesSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(SHOW_OUTPUT_DEVICES, showOutputDevicesSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(HIDE_MENU_ICONS, hideMenuIconsSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(ENABLE_LOG, logSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(NEW_PROFILE_ID, newProfileIdSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(CANNOT_ACTIVATE_HIDDEN_DEVICE, cantActHiddSwitch, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(OMIT_DEVICE_ORIGIN, omitDeviceOrigin, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(INTEGRATE_WITH_SLIDER, integrateWithSlider, "active", Gio.SettingsBindFlags.DEFAULT); - this._settings.bind(ICON_THEME, iconThemeCombo, "active-id", Gio.SettingsBindFlags.DEFAULT); - - //Show always is not working always, hidden in the UI directly - let showAlwaysToggleRender = builder.get_object("ShowAlwaysToggleRender"); - let hideAlwaysToggleRender = builder.get_object("HideAlwaysToggleRender"); - let showActiveToggleRender = builder.get_object("ShowActiveToggleRender"); - - this._signalManager.addSignal(showAlwaysToggleRender, "toggled", this._showAlwaysToggleRenderCallback.bind(this)); - this._signalManager.addSignal(hideAlwaysToggleRender, "toggled", this._hideAlwaysToggleRenderCallback.bind(this)); - this._signalManager.addSignal(showActiveToggleRender, "toggled", this._showActiveToggleRenderCallback.bind(this)); - - this._portsStore = builder.get_object("ports-store"); - - this._populatePorts(); - this._restorePortsFromSettings(); - } - }, - - _populatePorts: function() { - let ports = Lib.getPorts(true); - ports.sort((a, b) => (b.direction.localeCompare(a.direction)) || getPortDisplayName(a).localeCompare(getPortDisplayName(b))).forEach(port => { - this._portsStore.set(this._portsStore.append(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [port.human_name, false, false, true, port.name, 3, port.card_name, port.card_description, getPortDisplayName(port), port.direction]); - }); - }, - - _showAlwaysToggleRenderCallback: function(widget, path) { - //this._toggleCallback(widget, path, 1, [2, 3]); - this._toggleCallback(widget, path, DISPLAY_OPTIONS.SHOW_ALWAYS, [2, 3]); - }, - - _hideAlwaysToggleRenderCallback: function(widget, path) { - //this._toggleCallback(widget, path, 2, [1, 3]); - this._toggleCallback(widget, path, DISPLAY_OPTIONS.HIDE_ALWAYS, [1, 3]); - }, - - _showActiveToggleRenderCallback: function(widget, path) { - //this._toggleCallback(widget, path, 3, [1, 2]); - this._toggleCallback(widget, path, DISPLAY_OPTIONS.DEFAULT, [1, 2]); - }, - - _toggleCallback: function(widget, path, activeCol, inactiveCols) { - let active = !widget.active; - if (!active) { - return; - } - let [success, iter] = this._portsStore.get_iter_from_string(path); - if (!success) { - return; - } - /*Dont support non-pci cards for show always*/ - let card_name = this._portsStore.get_value(iter, 6); - if (!/\.pci-/.exec(card_name) && activeCol == 1) { - //this._toggleCallback(widget, path, 3, [1, 2]); - this._toggleCallback(widget, path, DISPLAY_OPTIONS.DEFAULT, [1, 2]); - } - else { - this._portsStore.set_value(iter, activeCol, active); - this._portsStore.set_value(iter, 5, activeCol); - for (let col of inactiveCols) { - this._portsStore.set_value(iter, col, !active); - } - this._commitSettings(); - } - }, - - _commitSettings: function() { - let ports = []; - let [success, iter] = this._portsStore.get_iter_first(); - while (iter && success) { - if (!this._portsStore.get_value(iter, 3)) { - let display_option = this._portsStore.get_value(iter, 5); - //if (display_option != 3) {//Dont store default value - if (display_option != DISPLAY_OPTIONS.DEFAULT) {//Dont store default value - ports.push({ - human_name: this._portsStore.get_value(iter, 0), - name: this._portsStore.get_value(iter, 4), - display_option: display_option, - card_name: this._portsStore.get_value(iter, 6), - card_description: this._portsStore.get_value(iter, 7), - display_name: this._portsStore.get_value(iter, 8) - }); - } - } - success = this._portsStore.iter_next(iter); - } - setPortsSettings(ports, this._settings); - }, - - _restorePortsFromSettings: function() { - let ports = getPortsFromSettings(this._settings); - - let found; - for (let port of ports) { - found = false; - if (!port || !port.human_name || !port.name) { - continue; - } - - let [success, iter] = this._portsStore.get_iter_first(); - - while (iter && success) { - let human_name = this._portsStore.get_value(iter, 0); - let name = this._portsStore.get_value(iter, 4); - let card_name = this._portsStore.get_value(iter, 6); - - if (port.name == name && port.human_name == human_name && port.card_name == card_name) { - this._portsStore.set_value(iter, 3, false); - this._portsStore.set_value(iter, port.display_option, true); - this._portsStore.set_value(iter, 5, port.display_option); - found = true; - break; - } - success = this._portsStore.iter_next(iter); - } - - if (!found) { - iter = this._portsStore.append(); - this._portsStore.set(iter, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], - [port.human_name, false, false, false, port.name, port.display_option, port.card_name, port.card_description, port.display_name, ""]); - this._portsStore.set_value(iter, port.display_option, true); - } - } - } -}); - - -function buildPrefsWidget() { - let _settingsWidget = new SDCSettingsWidget(); - _settingsWidget.__showFn(); - - return _settingsWidget; -} diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/schemas/gschemas.compiled b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/schemas/gschemas.compiled deleted file mode 100644 index 7c5c5c1..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/schemas/gschemas.compiled and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/schemas/org.gnome.shell.extensions.sound-output-device-chooser.gschema.xml b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/schemas/org.gnome.shell.extensions.sound-output-device-chooser.gschema.xml deleted file mode 100644 index d34d510..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/schemas/org.gnome.shell.extensions.sound-output-device-chooser.gschema.xml +++ /dev/null @@ -1,101 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!DOCTYPE schemalist PUBLIC "gschema" "https://gitlab.gnome.org/GNOME/glib/raw/master/gio/gschema.dtd"> -<schemalist > - <schema id="org.gnome.shell.extensions.sound-output-device-chooser" path="/org/gnome/shell/extensions/sound-output-device-chooser/"> - <key name="hide-on-single-device" type="b"> - <default>false</default> - <summary>Preference to show the chooser when only one device is available</summary> - <description>Value set to false hides the device chooser when only one device is available</description> - </key> - - <key name="show-profiles" type="b"> - <default>true</default> - <summary>Preference to show the available profiles for all devices</summary> - <description>Value set to true displays the individual available profiles for each device</description> - </key> - - <key name="expand-volume-menu" type="b"> - <default>true</default> - <summary>Preference to expand volume menu to fit the name of the sound devices</summary> - <description>Value set to true expands the volume menu to fit the names of sound devices displayed in the selector</description> - </key> - - <key name="use-monochrome" type="b"> - <default>true</default> - <summary>Preference to use monochrome icons instead of default icons</summary> - <description>Value set to true uses monochrome icons</description> - </key> - - <key name="show-input-slider" type="b"> - <default>true</default> - <summary>Preference to show input slider always</summary> - <description>Value set to true displays the slider control for input device volume</description> - </key> - - <key name="show-input-devices" type="b"> - <default>true</default> - <summary>Preference to show input device chooser</summary> - <description>Value set to true displays the device chooser for input devices</description> - </key> - - <key name="show-output-devices" type="b"> - <default>true</default> - <summary>Preference to show output device chooser</summary> - <description>Value set to true displays the device chooser for output devices</description> - </key> - - <key name="ports-settings" type="s"> - <default>"{\"version\":3,\"ports\":[]}"</default> - <summary>Preference to hide/show different ports always</summary> - <description></description> - </key> - - <key name="icon-theme" type="s"> - <default>"monochrome"</default> - <summary>Preference indicating the type of icons used by the extension</summary> - <description>Value can be "colored", "monochrome", "none", etc.</description> - </key> - - <key name="hide-menu-icons" type="b"> - <default>false</default> - <summary>Preference indicating whether the icons are hidden in the drop-down menu (but are visible in the expanded list).</summary> - <description></description> - </key> - - <key name="enable-log" type="b"> - <default>false</default> - <summary>Preference indicating log messages should be written to console</summary> - <description></description> - </key> - - <key name="new-profile-indentification" type="b"> - <default>true</default> - <summary>(Deprecated)Old preference name with a typo. To be removed in the next shell version</summary> - <description></description> - </key> - - <key name="new-profile-identification" type="b"> - <default>true</default> - <summary>Preference to enable python script to identify port profiles</summary> - <description></description> - </key> - - <key name="cannot-activate-hidden-device" type="b"> - <default>true</default> - <summary>Preference to avoid activation of hidden devices in Port Settings</summary> - <description></description> - </key> - - <key name="omit-device-origins" type="b"> - <default>false</default> - <summary>Preference to omit device origin at Volume Menu</summary> - <description></description> - </key> - - <key name="integrate-with-slider" type="b"> - <default>false</default> - <summary>Preference to integrate selector with slider</summary> - <description></description> - </key> - </schema> -</schemalist> diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/ui/prefs-dialog.glade b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/ui/prefs-dialog.glade deleted file mode 100644 index b6e62e7..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/ui/prefs-dialog.glade +++ /dev/null @@ -1,956 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- Generated with glade 3.38.2 --> -<interface> - <requires lib="gtk+" version="3.12"/> - <object class="GtkListStore" id="icon-theme-store"> - <columns> - <!-- column-name Key --> - <column type="gchararray"/> - <!-- column-name Value --> - <column type="gchararray"/> - </columns> - <data> - <row> - <col id="0">monochrome</col> - <col id="1" translatable="yes">Monochrome</col> - </row> - <row> - <col id="0">colored</col> - <col id="1" translatable="yes">Colored</col> - </row> - <row> - <col id="0">none</col> - <col id="1" translatable="yes">None</col> - </row> - </data> - </object> - <object class="GtkListStore" id="ports-store"> - <columns> - <!-- column-name Port --> - <column type="gchararray"/> - <!-- column-name ShowAlways --> - <column type="gboolean"/> - <!-- column-name HideAlways --> - <column type="gboolean"/> - <!-- column-name ShowOnActive --> - <column type="gboolean"/> - <!-- column-name PortRealName --> - <column type="gchararray"/> - <!-- column-name SelectedColumn --> - <column type="gint"/> - <!-- column-name CardName --> - <column type="gchararray"/> - <!-- column-name CardDescription --> - <column type="gchararray"/> - <!-- column-name DisplayName --> - <column type="gchararray"/> - <!-- column-name DeviceType --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkBox" id="main-container"> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <property name="orientation">vertical</property> - <property name="spacing">2</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="hexpand">True</property> - <property name="vexpand">True</property> - <property name="homogeneous">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">12</property> - <property name="margin-bottom">12</property> - <property name="orientation">vertical</property> - <property name="spacing">12</property> - <child> - <object class="GtkFrame"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-start">10</property> - <property name="margin-end">10</property> - <property name="label-xalign">0.029999999329447746</property> - <property name="shadow-type">out</property> - <child> - <object class="GtkListBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="selection-mode">none</property> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Integrate selector with slider</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="integrate-with-slider"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="halign">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Hide selector if there's only one device</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="hide-on-single-device"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="halign">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Display audio profiles for selection</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="show-profiles"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="halign">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Omit device origins at Volume Menu</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="omit-device-origins"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="halign">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Extend Volume Menu to fit device names</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="expand-volume-menu"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="halign">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Don't allow device hidden in Port Settings to be activated</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="cannot-activate-hidden-device"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="halign">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">(Select / deselect the required device in the Gnome Sound Settings)</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="label" translatable="yes">General Settings</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkFrame"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-start">10</property> - <property name="margin-end">10</property> - <property name="label-xalign">0.029999999329447746</property> - <property name="shadow-type">out</property> - <child> - <object class="GtkListBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="valign">center</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Show output devices</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="show-output-devices"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="halign">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="label" translatable="yes">Output Devices</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - <child> - <object class="GtkFrame"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-start">10</property> - <property name="margin-end">10</property> - <property name="label-xalign">0.029999999329447746</property> - <property name="shadow-type">out</property> - <child> - <object class="GtkListBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="selection-mode">none</property> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="hexpand">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="valign">center</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Show input devices</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="show-input-devices"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="halign">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="valign">center</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Show volume control for default device</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="show-input-slider"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="halign">end</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="label" translatable="yes">Input Devices</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">2</property> - </packing> - </child> - <child> - <object class="GtkFrame"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-start">10</property> - <property name="margin-end">10</property> - <property name="label-xalign">0.029999999329447746</property> - <property name="shadow-type">in</property> - <child> - <object class="GtkListBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="selection-mode">none</property> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="name">6</property> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Icon Theme</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkComboBox" id="icon-theme"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="model">icon-theme-store</property> - <property name="id-column">0</property> - <child> - <object class="GtkCellRendererText" id="Text"/> - <attributes> - <attribute name="text">1</attribute> - </attributes> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Display icons only in selection list</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="hide-menu-icons"> - <property name="visible">True</property> - <property name="can-focus">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="label" translatable="yes">Icons</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">3</property> - </packing> - </child> - <child> - <object class="GtkFrame"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-start">10</property> - <property name="margin-end">10</property> - <property name="label-xalign">0.029999999329447746</property> - <property name="shadow-type">in</property> - <child> - <object class="GtkListBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="selection-mode">none</property> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="name">6</property> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Enable Log messages</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="enable-log"> - <property name="visible">True</property> - <property name="can-focus">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="visible">True</property> - <property name="can-focus">True</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="halign">start</property> - <property name="label" translatable="yes">Enable new profile identification</property> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkSwitch" id="new-profile-identification"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="active">True</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="label" translatable="yes">Miscellaneous</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">4</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-top">12</property> - <property name="margin-bottom">12</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkFrame"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-start">10</property> - <property name="margin-end">10</property> - <property name="vexpand">True</property> - <property name="label-xalign">0.029999999329447746</property> - <property name="shadow-type">out</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="margin-bottom">4</property> - <property name="vexpand">True</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="opacity">0.9999999986588954</property> - <property name="hexpand">True</property> - <property name="vexpand">True</property> - <property name="resize-mode">queue</property> - <property name="shadow-type">in</property> - <property name="min-content-width">500</property> - <child> - <object class="GtkTreeView" id="port-treeview"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="vexpand">True</property> - <property name="model">ports-store</property> - <property name="headers-clickable">False</property> - <property name="enable-grid-lines">both</property> - <child internal-child="selection"> - <object class="GtkTreeSelection" id="treeview-selection1"/> - </child> - <child> - <object class="GtkTreeViewColumn" id="PortNameColumn"> - <property name="resizable">True</property> - <property name="sizing">autosize</property> - <property name="min-width">100</property> - <property name="title" translatable="yes">Name</property> - <property name="expand">True</property> - <child> - <object class="GtkCellRendererText" id="PortNameRenderer"/> - <attributes> - <attribute name="text">8</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkTreeViewColumn" id="DeviceTypeColumn"> - <property name="sizing">autosize</property> - <property name="min-width">100</property> - <property name="title" translatable="yes">Device Type</property> - <property name="expand">True</property> - <property name="sort-order">descending</property> - <child> - <object class="GtkCellRendererText" id="DeviceTypeRenderer"/> - <attributes> - <attribute name="text">9</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkTreeViewColumn" id="ShowAlwaysColumn"> - <property name="visible">False</property> - <property name="sizing">autosize</property> - <property name="title" translatable="yes">Show</property> - <child> - <object class="GtkCellRendererToggle" id="ShowAlwaysToggleRender"> - <property name="radio">True</property> - </object> - <attributes> - <attribute name="active">1</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkTreeViewColumn" id="HideAlwaysColumn"> - <property name="sizing">autosize</property> - <property name="title" translatable="yes">Hide</property> - <child> - <object class="GtkCellRendererToggle" id="HideAlwaysToggleRender"> - <property name="radio">True</property> - </object> - <attributes> - <attribute name="active">2</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkTreeViewColumn" id="ShowOnActiveColumn"> - <property name="sizing">autosize</property> - <property name="title" translatable="yes">Default</property> - <child> - <object class="GtkCellRendererToggle" id="ShowActiveToggleRender"> - <property name="radio">True</property> - </object> - <attributes> - <attribute name="active">3</attribute> - </attributes> - </child> - </object> - </child> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="label" translatable="yes">Port Settings</property> - <attributes> - <attribute name="weight" value="bold"/> - </attributes> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> - </object> -</interface> diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/ui/prefs-dialog40.glade b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/ui/prefs-dialog40.glade deleted file mode 100644 index 7e30ccc..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/ui/prefs-dialog40.glade +++ /dev/null @@ -1,655 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <requires lib="gtk+" version="4.0"/> - <object class="GtkListStore" id="icon-theme-store"> - <columns> - <!-- column-name Key --> - <column type="gchararray"/> - <!-- column-name Value --> - <column type="gchararray"/> - </columns> - <data> - <row> - <col id="0">monochrome</col> - <col id="1" translatable="yes">Monochrome</col> - </row> - <row> - <col id="0">colored</col> - <col id="1" translatable="yes">Colored</col> - </row> - <row> - <col id="0">none</col> - <col id="1" translatable="yes">None</col> - </row> - </data> - </object> - <object class="GtkListStore" id="ports-store"> - <columns> - <!-- column-name Port --> - <column type="gchararray"/> - <!-- column-name ShowAlways --> - <column type="gboolean"/> - <!-- column-name HideAlways --> - <column type="gboolean"/> - <!-- column-name ShowOnActive --> - <column type="gboolean"/> - <!-- column-name PortRealName --> - <column type="gchararray"/> - <!-- column-name SelectedColumn --> - <column type="gint"/> - <!-- column-name CardName --> - <column type="gchararray"/> - <!-- column-name CardDescription --> - <column type="gchararray"/> - <!-- column-name DisplayName --> - <column type="gchararray"/> - <!-- column-name DeviceType --> - <column type="gchararray"/> - </columns> - </object> - <object class="GtkBox" id="main-container"> - <property name="visible">1</property> - <property name="margin-start">6</property> - <property name="margin-end">6</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <property name="orientation">vertical</property> - <property name="spacing">2</property> - <child> - <object class="GtkBox"> - <property name="can-focus">0</property> - <property name="hexpand">1</property> - <property name="vexpand">1</property> - <property name="homogeneous">1</property> - <child> - <object class="GtkBox"> - <property name="margin-start">12</property> - <property name="margin-end">6</property> - <property name="margin-top">12</property> - <property name="margin-bottom">12</property> - <property name="orientation">vertical</property> - <property name="spacing">12</property> - <child> - <object class="GtkFrame"> - <property name="can-focus">0</property> - <child> - <object class="GtkListBox"> - <property name="can-focus">0</property> - <property name="selection-mode">none</property> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="can-focus">0</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Integrate selector with slider</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="integrate-with-slider"> - <property name="halign">end</property> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="can-focus">0</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Hide selector if there's only one device</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="hide-on-single-device"> - <property name="halign">end</property> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Display audio profiles for selection</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="show-profiles"> - <property name="halign">end</property> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="margin-end">20</property> - <property name="label" translatable="yes">Omit device origins at Volume Menu</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="omit-device-origins"> - <property name="halign">end</property> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="margin-end">20</property> - <property name="label" translatable="yes">Extend Volume Menu to fit device names</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="expand-volume-menu"> - <property name="halign">end</property> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="margin-end">20</property> - <property name="label" translatable="yes">Don't allow device hidden in Port Settings to be activated</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="cannot-activate-hidden-device"> - <property name="halign">end</property> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <child> - <object class="GtkBox"> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="margin-end">20</property> - <property name="label" translatable="yes">(Select / deselect the required device in the Gnome Sound Settings)</property> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="label" translatable="yes">General Settings</property> - <attributes> - <attribute name="weight" value="bold"></attribute> - </attributes> - </object> - </child> - </object> - </child> - <child> - <object class="GtkFrame"> - <child> - - <object class="GtkListBox"> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="valign">center</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Show output devices</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="show-output-devices"> - <property name="halign">end</property> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="label" translatable="yes">Output Devices</property> - <attributes> - <attribute name="weight" value="bold"></attribute> - </attributes> - </object> - </child> - </object> - </child> - <child> - <object class="GtkFrame"> - <child> - - <object class="GtkListBox"> - <property name="selection-mode">none</property> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="hexpand">1</property> - <property name="child"> - <object class="GtkBox"> - <property name="valign">center</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Show input devices</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="show-input-devices"> - <property name="halign">end</property> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="valign">center</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Show volume control for default device</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="show-input-slider"> - <property name="halign">end</property> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="label" translatable="yes">Input Devices</property> - <attributes> - <attribute name="weight" value="bold"></attribute> - </attributes> - </object> - </child> - </object> - </child> - <child> - <object class="GtkFrame"> - <child> - - <object class="GtkListBox"> - <property name="selection-mode">none</property> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="name">6</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Icon Theme</property> - </object> - </child> - <child> - <object class="GtkComboBox" id="icon-theme"> - <property name="width-request">100</property> - <property name="margin-end">5</property> - <property name="model">icon-theme-store</property> - <property name="id-column">0</property> - <child> - <object class="GtkCellRendererText" id="Text" /> - <attributes> - <attribute name="text">1</attribute> - </attributes> - </child> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Display icons only in selection list</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="hide-menu-icons"> - <property name="margin-end">5</property> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="label" translatable="yes">Icons</property> - <attributes> - <attribute name="weight" value="bold"></attribute> - </attributes> - </object> - </child> - </object> - </child> - <child> - <object class="GtkFrame"> - <child> - - <object class="GtkListBox"> - <property name="selection-mode">none</property> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="name">6</property> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Enable Log messages</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="enable-log" /> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="width-request">100</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">6</property> - <property name="margin-bottom">6</property> - <child> - <object class="GtkLabel"> - <property name="hexpand">1</property> - <property name="halign">start</property> - <property name="margin-start">5</property> - <property name="label" translatable="yes">Enable new profile identification</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="new-profile-identification"> - <property name="active">1</property> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - > - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="label" translatable="yes">Miscellaneous</property> - <attributes> - <attribute name="weight" value="bold"></attribute> - </attributes> - </object> - </child> - </object> - </child> - </object> - </child> - <child> - <object class="GtkBox"> - <property name="margin-start">6</property> - <property name="margin-end">12</property> - <property name="margin-top">12</property> - <property name="margin-bottom">12</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkFrame"> - <property name="vexpand">1</property> - - <property name="child"> - <object class="GtkBox"> - <property name="margin-start">4</property> - <property name="margin-end">4</property> - <property name="margin-bottom">4</property> - <property name="vexpand">1</property> - <property name="orientation">vertical</property> - <child> - <object class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="opacity">0.9999999986588954</property> - <property name="hexpand">1</property> - <property name="vexpand">1</property> - <property name="min-content-width">500</property> - <property name="child"> - <object class="GtkBox"> <!--TODO: Delete when Gnome 40 get the scrolled window bug(?) get fixed--> - <child> <!--TODO: Delete when Gnome 40 get the scrolled window bug(?) get fixed--> - <object class="GtkTreeView" id="port-treeview"> - <property name="vexpand">1</property> - <property name="model">ports-store</property> - <child internal-child="selection"> - <object class="GtkTreeSelection" id="treeview-selection1" /> - </child> - <child> - <object class="GtkTreeViewColumn" id="PortNameColumn"> - <property name="resizable">1</property> - <property name="sizing">autosize</property> - <property name="min-width">100</property> - <property name="title" translatable="yes">Name</property> - <property name="expand">1</property> - <property name="sort-order">descending</property> - <child> - <object class="GtkCellRendererText" id="PortNameRenderer" /> - <attributes> - <attribute name="text">8</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkTreeViewColumn" id="DeviceTypeColumn"> - <property name="sizing">autosize</property> - <property name="min-width">100</property> - <property name="title" translatable="yes">Device Type</property> - <property name="expand">True</property> - <property name="sort-order">descending</property> - <child> - <object class="GtkCellRendererText" id="DeviceTypeRenderer"/> - <attributes> - <attribute name="text">9</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkTreeViewColumn" id="ShowAlwaysColumn"> - <property name="visible">False</property> - <property name="sizing">autosize</property> - <property name="title" translatable="yes">Show</property> - <child> - <object class="GtkCellRendererToggle" id="ShowAlwaysToggleRender"> - <property name="radio">1</property> - </object> - <attributes> - <attribute name="active">1</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkTreeViewColumn" id="HideAlwaysColumn"> - <property name="sizing">autosize</property> - <property name="title" translatable="yes">Hide</property> - <child> - <object class="GtkCellRendererToggle" id="HideAlwaysToggleRender"> - <property name="radio">1</property> - </object> - <attributes> - <attribute name="active">2</attribute> - </attributes> - </child> - </object> - </child> - <child> - <object class="GtkTreeViewColumn" id="ShowOnActiveColumn"> - <property name="sizing">autosize</property> - <property name="title" translatable="yes">Default</property> - <child> - <object class="GtkCellRendererToggle" id="ShowActiveToggleRender"> - <property name="radio">1</property> - </object> - <attributes> - <attribute name="active">3</attribute> - </attributes> - </child> - </object> - </child> - </object> - </child> <!--TODO: Delete when Gnome 40 get the scrolled window bug(?) get fixed--> - </object> <!--TODO: Delete when Gnome 40 get the scrolled window bug(?) get fixed--> - </property> - </object> - </child> - </object> - </property> - <child type="label"> - <object class="GtkLabel"> - <property name="label" translatable="yes">Port Settings</property> - <attributes> - <attribute name="weight" value="bold"></attribute> - </attributes> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - </child> - </object> -</interface> diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/__pycache__/libpulse_introspect.cpython-310.pyc b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/__pycache__/libpulse_introspect.cpython-310.pyc deleted file mode 100644 index cf3a19f..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/__pycache__/libpulse_introspect.cpython-310.pyc and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/__pycache__/libpulse_introspect.cpython-39.pyc b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/__pycache__/libpulse_introspect.cpython-39.pyc deleted file mode 100644 index 778f7f9..0000000 Binary files a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/__pycache__/libpulse_introspect.cpython-39.pyc and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/libpulse_introspect.py b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/libpulse_introspect.py deleted file mode 100644 index af4209a..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/libpulse_introspect.py +++ /dev/null @@ -1,544 +0,0 @@ -# This file is generated using clang2py script. The following files are used -# '/usr/include/pulse/introspect.h' '/usr/include/pulse/mainloop.h' '/usr/include/pulse/context.h' -# Refer additional licensing requirements for the files included -# sample commands used -# python3 /usr/bin/clang2py --clang-args="-I/usr/include/clang/6.0/include -I/usr/include/pulse" -l /usr/lib/libpulse.so '/usr/include/pulse/introspect.h' '/usr/include/pulse/mainloop.h' '/usr/include/pulse/proplist.h' -# python3 /usr/local/bin/clang2py --clang-args="-I/usr/include/clang/6.0/include -I/usr/include/pulse" -l /usr/lib/x86_64-linux-gnu/libpulse.so '/usr/include/pulse/introspect.h' '/usr/include/pulse/mainloop.h' -# python3 /usr/local/bin/clang2py --clang-args="-I/usr/include/clang/6.0/include -I/usr/include/pulse" -l /usr/lib/x86_64-linux-gnu/libpulse.so '/usr/include/pulse/context.h' -################################################################################ -# # This program is free software: you can redistribute it and/or modify it under -# # the terms of the GNU General Public License as published by the Free Software -# # Foundation, either version 3 of the License, or (at your option) any later -# # version. -# # -# # This program is distributed in the hope that it will be useful, but WITHOUT -# # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# # details. -# # -# # You should have received a copy of the GNU General Public License along with -# # this program. If not, see <http://www.gnu.org/licenses/>. -# # -# # Original Author: Gopi Sankar Karmegam -# ############################################################################## -# -#- coding: utf-8 -#- -# -# TARGET arch is: ['-I/usr/include/clang/6.0/include', '-I/usr/include/pulse'] -# WORD_SIZE is: 8 -# POINTER_SIZE is: 8 -# LONGDOUBLE_SIZE is: 16 -# - -# Updated to determine libpulse.so location -import ctypes -from ctypes.util import find_library - -c_int128 = ctypes.c_ubyte*16 -c_uint128 = c_int128 -void = None -if ctypes.sizeof(ctypes.c_longdouble) == 16: - c_long_double_t = ctypes.c_longdouble -else: - c_long_double_t = ctypes.c_ubyte*16 - -# if local wordsize is same as target, keep ctypes pointer function. -if ctypes.sizeof(ctypes.c_void_p) == 8: - POINTER_T = ctypes.POINTER -else: - # required to access _ctypes - import _ctypes - # Emulate a pointer class using the approriate c_int32/c_int64 type - # The new class should have : - # ['__module__', 'from_param', '_type_', '__dict__', '__weakref__', '__doc__'] - # but the class should be submitted to a unique instance for each base type - # to that if A == B, POINTER_T(A) == POINTER_T(B) - ctypes._pointer_t_type_cache = {} - def POINTER_T(pointee): - # a pointer should have the same length as LONG - fake_ptr_base_type = ctypes.c_uint64 - # specific case for c_void_p - if pointee is None: # VOID pointer type. c_void_p. - pointee = type(None) # ctypes.c_void_p # ctypes.c_ulong - clsname = 'c_void' - else: - clsname = pointee.__name__ - if clsname in ctypes._pointer_t_type_cache: - return ctypes._pointer_t_type_cache[clsname] - # make template - class _T(_ctypes._SimpleCData,): - _type_ = 'L' - _subtype_ = pointee - def _sub_addr_(self): - return self.value - def __repr__(self): - return '%s(%d)'%(clsname, self.value) - def contents(self): - raise TypeError('This is not a ctypes pointer.') - def __init__(self, **args): - raise TypeError('This is not a ctypes pointer. It is not instanciable.') - _class = type('LP_%d_%s'%(8, clsname), (_T,),{}) - ctypes._pointer_t_type_cache[clsname] = _class - return _class - -_libraries = {} - -libpulse_library_name = find_library('pulse') -if libpulse_library_name is None: - raise Exception('No libpulse.so library found!') - -try: - _libraries['libpulse.so'] = ctypes.cdll.LoadLibrary(libpulse_library_name) -except OSError: - raise Exception('Cannot load libpulse.so library!') - - -uint32_t = ctypes.c_uint32 - -size_t = ctypes.c_uint64 -class struct_pa_context(ctypes.Structure): - pass - -pa_context = struct_pa_context -pa_context_notify_cb_t = ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_context), POINTER_T(None)) -pa_context_success_cb_t = POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_context), ctypes.c_int32, POINTER_T(None))) - -class struct_pa_proplist(ctypes.Structure): - pass - -pa_context_event_cb_t = POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_context), ctypes.c_char_p, POINTER_T(struct_pa_proplist), POINTER_T(None))) -class struct_pa_mainloop_api(ctypes.Structure): - pass - -pa_context_new = _libraries['libpulse.so'] .pa_context_new -pa_context_new.restype = POINTER_T(struct_pa_context) -pa_context_new.argtypes = [POINTER_T(struct_pa_mainloop_api), ctypes.c_char_p] - -# pa_context_new_with_proplist = _libraries['libpulse.so'] .pa_context_new_with_proplist -# pa_context_new_with_proplist.restype = POINTER_T(struct_pa_context) -# pa_context_new_with_proplist.argtypes = [POINTER_T(struct_pa_mainloop_api), ctypes.c_char_p, POINTER_T(struct_pa_proplist)] - -pa_context_unref = _libraries['libpulse.so'] .pa_context_unref -pa_context_unref.restype = None -pa_context_unref.argtypes = [POINTER_T(struct_pa_context)] - -# pa_context_ref = _libraries['libpulse.so'] .pa_context_ref -# pa_context_ref.restype = POINTER_T(struct_pa_context) -# pa_context_ref.argtypes = [POINTER_T(struct_pa_context)] - -pa_context_set_state_callback = _libraries['libpulse.so'] .pa_context_set_state_callback -pa_context_set_state_callback.restype = None -pa_context_set_state_callback.argtypes = [POINTER_T(struct_pa_context), pa_context_notify_cb_t, POINTER_T(None)] -# -# pa_context_set_event_callback = _libraries['libpulse.so'] .pa_context_set_event_callback -# pa_context_set_event_callback.restype = None -# pa_context_set_event_callback.argtypes = [POINTER_T(struct_pa_context), pa_context_event_cb_t, POINTER_T(None)] -# -# pa_context_errno = _libraries['libpulse.so'] .pa_context_errno -# pa_context_errno.restype = ctypes.c_int32 -# pa_context_errno.argtypes = [POINTER_T(struct_pa_context)] -# -# pa_context_is_pending = _libraries['libpulse.so'] .pa_context_is_pending -# pa_context_is_pending.restype = ctypes.c_int32 -# pa_context_is_pending.argtypes = [POINTER_T(struct_pa_context)] - - - -# values for enumeration 'pa_context_state' -pa_context_state__enumvalues = { - 0: 'PA_CONTEXT_UNCONNECTED', - 1: 'PA_CONTEXT_CONNECTING', - 2: 'PA_CONTEXT_AUTHORIZING', - 3: 'PA_CONTEXT_SETTING_NAME', - 4: 'PA_CONTEXT_READY', - 5: 'PA_CONTEXT_FAILED', - 6: 'PA_CONTEXT_TERMINATED', -} - -PA_CONTEXT_UNCONNECTED = 0 -PA_CONTEXT_CONNECTING = 1 -PA_CONTEXT_AUTHORIZING = 2 -PA_CONTEXT_SETTING_NAME = 3 -PA_CONTEXT_READY = 4 -PA_CONTEXT_FAILED = 5 -PA_CONTEXT_TERMINATED = 6 - -pa_context_state = ctypes.c_int # enum -pa_context_state_t = pa_context_state -pa_context_state_t__enumvalues = pa_context_state__enumvalues - -pa_context_get_state = _libraries['libpulse.so'] .pa_context_get_state -pa_context_get_state.restype = pa_context_state_t -pa_context_get_state.argtypes = [POINTER_T(struct_pa_context)] - -# values for enumeration 'pa_context_flags' -pa_context_flags__enumvalues = { - 0: 'PA_CONTEXT_NOFLAGS', - 1: 'PA_CONTEXT_NOAUTOSPAWN', - 2: 'PA_CONTEXT_NOFAIL', -} -PA_CONTEXT_NOFLAGS = 0 -PA_CONTEXT_NOAUTOSPAWN = 1 -PA_CONTEXT_NOFAIL = 2 -pa_context_flags = ctypes.c_int # enum -pa_context_flags_t = pa_context_flags -pa_context_flags_t__enumvalues = pa_context_flags__enumvalues -class struct_pa_spawn_api(ctypes.Structure): - pass - -pa_context_connect = _libraries['libpulse.so'] .pa_context_connect -pa_context_connect.restype = ctypes.c_int32 -pa_context_connect.argtypes = [POINTER_T(struct_pa_context), ctypes.c_char_p, pa_context_flags_t, POINTER_T(struct_pa_spawn_api)] -pa_context_disconnect = _libraries['libpulse.so'] .pa_context_disconnect -pa_context_disconnect.restype = None -pa_context_disconnect.argtypes = [POINTER_T(struct_pa_context)] - -class struct_pa_operation(ctypes.Structure): - pass - -# pa_context_drain = _libraries['libpulse.so'] .pa_context_drain -# pa_context_drain.restype = POINTER_T(struct_pa_operation) -# pa_context_drain.argtypes = [POINTER_T(struct_pa_context), pa_context_notify_cb_t, POINTER_T(None)] -# pa_context_exit_daemon = _libraries['libpulse.so'] .pa_context_exit_daemon -# pa_context_exit_daemon.restype = POINTER_T(struct_pa_operation) -# pa_context_exit_daemon.argtypes = [POINTER_T(struct_pa_context), pa_context_success_cb_t, POINTER_T(None)] -# pa_context_set_default_sink = _libraries['libpulse.so'] .pa_context_set_default_sink -# pa_context_set_default_sink.restype = POINTER_T(struct_pa_operation) -# pa_context_set_default_sink.argtypes = [POINTER_T(struct_pa_context), ctypes.c_char_p, pa_context_success_cb_t, POINTER_T(None)] -# pa_context_set_default_source = _libraries['libpulse.so'] .pa_context_set_default_source -# pa_context_set_default_source.restype = POINTER_T(struct_pa_operation) -# pa_context_set_default_source.argtypes = [POINTER_T(struct_pa_context), ctypes.c_char_p, pa_context_success_cb_t, POINTER_T(None)] -# pa_context_is_local = _libraries['libpulse.so'] .pa_context_is_local -# pa_context_is_local.restype = ctypes.c_int32 -# pa_context_is_local.argtypes = [POINTER_T(struct_pa_context)] -# pa_context_set_name = _libraries['libpulse.so'] .pa_context_set_name -# pa_context_set_name.restype = POINTER_T(struct_pa_operation) -# pa_context_set_name.argtypes = [POINTER_T(struct_pa_context), ctypes.c_char_p, pa_context_success_cb_t, POINTER_T(None)] -# pa_context_get_server = _libraries['libpulse.so'] .pa_context_get_server -# pa_context_get_server.restype = ctypes.c_char_p -# pa_context_get_server.argtypes = [POINTER_T(struct_pa_context)] - -# pa_context_get_protocol_version = _libraries['libpulse.so'] .pa_context_get_protocol_version -# pa_context_get_protocol_version.restype = uint32_t -# pa_context_get_protocol_version.argtypes = [POINTER_T(struct_pa_context)] -# pa_context_get_server_protocol_version = _libraries['libpulse.so'] .pa_context_get_server_protocol_version -# pa_context_get_server_protocol_version.restype = uint32_t -# pa_context_get_server_protocol_version.argtypes = [POINTER_T(struct_pa_context)] -class struct_pa_card_profile_info(ctypes.Structure): - _pack_ = True # source:False - _fields_ = [ - ('name', ctypes.c_char_p), - ('description', ctypes.c_char_p), - ('n_sinks', ctypes.c_uint32), - ('n_sources', ctypes.c_uint32), - ('priority', ctypes.c_uint32), - ('PADDING_0', ctypes.c_ubyte * 4), - ] - -pa_card_profile_info = struct_pa_card_profile_info -class struct_pa_card_profile_info2(ctypes.Structure): - _pack_ = True # source:False - _fields_ = [ - ('name', ctypes.c_char_p), - ('description', ctypes.c_char_p), - ('n_sinks', ctypes.c_uint32), - ('n_sources', ctypes.c_uint32), - ('priority', ctypes.c_uint32), - ('available', ctypes.c_int32), - ] - -pa_card_profile_info2 = struct_pa_card_profile_info2 -class struct_pa_card_port_info(ctypes.Structure): - _pack_ = True # source:False - _fields_ = [ - ('name', ctypes.c_char_p), - ('description', ctypes.c_char_p), - ('priority', ctypes.c_uint32), - ('available', ctypes.c_int32), - ('direction', ctypes.c_int32), - ('n_profiles', ctypes.c_uint32), - ('profiles', POINTER_T(POINTER_T(struct_pa_card_profile_info))), - ('proplist', POINTER_T(struct_pa_proplist)), - ('latency_offset', ctypes.c_int64), - ('profiles2', POINTER_T(POINTER_T(struct_pa_card_profile_info2))), - ] - -pa_card_port_info = struct_pa_card_port_info -class struct_pa_card_info(ctypes.Structure): - _pack_ = True # source:False - _fields_ = [ - ('index', ctypes.c_uint32), - ('PADDING_0', ctypes.c_ubyte * 4), - ('name', ctypes.c_char_p), - ('owner_module', ctypes.c_uint32), - ('PADDING_1', ctypes.c_ubyte * 4), - ('driver', ctypes.c_char_p), - ('n_profiles', ctypes.c_uint32), - ('PADDING_2', ctypes.c_ubyte * 4), - ('profiles', POINTER_T(struct_pa_card_profile_info)), - ('active_profile', POINTER_T(struct_pa_card_profile_info)), - ('proplist', POINTER_T(struct_pa_proplist)), - ('n_ports', ctypes.c_uint32), - ('PADDING_3', ctypes.c_ubyte * 4), - ('ports', POINTER_T(POINTER_T(struct_pa_card_port_info))), - ('profiles2', POINTER_T(POINTER_T(struct_pa_card_profile_info2))), - ('active_profile2', POINTER_T(struct_pa_card_profile_info2)), - ] - -pa_card_info = struct_pa_card_info -pa_card_info_cb_t = ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_context), POINTER_T(struct_pa_card_info), ctypes.c_int32, POINTER_T(None)) -pa_context_get_card_info_by_index = _libraries['libpulse.so'].pa_context_get_card_info_by_index -pa_context_get_card_info_by_index.restype = POINTER_T(struct_pa_operation) -pa_context_get_card_info_by_index.argtypes = [POINTER_T(struct_pa_context), uint32_t, pa_card_info_cb_t, POINTER_T(None)] - - -pa_context_get_card_info_list = _libraries['libpulse.so'].pa_context_get_card_info_list -pa_context_get_card_info_list.restype = POINTER_T(struct_pa_operation) -pa_context_get_card_info_list.argtypes = [POINTER_T(struct_pa_context), pa_card_info_cb_t, POINTER_T(None)] - - -# values for enumeration 'pa_update_mode' -# pa_update_mode__enumvalues = { -# 0: 'PA_UPDATE_SET', -# 1: 'PA_UPDATE_MERGE', -# 2: 'PA_UPDATE_REPLACE', -# } -# PA_UPDATE_SET = 0 -# PA_UPDATE_MERGE = 1 -# PA_UPDATE_REPLACE = 2 -# pa_update_mode = ctypes.c_int # enum -# pa_update_mode_t = pa_update_mode -# pa_update_mode_t__enumvalues = pa_update_mode__enumvalues -# pa_context_proplist_update = _libraries['libpulse.so'] .pa_context_proplist_update -# pa_context_proplist_update.restype = POINTER_T(struct_pa_operation) -# pa_context_proplist_update.argtypes = [POINTER_T(struct_pa_context), pa_update_mode_t, POINTER_T(struct_pa_proplist), pa_context_success_cb_t, POINTER_T(None)] -# pa_context_proplist_remove = _libraries['libpulse.so'] .pa_context_proplist_remove -# pa_context_proplist_remove.restype = POINTER_T(struct_pa_operation) -# pa_context_proplist_remove.argtypes = [POINTER_T(struct_pa_context), ctypes.c_char_p * 0, pa_context_success_cb_t, POINTER_T(None)] -# pa_context_get_index = _libraries['libpulse.so'] .pa_context_get_index -# pa_context_get_index.restype = uint32_t -# pa_context_get_index.argtypes = [POINTER_T(struct_pa_context)] -class struct_pa_time_event(ctypes.Structure): - pass - -# pa_usec_t = ctypes.c_uint64 -class struct_timeval(ctypes.Structure): - pass -# -# pa_time_event_cb_t = POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_mainloop_api), POINTER_T(struct_pa_time_event), POINTER_T(struct_timeval), POINTER_T(None))) -# pa_context_rttime_new = _libraries['libpulse.so'] .pa_context_rttime_new -# pa_context_rttime_new.restype = POINTER_T(struct_pa_time_event) -# pa_context_rttime_new.argtypes = [POINTER_T(struct_pa_context), pa_usec_t, pa_time_event_cb_t, POINTER_T(None)] -# pa_context_rttime_restart = _libraries['libpulse.so'] .pa_context_rttime_restart -# pa_context_rttime_restart.restype = None -# pa_context_rttime_restart.argtypes = [POINTER_T(struct_pa_context), POINTER_T(struct_pa_time_event), pa_usec_t] -class struct_pa_sample_spec(ctypes.Structure): - pass - -# pa_context_get_tile_size = _libraries['libpulse.so'] .pa_context_get_tile_size -# pa_context_get_tile_size.restype = size_t -# pa_context_get_tile_size.argtypes = [POINTER_T(struct_pa_context), POINTER_T(struct_pa_sample_spec)] -# pa_context_load_cookie_from_file = _libraries['libpulse.so'] .pa_context_load_cookie_from_file -# pa_context_load_cookie_from_file.restype = ctypes.c_int32 -# pa_context_load_cookie_from_file.argtypes = [POINTER_T(struct_pa_context), ctypes.c_char_p] -# struct_pa_spawn_api._pack_ = True # source:False -# struct_pa_spawn_api._fields_ = [ -# ('prefork', POINTER_T(ctypes.CFUNCTYPE(None))), -# ('postfork', POINTER_T(ctypes.CFUNCTYPE(None))), -# ('atfork', POINTER_T(ctypes.CFUNCTYPE(None))), -# ] -# - -# values for enumeration 'pa_io_event_flags' -pa_io_event_flags__enumvalues = { - 0: 'PA_IO_EVENT_NULL', - 1: 'PA_IO_EVENT_INPUT', - 2: 'PA_IO_EVENT_OUTPUT', - 4: 'PA_IO_EVENT_HANGUP', - 8: 'PA_IO_EVENT_ERROR', -} -PA_IO_EVENT_NULL = 0 -PA_IO_EVENT_INPUT = 1 -PA_IO_EVENT_OUTPUT = 2 -PA_IO_EVENT_HANGUP = 4 -PA_IO_EVENT_ERROR = 8 -pa_io_event_flags = ctypes.c_int # enum -class struct_pa_io_event(ctypes.Structure): - pass - -class struct_pa_defer_event(ctypes.Structure): - pass - -struct_pa_mainloop_api._pack_ = True # source:False -struct_pa_mainloop_api._fields_ = [ - ('userdata', POINTER_T(None)), - ('io_new', POINTER_T(ctypes.CFUNCTYPE(POINTER_T(struct_pa_io_event), POINTER_T(struct_pa_mainloop_api), ctypes.c_int32, pa_io_event_flags, POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_mainloop_api), POINTER_T(struct_pa_io_event), ctypes.c_int32, pa_io_event_flags, POINTER_T(None))), POINTER_T(None)))), - ('io_enable', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_io_event), pa_io_event_flags))), - ('io_free', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_io_event)))), - ('io_set_destroy', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_io_event), POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_mainloop_api), POINTER_T(struct_pa_io_event), POINTER_T(None)))))), - ('time_new', POINTER_T(ctypes.CFUNCTYPE(POINTER_T(struct_pa_time_event), POINTER_T(struct_pa_mainloop_api), POINTER_T(struct_timeval), POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_mainloop_api), POINTER_T(struct_pa_time_event), POINTER_T(struct_timeval), POINTER_T(None))), POINTER_T(None)))), - ('time_restart', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_time_event), POINTER_T(struct_timeval)))), - ('time_free', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_time_event)))), - ('time_set_destroy', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_time_event), POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_mainloop_api), POINTER_T(struct_pa_time_event), POINTER_T(None)))))), - ('defer_new', POINTER_T(ctypes.CFUNCTYPE(POINTER_T(struct_pa_defer_event), POINTER_T(struct_pa_mainloop_api), POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_mainloop_api), POINTER_T(struct_pa_defer_event), POINTER_T(None))), POINTER_T(None)))), - ('defer_enable', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_defer_event), ctypes.c_int32))), - ('defer_free', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_defer_event)))), - ('defer_set_destroy', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_defer_event), POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_mainloop_api), POINTER_T(struct_pa_defer_event), POINTER_T(None)))))), - ('quit', POINTER_T(ctypes.CFUNCTYPE(None, POINTER_T(struct_pa_mainloop_api), ctypes.c_int32))), -] - -class struct_pollfd(ctypes.Structure): - pass - -class struct_pa_mainloop(ctypes.Structure): - pass - -pa_mainloop = struct_pa_mainloop -pa_mainloop_new = _libraries['libpulse.so'] .pa_mainloop_new -pa_mainloop_new.restype = POINTER_T(struct_pa_mainloop) -pa_mainloop_new.argtypes = [] -pa_mainloop_free = _libraries['libpulse.so'] .pa_mainloop_free -pa_mainloop_free.restype = None -pa_mainloop_free.argtypes = [POINTER_T(struct_pa_mainloop)] - -# pa_mainloop_prepare = _libraries['libpulse.so'] .pa_mainloop_prepare -# pa_mainloop_prepare.restype = ctypes.c_int32 -# pa_mainloop_prepare.argtypes = [POINTER_T(struct_pa_mainloop), ctypes.c_int32] -# pa_mainloop_poll = _libraries['libpulse.so'] .pa_mainloop_poll -# pa_mainloop_poll.restype = ctypes.c_int32 -# pa_mainloop_poll.argtypes = [POINTER_T(struct_pa_mainloop)] -# pa_mainloop_dispatch = _libraries['libpulse.so'] .pa_mainloop_dispatch -# pa_mainloop_dispatch.restype = ctypes.c_int32 -# pa_mainloop_dispatch.argtypes = [POINTER_T(struct_pa_mainloop)] -# pa_mainloop_get_retval = _libraries['libpulse.so'] .pa_mainloop_get_retval -# pa_mainloop_get_retval.restype = ctypes.c_int32 -# pa_mainloop_get_retval.argtypes = [POINTER_T(struct_pa_mainloop)] - -pa_mainloop_iterate = _libraries['libpulse.so'] .pa_mainloop_iterate -pa_mainloop_iterate.restype = ctypes.c_int32 -pa_mainloop_iterate.argtypes = [POINTER_T(struct_pa_mainloop), ctypes.c_int32, POINTER_T(ctypes.c_int32)] - -# pa_mainloop_run = _libraries['libpulse.so'] .pa_mainloop_run -# pa_mainloop_run.restype = ctypes.c_int32 -# pa_mainloop_run.argtypes = [POINTER_T(struct_pa_mainloop), POINTER_T(ctypes.c_int32)] -pa_mainloop_get_api = _libraries['libpulse.so'] .pa_mainloop_get_api -pa_mainloop_get_api.restype = POINTER_T(struct_pa_mainloop_api) -pa_mainloop_get_api.argtypes = [POINTER_T(struct_pa_mainloop)] -# pa_mainloop_quit = _libraries['libpulse.so'] .pa_mainloop_quit -# pa_mainloop_quit.restype = None -# pa_mainloop_quit.argtypes = [POINTER_T(struct_pa_mainloop), ctypes.c_int32] -# pa_mainloop_wakeup = _libraries['libpulse.so'] .pa_mainloop_wakeup -# pa_mainloop_wakeup.restype = None -# pa_mainloop_wakeup.argtypes = [POINTER_T(struct_pa_mainloop)] -# pa_poll_func = POINTER_T(ctypes.CFUNCTYPE(ctypes.c_int32, POINTER_T(struct_pollfd), ctypes.c_uint64, ctypes.c_int32, POINTER_T(None))) -# pa_mainloop_set_poll_func = _libraries['libpulse.so'] .pa_mainloop_set_poll_func -# pa_mainloop_set_poll_func.restype = None -# pa_mainloop_set_poll_func.argtypes = [POINTER_T(struct_pa_mainloop), pa_poll_func, POINTER_T(None)] - -pa_operation_unref = _libraries['libpulse.so'] .pa_operation_unref -pa_operation_unref.restype = None -pa_operation_unref.argtypes = [POINTER_T(struct_pa_operation)] - -# values for enumeration 'pa_sample_format' -# pa_sample_format__enumvalues = { -# 0: 'PA_SAMPLE_U8', -# 1: 'PA_SAMPLE_ALAW', -# 2: 'PA_SAMPLE_ULAW', -# 3: 'PA_SAMPLE_S16LE', -# 4: 'PA_SAMPLE_S16BE', -# 5: 'PA_SAMPLE_FLOAT32LE', -# 6: 'PA_SAMPLE_FLOAT32BE', -# 7: 'PA_SAMPLE_S32LE', -# 8: 'PA_SAMPLE_S32BE', -# 9: 'PA_SAMPLE_S24LE', -# 10: 'PA_SAMPLE_S24BE', -# 11: 'PA_SAMPLE_S24_32LE', -# 12: 'PA_SAMPLE_S24_32BE', -# 13: 'PA_SAMPLE_MAX', -# -1: 'PA_SAMPLE_INVALID', -# } -# PA_SAMPLE_U8 = 0 -# PA_SAMPLE_ALAW = 1 -# PA_SAMPLE_ULAW = 2 -# PA_SAMPLE_S16LE = 3 -# PA_SAMPLE_S16BE = 4 -# PA_SAMPLE_FLOAT32LE = 5 -# PA_SAMPLE_FLOAT32BE = 6 -# PA_SAMPLE_S32LE = 7 -# PA_SAMPLE_S32BE = 8 -# PA_SAMPLE_S24LE = 9 -# PA_SAMPLE_S24BE = 10 -# PA_SAMPLE_S24_32LE = 11 -# PA_SAMPLE_S24_32BE = 12 -# PA_SAMPLE_MAX = 13 -# PA_SAMPLE_INVALID = -1 -# pa_sample_format = ctypes.c_int # enum -# struct_pa_sample_spec._pack_ = True # source:False -# struct_pa_sample_spec._fields_ = [ -# ('format', pa_sample_format), -# ('rate', ctypes.c_uint32), -# ('channels', ctypes.c_ubyte), -# ('PADDING_0', ctypes.c_ubyte * 3), -# ] -# -# struct_timeval._pack_ = True # source:False -# struct_timeval._fields_ = [ -# ('tv_sec', ctypes.c_int64), -# ('tv_usec', ctypes.c_int64), -# ] - -pa_proplist_to_string = _libraries['libpulse.so'].pa_proplist_to_string -pa_proplist_to_string.restype = POINTER_T(ctypes.c_char) -pa_proplist_to_string.argtypes = [POINTER_T(struct_pa_proplist)] - -pa_proplist_gets = _libraries['libpulse.so'].pa_proplist_gets -pa_proplist_gets.restype = POINTER_T(ctypes.c_char) -pa_proplist_gets.argtypes = [POINTER_T(struct_pa_proplist), POINTER_T(ctypes.c_char)] -PA_DIRECTION_OUTPUT = 0x0001 -PA_DIRECTION_INPUT = 0x0002 - - -__all__ = \ - ['PA_CONTEXT_AUTHORIZING', 'PA_CONTEXT_CONNECTING', - 'PA_CONTEXT_FAILED', 'PA_CONTEXT_NOAUTOSPAWN', - 'PA_CONTEXT_NOFAIL', 'PA_CONTEXT_NOFLAGS', 'PA_CONTEXT_READY', - 'PA_CONTEXT_SETTING_NAME', 'PA_CONTEXT_TERMINATED', - 'PA_CONTEXT_UNCONNECTED', 'PA_IO_EVENT_ERROR', - 'PA_IO_EVENT_HANGUP', 'PA_IO_EVENT_INPUT', 'PA_IO_EVENT_NULL', - 'PA_IO_EVENT_OUTPUT', 'PA_SAMPLE_ALAW', 'PA_SAMPLE_FLOAT32BE', - 'PA_SAMPLE_FLOAT32LE', 'PA_SAMPLE_INVALID', 'PA_SAMPLE_MAX', - 'PA_SAMPLE_S16BE', 'PA_SAMPLE_S16LE', 'PA_SAMPLE_S24BE', - 'PA_SAMPLE_S24LE', 'PA_SAMPLE_S24_32BE', 'PA_SAMPLE_S24_32LE', - 'PA_SAMPLE_S32BE', 'PA_SAMPLE_S32LE', 'PA_SAMPLE_U8', - 'PA_SAMPLE_ULAW', 'PA_UPDATE_MERGE', 'PA_UPDATE_REPLACE', - 'PA_UPDATE_SET', 'pa_context', 'pa_context_connect', - 'pa_context_disconnect', 'pa_context_drain', 'pa_context_errno', - 'pa_context_event_cb_t', 'pa_context_exit_daemon', - 'pa_context_flags', 'pa_context_flags_t', - 'pa_context_flags_t__enumvalues', 'pa_context_get_index', - 'pa_context_get_protocol_version', 'pa_context_get_server', - 'pa_context_get_server_protocol_version', 'pa_context_get_state', - 'pa_context_get_tile_size', 'pa_context_is_local', - 'pa_context_is_pending', 'pa_context_load_cookie_from_file', - 'pa_context_new', 'pa_context_new_with_proplist', - 'pa_context_notify_cb_t', 'pa_context_proplist_remove', - 'pa_context_proplist_update', 'pa_context_ref', - 'pa_context_rttime_new', 'pa_context_rttime_restart', - 'pa_context_set_default_sink', 'pa_context_set_default_source', - 'pa_context_set_event_callback', 'pa_context_set_name', - 'pa_context_set_state_callback', 'pa_context_state', - 'pa_context_state_t', 'pa_context_state_t__enumvalues', - 'pa_context_success_cb_t', 'pa_context_unref', - 'pa_io_event_flags', 'pa_mainloop', 'pa_mainloop_dispatch', - 'pa_mainloop_free', 'pa_mainloop_get_api', - 'pa_mainloop_get_retval', 'pa_mainloop_iterate', - 'pa_mainloop_new', 'pa_mainloop_poll', 'pa_mainloop_prepare', - 'pa_mainloop_quit', 'pa_mainloop_run', - 'pa_mainloop_set_poll_func', 'pa_mainloop_wakeup', 'pa_poll_func', - 'pa_sample_format', 'pa_time_event_cb_t', 'pa_update_mode', - 'pa_update_mode_t', 'pa_update_mode_t__enumvalues', 'pa_usec_t', - 'size_t', 'struct_pa_context', 'struct_pa_defer_event', - 'struct_pa_io_event', 'struct_pa_mainloop', - 'struct_pa_mainloop_api', 'struct_pa_operation', - 'struct_pa_proplist', 'struct_pa_sample_spec', - 'struct_pa_spawn_api', 'struct_pa_time_event', 'struct_pollfd', - 'struct_timeval', 'uint32_t','pa_proplist_to_string','pa_proplist_gets','PA_DIRECTION_OUTPUT', 'PA_DIRECTION_INPUT'] diff --git a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/pa_helper.py b/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/pa_helper.py deleted file mode 100644 index 6ec79a0..0000000 --- a/.local/share/gnome-shell/extensions/sound-output-device-chooser@kgshank.net/utils/pa_helper.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/python -############################################################################### - # This program is free software: you can redistribute it and/or modify it under - # the terms of the GNU General Public License as published by the Free Software - # Foundation, either version 3 of the License, or (at your option) any later - # version. - # - # This program is distributed in the hope that it will be useful, but WITHOUT - # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - # details. - # - # You should have received a copy of the GNU General Public License along with - # this program. If not, see <http://www.gnu.org/licenses/>. - # - # Original Author: Gopi Sankar Karmegam - ############################################################################## - -import libpulse_introspect as pa -import sys -from ctypes import c_int,byref, c_char_p, cast -import time -from json import dumps - -class PAHelper(): - - _error = { - 'success': False, - 'error': None, - } - _card_op_done = None - _pa_state = pa.PA_CONTEXT_UNCONNECTED - - - def __init__(self): - self._ports = [] - self._cards = {} - self.mainloop = pa.pa_mainloop_new() - self._context = pa.pa_context_new( pa.pa_mainloop_get_api(self.mainloop), b'PAHelper') - self._pa_context_notify_cb_t = pa.pa_context_notify_cb_t(self.pa_context_notify_cb_t) - pa.pa_context_set_state_callback(self._context, self._pa_context_notify_cb_t , None) - pa.pa_context_connect(self._context, None, 0, None) - self._opn_completed = False - - def print_card_info(self, index = None): - operation = None - retVal = c_int() - counter = 0 - - while counter < 10000 and self._opn_completed == False: - counter += 1 - if self._pa_state == pa.PA_CONTEXT_READY and operation == None: - self._pa_card_info_cb_t = pa.pa_card_info_cb_t(self.pa_card_info_cb) -# operation = pa.pa_context_get_card_info_by_index(self._context, -# index, self._pa_card_info_cb_t , None) - operation = pa.pa_context_get_card_info_list(self._context, - self._pa_card_info_cb_t , None) - - pa.pa_mainloop_iterate(self.mainloop, 0, byref(retVal)) - print(dumps({'cards': self._cards, 'ports':self._ports}, indent = 5)) - - try: - if operation: - pa.pa_operation_unref(operation) - - pa.pa_context_disconnect(self._context) - pa.pa_context_unref(self._context) - pa.pa_mainloop_free(self.mainloop) - except: - pass - - def pa_card_info_cb(self, context, card_info, eol, whatever): - - if not card_info or not card_info[0]: - return - - card = card_info[0] - #print (card.index) - card_obj = {} - card_obj['index'] = str(card.index) - self._cards[card.index] = card_obj - card_obj['profiles'] = [] - - card_name = cast(pa.pa_proplist_gets(card.proplist,c_char_p(b'alsa.card_name')),c_char_p) - card_obj['alsa_name'] = card_name.value.decode('utf8') if card_name else '' - description = cast(pa.pa_proplist_gets(card.proplist,c_char_p(b'device.description')),c_char_p) - card_obj['card_description'] = description.value.decode('utf8') if description else '' - - card_obj['name'] = card.name.decode('utf8') if card.name else '' - for k in range(0, card.n_profiles): - if(card.profiles2[k]): - profile = card.profiles2[k].contents - pobj = {} - pobj['name'] = profile.name.decode('utf8') if profile.name else '' - pobj['human_name'] = profile.description.decode('utf8') if profile.description else '' - pobj['available'] = profile.available - card_obj['profiles'].append(pobj) - - card_obj['ports'] = [] - for i in range(0, card.n_ports): - port = card.ports[i].contents -# print ("Port name "+ str(port.name)) - obj = {} - obj['name'] = port.name.decode('utf8') if port.name else '' - obj['human_name'] = port.description.decode('utf8') if port.description else '' - obj['direction'] = 'Output' if (port.direction & pa.PA_DIRECTION_OUTPUT) else 'Input' - obj['available'] = port.available - obj['n_profiles'] = port.n_profiles - obj['profiles'] = [] - obj['card_name'] = card_obj['name'] - obj['card_description'] = card_obj['card_description'] - for j in range(0, port.n_profiles): - if(port.profiles2[j]): - profile = port.profiles2[j].contents -# pobj = {} -# pobj['name'] = profile.name.decode('utf8') if profile.name else '' -# pobj['human_name'] = profile.description.decode('utf8') if profile.description else '' -# pobj['available'] = profile.available -# obj['profiles'].append(pobj) - if profile.name: - obj['profiles'].append(profile.name.decode('utf8')) - - self._ports.append(obj) - card_obj['ports'].append(obj) - - - - self._opn_completed = True - - - def pa_context_notify_cb_t(self, context, userdata): - try: - self._pa_state = pa.pa_context_get_state(context) - - except Exception: - self._pa_state = pa.PA_CONTEXT_FAILED - - -PAHelper().print_card_info() - - diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/README b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/README deleted file mode 100644 index 1f14023..0000000 --- a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/README +++ /dev/null @@ -1,6 +0,0 @@ -Dependencies: -libclutter, libgtop and NetworkManager gir bindings, and gnome-system-monitor - on Debian and Ubuntu: gir1.2-gtop-2.0, gir1.2-nm-1.0, gnome-system-monitor - on Fedora: libgtop2-devel NetworkManager-libnm-devel, gnome-system-monitor - on Mageia 64-bit: lib64gtop-gir2.0, lib64nm-gir1.0, lib64clutter-gir1.0, gnome-system-monitor - on Arch Linux: libgtop, networkmanager, gnome-system-monitor diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js deleted file mode 100644 index 2e1be07..0000000 --- a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/compat.js +++ /dev/null @@ -1,51 +0,0 @@ -const Config = imports.misc.config; -const Clutter = imports.gi.Clutter; - -/** Compare two dotted version strings (like '10.2.3'). - * @returns {Integer} 0: v1 == v2, -1: v1 < v2, 1: v1 > v2 - */ -function versionCompare(v1, v2) { - let v1parts = ('' + v1).split('.') - let v2parts = ('' + v2).split('.') - let minLength = Math.min(v1parts.length, v2parts.length) - let i, p1, p2; - // Compare tuple pair-by-pair. - for (i = 0; i < minLength; i++) { - // Convert to integer if possible, because "8" > "10". - p1 = parseInt(v1parts[i], 10); - p2 = parseInt(v2parts[i], 10); - if (isNaN(p1)) { - p1 = v1parts[i]; - } - if (isNaN(p2)) { - p2 = v2parts[i]; - } - if (p1 === p2) { - continue; - } else if (p1 > p2) { - return 1; - } else if (p1 < p2) { - return -1; - } - // one operand is NaN - return NaN; - } - // The longer tuple is always considered 'greater' - if (v1parts.length === v2parts.length) { - return 0; - } - return (v1parts.length < v2parts.length) ? -1 : 1; -} - -function color_from_string(color) { - let clutterColor, res; - - if (!Clutter.Color.from_string) { - clutterColor = new Clutter.Color(); - clutterColor.from_string(color); - } else { - [res, clutterColor] = Clutter.Color.from_string(color); - } - - return clutterColor; -} diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js deleted file mode 100644 index 79b85c1..0000000 --- a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/convenience.js +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- mode: js; js-basic-offset: 4; indent-tabs-mode: nil -*- */ -/* - Copyright (c) 2011-2012, Giovanni Campagna <scampa.giovanni@gmail.com> - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the GNOME nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -const Gettext = imports.gettext; -const Gio = imports.gi.Gio; - -const Config = imports.misc.config; -const ExtensionUtils = imports.misc.extensionUtils; - -/** - * initTranslations: - * @domain: (optional): the gettext domain to use - * - * Initialize Gettext to load translations from extensionsdir/locale. - * If @domain is not provided, it will be taken from metadata['gettext-domain'] - */ -function initTranslations(domain) { - let extension = ExtensionUtils.getCurrentExtension(); - - domain = domain || extension.metadata['gettext-domain']; - - // check if this extension was built with "make zip-file", and thus - // has the locale files in a subfolder - // otherwise assume that extension has been installed in the - // same prefix as gnome-shell - let localeDir = extension.dir.get_child('locale'); - if (localeDir.query_exists(null)) { - Gettext.bindtextdomain(domain, localeDir.get_path()); - } else { - Gettext.bindtextdomain(domain, Config.LOCALEDIR); - } -} - -/** - * getSettings: - * @schema: (optional): the GSettings schema id - * - * Builds and return a GSettings schema for @schema, using schema files - * in extensionsdir/schemas. If @schema is not provided, it is taken from - * metadata['settings-schema']. - */ -function getSettings(schema) { - let extension = ExtensionUtils.getCurrentExtension(); - - schema = schema || extension.metadata['settings-schema']; - - const GioSSS = Gio.SettingsSchemaSource; - - // check if this extension was built with "make zip-file", and thus - // has the schema files in a subfolder - // otherwise assume that extension has been installed in the - // same prefix as gnome-shell (and therefore schemas are available - // in the standard folders) - let schemaDir = extension.dir.get_child('schemas'); - let schemaSource; - if (schemaDir.query_exists(null)) { - schemaSource = GioSSS.new_from_directory(schemaDir.get_path(), - GioSSS.get_default(), - false); - } else { - schemaSource = GioSSS.get_default(); - } - - let schemaObj = schemaSource.lookup(schema, true); - if (!schemaObj) { - throw new Error('Schema ' + schema + ' could not be found for extension ' + extension.metadata.uuid + '. Please check your installation.'); - } - - return new Gio.Settings({settings_schema: schemaObj}); -} diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js deleted file mode 100644 index 1c56f0d..0000000 --- a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/extension.js +++ /dev/null @@ -1,2592 +0,0 @@ -/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ - -// system-monitor: Gnome shell extension displaying system informations in gnome shell status bar, such as memory usage, cpu usage, network rates… -// Copyright (C) 2011 Florian Mounier aka paradoxxxzero - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. - -// Author: Florian Mounier aka paradoxxxzero - -/* Ugly. This is here so that we don't crash old libnm-glib based shells unnecessarily - * by loading the new libnm.so. Should go away eventually */ - -var libnm_glib = imports.gi.GIRepository.Repository.get_default().is_registered('NMClient', '1.0'); - -var smDepsGtop = true; -var smDepsNM = true; - -var Config = imports.misc.config; -var Clutter = imports.gi.Clutter; -var GLib = imports.gi.GLib; -var GObject = imports.gi.GObject; -var Lang = imports.lang; - -var Gio = imports.gi.Gio; -var Shell = imports.gi.Shell; -var St = imports.gi.St; -const UPower = imports.gi.UPowerGlib; - -// const System = imports.system; -var ModalDialog = imports.ui.modalDialog; - -var ByteArray = imports.byteArray; - -var ExtensionSystem = imports.ui.extensionSystem; -var ExtensionUtils = imports.misc.extensionUtils; - -var Me = ExtensionUtils.getCurrentExtension(); -var Convenience = Me.imports.convenience; -var Compat = Me.imports.compat; - -var Background, GTop, IconSize, Locale, MountsMonitor, NM, NetworkManager, Schema, StatusArea, Style, gc_timeout, menu_timeout; - -try { - GTop = imports.gi.GTop; -} catch (e) { - log('[System monitor] catched error: ' + e); - smDepsGtop = false; -} - -try { - NM = libnm_glib ? imports.gi.NMClient : imports.gi.NM; - NetworkManager = libnm_glib ? imports.gi.NetworkManager : NM; -} catch (e) { - log('[System monitor] catched error: ' + e); - smDepsNM = false; -} - -const Main = imports.ui.main; -const Panel = imports.ui.panel; -const PanelMenu = imports.ui.panelMenu; -const PopupMenu = imports.ui.popupMenu; - -const Gettext = imports.gettext.domain('system-monitor'); -const Mainloop = imports.mainloop; -const Util = imports.misc.util; -const _ = Gettext.gettext; - -const MESSAGE = _('Dependencies Missing\n\ -Please install: \n\ -gnome-system-monitor and libgtop, clutter and Network Manager gir bindings \n\ -\t on Debian and Ubuntu: gir1.2-gtop-2.0, gir1.2-nm-1.0, gir1.2-clutter-1.0, gnome-system-monitor \n\ -\t on Fedora: libgtop2-devel, NetworkManager-libnm-devel, gnome-system-monitor \n\ -\t on Arch: libgtop, networkmanager, gnome-system-monitor\n\ -\t on openSUSE: typelib-1_0-GTop-2_0, typelib-1_0-NetworkManager-1_0, gnome-system-monitor \n\ -\t on Mageia 64-bit: lib64gtop-gir2.0, lib64nm-gir1.0, lib64clutter-gir1.0, gnome-system-monitor\n'); - -// stale network shares will cause the shell to freeze, enable this with caution -const ENABLE_NETWORK_DISK_USAGE = false; - -let extension = imports.misc.extensionUtils.getCurrentExtension(); -let metadata = extension.metadata; -let shell_Version = Config.PACKAGE_VERSION; - -Clutter.Actor.prototype.raise_top = function raise_top() { - const parent = this.get_parent(); - if (!parent) { - return; - } - parent.set_child_above_sibling(this, null); -} -Clutter.Actor.prototype.reparent = function reparent(newParent) { - const parent = this.get_parent(); - if (parent) { - parent.remove_child(this); - } - newParent.add_child(this); -} - -function parse_bytearray(bytearray) { - if (!ByteArray.toString(bytearray).match(/GjsModule byteArray/)) { - return ByteArray.toString(bytearray); - } - return bytearray -} - -function l_limit(t) { - return (t > 0) ? t : 1000; -} - -function change_text() { - this.label.visible = Schema.get_boolean(this.elt + '-show-text'); -} - -function change_style() { - let style = Schema.get_string(this.elt + '-style'); - this.text_box.visible = style === 'digit' || style === 'both'; - this.chart.actor.visible = style === 'graph' || style === 'both'; -} - -function build_menu_info() { - let elts = Main.__sm.elts; - let tray_menu = Main.__sm.tray.menu; - - if (tray_menu._getMenuItems().length && - typeof tray_menu._getMenuItems()[0].actor.get_last_child() !== 'undefined') { - tray_menu._getMenuItems()[0].actor.get_last_child().destroy_all_children(); - for (let elt in elts) { - elts[elt].menu_items = elts[elt].create_menu_items(); - } - } else { - return; - } - - let menu_info_box_table = new St.Widget({ - style: 'padding: 10px 0px 10px 0px; spacing-rows: 10px; spacing-columns: 15px;', - layout_manager: new Clutter.GridLayout({orientation: Clutter.Orientation.VERTICAL}) - }); - let menu_info_box_table_layout = menu_info_box_table.layout_manager; - - // Populate Table - let row_index = 0; - for (let elt in elts) { - if (!elts[elt].menu_visible) { - continue; - } - - // Add item name to table - menu_info_box_table_layout.attach( - new St.Label({ - text: elts[elt].item_name, - style_class: Style.get('sm-title'), - x_align: Clutter.ActorAlign.START, - y_align: Clutter.ActorAlign.CENTER - }), 0, row_index, 1, 1); - - // Add item data to table - let col_index = 1; - for (let item in elts[elt].menu_items) { - menu_info_box_table_layout.attach( - elts[elt].menu_items[item], col_index, row_index, 1, 1); - - col_index++; - } - - row_index++; - } - if (shell_Version < '3.36') { - tray_menu._getMenuItems()[0].actor.get_last_child().add(menu_info_box_table, {expand: true}); - } else { - tray_menu._getMenuItems()[0].actor.get_last_child().add_child(menu_info_box_table); - } -} - -function change_menu() { - this.menu_visible = Schema.get_boolean(this.elt + '-show-menu'); - build_menu_info(); -} - -function change_usage() { - let usage = Schema.get_string('disk-usage-style'); - Main.__sm.pie.show(usage === 'pie'); - Main.__sm.bar.show(usage === 'bar'); -} -let color_from_string = Compat.color_from_string; - -function interesting_mountpoint(mount) { - if (mount.length < 3) { - return false; - } - - return ((mount[0].indexOf('/dev/') === 0 || mount[2].toLowerCase() === 'nfs') && mount[2].toLowerCase() !== 'udf'); -} - - -const smStyleManager = class SystemMonitor_smStyleManager { - constructor() { - this._extension = ''; - this._iconsize = 1; - this._diskunits = _('MiB/s'); - this._netunits_kbytes = _('KiB/s'); - this._netunits_mbytes = _('MiB/s'); - this._netunits_gbytes = _('GiB/s'); - this._netunits_kbits = _('kbit/s'); - this._netunits_mbits = _('Mbit/s'); - this._netunits_gbits = _('Gbit/s'); - this._pie_size = 300; - this._pie_fontsize = 14; - this._bar_width = 300; - this._bar_thickness = 15; - this._bar_fontsize = 14; - this._compact = Schema.get_boolean('compact-display'); - - if (this._compact) { - this._extension = '-compact'; - this._iconsize = 3 / 5; - this._diskunits = _('MB'); - this._netunits_kbytes = _('kB'); - this._netunits_mbytes = _('MB'); - this._netunits_gbytes = _('GB'); - this._netunits_kbits = 'kb'; - this._netunits_mbits = 'Mb'; - this._netunits_gbits = 'Gb'; - this._pie_size *= 4 / 5; - this._pie_fontsize = 12; - this._bar_width *= 3 / 5; - this._bar_thickness = 12; - this._bar_fontsize = 12; - } - } - get(style) { - return style + this._extension; - } - iconsize() { - return this._iconsize; - } - diskunits() { - return this._diskunits; - } - netunits_kbytes() { - return this._netunits_kbytes; - } - netunits_mbytes() { - return this._netunits_mbytes; - } - netunits_gbytes() { - return this._netunits_gbytes; - } - netunits_kbits() { - return this._netunits_kbits; - } - netunits_mbits() { - return this._netunits_mbits; - } - netunits_gbits() { - return this._netunits_gbits; - } - pie_size() { - return this._pie_size; - } - pie_fontsize() { - return this._pie_fontsize; - } - bar_width() { - return this._bar_width; - } - bar_thickness() { - return this._bar_thickness; - } - bar_fontsize() { - return this._bar_fontsize; - } -} - -const smDialog = class SystemMonitor_smDialog extends ModalDialog.ModalDialog { - constructor() { - super({styleClass: 'prompt-dialog'}); - let mainContentBox = new St.BoxLayout({style_class: 'prompt-dialog-main-layout', - vertical: false}); - this.contentLayout.add(mainContentBox, - {x_fill: true, - y_fill: true}); - - let messageBox = new St.BoxLayout({style_class: 'prompt-dialog-message-layout', - vertical: true}); - mainContentBox.add(messageBox, - {y_align: St.Align.START}); - - this._subjectLabel = new St.Label({style_class: 'prompt-dialog-headline', - text: _('System Monitor Extension')}); - - messageBox.add(this._subjectLabel, - {y_fill: false, - y_align: St.Align.START}); - - this._descriptionLabel = new St.Label({style_class: 'prompt-dialog-description', - text: MESSAGE}); - - messageBox.add(this._descriptionLabel, - {y_fill: true, - y_align: St.Align.START}); - - - this.setButtons([ - { - label: _('Cancel'), - action: () => { - this.close(); - }, - key: Clutter.Escape - } - ]); - } -} - -const Chart = class SystemMonitor_Chart { - constructor(width, height, parent) { - this.actor = new St.DrawingArea({style_class: Style.get('sm-chart'), reactive: false}); - this.parentC = parent; - this.width = width; - let themeContext = St.ThemeContext.get_for_stage(global.stage); - this.scale_factor = themeContext.scale_factor; - this.actor.set_width(this.width * this.scale_factor); - this.actor.set_height(height); - this.data = []; - for (let i = 0; i < this.parentC.colors.length; i++) { - this.data[i] = []; - } - themeContext.connect('notify::scale-factor', this.rescale.bind(this)); - this.actor.connect('repaint', this._draw.bind(this)); - } - update() { - let data_a = this.parentC.vals; - if (data_a.length !== this.parentC.colors.length) { - return; - } - let accdata = []; - for (let l = 0; l < data_a.length; l++) { - accdata[l] = (l === 0) ? data_a[0] : accdata[l - 1] + ((data_a[l] > 0) ? data_a[l] : 0); - this.data[l].push(accdata[l]); - if (this.data[l].length > this.width) { - this.data[l].shift(); - } - } - if (!this.actor.visible) { - return; - } - this.actor.queue_repaint(); - } - _draw() { - if (!this.actor.visible) { - return; - } - let [width, height] = this.actor.get_surface_size(); - let cr = this.actor.get_context(); - let max; - if (this.parentC.max) { - max = this.parentC.max; - } else { - max = Math.max.apply(this, this.data[this.data.length - 1]); - max = Math.max(1, Math.pow(2, Math.ceil(Math.log(max) / Math.log(2)))); - } - Clutter.cairo_set_source_color(cr, Background); - cr.rectangle(0, 0, width, height); - cr.fill(); - for (let i = this.parentC.colors.length - 1; i >= 0; i--) { - let samples = this.data[i].length - 1; - if (samples > 0) { - cr.moveTo(width, height); // bottom right - let x = width - 0.25 * this.scale_factor; - cr.lineTo(x, (1 - this.data[i][samples] / max) * height); - x -= 0.5 * this.scale_factor; - for (let j = samples; j >= 0; j--) { - let y = (1 - this.data[i][j] / max) * height; - cr.lineTo(x, y); - x -= 0.5 * this.scale_factor; - cr.lineTo(x, y); - x -= 0.5 * this.scale_factor; - } - x += 0.25 * this.scale_factor; - cr.lineTo(x, (1 - this.data[i][0] / max) * height); - cr.lineTo(x, height); - cr.closePath(); - Clutter.cairo_set_source_color(cr, this.parentC.colors[i]); - cr.fill(); - } - } - cr.$dispose(); - } - resize(width) { - if (this.width === width) { - return; - } - this.width = width; - if (this.width < this.data[0].length) { - for (let i = 0; i < this.parentC.colors.length; i++) { - this.data[i] = this.data[i].slice(-this.width); - } - } - this.actor.set_width(this.width * this.scale_factor); // repaints - } - rescale(themeContext) { - this.scale_factor = themeContext.scale_factor; - this.actor.set_width(this.width * this.scale_factor); // repaints - } -} - -// Class to deal with volumes insertion / ejection -const smMountsMonitor = class SystemMonitor_smMountsMonitor { - constructor() { - this.files = []; - this.num_mounts = -1; - this.listeners = []; - this.connected = false; - - this._volumeMonitor = Gio.VolumeMonitor.get(); - let sys_mounts = ['/home', '/tmp', '/boot', '/usr', '/usr/local']; - this.base_mounts = ['/']; - sys_mounts.forEach((sMount) => { - if (this.is_sys_mount(sMount + '/')) { - this.base_mounts.push(sMount); - } - }); - this.connect(); - } - refresh() { - // try check that number of volumes has changed - // try { - // let num_mounts = this.manager.getMounts().length; - // if (num_mounts == this.num_mounts) - // return; - // this.num_mounts = num_mounts; - // } catch (e) {}; - - // Can't get mountlist: - // GTop.glibtop_get_mountlist - // Error: No symbol 'glibtop_get_mountlist' in namespace 'GTop' - // Getting it with mtab - // let mount_lines = Shell.get_file_contents_utf8_sync('/etc/mtab').split("\n"); - // this.mounts = []; - // for(let mount_line in mount_lines) { - // let mount = mount_lines[mount_line].split(" "); - // if(interesting_mountpoint(mount) && this.mounts.indexOf(mount[1]) < 0) { - // this.mounts.push(mount[1]); - // } - // } - // log("[System monitor] old mounts: " + this.mounts); - this.mounts = []; - for (let base in this.base_mounts) { - // log("[System monitor] " + this.base_mounts[base]); - this.mounts.push(this.base_mounts[base]); - } - let mount_lines = this._volumeMonitor.get_mounts(); - mount_lines.forEach((mount) => { - if ((!this.is_net_mount(mount) || ENABLE_NETWORK_DISK_USAGE) && - !this.is_ro_mount(mount)) { - let mpath = mount.get_root().get_path() || mount.get_default_location().get_path(); - if (mpath) { - this.mounts.push(mpath); - } - } - }); - // log("[System monitor] base: " + this.base_mounts); - // log("[System monitor] mounts: " + this.mounts); - for (let i in this.listeners) { - this.listeners[i](this.mounts); - } - } - add_listener(cb) { - this.listeners.push(cb); - } - remove_listener(cb) { - this.listeners.pop(cb); - } - get_mounts() { - return this.mounts; - } - is_sys_mount(mpath) { - let file = Gio.file_new_for_path(mpath); - let info = file.query_info(Gio.FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT, - Gio.FileQueryInfoFlags.NONE, null); - return info.get_attribute_boolean(Gio.FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT); - } - is_ro_mount(mount) { - // FIXME: running this function after "login after waking from suspend" - // can make login hang. Actual issue seems to occur when a former net - // mount got broken (e.g. due to a VPN connection terminated or - // otherwise broken connection) - try { - let file = mount.get_default_location(); - let info = file.query_filesystem_info(Gio.FILE_ATTRIBUTE_FILESYSTEM_READONLY, null); - return info.get_attribute_boolean(Gio.FILE_ATTRIBUTE_FILESYSTEM_READONLY); - } catch (e) { - return false; - } - } - is_net_mount(mount) { - try { - let file = mount.get_default_location(); - let info = file.query_filesystem_info(Gio.FILE_ATTRIBUTE_FILESYSTEM_TYPE, null); - let result = info.get_attribute_string(Gio.FILE_ATTRIBUTE_FILESYSTEM_TYPE); - let net_fs = ['nfs', 'smbfs', 'cifs', 'ftp', 'sshfs', 'sftp', 'mtp', 'mtpfs']; - return !file.is_native() || net_fs.indexOf(result) > -1; - } catch (e) { - return false; - } - } - connect() { - if (this.connected) { - return; - } - try { - this.manager = this._volumeMonitor; - this.mount_added_id = this.manager.connect('mount-added', this.refresh.bind(this)); - this.mount_removed_id = this.manager.connect('mount-removed', this.refresh.bind(this)); - // need to add the other signals here - this.connected = true; - } catch (e) { - log('[System monitor] Failed to register on placesManager notifications'); - log('[System monitor] Got exception : ' + e); - } - this.refresh(); - } - disconnect() { - if (!this.connected) { - return; - } - this.manager.disconnect(this.mount_added_id); - this.manager.disconnect(this.mount_removed_id); - this.connected = false; - } - destroy() { - this.disconnect(); - } -} - -const Graph = class SystemMonitor_Graph { - constructor(width, height) { - this.menu_item = ''; - this.actor = new St.DrawingArea({style_class: Style.get('sm-chart'), reactive: false}); - this.width = width; - this.height = height; - this.gtop = new GTop.glibtop_fsusage(); - this.colors = ['#888', '#aaa', '#ccc']; - for (let color in this.colors) { - this.colors[color] = color_from_string(this.colors[color]); - } - - let themeContext = St.ThemeContext.get_for_stage(global.stage); - themeContext.connect('notify::scale-factor', this.set_scale.bind(this)); - this.scale_factor = themeContext.scale_factor; - let interfaceSettings = new Gio.Settings({ - schema: 'org.gnome.desktop.interface' - }); - interfaceSettings.connect('changed', this.set_text_scaling.bind(this)); - this.text_scaling = interfaceSettings.get_double('text-scaling-factor'); - if (!this.text_scaling) { - this.text_scaling = 1; - } - - this.actor.set_width(this.width * this.scale_factor * this.text_scaling); - this.actor.set_height(this.height * this.scale_factor * this.text_scaling); - this.actor.connect('repaint', this._draw.bind(this)); - } - create_menu_item() { - this.menu_item = new PopupMenu.PopupBaseMenuItem({reactive: false}); - if (shell_Version < '3.36') { - this.menu_item.actor.add(this.actor, {span: -1, expand: true}); - } else { - this.menu_item.actor.add_child(this.actor); - } - // tray.menu.addMenuItem(this.menu_item); - } - show(visible) { - this.menu_item.actor.visible = visible; - } - set_scale(themeContext) { - this.scale_factor = themeContext.scale_factor; - this.actor.set_width(this.width * this.scale_factor * this.text_scaling); - this.actor.set_height(this.height * this.scale_factor * this.text_scaling); - } - set_text_scaling(interfaceSettings, key) { - // FIXME: for some reason we only get this signal once, not on later - // changes to the setting - //log('[System monitor] got text scaling signal'); - this.text_scaling = interfaceSettings.get_double(key); - this.actor.set_width(this.width * this.scale_factor * this.text_scaling); - this.actor.set_height(this.height * this.scale_factor * this.text_scaling); - } -} - -const Bar = class SystemMonitor_Bar extends Graph { - constructor() { - // Height doesn't matter, it gets set on every draw. - super(Style.bar_width(), 100); - this.mounts = MountsMonitor.get_mounts(); - MountsMonitor.add_listener(this.update_mounts.bind(this)); - } - _draw() { - if (!this.actor.visible) { - return; - } - let thickness = Style.bar_thickness() * this.scale_factor * this.text_scaling; - let fontsize = Style.bar_fontsize() * this.scale_factor * this.text_scaling; - this.actor.set_height(this.mounts.length * (3 * thickness)); - let [width, height] = this.actor.get_surface_size(); - let cr = this.actor.get_context(); - - let x0 = width / 8; - let y0 = thickness / 2; - cr.setLineWidth(thickness); - cr.setFontSize(fontsize); - for (let mount in this.mounts) { - GTop.glibtop_get_fsusage(this.gtop, this.mounts[mount]); - let perc_full = (this.gtop.blocks - this.gtop.bfree) / this.gtop.blocks; - Clutter.cairo_set_source_color(cr, this.colors[mount % this.colors.length]); - - var text = this.mounts[mount]; - if (text.length > 10) { - text = text.split('/').pop(); - } - cr.moveTo(0, y0 + thickness / 3); - cr.showText(text); - cr.moveTo(width - x0, y0 + thickness / 3); - cr.showText(Math.round(perc_full * 100).toString() + '%'); - y0 += (5 * thickness) / 4; - - cr.moveTo(0, y0); - cr.relLineTo(perc_full * width, 0); - cr.stroke(); - y0 += (7 * thickness) / 4; - } - cr.$dispose(); - } - update_mounts(mounts) { - this.mounts = mounts; - this.actor.queue_repaint(); - } -} - -const Pie = class SystemMonitor_Pie extends Graph { - constructor() { - super(Style.pie_size(), Style.pie_size()); - this.mounts = MountsMonitor.get_mounts(); - MountsMonitor.add_listener(this.update_mounts.bind(this)); - } - - _draw() { - if (!this.actor.visible) { - return; - } - let [width, height] = this.actor.get_surface_size(); - let cr = this.actor.get_context(); - let xc = width / 2; - let yc = height / 2; - let pi = Math.PI; - function arc(r, value, max, angle) { - if (max === 0) { - return angle; - } - let new_angle = angle + (value * 2 * pi / max); - cr.arc(xc, yc, r, angle, new_angle); - return new_angle; - } - - // Set the ring thickness so that at least 7 rings can be displayed. If - // there are more mounts, make the rings thinner. If the rings are too - // thin to have a line height of 1.2 for the labels, shrink the labels. - let rings = Math.max(this.mounts.length, 7); - let ring_width = width / (2 * rings); - let fontsize = Style.pie_fontsize() * this.scale_factor * this.text_scaling; - if (ring_width < 1.2 * fontsize) { - fontsize = ring_width / 1.2; - } - let thickness = ring_width / 1.5; - - cr.setLineWidth(thickness); - cr.setFontSize(fontsize); - let r = (height - ring_width) / 2; - for (let mount in this.mounts) { - GTop.glibtop_get_fsusage(this.gtop, this.mounts[mount]); - Clutter.cairo_set_source_color(cr, this.colors[mount % this.colors.length]); - arc(r, this.gtop.blocks - this.gtop.bfree, this.gtop.blocks, -pi / 2); - cr.stroke(); - r -= ring_width; - } - let y = (ring_width + fontsize) / 2; - for (let mount in this.mounts) { - var text = this.mounts[mount]; - if (text.length > 10) { - text = text.split('/').pop(); - } - cr.moveTo(0, y); - cr.showText(text); - y += ring_width; - } - cr.$dispose(); - } - - update_mounts(mounts) { - this.mounts = mounts; - this.actor.queue_repaint(); - } -} - -var TipItem = null; - -if (shell_Version < '3.36') { - TipItem = class SystemMonitor_TipItem extends PopupMenu.PopupBaseMenuItem { - constructor() { - super(); - // PopupMenu.PopupBaseMenuItem.prototype._init.call(this); - this.actor.remove_style_class_name('popup-menu-item'); - this.actor.add_style_class_name('sm-tooltip-item'); - } - } -} else { - TipItem = GObject.registerClass( - { - GTypeName: 'TipItem' - }, - class SystemMonitor_TipItem extends PopupMenu.PopupBaseMenuItem { - _init() { - super._init(); - // PopupMenu.PopupBaseMenuItem.prototype._init.call(this); - this.actor.remove_style_class_name('popup-menu-item'); - this.actor.add_style_class_name('sm-tooltip-item'); - } - } - ); -} -const TipMenu = class SystemMonitor_TipMenu extends PopupMenu.PopupMenuBase { - constructor(sourceActor) { - // PopupMenu.PopupMenuBase.prototype._init.call(this, sourceActor, 'sm-tooltip-box'); - super(sourceActor, 'sm-tooltip-box'); - this.actor = new Clutter.Actor(); - // this.actor.connect('get-preferred-width', - // this._boxGetPreferredWidth).bind(this); - // this.actor.connect('get-preferred-height', - // this._boxGetPreferredHeight.bind(this)); - this.actor.add_actor(this.box); - } - // _boxGetPreferredWidth (actor, forHeight, alloc) { - // // let columnWidths = this.getColumnWidths(); - // // this.setColumnWidths(columnWidths); - // - // [alloc.min_size, alloc.natural_size] = this.box.get_preferred_width(forHeight); - // } - // _boxGetPreferredHeight (actor, forWidth, alloc) { - // [alloc.min_size, alloc.natural_size] = this.box.get_preferred_height(forWidth); - // } - // _boxAllocate (actor, box, flags) { - // this.box.allocate(box, flags); - // } - _shift() { - // Probably old but works - let node = this.sourceActor.get_theme_node(); - let contentbox = node.get_content_box(this.sourceActor.get_allocation_box()); - - let sourceTopLeftX = 0; - let sourceTopLeftY = 0; - if (typeof this.sourceActor.get_transformed_extents === 'function') { - let extents = this.sourceActor.get_transformed_extents(); - let sourceTopLeft = extents.get_top_left(); - sourceTopLeftY = sourceTopLeft.y; - sourceTopLeftX = sourceTopLeft.x; - } else { - let allocation = Shell.util_get_transformed_allocation(this.sourceActor); - sourceTopLeftY = allocation.y1; - sourceTopLeftX = allocation.x1; - } - let monitor = Main.layoutManager.findMonitorForActor(this.sourceActor); - let [x, y] = [sourceTopLeftX + contentbox.x1, - sourceTopLeftY + contentbox.y1]; - let [cx, cy] = [sourceTopLeftX + (contentbox.x1 + contentbox.x2) / 2, - sourceTopLeftY + (contentbox.y1 + contentbox.y2) / 2]; - let [xm, ym] = [sourceTopLeftX + contentbox.x2, - sourceTopLeftY + contentbox.y2]; - let [width, height] = this.actor.get_size(); - let tipx = cx - width / 2; - tipx = Math.max(tipx, monitor.x); - tipx = Math.min(tipx, monitor.x + monitor.width - width); - let tipy = Math.floor(ym); - // Hacky condition to determine if the status bar is at the top or at the bottom of the screen - if (sourceTopLeftY / monitor.height > 0.3) { - tipy = sourceTopLeftY - height; // If it is at the bottom, place the tooltip above instead of below - } - this.actor.set_position(tipx, tipy); - } - open(animate) { - if (this.isOpen) { - return; - } - - this.isOpen = true; - this.actor.show(); - this._shift(); - this.actor.raise_top(); - this.emit('open-state-changed', true); - } - close(animate) { - this.isOpen = false; - this.actor.hide(); - this.emit('open-state-changed', false); - } -} - -const TipBox = class SystemMonitor_TipBox { - constructor() { - this.actor = new St.BoxLayout({reactive: true}); - this.actor._delegate = this; - this.set_tip(new TipMenu(this.actor)); - this.in_to = this.out_to = 0; - this.actor.connect('enter-event', this.on_enter.bind(this)); - this.actor.connect('leave-event', this.on_leave.bind(this)); - } - set_tip(tipmenu) { - if (this.tipmenu) { - this.tipmenu.destroy(); - } - this.tipmenu = tipmenu; - if (this.tipmenu) { - Main.uiGroup.add_actor(this.tipmenu.actor); - this.hide_tip(); - } - } - show_tip() { - if (!this.tipmenu) { - return; - } - this.tipmenu.open(); - if (this.in_to) { - Mainloop.source_remove(this.in_to); - this.in_to = 0; - } - } - hide_tip() { - if (!this.tipmenu) { - return; - } - this.tipmenu.close(); - if (this.out_to) { - Mainloop.source_remove(this.out_to); - this.out_to = 0; - } - if (this.in_to) { - Mainloop.source_remove(this.in_to); - this.in_to = 0; - } - } - on_enter() { - let show_tooltip = Schema.get_boolean('show-tooltip'); - - if (!show_tooltip) { - return; - } - - if (this.out_to) { - Mainloop.source_remove(this.out_to); - this.out_to = 0; - } - if (!this.in_to) { - this.in_to = Mainloop.timeout_add(500, - this.show_tip.bind(this)); - } - } - on_leave() { - if (this.in_to) { - Mainloop.source_remove(this.in_to); - this.in_to = 0; - } - if (!this.out_to) { - this.out_to = Mainloop.timeout_add(500, - this.hide_tip.bind(this)); - } - } - destroy() { - if (this.in_to) { - Mainloop.source_remove(this.in_to); - this.in_to = 0; - } - - if (this.out_to) { - Mainloop.source_remove(this.out_to); - this.out_to = 0; - } - - this.actor.destroy(); - } -} - -const ElementBase = class SystemMonitor_ElementBase extends TipBox { - constructor(properties) { - super(); - this.elt = ''; - this.item_name = _(''); - this.color_name = []; - this.text_items = []; - this.menu_items = []; - this.menu_visible = true; - - Object.assign(this, properties); - - // TipBox.prototype._init.apply(this, arguments); - this.vals = []; - this.tip_labels = []; - this.tip_vals = []; - this.tip_unit_labels = []; - - this.colors = []; - for (let color in this.color_name) { - let name = this.elt + '-' + this.color_name[color] + '-color'; - let clutterColor = color_from_string(Schema.get_string(name)); - Schema.connect('changed::' + name, (schema, key) => { - this.clutterColor = color_from_string(Schema.get_string(key)); - }); - Schema.connect('changed::' + name, () => { - this.chart.actor.queue_repaint(); - }); - this.colors.push(clutterColor); - } - - let element_width = Schema.get_int(this.elt + '-graph-width'); - if (Style.get('') === '-compact') { - element_width = Math.round(element_width / 1.5); - } - this.chart = new Chart(element_width, IconSize, this); - - Schema.connect('changed::background', () => { - this.chart.actor.queue_repaint(); - }); - - this.actor.visible = Schema.get_boolean(this.elt + '-display'); - Schema.connect( - 'changed::' + this.elt + '-display', (schema, key) => { - this.actor.visible = Schema.get_boolean(key); - }); - - this.interval = l_limit(Schema.get_int(this.elt + '-refresh-time')); - this.timeout = Mainloop.timeout_add( - this.interval, - this.update.bind(this), - GLib.PRIORITY_DEFAULT_IDLE - ); - - Schema.connect( - 'changed::' + this.elt + '-refresh-time', - (schema, key) => { - Mainloop.source_remove(this.timeout); - this.timeout = null; - this.interval = l_limit(Schema.get_int(key)); - this.timeout = Mainloop.timeout_add( - this.interval, this.update.bind(this), GLib.PRIORITY_DEFAULT_IDLE); - }); - Schema.connect('changed::' + this.elt + '-graph-width', this.resize.bind(this)); - - if (this.elt === 'thermal') { - Schema.connect('changed::thermal-threshold', - () => { - Mainloop.source_remove(this.timeout); - this.timeout = null; - this.reset_style(); - this.timeout = Mainloop.timeout_add( - this.interval, this.update.bind(this), GLib.PRIORITY_DEFAULT_IDLE); - }); - } - - this.label = new St.Label({text: this.elt === 'memory' ? _('mem') : _(this.elt), - style_class: Style.get('sm-status-label')}); - change_text.call(this); - Schema.connect('changed::' + this.elt + '-show-text', change_text.bind(this)); - - this.menu_visible = Schema.get_boolean(this.elt + '-show-menu'); - Schema.connect('changed::' + this.elt + '-show-menu', change_menu.bind(this)); - - this.actor.add_actor(this.label); - this.text_box = new St.BoxLayout(); - - this.actor.add_actor(this.text_box); - this.text_items = this.create_text_items(); - for (let item in this.text_items) { - this.text_box.add_actor(this.text_items[item]); - } - this.actor.add_actor(this.chart.actor); - change_style.call(this); - Schema.connect('changed::' + this.elt + '-style', change_style.bind(this)); - this.menu_items = this.create_menu_items(); - } - tip_format(unit) { - if (typeof (unit) === 'undefined') { - unit = '%'; - } - if (typeof (unit) === 'string') { - let all_unit = unit; - unit = []; - for (let i = 0; i < this.color_name.length; i++) { - unit.push(all_unit); - } - } - for (let i = 0; i < this.color_name.length; i++) { - let tipline = new TipItem(); - this.tipmenu.addMenuItem(tipline); - tipline.actor.add(new St.Label({text: _(this.color_name[i])})); - this.tip_labels[i] = new St.Label({text: ''}); - tipline.actor.add(this.tip_labels[i]); - - this.tip_unit_labels[i] = new St.Label({text: unit[i]}); - tipline.actor.add(this.tip_unit_labels[i]); - this.tip_vals[i] = 0; - } - } - // set_tip_unit: function(unit) { - // for (let i = 0;i < this.tip_unit_labels.length;i++) { - // this.tip_unit_labels[i].text = unit[i]; - // } - // } - update() { - if (!this.menu_visible && !this.actor.visible) { - return false; - } - this.refresh(); - this._apply(); - if (this.elt === 'thermal') { - this.threshold(); - } - this.chart.update(); - for (let i = 0; i < this.tip_vals.length; i++) { - if (this.tip_labels[i]) { - this.tip_labels[i].text = this.tip_vals[i].toString(); - } - } - return true; - } - reset_style() { - this.text_items[0].set_style('color: rgba(255, 255, 255, 1)'); - } - threshold() { - if (Schema.get_int('thermal-threshold')) { - if (this.temp_over_threshold) { - this.text_items[0].set_style('color: rgba(255, 0, 0, 1)'); - } else { - this.text_items[0].set_style('color: rgba(255, 255, 255, 1)'); - } - } - } - resize(schema, key) { - let width = Schema.get_int(key); - if (Style.get('') === '-compact') { - width = Math.round(width / 1.5); - } - this.chart.resize(width); - } - destroy() { - TipBox.prototype.destroy.call(this); - if (this.timeout) { - Mainloop.source_remove(this.timeout); - this.timeout = null; - } - } -} - -const Battery = class SystemMonitor_Battery extends ElementBase { - constructor() { - super({ - elt: 'battery', - item_name: _('Battery'), - color_name: ['batt0'], - icon: '. GThemedIcon battery-good-symbolic battery-good' - }); - - this.max = 100; - this.icon_hidden = false; - this.percentage = 0; - this.timeString = '-- '; - this._proxy = StatusArea.aggregateMenu._power._proxy; - if (typeof (this._proxy) === 'undefined') { - this._proxy = StatusArea.battery._proxy; - } - this.powerSigID = this._proxy.connect('g-properties-changed', this.update_battery.bind(this)); - - // need to specify a default icon, since the contructor completes before UPower callback - this.gicon = Gio.icon_new_for_string(this.icon); - - this.tip_format('%'); - - this.update_battery(); - this.update_tips(); - // this.hide_system_icon(); - this.update(); - - // Schema.connect('changed::' + this.elt + '-hidesystem', this.hide_system_icon.bind(this)); - Schema.connect('changed::' + this.elt + '-time', this.update_tips.bind(this)); - } - refresh() { - // do nothing here? - } - update_battery() { - // callback function for when battery stats updated. - let battery_found = false; - let isBattery = false; - if (typeof (this._proxy.GetDevicesRemote) === 'undefined') { - let device_type = this._proxy.Type; - isBattery = (device_type === UPower.DeviceKind.BATTERY); - if (isBattery) { - battery_found = true; - let icon = this._proxy.IconName; - let percentage = this._proxy.Percentage; - let seconds = this._proxy.TimeToEmpty; - this.update_battery_value(seconds, percentage, icon); - } else { - // log("[System monitor] No battery found"); - this.actor.hide(); - this.menu_visible = false; - build_menu_info(); - } - } else { - this._proxy.GetDevicesRemote((devices, error) => { - if (error) { - log('[System monitor] Power proxy error: ' + error); - this.actor.hide(); - this.menu_visible = false; - build_menu_info(); - return; - } - - let [result] = devices; - for (let i = 0; i < result.length; i++) { - let [device_id, device_type, icon, percentage, state, seconds] = result[i]; - - isBattery = (device_type === UPower.DeviceKind.BATTERY); - if (isBattery) { - battery_found = true; - this.update_battery_value(seconds, percentage, icon); - break; - } - } - - if (!battery_found) { - // log("[System monitor] No battery found"); - this.actor.hide(); - this.menu_visible = false; - build_menu_info(); - } - }); - } - } - update_battery_value(seconds, percentage, icon) { - if (seconds > 60) { - let time = Math.round(seconds / 60); - let minutes = time % 60; - let hours = Math.floor(time / 60); - this.timeString = C_('battery time remaining', '%d:%02d').format(hours, minutes); - } else { - this.timeString = '-- '; - } - this.percentage = Math.ceil(percentage); - this.gicon = Gio.icon_new_for_string(icon); - - if (Schema.get_boolean(this.elt + '-display')) { - this.actor.show() - } - if (Schema.get_boolean(this.elt + '-show-menu') && !this.menu_visible) { - this.menu_visible = true; - build_menu_info(); - } - } - hide_system_icon(override) { - let value = Schema.get_boolean(this.elt + '-hidesystem'); - if (!override) { - value = false; - } - if (value && Schema.get_boolean(this.elt + '-display')) { - if (shell_Version > '3.5') { - if (StatusArea.battery.actor.visible) { - StatusArea.battery.destroy(); - this.icon_hidden = true; - } - } else { - for (let Index = 0; Index < Main.panel._rightBox.get_children().length; Index++) { - if (StatusArea.battery === Main.panel._rightBox.get_children()[Index]._delegate) { - Main.panel._rightBox.get_children()[Index].destroy(); - StatusArea.battery = null; - this.icon_hidden = true; - break; - } - } - } - } else if (this.icon_hidden) { - if (shell_Version < '3.5') { - let Indicator = new Panel.STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION.battery(); - Main.panel.addToStatusArea('battery', Indicator, Panel.STANDARD_STATUS_AREA_ORDER.indexOf('battery')); - } else { - let Indicator = new Panel.PANEL_ITEM_IMPLEMENTATIONS.battery(); - Main.panel.addToStatusArea('battery', Indicator, Main.sessionMode.panel.right.indexOf('battery'), 'right'); - } - this.icon_hidden = false; - // Main.panel._updatePanel('right'); - } - } - get_battery_unit() { - let unitString; - let value = Schema.get_boolean(this.elt + '-time'); - - if (value) { - unitString = 'h'; - } else { - unitString = '%'; - } - - return unitString; - } - update_tips() { - let unitString = this.get_battery_unit(); - - if (Schema.get_boolean(this.elt + '-display')) { - this.text_items[2].text = unitString; - } - if (Schema.get_boolean(this.elt + '-show-menu')) { - this.menu_items[1].text = unitString; - } - - this.update(); - } - _apply() { - let displayString; - let value = Schema.get_boolean(this.elt + '-time'); - if (value) { - displayString = this.timeString; - } else { - displayString = this.percentage.toString() - } - if (Schema.get_boolean(this.elt + '-display')) { - this.text_items[0].gicon = this.gicon; - this.text_items[1].text = displayString; - } - if (Schema.get_boolean(this.elt + '-show-menu')) { - this.menu_items[0].text = displayString; - } - this.vals = [this.percentage]; - this.tip_vals[0] = Math.round(this.percentage); - } - create_text_items() { - return [ - new St.Icon({ - gicon: Gio.icon_new_for_string(this.icon), - style_class: Style.get('sm-status-icon')}), - new St.Label({ - text: '', - style_class: Style.get('sm-status-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: this.get_battery_unit(), - style_class: Style.get('sm-perc-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: this.get_battery_unit(), - style_class: Style.get('sm-label')}) - ]; - } - destroy() { - ElementBase.prototype.destroy.call(this); - this._proxy.disconnect(this.powerSigID); - } -} - -const Cpu = class SystemMonitor_Cpu extends ElementBase { - constructor(cpuid) { - super({ - elt: 'cpu', - item_name: _('CPU'), - color_name: ['user', 'system', 'nice', 'iowait', 'other'], - cpuid: -1 // cpuid is -1 when all cores are displayed in the same graph - }); - this.max = 100; - - this.cpuid = cpuid; - this.gtop = new GTop.glibtop_cpu(); - this.last = [0, 0, 0, 0, 0]; - this.current = [0, 0, 0, 0, 0]; - try { - this.total_cores = GTop.glibtop_get_sysinfo().ncpu; - if (cpuid === -1) { - this.max *= this.total_cores; - } - } catch (e) { - this.total_cores = this.get_cores(); - global.logError(e) - } - this.last_total = 0; - this.usage = [0, 0, 0, 1, 0]; - this.item_name = _('Cpu'); - if (cpuid !== -1) { - this.item_name += ' ' + (cpuid + 1); - } // append cpu number to cpu name in popup - // ElementBase.prototype._init.call(this); - this.tip_format(); - this.update(); - } - refresh() { - GTop.glibtop_get_cpu(this.gtop); - // display global cpu usage on 1 graph - if (this.cpuid === -1) { - this.current[0] = this.gtop.user; - this.current[1] = this.gtop.sys; - this.current[2] = this.gtop.nice; - this.current[3] = this.gtop.idle; - this.current[4] = this.gtop.iowait; - let delta = (this.gtop.total - this.last_total) / (100 * this.total_cores); - - if (delta > 0) { - for (let i = 0; i < 5; i++) { - this.usage[i] = Math.round((this.current[i] - this.last[i]) / delta); - this.last[i] = this.current[i]; - } - this.last_total = this.gtop.total; - } else if (delta < 0) { - this.last = [0, 0, 0, 0, 0]; - this.current = [0, 0, 0, 0, 0]; - this.last_total = 0; - this.usage = [0, 0, 0, 1, 0]; - } - } else { - // display per cpu data - this.current[0] = this.gtop.xcpu_user[this.cpuid]; - this.current[1] = this.gtop.xcpu_sys[this.cpuid]; - this.current[2] = this.gtop.xcpu_nice[this.cpuid]; - this.current[3] = this.gtop.xcpu_idle[this.cpuid]; - this.current[4] = this.gtop.xcpu_iowait[this.cpuid]; - let delta = (this.gtop.xcpu_total[this.cpuid] - this.last_total) / 100; - - if (delta > 0) { - for (let i = 0; i < 5; i++) { - this.usage[i] = Math.round((this.current[i] - this.last[i]) / delta); - this.last[i] = this.current[i]; - } - this.last_total = this.gtop.xcpu_total[this.cpuid]; - } else if (delta < 0) { - this.last = [0, 0, 0, 0, 0]; - this.current = [0, 0, 0, 0, 0]; - this.last_total = 0; - this.usage = [0, 0, 0, 1, 0]; - } - } - - // GTop.glibtop_get_cpu(this.gtop); - // // display global cpu usage on 1 graph - // if (this.cpuid == -1) { - // this.current[0] = this.gtop.user; - // this.current[1] = this.gtop.sys; - // this.current[2] = this.gtop.nice; - // this.current[3] = this.gtop.idle; - // this.current[4] = this.gtop.iowait; - // } else { - // // display cpu usage for given core - // this.current[0] = this.gtop.xcpu_user[this.cpuid]; - // this.current[1] = this.gtop.xcpu_sys[this.cpuid]; - // this.current[2] = this.gtop.xcpu_nice[this.cpuid]; - // this.current[3] = this.gtop.xcpu_idle[this.cpuid]; - // this.current[4] = this.gtop.xcpu_iowait[this.cpuid]; - // } - // - // let delta = 0; - // if (this.cpuid == -1) - // delta = (this.gtop.total - this.last_total)/(100*this.total_cores); - // else - // delta = (this.gtop.xcpu_total[this.cpuid] - this.last_total)/100; - // - // if (delta > 0) { - // for (let i = 0;i < 5;i++) { - // this.usage[i] = Math.round((this.current[i] - this.last[i])/delta); - // this.last[i] = this.current[i]; - // } - // if (this.cpuid == -1) - // this.last_total = this.gtop.total; - // else - // this.last_total = this.gtop.xcpu_total[this.cpuid]; - // } - } - _apply() { - let percent = 0; - if (this.cpuid === -1) { - percent = Math.round(((100 * this.total_cores) - this.usage[3]) / - this.total_cores); - } else { - percent = Math.round((100 - this.usage[3])); - } - - this.text_items[0].text = this.menu_items[0].text = percent.toString(); - let other = 100; - for (let i = 0; i < this.usage.length; i++) { - other -= this.usage[i]; - } - // Not to be confusing - other = Math.max(0, other); - this.vals = [this.usage[0], this.usage[1], - this.usage[2], this.usage[4], other]; - for (let i = 0; i < 5; i++) { - this.tip_vals[i] = Math.round(this.vals[i]); - } - } - - get_cores() { - // Getting xcpu_total makes gjs 1.29.18 segfault - // let cores = 0; - // GTop.glibtop_get_cpu(this.gtop); - // let gtop_total = this.gtop.xcpu_total - // for (let i = 0; i < gtop_total.length;i++) { - // if (gtop_total[i] > 0) - // cores++; - // } - // return cores; - return 1; - } - create_text_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-status-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: '%', style_class: Style.get('sm-perc-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: '%', - style_class: Style.get('sm-label')}) - ]; - } -} - -// Check if one graph per core must be displayed and create the -// appropriate number of cpu items -function createCpus() { - let array = []; - let numcores = 1; - - if (Schema.get_boolean('cpu-individual-cores')) { - // get number of cores - let gtop = new GTop.glibtop_cpu(); - try { - numcores = GTop.glibtop_get_sysinfo().ncpu; - } catch (e) { - global.logError(e); - numcores = 1; - } - } - - // there are several cores to display, - // instantiate each cpu - if (numcores > 1) { - for (let i = 0; i < numcores; i++) { - array.push(new Cpu(i)); - } - } else { - // individual cores option is not set or we failed to - // get the number of cores, create a global cpu item - array.push(new Cpu(-1)); - } - - return array; -} - -const Disk = class SystemMonitor_Disk extends ElementBase { - constructor() { - super({ - elt: 'disk', - item_name: _('Disk'), - color_name: ['read', 'write'] - }); - this.mounts = MountsMonitor.get_mounts(); - MountsMonitor.add_listener(this.update_mounts.bind(this)); - this.last = [0, 0]; - this.usage = [0, 0]; - this.last_time = 0; - this.tip_format(_('MiB/s')); - this.update(); - } - update_mounts(mounts) { - this.mounts = mounts; - } - refresh() { - let accum = [0, 0]; - - let file = Gio.file_new_for_path('/proc/diskstats'); - file.load_contents_async(null, (source, result) => { - let as_r = source.load_contents_finish(result); - let lines = parse_bytearray(as_r[1]).toString().split('\n'); - - for (let i = 0; i < lines.length; i++) { - let line = lines[i]; - let entry = line.trim().split(/[\s]+/); - if (typeof (entry[1]) === 'undefined') { - break; - } - accum[0] += parseInt(entry[5]); - accum[1] += parseInt(entry[9]); - } - - let time = GLib.get_monotonic_time() / 1000; - let delta = (time - this.last_time) / 1000; - if (delta > 0) { - for (let i = 0; i < 2; i++) { - this.usage[i] = ((accum[i] - this.last[i]) / delta / 1024 / 8); - this.last[i] = accum[i]; - } - } - this.last_time = time; - }); - } - _apply() { - this.vals = this.usage.slice(); - for (let i = 0; i < 2; i++) { - if (this.usage[i] < 10) { - this.usage[i] = Math.round(10 * this.usage[i]) / 10; - } else { - this.usage[i] = Math.round(this.usage[i]); - } - } - this.tip_vals = [this.usage[0], this.usage[1]]; - this.menu_items[0].text = this.text_items[1].text = this.tip_vals[0].toLocaleString(Locale); - this.menu_items[3].text = this.text_items[4].text = this.tip_vals[1].toLocaleString(Locale); - } - create_text_items() { - return [ - new St.Label({ - text: _('R'), - style_class: Style.get('sm-status-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-disk-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: Style.diskunits(), - style_class: Style.get('sm-disk-unit-label'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: _('W'), - style_class: Style.get('sm-status-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-disk-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: Style.diskunits(), - style_class: Style.get('sm-disk-unit-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: Style.diskunits(), - style_class: Style.get('sm-label')}), - new St.Label({ - text: _('R'), - style_class: Style.get('sm-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: Style.diskunits(), - style_class: Style.get('sm-label')}), - new St.Label({ - text: ' ' + _('W'), - style_class: Style.get('sm-label')}) - ]; - } -} - -const Freq = class SystemMonitor_Freq extends ElementBase { - constructor() { - super({ - elt: 'freq', - item_name: _('Freq'), - color_name: ['freq'] - }); - this.freq = 0; - this.tip_format('MHz'); - this.update(); - } - refresh() { - let total_frequency = 0; - let num_cpus = GTop.glibtop_get_sysinfo().ncpu; - let i = 0; - let file = Gio.file_new_for_path(`/sys/devices/system/cpu/cpu${i}/cpufreq/scaling_cur_freq`); - var that = this; - file.load_contents_async(null, function cb(source, result) { - let as_r = source.load_contents_finish(result); - total_frequency += parseInt(parse_bytearray(as_r[1])); - - if (++i >= num_cpus) { - that.freq = Math.round(total_frequency / num_cpus / 1000); - } else { - file = Gio.file_new_for_path(`/sys/devices/system/cpu/cpu${i}/cpufreq/scaling_cur_freq`); - file.load_contents_async(null, cb.bind(that)); - } - }); - } - _apply() { - let value = this.freq.toString(); - this.text_items[0].text = value + ' '; - this.vals[0] = value; - this.tip_vals[0] = value; - if (Style.get('') !== '-compact') { - this.menu_items[0].text = value; - } else { - this.menu_items[0].text = this._pad(value, 4); - } - } - // pad a string with leading spaces - _pad(number, length) { - var str = '' + number; - while (str.length < length) { - str = ' ' + str; - } - return str; - } - create_text_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-big-status-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: 'MHz', style_class: Style.get('sm-perc-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: 'MHz', - style_class: Style.get('sm-label')}) - ]; - } -} - -const Mem = class SystemMonitor_Mem extends ElementBase { - constructor() { - super({ - elt: 'memory', - item_name: _('Memory'), - color_name: ['program', 'buffer', 'cache'] - }); - this.max = 1; - - this.gtop = new GTop.glibtop_mem(); - this.mem = [0, 0, 0]; - - GTop.glibtop_get_mem(this.gtop); - this.total = Math.round(this.gtop.total / 1024 / 1024); - let threshold = 4 * 1024; // In MiB - this.useGiB = false; - this._unitConversion = 1024 * 1024; - this._decimals = 100; - if (this.total > threshold) { - this.useGiB = true; - this._unitConversion *= 1024 / this._decimals; - } - - this.tip_format(); - this.update(); - } - refresh() { - GTop.glibtop_get_mem(this.gtop); - if (this.useGiB) { - this.mem[0] = Math.round(this.gtop.user / this._unitConversion); - this.mem[0] /= this._decimals; - this.mem[1] = Math.round(this.gtop.buffer / this._unitConversion); - this.mem[1] /= this._decimals; - this.mem[2] = Math.round(this.gtop.cached / this._unitConversion); - this.mem[2] /= this._decimals; - this.total = Math.round(this.gtop.total / this._unitConversion); - this.total /= this._decimals; - } else { - this.mem[0] = Math.round(this.gtop.user / this._unitConversion); - this.mem[1] = Math.round(this.gtop.buffer / this._unitConversion); - this.mem[2] = Math.round(this.gtop.cached / this._unitConversion); - this.total = Math.round(this.gtop.total / this._unitConversion); - } - } - _pad(number) { - if (this.useGiB) { - if (number < 1) { - // examples: 0.01, 0.10, 0.88 - return number.toLocaleString(Locale, {minimumFractionDigits: 2, maximumFractionDigits: 2}); - } - // examples: 5.85, 16.0, 128 - return number.toLocaleString(Locale, {minimumSignificantDigits: 3, maximumSignificantDigits: 3}); - } - - return number.toLocaleString(Locale); - } - _apply() { - if (this.total === 0) { - this.vals = this.tip_vals = [0, 0, 0]; - } else { - for (let i = 0; i < 3; i++) { - this.vals[i] = this.mem[i] / this.total; - this.tip_vals[i] = Math.round(this.vals[i] * 100); - } - } - this.text_items[0].text = this.tip_vals[0].toString(); - this.menu_items[0].text = this.tip_vals[0].toLocaleString(Locale); - if (Style.get('') !== '-compact') { - this.menu_items[3].text = this._pad(this.mem[0]) + - ' / ' + this._pad(this.total); - } else { - this.menu_items[3].text = this._pad(this.mem[0]) + - '/' + this._pad(this.total); - } - } - create_text_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-status-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: '%', style_class: Style.get('sm-perc-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - let unit = _('MiB'); - if (this.useGiB) { - unit = _('GiB'); - } - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: '%', - style_class: Style.get('sm-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({text: unit, - style_class: Style.get('sm-label')}) - ]; - } -} - -const Net = class SystemMonitor_Net extends ElementBase { - constructor() { - super({ - elt: 'net', - item_name: _('Net'), - color_name: ['down', 'downerrors', 'up', 'uperrors', 'collisions'] - }); - this.speed_in_bits = false; - this.ifs = []; - this.client = libnm_glib ? NM.Client.new() : NM.Client.new(null); - this.update_iface_list(); - - if (!this.ifs.length) { - let net_lines = Shell.get_file_contents_utf8_sync('/proc/net/dev').split('\n'); - for (let i = 2; i < net_lines.length - 1; i++) { - let ifc = net_lines[i].replace(/^\s+/g, '').split(':')[0]; - if (Shell.get_file_contents_utf8_sync('/sys/class/net/' + ifc + '/operstate') - .replace(/\s/g, '') === 'up' && - ifc.indexOf('br') < 0 && - ifc.indexOf('lo') < 0) { - this.ifs.push(ifc); - } - } - } - this.gtop = new GTop.glibtop_netload(); - this.last = [0, 0, 0, 0, 0]; - this.usage = [0, 0, 0, 0, 0]; - this.last_time = 0; - this.tip_format([_('KiB/s'), '/s', _('KiB/s'), '/s', '/s']); - this.update_units(); - Schema.connect('changed::' + this.elt + '-speed-in-bits', this.update_units.bind(this)); - try { - let iface_list = this.client.get_devices(); - this.NMsigID = []; - for (let j = 0; j < iface_list.length; j++) { - this.NMsigID[j] = iface_list[j].connect('state-changed', this.update_iface_list.bind(this)); - } - } catch (e) { - global.logError('Please install Network Manager Gobject Introspection Bindings: ' + e); - } - this.update(); - } - update_units() { - this.speed_in_bits = Schema.get_boolean(this.elt + '-speed-in-bits'); - } - update_iface_list() { - try { - this.ifs = []; - let iface_list = this.client.get_devices(); - for (let j = 0; j < iface_list.length; j++) { - if (iface_list[j].state === NetworkManager.DeviceState.ACTIVATED) { - this.ifs.push(iface_list[j].get_ip_iface() || iface_list[j].get_iface()); - } - } - } catch (e) { - global.logError('Please install Network Manager Gobject Introspection Bindings'); - } - } - refresh() { - let accum = [0, 0, 0, 0, 0]; - - for (let ifn in this.ifs) { - GTop.glibtop_get_netload(this.gtop, this.ifs[ifn]); - accum[0] += this.gtop.bytes_in; - accum[1] += this.gtop.errors_in; - accum[2] += this.gtop.bytes_out; - accum[3] += this.gtop.errors_out; - accum[4] += this.gtop.collisions; - } - - let time = GLib.get_monotonic_time() * 0.001024; - let delta = time - this.last_time; - if (delta > 0) { - for (let i = 0; i < 5; i++) { - this.usage[i] = Math.round((accum[i] - this.last[i]) / delta); - this.last[i] = accum[i]; - this.vals[i] = this.usage[i]; - } - } - this.last_time = time; - } - - // pad a string with leading spaces - _pad(number, length) { - var str = '' + number; - while (str.length < length) { - str = ' ' + str; - } - return str; - } - - _apply() { - this.tip_vals = this.usage; - if (this.speed_in_bits) { - this.tip_vals[0] = Math.round(this.tip_vals[0] * 8.192); - this.tip_vals[2] = Math.round(this.tip_vals[2] * 8.192); - if (this.tip_vals[0] < 1000) { - this.text_items[2].text = Style.netunits_kbits(); - this.menu_items[1].text = this.tip_unit_labels[0].text = _('kbit/s'); - } else if (this.tip_vals[0] < 1000000) { - this.text_items[2].text = Style.netunits_mbits(); - this.menu_items[1].text = this.tip_unit_labels[0].text = _('Mbit/s'); - this.tip_vals[0] = (this.tip_vals[0] / 1000).toPrecision(3); - } else { - this.text_items[2].text = Style.netunits_gbits(); - this.menu_items[1].text = this.tip_unit_labels[0].text = _('Gbit/s'); - this.tip_vals[0] = (this.tip_vals[0] / 1000000).toPrecision(3); - } - if (this.tip_vals[2] < 1000) { - this.text_items[5].text = Style.netunits_kbits(); - this.menu_items[4].text = this.tip_unit_labels[2].text = _('kbit/s'); - } else if (this.tip_vals[2] < 1000000) { - this.text_items[5].text = Style.netunits_mbits(); - this.menu_items[4].text = this.tip_unit_labels[2].text = _('Mbit/s'); - this.tip_vals[2] = (this.tip_vals[2] / 1000).toPrecision(3); - } else { - this.text_items[5].text = Style.netunits_gbits(); - this.menu_items[4].text = this.tip_unit_labels[2].text = _('Gbit/s'); - this.tip_vals[2] = (this.tip_vals[2] / 1000000).toPrecision(3); - } - } else { - if (this.tip_vals[0] < 1024) { - this.text_items[2].text = Style.netunits_kbytes(); - this.menu_items[1].text = this.tip_unit_labels[0].text = _('KiB/s'); - } else if (this.tip_vals[0] < 1048576) { - this.text_items[2].text = Style.netunits_mbytes(); - this.menu_items[1].text = this.tip_unit_labels[0].text = _('MiB/s'); - this.tip_vals[0] = (this.tip_vals[0] / 1024).toPrecision(3); - } else { - this.text_items[2].text = Style.netunits_gbytes(); - this.menu_items[1].text = this.tip_unit_labels[0].text = _('GiB/s'); - this.tip_vals[0] = (this.tip_vals[0] / 1048576).toPrecision(3); - } - if (this.tip_vals[2] < 1024) { - this.text_items[5].text = Style.netunits_kbytes(); - this.menu_items[4].text = this.tip_unit_labels[2].text = _('KiB/s'); - } else if (this.tip_vals[2] < 1048576) { - this.text_items[5].text = Style.netunits_mbytes(); - this.menu_items[4].text = this.tip_unit_labels[2].text = _('MiB/s'); - this.tip_vals[2] = (this.tip_vals[2] / 1024).toPrecision(3); - } else { - this.text_items[5].text = Style.netunits_gbytes(); - this.menu_items[4].text = this.tip_unit_labels[2].text = _('GiB/s'); - this.tip_vals[2] = (this.tip_vals[2] / 1048576).toPrecision(3); - } - } - - if (Style.get('') !== '-compact') { - this.menu_items[0].text = this.text_items[1].text = this.tip_vals[0].toString(); - this.menu_items[3].text = this.text_items[4].text = this.tip_vals[2].toString(); - } else { - this.menu_items[0].text = this.text_items[1].text = this._pad(this.tip_vals[0].toString(), 4); - this.menu_items[3].text = this.text_items[4].text = this._pad(this.tip_vals[2].toString(), 4); - } - } - create_text_items() { - return [ - new St.Icon({ - icon_size: 2 * IconSize / 3 * Style.iconsize(), - icon_name: 'go-down-symbolic'}), - new St.Label({ - text: '', - style_class: Style.get('sm-net-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: _('KiB/s'), - style_class: Style.get('sm-net-unit-label'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Icon({ - icon_size: 2 * IconSize / 3 * Style.iconsize(), - icon_name: 'go-up-symbolic'}), - new St.Label({ - text: '', - style_class: Style.get('sm-net-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: _('KiB/s'), - style_class: Style.get('sm-net-unit-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: _('KiB/s'), - style_class: Style.get('sm-label')}), - new St.Label({ - text: _(' ↓'), - style_class: Style.get('sm-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: _(' KiB/s'), - style_class: Style.get('sm-label')}), - new St.Label({ - text: _(' ↑'), - style_class: Style.get('sm-label')}) - ]; - } -} - -const Swap = class SystemMonitor_Swap extends ElementBase { - constructor() { - super({ - elt: 'swap', - item_name: _('Swap'), - color_name: ['used'] - }); - this.max = 1; - this.gtop = new GTop.glibtop_swap(); - - GTop.glibtop_get_swap(this.gtop); - this.total = Math.round(this.gtop.total / 1024 / 1024); - let threshold = 4 * 1024; // In MiB - this.useGiB = false; - this._unitConversion = 1024 * 1024; - this._decimals = 100; - if (this.total > threshold) { - this.useGiB = true; - this._unitConversion *= 1024 / this._decimals; - } - - this.tip_format(); - this.update(); - } - refresh() { - GTop.glibtop_get_swap(this.gtop); - if (this.useGiB) { - this.swap = Math.round(this.gtop.used / this._unitConversion); - this.swap /= this._decimals; - this.total = Math.round(this.gtop.total / this._unitConversion); - this.total /= this._decimals; - } else { - this.swap = Math.round(this.gtop.used / this._unitConversion); - this.total = Math.round(this.gtop.total / this._unitConversion); - } - } - _pad(number) { - if (this.useGiB) { - if (number < 1) { - // examples: 0.01, 0.10, 0.88 - return number.toLocaleString(Locale, {minimumFractionDigits: 2, maximumFractionDigits: 2}); - } - // examples: 5.85, 16.0, 128 - return number.toLocaleString(Locale, {minimumSignificantDigits: 3, maximumSignificantDigits: 3}); - } - - return number.toLocaleString(Locale); - } - _apply() { - if (this.total === 0) { - this.vals = this.tip_vals = [0]; - } else { - this.vals[0] = this.swap / this.total; - this.tip_vals[0] = Math.round(this.vals[0] * 100); - } - this.text_items[0].text = this.tip_vals[0].toString(); - this.menu_items[0].text = this.tip_vals[0].toString(); - if (Style.get('') !== '-compact') { - this.menu_items[3].text = this._pad(this.swap) + - ' / ' + this._pad(this.total); - } else { - this.menu_items[3].text = this._pad(this.swap) + - '/' + this._pad(this.total); - } - } - - create_text_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-status-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: '%', - style_class: Style.get('sm-perc-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - let unit = 'MiB'; - if (this.useGiB) { - unit = 'GiB'; - } - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: '%', - style_class: Style.get('sm-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: _(unit), - style_class: Style.get('sm-label')}) - ]; - } -} - -const Thermal = class SystemMonitor_Thermal extends ElementBase { - constructor() { - super({ - elt: 'thermal', - item_name: _('Thermal'), - color_name: ['tz0'] - }); - this.max = 100; - - this.item_name = _('Thermal'); - this.temperature = '-- '; - this.fahrenheit_unit = Schema.get_boolean(this.elt + '-fahrenheit-unit'); - this.display_error = true; - this.tip_format(this.temperature_symbol()); - Schema.connect('changed::' + this.elt + '-sensor-file', this.refresh.bind(this)); - this.update(); - } - refresh() { - let sfile = Schema.get_string(this.elt + '-sensor-file'); - if (GLib.file_test(sfile, GLib.FileTest.EXISTS)) { - let file = Gio.file_new_for_path(sfile); - file.load_contents_async(null, (source, result) => { - let as_r = source.load_contents_finish(result) - this.temperature = Math.round(parseInt(parse_bytearray(as_r[1])) / 1000); - }); - } else if (this.display_error) { - global.logError('error reading: ' + sfile); - this.display_error = false; - } - - this.fahrenheit_unit = Schema.get_boolean(this.elt + '-fahrenheit-unit'); - } - _apply() { - this.text_items[0].text = this.menu_items[0].text = this.temperature_text(); - this.temp_over_threshold = this.temperature > Schema.get_int('thermal-threshold'); - this.vals = [this.temperature]; - this.tip_vals[0] = this.temperature_text(); - this.text_items[1].text = this.menu_items[1].text = this.temperature_symbol(); - this.tip_unit_labels[0].text = _(this.temperature_symbol()); - } - create_text_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-status-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: this.temperature_symbol(), - style_class: Style.get('sm-temp-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: this.temperature_symbol(), - style_class: Style.get('sm-label')}) - ]; - } - temperature_text() { - let temperature = this.temperature; - if (this.fahrenheit_unit) { - temperature = Math.round(temperature * 1.8 + 32); - } - return temperature.toString(); - } - temperature_symbol() { - return this.fahrenheit_unit ? '°F' : '°C'; - } -} - -const Fan = class SystemMonitor_Fan extends ElementBase { - constructor() { - super({ - elt: 'fan', - item_name: _('Fan'), - color_name: ['fan0'] - }); - this.rpm = 0; - this.display_error = true; - this.tip_format(_('rpm')); - Schema.connect('changed::' + this.elt + '-sensor-file', this.refresh.bind(this)); - this.update(); - } - refresh() { - let sfile = Schema.get_string(this.elt + '-sensor-file'); - if (GLib.file_test(sfile, GLib.FileTest.EXISTS)) { - let file = Gio.file_new_for_path(sfile); - file.load_contents_async(null, (source, result) => { - let as_r = source.load_contents_finish(result) - this.rpm = parseInt(parse_bytearray(as_r[1])); - }); - } else if (this.display_error) { - global.logError('error reading: ' + sfile); - this.display_error = false; - } - } - _apply() { - this.text_items[0].text = this.rpm.toString(); - this.menu_items[0].text = this.rpm.toString(); - this.vals = [this.rpm / 10]; - this.tip_vals[0] = this.rpm; - } - create_text_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-status-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: _('rpm'), style_class: Style.get('sm-unit-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: _('rpm'), - style_class: Style.get('sm-label')}) - ]; - } -} - -const Gpu = class SystemMonitor_Gpu extends ElementBase { - constructor() { - super({ - elt: 'gpu', - item_name: _('GPU'), - color_name: ['used', 'memory'] - }); - this.max = 100; - - this.item_name = _('GPU'); - this.mem = 0; - this.total = 0; - this.tip_format(); - this.update(); - } - _unit(total) { - this.total = total; - let threshold = 4 * 1024; // In MiB - this.useGiB = false; - this._unitConversion = 1; - this._decimals = 100; - if (this.total > threshold) { - this.useGiB = true; - this._unitConversion *= 1024 / this._decimals; - } - } - refresh() { - // Run asynchronously, to avoid shell freeze - try { - let path = Me.dir.get_path(); - let script = ['/bin/bash', path + '/gpu_usage.sh']; - - // Create subprocess and capture STDOUT - let proc = new Gio.Subprocess({argv: script, flags: Gio.SubprocessFlags.STDOUT_PIPE}); - proc.init(null); - // Asynchronously call the output handler when script output is ready - proc.communicate_utf8_async(null, null, Lang.bind(this, this._handleOutput)); - } catch (err) { - global.logError(err.message); - } - } - _handleOutput(proc, result) { - let [ok, output, ] = proc.communicate_utf8_finish(result); - if (ok) { - this._readTemperature(output); - } else { - global.logError('gpu_usage.sh invocation failed'); - } - } - _sanitizeUsageValue(val) { - val = parseInt(val); - if (isNaN(val)) { - val = 0 - } - return val; - } - _readTemperature(procOutput) { - let usage = procOutput.split('\n'); - let memTotal = this._sanitizeUsageValue(usage[0]); - let memUsed = this._sanitizeUsageValue(usage[1]); - this.percentage = this._sanitizeUsageValue(usage[2]); - if (typeof this.useGiB === 'undefined') { - this._unit(memTotal); - this._update_unit(); - } - - if (this.useGiB) { - this.mem = Math.round(memUsed / this._unitConversion); - this.mem /= this._decimals; - this.total = Math.round(memTotal / this._unitConversion); - this.total /= this._decimals; - } else { - this.mem = Math.round(memUsed / this._unitConversion); - this.total = Math.round(memTotal / this._unitConversion); - } - } - _pad(number) { - if (this.useGiB) { - if (number < 1) { - // examples: 0.01, 0.10, 0.88 - return number.toFixed(2); - } - // examples: 5.85, 16.0, 128 - return number.toPrecision(3); - } - - return number; - } - _update_unit() { - let unit = _('MiB'); - if (this.useGiB) { - unit = _('GiB'); - } - this.menu_items[4].text = unit; - } - _apply() { - this.tip_unit_labels[1].text = "/ " + this.total + " " + this.menu_items[4].text; - if (this.total === 0) { - this.vals = [0, 0]; - this.tip_vals = [0, 0]; - } else { - // we subtract percentage from memory because we do not want memory to be - // "accumulated" in the chart with utilization; these two measures should be - // independent - this.vals = [this.percentage, this.mem / this.total * 100 - this.percentage]; - this.tip_vals = [Math.round(this.vals[0]), this.mem]; - } - this.text_items[0].text = this.tip_vals[0].toString(); - this.menu_items[0].text = this.tip_vals[0].toLocaleString(Locale); - - if (Style.get('') !== '-compact') { - this.menu_items[3].text = this._pad(this.mem).toLocaleString(Locale) + - ' / ' + this._pad(this.total).toLocaleString(Locale); - } else { - this.menu_items[3].text = this._pad(this.mem).toLocaleString(Locale) + - '/' + this._pad(this.total).toLocaleString(Locale); - } - } - create_text_items() { - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-status-value'), - y_align: Clutter.ActorAlign.CENTER}), - new St.Label({ - text: '%', - style_class: Style.get('sm-perc-label'), - y_align: Clutter.ActorAlign.CENTER}) - ]; - } - create_menu_items() { - let unit = _('MiB'); - if (this.useGiB) { - unit = _('GiB'); - } - return [ - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: '%', - style_class: Style.get('sm-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-label')}), - new St.Label({ - text: '', - style_class: Style.get('sm-value')}), - new St.Label({ - text: unit, - style_class: Style.get('sm-label')}) - ]; - } -} - -const Icon = class SystemMonitor_Icon { - constructor() { - this.actor = new St.Icon({ - icon_name: 'org.gnome.SystemMonitor-symbolic', - style_class: 'system-status-icon' - }); - this.actor.visible = Schema.get_boolean('icon-display'); - Schema.connect( - 'changed::icon-display', - () => { - this.actor.visible = Schema.get_boolean('icon-display'); - } - ); - } -} - -function init() { - log('[System monitor] applet init from ' + extension.path); - - Convenience.initTranslations(); - // Get locale, needed as an argument for toLocaleString() since GNOME Shell 3.24 - // See: mozjs library bug https://bugzilla.mozilla.org/show_bug.cgi?id=999003 - Locale = GLib.get_language_names()[0]; - if (Locale.indexOf('_') !== -1) { - Locale = Locale.split('_')[0]; - } - - IconSize = Math.round(Panel.PANEL_ICON_SIZE * 4 / 5); -} - -function enable() { - log('[System monitor] applet enabling'); - Schema = Convenience.getSettings(); - - Style = new smStyleManager(); - MountsMonitor = new smMountsMonitor(); - - Background = color_from_string(Schema.get_string('background')); - - if (!(smDepsGtop && smDepsNM)) { - Main.__sm = { - smdialog: new smDialog() - }; - - let dialog_timeout = Mainloop.timeout_add_seconds( - 1, - () => { - Main.__sm.smdialog.open(); - Mainloop.source_remove(dialog_timeout); - return true; - }); - } else { - let panel = Main.panel._rightBox; - StatusArea = Main.panel._statusArea; - if (typeof (StatusArea) === 'undefined') { - StatusArea = Main.panel.statusArea; - } - if (Schema.get_boolean('center-display')) { - panel = Main.panel._centerBox; - } - - MountsMonitor.connect(); - - // Debug - Main.__sm = { - tray: new PanelMenu.Button(0.5), - icon: new Icon(), - pie: new Pie(), - bar: new Bar(), - elts: [], - }; - - // Items to Monitor - Main.__sm.elts = createCpus(); - Main.__sm.elts.push(new Freq()); - Main.__sm.elts.push(new Mem()); - Main.__sm.elts.push(new Swap()); - Main.__sm.elts.push(new Net()); - Main.__sm.elts.push(new Disk()); - Main.__sm.elts.push(new Gpu()); - Main.__sm.elts.push(new Thermal()); - Main.__sm.elts.push(new Fan()); - Main.__sm.elts.push(new Battery()); - - let tray = Main.__sm.tray; - let elts = Main.__sm.elts; - - if (Schema.get_boolean('move-clock')) { - let dateMenu = Main.panel.statusArea.dateMenu; - Main.panel._centerBox.remove_actor(dateMenu.container); - Main.panel._addToPanelBox('dateMenu', dateMenu, -1, Main.panel._rightBox); - tray.clockMoved = true; - } - - Schema.connect('changed::background', (schema, key) => { - Background = color_from_string(Schema.get_string(key)); - }); - Main.panel._addToPanelBox('system-monitor', tray, 1, panel); - - // The spacing adds a distance between the graphs/text on the top bar - let spacing = Schema.get_boolean('compact-display') ? '1' : '4'; - let box = new St.BoxLayout({style: 'spacing: ' + spacing + 'px;'}); - if (shell_Version < '3.36') { - tray.actor.add_actor(box); - } else { - tray.add_actor(box); - } - box.add_actor(Main.__sm.icon.actor); - // Add items to panel box - for (let elt in elts) { - box.add_actor(elts[elt].actor); - } - - // Build Menu Info Box Table - let menu_info = new PopupMenu.PopupBaseMenuItem({reactive: false}); - let menu_info_box = new St.BoxLayout(); - menu_info.actor.add(menu_info_box); - Main.__sm.tray.menu.addMenuItem(menu_info, 0); - - build_menu_info(); - - tray.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - - let pie_item = Main.__sm.pie; - pie_item.create_menu_item(); - tray.menu.addMenuItem(pie_item.menu_item); - - let bar_item = Main.__sm.bar; - bar_item.create_menu_item(); - tray.menu.addMenuItem(bar_item.menu_item); - - change_usage(); - Schema.connect('changed::disk-usage-style', change_usage); - - tray.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - - tray.menu.connect( - 'open-state-changed', - function (menu, isOpen) { - if (isOpen) { - Main.__sm.pie.actor.queue_repaint(); - - menu_timeout = Mainloop.timeout_add_seconds( - 5, - () => { - Main.__sm.pie.actor.queue_repaint(); - return true; - }); - } else { - Mainloop.source_remove(menu_timeout); - } - } - ); - - let _appSys = Shell.AppSystem.get_default(); - let _gsmApp = _appSys.lookup_app('gnome-system-monitor.desktop'); - let _gsmPrefs = _appSys.lookup_app('gnome-shell-extension-prefs.desktop'); - if (_gsmPrefs === null) { - _gsmPrefs = _appSys.lookup_app('org.gnome.Extensions.desktop'); - } - let item; - item = new PopupMenu.PopupMenuItem(_('System Monitor...')); - item.connect('activate', () => { - _gsmApp.activate(); - }); - tray.menu.addMenuItem(item); - - item = new PopupMenu.PopupMenuItem(_('Preferences...')); - item.connect('activate', () => { - if (typeof ExtensionUtils.openPrefs === 'function') { - ExtensionUtils.openPrefs(); - } else if (_gsmPrefs.get_state() === _gsmPrefs.SHELL_APP_STATE_RUNNING) { - _gsmPrefs.activate(); - } else { - let info = _gsmPrefs.get_app_info(); - let timestamp = global.display.get_current_time_roundtrip(); - info.launch_uris([metadata.uuid], global.create_app_launch_context(timestamp, -1)); - } - }); - tray.menu.addMenuItem(item); - Main.panel.menuManager.addMenu(tray.menu); - } - log('[System monitor] applet enabling done'); -} - -function disable() { - // restore clock - if (Main.__sm.tray.clockMoved) { - let dateMenu = Main.panel.statusArea.dateMenu; - Main.panel._rightBox.remove_actor(dateMenu.container); - Main.panel._addToPanelBox('dateMenu', dateMenu, Main.sessionMode.panel.center.indexOf('dateMenu'), Main.panel._centerBox); - } - // restore system power icon if necessary - // workaround bug introduced by multiple cpus init : - // if (Schema.get_boolean('battery-hidesystem') && Main.__sm.elts.battery.icon_hidden) { - // Main.__sm.elts.battery.hide_system_icon(false); - // } - // for (let i in Main.__sm.elts) { - // if (Main.__sm.elts[i].elt == 'battery') - // Main.__sm.elts[i].hide_system_icon(false); - // } - - if (MountsMonitor) { - MountsMonitor.disconnect(); - MountsMonitor = null; - } - - if (Style) { - Style = null; - } - - Schema.run_dispose(); - for (let eltName in Main.__sm.elts) { - Main.__sm.elts[eltName].destroy(); - } - if (shell_Version < '3.36') { - Main.__sm.tray.actor.destroy(); - } else { - Main.__sm.tray.destroy(); - } - Main.__sm = null; - - log('[System monitor] applet disable'); -} diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh deleted file mode 100755 index f2167ef..0000000 --- a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/gpu_usage.sh +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -################################################################################## -# This file is part of System Monitor Gnome extension. -# System Monitor Gnome extension is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# System Monitor Gnome extension is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# You should have received a copy of the GNU General Public License -# along with System Monitor. If not, see <http://www.gnu.org/licenses/>. -# Copyright 2017 Fran Glais, David King, indigohedgehog@github. -################################################################################## - -################################## -# # -# Check for GPU memory usage # -# # -################################## - -checkcommand() -{ - command -v "$1" > /dev/null 2>&1 -} - -# This will print three lines. The first one is the the total vRAM available, -# the second one is the used vRAM and the third on is the GPU usage in %. -if checkcommand nvidia-smi; then - nvidia-smi -i 0 --query-gpu=memory.total,memory.used,utilization.gpu --format=csv,noheader,nounits | while IFS=', ' read -r a b c; do echo "$a"; echo "$b"; echo "$c"; done - -elif lsmod | grep amdgpu > /dev/null; then - total=$(cat /sys/class/drm/card0/device/mem_info_vram_total) - echo $(($total / 1024 / 1024)) - - used=$(cat /sys/class/drm/card0/device/mem_info_vram_used) - echo $(($used / 1024 / 1024)) - - cat /sys/class/drm/card0/device/gpu_busy_percent - -elif checkcommand glxinfo; then - TOTALVRAM=$(glxinfo | grep -A2 -i GL_NVX_gpu_memory_info | grep -E -i "dedicated" | cut -f2- -d ':' | gawk '{print $1}') - AVAILVRAM=$(glxinfo | grep -A4 -i GL_NVX_gpu_memory_info | grep -E -i "available dedicated" | cut -f2- -d ':' | gawk '{print $1}') - FREEVRAM=$((TOTALVRAM-AVAILVRAM)) - echo "$TOTALVRAM" - echo "$FREEVRAM" - -fi diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index ed116be..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ar/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index ab48c30..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ca/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index be4ab2d..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/cs/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index a14e961..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/de/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 7302234..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_ES/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 7f3d4b3..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/es_MX/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index b1ccb17..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fa/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 7623fac..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fi/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index e567368..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/fr/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 5ffcee0..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/hu/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 8fb4592..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/it/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 4e96e8e..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ja/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 94c2ce3..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ko/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 472482f..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/nl_NL/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 9537a6e..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pl/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index b756a3d..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 7d79d27..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/pt_BR/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index c789c33..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ro/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 3bca914..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/ru/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index c362e0e..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/sk/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 1d4ff15..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/tr/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 9169a1f..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/uk/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo deleted file mode 100644 index 09f9162..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/locale/zh_CN/LC_MESSAGES/system-monitor.mo and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json deleted file mode 100644 index 44e737a..0000000 --- a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/metadata.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Display system information in GNOME Shell status bar, such as memory, CPU, disk and battery usages, network rates\u2026", - "gettext-domain": "system-monitor", - "name": "system-monitor", - "settings-schema": "org.gnome.shell.extensions.system-monitor", - "shell-version": [ - "3.26", - "3.28", - "3.30", - "3.34", - "3.32", - "3.36", - "40" - ], - "url": "https://github.com/paradoxxxzero/gnome-shell-system-monitor-applet", - "uuid": "system-monitor@paradoxxx.zero.gmail.com", - "version": 40 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js deleted file mode 100644 index 388f512..0000000 --- a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/prefs.js +++ /dev/null @@ -1,553 +0,0 @@ -const Gtk = imports.gi.Gtk; -const Gio = imports.gi.Gio; -const Gdk = imports.gi.Gdk; -const GLib = imports.gi.GLib; -const ByteArray = imports.byteArray; -const Config = imports.misc.config; - -const Gettext = imports.gettext.domain('system-monitor'); - -let extension = imports.misc.extensionUtils.getCurrentExtension(); -let convenience = extension.imports.convenience; - -const _ = Gettext.gettext; -const N_ = function (e) { - return e; -}; - -let Schema; - -const shellMajorVersion = parseInt(Config.PACKAGE_VERSION.split('.')[0]); - -function init() { - convenience.initTranslations(); - Schema = convenience.getSettings(); -} - -String.prototype.capitalize = function () { - return this.replace(/(^|\s)([a-z])/g, function (m, p1, p2) { - return p1 + p2.toUpperCase(); - }); -}; - -function color_to_hex(color) { - var output = N_('#%02x%02x%02x%02x').format( - 255 * color.red, - 255 * color.green, - 255 * color.blue, - 255 * color.alpha); - return output; -} - -function parse_bytearray(bytearray) { - if (!ByteArray.toString(bytearray).match(/GjsModule byteArray/)) { - return ByteArray.toString(bytearray); - } - return bytearray -} - -function check_sensors(sensor_type) { - const hwmon_path = '/sys/class/hwmon/'; - const hwmon_dir = Gio.file_new_for_path(hwmon_path); - - const sensor_files = []; - const sensor_labels = []; - - function get_label_from(file) { - if (file.query_exists(null)) { - // load_contents (and even cat) fails with "Invalid argument" for some label files - try { - let [success, contents] = file.load_contents(null); - if (success) { - return String(parse_bytearray(contents)).split('\n')[0]; - } - } catch (e) { - log('[System monitor] error loading label from file ' + file.get_path() + ': ' + e); - } - } - return null; - } - - function add_sensors_from(chip_dir, chip_label) { - const chip_children = chip_dir.enumerate_children( - 'standard::name,standard::type', Gio.FileQueryInfoFlags.NONE, null); - if (!chip_children) { - log('[System monitor] error enumerating children of chip ' + chip_dir.get_path()); - return false; - } - - const input_entry_regex = new RegExp('^' + sensor_type + '(\\d+)_input$'); - let info; - let added = false; - while ((info = chip_children.next_file(null))) { - if (info.get_file_type() !== Gio.FileType.REGULAR) { - continue; - } - const matches = info.get_name().match(input_entry_regex); - if (!matches) { - continue; - } - const input_ordinal = matches[1]; - const input = chip_children.get_child(info); - const input_label = get_label_from(chip_dir.get_child(sensor_type + input_ordinal + '_label')); - - sensor_files.push(input.get_path()); - sensor_labels.push(chip_label + ' - ' + (input_label || input_ordinal)); - added = true; - } - return added; - } - - const hwmon_children = hwmon_dir.enumerate_children( - 'standard::name,standard::type', Gio.FileQueryInfoFlags.NONE, null); - if (!hwmon_children) { - log('[System monitor] error enumerating hwmon children'); - return [[], []]; - } - - let info; - while ((info = hwmon_children.next_file(null))) { - if (info.get_file_type() !== Gio.FileType.DIRECTORY || !info.get_name().match(/^hwmon\d+$/)) { - continue; - } - const chip = hwmon_children.get_child(info); - const chip_label = get_label_from(chip.get_child('name')) || chip.get_basename(); - - if (!add_sensors_from(chip, chip_label)) { - // This is here to provide compatibility with previous code, but I can't find any - // information about sensors being stored in chip/device directory. Can we delete it? - const chip_device = chip.get_child('device'); - if (chip_device.query_exists(null)) { - add_sensors_from(chip_device, chip_label); - } - } - } - return [sensor_files, sensor_labels]; -} - -/** - * @param args.hasBorder Whether the box has a border (true) or not - * @param args.horizontal Whether the box is horizontal (true) - * or vertical (false) - * @param args.shouldPack Determines whether a horizontal box should have - * uniform spacing for its children. Only applies to horizontal boxes - * @param args.spacing The amount of spacing for a given box - * @returns a new Box with settings specified by args - */ -function box(args = {}) { - const options = { }; - - if (typeof args.spacing !== 'undefined') { - options.spacing = args.spacing; - } - - if (shellMajorVersion < 40) { - if (args.hasBorder) { - options.border_width = 10; - } - - return args.horizontal ? - new Gtk.HBox(options) : new Gtk.VBox(options); - } - - if (args.hasBorder) { - options.margin_top = 10; - options.margin_bottom = 10; - options.margin_start = 10; - options.margin_end = 10; - } - - options.orientation = args.horizontal ? - Gtk.Orientation.HORIZONTAL : Gtk.Orientation.VERTICAL; - - const aliasBox = new Gtk.Box(options); - - if (args.shouldPack) { - aliasBox.set_homogeneous(true); - } - - - aliasBox.add = aliasBox.append; - aliasBox.pack_start = aliasBox.prepend; - // normally, this would be append; it is aliased to prepend because - // that appears to yield the same behavior as version < 40 - aliasBox.pack_end = aliasBox.prepend; - - return aliasBox; -} - -const ColorSelect = class SystemMonitor_ColorSelect { - constructor(name) { - this.label = new Gtk.Label({label: name + _(':')}); - this.picker = new Gtk.ColorButton(); - this.actor = box({horizontal: true, spacing: 5}); - this.actor.add(this.label); - this.actor.add(this.picker); - this.picker.set_use_alpha(true); - } - set_value(value) { - let color = new Gdk.RGBA(); - - if (Gtk.get_major_version() >= 4) { - // GDK did not support parsing hex colours with alpha before GTK 4. - color.parse(value); - } else { - // Use the Compat only when GTK 4 is not available, - // since it depends on the deprecated Clutter library. - let Compat = extension.imports.compat; - let clutterColor = Compat.color_from_string(value); - let ctemp = [clutterColor.red, clutterColor.green, clutterColor.blue, clutterColor.alpha / 255]; - color.parse('rgba(' + ctemp.join(',') + ')'); - } - - this.picker.set_rgba(color); - } -} - -const IntSelect = class SystemMonitor_IntSelect { - constructor(name) { - this.label = new Gtk.Label({label: name + _(':')}); - this.spin = new Gtk.SpinButton(); - this.actor = box({horizontal: true, shouldPack: true, }); - this.actor.add(this.label); - this.actor.add(this.spin); - this.spin.set_numeric(true); - } - set_args(minv, maxv, incre, page) { - this.spin.set_range(minv, maxv); - this.spin.set_increments(incre, page); - } - set_value(value) { - this.spin.set_value(value); - } -} - -const Select = class SystemMonitor_Select { - constructor(name) { - this.label = new Gtk.Label({label: name + _(':')}); - // this.label.set_justify(Gtk.Justification.RIGHT); - this.selector = new Gtk.ComboBoxText(); - this.actor = box({horizontal: true, shouldPack: true, spacing: 5}); - this.actor.add(this.label); - this.actor.add(this.selector); - } - set_value(value) { - this.selector.set_active(value); - } - add(items) { - items.forEach((item) => { - this.selector.append_text(item); - }) - } -} - -function set_enum(combo, schema, name) { - Schema.set_enum(name, combo.get_active()); -} - -function set_color(color, schema, name) { - Schema.set_string(name, color_to_hex(color.get_rgba())) -} - -function set_string(combo, schema, name, _slist) { - Schema.set_string(name, _slist[combo.get_active()]); -} - -const SettingFrame = class SystemMonitor { - constructor(name, schema) { - this.schema = schema; - this.label = new Gtk.Label({label: name}); - - this.vbox = box({horizontal: false, shouldPack: true, spacing: 20}); - this.hbox0 = box({horizontal: true, shouldPack: true, spacing: 20}); - this.hbox1 = box({horizontal: true, shouldPack: true, spacing: 20}); - this.hbox2 = box({horizontal: true, shouldPack: true, spacing: 20}); - this.hbox3 = box({horizontal: true, shouldPack: true, spacing: 20}); - - if (shellMajorVersion < 40) { - this.frame = new Gtk.Frame({border_width: 10}); - this.frame.add(this.vbox); - } else { - this.frame = new Gtk.Frame({ - margin_top: 10, - margin_bottom: 10, - margin_start: 10, - margin_end: 10 - }); - this.frame.set_child(this.vbox); - } - - - if (shellMajorVersion < 40) { - this.vbox.pack_start(this.hbox0, true, false, 0); - this.vbox.pack_start(this.hbox1, true, false, 0); - this.vbox.pack_start(this.hbox2, true, false, 0); - this.vbox.pack_start(this.hbox3, true, false, 0); - } else { - this.vbox.append(this.hbox0); - this.vbox.append(this.hbox1); - this.vbox.append(this.hbox2); - this.vbox.append(this.hbox3); - } - } - - /** Enforces child ordering of first 2 boxes by label */ - _reorder() { - if (shellMajorVersion < 40) { - /** @return {string} label of/inside component */ - const labelOf = el => { - if (el.get_children) { - return labelOf(el.get_children()[0]); - } - return el && el.label || ''; - }; - [this.hbox0, this.hbox1].forEach(hbox => { - hbox.get_children() - .sort((c1, c2) => labelOf(c1).localeCompare(labelOf(c2))) - .forEach((child, index) => hbox.reorder_child(child, index)); - }); - } else { - /** @return {string} label of/inside component */ - const labelOf = el => { - if (el.get_label) { - return el.get_label(); - } - return labelOf(el.get_first_child()); - } - - [this.hbox0, this.hbox1].forEach(hbox => { - const children = []; - let next = hbox.get_first_child(); - - while (next !== null) { - children.push(next); - next = next.get_next_sibling(); - } - - const sorted = children - .sort((c1, c2) => labelOf(c1).localeCompare(labelOf(c2))); - - sorted - .forEach((child, index) => { - hbox.reorder_child_after(child, sorted[index - 1] || null); - }); - }); - } - } - - add(key) { - const configParent = key.substring(0, key.indexOf('-')); - const config = key.substring(configParent.length + 1); - - // hbox0 - if (config === 'display') { - let item = new Gtk.CheckButton({label: _('Display')}); - this.hbox0.add(item); - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (config === 'show-text') { - let item = new Gtk.CheckButton({label: _('Show Text')}); - this.hbox0.add(item); - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (config === 'show-menu') { - let item = new Gtk.CheckButton({label: _('Show In Menu')}); - this.hbox0.add(item); - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - // hbox1 - } else if (config === 'refresh-time') { - let item = new IntSelect(_('Refresh Time')); - item.set_args(50, 100000, 1000, 5000); - this.hbox1.add(item.actor); - Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); - } else if (config === 'graph-width') { - let item = new IntSelect(_('Graph Width')); - item.set_args(1, 1000, 1, 10); - this.hbox1.add(item.actor); - Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); - } else if (config === 'style') { - let item = new Select(_('Display Style')); - item.add([_('digit'), _('graph'), _('both')]); - item.set_value(this.schema.get_enum(key)); - this.hbox1.add(item.actor); - item.selector.connect('changed', function (style) { - set_enum(style, Schema, key); - }); - // Schema.bind(key, item.selector, 'active', Gio.SettingsBindFlags.DEFAULT); - // hbox2 - } else if (config.match(/-color$/)) { - let item = new ColorSelect(_(config.split('-')[0].capitalize())); - item.set_value(this.schema.get_string(key)); - if (shellMajorVersion < 40) { - this.hbox2.pack_end(item.actor, true, false, 0); - } else { - this.hbox2.append(item.actor); - } - item.picker.connect('color-set', function (color) { - set_color(color, Schema, key); - }); - } else if (config.match(/sensor/)) { - let sensor_type = configParent === 'fan' ? 'fan' : 'temp'; - let [_slist, _strlist] = check_sensors(sensor_type); - let item = new Select(_('Sensor')); - if (_slist.length === 0) { - item.add([_('Please install lm-sensors')]); - } else if (_slist.length === 1) { - this.schema.set_string(key, _slist[0]); - } - item.add(_strlist); - try { - item.set_value(_slist.indexOf(this.schema.get_string(key))); - } catch (e) { - item.set_value(0); - } - // this.hbox3.add(item.actor); - if (configParent === 'fan') { - if (shellMajorVersion < 40) { - this.hbox2.pack_end(item.actor, true, false, 0); - } else { - this.hbox2.append(item.actor); - } - } else if (shellMajorVersion < 40) { - this.hbox2.pack_start(item.actor, true, false, 0); - } else { - this.hbox2.prepend(item.actor); - } - item.selector.connect('changed', function (combo) { - set_string(combo, Schema, key, _slist); - }); - // hbox3 - } else if (config === 'speed-in-bits') { - let item = new Gtk.CheckButton({label: _('Show network speed in bits')}); - this.hbox3.add(item); - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (config === 'individual-cores') { - let item = new Gtk.CheckButton({label: _('Display Individual Cores')}); - this.hbox3.add(item); - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (config === 'time') { - let item = new Gtk.CheckButton({label: _('Show Time Remaining')}); - this.hbox3.add(item); - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (config === 'hidesystem') { - let item = new Gtk.CheckButton({label: _('Hide System Icon')}); - this.hbox3.add(item); - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (config === 'usage-style') { - let item = new Select(_('Usage Style')); - item.add([_('pie'), _('bar'), _('none')]); - item.set_value(this.schema.get_enum(key)); - if (shellMajorVersion < 40) { - this.hbox3.pack_end(item.actor, false, false, 20); - } else { - this.hbox3.append(item.actor); - } - - item.selector.connect('changed', function (style) { - set_enum(style, Schema, key); - }); - } else if (config === 'fahrenheit-unit') { - let item = new Gtk.CheckButton({label: _('Display temperature in Fahrenheit')}); - this.hbox3.add(item); - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (config === 'threshold') { - let item = new IntSelect(_('Temperature threshold (0 to disable)')); - item.set_args(0, 300, 5, 5); - this.hbox3.add(item.actor); - Schema.bind(key, item.spin, 'value', Gio.SettingsBindFlags.DEFAULT); - } - if (configParent.indexOf('gpu') !== -1 && - config === 'display') { - let item = new Gtk.Label({label: _('** Only Nvidia GPUs supported so far **')}); - this.hbox3.add(item); - } - this._reorder(); - } -} - -const App = class SystemMonitor_App { - constructor() { - let setting_items = ['cpu', 'memory', 'swap', 'net', 'disk', 'gpu', 'thermal', 'fan', 'freq', 'battery']; - let keys = Schema.list_keys(); - - this.items = []; - this.settings = []; - - setting_items.forEach((setting) => { - this.settings[setting] = new SettingFrame(_(setting.capitalize()), Schema); - }); - - this.main_vbox = box({ - hasBorder: true, horizontal: false, spacing: 10}); - this.hbox1 = box({ - hasBorder: true, horizontal: true, shouldPack: true, spacing: 20}); - if (shellMajorVersion < 40) { - this.main_vbox.pack_start(this.hbox1, false, false, 0); - } else { - this.main_vbox.prepend(this.hbox1); - } - - keys.forEach((key) => { - if (key === 'icon-display') { - let item = new Gtk.CheckButton({label: _('Display Icon')}); - this.items.push(item) - this.hbox1.add(item) - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (key === 'center-display') { - let item = new Gtk.CheckButton({label: _('Display in the Middle')}) - this.items.push(item) - this.hbox1.add(item) - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (key === 'compact-display') { - let item = new Gtk.CheckButton({label: _('Compact Display')}) - this.items.push(item) - this.hbox1.add(item) - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (key === 'show-tooltip') { - let item = new Gtk.CheckButton({label: _('Show tooltip')}) - item.set_active(Schema.get_boolean(key)) - this.items.push(item) - this.hbox1.add(item) - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (key === 'move-clock') { - let item = new Gtk.CheckButton({label: _('Move the clock')}) - this.items.push(item) - this.hbox1.add(item) - Schema.bind(key, item, 'active', Gio.SettingsBindFlags.DEFAULT); - } else if (key === 'background') { - let item = new ColorSelect(_('Background Color')) - item.set_value(Schema.get_string(key)) - this.items.push(item) - if (shellMajorVersion < 40) { - this.hbox1.pack_start(item.actor, true, false, 0) - } else { - this.hbox1.prepend(item.actor) - } - item.picker.connect('color-set', function (color) { - set_color(color, Schema, key); - }); - } else { - let sections = key.split('-'); - if (setting_items.indexOf(sections[0]) >= 0) { - this.settings[sections[0]].add(key); - } - } - }); - this.notebook = new Gtk.Notebook() - setting_items.forEach((setting) => { - this.notebook.append_page(this.settings[setting].frame, this.settings[setting].label) - if (shellMajorVersion < 40) { - this.main_vbox.show_all(); - this.main_vbox.pack_start(this.notebook, true, true, 0) - } else { - this.main_vbox.append(this.notebook); - } - }); - if (shellMajorVersion < 40) { - this.main_vbox.show_all(); - } - } -} - -function buildPrefsWidget() { - let widget = new App(); - return widget.main_vbox; -} diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled deleted file mode 100644 index aeef9ca..0000000 Binary files a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/gschemas.compiled and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml deleted file mode 100644 index 6247263..0000000 --- a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/schemas/org.gnome.shell.extensions.system-monitor.gschema.xml +++ /dev/null @@ -1,463 +0,0 @@ -<schemalist gettext-domain="system-monitor"> - <enum id="org.gnome.shell.extensions.system-monitor.display-style"> - <value value="0" nick="digit"/> - <value value="1" nick="graph"/> - <value value="2" nick="both"/> - </enum> - <enum id="org.gnome.shell.extensions.system-monitor.disk-usage-style"> - <value value="0" nick="pie"/> - <value value="1" nick="bar"/> - <value value="2" nick="none"/> - </enum> - <schema id="org.gnome.shell.extensions.system-monitor" path="/org/gnome/shell/extensions/system-monitor/"> - <key name="icon-display" type="b"> - <default>true</default> - <summary>Display system monitor icon</summary> - <description>Set to true to display system monitor icon in status bar.(NOTICE: The icon will be shown when none of the others is shown.)</description> - </key> - <key name="memory-display" type="b"> - <default>true</default> - <summary>Display memory</summary> - <description>Set to false to remove memory display in status bar</description> - </key> - <key name="memory-refresh-time" type="i"> - <default>5000</default> - <summary>Memory refresh time</summary> - <description>Time in ms between 2 refresh of memory</description> - </key> - <key name="memory-graph-width" type="i"> - <default>100</default> - <summary>Memory graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="memory-show-text" type="b"> - <default>true</default> - <summary>Display 'mem'</summary> - <description>Set to true to show 'mem' before memory display</description> - </key> - <key name="memory-show-menu" type="b"> - <default>true</default> - <summary>Display Memory In Menu</summary> - <description>Set to true to show memory in pop-up menu</description> - </key> - <key name="memory-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'graph'</default> - <summary>Choose the display style.</summary> - </key> - <key name="swap-display" type="b"> - <default>false</default> - <summary>Display swap</summary> - <description>Set to false to remove swap display in status bar</description> - </key> - <key name="swap-refresh-time" type="i"> - <default>5000</default> - <summary>Swap refresh time</summary> - <description>Time in ms between 2 refresh of swap</description> - </key> - <key name="swap-graph-width" type="i"> - <default>100</default> - <summary>Swap graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="swap-show-text" type="b"> - <default>true</default> - <summary>Display 'swap'</summary> - <description>Set to true to show 'swap' before swap display</description> - </key> - <key name="swap-show-menu" type="b"> - <default>true</default> - <summary>Display Swap In Menu</summary> - <description>Set to true to show swap in pop-up menu</description> - </key> - <key name="swap-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'graph'</default> - <summary>Choose the display style.</summary> - </key> - <key name="cpu-display" type="b"> - <default>true</default> - <summary>Display cpu</summary> - <description>Set to false to remove cpu display in status bar</description> - </key> - <key name="cpu-refresh-time" type="i"> - <default>1500</default> - <summary>Cpu refresh time</summary> - <description>Time in ms between 2 refresh of cpu</description> - </key> - <key name="cpu-graph-width" type="i"> - <default>100</default> - <summary>Cpu graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="cpu-show-text" type="b"> - <default>true</default> - <summary>Display 'cpu'</summary> - <description>Set to true to show 'cpu' before cpu display</description> - </key> - <key name="cpu-show-menu" type="b"> - <default>true</default> - <summary>Display Cpu In Menu</summary> - <description>Set to true to show cpu in pop-up menu</description> - </key> - <key name="cpu-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'graph'</default> - <summary>Choose the display style.</summary> - </key> - <key name="cpu-individual-cores" type="b"> - <default>false</default> - <summary>Display one graph per cpu core</summary> - <description>Set to true to display one graph per cpu core</description> - </key> - <key name="gpu-display" type="b"> - <default>false</default> - <summary>Display GPU usage</summary> - <description>Set to false to remove GPU display in status bar</description> - </key> - <key name="gpu-refresh-time" type="i"> - <default>5000</default> - <summary>Memory refresh time</summary> - <description>Time in ms between 2 refreshes of GPU usage</description> - </key> - <key name="gpu-graph-width" type="i"> - <default>100</default> - <summary>GPU usage graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="gpu-show-text" type="b"> - <default>true</default> - <summary>Display 'gpu'</summary> - <description>Set to true to show 'gpu' before GPU display</description> - </key> - <key name="gpu-show-menu" type="b"> - <default>false</default> - <summary>Display GPU In Menu</summary> - <description>Set to true to show GPU in pop-up menu</description> - </key> - <key name="gpu-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'graph'</default> - <summary>Choose the display style.</summary> - </key> - <key name="freq-display" type="b"> - <default>false</default> - <summary>Display freq</summary> - <description>Set to false to remove freq display in status bar</description> - </key> - <key name="freq-refresh-time" type="i"> - <default>1500</default> - <summary>Cpu frequency refresh time</summary> - <description>Time in ms between 2 refresh of cpu</description> - </key> - <key name="freq-graph-width" type="i"> - <default>100</default> - <summary>Cpu frequency graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="freq-show-text" type="b"> - <default>false</default> - <summary>Display freq'</summary> - <description>Set to true to show 'freq' before cpu frequency display</description> - </key> - <key name="freq-show-menu" type="b"> - <default>false</default> - <summary>Display Freq In Menu</summary> - <description>Set to true to show freq in pop-up menu</description> - </key> - <key name="freq-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'graph'</default> - <summary>Choose the display style.</summary> - </key> - <key name="net-display" type="b"> - <default>true</default> - <summary>Display net</summary> - <description>Set to false to remove net display in status bar</description> - </key> - <key name="net-refresh-time" type="i"> - <default>1000</default> - <summary>Net refresh time</summary> - <description>Time in ms between 2 refresh of net</description> - </key> - <key name="net-graph-width" type="i"> - <default>100</default> - <summary>Net graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="net-show-text" type="b"> - <default>true</default> - <summary>Display 'net'</summary> - <description>Set to true to show 'net' before net display</description> - </key> - <key name="net-show-menu" type="b"> - <default>true</default> - <summary>Display Net In Menu</summary> - <description>Set to true to show net in pop-up menu</description> - </key> - <key name="net-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'graph'</default> - <summary>Choose the display style.</summary> - </key> - <key name="net-speed-in-bits" type="b"> - <default>false</default> - <summary>Show network speed in bits/sec</summary> - </key> - <key name="disk-display" type="b"> - <default>false</default> - <summary>Display disk io speed</summary> - <description>Set to false to remove disk display in status bar</description> - </key> - <key name="disk-refresh-time" type="i"> - <default>2000</default> - <summary>Disk IO refresh time</summary> - <description>Time in ms between 2 refresh of Disk IO</description> - </key> - <key name="disk-graph-width" type="i"> - <default>100</default> - <summary>Disk IO graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="disk-show-text" type="b"> - <default>true</default> - <summary>Display 'disk'</summary> - <description>Set to true to show 'disk' before disk io display</description> - </key> - <key name="disk-show-menu" type="b"> - <default>true</default> - <summary>Display Disk In Menu</summary> - <description>Set to true to show disk in pop-up menu</description> - </key> - <key name="disk-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'graph'</default> - <summary>Choose the display style.</summary> - </key> - <key name="disk-usage-style" enum="org.gnome.shell.extensions.system-monitor.disk-usage-style"> - <default>'pie'</default> - <summary>Choose the disk usage display style.</summary> - </key> - <key name="thermal-display" type="b"> - <default>false</default> - <summary>Display thermal</summary> - <description>Set to false to remove thermal display in status bar</description> - </key> - <key name="thermal-refresh-time" type="i"> - <default>5000</default> - <summary>thermal refresh time</summary> - <description>Time in ms between 2 refresh of thermal</description> - </key> - <key name="thermal-graph-width" type="i"> - <default>100</default> - <summary>thermal graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="thermal-show-text" type="b"> - <default>true</default> - <summary>Display 'thermal'</summary> - <description>Set to true to show 'thermal' before thermal display</description> - </key> - <key name="thermal-show-menu" type="b"> - <default>true</default> - <summary>Display Temps In Menu</summary> - <description>Set to true to show thermal in pop-up menu</description> - </key> - <key name="thermal-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'graph'</default> - <summary>Choose the display style.</summary> - </key> - <key name="thermal-sensor-file" type="s"> - <default>'/sys/devices/virtual/thermal/thermal_zone0/temp'</default> - <summary>Sensor File</summary> - <description>Location of the sensor file for cpu temp</description> - </key> - <key name="thermal-threshold" type="i"> - <default>0</default> - <summary>Thermal threshold</summary> - <description>When the temprature passes the threshold, the text is set to red as an alert.</description> - </key> - <key name="fan-display" type="b"> - <default>false</default> - <summary>Display fan</summary> - <description>Set to false to remove fan display in status bar</description> - </key> - <key name="fan-refresh-time" type="i"> - <default>5000</default> - <summary>fan refresh time</summary> - <description>Time in ms between 2 refresh of fan</description> - </key> - <key name="fan-graph-width" type="i"> - <default>100</default> - <summary>fan graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="fan-show-text" type="b"> - <default>true</default> - <summary>Display 'fan'</summary> - <description>Set to true to show 'fan' before fan display</description> - </key> - <key name="fan-show-menu" type="b"> - <default>true</default> - <summary>Display Fans In Menu</summary> - <description>Set to true to show fan in pop-up menu</description> - </key> - <key name="fan-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'graph'</default> - <summary>Choose the display style.</summary> - </key> - <key name="fan-sensor-file" type="s"> - <default>'/sys/devices/virtual/thermal/cooling_device0/cur_state'</default> - <summary>Sensor File</summary> - <description>Location of the sensor file for fan</description> - </key> - <key name="fan-fan0-color" type="s"> - <default>'#f2002e'</default> - <summary>Color of fan in the chart</summary> - </key> - <key name="center-display" type="b"> - <default>false</default> - <summary>Display informations next to the clock</summary> - <description>True: Set information at the center, False: Set information in status bar (at top right)</description> - </key> - <key name="move-clock" type="b"> - <default>false</default> - <summary>Move the clock to the right when center-display is true</summary> - <description>True: Move the clock to the right, False: Keep it in center</description> - </key> - <key name="show-tooltip" type="b"> - <default>false</default> - <summary>Enable or disable the tooltip</summary> - <description>True: show tool tip on mouse hover </description> - </key> - <key name="compact-display" type="b"> - <default>false</default> - <summary>Optimize view for small displays</summary> - <description>Optimize texts sizes to fit on a small display </description> - </key> - <key name="memory-program-color" type="s"> - <default>'#00b35b'</default> - <summary>Color of program memory in the chart</summary> - </key> - <key name="memory-buffer-color" type="s"> - <default>'#00ff82'</default> - <summary>Color of buffer memory in the chart</summary> - </key> - <key name="memory-cache-color" type="s"> - <default>'#aaf5d0'</default> - <summary>Color of cache memory in the chart</summary> - </key> - <key name="net-down-color" type="s"> - <default>'#fce94f'</default> - <summary>Color of download speed in the chart</summary> - </key> - <key name="net-up-color" type="s"> - <default>'#fb74fb'</default> - <summary>Color of upload speed in the chart</summary> - </key> - <key name="net-downerrors-color" type="s"> - <default>'#ff6e00'</default> - <summary>Color of download errors</summary> - </key> - <key name="net-uperrors-color" type="s"> - <default>'#e0006e'</default> - <summary>Color of upload errors</summary> - </key> - <key name="net-collisions-color" type="s"> - <default>'#ff0000'</default> - <summary>Color of collisions</summary> - </key> - <key name="cpu-user-color" type="s"> - <default>'#0072b3'</default> - <summary>Color of user cpu in the chart</summary> - </key> - <key name="cpu-system-color" type="s"> - <default>'#0092e6'</default> - <summary>Color of system cpu in the chart</summary> - </key> - <key name="cpu-nice-color" type="s"> - <default>'#00a3ff'</default> - <summary>Color of nice cpu in the chart</summary> - </key> - <key name="cpu-iowait-color" type="s"> - <default>'#002f3d'</default> - <summary>Color of iowait in the chart</summary> - </key> - <key name="cpu-other-color" type="s"> - <default>'#001d26'</default> - <summary>Color of other cpu in the chart</summary> - </key> - <key name="freq-freq-color" type="s"> - <default>'#001d26'</default> - <summary>Color of freq in the chart</summary> - </key> - <key name="swap-used-color" type="s"> - <default>'#8b00c3'</default> - <summary>Color of used swap in the chart</summary> - </key> - <key name="disk-read-color" type="s"> - <default>'#c65000'</default> - <summary>Color of disk reading speed in the chart</summary> - </key> - <key name="disk-write-color" type="s"> - <default>'#ff6700'</default> - <summary>Color of disk writing speed in the chart</summary> - </key> - <key name="gpu-used-color" type="s"> - <default>'#00b35b'</default> - <summary>Color of program GPU usage in the chart</summary> - </key> - <key name="gpu-memory-color" type="s"> - <default>'#00ff82'</default> - <summary>Color of program GPU memory in the chart</summary> - </key> - <key name="thermal-tz0-color" type="s"> - <default>'#f2002e'</default> - <summary>Color of user thermal in the chart</summary> - </key> - <key name="thermal-fahrenheit-unit" type="b"> - <default>false</default> - <summary>Display temperature in Fahrenheit</summary> - <description>Set to true to show temperature in Fahrenheit</description> - </key> - <key name="background" type="s"> - <default>'#ffffff16'</default> - <summary>Color of background</summary> - </key> - <key name="battery-display" type="b"> - <default>false</default> - <summary>Display battery</summary> - <description>Set to false to remove battery display in status bar</description> - </key> - <key name="battery-refresh-time" type="i"> - <default>5000</default> - <summary>thermal refresh time</summary> - <description>Time in ms between 2 refresh of thermal</description> - </key> - <key name="battery-graph-width" type="i"> - <default>100</default> - <summary>thermal graph width</summary> - <description>Graph width in pixel</description> - </key> - <key name="battery-show-text" type="b"> - <default>true</default> - <summary>Display 'batt'</summary> - <description>Set to true to show 'batt' before net display</description> - </key> - <key name="battery-show-menu" type="b"> - <default>false</default> - <summary>Display 'batt'</summary> - <description>Set to true to show battery in pop-up menu</description> - </key> - <key name="battery-style" enum="org.gnome.shell.extensions.system-monitor.display-style"> - <default>'digit'</default> - <summary>Choose the display style.</summary> - </key> - <key name="battery-batt0-color" type="s"> - <default>'#f2002e'</default> - <summary>Color of battery</summary> - </key> - <key name="battery-time" type="b"> - <default>false</default> - <summary>Display battery time remaining rather than percentage</summary> - </key> - <key name="battery-hidesystem" type="b"> - <default>false</default> - <summary>Hide system battery icon</summary> - </key> - - </schema> -</schemalist> diff --git a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css b/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css deleted file mode 100644 index 5f7120e..0000000 --- a/.local/share/gnome-shell/extensions/system-monitor@paradoxxx.zero.gmail.com/stylesheet.css +++ /dev/null @@ -1,204 +0,0 @@ -.sm-title { - font-size: 1em; - padding: 0px 25px 0px 0px; -} - -.sm-label { - color: #bbb; - font-size: 0.75em; - padding-top: 5px; - font-family: monospace; -} - -.sm-label-left { - color: #bbb; - font-size: 0.75em; - padding: 5px 5px 0 0; -} - -.sm-value { - text-align: right; - min-width: 40px; - padding: 2px 5px 0 0; - font-family: monospace; -} - -.sm-status-label { - color: #bbb; - font-size: 0.625em; - padding: 0 2px 0 5px; -} - -.sm-unit-label, -.sm-net-unit-label { - color: #aaa; - font-size: 0.5em; - padding: 0 5px 0 2px; -} - -.sm-disk-unit-label { - color: #aaa; - font-size: 0.625em; - padding: 0 5px 0 2px; -} - -.sm-net-unit-label { - min-width: 25px; -} - -.sm-perc-label { - color: #aaa; - font-size: 0.625em; - padding: 0 5px 0 2px; -} - -.sm-temp-label { - color: #aaa; - font-size: 0.6875em; - padding: 0 5px 0 2px; -} - -.sm-status-value { - min-width: 25px; - text-align: right; -} - -.sm-net-value { - min-width: 40px; - text-align: center; -} - -.sm-disk-value { - min-width: 25px; - text-align: right; -} - -.sm-big-status-value { - min-width: 42px; - text-align: right; -} - -.sm-chart { - padding: 0 2px; -} - -.sm-tooltip-box { - font-size: 0.85em; - font-weight: bold; - color: rgba(255, 255, 255, 0.9); - background-color: rgba(10, 10, 10, 0.7); - border-radius: 5px; - padding: 3px; - border: 1px solid #a5a5a5; -} - -.sm-tooltip-item { - padding: 0px; - spacing: 10px; -} -.sm-status-icon { - padding: 0px 2px; - icon-size: 1.14em; -} - -.sm-popup-menu-item-compact { -} - -/* style definition when 'compact-display' option is activated */ - -.sm-title-compact { - font-size: 0.75em; -} - -.sm-label-compact { - color: #bbb; - font-size: 0.6875em; - font-family: monospace; -} /* Bat, Net... units in menu items */ - -.sm-value-compact { - font-size: 0.6875em; - text-align: right; - font-family: monospace; -} /* Values in menu items */ - -.sm-status-label-compact { - color: #bbb; - font-size: 0.5em; - padding: 2px 0px 0 0px; -} /* names and Disk R and W signs in text items */ - -.sm-unit-label-compact, -.sm-net-unit-label-compact { - color: #aaa; - padding: 0 3px 0px 1px; - text-align: right; - font-size: 0.4375em; -} /* Bat, Net... units in text items */ - -.sm-disk-unit-label-compact { - color: #aaa; - padding: 0 3px 0px 0px; - text-align: right; - font-size: 0.4375em; -} /* Disk units in text items */ - -.sm-perc-label-compact { - padding: 0 3px 0 0px; - color: #aaa; - font-size: 0.5em; -} /* Cpu, Mem ... % sign in text items */ - -.sm-temp-label-compact { - font-size: 0.625em; - color: #aaa; - padding: 0 1px 0 1px; -} /* Thermal °C sign in text items */ - -.sm-status-value-compact { - padding:0 0px 0 1px; - font-size: 0.6875em; - text-align: right; - min-width:16px; -} /* Cpu, Mem... value in text items */ - -.sm-net-value-compact { - padding:0 0px 0 1px; - font-size: 0.6875em; - text-align: right; - min-width:24px; -} /* Net value in text items */ - -.sm-disk-value-compact { - padding: 0 1px 0 1px; - font-size: 0.6875em; - text-align: right; - min-width: 20px; -} /* Disk value in text items */ - -.sm-big-status-value-compact { - padding: 0 0px 0px 1px; - font-size: 0.6875em; - min-width: 38px; - text-align: right; -} /* freq in text_items */ - -.sm-chart-compact { - padding: 0 2px; -} - -.sm-tooltip-item-compact { - padding: 0px; - spacing: 10px; -} - -.sm-status-icon-compact { - padding: 1px 0 0 2px; - icon-size: 1.00em; -} /* BAT icon in text_items */ - -.sm-popup-menu-item-compact { - font-size: 0.6875em; - width: 20px; - padding: 1px 2px 1px 7px; -} diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/AppManager.js b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/AppManager.js deleted file mode 100644 index 283b342..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/AppManager.js +++ /dev/null @@ -1,152 +0,0 @@ -const AppSystem = imports.gi.Shell.AppSystem; -const WindowTracker = imports.gi.Shell.WindowTracker; -const getSettings = imports.misc.extensionUtils.getSettings; -const GLib = imports.gi.GLib; -const Me = imports.misc.extensionUtils.getCurrentExtension(); - -var leftClick = function (icon, event) { - let trayApp = getTrayApp(icon); - if (trayApp) { - let focusedApp = WindowTracker.get_default().focusApp; - let windows = trayApp.get_windows(); - - if (windows == "") { - return openApplication(trayApp, icon, event); - } - - if (focusedApp != null && focusedApp.id == trayApp.id) { - return minimizeWindows(focusedApp.get_windows(), icon, event); - } - - return activateWindows(windows, trayApp, event); - } - - icon.click(event); - - // On Windows double-click restore app - if (isWine(icon)) { - icon.click(event); - } -}; - -var middleClick = function (icon, event) { - // When holding SHIFT - if (event.get_state_full()[1] === 1) { - let trayApp = getTrayApp(icon); - if (trayApp) { - const pid = getPid(icon); - // Kill app - if (isUsingQt(pid)) { - return GLib.spawn_command_line_sync(`/bin/kill ${pid}`); - } - let windows = trayApp.get_windows(); - windows.forEach((window) => { - window.kill(); - }); - trayApp.request_quit(); - } - } else { - icon.click(event); - } -}; - -var getAppSetting = function (icon, setting) { - const iconApp = getTrayApp(icon); - const appsSettings = JSON.parse(getSettings().get_string("applications")); - const appSettings = appsSettings.find((app) => app.id == iconApp.get_id()); - - return appSettings?.[setting]; -}; - -function getTrayApp(icon) { - if (isWine(icon)) { - const wineApps = AppSystem.get_default() - .get_running() - .filter((app) => { - return app.get_windows()[0].wm_class.includes(".exe"); - }); - return wineApps[0]; - } - - const searchedApps = AppSystem.search(getWmClass(icon.wm_class)); - if (searchedApps[0] && searchedApps[0][0]) { - var i = 1; - for (let lookup of searchedApps[0]) { - let app = AppSystem.get_default().lookup_app(lookup); - if (app.get_windows() != "" || i == searchedApps[0].length) { - return app; - } - i++; - } - } - - return false; -} - -function openApplication(trayApp, icon, event) { - const isFlatpak = trayApp.app_info.has_key("X-Flatpak"); - const onBlacklist = Me.metadata["open-blacklist"].includes(icon.wm_class); // Caprine - if (isUsingQt(getPid(icon)) || isFlatpak || onBlacklist) { - return icon.click(event); - } - - return trayApp.open_new_window(0); -} - -function minimizeWindows(windows, icon, event) { - if (isUsingQt(getPid(icon))) { - return icon.click(event); - } - - windows.forEach((window) => { - window.minimize(); - }); -} - -function activateWindows(windows, trayApp, event) { - windows.forEach((window) => { - if (getSettings().get_boolean("invoke-to-workspace")) { - window.change_workspace(global.workspace_manager.get_active_workspace()); - } - trayApp.activate_window(window, event.get_time()); - window.unminimize(); - }); -} - -function isWine(icon) { - if ( - (icon.wm_class == "Wine" || icon.wm_class == "explorer.exe") && - getSettings().get_boolean("wine-behavior") - ) { - return true; - } -} - -function isUsingQt(pid) { - let [ok, out, err, exit] = GLib.spawn_command_line_sync( - `/bin/bash -c 'pmap -p ${pid} | grep Qt'` - ); - if (out.length) { - return true; - } -} - -function getWmClass(wmclass) { - wmclass = wmclass.replace(/[0-9]/g, ""); // skype discord - wmclass = wmclass.replace("Desktop", ""); // telegram - return wmclass; -} - -function getPid(icon) { - const wmclass = getWmClass(icon.wm_class); - if (icon.title != "snixembed") { - return icon.pid; - } - - let [ok, out, err, exit] = GLib.spawn_command_line_sync( - `/bin/bash -c "pidof -s ${wmclass}"` - ); - if (out.length) { - return Number(out); - } -} diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/TrayIndicator.js b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/TrayIndicator.js deleted file mode 100644 index d0ee40f..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/TrayIndicator.js +++ /dev/null @@ -1,192 +0,0 @@ -const { GObject, Clutter, St, GLib } = imports.gi; -const { panelMenu, popupMenu } = imports.ui; -const { getCurrentExtension, getSettings } = imports.misc.extensionUtils; -const AppManager = getCurrentExtension().imports.AppManager; - -var TrayIndicator = GObject.registerClass( - class TrayIndicator extends panelMenu.Button { - _init() { - this._icons = []; - - super._init(0.0, null, false); - this._overflow = false; - - this._indicators = new St.BoxLayout(); - this.add_child(this._indicators); - - this._icon = new St.Icon({ - icon_name: "view-more-horizontal", - style_class: "system-status-icon", - reactive: true, - track_hover: true, - }); - this._indicators.add_child(this._icon); - - this._menuItem = new popupMenu.PopupBaseMenuItem({ - reactive: false, - can_focus: true, - }); - this.menu.addMenuItem(this._menuItem); - this.menu.actor.add_style_class_name("TrayIndicatorPopup"); - this.hide(); - } - - get size() { - const context = St.ThemeContext.get_for_stage(global.stage); - return this._size * context.scale_factor; - } - - setSize(size, margin, padding) { - this._size = size; - this._margin = margin; - this._padding = padding; - - this._icons.forEach((icon) => { - icon.get_parent().style = this._getButtonStyle(); - icon.set_size(this._size, this._size); - }); - } - - addIcon(icon) { - const isHidden = AppManager.getAppSetting(icon, "hidden"); - if (isHidden) return; - - const button = new St.Button({ - child: icon, - button_mask: - St.ButtonMask.ONE | St.ButtonMask.TWO | St.ButtonMask.THREE, - style: this._getButtonStyle(), - style_class: "panel-button", - }); - icon.opacity = 0; - icon.set_x_align(Clutter.ActorAlign.CENTER); - icon.set_y_align(Clutter.ActorAlign.CENTER); - icon.inOverflow = this._overflow; - GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => { - icon.set_size(this.size, this.size); - icon.ease({ - opacity: 255, - duration: 400, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - this._addEffectIcon(icon); - return GLib.SOURCE_REMOVE; - }); - icon.connect("destroy", () => { - button.destroy(); - }); - - button.connect("button-release-event", (actor, event) => { - switch (event.get_button()) { - case 1: - AppManager.leftClick(icon, event); - break; - case 2: - AppManager.middleClick(icon, event); - break; - case 3: - icon.click(event); - break; - } - if (AppManager.isWine(icon)) { - GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1, () => { - this.menu.close(); - return GLib.SOURCE_REMOVE; - }); - } else { - this.menu.close(); - } - }); - - this._icons.push(icon); - - if (this._overflow) { - this._menuItem.actor.add(button); - } else { - this._indicators.insert_child_at_index(button, 0); - } - - this.checkOverflow(); - } - - removeIcon(icon, ignoreCheckOverflow) { - const index = this._icons.indexOf(icon); - this._icons.splice(index, 1); - - const actor = icon.get_parent(); - actor.remove_actor(icon); - actor.destroy(); - - if (!ignoreCheckOverflow) { - this.checkOverflow(); - } - } - - checkOverflow() { - if (this._icons.length >= getSettings().get_int("icons-limit")) { - this._overflow = true; - this._icon.visible = true; - this.reactive = true; - this.style_class = "panel-button TrayIndicator"; - } else { - this._overflow = false; - this._icon.visible = false; - this.reactive = false; - this.style_class = "TrayIndicator"; - } - - if (this._icons.length) { - this.show(); - } else { - this.hide(); - } - - this._refreshIcons(this._overflow); - } - - _refreshIcons(overflow) { - this._icons.forEach((icon) => { - if (icon.inOverflow != overflow) { - this.removeIcon(icon, true); - this.addIcon(icon); - } - }); - } - - _getButtonStyle() { - let style; - if (!this._overflow) { - style = `margin: ${this._margin.vertical}px ${this._margin.horizontal}px; padding: ${this._padding.vertical}px ${this._padding.horizontal}px`; - } - return `width: ${this.size}px; height: ${this.size}px;${style}`; - } - - _addEffectIcon(icon) { - let brightnessContrast = new Clutter.BrightnessContrastEffect({}); - brightnessContrast.set_contrast( - getSettings().get_int("icon-contrast") / 100 - ); - brightnessContrast.set_brightness( - getSettings().get_int("icon-brightness") / 100 - ); - icon.add_effect_with_name("brightnessContrast", brightnessContrast); - icon.add_effect_with_name( - "desaturate", - new Clutter.DesaturateEffect({ - factor: getSettings().get_int("icon-saturation") / 100, - }) - ); - } - - setEffect(contrast, saturation, brightness) { - this._icons.forEach((icon) => { - let brightnessContrast = icon.get_effect("brightnessContrast"); - brightnessContrast.set_contrast(contrast / 100); - brightnessContrast.set_brightness(brightness / 100); - - let desaturate = icon.get_effect("desaturate"); - desaturate.set_factor(saturation / 100); - }); - } - } -); diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/extension.js b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/extension.js deleted file mode 100644 index 178041f..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/extension.js +++ /dev/null @@ -1,97 +0,0 @@ -const { GObject, Shell } = imports.gi; -const { getCurrentExtension, getSettings } = imports.misc.extensionUtils; -const System = imports.system; -const Main = imports.ui.main; -const TrayIndicator = getCurrentExtension().imports.TrayIndicator; - -var TrayIconsClass = GObject.registerClass( -class TrayIconsClass extends GObject.Object { - _init() { - this.tray = new Shell.TrayManager(); - this.indicators = new TrayIndicator.TrayIndicator(); - - this.tray.connect('tray-icon-added', this._onIconAdded.bind(this)); - this.tray.connect('tray-icon-removed', this._onIconRemoved.bind(this)); - - this.tray.manage_screen(Main.panel); - } - - _onIconAdded(trayManager, icon) { this.indicators.addIcon(icon); } - _onIconRemoved(trayManager, icon) { this.indicators.removeIcon(icon); } - - _destroy() { - this.tray = null; - - this.indicators.destroy(); - System.gc(); - } -}); - -let TrayIcons; - -class Extension { - _setIconSize() { - const margin = { vertical: this._settings.get_int('icon-margin-vertical'), horizontal: this._settings.get_int('icon-margin-horizontal') } - const padding = { vertical: this._settings.get_int('icon-padding-vertical'), horizontal: this._settings.get_int('icon-padding-horizontal') } - TrayIcons.indicators.setSize(this._settings.get_int('icon-size'), margin, padding); - } - - _setTrayMargin() { - TrayIcons.indicators.set_style('margin-left: ' + this._settings.get_int('tray-margin-left') + 'px; margin-right: ' + this._settings.get_int('tray-margin-right') + 'px'); - } - - _setTrayArea() { - Main.panel.statusArea['TrayIconsReloaded'] = null; - Main.panel.addToStatusArea('TrayIconsReloaded', TrayIcons.indicators, this._settings.get_int('position-weight'), this._settings.get_string('tray-position')); - } - - _setIconsLimit() { - TrayIcons.indicators.checkOverflow(); - } - - _setIconEffect() { - TrayIcons.indicators.setEffect(this._settings.get_int('icon-contrast'), this._settings.get_int('icon-saturation'), this._settings.get_int('icon-brightness')); - } - - _onChange() { - this._settings.connect('changed::tray-position', this._setTrayArea.bind(this)); - this._settings.connect('changed::position-weight', this._setTrayArea.bind(this)); - this._settings.connect('changed::tray-margin-left', this._setTrayMargin.bind(this)); - this._settings.connect('changed::tray-margin-right', this._setTrayMargin.bind(this)); - this._settings.connect('changed::icon-size', this._setIconSize.bind(this)); - this._settings.connect('changed::icon-margin-horizontal', this._setIconSize.bind(this)); - this._settings.connect('changed::icon-margin-vertical', this._setIconSize.bind(this)); - this._settings.connect('changed::icon-padding-vertical', this._setIconSize.bind(this)); - this._settings.connect('changed::icon-padding-horizontal', this._setIconSize.bind(this)); - this._settings.connect('changed::icons-limit', this._setIconsLimit.bind()); - this._settings.connect('changed::icon-saturation', this._setIconEffect.bind(this)); - this._settings.connect('changed::icon-contrast', this._setIconEffect.bind(this)); - this._settings.connect('changed::icon-brightness', this._setIconEffect.bind(this)); - } - - enable() { - TrayIcons = new TrayIconsClass(); - this._settings = getSettings(); - this._setTrayMargin(); - this._setIconSize(); - this._onChange(); - - if (Main.layoutManager._startingUp) { - this._startupComplete = Main.layoutManager.connect('startup-complete', () => { - this._setTrayArea(); - Main.layoutManager.disconnect(this._startupComplete); - }); - } else { - this._setTrayArea(); - } - } - - disable() { - TrayIcons._destroy(); - this._settings.run_dispose(); - } -} - -function init() { - return new Extension(); -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/metadata.json b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/metadata.json deleted file mode 100644 index ec8068a..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/metadata.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Tray Icons Reloaded is a GNOME Shell extension which bring back Tray Icons to top panel, with additional features.\n\n>>> Read compatibility note on GitHub there is also bug reporting <<<", - "name": "Tray Icons: Reloaded", - "open-blacklist": [ - "Electron", - "Yad" - ], - "settings-schema": "org.gnome.shell.extensions.trayIconsReloaded", - "shell-version": [ - "41" - ], - "url": "https://github.com/MartinPL/Tray-Icons-Reloaded", - "uuid": "trayIconsReloaded@selfmade.pl", - "version": 19 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/AppChooser.js b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/AppChooser.js deleted file mode 100644 index f81423e..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/AppChooser.js +++ /dev/null @@ -1,56 +0,0 @@ -const { GObject, Gtk } = imports.gi; -const ExtensionUtils = imports.misc.extensionUtils; -const getSettings = ExtensionUtils.getSettings; - -var AppChooser = GObject.registerClass( - class AppChooser extends Gtk.AppChooserDialog { - _init(parent) { - super._init({ - transient_for: parent, - modal: true, - }); - - this._widget = this.get_widget(); - this._widget.set({ - show_all: true, - show_other: true, - }); - this._widget.connect( - "application-selected", - this._updateSensitivity.bind(this) - ); - - this.connect("response", this._onResponse.bind(this)); - this._updateSensitivity(); - } - - _updateSensitivity() { - const apps = JSON.parse(getSettings().get_string("applications")); - const appInfo = this._widget.get_app_info(); - - this.set_response_sensitive( - Gtk.ResponseType.OK, - appInfo && !apps.some((app) => app.id.startsWith(appInfo.get_id())) - ); - } - - _onResponse(dlg, id) { - const appInfo = - id === Gtk.ResponseType.OK ? this._widget.get_app_info() : null; - - if (appInfo) { - let apps = JSON.parse(getSettings().get_string("applications")); - apps = [ - ...apps, - { - id: appInfo.get_id(), - }, - ]; - - getSettings().set_string("applications", JSON.stringify(apps)); - } - - this.destroy(); - } - } -); diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/AppRow.js b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/AppRow.js deleted file mode 100644 index 2b2b538..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/AppRow.js +++ /dev/null @@ -1,54 +0,0 @@ -const { GObject, Gtk, Gio } = imports.gi; -const ExtensionUtils = imports.misc.extensionUtils; -const getSettings = ExtensionUtils.getSettings; -const Me = ExtensionUtils.getCurrentExtension(); - -var AppRow = GObject.registerClass( - { - GTypeName: "AppRow", - Template: Me.dir.get_child("preferences/AppRow.xml").get_uri(), - InternalChildren: ["icon", "label", "revealButton", "revealer", "hidden"], - }, - class AppRow extends Gtk.ListBoxRow { - _init(app) { - super._init(); - this._appInfo = Gio.DesktopAppInfo.new(app.id); - this._settings = getSettings(); - this._icon.gicon = this._appInfo.get_icon(); - this._label.label = this._appInfo.get_display_name(); - this._hidden.set_active(app.hidden); - this._hidden.connect("state-set", () => { - this._updateApp(); - }); - this.appId = this._appInfo.get_id(); - } - - toggleSettingsVisibility() { - this._revealer.reveal_child = !this._revealer.reveal_child; - - if (this._revealer.reveal_child) { - this._revealButton.get_style_context().add_class("expanded"); - } else { - this._revealButton.get_style_context().remove_class("expanded"); - } - } - - removeRow() { - const current = JSON.parse(this._settings.get_string("applications")); - const updated = current.filter((app) => app.id !== this.appId); - - this._settings.set_string("applications", JSON.stringify(updated)); - } - - _updateApp() { - let apps = JSON.parse(this._settings.get_string("applications")); - const index = apps.findIndex((app) => app.id == this.appId); - apps[index] = { - id: this.appId, - hidden: this._hidden.get_active(), - }; - - this._settings.set_string("applications", JSON.stringify(apps)); - } - } -); diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/AppRow.xml b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/AppRow.xml deleted file mode 100644 index d171f7b..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/AppRow.xml +++ /dev/null @@ -1,92 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <template class="AppRow" parent="GtkListBoxRow"> - <property name="selectable">false</property> - <property name="activatable">false</property> - <child> - <object class="GtkGrid"> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <property name="margin-top">12</property> - <property name="margin-bottom">12</property> - <property name="column-spacing">12</property> - <child> - <object class="GtkImage" id="icon"> - <property name="pixel-size">32</property> - </object> - </child> - <child> - <object class="GtkLabel" id="label"> - <property name="halign">start</property> - <property name="hexpand">true</property> - </object> - </child> - <child> - <object class="GtkButton" id="remove-button"> - <property name="tooltip-text" translatable="yes">Remove</property> - <property name="halign">center</property> - <property name="valign">center</property> - <signal name="clicked" handler="removeRow" swapped="no" /> - <child> - <object class="GtkImage"> - <property name="icon-name">user-trash-symbolic</property> - </object> - </child> - </object> - </child> - <child> - <object class="GtkSeparator"/> - </child> - <child> - <object class="GtkButton" id="revealButton"> - <property name="valign">center</property> - <property name="has-frame">false</property> - <property name="icon-name">pan-end-symbolic</property> - <signal name="clicked" handler="toggleSettingsVisibility" swapped="no" /> - <style> - <class name="reveal-button"/> - </style> - </object> - </child> - <child> - <object class="GtkRevealer" id="revealer"> - <child> - <object class="GtkListBox"> - <property name="margin-top">8</property> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">false</property> - <property name="activatable">false</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Hidden</property> - <property name="halign">start</property> - <property name="hexpand">true</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="hidden"> - <property name="halign">end</property> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - </child> - <layout> - <property name="column">0</property> - <property name="row">1</property> - <property name="column-span">5</property> - </layout> - </object> - </child> - </object> - </child> - </template> -</interface> \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/Prefs.css b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/Prefs.css deleted file mode 100644 index 6f12772..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/Prefs.css +++ /dev/null @@ -1,6 +0,0 @@ -.reveal-button image { - transition: 250ms; -} -.reveal-button--expanded image { - -gtk-icon-transform: rotate(0.25turn); -} diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/Prefs.js b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/Prefs.js deleted file mode 100644 index 07c2a9f..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/Prefs.js +++ /dev/null @@ -1,124 +0,0 @@ -const { GObject, Gtk, Gio, Gdk } = imports.gi; -const ExtensionUtils = imports.misc.extensionUtils; -const getSettings = ExtensionUtils.getSettings; -const Me = ExtensionUtils.getCurrentExtension(); -const AppRow = Me.imports.preferences.AppRow.AppRow; -const AppChooser = Me.imports.preferences.AppChooser.AppChooser; - -const schemaNames = [ - "tray-position", - "position-weight", - "tray-margin-left", - "tray-margin-right", - "icons-limit", - "icon-size", - "icon-margin-vertical", - "icon-margin-horizontal", - "icon-padding-vertical", - "icon-padding-horizontal", - "icon-saturation", - "icon-contrast", - "icon-brightness", - "invoke-to-workspace", - "wine-behavior", -]; - -const settingIds = schemaNames.map(function (name) { - return name.replaceAll("-", "_"); -}); - -var Prefs = GObject.registerClass( - { - GTypeName: "Prefs", - Template: Me.dir.get_child("preferences/Prefs.xml").get_uri(), - InternalChildren: ["headerBar", "appList", ...settingIds], - }, - class Prefs extends Gtk.Box { - _init(params = {}) { - super._init(params); - - this._bindSettings(schemaNames); - - this.connect("realize", () => { - const window = this.get_root(); - window.set_titlebar(this._headerBar); - }); - - let provider = new Gtk.CssProvider(); - provider.load_from_file( - Gio.File.new_for_uri( - Me.dir.get_child("preferences/Prefs.css").get_uri() - ) - ); - Gtk.StyleContext.add_provider_for_display( - Gdk.Display.get_default(), - provider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ); - - this._settings = getSettings(); - - this._changeId = this._settings.connect( - "changed::applications", - this._syncAppsRows.bind(this) - ); - - this._syncAppsRows(); - } - - showAppChooser() { - const dialog = new AppChooser(this.get_root()); - dialog.show(); - } - - _syncAppsRows() { - this._settings.block_signal_handler(this._changeId); - - const oldApps = [...this._appList].filter((row) => !!row.appId); - const newApps = JSON.parse( - this._settings.get_string("applications") - ).filter((app) => !!app); - - newApps.forEach((appInfo, index) => { - if (!oldApps.some((row) => row.appId == appInfo.id)) { - const appRow = new AppRow(appInfo); - this._appList.insert(appRow, index); - - if (this._notFirstSync) { - appRow.toggleSettingsVisibility(); - } - } - }); - - oldApps.forEach((row, index) => { - if (!newApps.some((app) => row.appId == app.id)) { - this._appList.remove(row); - } - }); - - this._notFirstSync = true; - - this._settings.unblock_signal_handler(this._changeId); - } - - _bindSettings(settings) { - settings.forEach((name) => { - let obj = eval("this._" + name.replaceAll("-", "_")); - let valueType; - - switch (obj.css_name) { - case "combobox": - valueType = "active-id"; - break; - case "switch": - valueType = "active"; - break; - default: - valueType = "value"; - } - - getSettings().bind(name, obj, valueType, Gio.SettingsBindFlags.DEFAULT); - }); - } - } -); diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/Prefs.xml b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/Prefs.xml deleted file mode 100644 index 28db0fa..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/preferences/Prefs.xml +++ /dev/null @@ -1,566 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<interface> - <object class="GtkHeaderBar" id="headerBar"> - <property name="title-widget"> - <object class="GtkStackSwitcher"> - <property name="stack">stack</property> - </object> - </property> - </object> - <template class="Prefs" parent="GtkBox"> - <property name="orientation">vertical</property> - <child> - <object class="GtkStack" id="stack"> - <property name="transition-type">slide-left-right</property> - <child> - <object class="GtkStackPage"> - <property name="title">General</property> - <property name="child"> - <object class="GtkScrolledWindow"> - <property name="vscrollbar-policy">never</property> - <property name="hscrollbar-policy">never</property> - <child> - <object class="GtkBox"> - <property name="orientation">vertical</property> - <property name="valign">start</property> - <property name="halign">center</property> - <property name="width-request">630</property> - <property name="margin-top">24</property> - <property name="margin-bottom">24</property> - <property name="margin-start">24</property> - <property name="margin-end">24</property> - <child> - <object class="GtkFrame"> - <property name="child"> - <object class="GtkListBox"> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <property name="spacing">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Tray position</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkComboBoxText" id="tray_position"> - <property name="halign">end</property> - <items> - <item translatable="yes" id="left">Left</item> - <item translatable="yes" id="center">Center</item> - <item translatable="yes" id="right">Right</item> - </items> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-position-weight"> - <property name="step-increment">1</property> - <property name="lower">-99</property> - <property name="upper">99</property> - </object> - <object class="GtkSpinButton" id="position_weight"> - <property name="tooltip-text" translatable="yes">Position weight</property> - <property name="halign">end</property> - <property name="adjustment">adjustment-position-weight</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Tray icons limit</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-icons-limit"> - <property name="step-increment">1</property> - <property name="lower">1</property> - <property name="upper">16</property> - </object> - <object class="GtkSpinButton" id="icons_limit"> - <property name="halign">end</property> - <property name="adjustment">adjustment-icons-limit</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Icon size</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-icon-size"> - <property name="step-increment">1</property> - <property name="lower">16</property> - <property name="upper">32</property> - </object> - <object class="GtkSpinButton" id="icon_size"> - <property name="halign">end</property> - <property name="adjustment">adjustment-icon-size</property> - </object> - </child> - </object> - </property> - </object> - </child> - - </object> - </property> - </object> - </child> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Colors</property> - <property name="halign">start</property> - <property name="margin-top">24</property> - <property name="margin-bottom">8</property> - <attributes> - <attribute name="weight" value="bold"></attribute> - </attributes> - </object> - </child> - <child> - <object class="GtkFrame"> - <property name="child"> - <object class="GtkListBox"> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Icon saturation</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-icon-saturation"> - <property name="step-increment">10</property> - <property name="page-size">20</property> - <property name="upper">100</property> - </object> - <object class="GtkSpinButton" id="icon_saturation"> - <property name="halign">end</property> - <property name="adjustment">adjustment-icon-saturation</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Icon contrast</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-icon-contrast"> - <property name="step-increment">10</property> - <property name="page-size">20</property> - <property name="lower">-100</property> - <property name="upper">100</property> - </object> - <object class="GtkSpinButton" id="icon_contrast"> - <property name="halign">end</property> - <property name="adjustment">adjustment-icon-contrast</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Icon brightness</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-icon-brightness"> - <property name="step-increment">10</property> - <property name="page-size">20</property> - <property name="lower">-100</property> - <property name="upper">100</property> - </object> - <object class="GtkSpinButton" id="icon_brightness"> - <property name="halign">end</property> - <property name="adjustment">adjustment-icon-brightness</property> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Spacing</property> - <property name="halign">start</property> - <property name="margin-top">24</property> - <property name="margin-bottom">8</property> - <attributes> - <attribute name="weight" value="bold"></attribute> - </attributes> - </object> - </child> - <child> - <object class="GtkFrame"> - <property name="child"> - <object class="GtkListBox"> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <property name="spacing">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Tray margin</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-tray-margin-left"> - <property name="step-increment">1</property> - <property name="upper">24</property> - </object> - <object class="GtkSpinButton" id="tray_margin_left"> - <property name="halign">center</property> - <property name="adjustment">adjustment-tray-margin-left</property> - <property name="tooltip-text" translatable="yes">Left margin</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-tray-margin-right"> - <property name="step-increment">1</property> - <property name="upper">24</property> - </object> - <object class="GtkSpinButton" id="tray_margin_right"> - <property name="halign">end</property> - <property name="adjustment">adjustment-tray-margin-right</property> - <property name="tooltip-text" translatable="yes">Right margin</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <property name="spacing">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Icon margin</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-icon-margin-vertical"> - <property name="step-increment">1</property> - <property name="upper">24</property> - </object> - <object class="GtkSpinButton" id="icon_margin_vertical"> - <property name="halign">center</property> - <property name="adjustment">adjustment-icon-margin-vertical</property> - <property name="tooltip-text" translatable="yes">Vertical icon margin. NOTE: May not update in real time</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-icon-margin-horizontal"> - <property name="step-increment">1</property> - <property name="upper">24</property> - </object> - <object class="GtkSpinButton" id="icon_margin_horizontal"> - <property name="halign">end</property> - <property name="adjustment">adjustment-icon-margin-horizontal</property> - <property name="tooltip-text" translatable="yes">Horizontal icon margin</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <property name="spacing">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Icon padding</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-icon-padding-vertical"> - <property name="step-increment">1</property> - <property name="upper">24</property> - </object> - <object class="GtkSpinButton" id="icon_padding_vertical"> - <property name="valign">center</property> - <property name="halign">center</property> - <property name="adjustment">adjustment-icon-padding-vertical</property> - <property name="tooltip-text" translatable="yes">Vertical icon padding</property> - </object> - </child> - <child> - <object class="GtkAdjustment" id="adjustment-icon-padding-horizontal"> - <property name="step-increment">1</property> - <property name="upper">24</property> - </object> - <object class="GtkSpinButton" id="icon_padding_horizontal"> - <property name="tooltip-text" translatable="yes">Horizontal icon padding</property> - <property name="valign">center</property> - <property name="halign">end</property> - <property name="adjustment">adjustment-icon-padding-horizontal</property> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Behavior</property> - <property name="halign">start</property> - <property name="margin-top">24</property> - <property name="margin-bottom">8</property> - <attributes> - <attribute name="weight" value="bold"></attribute> - </attributes> - </object> - </child> - <child> - <object class="GtkFrame"> - <property name="child"> - <object class="GtkListBox"> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Invoke windows to current workspace</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="invoke_to_workspace"> - <property name="halign">end</property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkListBoxRow"> - <property name="selectable">0</property> - <property name="child"> - <object class="GtkBox"> - <property name="margin-top">8</property> - <property name="margin-bottom">8</property> - <property name="margin-start">12</property> - <property name="margin-end">12</property> - <child> - <object class="GtkLabel"> - <property name="label" translatable="yes">Modify Wine apps behavior</property> - <property name="halign">start</property> - <property name="hexpand">1</property> - </object> - </child> - <child> - <object class="GtkSwitch" id="wine_behavior"> - <property name="halign">end</property> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkGrid"> - <property name="margin-top">16</property> - <property name="valign">start</property> - <property name="halign">center</property> - <child> - <object class="GtkLinkButton"> - <property name="label">GitHub</property> - <property name="uri">https://github.com/MartinPL/Tray-Icons-Reloaded</property> - <property name="halign">start</property> - <layout> - <property name="row">0</property> - <property name="column">1</property> - </layout> - </object> - </child> - <child> - <object class="GtkLinkButton"> - <property name="label">Donate</property> - <property name="uri">https://revolut.me/martinpl</property> - <property name="halign">end</property> - <layout> - <property name="row">0</property> - <property name="column">2</property> - </layout> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - </property> - </object> - </child> - <child> - <object class="GtkStackPage"> - <property name="title">Applications</property> - <property name="child"> - <object class="GtkScrolledWindow"> - <property name="propagate-natural-height">1</property> - <property name="hscrollbar-policy">never</property> - <child> - <object class="GtkBox"> - <property name="orientation">vertical</property> - <property name="valign">start</property> - <property name="halign">center</property> - <property name="width-request">630</property> - <property name="margin-top">24</property> - <property name="margin-bottom">24</property> - <property name="margin-start">24</property> - <property name="margin-end">24</property> - <child> - <object class="GtkFrame"> - <property name="child"> - <object class="GtkListBox" id="appList"> - <child> - <object class="GtkListBoxRow"> - <property name="height-request">50</property> - <property name="selectable">false</property> - <property name="activatable">false</property> - <child> - <object class="GtkButton"> - <property name="receives_default">True</property> - <signal name="clicked" handler="showAppChooser" swapped="no" /> - <child> - <object class="GtkImage" id="add-button"> - <property name="icon-name">list-add-symbolic</property> - </object> - </child> - </object> - </child> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - </child> - </object> - </property> - </object> - </child> - </object> - </child> - </template> -</interface> \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/prefs.js b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/prefs.js deleted file mode 100644 index f50b12d..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/prefs.js +++ /dev/null @@ -1,8 +0,0 @@ -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Prefs = Me.imports.preferences.Prefs.Prefs; - -function buildPrefsWidget() { - return new Prefs(); -} - -function init() {} diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/schemas/gschemas.compiled b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/schemas/gschemas.compiled deleted file mode 100644 index 76d175d..0000000 Binary files a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/schemas/gschemas.compiled and /dev/null differ diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/schemas/org.gnome.shell.extensions.trayIconsReloaded.gschema.xml b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/schemas/org.gnome.shell.extensions.trayIconsReloaded.gschema.xml deleted file mode 100644 index 30af6a7..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/schemas/org.gnome.shell.extensions.trayIconsReloaded.gschema.xml +++ /dev/null @@ -1,68 +0,0 @@ -<schemalist> - <schema id="org.gnome.shell.extensions.trayIconsReloaded" path="/org/gnome/shell/extensions/trayIconsReloaded/"> - <key name="tray-position" type="s"> - <default>"right"</default> - <summary>Tray position</summary> - </key> - <key name="position-weight" type="i"> - <default>0</default> - <summary>Position weight</summary> - </key> - <key name="tray-margin-left" type="i"> - <default>4</default> - <summary>Tray icons left margin</summary> - </key> - <key name="tray-margin-right" type="i"> - <default>0</default> - <summary>Tray icons left margin</summary> - </key> - <key name="icons-limit" type="i"> - <default>4</default> - <summary>Icons limit</summary> - </key> - <key name="icon-size" type="i"> - <default>20</default> - <summary>Icon size</summary> - </key> - <key name="icon-margin-vertical" type="i"> - <default>0</default> - <summary>Icon margin vertical</summary> - </key> - <key name="icon-margin-horizontal" type="i"> - <default>4</default> - <summary>Icon margin horizontal</summary> - </key> - <key name="icon-padding-vertical" type="i"> - <default>0</default> - <summary>Icon padding vertical</summary> - </key> - <key name="icon-padding-horizontal" type="i"> - <default>16</default> - <summary>Icon padding horizontal</summary> - </key> - <key name="icon-saturation" type="i"> - <default>0</default> - <summary>Icon contrast</summary> - </key> - <key name="icon-contrast" type="i"> - <default>0</default> - <summary>Icon contrast</summary> - </key> - <key name="icon-brightness" type="i"> - <default>0</default> - <summary>Icon contrast</summary> - </key> - <key name="invoke-to-workspace" type="b"> - <default>true</default> - <summary>Whether to invoke window to current workspace</summary> - </key> - <key name="wine-behavior" type="b"> - <default>true</default> - <summary>Wine behavior</summary> - </key> - <key name="applications" type="s"> - <default>"[]"</default> - <summary>Applications list</summary> - </key> - </schema> -</schemalist> \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/stylesheet.css b/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/stylesheet.css deleted file mode 100644 index 40a92b3..0000000 --- a/.local/share/gnome-shell/extensions/trayIconsReloaded@selfmade.pl/stylesheet.css +++ /dev/null @@ -1,11 +0,0 @@ -.TrayIndicatorPopup StButton { - padding: 8px; - border-radius: 6px; - transition-property: background-color; - transition-duration: 0.1s; - transition-timing-function: linear; -} - -.TrayIndicatorPopup StButton:hover { - background-color: rgba(255, 255, 255, 0.1); -} diff --git a/.local/share/gnome-shell/extensions/workspaces-bar@fthx/README.md b/.local/share/gnome-shell/extensions/workspaces-bar@fthx/README.md deleted file mode 100644 index 6589088..0000000 --- a/.local/share/gnome-shell/extensions/workspaces-bar@fthx/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# workspaces-bar -GNOME Shell extension that shows workspaces buttons in top panel - -https://extensions.gnome.org/extension/3851/workspaces-bar/ diff --git a/.local/share/gnome-shell/extensions/workspaces-bar@fthx/extension.js b/.local/share/gnome-shell/extensions/workspaces-bar@fthx/extension.js deleted file mode 100644 index 1cb31c7..0000000 --- a/.local/share/gnome-shell/extensions/workspaces-bar@fthx/extension.js +++ /dev/null @@ -1,146 +0,0 @@ -/* - Workspaces Bar - Copyright Francois Thirioux 2021 - GitHub contributors: @fthx - License GPL v3 -*/ - - -const { Clutter, Gio, GObject, Shell, St } = imports.gi; - -const Main = imports.ui.main; -const PanelMenu = imports.ui.panelMenu; - -var WORKSPACES_SCHEMA = "org.gnome.desktop.wm.preferences"; -var WORKSPACES_KEY = "workspace-names"; - - -var WorkspacesBar = GObject.registerClass( -class WorkspacesBar extends PanelMenu.Button { - _init() { - super._init(0.0, 'Workspaces bar'); - - // define gsettings schema for workspaces names, get workspaces names, signal for settings key changed - this.workspaces_settings = new Gio.Settings({ schema: WORKSPACES_SCHEMA }); - this.workspaces_names_changed = this.workspaces_settings.connect(`changed::${WORKSPACES_KEY}`, this._update_workspaces_names.bind(this)); - - // hide Activities button - this._show_activities(false); - - // bar creation - this.ws_bar = new St.BoxLayout({}); - this._update_workspaces_names(); - this.add_child(this.ws_bar); - - // signals for workspaces state: active workspace, number of workspaces - this._ws_active_changed = global.workspace_manager.connect('active-workspace-changed', this._update_ws.bind(this)); - this._ws_number_changed = global.workspace_manager.connect('notify::n-workspaces', this._update_ws.bind(this)); - this._restacked = global.display.connect('restacked', this._update_ws.bind(this)); - this._windows_changed = Shell.WindowTracker.get_default().connect('tracked-windows-changed', this._update_ws.bind(this)); - } - - // remove signals, restore Activities button, destroy workspaces bar - _destroy() { - this._show_activities(true); - if (this._ws_active_changed) { - global.workspace_manager.disconnect(this._ws_active_changed); - } - if (this._ws_number_changed) { - global.workspace_manager.disconnect(this._ws_number_changed); - } - if (this._restacked) { - global.display.disconnect(this._restacked); - } - if (this._windows_changed) { - Shell.WindowTracker.get_default().disconnect(this._windows_changed); - } - if (this.workspaces_names_changed) { - this.workspaces_settings.disconnect(this.workspaces_names_changed); - } - this.ws_bar.destroy(); - super.destroy(); - } - - // hide Activities button - _show_activities(show) { - this.activities_button = Main.panel.statusArea['activities']; - if (this.activities_button) { - if (show && !Main.sessionMode.isLocked) { - this.activities_button.container.show(); - } else { - this.activities_button.container.hide(); - } - } - } - - // update workspaces names - _update_workspaces_names() { - this.workspaces_names = this.workspaces_settings.get_strv(WORKSPACES_KEY); - this._update_ws(); - } - - // update the workspaces bar - _update_ws() { - // destroy old workspaces bar buttons - this.ws_bar.destroy_all_children(); - - // get number of workspaces - this.ws_count = global.workspace_manager.get_n_workspaces(); - this.active_ws_index = global.workspace_manager.get_active_workspace_index(); - - // display all current workspaces buttons - for (let ws_index = 0; ws_index < this.ws_count; ++ws_index) { - this.ws_box = new St.Bin({visible: true, reactive: true, can_focus: true, track_hover: true}); - this.ws_box.label = new St.Label({y_align: Clutter.ActorAlign.CENTER}); - if (ws_index == this.active_ws_index) { - if (global.workspace_manager.get_workspace_by_index(ws_index).n_windows > 0) { - this.ws_box.label.style_class = 'desktop-label-nonempty-active'; - } else { - this.ws_box.label.style_class = 'desktop-label-empty-active'; - } - } else { - if (global.workspace_manager.get_workspace_by_index(ws_index).n_windows > 0) { - this.ws_box.label.style_class = 'desktop-label-nonempty-inactive'; - } else { - this.ws_box.label.style_class = 'desktop-label-empty-inactive'; - } - } - if (this.workspaces_names[ws_index]) { - this.ws_box.label.set_text(" " + this.workspaces_names[ws_index] + " "); - } else { - this.ws_box.label.set_text(" " + (ws_index + 1) + " "); - } - this.ws_box.set_child(this.ws_box.label); - this.ws_box.connect('button-release-event', () => this._toggle_ws(ws_index) ); - this.ws_bar.add_actor(this.ws_box); - } - } - - // activate workspace or show overview - _toggle_ws(ws_index) { - if (global.workspace_manager.get_active_workspace_index() == ws_index) { - Main.overview.toggle(); - } else { - global.workspace_manager.get_workspace_by_index(ws_index).activate(global.get_current_time()); - } - } -}); - -class Extension { - constructor() { - } - - enable() { - this.workspaces_bar = new WorkspacesBar(); - Main.panel.addToStatusArea('workspaces-bar', this.workspaces_bar, 0, 'left'); - } - - disable() { - this.workspaces_bar._destroy(); - } -} - -function init() { - return new Extension(); -} - diff --git a/.local/share/gnome-shell/extensions/workspaces-bar@fthx/metadata.json b/.local/share/gnome-shell/extensions/workspaces-bar@fthx/metadata.json deleted file mode 100644 index 44e6a8c..0000000 --- a/.local/share/gnome-shell/extensions/workspaces-bar@fthx/metadata.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "_generated": "Generated by SweetTooth, do not edit", - "description": "Replace 'Activities' button by all current workspaces buttons. Switch workspace or toggle overview by clicking on these buttons.\n\n You can use names for workspaces: there are two ways for that. 1) Edit the string array 'org.gnome.desktop.wm.preferences.workspace-names' gsettings key (through dconf editor, e.g.). 2) Use official GNOME extension Workspaces Indicator's settings. You don't have to write a long enough list: numbers are displayed if no workspace name is defined.", - "name": "Workspaces Bar", - "shell-version": [ - "3.36", - "3.38", - "40", - "41" - ], - "url": "https://github.com/fthx/workspaces-bar", - "uuid": "workspaces-bar@fthx", - "version": 12 -} \ No newline at end of file diff --git a/.local/share/gnome-shell/extensions/workspaces-bar@fthx/stylesheet.css b/.local/share/gnome-shell/extensions/workspaces-bar@fthx/stylesheet.css deleted file mode 100644 index 1e0a55a..0000000 --- a/.local/share/gnome-shell/extensions/workspaces-bar@fthx/stylesheet.css +++ /dev/null @@ -1,67 +0,0 @@ -/* framed version */ - -/*.desktop-label-nonempty-active { - margin-left: 0px; - margin-right: 8px; - background-color: rgba(128, 128, 128, 0.7); - color: rgba(207, 207, 207, 1); - border: 1px solid rgba(207, 207, 207, 0.7); - border-radius: 4px; -} - -.desktop-label-nonempty-inactive { - margin-left: 0px; - margin-right: 8px; - background-color: rgba(76, 76, 76, 0.7); - color: rgba(207, 207, 207, 0.7); - border: 1px solid rgba(207, 207, 207, 0.7); - border-radius: 4px; -} - -.desktop-label-empty-active { - margin-left: 0px; - margin-right: 8px; - background-color: rgba(128, 128, 128, 0.7); - color: rgba(207, 207, 207, 1); - border: 1px solid rgba(207, 207, 207, 0); - border-radius: 4px; -} - -.desktop-label-empty-inactive { - margin-left: 0px; - margin-right: 8px; - background-color: rgba(76, 76, 76, 0.7); - color: rgba(207, 207, 207, 0.7); - border: 1px solid rgba(207, 207, 207, 0); - border-radius: 4px; -}*/ - -/* non-framed version */ - -.desktop-label-nonempty-active { - margin-left: 0px; - margin-right: 8px; - background-color: rgba(154, 154, 154, 0.7); - border-radius: 4px; -} - -.desktop-label-nonempty-inactive { - margin-left: 0px; - margin-right: 8px; - background-color: rgba(96, 96, 96, 0.7); - border-radius: 4px; -} - -.desktop-label-empty-active { - margin-left: 0px; - margin-right: 8px; - background-color: rgba(154, 154, 154, 0.7); - border-radius: 4px; -} - -.desktop-label-empty-inactive { - margin-left: 0px; - margin-right: 8px; - background-color: rgba(0, 0, 0, 0.0); - border-radius: 4px; -} diff --git a/.osx b/.osx index f027ef3..8669fcf 100755 --- a/.osx +++ b/.osx @@ -37,6 +37,61 @@ fi # General UI/UX # ############################################################################### +if [[ $RUN_AS_ROOT ]]; then + # Set computer name (as done via System Preferences → Sharing) + sudo scutil --set ComputerName "Charles III" + sudo scutil --set HostName "Charles III" + sudo scutil --set LocalHostName "Charles III" + sudo defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server NetBIOSName -string "Charles III" + + # Reveal IP address, hostname, OS version, etc. when clicking the clock + # in the login window + sudo defaults write /Library/Preferences/com.apple.loginwindow AdminHostInfo HostName + + # Set a custom wallpaper image. `DefaultDesktop.jpg` is already a symlink, and + # all wallpapers are in `/Library/Desktop Pictures/`. + rm -rf ~/Library/Application Support/Dock/desktoppicture.db + sudo rm -rf /System/Library/CoreServices/DefaultDesktop.jpg + sudo ln -s $HOME/clone/dotfiles/images/nord.png /System/Library/CoreServices/DefaultDesktop.jpg +fi + +# Set language and text formats +# Note: if you’re in the US, replace `EUR` with `USD`, `Centimeters` with +# `Inches`, `en_GB` with `en_US`, and `true` with `false`. +defaults write NSGlobalDomain AppleLanguages -array "en" "eo" "es" "pt" +defaults write NSGlobalDomain AppleLocale -string "en_US@currency=USD" +defaults write NSGlobalDomain AppleMeasurementUnits -string "Centimeters" +defaults write NSGlobalDomain AppleMetricUnits -bool true + +# Show language menu in the top right corner of the boot screen +sudo defaults write /Library/Preferences/com.apple.loginwindow showInputMenu -bool true + +# Enable full keyboard access for all controls +# (e.g. enable Tab in modal dialogs) +defaults write NSGlobalDomain AppleKeyboardUIMode -int 3 + +# Use scroll gesture with the Ctrl (^) modifier key to zoom +defaults write com.apple.universalaccess closeViewScrollWheelToggle -bool true +defaults write com.apple.universalaccess HIDScrollZoomModifierMask -int 262144 +# Follow the keyboard focus while zoomed in +defaults write com.apple.universalaccess closeViewZoomFollowsFocus -bool true + +# Set highlight color to green +defaults write NSGlobalDomain AppleHighlightColor -string "0.184300 0.937200 0.937200" + +# Always show scrollbars +defaults write NSGlobalDomain AppleShowScrollBars -string "Always" +# Possible values: `WhenScrolling`, `Automatic` and `Always` + +# Disable the “Are you sure you want to open this application?” dialog +defaults write com.apple.LaunchServices LSQuarantine -bool false + +# Set Help Viewer windows to non-floating mode +defaults write com.apple.helpviewer DevMode -bool true + +# Disable Notification Center and remove the menu bar icon +launchctl unload -w /System/Library/LaunchAgents/com.apple.notificationcenterui.plist 2> /dev/null + # Expand save panel by default defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true @@ -71,6 +126,82 @@ defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false defaults write NSGlobalDomain InitialKeyRepeat -int 20 defaults write NSGlobalDomain KeyRepeat -int 1 +# Change keyboard layout to Dvorak by default +defaults import com.apple.HIToolbox - <<EOF +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>AppleCurrentKeyboardLayoutInputSourceID</key> + <string>com.apple.keylayout.Dvorak</string> + <key>AppleEnabledInputSources</key> + <array> + <dict> + <key>Bundle ID</key> + <string>com.apple.CharacterPaletteIM</string> + <key>InputSourceKind</key> + <string>Non Keyboard Input Method</string> + </dict> + <dict> + <key>Bundle ID</key> + <string>com.apple.inputmethod.EmojiFunctionRowItem</string> + <key>InputSourceKind</key> + <string>Non Keyboard Input Method</string> + </dict> + <dict> + <key>InputSourceKind</key> + <string>Keyboard Layout</string> + <key>KeyboardLayout ID</key> + <integer>16300</integer> + <key>KeyboardLayout Name</key> + <string>Dvorak</string> + </dict> + <dict> + <key>InputSourceKind</key> + <string>Keyboard Layout</string> + <key>KeyboardLayout ID</key> + <integer>0</integer> + <key>KeyboardLayout Name</key> + <string>U.S.</string> + </dict> + </array> + <key>AppleInputSourceHistory</key> + <array> + <dict> + <key>InputSourceKind</key> + <string>Keyboard Layout</string> + <key>KeyboardLayout ID</key> + <integer>16300</integer> + <key>KeyboardLayout Name</key> + <string>Dvorak</string> + </dict> + <dict> + <key>InputSourceKind</key> + <string>Keyboard Layout</string> + <key>KeyboardLayout ID</key> + <integer>0</integer> + <key>KeyboardLayout Name</key> + <string>U.S.</string> + </dict> + </array> + <key>AppleSelectedInputSources</key> + <array> + <dict> + <key>InputSourceKind</key> + <string>Keyboard Layout</string> + <key>KeyboardLayout ID</key> + <integer>16300</integer> + <key>KeyboardLayout Name</key> + <string>Dvorak</string> + </dict> + </array> +</dict> +</plist> +EOF + +# Increase sound quality for Bluetooth headphones/headsets +defaults write com.apple.BluetoothAudioAgent "Apple Bitpool Min (editable)" -int 40 + # Disable auto-correct defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false @@ -81,8 +212,12 @@ hidutil property --set '{"UserKeyMapping":[{"HIDKeyboardModifierMappingSrc": 0x7 # Screen # ############################################################################### +# Require password immediately after sleep or screen saver begins +defaults write com.apple.screensaver askForPassword -int 1 +defaults write com.apple.screensaver askForPasswordDelay -int 0 + # Save screenshots to Downloads folder. -defaults write com.apple.screencapture location -string "${HOME}/Downloads" +defaults write com.apple.screencapture location -string "${HOME}/Documents/04 - Pictures/Screenshots" # Save screenshots in PNG format (other options: BMP, GIF, JPG, PDF, TIFF) defaults write com.apple.screencapture type -string "png" @@ -149,6 +284,12 @@ chflags nohidden ~/Library # Set the icon size of Dock items defaults write com.apple.dock tilesize -int 30 +# Don't automatically rearrange spaces... +defaults write com.apple.dock mru-spaces -bool false + +# Automatically hide and show the Dock +defaults write com.apple.dock autohide -bool true + # Speed up Mission Control animations defaults write com.apple.dock expose-animation-duration -float 0.15 @@ -176,19 +317,28 @@ defaults write com.apple.dock wvous-br-modifier -int 0 # Top right screen corner → Put display to sleep defaults write com.apple.dock wvous-tr-corner -int 10 defaults write com.apple.dock wvous-tr-modifier -int 0 -# Bottom left screen corner → Desktop -defaults write com.apple.dock wvous-bl-corner -int 4 +# Bottom left screen corner → Launchpad +defaults write com.apple.dock wvous-bl-corner -int 11 defaults write com.apple.dock wvous-bl-modifier -int 0 ############################################################################### # Safari & WebKit # ############################################################################### +# Enable Safari’s debug menu +defaults write com.apple.Safari IncludeInternalDebugMenu -bool true + +# Set Safari’s home page to `about:blank` for faster loading +defaults write com.apple.Safari HomePage -string "about:blank" + # Enable the Develop menu and the Web Inspector in Safari defaults write com.apple.Safari IncludeDevelopMenu -bool true defaults write com.apple.Safari WebKitDeveloperExtrasEnabledPreferenceKey -bool true defaults write com.apple.Safari com.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled -bool true +# Enable “Do Not Track” +defaults write com.apple.Safari SendDoNotTrackHTTPHeader -bool true + # Add a context menu item for showing the Web Inspector in web views defaults write NSGlobalDomain WebKitDeveloperExtras -bool true @@ -199,10 +349,45 @@ defaults write NSGlobalDomain WebKitDeveloperExtras -bool true # Copy email addresses as `foo@example.com` instead of `Foo Bar <foo@example.com>` in Mail.app defaults write com.apple.mail AddressesIncludeNameOnPasteboard -bool false + +############################################################################### +# Photos # +############################################################################### + +# Prevent Photos from opening automatically when devices are plugged in +defaults -currentHost write com.apple.ImageCapture disableHotPlug -bool true + + ############################################################################### # Spotlight # ############################################################################### +# Change indexing order and disable some search results +# Yosemite-specific search results (remove them if you are using macOS 10.9 or older): +# MENU_DEFINITION +# MENU_CONVERSION +# MENU_EXPRESSION +# MENU_SPOTLIGHT_SUGGESTIONS (send search queries to Apple) +# MENU_WEBSEARCH (send search queries to Apple) +# MENU_OTHER +defaults write com.apple.spotlight orderedItems -array \ + '{"enabled" = 1;"name" = "APPLICATIONS";}' \ + '{"enabled" = 1;"name" = "SYSTEM_PREFS";}' \ + '{"enabled" = 0;"name" = "DIRECTORIES";}' \ + '{"enabled" = 0;"name" = "PDF";}' \ + '{"enabled" = 1;"name" = "FONTS";}' \ + '{"enabled" = 0;"name" = "DOCUMENTS";}' \ + '{"enabled" = 0;"name" = "MESSAGES";}' \ + '{"enabled" = 0;"name" = "CONTACT";}' \ + '{"enabled" = 0;"name" = "EVENT_TODO";}' \ + '{"enabled" = 0;"name" = "IMAGES";}' \ + '{"enabled" = 0;"name" = "BOOKMARKS";}' \ + '{"enabled" = 0;"name" = "MUSIC";}' \ + '{"enabled" = 0;"name" = "MOVIES";}' \ + '{"enabled" = 0;"name" = "PRESENTATIONS";}' \ + '{"enabled" = 0;"name" = "SPREADSHEETS";}' \ + '{"enabled" = 0;"name" = "SOURCE";}' \ + if [[ "$RUN_AS_ROOT" = true ]]; then # Disable Spotlight indexing for any volume that gets mounted and has not yet # been indexed before. diff --git a/Library/.DS_Store b/Library/.DS_Store new file mode 100644 index 0000000..85c564a Binary files /dev/null and b/Library/.DS_Store differ diff --git a/Library/Application Support/MTMR/items.json b/Library/Application Support/MTMR/items.json new file mode 100644 index 0000000..3af6816 --- /dev/null +++ b/Library/Application Support/MTMR/items.json @@ -0,0 +1,82 @@ +[ + { + "type": "escape", + "width": 64, + "align": "left" + }, + { + "type": "group", + "align": "left", + "title": "💡", + "background": "#000000", + "bordered": false, + "width": 38, + "items": [ + { + "type": "close", + "align":"left", + "background": "#000000", + "bordered": false, + "image": { + "base64": "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAAXNSR0IArs4c6QAAAKJlWElmTU0AKgAAAAgABgESAAMAAAABAAEAAAEaAAUAAAABAAAAVgEbAAUAAAABAAAAXgEoAAMAAAABAAIAAAExAAIAAAARAAAAZodpAAQAAAABAAAAeAAAAAAAAABgAAAAAQAAAGAAAAABd3d3Lmlua3NjYXBlLm9yZwAAAAOgAQADAAAAAQABAACgAgAEAAAAAQAAACigAwAEAAAAAQAAACgAAAAAuZ8ckgAAAAlwSFlzAAAOxAAADsQBlSsOGwAAActpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDYuMC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgICAgIDx4bXA6Q3JlYXRvclRvb2w+d3d3Lmlua3NjYXBlLm9yZzwveG1wOkNyZWF0b3JUb29sPgogICAgICA8L3JkZjpEZXNjcmlwdGlvbj4KICAgPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4K56DsKAAAADJJREFUWAnt0IEAAAAAw6D5Ux/khVBhwIABAwYMGDBgwIABAwYMGDBgwIABAwYMGPgcGBkoAAE/HDEPAAAAAElFTkSuQmCC" + } + } + ] + }, + { + "type": "dock", + "width": 400, + "align": "left" + }, + { + "type": "dnd", + "align": "right", + "width": 38 + }, + + { + "type": "weather", + "align": "right", + "icon_type": "images", + "api_key": "ca93a0bb8cdb428552660d83249e4bc9", + "bordered": false, + "width": 56 + }, + { "type": "brightnessDown", "width": 32, "bordered": false, "align": "right" }, + { "type": "brightnessUp", "width": 32, "bordered": false, "align": "right" }, + { + "type": "volumeDown", + "bordered": false, + "align": "right", + "width": 28 + }, + { + "type": "volumeUp", + "bordered": false, + "align": "right", + "width": 28 + }, + { + "type": "play", + "align": "right", + "bordered": false, + "width": 38 + }, + { + "type": "battery", + "align": "right", + "longAction": "openUrl", + "longUrl": "x-apple.systempreferences:com.apple.preference.battery", + "bordered": false, + "width": 64 + }, + { + "type": "timeButton", + "formatTemplate": "EEE, MMM d, HH:mm", + "align": "right", + "bordered": false, + "longAction": "shellScript", + "longExecutablePath": "/usr/bin/s", + "longShellArguments": ["sleepnow"] + } +] diff --git a/images/nord.png b/images/nord.png new file mode 100644 index 0000000..fa2c491 Binary files /dev/null and b/images/nord.png differ diff --git a/install.sh b/install.sh deleted file mode 100755 index 5d18b22..0000000 --- a/install.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -current_dir="$(pwd)" - -tar -xvf .config/nvim.tar.xz -mv nvim .config/nvim - -cd $HOME -cp -rf "$current_dir"/{.config,.local,scripts} . -cp -rf "$current_dir"/.nvimrc . diff --git a/scripts/albert-start b/scripts/albert-start deleted file mode 100755 index 718d81b..0000000 --- a/scripts/albert-start +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -sleep 2 -albert diff --git a/scripts/arch-custom-install b/scripts/arch-custom-install deleted file mode 100644 index 3535903..0000000 --- a/scripts/arch-custom-install +++ /dev/null @@ -1,135 +0,0 @@ -#!/bin/bash - -# ---Clearing Variables to Default--- -var_wheel="" - -# ---Questions--- -read -p 'Hostname: ' var_hostname -read -p 'Root password: ' var_password -read -p 'User name: ' var_user_name -read -p "User ($var_user_name) password: " var_user_password -read -p "Would you like the user \"$var_user_name\" to be a super user? (type \'wheel\' to say yes) " var_user_wheel -if [[ $var_user_wheel = "wheel" ]] -then - var_wheel="-aG wheel" -else - var_wheel=" " -fi - - -echo -echo -echo 'Starting to install...' -echo -echo -echo -sleep 1 - -# ---Execution--- -ln -sf /usr/share/zoneinfo/America/Buenos_Aires /etc/localtime -hwclock --systohc -timedatectl set-ntp true - -sed -i 's/#en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen -locale-gen - -echo 'LANG=en_US.UTF-8' >> /etc/locale.conf -echo "$var_hostname" >> /etc/hostname - -echo '127.0.0.1 localhost' >> /etc/hosts -echo '::1 localhost' >> /etc/hosts -echo "127.0.0.1 $var_hostname.localdomain $var_hostname" >> /etc/hosts - -echo -echo -echo 'Doing btrfs stuff and encryption...' -echo -echo -echo -sleep 1 - -# ---[Btrfs and encryption]--- -sed -i 's/MODULES=(/MODULES=(btrfs/' /etc/mkinitcpio.conf -var_hooks_line="$(grep 'HOOKS=(' /etc/mkinitcpio.conf | grep -v '# HOOKS')" -var_hooks_replace="$(grep 'HOOKS=(' /etc/mkinitcpio.conf | grep -v '# HOOKS' | sed 's/filesystems/encrypt filesystems/')" -sed -i "s/$var_hooks_line/$var_hooks_replace/" /etc/mkinitcpio.conf -mkinitcpio -p linux - -echo -echo -echo 'Doing user stuff...' -echo -echo -echo -sleep 1 - -# ---[Users]--- -useradd -m "$var_user_name" -echo "$var_user_name:$var_user_password" | chpasswd - -echo "root:$var_password" | chpasswd - -sed -i 's/# %wheel ALL=(ALL) ALL/%wheel ALL=(ALL) ALL/' /etc/sudoers -if [[ $var_wheel = "-aG wheel" ]] -then - usermod $var_wheel $var_user_name -fi - -echo -echo -echo 'Installing packages...' -echo -echo -echo -sleep 1 - -# ---[Packages]--- -pacman -S networkmanager gnome gdm gnome-tweaks alacritty fish exa vlc git base-devel adobe-source-sans-fonts - -mkdir /root/arch-custom-install -cd /root/arch-custom-install - -git clone https://gitlab.com/thebiblelover7/prebuilt-packages -cd prebuilt-packages -for i in $(ls -1) -do - pacman -U $i -done - -paru -S brave-bin logseq-desktop-bin slack-desktop schildichat-desktop-bin whitesur-icon-theme whitesur-gtk-theme gnome-shell-extension-pop-shell-git cursor-theme-macos-big-sur - -echo -echo -echo 'Installing configs...' -echo -echo -echo -sleep 1 - -# ---[Configs]--- -cd /home/$var_user_name -git clone https://gitlab.com/thebiblelover7/dotfiles -cd dotfiles -./install.sh -chown -R $var_user_name:$var_user_name /home/$var_user_name -chsh -s /bin/fish $var_user_name - -cd - -# pacman color and parallel downloads -# change dotfiles to have the plain background, and to have the right theme -# albert - -echo -echo -echo 'Enabling services to start on boot...' -echo -echo -echo -sleep 1 - -# ---[Services] -systemctl enable NetworkManager -systemctl enable bluetooth -systemctl enable gdm -#systemctl enable cups.service diff --git a/scripts/arch-install b/scripts/arch-install deleted file mode 100755 index d8ecb65..0000000 --- a/scripts/arch-install +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash - -# |||||- Pre-Configurations -||||| - -diselect() { - PS3='Please enter your choice: ' - select opt in "${options[@]}" - do - case $opt in - 1|"${options[0]}") - ${option_c[0]} - break - ;; - 2|"${options[1]}") - ${option_c[1]} - break - ;; - 3|"${options[2]}") - ${option_c[2]} - break - ;; - 4|"${options[3]}") - ${option_c[3]} - break - ;; - 5|"${options[4]}") - ${option_c[4]} - break - ;; - *) echo "invalid option, try again" ;; - - esac - done - -} - -# |||||- Functions -||||| - -check_internet() { - ping -c 2 archlinux.org && check_intenet_state=true || check_intenet_state=false - if [[ $check_intenet_state = false ]] - then - echo "No internet.. Exiting..." - exit 2 - fi -} - -update_time() { - timedatectl set-ntp true -} - -dialog_partition_disks() { - options=("cfdisk" "fdisk" "I already partitioned my disks") - option_c=("fun_cfdisk" "fun_fdisk" "echo") - diselect -} - -dialog_drive_list() { - echo "Please enter your drive to be partitioned in the format '/dev/sda'" - read -p "-> " var_drive - -} -fun_cfdisk() { - dialog_drive_list - cfdisk $var_drive - -} - - -# |||||- Execution -||||| - -check_internet - -dialog_partition_disks diff --git a/scripts/edit_npad b/scripts/edit_npad deleted file mode 100755 index 0be3db9..0000000 --- a/scripts/edit_npad +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -nvim $HOME/scripts/npad -cp $HOME/scripts/npad $HOME/clonenbuild/npad/npad diff --git a/scripts/night-shift-g b/scripts/night-shift-g deleted file mode 100755 index 235ea2e..0000000 --- a/scripts/night-shift-g +++ /dev/null @@ -1,8 +0,0 @@ -#/bin/bash - -if [[ $(gsettings get org.gnome.settings-daemon.plugins.color night-light-enabled) = "true" ]] -then - gsettings set org.gnome.settings-daemon.plugins.color night-light-enabled false -else - gsettings set org.gnome.settings-daemon.plugins.color night-light-enabled true -fi diff --git a/scripts/npad_sleep b/scripts/npad_sleep deleted file mode 100644 index f22aa22..0000000 --- a/scripts/npad_sleep +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -sleep 0.05 -/home/adriel/scripts/npad diff --git a/scripts/projman b/scripts/projman deleted file mode 100755 index dc74f9e..0000000 --- a/scripts/projman +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash - -project_dir=$HOME/Videos/Projects -proj_name=$1 - -mkproj(){ - mkdir -p $project_dir/$proj_name -} -openproj(){ - cd $project_dir/$proj_name - tmux -} - -case $1 in - '--help' | '-h' | 'help') - echo "HELP!" - ;; - * ) - echo $proj_name - mkproj - openproj - ;; -esac diff --git a/scripts/social b/scripts/social deleted file mode 100755 index 02d3df6..0000000 --- a/scripts/social +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -choice=$(echo "Schildichat -Element -Signal -Telegram" | rofi -dmenu -i) - -case $choice in - 'Schildichat') - schildichat-desktop - ;; - 'Element') - element-desktop - ;; - 'Signal') - signal-desktop - ;; - 'Telegram') - telegram-desktop - ;; -esac diff --git a/scripts/ssh-into b/scripts/ssh-into deleted file mode 100755 index 61ee2f3..0000000 --- a/scripts/ssh-into +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -ssher=$(wofi --dmenu -i < $HOME/.config/ssh-into); terminator -e "ssh $ssher" diff --git a/scripts/write-write b/scripts/write-write deleted file mode 100755 index 10c1539..0000000 --- a/scripts/write-write +++ /dev/null @@ -1,200 +0,0 @@ -#!/bin/bash - -sleep 0.2 -write_config_dir=$HOME/.config/write -write_config_file_path=$write_config_dir/write.conf -write_config_exists_out=$(cat $write_config_file_path &> /dev/null) -write_config_exists=$? -write_default_notes_dir=$HOME/Write-Write -write_default_note_num=1 -write_default_editor=$EDITOR -write_default_note_extension=".md" -logseq_page_path="$HOME/Nextcloud/Notes/Logseq/pages/write-write.md" -note_num=$write_default_note_num -bold_on="setterm --bold on" -bold_off="setterm --bold off" - -make_default_config() { - mkdir -p $write_config_dir || exit 2 - - echo "write_notes_dir=$write_default_notes_dir" > $write_config_file_path - echo "note_num=$write_default_note_num" >> $write_config_file_path - echo "write_note_extension=$write_default_note_extension" >> $write_config_file_path - echo "write_editor=$write_default_editor" >> $write_config_file_path - - mkdir -p $write_default_notes_dir || exit 2 -} - -make_config_file() { - mkdir -p $write_config_dir || exit 2 - - echo "write_notes_dir=$write_notes_dir" > $write_config_file_path - echo "note_num=$note_num" >> $write_config_file_path - echo "write_note_extension=$write_note_extension" >> $write_config_file_path - echo "write_editor=$write_editor" >> $write_config_file_path - - mkdir -p $write_notes_dir || exit 2 -} - -make_config_dialog() { - $bold_on && echo "Would you like to change the default notes directory? $write_default_notes_dir" - echo "[y,N]" && $bold_off - read change_notes_dir - if [[ $change_notes_dir = "y" || $change_notes_dir = "Y" ]] - then - $bold_on && echo "Enter absolute directory of stored files e.g. /home/$(whoami)/notes" && $bold_off - read write_notes_dir_input - write_notes_dir=$write_notes_dir_input - make_config_file - else - write_notes_dir=$write_default_notes_dir - make_config_file - fi - mkdir -p $write_notes_dir || exit 2 - - $bold_on && echo "Would you like to change the current editor ($EDITOR)?" - echo "[y,N]" && $bold_off - read change_editor - if [[ $change_editor = "y" || $change_editor = "Y" ]] - then - $bold_on && echo "Enter the command used to run the editor (e.g. 'nano', 'vi', 'micro')" && $bold_off - read write_editor_input - write_editor=$write_editor_input - make_config_file - else - write_editor=$write_default_editor - make_config_file - fi - - - $bold_on && echo "Would you like to change the current file extension for the notes ($write_default_note_extension)?" - echo "[y,N]" && $bold_off - read change_note_extension - if [[ $change_note_extension = "y" || $change_note_extension = "Y" ]] - then - $bold_on && echo "Enter the file extension desired (e.g. '.md', '.txt')" && $bold_off - read write_note_extension_input - write_note_extension="$write_note_extension_input" - make_config_file - else - write_note_extension=$write_default_note_extension - make_config_file - fi - - - source $write_config_file_path - -} - -append_note_logseq() { - echo "" >> $logseq_page_path - echo "# $note_num$write_note_extension" >> $logseq_page_path -# echo " -" >> $logseq_page_path - cat $write_notes_dir/$note_num$write_note_extension >> $logseq_page_path - echo "" >> $logseq_page_path -} - -check_note_diff() { - diff_state=$(diff $write_notes_dir/$note_num$write_note_extension $write_notes_dir/$note_num$write_note_extension.previous &> /dev/null && echo $?) -} - -update_note_num() { - note_exists=$(cat $write_notes_dir/$note_num$write_note_extension &> /dev/null && echo $?) - if [[ $note_exists = 0 ]] - then - note_num=$(($note_num + 1)) - fi - make_config_file -} - -new_note() { - $write_editor $write_notes_dir/$note_num$write_note_extension - note_exists=$(cat $write_notes_dir/$note_num$write_note_extension &> /dev/null && echo $?) - if [[ $note_exists = 0 ]] - then - append_note_logseq - fi - update_note_num -} - -open_note(){ - cp $write_notes_dir/$note_num$write_note_extension $write_notes_dir/$note_num$write_note_extension.previous - $write_editor $write_notes_dir/$note_num$write_note_extension - check_note_diff - if [[ $diff_state = 1 ]] - then - replace_note_logseq - fi -} - -get_entries() { - ls -1 $write_notes_dir | while read note - do - $bold_on && echo "$note" && $bold_off - cat -n $write_notes_dir/$note | while read line - do - line_num=$(echo $line | cut -d ' ' -f1) - new_line=$(echo $line | sed "s/$line_num //g") -# line_num=$(echo "$line" | cut --delimiter=' ' -f1) - if [[ $line_num -lt 5 ]] - then -# echo $line_num - echo "$new_line" -# echo $line | sed "s/$line_num //" - fi - done - echo - echo - done -# for i in $notes_list -# do -# echo "$i" -# sleep 2 -# for line in $(cat -n $write_notes_dir/$i) -# do -# if [[ $(echo $line | cut --delimiter=' ' -f1) < 5 ]] -# then -# echo $line -# fi -# done -# done -} - -if [[ $write_config_exists = 1 ]] # 1 means not true in this case (exit code) -then - make_default_config - echo "write-write Copyright (C) 2021 Adriel Sand -This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See https://gitlab.com/thebiblelover7/npad for more details." - $bold_on - echo "Would you like to change the defaults?" - echo "[y,N]" && $bold_off - read change_defaults - if [[ $change_defaults = "y" || $change_defaults = "Y" ]] - then - make_config_dialog - else - make_default_config - fi - - source $write_config_file_path || exit 2 - -else - source $write_config_file_path || exit 2 -fi - -case $1 in - 'list' | '-l' | '--list') - get_entries - ;; - *) - note_num=$1 - note_exists=$(cat $write_notes_dir/$note_num$write_note_extension &> /dev/null && echo $?) - if [[ $note_exists = 0 ]] - then - open_note - else - source $write_config_file_path || exit 2 - new_note - fi - ;; -esac