From 2b8871320c96f5084d71f4bf7c6da1407f0d5b3c Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 05 2019 20:55:05 +0000 Subject: import gnome-shell-extensions-3.32.1-10.el8 --- diff --git a/.gitignore b/.gitignore index 6b31b44..3529e4d 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/gnome-shell-extensions-3.28.1.tar.xz +SOURCES/gnome-shell-extensions-3.32.1.tar.xz diff --git a/.gnome-shell-extensions.metadata b/.gnome-shell-extensions.metadata index 8fb3d9e..4e2ddcc 100644 --- a/.gnome-shell-extensions.metadata +++ b/.gnome-shell-extensions.metadata @@ -1 +1 @@ -51b02a3157aa4c36af145b0c57b8132203954fc2 SOURCES/gnome-shell-extensions-3.28.1.tar.xz +51c1c16bcd0dc9125834b32d7c539c38fa9c4f52 SOURCES/gnome-shell-extensions-3.32.1.tar.xz diff --git a/SOURCES/0001-Include-top-icons-in-classic-session.patch b/SOURCES/0001-Include-top-icons-in-classic-session.patch index 4f7dae5..9c5283f 100644 --- a/SOURCES/0001-Include-top-icons-in-classic-session.patch +++ b/SOURCES/0001-Include-top-icons-in-classic-session.patch @@ -1,4 +1,4 @@ -From 12f264be954474200864c9acad33c11292f34e14 Mon Sep 17 00:00:00 2001 +From a3db60786407481efbfc4875f887d03b58f0a7b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 23 Feb 2018 16:56:46 +0100 Subject: [PATCH] Include top-icons in classic session @@ -8,10 +8,10 @@ Subject: [PATCH] Include top-icons in classic session 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build -index da5e791..ca9f60a 100644 +index 6764f9a..32743ed 100644 --- a/meson.build +++ b/meson.build -@@ -39,6 +39,7 @@ classic_extensions = [ +@@ -36,6 +36,7 @@ classic_extensions = [ 'desktop-icons', 'places-menu', 'launch-new-instance', @@ -19,14 +19,14 @@ index da5e791..ca9f60a 100644 'window-list' ] -@@ -59,7 +60,6 @@ all_extensions += [ +@@ -56,7 +57,6 @@ all_extensions += [ 'no-hot-corner', 'panel-favorites', 'systemMonitor', - 'top-icons', 'updates-dialog', - 'user-theme' - ] + 'user-theme', + 'window-grouper' -- -2.20.1 +2.21.0 diff --git a/SOURCES/0001-Update-style.patch b/SOURCES/0001-Update-style.patch index 091f008..8173ded 100644 --- a/SOURCES/0001-Update-style.patch +++ b/SOURCES/0001-Update-style.patch @@ -1,18 +1,48 @@ -From bddab939dedf770220f59394b4d4d5534063f0f1 Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Mon, 11 Jun 2018 16:40:34 -0400 +From e768ad73e2d68b3f1567051675ba0539a75e3105 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sat, 18 May 2019 19:37:05 +0200 Subject: [PATCH] Update style --- - data/gnome-shell-sass/_common.scss | 19 +++++++++++++++++-- - 1 file changed, 17 insertions(+), 2 deletions(-) + data/gnome-shell-sass | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) +Submodule data/gnome-shell-sass 1a56956..8842e57: diff --git a/data/gnome-shell-sass/_common.scss b/data/gnome-shell-sass/_common.scss -index 2f05098df..de3a9cdbc 100644 +index a6357ba..62d9c82 100644 --- a/data/gnome-shell-sass/_common.scss +++ b/data/gnome-shell-sass/_common.scss -@@ -776,6 +776,11 @@ StScrollBar { - //dimensions of the icon are hardcoded +@@ -571,6 +571,18 @@ StScrollBar { + app menu inside the main app window itself rather than the top bar + */ + ++/************* ++ * App Icons * ++ *************/ ++/* Outline for low res icons */ ++.lowres-icon { ++ icon-shadow: 0 1px 2px rgba(0,0,0,0.3); ++} ++ ++/* Drapshadow for large icons */ ++.icon-dropshadow { ++ icon-shadow: 0 1px 2px rgba(0,0,0,0.4); ++} + + /* OSD */ + .osd-window { +@@ -680,7 +692,8 @@ StScrollBar { + spacing: 8px; + } + +- .ws-switcher-active-up, .ws-switcher-active-down { ++ .ws-switcher-active-up, .ws-switcher-active-down, ++ .ws-switcher-active-left, .ws-switcher-active-right { + height: 50px; + background-color: $selected_bg_color; + color: $selected_fg_color; +@@ -781,6 +794,11 @@ StScrollBar { + color: lighten($fg_color,10%); } + .panel-logo-icon { @@ -20,10 +50,10 @@ index 2f05098df..de3a9cdbc 100644 + icon-size: 1em; + } + - .system-status-icon, - .app-menu-icon > StIcon, - .popup-menu-arrow { -@@ -1397,6 +1402,14 @@ StScrollBar { + .system-status-icon { icon-size: 1.09em; padding: 0 5px; } + .unlock-screen &, + .login-screen &, +@@ -1406,6 +1424,14 @@ StScrollBar { } @@ -38,7 +68,7 @@ index 2f05098df..de3a9cdbc 100644 .app-well-app-running-dot { //running apps indicator width: 10px; height: 3px; background-color: $selected_bg_color; -@@ -1769,7 +1782,12 @@ StScrollBar { +@@ -1801,7 +1827,12 @@ StScrollBar { .login-dialog-banner { color: darken($osd_fg_color,10%); } .login-dialog-button-box { spacing: 5px; } .login-dialog-message-warning { color: $warning_color; } @@ -52,7 +82,7 @@ index 2f05098df..de3a9cdbc 100644 .login-dialog-user-selection-box { padding: 100px 0px; } .login-dialog-not-listed-label { padding-left: 2px; -@@ -1825,6 +1843,10 @@ StScrollBar { +@@ -1856,6 +1887,10 @@ StScrollBar { padding-bottom: 12px; spacing: 8px; width: 23em; @@ -63,3 +93,6 @@ index 2f05098df..de3a9cdbc 100644 } .login-dialog-prompt-label { +-- +2.21.0 + diff --git a/SOURCES/0001-apps-menu-Add-missing-chain-up.patch b/SOURCES/0001-apps-menu-Add-missing-chain-up.patch new file mode 100644 index 0000000..35fd0f7 --- /dev/null +++ b/SOURCES/0001-apps-menu-Add-missing-chain-up.patch @@ -0,0 +1,33 @@ +From 0bbeadadc41128b2be1f2b56c60b5a7a671d40da Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 27 Jun 2019 03:57:53 +0200 +Subject: [PATCH] apps-menu: Add missing chain-up + +PanelMenu.Button is a bit weird in that it also "contains" its parent +actor. That container is supposed to be destroyed with the button, but +as we currently don't chain up to the parent class' _onDestroy(), we +leave behind an empty container every time the extension is disabled. + +Fix this by adding the missing chain-up. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/75 +--- + extensions/apps-menu/extension.js | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js +index b9e7111..9803cc1 100644 +--- a/extensions/apps-menu/extension.js ++++ b/extensions/apps-menu/extension.js +@@ -433,6 +433,8 @@ class ApplicationsButton extends PanelMenu.Button { + } + + _onDestroy() { ++ super._onDestroy(); ++ + Main.overview.disconnect(this._showingId); + Main.overview.disconnect(this._hidingId); + appSys.disconnect(this._installedChangedId); +-- +2.21.0 + diff --git a/SOURCES/0001-apps-menu-Explicitly-set-label_actor.patch b/SOURCES/0001-apps-menu-Explicitly-set-label_actor.patch index d917c3d..131ea79 100644 --- a/SOURCES/0001-apps-menu-Explicitly-set-label_actor.patch +++ b/SOURCES/0001-apps-menu-Explicitly-set-label_actor.patch @@ -1,4 +1,4 @@ -From 07d409f6bf4e5bffa4dbda8d7cdefaf71742b85f Mon Sep 17 00:00:00 2001 +From 52ee25effa3debb21307e33ac223cf48ac7bc57a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 17 Mar 2016 17:15:38 +0100 Subject: [PATCH] apps-menu: Explicitly set label_actor @@ -10,23 +10,23 @@ so set the label_actor explicitly as workaround. 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js -index 5067b63..49a05c7 100644 +index d62e3d7..cc399c6 100644 --- a/extensions/apps-menu/extension.js +++ b/extensions/apps-menu/extension.js -@@ -34,7 +34,9 @@ class ActivitiesMenuItem extends PopupMenu.PopupBaseMenuItem { +@@ -29,7 +29,9 @@ class ActivitiesMenuItem extends PopupMenu.PopupBaseMenuItem { constructor(button) { super(); this._button = button; -- this.actor.add_child(new St.Label({ text: _("Activities Overview") })); -+ let label = new St.Label({ text: _("Activities Overview") }); +- this.actor.add_child(new St.Label({ text: _('Activities Overview') })); ++ let label = new St.Label({ text: _('Activities Overview') }); + this.actor.add_child(label); + this.actor.label_actor = label; } activate(event) { -@@ -129,7 +131,9 @@ class CategoryMenuItem extends PopupMenu.PopupBaseMenuItem { +@@ -120,7 +122,9 @@ class CategoryMenuItem extends PopupMenu.PopupBaseMenuItem { else - name = _("Favorites"); + name = _('Favorites'); - this.actor.add_child(new St.Label({ text: name })); + let label = new St.Label({ text: name }); @@ -36,5 +36,5 @@ index 5067b63..49a05c7 100644 } -- -2.20.1 +2.21.0 diff --git a/SOURCES/0001-apps-menu-add-logo-icon-to-Applications-menu.patch b/SOURCES/0001-apps-menu-add-logo-icon-to-Applications-menu.patch index 2f79690..973c077 100644 --- a/SOURCES/0001-apps-menu-add-logo-icon-to-Applications-menu.patch +++ b/SOURCES/0001-apps-menu-add-logo-icon-to-Applications-menu.patch @@ -1,29 +1,32 @@ -From fe6695b8d45fe7d1d9aea8c41c9aa54048a9704d Mon Sep 17 00:00:00 2001 +From 3e3634b59455da0cbae1de4af0ce5cf97be8b80d Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 21 Jan 2014 16:48:17 -0500 Subject: [PATCH] apps-menu: add logo icon to Applications menu Brand requested it. --- - extensions/apps-menu/extension.js | 5 +++++ - 1 file changed, 5 insertions(+) + extensions/apps-menu/extension.js | 8 ++++++++ + 1 file changed, 8 insertions(+) diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js -index 2f4002a..41d1faf 100644 +index d7ba570..d62e3d7 100644 --- a/extensions/apps-menu/extension.js +++ b/extensions/apps-menu/extension.js -@@ -433,6 +433,11 @@ const ApplicationsButton = new Lang.Class({ +@@ -390,6 +390,14 @@ class ApplicationsButton extends PanelMenu.Button { let hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' }); -+ let iconFile = Gio.File.new_for_path('/usr/share/icons/hicolor/scalable/apps/start-here.svg'); -+ this._icon = new St.Icon({ gicon: new Gio.FileIcon({ file: iconFile }), -+ style_class: 'panel-logo-icon' }); ++ let iconFile = Gio.File.new_for_path( ++ '/usr/share/icons/hicolor/scalable/apps/start-here.svg'); ++ this._icon = new St.Icon({ ++ gicon: new Gio.FileIcon({ file: iconFile }), ++ style_class: 'panel-logo-icon' ++ }); + hbox.add_actor(this._icon); + - this._label = new St.Label({ text: _("Applications"), - y_expand: true, - y_align: Clutter.ActorAlign.CENTER }); + this._label = new St.Label({ + text: _('Applications'), + y_expand: true, -- -2.14.2 +2.21.0 diff --git a/SOURCES/0001-classic-Shade-panel-in-overview.patch b/SOURCES/0001-classic-Shade-panel-in-overview.patch deleted file mode 100644 index 5894023..0000000 --- a/SOURCES/0001-classic-Shade-panel-in-overview.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 91ed30147a69d53d7c170b65602be5f90851666e Mon Sep 17 00:00:00 2001 -From: Jakub Steiner -Date: Tue, 14 Jan 2014 17:00:23 +0100 -Subject: [PATCH] classic: Shade panel in overview - -... rather than using the top bar styling (negative space), -base the overview panel on the classic grey and "darken" -for overview. ---- - data/gnome-classic.scss | 8 +++----- - 1 file changed, 3 insertions(+), 5 deletions(-) - -diff --git a/data/gnome-classic.scss b/data/gnome-classic.scss -index 9e23506..e8f4803 100644 ---- a/data/gnome-classic.scss -+++ b/data/gnome-classic.scss -@@ -19,11 +19,9 @@ $variant: 'light'; - border-bottom: 1px solid #666; - app-icon-bottom-clip: 0px; - &:overview { -- background-color: #000; -- background-gradient-end: #000; -- border-top-color: #000; -- border-bottom: 1px solid #000; -- .panel-button { color: #fff; } -+ background-color: darken($bg_color,5%); -+ background-gradient-end: darken($bg_color,10%); -+ .panel-button { color: darken($fg_color,5%); } - } - - .panel-button { --- -2.20.1 - diff --git a/SOURCES/0001-common-get-rid-of-weird-drop-shadow-nex-to-app-menu.patch b/SOURCES/0001-common-get-rid-of-weird-drop-shadow-nex-to-app-menu.patch deleted file mode 100644 index c8ac779..0000000 --- a/SOURCES/0001-common-get-rid-of-weird-drop-shadow-nex-to-app-menu.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 707ca4122da0a638f3df3b92178acc04eea264ec Mon Sep 17 00:00:00 2001 -From: rpm-build -Date: Tue, 4 Sep 2018 15:33:26 -0400 -Subject: [PATCH] common: get rid of weird drop shadow nex to app menu - -Resolves: #1620241 - ---- - data/gnome-shell-sass/_common.scss | 10 ---------- - 1 file changed, 10 deletions(-) - -diff --git a/data/gnome-shell-sass/_common.scss b/data/gnome-shell-sass/_common.scss -index 2f5c887..9883c78 100644 ---- a/data/gnome-shell-sass/_common.scss -+++ b/data/gnome-shell-sass/_common.scss -@@ -742,140 +742,130 @@ StScrollBar { - - #panelLeft, #panelCenter { // spacing between activities<>app menu and such - spacing: 4px; - } - - .panel-corner { - -panel-corner-radius: $panel-corner-radius; - -panel-corner-background-color: rgba(0, 0, 0, 0.35); - -panel-corner-border-width: 2px; - -panel-corner-border-color: transparent; - - &:active, &:overview, &:focus { - -panel-corner-border-color: lighten($selected_bg_color,5%); - } - - &.lock-screen, &.login-screen, &.unlock-screen { - -panel-corner-radius: 0; - -panel-corner-background-color: transparent; - -panel-corner-border-color: transparent; - } - } - - .panel-button { - -natural-hpadding: 12px; - -minimum-hpadding: 6px; - font-weight: bold; - color: #eee; - text-shadow: 0px 1px 2px rgba(0, 0, 0, 0.9); - transition-duration: 100ms; - -- .app-menu-icon { -- -st-icon-style: symbolic; -- margin-left: 4px; -- margin-right: 4px; -- //dimensions of the icon are hardcoded -- } -- - .panel-logo-icon { - padding-right: .4em; - icon-size: 1em; - } - - .system-status-icon, -- .app-menu-icon > StIcon, - .popup-menu-arrow { - icon-shadow: 0px 1px 2px rgba(0, 0, 0, 0.9); - } - - &:hover { - color: lighten($fg_color, 10%); - text-shadow: 0px 1px 6px rgba(0, 0, 0, 1); - - .system-status-icon, -- .app-menu-icon > StIcon, - .popup-menu-arrow { - icon-shadow: 0px 1px 6px rgba(0, 0, 0, 1); - } - } - - &:active, &:overview, &:focus, &:checked { - // Trick due to St limitations. It needs a background to draw - // a box-shadow - background-color: rgba(0, 0, 0, 0.01); - box-shadow: inset 0 -2px 0px lighten($selected_bg_color,5%); - color: lighten($fg_color,10%); - - & > .system-status-icon { icon-shadow: black 0 2px 2px; } - } - - .system-status-icon { icon-size: 1.09em; padding: 0 5px; } - .unlock-screen &, - .login-screen &, - .lock-screen & { - color: lighten($fg_color, 10%); - &:focus, &:hover, &:active { color: lighten($fg_color, 10%); } - } - } - - .panel-status-indicators-box, - .panel-status-menu-box { - spacing: 2px; - } - - // spacing between power icon and (optional) percentage label - .power-status.panel-status-indicators-box { - spacing: 0; - } - - .screencast-indicator { color: $warning_color; } - - &.solid { - background-color: black; - /* transition from transparent to solid */ - transition-duration: 300ms; - - .panel-corner { - -panel-corner-background-color: black; - } - - .panel-button { - color: #ccc; - text-shadow: none; - - &:hover, &:active, &:overview, &:focus, &:checked { - color: lighten($fg_color, 10%); - } - } - - .system-status-icon, -- .app-menu-icon > StIcon, - .popup-menu-arrow { - icon-shadow: none; - } - } - } - - // calendar popover - #calendarArea { - padding: 0.75em 1.0em; - } - - .calendar { - margin-bottom: 1em; - } - - .calendar, - .datemenu-today-button, - .datemenu-displays-box, - .message-list-sections { - margin: 0 1.5em; - } - - .datemenu-calendar-column { spacing: 0.5em; } - .datemenu-displays-section { padding-bottom: 3em; } - .datemenu-displays-box { spacing: 1em; } - - .datemenu-calendar-column { - border: 0 solid lighten($bg_color,5%); - &:ltr { border-left-width: 1px; } - &:rtl { border-right-width: 1px; } --- -2.17.1 - diff --git a/SOURCES/add-extra-extensions.patch b/SOURCES/add-extra-extensions.patch index f5d284f..108707a 100644 --- a/SOURCES/add-extra-extensions.patch +++ b/SOURCES/add-extra-extensions.patch @@ -1,15 +1,15 @@ -From 3ce61087bd6777c450690f5f10e7d5a689f8d08c Mon Sep 17 00:00:00 2001 +From d97e40a53d1844c84c895ede9a102e6d9d73ec1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 20 May 2015 17:44:50 +0200 -Subject: [PATCH 1/6] Add top-icons extension +Subject: [PATCH 1/8] Add top-icons extension --- - extensions/top-icons/extension.js | 225 ++++++++++++++++++++++++++ - extensions/top-icons/meson.build | 5 + - extensions/top-icons/metadata.json.in | 10 ++ - extensions/top-icons/stylesheet.css | 1 + - meson.build | 1 + - 5 files changed, 242 insertions(+) + extensions/top-icons/extension.js | 96 +++++++++++++++++++++++++++ + extensions/top-icons/meson.build | 5 ++ + extensions/top-icons/metadata.json.in | 10 +++ + extensions/top-icons/stylesheet.css | 1 + + meson.build | 1 + + 5 files changed, 113 insertions(+) create mode 100644 extensions/top-icons/extension.js create mode 100644 extensions/top-icons/meson.build create mode 100644 extensions/top-icons/metadata.json.in @@ -17,234 +17,105 @@ Subject: [PATCH 1/6] Add top-icons extension diff --git a/extensions/top-icons/extension.js b/extensions/top-icons/extension.js new file mode 100644 -index 0000000..7312a26 +index 0000000..a8eec13 --- /dev/null +++ b/extensions/top-icons/extension.js -@@ -0,0 +1,225 @@ +@@ -0,0 +1,96 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- ++/* exported init */ + -+const Clutter = imports.gi.Clutter; -+const Shell = imports.gi.Shell; -+const St = imports.gi.St; ++const { Clutter, Shell, St } = imports.gi; +const Main = imports.ui.main; -+const GLib = imports.gi.GLib; -+const Lang = imports.lang; -+const Panel = imports.ui.panel; +const PanelMenu = imports.ui.panelMenu; -+const Meta = imports.gi.Meta; -+const Mainloop = imports.mainloop; -+const NotificationDaemon = imports.ui.notificationDaemon; +const System = imports.system; + -+let trayAddedId = 0; -+let trayRemovedId = 0; -+let getSource = null; -+let icons = []; -+let notificationDaemon = null; -+let sysTray = null; -+ -+const PANEL_ICON_SIZE = 24; ++const PANEL_ICON_SIZE = 16; ++ ++const STANDARD_TRAY_ICON_IMPLEMENTATIONS = [ ++ 'bluetooth-applet', ++ 'gnome-sound-applet', ++ 'nm-applet', ++ 'gnome-power-manager', ++ 'keyboard', ++ 'a11y-keyboard', ++ 'kbd-scrolllock', ++ 'kbd-numlock', ++ 'kbd-capslock', ++ 'ibus-ui-gtk' ++]; + -+function init() { -+ if (Main.legacyTray) { -+ notificationDaemon = Main.legacyTray; -+ NotificationDaemon.STANDARD_TRAY_ICON_IMPLEMENTATIONS = imports.ui.legacyTray.STANDARD_TRAY_ICON_IMPLEMENTATIONS; -+ } -+ else if (Main.notificationDaemon._fdoNotificationDaemon && -+ Main.notificationDaemon._fdoNotificationDaemon._trayManager) { -+ notificationDaemon = Main.notificationDaemon._fdoNotificationDaemon; -+ getSource = Lang.bind(notificationDaemon, NotificationDaemon.FdoNotificationDaemon.prototype._getSource); -+ } -+ else if (Main.notificationDaemon._trayManager) { -+ notificationDaemon = Main.notificationDaemon; -+ getSource = Lang.bind(notificationDaemon, NotificationDaemon.NotificationDaemon.prototype._getSource); -+ } -+ else { -+ NotificationDaemon.STANDARD_TRAY_ICON_IMPLEMENTATIONS = { -+ 'bluetooth-applet': 1, 'gnome-sound-applet': 1, 'nm-applet': 1, -+ 'gnome-power-manager': 1, 'keyboard': 1, 'a11y-keyboard': 1, -+ 'kbd-scrolllock': 1, 'kbd-numlock': 1, 'kbd-capslock': 1, 'ibus-ui-gtk': 1 -+ }; ++class SysTray { ++ constructor() { ++ this._icons = []; ++ this._tray = null; + } -+} -+ -+function enable() { -+ if (notificationDaemon) -+ GLib.idle_add(GLib.PRIORITY_LOW, moveToTop); -+ else -+ createTray(); -+} -+ -+function createSource (title, pid, ndata, sender, trayIcon) { -+ if (trayIcon) { -+ onTrayIconAdded(this, trayIcon, title); -+ return null; -+ } -+ -+ return getSource(title, pid, ndata, sender, trayIcon); -+}; -+ -+function onTrayIconAdded(o, icon, role) { -+ let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : ''; -+ if (NotificationDaemon.STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined) -+ return; -+ -+ let buttonBox = new PanelMenu.ButtonBox(); -+ let box = buttonBox.actor; -+ let parent = box.get_parent(); + -+ let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; -+ let iconSize = PANEL_ICON_SIZE * scaleFactor; -+ -+ icon.set_size(iconSize, iconSize); -+ box.add_actor(icon); -+ -+ icon.reactive = true; -+ -+ if (parent) -+ parent.remove_actor(box); ++ _onTrayIconAdded(o, icon) { ++ let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : ''; ++ if (STANDARD_TRAY_ICON_IMPLEMENTATIONS.includes(wmClass)) ++ return; + -+ icons.push(icon); -+ Main.panel._rightBox.insert_child_at_index(box, 0); ++ let button = new PanelMenu.Button(0.5, null, true); + -+ let clickProxy = new St.Bin({ width: iconSize, height: iconSize }); -+ clickProxy.reactive = true; -+ Main.uiGroup.add_actor(clickProxy); ++ let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; ++ let iconSize = PANEL_ICON_SIZE * scaleFactor; + -+ icon._proxyAlloc = Main.panel._rightBox.connect('allocation-changed', function() { -+ Meta.later_add(Meta.LaterType.BEFORE_REDRAW, function() { -+ let [x, y] = icon.get_transformed_position(); -+ clickProxy.set_position(x, y); ++ icon.set({ ++ width: iconSize, ++ height: iconSize, ++ x_align: Clutter.ActorAlign.CENTER, ++ y_align: Clutter.ActorAlign.CENTER + }); -+ }); -+ -+ icon.connect("destroy", function() { -+ Main.panel._rightBox.disconnect(icon._proxyAlloc); -+ clickProxy.destroy(); -+ }); -+ -+ clickProxy.connect('button-release-event', function(actor, event) { -+ icon.click(event); -+ }); -+ -+ icon._clickProxy = clickProxy; -+ -+ /* Fixme: HACK */ -+ Meta.later_add(Meta.LaterType.BEFORE_REDRAW, function() { -+ let [x, y] = icon.get_transformed_position(); -+ clickProxy.set_position(x, y); -+ return false; -+ }); -+ let timerId = 0; -+ let i = 0; -+ timerId = Mainloop.timeout_add(500, function() { -+ icon.set_size(icon.width == iconSize ? iconSize - 1 : iconSize, -+ icon.width == iconSize ? iconSize - 1 : iconSize); -+ i++; -+ if (i == 2) -+ Mainloop.source_remove(timerId); -+ }); -+} -+ -+function onTrayIconRemoved(o, icon) { -+ let parent = icon.get_parent(); -+ parent.destroy(); -+ icon.destroy(); -+ icons.splice(icons.indexOf(icon), 1); -+} -+ -+function createTray() { -+ sysTray = new Shell.TrayManager(); -+ sysTray.connect('tray-icon-added', onTrayIconAdded); -+ sysTray.connect('tray-icon-removed', onTrayIconRemoved); -+ sysTray.manage_screen(global.screen, Main.panel.actor); -+} + -+function destroyTray() { -+ icons.forEach(icon => { icon.get_parent().destroy(); }); -+ icons = []; -+ -+ sysTray = null; -+ System.gc(); // force finalizing tray to unmanage screen -+} ++ let iconBin = new St.Widget({ ++ layout_manager: new Clutter.BinLayout() ++ }); ++ iconBin.add_actor(icon); ++ button.add_actor(iconBin); + -+function moveToTop() { -+ notificationDaemon._trayManager.disconnect(notificationDaemon._trayIconAddedId); -+ notificationDaemon._trayManager.disconnect(notificationDaemon._trayIconRemovedId); -+ trayAddedId = notificationDaemon._trayManager.connect('tray-icon-added', onTrayIconAdded); -+ trayRemovedId = notificationDaemon._trayManager.connect('tray-icon-removed', onTrayIconRemoved); ++ this._icons.push(icon); + -+ notificationDaemon._getSource = createSource; ++ button.connect('button-release-event', (actor, event) => { ++ icon.click(event); ++ }); ++ button.connect('key-press-event', (actor, event) => { ++ icon.click(event); ++ }); + -+ let toDestroy = []; -+ if (notificationDaemon._sources) { -+ for (let i = 0; i < notificationDaemon._sources.length; i++) { -+ let source = notificationDaemon._sources[i]; -+ if (!source.trayIcon) -+ continue; -+ let parent = source.trayIcon.get_parent(); -+ parent.remove_actor(source.trayIcon); -+ onTrayIconAdded(this, source.trayIcon, source.initialTitle); -+ toDestroy.push(source); -+ } -+ } -+ else { -+ for (let i = 0; i < notificationDaemon._iconBox.get_n_children(); i++) { -+ let button = notificationDaemon._iconBox.get_child_at_index(i); -+ let icon = button.child; -+ button.remove_actor(icon); -+ onTrayIconAdded(this, icon, ''); -+ toDestroy.push(button); -+ } -+ } ++ icon.connect('destroy', () => { ++ button.destroy(); ++ }); + -+ for (let i = 0; i < toDestroy.length; i++) { -+ toDestroy[i].destroy(); ++ let role = wmClass || `${icon}`; ++ Main.panel.addToStatusArea(role, button); + } -+} + -+function moveToTray() { -+ if (trayAddedId != 0) { -+ notificationDaemon._trayManager.disconnect(trayAddedId); -+ trayAddedId = 0; ++ _onTrayIconRemoved(o, icon) { ++ let parent = icon.get_parent(); ++ parent.destroy(); ++ this._icons.splice(this._icons.indexOf(icon), 1); + } + -+ if (trayRemovedId != 0) { -+ notificationDaemon._trayManager.disconnect(trayRemovedId); -+ trayRemovedId = 0; ++ enable() { ++ this._tray = new Shell.TrayManager(); ++ this._tray.connect('tray-icon-added', ++ this._onTrayIconAdded.bind(this)); ++ this._tray.connect('tray-icon-removed', ++ this._onTrayIconRemoved.bind(this)); ++ this._tray.manage_screen(Main.panel); + } + -+ notificationDaemon._trayIconAddedId = notificationDaemon._trayManager.connect('tray-icon-added', -+ Lang.bind(notificationDaemon, notificationDaemon._onTrayIconAdded)); -+ notificationDaemon._trayIconRemovedId = notificationDaemon._trayManager.connect('tray-icon-removed', -+ Lang.bind(notificationDaemon, notificationDaemon._onTrayIconRemoved)); -+ -+ notificationDaemon._getSource = getSource; ++ disable() { ++ this._icons.forEach(icon => icon.get_parent().destroy()); ++ this._icons = []; + -+ for (let i = 0; i < icons.length; i++) { -+ let icon = icons[i]; -+ let parent = icon.get_parent(); -+ if (icon._clicked) { -+ icon.disconnect(icon._clicked); -+ } -+ icon._clicked = undefined; -+ if (icon._proxyAlloc) { -+ Main.panel._rightBox.disconnect(icon._proxyAlloc); -+ } -+ icon._clickProxy.destroy(); -+ parent.remove_actor(icon); -+ parent.destroy(); -+ notificationDaemon._onTrayIconAdded(notificationDaemon, icon); ++ this._tray = null; ++ System.gc(); // force finalizing tray to unmanage screen + } -+ -+ icons = []; +} + -+function disable() { -+ if (notificationDaemon) -+ moveToTray(); -+ else -+ destroyTray(); ++function init() { ++ return new SysTray(); +} diff --git a/extensions/top-icons/meson.build b/extensions/top-icons/meson.build new file mode 100644 @@ -281,58 +152,60 @@ index 0000000..25134b6 @@ -0,0 +1 @@ +/* This extensions requires no special styling */ diff --git a/meson.build b/meson.build -index 40a8275..c16bde1 100644 +index b987f2d..6050c32 100644 --- a/meson.build +++ b/meson.build -@@ -54,6 +54,7 @@ all_extensions += [ +@@ -50,6 +50,7 @@ all_extensions = default_extensions + all_extensions += [ 'auto-move-windows', - 'example', 'native-window-placement', + 'top-icons', 'user-theme' ] -- -2.20.1 +2.21.0 -From 6bbc576ed2c697b9da688fe19febff9c6ac7163f Mon Sep 17 00:00:00 2001 +From 3035a9e961fdae1bd242664130fbf55ce67131ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 20 May 2015 18:05:41 +0200 -Subject: [PATCH 2/6] Add dash-to-dock extension +Subject: [PATCH 2/8] Add dash-to-dock extension --- - extensions/dash-to-dock/Settings.ui | 3332 +++++++++++++++++ - extensions/dash-to-dock/appIconIndicators.js | 1124 ++++++ - extensions/dash-to-dock/appIcons.js | 1171 ++++++ - extensions/dash-to-dock/convenience.js | 74 + - extensions/dash-to-dock/dash.js | 1175 ++++++ - extensions/dash-to-dock/docking.js | 1925 ++++++++++ + extensions/dash-to-dock/Settings.ui | 3335 +++++++++++++++++ + extensions/dash-to-dock/appIconIndicators.js | 1102 ++++++ + extensions/dash-to-dock/appIcons.js | 1172 ++++++ + extensions/dash-to-dock/dash.js | 1171 ++++++ + extensions/dash-to-dock/docking.js | 1853 +++++++++ extensions/dash-to-dock/extension.js | 23 + - extensions/dash-to-dock/intellihide.js | 323 ++ - extensions/dash-to-dock/launcherAPI.js | 244 ++ + extensions/dash-to-dock/intellihide.js | 321 ++ + extensions/dash-to-dock/launcherAPI.js | 239 ++ extensions/dash-to-dock/media/glossy.svg | 139 + + .../media/highlight_stacked_bg.svg | 82 + + .../media/highlight_stacked_bg_h.svg | 82 + extensions/dash-to-dock/media/logo.svg | 528 +++ extensions/dash-to-dock/meson.build | 23 + extensions/dash-to-dock/metadata.json.in | 12 + ....shell.extensions.dash-to-dock.gschema.xml | 540 +++ - extensions/dash-to-dock/prefs.js | 868 +++++ - extensions/dash-to-dock/stylesheet.css | 109 + - extensions/dash-to-dock/theming.js | 672 ++++ - extensions/dash-to-dock/utils.js | 255 ++ - extensions/dash-to-dock/windowPreview.js | 630 ++++ + extensions/dash-to-dock/prefs.js | 861 +++++ + extensions/dash-to-dock/stylesheet.css | 175 + + extensions/dash-to-dock/theming.js | 569 +++ + extensions/dash-to-dock/utils.js | 258 ++ + extensions/dash-to-dock/windowPreview.js | 578 +++ meson.build | 1 + - 20 files changed, 13168 insertions(+) + 21 files changed, 13064 insertions(+) create mode 100644 extensions/dash-to-dock/Settings.ui create mode 100644 extensions/dash-to-dock/appIconIndicators.js create mode 100644 extensions/dash-to-dock/appIcons.js - create mode 100644 extensions/dash-to-dock/convenience.js create mode 100644 extensions/dash-to-dock/dash.js create mode 100644 extensions/dash-to-dock/docking.js create mode 100644 extensions/dash-to-dock/extension.js create mode 100644 extensions/dash-to-dock/intellihide.js create mode 100644 extensions/dash-to-dock/launcherAPI.js create mode 100644 extensions/dash-to-dock/media/glossy.svg + create mode 100644 extensions/dash-to-dock/media/highlight_stacked_bg.svg + create mode 100644 extensions/dash-to-dock/media/highlight_stacked_bg_h.svg create mode 100644 extensions/dash-to-dock/media/logo.svg create mode 100644 extensions/dash-to-dock/meson.build create mode 100644 extensions/dash-to-dock/metadata.json.in @@ -345,10 +218,10 @@ Subject: [PATCH 2/6] Add dash-to-dock extension diff --git a/extensions/dash-to-dock/Settings.ui b/extensions/dash-to-dock/Settings.ui new file mode 100644 -index 0000000..2b164a8 +index 0000000..c141eff --- /dev/null +++ b/extensions/dash-to-dock/Settings.ui -@@ -0,0 +1,3332 @@ +@@ -0,0 +1,3335 @@ + + + @@ -436,6 +309,7 @@ index 0000000..2b164a8 + Minimize or overview + Show window previews + Minimize or show previews ++ Focus or show previews + Quit + + @@ -508,6 +382,7 @@ index 0000000..2b164a8 + Minimize or overview + Show window previews + Minimize or show previews ++ Focus or show previews + Quit + + @@ -580,6 +455,7 @@ index 0000000..2b164a8 + Minimize or overview + Show window previews + Minimize or show previews ++ Focus or show previews + Quit + + @@ -1940,6 +1816,7 @@ index 0000000..2b164a8 + Minimize or overview + Show window previews + Minimize or show previews ++ Focus or show previews + + + @@ -2511,7 +2388,6 @@ index 0000000..2b164a8 + + Default + Fixed -+ Adaptive + Dynamic + + @@ -3200,7 +3076,7 @@ index 0000000..2b164a8 + 32 + + -+ False ++ True + center + 12 + @@ -3683,17 +3559,16 @@ index 0000000..2b164a8 + diff --git a/extensions/dash-to-dock/appIconIndicators.js b/extensions/dash-to-dock/appIconIndicators.js new file mode 100644 -index 0000000..6eb0706 +index 0000000..ddff512 --- /dev/null +++ b/extensions/dash-to-dock/appIconIndicators.js -@@ -0,0 +1,1124 @@ +@@ -0,0 +1,1102 @@ +const Cogl = imports.gi.Cogl; +const Cairo = imports.cairo; +const Clutter = imports.gi.Clutter; +const GdkPixbuf = imports.gi.GdkPixbuf +const Gio = imports.gi.Gio; +const Gtk = imports.gi.Gtk; -+const Lang = imports.lang; +const Pango = imports.gi.Pango; +const Shell = imports.gi.Shell; +const St = imports.gi.St; @@ -3724,11 +3599,9 @@ index 0000000..6eb0706 + * obtained by composing the desired classes below based on the settings. + * + */ -+var AppIconIndicator = new Lang.Class({ ++var AppIconIndicator = class DashToDock_AppIconIndicator { + -+ Name: 'DashToDock.AppIconIndicator', -+ -+ _init: function(source, settings) { ++ constructor(source, settings) { + this._indicators = []; + + // Unity indicators always enabled for now @@ -3747,7 +3620,7 @@ index 0000000..6eb0706 + + switch (runningIndicatorStyle) { + case RunningIndicatorStyle.DEFAULT: -+ runningIndicator = new RunningIndicatorBase(source, settings); ++ runningIndicator = new RunningIndicatorDefault(source, settings); + break; + + case RunningIndicatorStyle.DOTS: @@ -3783,62 +3656,56 @@ index 0000000..6eb0706 + } + + this._indicators.push(runningIndicator); -+ }, ++ } + -+ update: function() { ++ update() { + for (let i=0; i { ++ this._signalsHandler.destroy(); ++ }); ++ } + -+ update: function() { -+ }, ++ update() { ++ } + -+ destroy: function() { ++ destroy() { + this._source.actor.disconnect(this._sourceDestroyId); + this._signalsHandler.destroy(); + } -+}); ++}; + +/* + * A base indicator class for running style, from which all other EunningIndicators should derive, + * providing some basic methods, variables definitions and their update, css style classes handling. + * + */ -+const RunningIndicatorBase = new Lang.Class({ -+ -+ Name: 'DashToDock.RunningIndicatorBase', -+ Extends: IndicatorBase, ++var RunningIndicatorBase = class DashToDock_RunningIndicatorBase extends IndicatorBase { + -+ _init: function(source, settings) { -+ -+ this.parent(source, settings) ++ constructor(source, settings) { ++ super(source, settings) + + this._side = Utils.getPosition(this._settings); + this._nWindows = 0; @@ -3848,9 +3715,9 @@ index 0000000..6eb0706 + // These statuses take into account the workspace/monitor isolation + this._isFocused = false; + this._isRunning = false; -+ }, ++ } + -+ update: function() { ++ update() { + // Limit to 1 to MAX_WINDOWS_CLASSES windows classes + this._nWindows = Math.min(this._source.getInterestingWindows().length, MAX_WINDOWS_CLASSES); + @@ -3871,9 +3738,9 @@ index 0000000..6eb0706 + this._updateCounterClass(); + this._updateFocusClass(); + this._updateDefaultDot(); -+ }, ++ } + -+ _updateCounterClass: function() { ++ _updateCounterClass() { + for (let i = 1; i <= MAX_WINDOWS_CLASSES; i++) { + let className = 'running' + i; + if (i != this._nWindows) @@ -3881,33 +3748,33 @@ index 0000000..6eb0706 + else + this._source.actor.add_style_class_name(className); + } -+ }, ++ } + -+ _updateFocusClass: function() { ++ _updateFocusClass() { + if (this._isFocused) + this._source.actor.add_style_class_name('focused'); + else + this._source.actor.remove_style_class_name('focused'); -+ }, ++ } + -+ _updateDefaultDot: function() { ++ _updateDefaultDot() { + if (this._isRunning) + this._source._dot.show(); + else + this._source._dot.hide(); -+ }, ++ } + -+ _hideDefaultDot: function() { ++ _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: function() { ++ _restoreDefaultDot() { + this._source._dot.opacity = 255; -+ }, ++ } + -+ _enableBacklight: function() { ++ _enableBacklight() { + + let colorPalette = this._dominantColorExtractor._getColorPalette(); + @@ -3930,31 +3797,42 @@ index 0000000..6eb0706 + 'background-gradient-end: ' + colorPalette.darker + ';' + ); + -+ }, ++ } + -+ _disableBacklight: function() { ++ _disableBacklight() { + this._source._iconContainer.set_style(null); -+ }, ++ } + -+ destroy: function() { -+ this.parent(); ++ 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 { + -+const RunningIndicatorDots = new Lang.Class({ ++ constructor(source, settings) { ++ super(source, settings); ++ this._source.actor.add_style_class_name('default'); ++ } + -+ Name: 'DashToDock.RunningIndicatorDots', -+ Extends: RunningIndicatorBase, ++ destory() { ++ this._source.actor.remove_style_class_name('default'); ++ super.destroy(); ++ } ++}; + -+ _init: function(source, settings) { ++var RunningIndicatorDots = class DashToDock_RunningIndicatorDots extends RunningIndicatorBase { + -+ this.parent(source, settings) ++ constructor(source, settings) { ++ super(source, settings) + + this._hideDefaultDot(); + @@ -3989,7 +3867,7 @@ index 0000000..6eb0706 + + this._area.set_transform(m); + -+ this._area.connect('repaint', Lang.bind(this, this._updateIndicator)); ++ this._area.connect('repaint', this._updateIndicator.bind(this)); + this._source._iconContainer.add_child(this._area); + + let keys = ['custom-theme-running-dots-color', @@ -4003,21 +3881,19 @@ index 0000000..6eb0706 + this._signalsHandler.add([ + this._settings, + 'changed::' + key, -+ Lang.bind(this, this.update) ++ 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 -+ let path = imports.misc.extensionUtils.getCurrentExtension().path; -+ this._glossyBackgroundStyle = 'background-image: url(\'' + path + '/media/glossy.svg\');' + -+ 'background-size: contain;'; -+ -+ }, ++ this._glossyBackgroundStyle = 'background-image: url(\'' + Me.path + '/media/glossy.svg\');' + ++ 'background-size: contain;'; ++ } + -+ update: function() { -+ this.parent(); ++ update() { ++ super.update(); + + // Enable / Disable the backlight of running apps + if (!this._settings.get_boolean('apply-custom-theme') && this._settings.get_boolean('unity-backlit-items')) { @@ -4033,9 +3909,9 @@ index 0000000..6eb0706 + + if (this._area) + this._area.queue_repaint(); -+ }, ++ } + -+ _computeStyle: function() { ++ _computeStyle() { + + let [width, height] = this._area.get_surface_size(); + this._width = height; @@ -4088,9 +3964,9 @@ index 0000000..6eb0706 + 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: function() { ++ _updateIndicator() { + + let area = this._area; + let cr = this._area.get_context(); @@ -4098,9 +3974,9 @@ index 0000000..6eb0706 + this._computeStyle(); + this._drawIndicator(cr); + cr.$dispose(); -+ }, ++ } + -+ _drawIndicator: function(cr) { ++ _drawIndicator(cr) { + // Draw the required numbers of dots + let n = this._nWindows; + @@ -4117,23 +3993,19 @@ index 0000000..6eb0706 + cr.strokePreserve(); + Clutter.cairo_set_source_color(cr, this._bodyColor); + cr.fill(); -+ }, ++ } + -+ destroy: function() { -+ this.parent(); ++ destroy() { + this._area.destroy(); ++ super.destroy(); + } -+ -+}); ++}; + +// Adapted from dash-to-panel by Jason DeRose +// https://github.com/jderose9/dash-to-panel -+const RunningIndicatorCiliora = new Lang.Class({ -+ -+ Name: 'DashToDock.RunningIndicatorCiliora', -+ Extends: RunningIndicatorDots, ++var RunningIndicatorCiliora = class DashToDock_RunningIndicatorCiliora extends RunningIndicatorDots { + -+ _drawIndicator: function(cr) { ++ _drawIndicator(cr) { + if (this._isRunning) { + + let size = Math.max(this._width/20, this._borderWidth); @@ -4161,16 +4033,13 @@ index 0000000..6eb0706 + cr.fill(); + } + } -+}); ++}; + +// Adapted from dash-to-panel by Jason DeRose +// https://github.com/jderose9/dash-to-panel -+const RunningIndicatorSegmented = new Lang.Class({ ++var RunningIndicatorSegmented = class DashToDock_RunningIndicatorSegmented extends RunningIndicatorDots { + -+ Name: 'DashToDock.RunningIndicatorSegmented', -+ Extends: RunningIndicatorDots, -+ -+ _drawIndicator: function(cr) { ++ _drawIndicator(cr) { + if (this._isRunning) { + let size = Math.max(this._width/20, this._borderWidth); + let spacing = Math.ceil(this._width/18); // separation between the dots @@ -4196,16 +4065,13 @@ index 0000000..6eb0706 + cr.fill() + } + } -+}); ++}; + +// Adapted from dash-to-panel by Jason DeRose +// https://github.com/jderose9/dash-to-panel -+const RunningIndicatorSolid = new Lang.Class({ -+ -+ Name: 'DashToDock.RunningIndicatorSolid', -+ Extends: RunningIndicatorDots, ++var RunningIndicatorSolid = class DashToDock_RunningIndicatorSolid extends RunningIndicatorDots { + -+ _drawIndicator: function(cr) { ++ _drawIndicator(cr) { + if (this._isRunning) { + + let size = Math.max(this._width/20, this._borderWidth); @@ -4228,16 +4094,13 @@ index 0000000..6eb0706 + + } + } -+}); ++}; + +// Adapted from dash-to-panel by Jason DeRose +// https://github.com/jderose9/dash-to-panel -+const RunningIndicatorSquares = new Lang.Class({ ++var RunningIndicatorSquares = class DashToDock_RunningIndicatorSquares extends RunningIndicatorDots { + -+ Name: 'DashToDock.RunningIndicatorSquares', -+ Extends: RunningIndicatorDots, -+ -+ _drawIndicator: function(cr) { ++ _drawIndicator(cr) { + if (this._isRunning) { + let size = Math.max(this._width/11, this._borderWidth); + let padding = this._borderWidth; @@ -4257,16 +4120,13 @@ index 0000000..6eb0706 + cr.fill(); + } + } -+}); ++} + +// Adapted from dash-to-panel by Jason DeRose +// https://github.com/jderose9/dash-to-panel -+const RunningIndicatorDashes = new Lang.Class({ -+ -+ Name: 'DashToDock.RunningIndicatorDashes', -+ Extends: RunningIndicatorDots, ++var RunningIndicatorDashes = class DashToDock_RunningIndicatorDashes extends RunningIndicatorDots { + -+ _drawIndicator: function(cr) { ++ _drawIndicator(cr) { + if (this._isRunning) { + let size = Math.max(this._width/20, this._borderWidth); + let padding = this._borderWidth; @@ -4288,21 +4148,23 @@ index 0000000..6eb0706 + cr.fill(); + } + } -+}); ++} + +// Adapted from dash-to-panel by Jason DeRose +// https://github.com/jderose9/dash-to-panel -+const RunningIndicatorMetro = new Lang.Class({ ++var RunningIndicatorMetro = class DashToDock_RunningIndicatorMetro extends RunningIndicatorDots { + -+ Name: 'DashToDock.RunningIndicatorMetro', -+ Extends: RunningIndicatorDots, -+ -+ _init: function(source, settings) { -+ this.parent(source, settings); ++ constructor(source, settings) { ++ super(source, settings); + this._source.actor.add_style_class_name('metro'); -+ }, ++ } ++ ++ destroy() { ++ this._source.actor.remove_style_class_name('metro'); ++ super.destroy(); ++ } + -+ _drawIndicator: function(cr) { ++ _drawIndicator(cr) { + if (this._isRunning) { + let size = Math.max(this._width/20, this._borderWidth); + let padding = 0; @@ -4340,24 +4202,17 @@ index 0000000..6eb0706 + cr.fill(); + } + } -+ }, -+ -+ destroy: function() { -+ this.parent(); -+ this._source.actor.remove_style_class_name('metro'); + } -+}); ++} + +/* + * Unity like notification and progress indicators + */ -+const UnityIndicator = new Lang.Class({ -+ Name: 'DashToDock.UnityIndicator', -+ Extends: IndicatorBase, ++var UnityIndicator = class DashToDock_UnityIndicator extends IndicatorBase { + -+ _init: function(source, settings) { ++ constructor(source, settings) { + -+ this.parent(source, settings); ++ super(source, settings); + + this._notificationBadgeLabel = new St.Label(); + this._notificationBadgeBin = new St.Bin({ @@ -4370,44 +4225,44 @@ index 0000000..6eb0706 + this._notificationBadgeBin.hide(); + + this._source._iconContainer.add_child(this._notificationBadgeBin); -+ this._source._iconContainer.connect('allocation-changed', Lang.bind(this, this.updateNotificationBadge)); ++ this._source._iconContainer.connect('allocation-changed', this.updateNotificationBadge.bind(this)); + + this._remoteEntries = []; + this._source.remoteModel.lookupById(this._source.app.id).forEach( -+ Lang.bind(this, function(entry) { ++ (entry) => { + this.insertEntryRemote(entry); -+ }) ++ } + ); + + this._signalsHandler.add([ + this._source.remoteModel, + 'entry-added', -+ Lang.bind(this, this._onLauncherEntryRemoteAdded) ++ this._onLauncherEntryRemoteAdded.bind(this) + ], [ + this._source.remoteModel, + 'entry-removed', -+ Lang.bind(this, this._onLauncherEntryRemoteRemoved) ++ this._onLauncherEntryRemoteRemoved.bind(this) + ]) -+ }, ++ } + -+ _onLauncherEntryRemoteAdded: function(remoteModel, entry) { ++ _onLauncherEntryRemoteAdded(remoteModel, entry) { + if (!entry || !entry.appId()) + return; + if (this._source && this._source.app && this._source.app.id == entry.appId()) { + this.insertEntryRemote(entry); + } -+ }, ++ } + -+ _onLauncherEntryRemoteRemoved: function(remoteModel, entry) { ++ _onLauncherEntryRemoteRemoved(remoteModel, entry) { + if (!entry || !entry.appId()) + return; + + if (this._source && this._source.app && this._source.app.id == entry.appId()) { + this.removeEntryRemote(entry); + } -+ }, ++ } + -+ updateNotificationBadge: function() { ++ updateNotificationBadge() { + let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; + let [minWidth, natWidth] = this._source._iconContainer.get_preferred_width(-1); + let logicalNatWidth = natWidth / scaleFactor; @@ -4421,9 +4276,9 @@ index 0000000..6eb0706 + + this._notificationBadgeBin.width = Math.round(logicalNatWidth - margin_left); + this._notificationBadgeLabel.clutter_text.ellipsize = Pango.EllipsizeMode.MIDDLE; -+ }, ++ } + -+ _notificationBadgeCountToText: function(count) { ++ _notificationBadgeCountToText(count) { + if (count <= 9999) { + return count.toString(); + } else if (count < 1e5) { @@ -4442,50 +4297,50 @@ index 0000000..6eb0706 + let billions = count / 1e9; + return billions.toFixed(1).toString() + "B"; + } -+ }, ++ } + -+ setNotificationBadge: function(count) { ++ setNotificationBadge(count) { + this._notificationBadgeCount = count; + let text = this._notificationBadgeCountToText(count); + this._notificationBadgeLabel.set_text(text); -+ }, ++ } + -+ toggleNotificationBadge: function(activate) { ++ toggleNotificationBadge(activate) { + if (activate && this._notificationBadgeCount > 0) { + this.updateNotificationBadge(); + this._notificationBadgeBin.show(); + } + else + this._notificationBadgeBin.hide(); -+ }, ++ } + -+ _showProgressOverlay: function() { ++ _showProgressOverlay() { + if (this._progressOverlayArea) { + this._updateProgressOverlay(); + return; + } + + this._progressOverlayArea = new St.DrawingArea({x_expand: true, y_expand: true}); -+ this._progressOverlayArea.connect('repaint', Lang.bind(this, function() { ++ this._progressOverlayArea.connect('repaint', () => { + this._drawProgressOverlay(this._progressOverlayArea); -+ })); ++ }); + + this._source._iconContainer.add_child(this._progressOverlayArea); + this._updateProgressOverlay(); -+ }, ++ } + -+ _hideProgressOverlay: function() { ++ _hideProgressOverlay() { + if (this._progressOverlayArea) + this._progressOverlayArea.destroy(); + this._progressOverlayArea = null; -+ }, ++ } + -+ _updateProgressOverlay: function() { ++ _updateProgressOverlay() { + if (this._progressOverlayArea) + this._progressOverlayArea.queue_repaint(); -+ }, ++ } + -+ _drawProgressOverlay: function(area) { ++ _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(); @@ -4539,31 +4394,31 @@ index 0000000..6eb0706 + Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill); + + cr.$dispose(); -+ }, ++ } + -+ setProgress: function(progress) { ++ setProgress(progress) { + this._progress = Math.min(Math.max(progress, 0.0), 1.0); + this._updateProgressOverlay(); -+ }, ++ } + -+ toggleProgressOverlay: function(activate) { ++ toggleProgressOverlay(activate) { + if (activate) { + this._showProgressOverlay(); + } + else { + this._hideProgressOverlay(); + } -+ }, ++ } + -+ insertEntryRemote: function(remote) { ++ insertEntryRemote(remote) { + if (!remote || this._remoteEntries.indexOf(remote) !== -1) + return; + + this._remoteEntries.push(remote); + this._selectEntryRemote(remote); -+ }, ++ } + -+ removeEntryRemote: function(remote) { ++ removeEntryRemote(remote) { + if (!remote || this._remoteEntries.indexOf(remote) == -1) + return; + @@ -4577,9 +4432,9 @@ index 0000000..6eb0706 + this.setProgress(0); + this.toggleProgressOverlay(false); + } -+ }, ++ } + -+ _selectEntryRemote: function(remote) { ++ _selectEntryRemote(remote) { + if (!remote) + return; + @@ -4589,27 +4444,27 @@ index 0000000..6eb0706 + [ + remote, + 'count-changed', -+ Lang.bind(this, (remote, value) => { ++ (remote, value) => { + this.setNotificationBadge(value); -+ }) ++ } + ], [ + remote, + 'count-visible-changed', -+ Lang.bind(this, (remote, value) => { ++ (remote, value) => { + this.toggleNotificationBadge(value); -+ }) ++ } + ], [ + remote, + 'progress-changed', -+ Lang.bind(this, (remote, value) => { ++ (remote, value) => { + this.setProgress(value); -+ }) ++ } + ], [ + remote, + 'progress-visible-changed', -+ Lang.bind(this, (remote, value) => { ++ (remote, value) => { + this.toggleProgressOverlay(value); -+ }) ++ } + ]); + + this.setNotificationBadge(remote.count()); @@ -4617,7 +4472,7 @@ index 0000000..6eb0706 + this.setProgress(remote.progress()); + this.toggleProgressOverlay(remote.progressVisible()); + } -+}); ++} + + +// We need an icons theme object, this is the only way I managed to get @@ -4637,17 +4492,16 @@ index 0000000..6eb0706 + +// Compute dominant color frim the app icon. +// The color is cached for efficiency. -+const DominantColorExtractor = new Lang.Class({ -+ Name: 'DashToDock.DominantColorExtractor', ++var DominantColorExtractor = class DashToDock_DominantColorExtractor { + -+ _init: function(app) { ++ constructor(app) { + this._app = app; -+ }, ++ } + + /** + * Try to get the pixel buffer for the current icon, if not fail gracefully + */ -+ _getIconPixBuf: function() { ++ _getIconPixBuf() { + let iconTexture = this._app.create_icon_texture(16); + + if (themeLoader === null) { @@ -4680,7 +4534,7 @@ index 0000000..6eb0706 + return icon_info.load_icon(); + else + return null; -+ }, ++ } + + /** + * The backlight color choosing algorithm was mostly ported to javascript from the @@ -4688,7 +4542,7 @@ index 0000000..6eb0706 + * https://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/launcher/LauncherIcon.cpp + * so it more or less works the same way. + */ -+ _getColorPalette: function() { ++ _getColorPalette() { + if (iconCacheMap.get(this._app.get_id())) { + // We already know the answer + return iconCacheMap.get(this._app.get_id()); @@ -4781,7 +4635,7 @@ index 0000000..6eb0706 + iconCacheMap.set(this._app.get_id(), backgroundColor); + + return backgroundColor; -+ }, ++ } + + /** + * Downsample large icons before scanning for the backlight color to @@ -4794,7 +4648,7 @@ index 0000000..6eb0706 + * + * @return []; + */ -+ _resamplePixels: function (pixels, resampleX, resampleY) { ++ _resamplePixels (pixels, resampleX, resampleY) { + let resampledPixels = []; + // computing the limit outside the for (where it would be repeated at each iteration) + // for performance reasons @@ -4809,14 +4663,14 @@ index 0000000..6eb0706 + } + + return resampledPixels; -+ }, -+}) ++ } ++}; diff --git a/extensions/dash-to-dock/appIcons.js b/extensions/dash-to-dock/appIcons.js new file mode 100644 -index 0000000..ef9c6e1 +index 0000000..3b28304 --- /dev/null +++ b/extensions/dash-to-dock/appIcons.js -@@ -0,0 +1,1171 @@ +@@ -0,0 +1,1172 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; @@ -4825,7 +4679,6 @@ index 0000000..ef9c6e1 +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; -+const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; @@ -4865,7 +4718,8 @@ index 0000000..ef9c6e1 + MINIMIZE_OR_OVERVIEW: 4, + PREVIEWS: 5, + MINIMIZE_OR_PREVIEWS: 6, -+ QUIT: 7 ++ FOCUS_OR_PREVIEWS: 7, ++ QUIT: 8, +}; + +const scrollAction = { @@ -4893,12 +4747,12 @@ index 0000000..ef9c6e1 + * - Update minimization animation target + * - Update menu if open on windows change + */ -+var MyAppIcon = new Lang.Class({ -+ Name: 'DashToDock.AppIcon', -+ Extends: AppDisplay.AppIcon, ++var MyAppIcon = class DashToDock_AppIcon extends AppDisplay.AppIcon { + + // settings are required inside. -+ _init: function(settings, remoteModel, app, monitorIndex, iconParams) { ++ constructor(settings, remoteModel, app, monitorIndex, iconParams) { ++ super(app, iconParams); ++ + // a prefix is required to avoid conflicting with the parent class variable + this._dtdSettings = settings; + this.monitorIndex = monitorIndex; @@ -4906,8 +4760,6 @@ index 0000000..ef9c6e1 + this.remoteModel = remoteModel; + this._indicator = null; + -+ this.parent(app, iconParams); -+ + this._updateIndicatorStyle(); + + // Monitor windows-changes instead of app state. @@ -4918,11 +4770,9 @@ index 0000000..ef9c6e1 + } + + this._windowsChangedId = this.app.connect('windows-changed', -+ Lang.bind(this, -+ this.onWindowsChanged)); ++ this.onWindowsChanged.bind(this)); + this._focusAppChangeId = tracker.connect('notify::focus-app', -+ Lang.bind(this, -+ this._onFocusAppChanged)); ++ this._onFocusAppChanged.bind(this)); + + // 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 @@ -4933,9 +4783,9 @@ index 0000000..ef9c6e1 + Main.layoutManager.monitors.length > 1) { + this._signalsHandler.removeWithLabel('isolate-monitors'); + this._signalsHandler.addWithLabel('isolate-monitors', [ -+ global.screen, ++ global.display, + 'window-entered-monitor', -+ Lang.bind(this, this._onWindowEntered) ++ this._onWindowEntered.bind(this) + ]); + } + @@ -4950,23 +4800,23 @@ index 0000000..ef9c6e1 + this._signalsHandler.add([ + this._dtdSettings, + 'changed::' + key, -+ Lang.bind(this, this._updateIndicatorStyle) ++ this._updateIndicatorStyle.bind(this) + ]); + }, this); + -+ this._dtdSettings.connect('changed::scroll-action', Lang.bind(this, function() { ++ this._dtdSettings.connect('changed::scroll-action', () => { + this._optionalScrollCycleWindows(); -+ })); ++ }); + this._optionalScrollCycleWindows(); + + this._numberOverlay(); + + this._previewMenuManager = null; + this._previewMenu = null; -+ }, ++ } + -+ _onDestroy: function() { -+ this.parent(); ++ _onDestroy() { ++ super._onDestroy(); + + // This is necessary due to an upstream bug + // https://bugzilla.gnome.org/show_bug.cgi?id=757556 @@ -4989,10 +4839,10 @@ index 0000000..ef9c6e1 + + if (this._scrollEventHandler) + this.actor.disconnect(this._scrollEventHandler); -+ }, ++ } + + // TOOD Rename this function -+ _updateIndicatorStyle: function() { ++ _updateIndicatorStyle() { + + if (this._indicator !== null) { + this._indicator.destroy(); @@ -5000,15 +4850,15 @@ index 0000000..ef9c6e1 + } + this._indicator = new AppIconIndicators.AppIconIndicator(this, this._dtdSettings); + this._indicator.update(); -+ }, ++ } + -+ _onWindowEntered: function(metaScreen, monitorIndex, metaWin) { ++ _onWindowEntered(metaScreen, monitorIndex, metaWin) { + let app = Shell.WindowTracker.get_default().get_window_app(metaWin); + if (app && app.get_id() == this.app.get_id()) + this.onWindowsChanged(); -+ }, ++ } + -+ _optionalScrollCycleWindows: function() { ++ _optionalScrollCycleWindows() { + if (this._scrollEventHandler) { + this.actor.disconnect(this._scrollEventHandler); + this._scrollEventHandler = 0; @@ -5016,11 +4866,11 @@ index 0000000..ef9c6e1 + + let isEnabled = this._dtdSettings.get_enum('scroll-action') === scrollAction.CYCLE_WINDOWS; + if (!isEnabled) return; -+ this._scrollEventHandler = this.actor.connect('scroll-event', Lang.bind(this, -+ this.onScrollEvent)); -+ }, ++ this._scrollEventHandler = this.actor.connect('scroll-event', ++ this.onScrollEvent.bind(this)); ++ } + -+ onScrollEvent: function(actor, event) { ++ onScrollEvent(actor, event) { + + // 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 @@ -5034,9 +4884,9 @@ index 0000000..ef9c6e1 + if (this._optionalScrollCycleWindowsDeadTimeId > 0) + return false; + else -+ this._optionalScrollCycleWindowsDeadTimeId = Mainloop.timeout_add(250, Lang.bind(this, function() { ++ this._optionalScrollCycleWindowsDeadTimeId = Mainloop.timeout_add(250, () => { + this._optionalScrollCycleWindowsDeadTimeId = 0; -+ })); ++ }); + + let direction = null; + @@ -5073,21 +4923,21 @@ index 0000000..ef9c6e1 + else + this.app.activate(); + return true; -+ }, ++ } + -+ onWindowsChanged: function() { ++ onWindowsChanged() { + + if (this._menu && this._menu.isOpen) + this._menu.update(); + + this._indicator.update(); + this.updateIconGeometry(); -+ }, ++ } + + /** + * Update taraget for minimization animation + */ -+ updateIconGeometry: function() { ++ 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 @@ -5110,25 +4960,25 @@ index 0000000..ef9c6e1 + windows.forEach(function(w) { + w.set_icon_geometry(rect); + }); -+ }, ++ } + -+ _updateRunningStyle: function() { ++ _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: function() { ++ popupMenu() { + this._removeMenuTimeout(); + this.actor.fake_release(); + this._draggable.fakeRelease(); + + if (!this._menu) { + this._menu = new MyAppIconMenu(this, this._dtdSettings); -+ this._menu.connect('activate-window', Lang.bind(this, function(menu, window) { ++ this._menu.connect('activate-window', (menu, window) => { + this.activateWindow(window); -+ })); -+ this._menu.connect('open-state-changed', Lang.bind(this, function(menu, isPoppedUp) { ++ }); ++ this._menu.connect('open-state-changed', (menu, isPoppedUp) => { + if (!isPoppedUp) + this._onMenuPoppedDown(); + else { @@ -5146,10 +4996,10 @@ index 0000000..ef9c6e1 + this._menu.actor.style = ('max-height: ' + Math.round(workArea.height - additional_margin - verticalMargins) + 'px;' + + 'max-width: 400px'); + } -+ })); -+ let id = Main.overview.connect('hiding', Lang.bind(this, function() { ++ }); ++ let id = Main.overview.connect('hiding', () => { + this._menu.close(); -+ })); ++ }); + this._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); @@ -5165,13 +5015,13 @@ index 0000000..ef9c6e1 + this.emit('sync-tooltip'); + + return false; -+ }, ++ } + -+ _onFocusAppChanged: function() { ++ _onFocusAppChanged() { + this._indicator.update(); -+ }, ++ } + -+ activate: function(button) { ++ activate(button) { + let event = Clutter.get_current_event(); + let modifiers = event ? event.get_state() : 0; + let focusedApp = tracker.focus_app; @@ -5185,7 +5035,7 @@ index 0000000..ef9c6e1 + // Keep default behaviour: launch new window + // By calling the parent method I make it compatible + // with other extensions tweaking ctrl + click -+ this.parent(button); ++ super.activate(button); + return; + } + @@ -5278,6 +5128,17 @@ index 0000000..ef9c6e1 + this.app.activate(); + break; + ++ case clickAction.FOCUS_OR_PREVIEWS: ++ if (this.app == focusedApp && ++ (windows.length > 1 || modifiers || button != 1)) { ++ this._windowPreviews(); ++ } else { ++ // Activate the first window ++ let w = windows[0]; ++ Main.activateWindow(w); ++ } ++ break; ++ + case clickAction.LAUNCH: + this.launchNewWindow(); + break; @@ -5338,14 +5199,14 @@ index 0000000..ef9c6e1 + if(shouldHideOverview) { + Main.overview.hide(); + } -+ }, ++ } + -+ shouldShowTooltip: function() { ++ shouldShowTooltip() { + return this.actor.hover && (!this._menu || !this._menu.isOpen) && + (!this._previewMenu || !this._previewMenu.isOpen); -+ }, ++ } + -+ _windowPreviews: function() { ++ _windowPreviews() { + if (!this._previewMenu) { + this._previewMenuManager = new PopupMenu.PopupMenuManager(this); + @@ -5353,13 +5214,13 @@ index 0000000..ef9c6e1 + + this._previewMenuManager.addMenu(this._previewMenu); + -+ this._previewMenu.connect('open-state-changed', Lang.bind(this, function(menu, isPoppedUp) { ++ this._previewMenu.connect('open-state-changed', (menu, isPoppedUp) => { + if (!isPoppedUp) + this._onMenuPoppedDown(); -+ })); -+ let id = Main.overview.connect('hiding', Lang.bind(this, function() { ++ }); ++ let id = Main.overview.connect('hiding', () => { + this._previewMenu.close(); -+ })); ++ }); + this._previewMenu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); @@ -5372,12 +5233,12 @@ index 0000000..ef9c6e1 + 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: function(p) { ++ launchNewWindow(p) { + let appInfo = this.app.get_app_info(); + let actions = appInfo.list_actions(); + if (this.app.can_open_new_window()) { @@ -5409,9 +5270,9 @@ index 0000000..ef9c6e1 + else + this.app.activate(); + } -+ }, ++ } + -+ _numberOverlay: function() { ++ _numberOverlay() { + // Add label for a Hot-Key visual aid + this._numberOverlayLabel = new St.Label(); + this._numberOverlayBin = new St.Bin({ @@ -5425,9 +5286,9 @@ index 0000000..ef9c6e1 + + this._iconContainer.add_child(this._numberOverlayBin); + -+ }, ++ } + -+ updateNumberOverlay: function() { ++ 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. @@ -5442,26 +5303,26 @@ index 0000000..ef9c6e1 + 'border-radius: ' + this.icon.iconSize + 'px;' + + 'width: ' + size + 'px; height: ' + size +'px;' + ); -+ }, ++ } + -+ setNumberOverlay: function(number) { ++ setNumberOverlay(number) { + this._numberOverlayOrder = number; + this._numberOverlayLabel.set_text(number.toString()); -+ }, ++ } + -+ toggleNumberOverlay: function(activate) { ++ toggleNumberOverlay(activate) { + if (activate && this._numberOverlayOrder > -1) { + this.updateNumberOverlay(); + this._numberOverlayBin.show(); + } + else + this._numberOverlayBin.hide(); -+ }, ++ } + -+ _minimizeWindow: function(param) { ++ _minimizeWindow(param) { + // Param true make all app windows minimize + let windows = this.getInterestingWindows(); -+ let current_workspace = global.screen.get_active_workspace(); ++ 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()) { @@ -5472,11 +5333,11 @@ index 0000000..ef9c6e1 + break; + } + } -+ }, ++ } + + // By default only non minimized windows are activated. + // This activates all windows in the current workspace. -+ _activateAllWindows: function() { ++ _activateAllWindows() { + // First activate first window so workspace is switched if needed. + // We don't do this if isolation is on! + if (!this._dtdSettings.get_boolean('isolate-workspaces') && @@ -5485,7 +5346,7 @@ index 0000000..ef9c6e1 + + // then activate all other app windows in the current workspace + let windows = this.getInterestingWindows(); -+ let activeWorkspace = global.screen.get_active_workspace_index(); ++ let activeWorkspace = global.workspace_manager.get_active_workspace_index(); + + if (windows.length <= 0) + return; @@ -5498,16 +5359,16 @@ index 0000000..ef9c6e1 + activatedWindows++; + } + } -+ }, ++ } + + //This closes all windows of the app. -+ closeAllWindows: function() { ++ closeAllWindows() { + let windows = this.getInterestingWindows(); + for (let i = 0; i < windows.length; i++) + windows[i].delete(global.get_current_time()); -+ }, ++ } + -+ _cycleThroughWindows: function(reversed) { ++ _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; @@ -5544,9 +5405,9 @@ index 0000000..ef9c6e1 + let window = recentlyClickedAppWindows[index]; + + Main.activateWindow(window); -+ }, ++ } + -+ _resetRecentlyClickedApp: function() { ++ _resetRecentlyClickedApp() { + if (recentlyClickedAppLoopId > 0) + Mainloop.source_remove(recentlyClickedAppLoopId); + recentlyClickedAppLoopId=0; @@ -5556,14 +5417,14 @@ index 0000000..ef9c6e1 + recentlyClickedAppMonitor = -1; + + return false; -+ }, ++ } + + // Filter out unnecessary windows, for instance + // nautilus desktop window. -+ getInterestingWindows: function() { ++ getInterestingWindows() { + return getInterestingWindows(this.app, this._dtdSettings, this.monitorIndex); + } -+}); ++}; +/** + * Extend AppIconMenu + * @@ -5574,17 +5435,15 @@ index 0000000..ef9c6e1 + * - Add open windows thumbnails instead of list + * - update menu when application windows change + */ -+const MyAppIconMenu = new Lang.Class({ -+ Name: 'DashToDock.MyAppIconMenu', -+ Extends: AppDisplay.AppIconMenu, ++const MyAppIconMenu = class DashToDock_MyAppIconMenu extends AppDisplay.AppIconMenu { + -+ _init: function(source, settings) { ++ constructor(source, settings) { + let side = Utils.getPosition(settings); + + // Damm it, there has to be a proper way of doing this... + // As I can't call the parent parent constructor (?) passing the side + // parameter, I overwite what I need later -+ this.parent(source); ++ super(source); + + // Change the initialized side where required. + this._arrowSide = side; @@ -5592,9 +5451,9 @@ index 0000000..ef9c6e1 + this._boxPointer._userArrowSide = side; + + this._dtdSettings = settings; -+ }, ++ } + -+ _redisplay: function() { ++ _redisplay() { + this.removeAll(); + + if (this._dtdSettings.get_boolean('show-windows-preview')) { @@ -5613,13 +5472,13 @@ index 0000000..ef9c6e1 + if (this._source.app.can_open_new_window() && + actions.indexOf('new-window') == -1) { + this._newWindowMenuItem = this._appendMenuItem(_("New Window")); -+ this._newWindowMenuItem.connect('activate', Lang.bind(this, function() { ++ 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(); + } + @@ -5628,22 +5487,22 @@ index 0000000..ef9c6e1 + this._source.app.state == Shell.AppState.STOPPED && + actions.indexOf('activate-discrete-gpu') == -1) { + this._onDiscreteGpuMenuItem = this._appendMenuItem(_("Launch using Dedicated Graphics Card")); -+ this._onDiscreteGpuMenuItem.connect('activate', Lang.bind(this, function() { ++ this._onDiscreteGpuMenuItem.connect('activate', () => { + if (this._source.app.state == Shell.AppState.STOPPED) + this._source.animateLaunch(); + + this._source.app.launch(0, -1, true); + 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', Lang.bind(this, function(emitter, event) { ++ 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'); @@ -5655,23 +5514,23 @@ index 0000000..ef9c6e1 + + if (isFavorite) { + let item = this._appendMenuItem(_("Remove from Favorites")); -+ item.connect('activate', Lang.bind(this, function() { ++ 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', Lang.bind(this, function() { ++ 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._appendSeparator(); + let item = this._appendMenuItem(_("Show Details")); -+ item.connect('activate', Lang.bind(this, function() { ++ item.connect('activate', () => { + let id = this._source.app.get_id(); + let args = GLib.Variant.new('(ss)', [id, '']); + Gio.DBus.get(Gio.BusType.SESSION, null, @@ -5685,27 +5544,27 @@ index 0000000..ef9c6e1 + null, 0, -1, null, null); + Main.overview.hide(); + }); -+ })); ++ }); + } + } + + } else { -+ this.parent(); ++ super._redisplay(); + } + + // quit menu + this._appendSeparator(); + this._quitfromDashMenuItem = this._appendMenuItem(_("Quit")); -+ this._quitfromDashMenuItem.connect('activate', Lang.bind(this, function() { ++ 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: function() { ++ update() { + + if(this._dtdSettings.get_boolean('show-windows-preview')){ + @@ -5717,7 +5576,7 @@ index 0000000..ef9c6e1 + if (windows.length == 1) + this._quitfromDashMenuItem.label.set_text(_("Quit")); + else -+ this._quitfromDashMenuItem.label.set_text(_("Quit") + ' ' + windows.length + ' ' + _("Windows")); ++ this._quitfromDashMenuItem.label.set_text(_("Quit %d Windows").format(windows.length)); + + this._quitfromDashMenuItem.actor.show(); + @@ -5751,19 +5610,19 @@ index 0000000..ef9c6e1 + } + + // Update separators -+ this._getMenuItems().forEach(Lang.bind(this, this._updateSeparatorVisibility)); ++ this._getMenuItems().forEach(this._updateSeparatorVisibility.bind(this)); + } + + -+ }, ++ } + -+ _populateAllWindowMenu: function(windows) { ++ _populateAllWindowMenu(windows) { + + this._allWindowsMenuItem.menu.removeAll(); + + if (windows.length > 0) { + -+ let activeWorkspace = global.screen.get_active_workspace(); ++ let activeWorkspace = global.workspace_manager.get_active_workspace(); + let separatorShown = windows[0].get_workspace() != activeWorkspace; + + for (let i = 0; i < windows.length; i++) { @@ -5775,19 +5634,19 @@ index 0000000..ef9c6e1 + + let item = new WindowPreview.WindowPreviewMenuItem(window); + this._allWindowsMenuItem.menu.addMenuItem(item); -+ item.connect('activate', Lang.bind(this, function() { ++ 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', Lang.bind(this, function() { ++ 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); -+ })); ++ }); + } + } -+ }, -+}); ++ } ++}; +Signals.addSignalMethods(MyAppIconMenu.prototype); + +// Filter out unnecessary windows, for instance @@ -5801,7 +5660,7 @@ index 0000000..ef9c6e1 + // that are not in the current workspace + if (settings.get_boolean('isolate-workspaces')) + windows = windows.filter(function(w) { -+ return w.get_workspace().index() == global.screen.get_active_workspace_index(); ++ return w.get_workspace().index() == global.workspace_manager.get_active_workspace_index(); + }); + + if (settings.get_boolean('isolate-monitors')) @@ -5825,10 +5684,8 @@ index 0000000..ef9c6e1 + * + */ + -+ var ShowAppsIconWrapper = new Lang.Class({ -+ Name: 'DashToDock.ShowAppsIconWrapper', -+ -+ _init: function(settings) { ++var ShowAppsIconWrapper = class DashToDock_ShowAppsIconWrapper { ++ constructor(settings) { + this._dtdSettings = settings; + this.realShowAppsIcon = new Dash.ShowAppsIcon(); + @@ -5846,36 +5703,37 @@ index 0000000..ef9c6e1 + this._onMenuPoppedDown = AppDisplay.AppIcon.prototype._onMenuPoppedDown; + + // No action on clicked (showing of the appsview is controlled elsewhere) -+ this._onClicked = Lang.bind(this, function(actor, button) { ++ this._onClicked = (actor, button) => { + this._removeMenuTimeout(); -+ }); ++ }; + -+ this.actor.connect('leave-event', Lang.bind(this, this._onLeaveEvent)); -+ this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress)); -+ this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent)); -+ this.actor.connect('clicked', Lang.bind(this, this._onClicked)); -+ this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu)); ++ this.actor.connect('leave-event', this._onLeaveEvent.bind(this)); ++ this.actor.connect('button-press-event', this._onButtonPress.bind(this)); ++ this.actor.connect('touch-event', this._onTouchEvent.bind(this)); ++ this.actor.connect('clicked', this._onClicked.bind(this)); ++ this.actor.connect('popup-menu', this._onKeyboardPopupMenu.bind(this)); + + this._menu = null; + this._menuManager = new PopupMenu.PopupMenuManager(this); + this._menuTimeoutId = 0; + -+ this.showLabel = itemShowLabel; -+ }, ++ this.realShowAppsIcon._dtdSettings = settings; ++ this.realShowAppsIcon.showLabel = itemShowLabel; ++ } + -+ popupMenu: function() { ++ popupMenu() { + this._removeMenuTimeout(); + this.actor.fake_release(); + + if (!this._menu) { + this._menu = new MyShowAppsIconMenu(this, this._dtdSettings); -+ this._menu.connect('open-state-changed', Lang.bind(this, function(menu, isPoppedUp) { ++ this._menu.connect('open-state-changed', (menu, isPoppedUp) => { + if (!isPoppedUp) + this._onMenuPoppedDown(); -+ })); -+ let id = Main.overview.connect('hiding', Lang.bind(this, function() { ++ }); ++ let id = Main.overview.connect('hiding', () => { + this._menu.close(); -+ })); ++ }); + this._menu.actor.connect('destroy', function() { + Main.overview.disconnect(id); + }); @@ -5891,18 +5749,15 @@ index 0000000..ef9c6e1 + + return false; + } -+}); ++}; +Signals.addSignalMethods(ShowAppsIconWrapper.prototype); + + +/** + * A menu for the showAppsIcon + */ -+const MyShowAppsIconMenu = new Lang.Class({ -+ Name: 'DashToDock.ShowAppsIconMenu', -+ Extends: MyAppIconMenu, -+ -+ _redisplay: function() { ++var MyShowAppsIconMenu = class DashToDock_MyShowAppsIconMenu extends MyAppIconMenu { ++ _redisplay() { + this.removeAll(); + + /* Translators: %s is "Settings", which is automatically translated. You @@ -5914,7 +5769,7 @@ index 0000000..ef9c6e1 + Util.spawn(["gnome-shell-extension-prefs", Me.metadata.uuid]); + }); + } -+}); ++}; + +/** + * This function is used for both extendShowAppsIcon and extendDashItemContainer @@ -5988,100 +5843,20 @@ index 0000000..ef9c6e1 + transition: 'easeOutQuad', + }); +} -diff --git a/extensions/dash-to-dock/convenience.js b/extensions/dash-to-dock/convenience.js -new file mode 100644 -index 0000000..bc50419 ---- /dev/null -+++ b/extensions/dash-to-dock/convenience.js -@@ -0,0 +1,74 @@ -+/* -*- mode: js; js-basic-offset: 4; indent-tabs-mode: nil -*- */ -+ -+/* -+ * Part of this file comes from gnome-shell-extensions: -+ * https://gitlab.gnome.org/GNOME/gnome-shell-extensions/ -+ */ -+ -+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/extensions/dash-to-dock/dash.js b/extensions/dash-to-dock/dash.js new file mode 100644 -index 0000000..4cf5aa2 +index 0000000..a646256 --- /dev/null +++ b/extensions/dash-to-dock/dash.js -@@ -0,0 +1,1175 @@ +@@ -0,0 +1,1171 @@ +// -*- 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 Gtk = imports.gi.Gtk; +const Signals = imports.signals; -+const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; @@ -6128,10 +5903,10 @@ index 0000000..4cf5aa2 + * - modified chldBox calculations for when 'show-apps-at-top' option is checked + * - handle horizontal dash + */ -+const MyDashActor = new Lang.Class({ -+ Name: 'DashToDock.MyDashActor', ++var MyDashActor = GObject.registerClass( ++class DashToDock_MyDashActor extends St.Widget { + -+ _init: function(settings) { ++ _init(settings) { + // a prefix is required to avoid conflicting with the parent class variable + this._dtdSettings = settings; + this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL); @@ -6144,24 +5919,25 @@ index 0000000..4cf5aa2 + orientation: this._isHorizontal ? Clutter.Orientation.HORIZONTAL : Clutter.Orientation.VERTICAL + }); + -+ this.actor = new Shell.GenericContainer({ ++ super._init({ + name: 'dash', + layout_manager: layout, + clip_to_allocation: true + }); -+ this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth)); -+ this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight)); -+ this.actor.connect('allocate', Lang.bind(this, this._allocate)); + -+ this.actor._delegate = this; -+ }, ++ // Since we are usually visible but not usually changing, make sure ++ // most repaint requests don't actually require us to repaint anything. ++ // This saves significant CPU when repainting the screen. ++ this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); ++ } + -+ _allocate: function(actor, box, flags) { ++ vfunc_allocate(box, flags) { ++ this.set_allocation(box, flags); + let contentBox = box; + let availWidth = contentBox.x2 - contentBox.x1; + let availHeight = contentBox.y2 - contentBox.y1; + -+ let [appIcons, showAppsButton] = actor.get_children(); ++ let [appIcons, showAppsButton] = this.get_children(); + let [showAppsMinHeight, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth); + let [showAppsMinWidth, showAppsNatWidth] = showAppsButton.get_preferred_width(availHeight); + @@ -6197,39 +5973,36 @@ index 0000000..4cf5aa2 + childBox.y1 = contentBox.y2 - showAppsNatHeight; + showAppsButton.allocate(childBox, flags); + } -+ }, ++ } + -+ _getPreferredWidth: function(actor, forHeight, alloc) { ++ vfunc_get_preferred_width(forHeight) { + // We want to request the natural height of all our children + // as our natural height, so we chain up to StWidget (which + // then calls BoxLayout), but we only request the showApps + // button as the minimum size + -+ let [, natWidth] = this.actor.layout_manager.get_preferred_width(this.actor, forHeight); ++ let [, natWidth] = this.layout_manager.get_preferred_width(this, forHeight); + -+ let themeNode = this.actor.get_theme_node(); -+ let [, showAppsButton] = this.actor.get_children(); ++ let themeNode = this.get_theme_node(); ++ let [, showAppsButton] = this.get_children(); + let [minWidth, ] = showAppsButton.get_preferred_height(forHeight); + -+ alloc.min_size = minWidth; -+ alloc.natural_size = natWidth; -+ -+ }, ++ return [minWidth, natWidth]; ++ } + -+ _getPreferredHeight: function(actor, forWidth, alloc) { ++ vfunc_get_preferred_height(forWidth) { + // We want to request the natural height of all our children + // as our natural height, so we chain up to StWidget (which + // then calls BoxLayout), but we only request the showApps + // button as the minimum size + -+ let [, natHeight] = this.actor.layout_manager.get_preferred_height(this.actor, forWidth); ++ let [, natHeight] = this.layout_manager.get_preferred_height(this, forWidth); + -+ let themeNode = this.actor.get_theme_node(); -+ let [, showAppsButton] = this.actor.get_children(); ++ let themeNode = this.get_theme_node(); ++ let [, showAppsButton] = this.get_children(); + let [minHeight, ] = showAppsButton.get_preferred_height(forWidth); + -+ alloc.min_size = minHeight; -+ alloc.natural_size = natHeight; ++ return [minHeight, natHeight]; + } +}); + @@ -6251,10 +6024,9 @@ index 0000000..4cf5aa2 + * - sync minimization application target position. + * - keep running apps ordered. + */ -+var MyDash = new Lang.Class({ -+ Name: 'DashToDock.MyDash', ++var MyDash = class DashToDock_MyDash { + -+ _init: function(settings, remoteModel, monitorIndex) { ++ constructor(settings, remoteModel, monitorIndex) { + this._dtdSettings = settings; + + // Initialize icon variables and size @@ -6279,8 +6051,7 @@ index 0000000..4cf5aa2 + this._ensureAppIconVisibilityTimeoutId = 0; + this._labelShowing = false; + -+ this._containerObject = new MyDashActor(settings); -+ this._container = this._containerObject.actor; ++ this._container = new MyDashActor(settings); + this._scrollView = new St.ScrollView({ + name: 'dashtodockDashScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, @@ -6288,7 +6059,7 @@ index 0000000..4cf5aa2 + enable_mouse_scrolling: false + }); + -+ this._scrollView.connect('scroll-event', Lang.bind(this, this._onScrollEvent)); ++ this._scrollView.connect('scroll-event', this._onScrollEvent.bind(this)); + + this._box = new St.BoxLayout({ + vertical: !this._isHorizontal, @@ -6302,9 +6073,9 @@ index 0000000..4cf5aa2 + + // Create a wrapper around the real showAppsIcon in order to add a popupMenu. + let showAppsIconWrapper = new AppIcons.ShowAppsIconWrapper(this._dtdSettings); -+ showAppsIconWrapper.connect('menu-state-changed', Lang.bind(this, function(showAppsIconWrapper, opened) { ++ showAppsIconWrapper.connect('menu-state-changed', (showAppsIconWrapper, opened) => { + this._itemMenuStateChanged(showAppsIconWrapper, opened); -+ })); ++ }); + // an instance of the showAppsIcon class is encapsulated in the wrapper + this._showAppsIcon = showAppsIconWrapper.realShowAppsIcon; + @@ -6325,27 +6096,27 @@ index 0000000..4cf5aa2 + }); + + if (this._isHorizontal) { -+ this.actor.connect('notify::width', Lang.bind(this, function() { ++ this.actor.connect('notify::width', () => { + if (this._maxHeight != this.actor.width) + this._queueRedisplay(); + this._maxHeight = this.actor.width; -+ })); ++ }); + } + else { -+ this.actor.connect('notify::height', Lang.bind(this, function() { ++ this.actor.connect('notify::height', () => { + if (this._maxHeight != this.actor.height) + this._queueRedisplay(); + this._maxHeight = this.actor.height; -+ })); ++ }); + } + + // Update minimization animation target position on allocation of the + // container and on scrollview change. -+ this._box.connect('notify::allocation', Lang.bind(this, this._updateAppsIconGeometry)); ++ this._box.connect('notify::allocation', this._updateAppsIconGeometry.bind(this)); + let scrollViewAdjustment = this._isHorizontal ? this._scrollView.hscroll.adjustment : this._scrollView.vscroll.adjustment; -+ scrollViewAdjustment.connect('notify::value', Lang.bind(this, this._updateAppsIconGeometry)); ++ scrollViewAdjustment.connect('notify::value', this._updateAppsIconGeometry.bind(this)); + -+ this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay)); ++ this._workId = Main.initializeDeferredWork(this._box, this._redisplay.bind(this)); + + this._settings = new Gio.Settings({ + schema_id: 'org.gnome.shell' @@ -6356,38 +6127,38 @@ index 0000000..4cf5aa2 + this._signalsHandler.add([ + this._appSystem, + 'installed-changed', -+ Lang.bind(this, function() { ++ () => { + AppFavorites.getAppFavorites().reload(); + this._queueRedisplay(); -+ }) ++ } + ], [ + AppFavorites.getAppFavorites(), + 'changed', -+ Lang.bind(this, this._queueRedisplay) ++ this._queueRedisplay.bind(this) + ], [ + this._appSystem, + 'app-state-changed', -+ Lang.bind(this, this._queueRedisplay) ++ this._queueRedisplay.bind(this) + ], [ + Main.overview, + 'item-drag-begin', -+ Lang.bind(this, this._onDragBegin) ++ this._onDragBegin.bind(this) + ], [ + Main.overview, + 'item-drag-end', -+ Lang.bind(this, this._onDragEnd) ++ this._onDragEnd.bind(this) + ], [ + Main.overview, + 'item-drag-cancelled', -+ Lang.bind(this, this._onDragCancelled) ++ this._onDragCancelled.bind(this) + ]); -+ }, ++ } + -+ destroy: function() { ++ destroy() { + this._signalsHandler.destroy(); -+ }, ++ } + -+ _onScrollEvent: function(actor, event) { ++ _onScrollEvent(actor, event) { + // If scroll is not used because the icon is resized, let the scroll event propagate. + if (!this._dtdSettings.get_boolean('icon-size-fixed')) + return Clutter.EVENT_PROPAGATE; @@ -6430,12 +6201,12 @@ index 0000000..4cf5aa2 + adjustment.set_value(adjustment.get_value() + delta); + + return Clutter.EVENT_STOP; -+ }, ++ } + -+ _onDragBegin: function() { ++ _onDragBegin() { + this._dragCancelled = false; + this._dragMonitor = { -+ dragMotion: Lang.bind(this, this._onDragMotion) ++ dragMotion: this._onDragMotion.bind(this) + }; + DND.addDragMonitor(this._dragMonitor); + @@ -6444,28 +6215,28 @@ index 0000000..4cf5aa2 + this._box.insert_child_at_index(this._emptyDropTarget, 0); + this._emptyDropTarget.show(true); + } -+ }, ++ } + -+ _onDragCancelled: function() { ++ _onDragCancelled() { + this._dragCancelled = true; + this._endDrag(); -+ }, ++ } + -+ _onDragEnd: function() { ++ _onDragEnd() { + if (this._dragCancelled) + return; + + this._endDrag(); -+ }, ++ } + -+ _endDrag: function() { ++ _endDrag() { + this._clearDragPlaceholder(); + this._clearEmptyDropTarget(); + this._showAppsIcon.setDragApp(null); + DND.removeDragMonitor(this._dragMonitor); -+ }, ++ } + -+ _onDragMotion: function(dragEvent) { ++ _onDragMotion(dragEvent) { + let app = Dash.getAppFromSource(dragEvent.source); + if (app == null) + return DND.DragMotionResult.CONTINUE; @@ -6481,69 +6252,69 @@ index 0000000..4cf5aa2 + this._showAppsIcon.setDragApp(null); + + return DND.DragMotionResult.CONTINUE; -+ }, ++ } + -+ _appIdListToHash: function(apps) { ++ _appIdListToHash(apps) { + let ids = {}; + for (let i = 0; i < apps.length; i++) + ids[apps[i].get_id()] = apps[i]; + return ids; -+ }, ++ } + -+ _queueRedisplay: function() { ++ _queueRedisplay() { + Main.queueDeferredWork(this._workId); -+ }, ++ } + -+ _hookUpLabel: function(item, appIcon) { -+ item.child.connect('notify::hover', Lang.bind(this, function() { ++ _hookUpLabel(item, appIcon) { ++ item.child.connect('notify::hover', () => { + this._syncLabel(item, appIcon); -+ })); ++ }); + -+ let id = Main.overview.connect('hiding', Lang.bind(this, function() { ++ let id = Main.overview.connect('hiding', () => { + this._labelShowing = false; + item.hideLabel(); -+ })); ++ }); + item.child.connect('destroy', function() { + Main.overview.disconnect(id); + }); + + if (appIcon) { -+ appIcon.connect('sync-tooltip', Lang.bind(this, function() { ++ appIcon.connect('sync-tooltip', () => { + this._syncLabel(item, appIcon); -+ })); ++ }); + } -+ }, ++ } + -+ _createAppItem: function(app) { ++ _createAppItem(app) { + let appIcon = new AppIcons.MyAppIcon(this._dtdSettings, this._remoteModel, app, this._monitorIndex, + { setSizeManually: true, + showLabel: false }); + + if (appIcon._draggable) { -+ appIcon._draggable.connect('drag-begin', Lang.bind(this, function() { ++ appIcon._draggable.connect('drag-begin', () => { + appIcon.actor.opacity = 50; -+ })); -+ appIcon._draggable.connect('drag-end', Lang.bind(this, function() { ++ }); ++ appIcon._draggable.connect('drag-end', () => { + appIcon.actor.opacity = 255; -+ })); ++ }); + } + -+ appIcon.connect('menu-state-changed', Lang.bind(this, function(appIcon, opened) { ++ appIcon.connect('menu-state-changed', (appIcon, opened) => { + this._itemMenuStateChanged(item, opened); -+ })); ++ }); + + let item = new Dash.DashItemContainer(); + + extendDashItemContainer(item, this._dtdSettings); + item.setChild(appIcon.actor); + -+ appIcon.actor.connect('notify::hover', Lang.bind(this, function() { ++ appIcon.actor.connect('notify::hover', () => { + if (appIcon.actor.hover) { -+ this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function() { ++ this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, () => { + ensureActorVisibleInScrollView(this._scrollView, appIcon.actor); + this._ensureAppIconVisibilityTimeoutId = 0; + return GLib.SOURCE_REMOVE; -+ })); ++ }); + } + else { + if (this._ensureAppIconVisibilityTimeoutId > 0) { @@ -6551,13 +6322,13 @@ index 0000000..4cf5aa2 + this._ensureAppIconVisibilityTimeoutId = 0; + } + } -+ })); ++ }); + -+ appIcon.actor.connect('clicked', Lang.bind(this, function(actor) { ++ appIcon.actor.connect('clicked', (actor) => { + ensureActorVisibleInScrollView(this._scrollView, actor); -+ })); ++ }); + -+ appIcon.actor.connect('key-focus-in', Lang.bind(this, function(actor) { ++ appIcon.actor.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 @@ -6566,7 +6337,7 @@ index 0000000..4cf5aa2 + appIcon._menu._boxPointer.xOffset = -x_shift; + appIcon._menu._boxPointer.yOffset = -y_shift; + } -+ })); ++ }); + + // Override default AppIcon label_actor, now the + // accessible_name is set at DashItemContainer.setLabelText @@ -6577,12 +6348,12 @@ index 0000000..4cf5aa2 + this._hookUpLabel(item, appIcon); + + return item; -+ }, ++ } + + /** + * Return an array with the "proper" appIcons currently in the dash + */ -+ getAppIcons: function() { ++ 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 @@ -6599,16 +6370,16 @@ index 0000000..4cf5aa2 + }); + + return appIcons; -+ }, ++ } + -+ _updateAppsIconGeometry: function() { ++ _updateAppsIconGeometry() { + let appIcons = this.getAppIcons(); + appIcons.forEach(function(icon) { + icon.updateIconGeometry(); + }); -+ }, ++ } + -+ _itemMenuStateChanged: function(item, opened) { ++ _itemMenuStateChanged(item, opened) { + // When the menu closes, it calls sync_hover, which means + // that the notify::hover handler does everything we need to. + if (opened) { @@ -6625,20 +6396,20 @@ index 0000000..4cf5aa2 + // calling this callback was added upstream. + this.emit('menu-closed'); + } -+ }, ++ } + -+ _syncLabel: function(item, appIcon) { ++ _syncLabel(item, appIcon) { + let shouldShow = appIcon ? appIcon.shouldShowTooltip() : item.child.get_hover(); + + if (shouldShow) { + if (this._showLabelTimeoutId == 0) { + let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT; -+ this._showLabelTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(this, function() { ++ this._showLabelTimeoutId = Mainloop.timeout_add(timeout, () => { + this._labelShowing = true; + item.showLabel(); + this._showLabelTimeoutId = 0; + return GLib.SOURCE_REMOVE; -+ })); ++ }); + GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel'); + if (this._resetHoverTimeoutId > 0) { + Mainloop.source_remove(this._resetHoverTimeoutId); @@ -6652,17 +6423,17 @@ index 0000000..4cf5aa2 + this._showLabelTimeoutId = 0; + item.hideLabel(); + if (this._labelShowing) { -+ this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT, Lang.bind(this, function() { ++ this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT, () => { + this._labelShowing = false; + this._resetHoverTimeoutId = 0; + return GLib.SOURCE_REMOVE; -+ })); ++ }); + GLib.Source.set_name_by_id(this._resetHoverTimeoutId, '[gnome-shell] this._labelShowing'); + } + } -+ }, ++ } + -+ _adjustIconSize: function() { ++ _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 @@ -6767,9 +6538,9 @@ index 0000000..4cf5aa2 + transition: 'easeOutQuad', + }); + } -+ }, ++ } + -+ _redisplay: function() { ++ _redisplay() { + let favorites = AppFavorites.getAppFavorites().getFavoriteMap(); + + let running = this._appSystem.get_running(); @@ -6933,9 +6704,9 @@ index 0000000..4cf5aa2 + + // This will update the size, and the corresponding number for each icon + this._updateNumberOverlay(); -+ }, ++ } + -+ _updateNumberOverlay: function() { ++ _updateNumberOverlay() { + let appIcons = this.getAppIcons(); + let counter = 1; + appIcons.forEach(function(icon) { @@ -6954,16 +6725,16 @@ index 0000000..4cf5aa2 + icon.updateNumberOverlay(); + }); + -+ }, ++ } + -+ toggleNumberOverlay: function(activate) { ++ toggleNumberOverlay(activate) { + let appIcons = this.getAppIcons(); + appIcons.forEach(function(icon) { + icon.toggleNumberOverlay(activate); + }); -+ }, ++ } + -+ _initializeIconSize: function(max_size) { ++ _initializeIconSize(max_size) { + let max_allowed = baseIconSizes[baseIconSizes.length-1]; + max_size = Math.min(max_size, max_allowed); + @@ -6975,22 +6746,22 @@ index 0000000..4cf5aa2 + }); + this._availableIconSizes.push(max_size); + } -+ }, ++ } + -+ setIconSize: function(max_size, doNotAnimate) { ++ setIconSize(max_size, doNotAnimate) { + this._initializeIconSize(max_size); + + if (doNotAnimate) + this._shownInitially = false; + + this._queueRedisplay(); -+ }, ++ } + + /** + * Reset the displayed apps icon to mantain the correct order when changing + * show favorites/show running settings + */ -+ resetAppIcons: function() { ++ resetAppIcons() { + let children = this._box.get_children().filter(function(actor) { + return actor.child && + actor.child._delegate && @@ -7005,28 +6776,28 @@ index 0000000..4cf5aa2 + this._shownInitially = false; + this._redisplay(); + -+ }, ++ } + -+ _clearDragPlaceholder: function() { ++ _clearDragPlaceholder() { + if (this._dragPlaceholder) { + this._animatingPlaceholdersCount++; + this._dragPlaceholder.animateOutAndDestroy(); -+ this._dragPlaceholder.connect('destroy', Lang.bind(this, function() { ++ this._dragPlaceholder.connect('destroy', () => { + this._animatingPlaceholdersCount--; -+ })); ++ }); + this._dragPlaceholder = null; + } + this._dragPlaceholderPos = -1; -+ }, ++ } + -+ _clearEmptyDropTarget: function() { ++ _clearEmptyDropTarget() { + if (this._emptyDropTarget) { + this._emptyDropTarget.animateOutAndDestroy(); + this._emptyDropTarget = null; + } -+ }, ++ } + -+ handleDragOver: function(source, actor, x, y, time) { ++ handleDragOver(source, actor, x, y, time) { + let app = Dash.getAppFromSource(source); + + // Don't allow favoriting of transient apps @@ -7116,12 +6887,12 @@ index 0000000..4cf5aa2 + return DND.DragMotionResult.MOVE_DROP; + + return DND.DragMotionResult.COPY_DROP; -+ }, ++ } + + /** + * Draggable target interface + */ -+ acceptDrop: function(source, actor, x, y, time) { ++ acceptDrop(source, actor, x, y, time) { + let app = Dash.getAppFromSource(source); + + // Don't allow favoriting of transient apps @@ -7155,30 +6926,30 @@ index 0000000..4cf5aa2 + if (!this._dragPlaceholder) + return true; + -+ Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { ++ Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { + let appFavorites = AppFavorites.getAppFavorites(); + if (srcIsFavorite) + appFavorites.moveFavoriteToPos(id, favPos); + else + appFavorites.addFavoriteAtPos(id, favPos); + return false; -+ })); ++ }); + + return true; -+ }, ++ } + -+ showShowAppsButton: function() { ++ showShowAppsButton() { + this.showAppsButton.visible = true + this.showAppsButton.set_width(-1) + this.showAppsButton.set_height(-1) -+ }, ++ } + -+ hideShowAppsButton: function() { ++ hideShowAppsButton() { + this.showAppsButton.hide() + this.showAppsButton.set_width(0) + this.showAppsButton.set_height(0) + } -+}); ++}; + +Signals.addSignalMethods(MyDash.prototype); + @@ -7251,16 +7022,16 @@ index 0000000..4cf5aa2 +} diff --git a/extensions/dash-to-dock/docking.js b/extensions/dash-to-dock/docking.js new file mode 100644 -index 0000000..11810a1 +index 0000000..d35094b --- /dev/null +++ b/extensions/dash-to-dock/docking.js -@@ -0,0 +1,1925 @@ +@@ -0,0 +1,1853 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; +const GLib = imports.gi.GLib; ++const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; -+const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; @@ -7280,8 +7051,8 @@ index 0000000..11810a1 +const Layout = imports.ui.layout; +const LayoutManager = imports.ui.main.layoutManager; + -+const Me = imports.misc.extensionUtils.getCurrentExtension(); -+const Convenience = Me.imports.convenience; ++const ExtensionUtils = imports.misc.extensionUtils; ++const Me = ExtensionUtils.getCurrentExtension(); +const Utils = Me.imports.utils; +const Intellihide = Me.imports.intellihide; +const Theming = Me.imports.theming; @@ -7315,14 +7086,11 @@ index 0000000..11810a1 + * The slidex 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. -+ * -+ * It can't be an extended object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973. -+ * thus use the Shell.GenericContainer pattern. +*/ -+const DashSlideContainer = new Lang.Class({ -+ Name: 'DashToDock.DashSlideContainer', ++var DashSlideContainer = GObject.registerClass( ++class DashToDock_DashSlideContainer extends St.Widget { + -+ _init: function(params) { ++ _init(params) { + // Default local params + let localDefaults = { + side: St.Side.LEFT, @@ -7341,28 +7109,24 @@ index 0000000..11810a1 + } + } + -+ this.actor = new Shell.GenericContainer(params); -+ this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth)); -+ this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight)); -+ this.actor.connect('allocate', Lang.bind(this, this._allocate)); -+ -+ this.actor._delegate = this; -+ ++ super._init(params); + this._child = null; + + // slide parameter: 1 = visible, 0 = hidden. + this._slidex = localParams.initialSlideValue; + this._side = localParams.side; + this._slideoutSize = 0; // minimum size when slided out -+ }, ++ } ++ ++ vfunc_allocate(box, flags) { ++ this.set_allocation(box, flags); + -+ _allocate: function(actor, box, flags) { + if (this._child == null) + return; + + let availWidth = box.x2 - box.x1; + let availHeight = box.y2 - box.y1; -+ let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] = ++ let [, , natChildWidth, natChildHeight] = + this._child.get_preferred_size(); + + let childWidth = natChildWidth; @@ -7394,62 +7158,58 @@ index 0000000..11810a1 + this._child.allocate(childBox, flags); + 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 + */ -+ _getPreferredWidth: function(actor, forHeight, alloc) { ++ vfunc_get_preferred_width(forHeight) { + let [minWidth, natWidth] = this._child.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; + } -+ -+ alloc.min_size = minWidth; -+ alloc.natural_size = natWidth; -+ }, ++ return [minWidth, natWidth]; ++ } + + /** + * Just the child height but taking into account the slided out part + */ -+ _getPreferredHeight: function(actor, forWidth, alloc) { ++ vfunc_get_preferred_height(forWidth) { + let [minHeight, natHeight] = this._child.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; + } -+ alloc.min_size = minHeight; -+ alloc.natural_size = natHeight; -+ }, ++ return [minHeight, natHeight]; ++ } + + /** + * I was expecting it to be a virtual function... stil I don't understand + * how things work. + */ -+ add_child: function(actor) { ++ add_child(actor) { + // I'm supposed to have only on child + if (this._child !== null) -+ this.actor.remove_child(actor); ++ this.remove_child(actor); + + this._child = actor; -+ this.actor.add_child(actor); -+ }, ++ super.add_child(actor); ++ } + + set slidex(value) { + this._slidex = value; + this._child.queue_relayout(); -+ }, ++ } + + get slidex() { + return this._slidex; + } +}); + -+const DockedDash = new Lang.Class({ -+ Name: 'DashToDock.DockedDash', ++var DockedDash = class DashToDock { + -+ _init: function(settings, remoteModel, monitorIndex) { ++ constructor(settings, remoteModel, monitorIndex) { + this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL); + + // Load settings @@ -7530,7 +7290,7 @@ index 0000000..11810a1 + reactive: true, + track_hover: true + }); -+ this._box.connect('notify::hover', Lang.bind(this, this._hoverChanged)); ++ this._box.connect('notify::hover', this._hoverChanged.bind(this)); + + // Create and apply height constraint to the dash. It's controlled by this.actor height + this.constrainSize = new Clutter.BindConstraint({ @@ -7542,59 +7302,57 @@ index 0000000..11810a1 + this._signalsHandler.add([ + Main.overview, + 'item-drag-begin', -+ Lang.bind(this, this._onDragStart) ++ this._onDragStart.bind(this) + ], [ + Main.overview, + 'item-drag-end', -+ Lang.bind(this, this._onDragEnd) ++ this._onDragEnd.bind(this) + ], [ + Main.overview, + 'item-drag-cancelled', -+ Lang.bind(this, this._onDragEnd) ++ this._onDragEnd.bind(this) + ], [ + // update when workarea changes, for instance if other extensions modify the struts + //(like moving th panel at the bottom) -+ global.screen, ++ global.display, + 'workareas-changed', -+ Lang.bind(this, this._resetPosition) ++ this._resetPosition.bind(this) + ], [ + Main.overview, + 'showing', -+ Lang.bind(this, this._onOverviewShowing) ++ this._onOverviewShowing.bind(this) + ], [ + Main.overview, + 'hiding', -+ Lang.bind(this, this._onOverviewHiding) ++ this._onOverviewHiding.bind(this) + ], [ + // Hide on appview + Main.overview.viewSelector, + 'page-changed', -+ Lang.bind(this, this._pageChanged) ++ this._pageChanged.bind(this) + ], [ + Main.overview.viewSelector, + 'page-empty', -+ Lang.bind(this, this._onPageEmpty) ++ this._onPageEmpty.bind(this) + ], [ + // Ensure the ShowAppsButton status is kept in sync + Main.overview.viewSelector._showAppsButton, + 'notify::checked', -+ Lang.bind(this, this._syncShowAppsButtonToggled) ++ this._syncShowAppsButtonToggled.bind(this) + ], [ -+ global.screen, ++ global.display, + 'in-fullscreen-changed', -+ Lang.bind(this, this._updateBarrier) ++ this._updateBarrier.bind(this) + ], [ + // Monitor windows overlapping + this._intellihide, + 'status-changed', -+ Lang.bind(this, this._updateDashVisibility) ++ this._updateDashVisibility.bind(this) + ], [ + // Keep dragged icon consistent in size with this dash + this.dash, + 'icon-size-changed', -+ Lang.bind(this, function() { -+ Main.overview.dashIconSize = this.dash.iconSize; -+ }) ++ () => { Main.overview.dashIconSize = this.dash.iconSize; } + ], [ + // This duplicate the similar signal which is in owerview.js. + // Being connected and thus executed later this effectively @@ -7603,9 +7361,12 @@ index 0000000..11810a1 + // I can't easily disconnect the original signal + Main.overview._controls.dash, + 'icon-size-changed', -+ Lang.bind(this, function() { -+ Main.overview.dashIconSize = this.dash.iconSize; -+ }) ++ () => { Main.overview.dashIconSize = this.dash.iconSize; } ++ ], [ ++ // sync hover after a popupmenu is closed ++ this.dash, ++ 'menu-closed', ++ () => { this._box.sync_hover() } + ]); + + this._injectionsHandler = new Utils.InjectionsHandler(); @@ -7615,15 +7376,10 @@ index 0000000..11810a1 + // 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.actor.connect('notify::allocation', -+ Lang.bind(Main.layoutManager, Main.layoutManager._queueUpdateRegions)); ++ Main.layoutManager._queueUpdateRegions.bind(Main.layoutManager)); + -+ this.dash._container.connect('allocation-changed', Lang.bind(this, this._updateStaticBox)); -+ this._slider.actor.connect(this._isHorizontal ? 'notify::x' : 'notify::y', Lang.bind(this, this._updateStaticBox)); -+ -+ // sync hover after a popupmenu is closed -+ this.dash.connect('menu-closed', Lang.bind(this, function() { -+ this._box.sync_hover(); -+ })); ++ this.dash._container.connect('allocation-changed', 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 == this._settings.get_int('preferred-monitor')) @@ -7634,7 +7390,7 @@ index 0000000..11810a1 + // Delay operations that require the shell to be fully loaded and with + // user theme applied. + -+ this._paintId = this.actor.connect('paint', Lang.bind(this, this._initialize)); ++ this._paintId = this.actor.connect('paint', this._initialize.bind(this)); + + // Manage the which is used to reserve space in the overview for the dock + // Add and additional dashSpacer positioned according to the dash positioning. @@ -7652,7 +7408,7 @@ index 0000000..11810a1 + Main.overview._overview.insert_child_at_index(this._dashSpacer, -1); + + // Add dash container actor and the container to the Chrome. -+ this.actor.set_child(this._slider.actor); ++ this.actor.set_child(this._slider); + this._slider.add_child(this._box); + this._box.add_actor(this.dash.actor); + @@ -7663,17 +7419,17 @@ index 0000000..11810a1 + // Note: tracking the fullscreen directly on the slider actor causes some hiccups when fullscreening + // windows of certain applications + Main.layoutManager._trackActor(this.actor, {affectsInputRegion: false, trackFullscreen: true}); -+ Main.layoutManager._trackActor(this._slider.actor, {affectsStruts: true}); ++ Main.layoutManager._trackActor(this._slider, {affectsStruts: true}); + } + else -+ Main.layoutManager._trackActor(this._slider.actor); ++ Main.layoutManager._trackActor(this._slider); + + // Set initial position + this._resetDepth(); + this._resetPosition(); -+ }, ++ } + -+ _initialize: function() { ++ _initialize() { + if (this._paintId > 0) { + this.actor.disconnect(this._paintId); + this._paintId=0; @@ -7702,9 +7458,9 @@ index 0000000..11810a1 + + // setup dwelling system if pressure barriers are not available + this._setupDockDwellIfNeeded(); -+ }, ++ } + -+ destroy: function() { ++ destroy() { + // Disconnect global signals + this._signalsHandler.destroy(); + // The dash, intellihide and themeManager have global signals as well internally @@ -7734,70 +7490,55 @@ index 0000000..11810a1 + // Remove the dashSpacer + this._dashSpacer.destroy(); + -+ // Restore legacyTray position -+ this._resetLegacyTray(); -+ -+ }, ++ } + -+ _bindSettingsChanges: function() { ++ _bindSettingsChanges() { + this._signalsHandler.add([ + this._settings, + 'changed::scroll-action', -+ Lang.bind(this, function() { -+ this._optionalScrollWorkspaceSwitch(); -+ }) ++ () => { this._optionalScrollWorkspaceSwitch(); } + ], [ + this._settings, + 'changed::dash-max-icon-size', -+ Lang.bind(this, function() { -+ this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); -+ }) ++ () => { this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); } + ], [ + this._settings, + 'changed::icon-size-fixed', -+ Lang.bind(this, function() { -+ this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); -+ }) ++ () => { this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); } + ], [ + this._settings, + 'changed::show-favorites', -+ Lang.bind(this, function() { -+ this.dash.resetAppIcons(); -+ }) ++ () => { this.dash.resetAppIcons(); } + ], [ + this._settings, + 'changed::show-running', -+ Lang.bind(this, function() { -+ this.dash.resetAppIcons(); -+ }) ++ () => { this.dash.resetAppIcons(); } + ], [ + this._settings, + 'changed::show-apps-at-top', -+ Lang.bind(this, function() { -+ this.dash.resetAppIcons(); -+ }) ++ () => { this.dash.resetAppIcons(); } + ], [ + this._settings, + 'changed::show-show-apps-button', -+ Lang.bind(this, function() { ++ () => { + if (this._settings.get_boolean('show-show-apps-button')) + this.dash.showShowAppsButton(); + else + this.dash.hideShowAppsButton(); -+ }) ++ } + ], [ + this._settings, + 'changed::dock-fixed', -+ Lang.bind(this, function() { ++ () => { + if (this._settings.get_boolean('dock-fixed')) { + Main.layoutManager._untrackActor(this.actor); + Main.layoutManager._trackActor(this.actor, {affectsInputRegion: false, trackFullscreen: true}); -+ Main.layoutManager._untrackActor(this._slider.actor); -+ Main.layoutManager._trackActor(this._slider.actor, {affectsStruts: true}); ++ Main.layoutManager._untrackActor(this._slider); ++ Main.layoutManager._trackActor(this._slider, {affectsStruts: true}); + } else { + Main.layoutManager._untrackActor(this.actor); -+ Main.layoutManager._untrackActor(this._slider.actor); -+ Main.layoutManager._trackActor(this._slider.actor); ++ Main.layoutManager._untrackActor(this._slider); ++ Main.layoutManager._trackActor(this._slider); + } + + this._resetPosition(); @@ -7806,41 +7547,39 @@ index 0000000..11810a1 + this._updateBarrier(); + + this._updateVisibilityMode(); -+ }) ++ } + ], [ + this._settings, + 'changed::intellihide', -+ Lang.bind(this, this._updateVisibilityMode) ++ this._updateVisibilityMode.bind(this) + ], [ + this._settings, + 'changed::intellihide-mode', -+ Lang.bind(this, function() { -+ this._intellihide.forceUpdate(); -+ }) ++ () => { this._intellihide.forceUpdate(); } + ], [ + this._settings, + 'changed::autohide', -+ Lang.bind(this, function() { ++ () => { + this._updateVisibilityMode(); + this._updateBarrier(); -+ }) ++ } + ], [ + this._settings, + 'changed::autohide-in-fullscreen', -+ Lang.bind(this, this._updateBarrier) ++ this._updateBarrier.bind(this) + ], + [ + this._settings, + 'changed::extend-height', -+ Lang.bind(this, this._resetPosition) ++ this._resetPosition.bind(this) + ], [ + this._settings, + 'changed::height-fraction', -+ Lang.bind(this, this._resetPosition) ++ this._resetPosition.bind(this) + ], [ + this._settings, + 'changed::require-pressure-to-show', -+ Lang.bind(this, function() { ++ () => { + // Remove pointer watcher + if (this._dockWatch) { + PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch); @@ -7848,22 +7587,22 @@ index 0000000..11810a1 + } + this._setupDockDwellIfNeeded(); + this._updateBarrier(); -+ }) ++ } + ], [ + this._settings, + 'changed::pressure-threshold', -+ Lang.bind(this, function() { ++ () => { + this._updatePressureBarrier(); + this._updateBarrier(); -+ }) ++ } + ]); + -+ }, ++ } + + /** + * This is call when visibility settings change + */ -+ _updateVisibilityMode: function() { ++ _updateVisibilityMode() { + if (this._settings.get_boolean('dock-fixed')) { + this._fixedIsEnabled = true; + this._autohideIsEnabled = false; @@ -7881,7 +7620,7 @@ index 0000000..11810a1 + this._intellihide.disable(); + + this._updateDashVisibility(); -+ }, ++ } + + /** + * Show/hide dash based on, in order of priority: @@ -7891,7 +7630,7 @@ index 0000000..11810a1 + * autohide + * overview visibility + */ -+ _updateDashVisibility: function() { ++ _updateDashVisibility() { + if (Main.overview.visibleTarget) + return; + @@ -7925,22 +7664,22 @@ index 0000000..11810a1 + else + this._animateOut(this._settings.get_double('animation-time'), 0); + } -+ }, ++ } + -+ _onOverviewShowing: function() { ++ _onOverviewShowing() { + this._ignoreHover = true; + this._intellihide.disable(); + this._removeAnimations(); + this._animateIn(this._settings.get_double('animation-time'), 0); -+ }, ++ } + -+ _onOverviewHiding: function() { ++ _onOverviewHiding() { + this._ignoreHover = false; + this._intellihide.enable(); + this._updateDashVisibility(); -+ }, ++ } + -+ _hoverChanged: function() { ++ _hoverChanged() { + if (!this._ignoreHover) { + // Skip if dock is not in autohide mode for instance because it is shown + // by intellihide. @@ -7951,13 +7690,13 @@ index 0000000..11810a1 + this._hide(); + } + } -+ }, ++ } + -+ getDockState: function() { ++ getDockState() { + return this._dockState; -+ }, ++ } + -+ _show: function() { ++ _show() { + if ((this._dockState == State.HIDDEN) || (this._dockState == State.HIDING)) { + if (this._dockState == State.HIDING) + // suppress all potential queued hiding animations - i.e. added to Tweener but not started, @@ -7967,9 +7706,9 @@ index 0000000..11810a1 + this.emit('showing'); + this._animateIn(this._settings.get_double('animation-time'), 0); + } -+ }, ++ } + -+ _hide: function() { ++ _hide() { + // If no hiding animation is running or queued + if ((this._dockState == State.SHOWN) || (this._dockState == State.SHOWING)) { + let delay; @@ -7985,9 +7724,9 @@ index 0000000..11810a1 + this.emit('hiding'); + this._animateOut(this._settings.get_double('animation-time'), delay); + } -+ }, ++ } + -+ _animateIn: function(time, delay) { ++ _animateIn(time, delay) { + this._dockState = State.SHOWING; + + Tweener.addTween(this._slider, { @@ -7995,50 +7734,50 @@ index 0000000..11810a1 + time: time, + delay: delay, + transition: 'easeOutQuad', -+ onComplete: Lang.bind(this, function() { ++ 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) + Mainloop.source_remove(this._removeBarrierTimeoutId); -+ this._removeBarrierTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, this._removeBarrier)); -+ }) ++ this._removeBarrierTimeoutId = Mainloop.timeout_add(100, this._removeBarrier.bind(this)); ++ } + }); -+ }, ++ } + -+ _animateOut: function(time, delay) { ++ _animateOut(time, delay) { + this._dockState = State.HIDING; + Tweener.addTween(this._slider, { + slidex: 0, + time: time, + delay: delay , + transition: 'easeOutQuad', -+ onComplete: Lang.bind(this, function() { ++ onComplete: () => { + this._dockState = State.HIDDEN; + // Remove queued barried removal if any + if (this._removeBarrierTimeoutId > 0) + Mainloop.source_remove(this._removeBarrierTimeoutId); + this._updateBarrier(); -+ }) ++ } + }); -+ }, ++ } + + /** + * Dwelling system based on the GNOME Shell 3.14 messageTray code. + */ -+ _setupDockDwellIfNeeded: function() { ++ _setupDockDwellIfNeeded() { + // If we don't have extended barrier features, then we need + // to support the old tray dwelling mechanism. + if (!global.display.supports_extended_barriers() || !this._settings.get_boolean('require-pressure-to-show')) { + let pointerWatcher = PointerWatcher.getPointerWatcher(); -+ this._dockWatch = pointerWatcher.addWatch(DOCK_DWELL_CHECK_INTERVAL, Lang.bind(this, this._checkDockDwell)); ++ this._dockWatch = pointerWatcher.addWatch(DOCK_DWELL_CHECK_INTERVAL, this._checkDockDwell.bind(this)); + this._dockDwelling = false; + this._dockDwellUserTime = 0; + } -+ }, ++ } + -+ _checkDockDwell: function(x, y) { ++ _checkDockDwell(x, y) { + + let workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitor.index) + let shouldDwell; @@ -8065,7 +7804,7 @@ index 0000000..11810a1 + this._dockDwellUserTime = focusWindow ? focusWindow.user_time : 0; + + this._dockDwellTimeoutId = Mainloop.timeout_add(this._settings.get_double('show-delay') * 1000, -+ Lang.bind(this, this._dockDwellTimeout)); ++ this._dockDwellTimeout.bind(this)); + GLib.Source.set_name_by_id(this._dockDwellTimeoutId, '[dash-to-dock] this._dockDwellTimeout'); + } + this._dockDwelling = true; @@ -8074,16 +7813,16 @@ index 0000000..11810a1 + this._cancelDockDwell(); + this._dockDwelling = false; + } -+ }, ++ } + -+ _cancelDockDwell: function() { ++ _cancelDockDwell() { + if (this._dockDwellTimeoutId != 0) { + Mainloop.source_remove(this._dockDwellTimeoutId); + this._dockDwellTimeoutId = 0; + } -+ }, ++ } + -+ _dockDwellTimeout: function() { ++ _dockDwellTimeout() { + this._dockDwellTimeoutId = 0; + + if (!this._settings.get_boolean('autohide-in-fullscreen') && this._monitor.inFullscreen) @@ -8105,9 +7844,9 @@ index 0000000..11810a1 + // Reuse the pressure version function, the logic is the same + this._onPressureSensed(); + return GLib.SOURCE_REMOVE; -+ }, ++ } + -+ _updatePressureBarrier: function() { ++ _updatePressureBarrier() { + this._canUsePressure = global.display.supports_extended_barriers(); + let pressureThreshold = this._settings.get_double('pressure-threshold'); + @@ -8126,24 +7865,24 @@ index 0000000..11810a1 + if (this._canUsePressure) { + this._pressureBarrier = new Layout.PressureBarrier(pressureThreshold, this._settings.get_double('show-delay')*1000, + Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW); -+ this._pressureBarrier.connect('trigger', Lang.bind(this, function(barrier) { ++ this._pressureBarrier.connect('trigger', (barrier) => { + if (!this._settings.get_boolean('autohide-in-fullscreen') && this._monitor.inFullscreen) + return; + this._onPressureSensed(); -+ })); ++ }); + } -+ }, ++ } + + /** + * handler for mouse pressure sensed + */ -+ _onPressureSensed: function() { ++ _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 = Mainloop.timeout_add(250, Lang.bind(this, function() { ++ let triggerTimeoutId = Mainloop.timeout_add(250, () => { + triggerTimeoutId = 0; + + let [x, y, mods] = global.get_pointer(); @@ -8189,15 +7928,15 @@ index 0000000..11810a1 + return GLib.SOURCE_CONTINUE; + } + -+ })); ++ }); + + this._show(); -+ }, ++ } + + /** + * Remove pressure barrier + */ -+ _removeBarrier: function() { ++ _removeBarrier() { + if (this._barrier) { + if (this._pressureBarrier) + this._pressureBarrier.removeBarrier(this._barrier); @@ -8206,12 +7945,12 @@ index 0000000..11810a1 + } + this._removeBarrierTimeoutId = 0; + return false; -+ }, ++ } + + /** + * Update pressure barrier size + */ -+ _updateBarrier: function() { ++ _updateBarrier() { + // Remove existing barrier + this._removeBarrier(); + @@ -8274,13 +8013,13 @@ index 0000000..11810a1 + if (this._pressureBarrier) + this._pressureBarrier.addBarrier(this._barrier); + } -+ }, ++ } + -+ _isPrimaryMonitor: function() { ++ _isPrimaryMonitor() { + return (this._monitorIndex == Main.layoutManager.primaryIndex); -+ }, ++ } + -+ _resetPosition: function() { ++ _resetPosition() { + // Ensure variables linked to settings are updated. + this._updateVisibilityMode(); + @@ -8362,78 +8101,39 @@ index 0000000..11810a1 + } + + this._y0 = this.actor.y; -+ -+ this._adjustLegacyTray(); -+ }, ++ } + + // Set the dash at the correct depth in z -+ _resetDepth: function() { -+ // Keep the dash below the modalDialogGroup and the legacyTray -+ if (Main.legacyTray && Main.legacyTray.actor) -+ Main.layoutManager.uiGroup.set_child_below_sibling(this.actor, Main.legacyTray.actor); -+ else -+ Main.layoutManager.uiGroup.set_child_below_sibling(this.actor, Main.layoutManager.modalDialogGroup); -+ }, -+ -+ _adjustLegacyTray: function() { -+ // The legacyTray has been removed in GNOME Shell 3.26. -+ // Once we drop support for previous releases this fuction can be dropped too. -+ if (!Main.legacyTray) -+ return; -+ -+ let use_work_area = true; -+ -+ if (this._fixedIsEnabled && !this._settings.get_boolean('extend-height') -+ && this._isPrimaryMonitor() -+ && ((this._position == St.Side.BOTTOM) || (this._position == St.Side.LEFT))) -+ use_work_area = false; -+ -+ Main.legacyTray.actor.clear_constraints(); -+ let constraint = new Layout.MonitorConstraint({ -+ primary: true, -+ work_area: use_work_area -+ }); -+ Main.legacyTray.actor.add_constraint(constraint); -+ }, -+ -+ _resetLegacyTray: function() { -+ // The legacyTray has been removed in GNOME Shell 3.26. -+ // Once we drop support for previous releases this fuction can be dropped too. -+ if (!Main.legacyTray) -+ return; -+ Main.legacyTray.actor.clear_constraints(); -+ let constraint = new Layout.MonitorConstraint({ -+ primary: true, -+ work_area: true -+ }); -+ Main.legacyTray.actor.add_constraint(constraint); -+ }, ++ _resetDepth() { ++ // Keep the dash below the modalDialogGroup ++ Main.layoutManager.uiGroup.set_child_below_sibling(this.actor, Main.layoutManager.modalDialogGroup); ++ } + -+ _updateStaticBox: function() { ++ _updateStaticBox() { + this.staticBox.init_rect( -+ this.actor.x + this._slider.actor.x - (this._position == St.Side.RIGHT ? this._box.width : 0), -+ this.actor.y + this._slider.actor.y - (this._position == St.Side.BOTTOM ? this._box.height : 0), ++ this.actor.x + this._slider.x - (this._position == St.Side.RIGHT ? this._box.width : 0), ++ this.actor.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: function() { ++ _removeAnimations() { + Tweener.removeTweens(this._slider); -+ }, ++ } + -+ _onDragStart: function() { ++ _onDragStart() { + // The dash need to be above the top_window_group, otherwise it doesn't + // accept dnd of app icons when not in overiew mode. + Main.layoutManager.uiGroup.set_child_above_sibling(this.actor, global.top_window_group); + this._oldignoreHover = this._ignoreHover; + this._ignoreHover = true; + this._animateIn(this._settings.get_double('animation-time'), 0); -+ }, ++ } + -+ _onDragEnd: function() { ++ _onDragEnd() { + // Restore drag default dash stack order + this._resetDepth(); + if (this._oldignoreHover !== null) @@ -8442,9 +8142,9 @@ index 0000000..11810a1 + this._box.sync_hover(); + if (Main.overview._shown) + this._pageChanged(); -+ }, ++ } + -+ _pageChanged: function() { ++ _pageChanged() { + let activePage = Main.overview.viewSelector.getActivePage(); + let dashVisible = (activePage == ViewSelector.ViewPage.WINDOWS || + activePage == ViewSelector.ViewPage.APPS); @@ -8453,9 +8153,9 @@ index 0000000..11810a1 + this._animateIn(this._settings.get_double('animation-time'), 0); + else + this._animateOut(this._settings.get_double('animation-time'), 0); -+ }, ++ } + -+ _onPageEmpty: function() { ++ _onPageEmpty() { + /* The dash spacer is required only in the WINDOWS view if in the default position. + * The 'page-empty' signal is emitted in between a change of view, + * signalling the spacer can be added and removed without visible effect, @@ -8474,52 +8174,52 @@ index 0000000..11810a1 + + let activePage = Main.overview.viewSelector.getActivePage(); + this._dashSpacer.visible = (this._isHorizontal || activePage == ViewSelector.ViewPage.WINDOWS); -+ }, ++ } + + /** + * Show dock and give key focus to it + */ -+ _onAccessibilityFocus: function() { ++ _onAccessibilityFocus() { + this._box.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); + this._animateIn(this._settings.get_double('animation-time'), 0); -+ }, ++ } + + /** + * Keep ShowAppsButton status in sync with the overview status + */ -+ _syncShowAppsButtonToggled: function() { ++ _syncShowAppsButtonToggled() { + let status = Main.overview.viewSelector._showAppsButton.checked; + if (this.dash.showAppsButton.checked !== status) + this.dash.showAppsButton.checked = status; -+ }, ++ } + + // Optional features to be enabled only for the main Dock -+ _enableExtraFeatures: function() { ++ _enableExtraFeatures() { + // Restore dash accessibility + Main.ctrlAltTabManager.addGroup( + this.dash.actor, _('Dash'), 'user-bookmarks-symbolic', -+ {focusCallback: Lang.bind(this, this._onAccessibilityFocus)}); -+ }, ++ {focusCallback: this._onAccessibilityFocus.bind(this)}); ++ } + + /** + * Switch workspace by scrolling over the dock + */ -+ _optionalScrollWorkspaceSwitch: function() { ++ _optionalScrollWorkspaceSwitch() { + let label = 'optionalScrollWorkspaceSwitch'; + + function isEnabled() { + return this._settings.get_enum('scroll-action') === scrollAction.SWITCH_WORKSPACE; + } + -+ this._settings.connect('changed::scroll-action', Lang.bind(this, function() { -+ if (Lang.bind(this, isEnabled)()) -+ Lang.bind(this, enable)(); ++ this._settings.connect('changed::scroll-action', () => { ++ if (isEnabled.bind(this)()) ++ enable.bind(this)(); + else -+ Lang.bind(this, disable)(); -+ })); ++ disable.bind(this)(); ++ }); + -+ if (Lang.bind(this, isEnabled)()) -+ Lang.bind(this, enable)(); ++ if (isEnabled.bind(this)()) ++ enable.bind(this)(); + + function enable() { + this._signalsHandler.removeWithLabel(label); @@ -8527,7 +8227,7 @@ index 0000000..11810a1 + this._signalsHandler.addWithLabel(label, [ + this._box, + 'scroll-event', -+ Lang.bind(this, onScrollEvent) ++ onScrollEvent.bind(this) + ]); + + this._optionalScrollWorkspaceSwitchDeadTimeId = 0; @@ -8548,7 +8248,7 @@ index 0000000..11810a1 + if (Main.overview.visible && Main.overview.viewSelector.getActivePage() !== ViewSelector.ViewPage.WINDOWS) + return false; + -+ let activeWs = global.screen.get_active_workspace(); ++ let activeWs = global.workspace_manager.get_active_workspace(); + let direction = null; + + switch (event.get_scroll_direction()) { @@ -8576,9 +8276,9 @@ index 0000000..11810a1 + if (this._optionalScrollWorkspaceSwitchDeadTimeId > 0) + return false; + else -+ this._optionalScrollWorkspaceSwitchDeadTimeId = Mainloop.timeout_add(250, Lang.bind(this, function() { ++ this._optionalScrollWorkspaceSwitchDeadTimeId = Mainloop.timeout_add(250, () => { + this._optionalScrollWorkspaceSwitchDeadTimeId = 0; -+ })); ++ }); + + let ws; + @@ -8604,9 +8304,9 @@ index 0000000..11810a1 + else + return false; + } -+ }, ++ } + -+ _activateApp: function(appIndex) { ++ _activateApp(appIndex) { + let children = this.dash._box.get_children().filter(function(actor) { + return actor.child && + actor.child._delegate && @@ -8623,22 +8323,18 @@ index 0000000..11810a1 + if (appIndex < apps.length) + apps[appIndex].activate(button); + } -+ -+}); ++}; + +Signals.addSignalMethods(DockedDash.prototype); + +/* + * Handle keybaord shortcuts + */ -+const KeyboardShortcuts = new Lang.Class({ -+ -+ Name: 'DashToDock.KeyboardShortcuts', ++const DashToDock_KeyboardShortcuts_NUM_HOTKEYS = 10; + -+ _numHotkeys: 10, -+ -+ _init: function(settings, allDocks){ ++var KeyboardShortcuts = class DashToDock_KeyboardShortcuts { + ++ constructor(settings, allDocks){ + this._settings = settings; + this._allDocks = allDocks; + this._signalsHandler = new Utils.GlobalSignalsHandler(); @@ -8650,60 +8346,60 @@ index 0000000..11810a1 + this._signalsHandler.add([ + this._settings, + 'changed::hot-keys', -+ Lang.bind(this, function() { ++ () => { + if (this._settings.get_boolean('hot-keys')) -+ Lang.bind(this, this._enableHotKeys)(); ++ this._enableHotKeys.bind(this)(); + else -+ Lang.bind(this, this._disableHotKeys)(); -+ }) ++ this._disableHotKeys.bind(this)(); ++ } + ]); + + this._optionalNumberOverlay(); -+ }, ++ } + -+ destroy: function (){ ++ destroy() { + // Remove keybindings + this._disableHotKeys(); + this._disableExtraShortcut(); + this._signalsHandler.destroy(); -+ }, ++ } + -+ _enableHotKeys: function() { ++ _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 < this._numHotkeys; i++) { ++ for (let i = 0; i < DashToDock_KeyboardShortcuts_NUM_HOTKEYS; i++) { + let appNum = i; + Main.wm.addKeybinding(key + (i + 1), this._settings, + Meta.KeyBindingFlags.NONE, + Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW, -+ Lang.bind(this, function() { ++ () => { + this._allDocks[0]._activateApp(appNum); + this._showOverlay(); -+ })); ++ }); + } + }, this); + + this._hotKeysEnabled = true; -+ }, ++ } + -+ _disableHotKeys: function() { ++ _disableHotKeys() { + if (!this._hotKeysEnabled) + return; + + let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-']; + keys.forEach( function(key) { -+ for (let i = 0; i < this._numHotkeys; i++) ++ for (let i = 0; i < DashToDock_KeyboardShortcuts_NUM_HOTKEYS; i++) + Main.wm.removeKeybinding(key + (i + 1)); + }, this); + + this._hotKeysEnabled = false; -+ }, ++ } + -+ _optionalNumberOverlay: function() { ++ _optionalNumberOverlay() { + this._shortcutIsSet = false; + // Enable extra shortcut if either 'overlay' or 'show-dock' are true + if (this._settings.get_boolean('hot-keys') && @@ -8713,44 +8409,44 @@ index 0000000..11810a1 + this._signalsHandler.add([ + this._settings, + 'changed::hot-keys', -+ Lang.bind(this, this._checkHotkeysOptions) ++ this._checkHotkeysOptions.bind(this) + ], [ + this._settings, + 'changed::hotkeys-overlay', -+ Lang.bind(this, this._checkHotkeysOptions) ++ this._checkHotkeysOptions.bind(this) + ], [ + this._settings, + 'changed::hotkeys-show-dock', -+ Lang.bind(this, this._checkHotkeysOptions) ++ this._checkHotkeysOptions.bind(this) + ]); -+ }, ++ } + -+ _checkHotkeysOptions: function() { ++ _checkHotkeysOptions() { + if (this._settings.get_boolean('hot-keys') && + (this._settings.get_boolean('hotkeys-overlay') || this._settings.get_boolean('hotkeys-show-dock'))) + this._enableExtraShortcut(); + else + this._disableExtraShortcut(); -+ }, ++ } + -+ _enableExtraShortcut: function() { ++ _enableExtraShortcut() { + if (!this._shortcutIsSet) { + Main.wm.addKeybinding('shortcut', this._settings, + Meta.KeyBindingFlags.NONE, + Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW, -+ Lang.bind(this, this._showOverlay)); ++ this._showOverlay.bind(this)); + this._shortcutIsSet = true; + } -+ }, ++ } + -+ _disableExtraShortcut: function() { ++ _disableExtraShortcut() { + if (this._shortcutIsSet) { + Main.wm.removeKeybinding('shortcut'); + this._shortcutIsSet = false; + } -+ }, ++ } + -+ _showOverlay: function() { ++ _showOverlay() { + for (let i = 0; i < this._allDocks.length; i++) { + let dock = this._allDocks[i]; + if (dock._settings.get_boolean('hotkeys-overlay')) @@ -8764,12 +8460,12 @@ index 0000000..11810a1 + + // Hide the overlay/dock after the timeout + let timeout = dock._settings.get_double('shortcut-timeout') * 1000; -+ dock._numberOverlayTimeoutId = Mainloop.timeout_add(timeout, Lang.bind(dock, function() { ++ dock._numberOverlayTimeoutId = Mainloop.timeout_add(timeout, () => { + dock._numberOverlayTimeoutId = 0; + dock.dash.toggleNumberOverlay(false); + // Hide the dock again if necessary + dock._updateDashVisibility(); -+ })); ++ }); + + // Show the dock if it is hidden + if (dock._settings.get_boolean('hotkeys-show-dock')) { @@ -8779,19 +8475,16 @@ index 0000000..11810a1 + } + } + } -+ -+}); ++}; + +/** + * 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. + */ -+const WorkspaceIsolation = new Lang.Class({ -+ -+ Name: 'DashToDock.WorkspaceIsolation', ++var WorkspaceIsolation = class DashToDock_WorkspaceIsolation { + -+ _init: function(settings, allDocks) { ++ constructor(settings, allDocks) { + + this._settings = settings; + this._allDocks = allDocks; @@ -8802,38 +8495,38 @@ index 0000000..11810a1 + this._signalsHandler.add([ + this._settings, + 'changed::isolate-workspaces', -+ Lang.bind(this, function() { ++ () => { + this._allDocks.forEach(function(dock) { + dock.dash.resetAppIcons(); + }); + if (this._settings.get_boolean('isolate-workspaces') || + this._settings.get_boolean('isolate-monitors')) -+ Lang.bind(this, this._enable)(); ++ this._enable.bind(this)(); + else -+ Lang.bind(this, this._disable)(); -+ }) ++ this._disable.bind(this)(); ++ } + ],[ + this._settings, + 'changed::isolate-monitors', -+ Lang.bind(this, function() { ++ () => { + this._allDocks.forEach(function(dock) { + dock.dash.resetAppIcons(); + }); + if (this._settings.get_boolean('isolate-workspaces') || + this._settings.get_boolean('isolate-monitors')) -+ Lang.bind(this, this._enable)(); ++ this._enable.bind(this)(); + else -+ Lang.bind(this, this._disable)(); -+ }) ++ this._disable.bind(this)(); ++ } + ]); + + if (this._settings.get_boolean('isolate-workspaces') || + this._settings.get_boolean('isolate-monitors')) + this._enable(); + -+ }, ++ } + -+ _enable: function() { ++ _enable() { + + // ensure I never double-register/inject + // although it should never happen @@ -8841,22 +8534,22 @@ index 0000000..11810a1 + + this._allDocks.forEach(function(dock) { + this._signalsHandler.addWithLabel('isolation', [ -+ global.screen, ++ global.display, + 'restacked', -+ Lang.bind(dock.dash, dock.dash._queueRedisplay) ++ dock.dash._queueRedisplay.bind(dock.dash) + ], [ + global.window_manager, + 'switch-workspace', -+ Lang.bind(dock.dash, dock.dash._queueRedisplay) ++ 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 (this._settings.get_boolean('isolate-monitors')) + this._signalsHandler.addWithLabel('isolation', [ -+ global.screen, ++ global.display, + 'window-entered-monitor', -+ Lang.bind(dock.dash, dock.dash._queueRedisplay) ++ dock.dash._queueRedisplay.bind(dock.dash) + ]); + + }, this); @@ -8865,13 +8558,13 @@ index 0000000..11810a1 + 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.screen.get_active_workspace_index(); ++ 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.screen.get_active_workspace())) ++ if (this.is_on_workspace(global.workspace_manager.get_active_workspace())) + return Main.activateWindow(windows[0]); + return this.open_new_window(-1); + } @@ -8881,27 +8574,25 @@ index 0000000..11810a1 + 'activate', + IsolatedOverview + ]); -+ }, ++ } + -+ _disable: function () { ++ _disable () { + this._signalsHandler.removeWithLabel('isolation'); + this._injectionsHandler.removeWithLabel('isolation'); -+ }, ++ } + -+ destroy: function() { ++ destroy() { + this._signalsHandler.destroy(); + this._injectionsHandler.destroy(); + } -+ -+}); ++}; + + -+var DockManager = new Lang.Class({ -+ Name: 'DashToDock.DockManager', ++var DockManager = class DashToDock_DockManager { + -+ _init: function() { ++ constructor() { + this._remoteModel = new LauncherAPI.LauncherEntryRemoteModel(); -+ this._settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-dock'); ++ this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.dash-to-dock'); + this._oldDash = Main.overview._dash; + /* Array of all the docks created */ + this._allDocks = []; @@ -8913,45 +8604,53 @@ index 0000000..11810a1 + + // Connect relevant signals to the toggling function + this._bindSettingsChanges(); -+ }, ++ } + -+ _toggle: function() { ++ _toggle() { + this._deleteDocks(); + this._createDocks(); + this.emit('toggled'); -+ }, ++ } + -+ _bindSettingsChanges: function() { ++ _bindSettingsChanges() { + // Connect relevant signals to the toggling function + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._signalsHandler.add([ -+ global.screen, ++ Meta.MonitorManager.get(), + 'monitors-changed', -+ Lang.bind(this, this._toggle) ++ this._toggle.bind(this) + ], [ + this._settings, + 'changed::multi-monitor', -+ Lang.bind(this, this._toggle) ++ this._toggle.bind(this) + ], [ + this._settings, + 'changed::preferred-monitor', -+ Lang.bind(this, this._toggle) ++ this._toggle.bind(this) + ], [ + this._settings, + 'changed::dock-position', -+ Lang.bind(this, this._toggle) ++ this._toggle.bind(this) + ], [ + this._settings, + 'changed::extend-height', -+ Lang.bind(this, this._adjustPanelCorners) ++ this._adjustPanelCorners.bind(this) + ], [ + this._settings, + 'changed::dock-fixed', -+ Lang.bind(this, this._adjustPanelCorners) ++ this._adjustPanelCorners.bind(this) + ]); -+ }, ++ } ++ ++ _createDocks() { + -+ _createDocks: function() { ++ // 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 @@ -8976,7 +8675,7 @@ index 0000000..11810a1 + this._allDocks.push(dock); + + // connect app icon into the view selector -+ dock.dash.showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled)); ++ dock.dash.showAppsButton.connect('notify::checked', this._onShowAppsButtonToggled.bind(this)); + + // Make the necessary changes to Main.overview._dash + this._prepareMainDash(); @@ -8992,7 +8691,7 @@ index 0000000..11810a1 + let dock = new DockedDash(this._settings, this._remoteModel, iMon); + this._allDocks.push(dock); + // connect app icon into the view selector -+ dock.dash.showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled)); ++ dock.dash.showAppsButton.connect('notify::checked', this._onShowAppsButtonToggled.bind(this)); + } + } + @@ -9000,9 +8699,9 @@ index 0000000..11810a1 + // we need to connect the signals to all dock instances. + this._workspaceIsolation = new WorkspaceIsolation(this._settings, this._allDocks); + this._keyboardShortcuts = new KeyboardShortcuts(this._settings, this._allDocks); -+ }, ++ } + -+ _prepareMainDash: function() { ++ _prepareMainDash() { + // Pretend I'm the dash: meant to make appgrd swarm animation come from the + // right position of the appShowButton. + Main.overview._dash = this._allDocks[0].dash; @@ -9020,9 +8719,9 @@ index 0000000..11810a1 + // actors has this effect, i.e in horizontal mode and without the workspaceThumnails + // 1 static workspace only) + Main.overview._controls.dash.actor.set_width(1); -+ }, ++ } + -+ _deleteDocks: function() { ++ _deleteDocks() { + // Remove extra features + this._workspaceIsolation.destroy(); + this._keyboardShortcuts.destroy(); @@ -9033,9 +8732,9 @@ index 0000000..11810a1 + this._allDocks[i].destroy(); + this._allDocks.pop(); + } -+ }, ++ } + -+ _restoreDash: function() { ++ _restoreDash() { + Main.overview._controls.dash.actor.show(); + Main.overview._controls.dash.actor.set_width(-1); //reset default dash size + // This force the recalculation of the icon size @@ -9045,9 +8744,9 @@ index 0000000..11810a1 + Main.overview.dashIconSize = Main.overview._controls.dash.iconSize; + + Main.overview._dash = this._oldDash; -+ }, ++ } + -+ _onShowAppsButtonToggled: function(button) { ++ _onShowAppsButtonToggled(button) { + // Sync the status of the default appButtons. Only if the two statuses are + // different, that means the user interacted with the extension provided + // application button, cutomize the behaviour. Otherwise the shell has changed the @@ -9092,13 +8791,13 @@ index 0000000..11810a1 + // and the appgrid could already be allocated from previous shown. + // It has to be triggered after the overview is shown as wrong coordinates are obtained + // otherwise. -+ let overviewShownId = Main.overview.connect('shown', Lang.bind(this, function() { ++ let overviewShownId = Main.overview.connect('shown', () => { + Main.overview.disconnect(overviewShownId); -+ Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { ++ Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { + grid.actor.opacity = 255; + grid.animateSpring(IconGrid.AnimationDirection.IN, this._allDocks[0].dash.showAppsButton); -+ })); -+ })); ++ }); ++ }); + } + else { + Main.overview.viewSelector._activePage = Main.overview.viewSelector._appsPage; @@ -9122,12 +8821,12 @@ index 0000000..11810a1 + // onComplete to avoid ugly flashing of original icons. + let view = Main.overview.viewSelector.appDisplay._views[visibleView].view; + let grid = view._grid; -+ view.animate(IconGrid.AnimationDirection.OUT, Lang.bind(this, function() { ++ view.animate(IconGrid.AnimationDirection.OUT, () => { + Main.overview.viewSelector._appsPage.hide(); + Main.overview.hide(); + selector._showAppsButton.checked = false; + this._forcedOverview = false; -+ })); ++ }); + } + else { + Main.overview.hide(); @@ -9145,20 +8844,20 @@ index 0000000..11810a1 + // forcedOverview flag + if (button.checked == false) + this._forcedOverview = false; -+ }, ++ } + -+ destroy: function() { ++ destroy() { + this._signalsHandler.destroy(); + this._deleteDocks(); + this._revertPanelCorners(); + this._restoreDash(); + this._remoteModel.destroy(); -+ }, ++ } + + /** + * Adjust Panel corners + */ -+ _adjustPanelCorners: function() { ++ _adjustPanelCorners() { + let position = Utils.getPosition(this._settings); + let isHorizontal = ((position == St.Side.TOP) || (position == St.Side.BOTTOM)); + let extendHeight = this._settings.get_boolean('extend-height'); @@ -9172,32 +8871,32 @@ index 0000000..11810a1 + } + else + this._revertPanelCorners(); -+ }, ++ } + -+ _revertPanelCorners: function() { ++ _revertPanelCorners() { + Main.panel._leftCorner.actor.show(); + Main.panel._rightCorner.actor.show(); + } -+}); ++}; +Signals.addSignalMethods(DockManager.prototype); diff --git a/extensions/dash-to-dock/extension.js b/extensions/dash-to-dock/extension.js new file mode 100644 -index 0000000..97c1dbb +index 0000000..f025fae --- /dev/null +++ b/extensions/dash-to-dock/extension.js @@ -0,0 +1,23 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + -+const Me = imports.misc.extensionUtils.getCurrentExtension(); ++const ExtensionUtils = imports.misc.extensionUtils; ++const Me = ExtensionUtils.getCurrentExtension(); +const Docking = Me.imports.docking; -+const Convenience = Me.imports.convenience; + +// We declare this with var so it can be accessed by other extensions in +// GNOME Shell 3.26+ (mozjs52+). +var dockManager; + +function init() { -+ Convenience.initTranslations('dashtodock'); ++ ExtensionUtils.initTranslations('dashtodock'); +} + +function enable() { @@ -9211,14 +8910,13 @@ index 0000000..97c1dbb +} diff --git a/extensions/dash-to-dock/intellihide.js b/extensions/dash-to-dock/intellihide.js new file mode 100644 -index 0000000..1fd2699 +index 0000000..f102ea3 --- /dev/null +++ b/extensions/dash-to-dock/intellihide.js -@@ -0,0 +1,323 @@ +@@ -0,0 +1,321 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const GLib = imports.gi.GLib; -+const Lang = imports.lang; +const Mainloop = imports.mainloop; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; @@ -9262,10 +8960,9 @@ index 0000000..1fd2699 + * Intallihide object: emit 'status-changed' signal when the overlap of windows + * with the provided targetBoxClutter.ActorBox changes; + */ -+var Intellihide = new Lang.Class({ -+ Name: 'DashToDock.Intellihide', ++var Intellihide = class DashToDock_Intellihide { + -+ _init: function(settings, monitorIndex) { ++ constructor(settings, monitorIndex) { + // Load settings + this._settings = settings; + this._monitorIndex = monitorIndex; @@ -9289,45 +8986,45 @@ index 0000000..1fd2699 + // Add signals on windows created from now on + global.display, + 'window-created', -+ Lang.bind(this, this._windowCreated) ++ this._windowCreated.bind(this) + ], [ + // triggered for instance when the window list order changes, + // included when the workspace is switched -+ global.screen, ++ global.display, + 'restacked', -+ Lang.bind(this, this._checkOverlap) ++ 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', -+ Lang.bind(this, this._checkOverlap) ++ this._checkOverlap.bind(this) + ], [ + // update wne monitor changes, for instance in multimonitor when monitor are attached -+ global.screen, ++ Meta.MonitorManager.get(), + 'monitors-changed', -+ Lang.bind(this, this._checkOverlap ) ++ this._checkOverlap.bind(this) + ]); -+ }, ++ } + -+ destroy: function() { ++ destroy() { + // Disconnect global signals + this._signalsHandler.destroy(); + + // Remove residual windows signals + this.disable(); -+ }, ++ } + -+ enable: function() { ++ enable() { + this._isEnabled = true; + this._status = OverlapStatus.UNDEFINED; + global.get_window_actors().forEach(function(wa) { + this._addWindowSignals(wa); + }, this); + this._doCheckOverlap(); -+ }, ++ } + -+ disable: function() { ++ disable() { + this._isEnabled = false; + + for (let wa of this._trackedWindows.keys()) { @@ -9339,43 +9036,43 @@ index 0000000..1fd2699 + Mainloop.source_remove(this._checkOverlapTimeoutId); + this._checkOverlapTimeoutId = 0; + } -+ }, ++ } + -+ _windowCreated: function(display, metaWindow) { ++ _windowCreated(display, metaWindow) { + this._addWindowSignals(metaWindow.get_compositor_private()); -+ }, ++ } + -+ _addWindowSignals: function(wa) { ++ _addWindowSignals(wa) { + if (!this._handledWindow(wa)) + return; -+ let signalId = wa.connect('allocation-changed', Lang.bind(this, this._checkOverlap, wa.get_meta_window())); ++ let signalId = wa.connect('allocation-changed', this._checkOverlap.bind(this)); + this._trackedWindows.set(wa, signalId); -+ wa.connect('destroy', Lang.bind(this, this._removeWindowSignals)); -+ }, ++ wa.connect('destroy', this._removeWindowSignals.bind(this)); ++ } + -+ _removeWindowSignals: function(wa) { ++ _removeWindowSignals(wa) { + if (this._trackedWindows.get(wa)) { + wa.disconnect(this._trackedWindows.get(wa)); + this._trackedWindows.delete(wa); + } + -+ }, ++ } + -+ updateTargetBox: function(box) { ++ updateTargetBox(box) { + this._targetBox = box; + this._checkOverlap(); -+ }, ++ } + -+ forceUpdate: function() { ++ forceUpdate() { + this._status = OverlapStatus.UNDEFINED; + this._doCheckOverlap(); -+ }, ++ } + -+ getOverlapStatus: function() { ++ getOverlapStatus() { + return (this._status == OverlapStatus.TRUE); -+ }, ++ } + -+ _checkOverlap: function() { ++ _checkOverlap() { + if (!this._isEnabled || (this._targetBox == null)) + return; + @@ -9387,7 +9084,7 @@ index 0000000..1fd2699 + + this._doCheckOverlap(); + -+ this._checkOverlapTimeoutId = Mainloop.timeout_add(INTELLIHIDE_CHECK_INTERVAL, Lang.bind(this, function() { ++ this._checkOverlapTimeoutId = Mainloop.timeout_add(INTELLIHIDE_CHECK_INTERVAL, () => { + this._doCheckOverlap(); + if (this._checkOverlapTimeoutContinue) { + this._checkOverlapTimeoutContinue = false; @@ -9396,10 +9093,10 @@ index 0000000..1fd2699 + this._checkOverlapTimeoutId = 0; + return GLib.SOURCE_REMOVE; + } -+ })); -+ }, ++ }); ++ } + -+ _doCheckOverlap: function() { ++ _doCheckOverlap() { + + if (!this._isEnabled || (this._targetBox == null)) + return; @@ -9456,17 +9153,17 @@ index 0000000..1fd2699 + 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: function(wa) { ++ _intellihideFilterInteresting(wa) { + let meta_win = wa.get_meta_window(); + if (!this._handledWindow(wa)) + return false; + -+ let currentWorkspace = global.screen.get_active_workspace_index(); ++ let currentWorkspace = global.workspace_manager.get_active_workspace_index(); + let wksp = meta_win.get_workspace(); + let wksp_index = wksp.index(); + @@ -9510,11 +9207,11 @@ index 0000000..1fd2699 + else + return false; + -+ }, ++ } + + // Filter windows by type + // inspired by Opacify@gnome-shell.localdomain.pl -+ _handledWindow: function(wa) { ++ _handledWindow(wa) { + let metaWindow = wa.get_meta_window(); + + if (!metaWindow) @@ -9535,25 +9232,23 @@ index 0000000..1fd2699 + } + return false; + } -+}); ++}; + +Signals.addSignalMethods(Intellihide.prototype); diff --git a/extensions/dash-to-dock/launcherAPI.js b/extensions/dash-to-dock/launcherAPI.js new file mode 100644 -index 0000000..d051a70 +index 0000000..f0b6199 --- /dev/null +++ b/extensions/dash-to-dock/launcherAPI.js -@@ -0,0 +1,244 @@ +@@ -0,0 +1,239 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Gio = imports.gi.Gio; -+const Lang = imports.lang; +const Signals = imports.signals; + -+var LauncherEntryRemoteModel = new Lang.Class({ -+ Name: 'DashToDock.LauncherEntryRemoteModel', ++var LauncherEntryRemoteModel = class DashToDock_LauncherEntryRemoteModel { + -+ _init: function () { ++ constructor() { + this._entriesByDBusName = {}; + + this._launcher_entry_dbus_signal_id = @@ -9563,7 +9258,7 @@ index 0000000..d051a70 + null, // path + null, // arg0 + Gio.DBusSignalFlags.NONE, -+ Lang.bind(this, this._onEntrySignalReceived)); ++ this._onEntrySignalReceived.bind(this)); + + this._dbus_name_owner_changed_signal_id = + Gio.DBus.session.signal_subscribe('org.freedesktop.DBus', // sender @@ -9572,12 +9267,12 @@ index 0000000..d051a70 + '/org/freedesktop/DBus', // path + null, // arg0 + Gio.DBusSignalFlags.NONE, -+ Lang.bind(this, this._onDBusNameOwnerChanged)); ++ this._onDBusNameOwnerChanged.bind(this)); + + this._acquireUnityDBus(); -+ }, ++ } + -+ destroy: function () { ++ destroy() { + if (this._launcher_entry_dbus_signal_id) { + Gio.DBus.session.signal_unsubscribe(this._launcher_entry_dbus_signal_id); + } @@ -9587,17 +9282,17 @@ index 0000000..d051a70 + } + + this._releaseUnityDBus(); -+ }, ++ } + -+ size: function () { ++ size() { + return Object.keys(this._entriesByDBusName).length; -+ }, ++ } + -+ lookupByDBusName: function (dbusName) { ++ lookupByDBusName(dbusName) { + return this._entriesByDBusName.hasOwnProperty(dbusName) ? this._entriesByDBusName[dbusName] : null; -+ }, ++ } + -+ lookupById: function (appId) { ++ lookupById(appId) { + let ret = []; + for (let dbusName in this._entriesByDBusName) { + let entry = this._entriesByDBusName[dbusName]; @@ -9607,9 +9302,9 @@ index 0000000..d051a70 + } + + return ret; -+ }, ++ } + -+ addEntry: function (entry) { ++ addEntry(entry) { + let existingEntry = this.lookupByDBusName(entry.dbusName()); + if (existingEntry) { + existingEntry.update(entry); @@ -9617,28 +9312,28 @@ index 0000000..d051a70 + this._entriesByDBusName[entry.dbusName()] = entry; + this.emit('entry-added', entry); + } -+ }, ++ } + -+ removeEntry: function (entry) { ++ removeEntry(entry) { + delete this._entriesByDBusName[entry.dbusName()] + this.emit('entry-removed', entry); -+ }, ++ } + -+ _acquireUnityDBus: function () { ++ _acquireUnityDBus() { + if (!this._unity_bus_id) { + Gio.DBus.session.own_name('com.canonical.Unity', + Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null); + } -+ }, ++ } + -+ _releaseUnityDBus: function () { ++ _releaseUnityDBus() { + if (this._unity_bus_id) { + Gio.DBus.session.unown_name(this._unity_bus_id); + this._unity_bus_id = 0; + } -+ }, ++ } + -+ _onEntrySignalReceived: function (connection, sender_name, object_path, ++ _onEntrySignalReceived(connection, sender_name, object_path, + interface_name, signal_name, parameters, user_data) { + if (!parameters || !signal_name) + return; @@ -9650,9 +9345,9 @@ index 0000000..d051a70 + + this._handleUpdateRequest(sender_name, parameters); + } -+ }, ++ } + -+ _onDBusNameOwnerChanged: function (connection, sender_name, object_path, ++ _onDBusNameOwnerChanged(connection, sender_name, object_path, + interface_name, signal_name, parameters, user_data) { + if (!parameters || !this.size()) + return; @@ -9664,9 +9359,9 @@ index 0000000..d051a70 + this.removeEntry(this._entriesByDBusName[before]); + } + } -+ }, ++ } + -+ _handleUpdateRequest: function (senderName, parameters) { ++ _handleUpdateRequest(senderName, parameters) { + if (!senderName || !parameters) { + return; + } @@ -9682,15 +9377,13 @@ index 0000000..d051a70 + let entry = new LauncherEntryRemote(senderName, appId, properties); + this.addEntry(entry); + } -+ }, -+}); -+ ++ } ++}; +Signals.addSignalMethods(LauncherEntryRemoteModel.prototype); + -+var LauncherEntryRemote = new Lang.Class({ -+ Name: 'DashToDock.LauncherEntryRemote', ++var LauncherEntryRemote = class DashToDock_LauncherEntryRemote { + -+ _init: function (dbusName, appId, properties) { ++ constructor(dbusName, appId, properties) { + this._dbusName = dbusName; + this._appId = appId; + this._count = 0; @@ -9698,69 +9391,69 @@ index 0000000..d051a70 + this._progress = 0.0; + this._progressVisible = false; + this.update(properties); -+ }, ++ } + -+ appId: function () { ++ appId() { + return this._appId; -+ }, ++ } + -+ dbusName: function () { ++ dbusName() { + return this._dbusName; -+ }, ++ } + -+ count: function () { ++ count() { + return this._count; -+ }, ++ } + -+ setCount: function (count) { ++ setCount(count) { + if (this._count != count) { + this._count = count; + this.emit('count-changed', this._count); + } -+ }, ++ } + -+ countVisible: function () { ++ countVisible() { + return this._countVisible; -+ }, ++ } + -+ setCountVisible: function (countVisible) { ++ setCountVisible(countVisible) { + if (this._countVisible != countVisible) { + this._countVisible = countVisible; + this.emit('count-visible-changed', this._countVisible); + } -+ }, ++ } + -+ progress: function () { ++ progress() { + return this._progress; -+ }, ++ } + -+ setProgress: function (progress) { ++ setProgress(progress) { + if (this._progress != progress) { + this._progress = progress; + this.emit('progress-changed', this._progress); + } -+ }, ++ } + -+ progressVisible: function () { ++ progressVisible() { + return this._progressVisible; -+ }, ++ } + -+ setProgressVisible: function (progressVisible) { ++ setProgressVisible(progressVisible) { + if (this._progressVisible != progressVisible) { + this._progressVisible = progressVisible; + this.emit('progress-visible-changed', this._progressVisible); + } -+ }, ++ } + -+ setDBusName: function (dbusName) { ++ setDBusName(dbusName) { + if (this._dbusName != dbusName) { + let oldName = this._dbusName; + this._dbusName = dbusName; + this.emit('dbus-name-changed', oldName); + } -+ }, ++ } + -+ update: function (other) { ++ update(other) { + if (other instanceof LauncherEntryRemote) { + this.setDBusName(other.dbusName()) + this.setCount(other.count()); @@ -9784,9 +9477,8 @@ index 0000000..d051a70 + } + } + } -+ }, -+}); -+ ++ } ++}; +Signals.addSignalMethods(LauncherEntryRemote.prototype); diff --git a/extensions/dash-to-dock/media/glossy.svg b/extensions/dash-to-dock/media/glossy.svg new file mode 100644 @@ -9933,6 +9625,182 @@ index 0000000..55b71ba + y="223.07919" /> + + +diff --git a/extensions/dash-to-dock/media/highlight_stacked_bg.svg b/extensions/dash-to-dock/media/highlight_stacked_bg.svg +new file mode 100644 +index 0000000..19be5a9 +--- /dev/null ++++ b/extensions/dash-to-dock/media/highlight_stacked_bg.svg +@@ -0,0 +1,82 @@ ++ ++ ++ ++ ++ ++ image/svg+xml ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/extensions/dash-to-dock/media/highlight_stacked_bg_h.svg b/extensions/dash-to-dock/media/highlight_stacked_bg_h.svg +new file mode 100644 +index 0000000..eeaa869 +--- /dev/null ++++ b/extensions/dash-to-dock/media/highlight_stacked_bg_h.svg +@@ -0,0 +1,82 @@ ++ ++ ++ ++ ++ ++ image/svg+xml ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ diff --git a/extensions/dash-to-dock/media/logo.svg b/extensions/dash-to-dock/media/logo.svg new file mode 100644 index 0000000..eebd0b1 @@ -10469,7 +10337,7 @@ index 0000000..eebd0b1 + diff --git a/extensions/dash-to-dock/meson.build b/extensions/dash-to-dock/meson.build new file mode 100644 -index 0000000..e0906fa +index 0000000..290374f --- /dev/null +++ b/extensions/dash-to-dock/meson.build @@ -0,0 +1,23 @@ @@ -10482,9 +10350,9 @@ index 0000000..e0906fa +extension_sources += files( + 'appIconIndicators.js', + 'appIcons.js', -+ 'convenience.js', + 'dash.js', + 'docking.js', ++ 'extension.js', + 'intellihide.js', + 'launcherAPI.js', + 'prefs.js', @@ -10498,7 +10366,7 @@ index 0000000..e0906fa +install_data(['media/logo.svg', 'media/glossy.svg'], install_dir: join_paths(extensiondir, uuid, 'media')) diff --git a/extensions/dash-to-dock/metadata.json.in b/extensions/dash-to-dock/metadata.json.in new file mode 100644 -index 0000000..90eddb5 +index 0000000..641a935 --- /dev/null +++ b/extensions/dash-to-dock/metadata.json.in @@ -0,0 +1,12 @@ @@ -10511,12 +10379,12 @@ index 0000000..90eddb5 +"name": "Dash to Dock", +"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.", +"shell-version": [ "@shell_current@" ], -+"version": 45, ++"version": 66, +"url": "https://micheleg.github.io/dash-to-dock/" +} diff --git a/extensions/dash-to-dock/org.gnome.shell.extensions.dash-to-dock.gschema.xml b/extensions/dash-to-dock/org.gnome.shell.extensions.dash-to-dock.gschema.xml new file mode 100644 -index 0000000..3e4f68a +index 0000000..9cf371b --- /dev/null +++ b/extensions/dash-to-dock/org.gnome.shell.extensions.dash-to-dock.gschema.xml @@ -0,0 +1,540 @@ @@ -10530,7 +10398,8 @@ index 0000000..3e4f68a + + + -+ ++ ++ + + + @@ -10553,7 +10422,6 @@ index 0000000..3e4f68a + + + -+ + + + @@ -10600,7 +10468,7 @@ index 0000000..3e4f68a + + 'DEFAULT' + Transparency mode for the dock -+ FIXED: constant transparency. ADAPTIVE: lock state with the top panel when not hidden. DYNAMIC: dock takes the opaque style only when windows are close to it. ++ FIXED: constant transparency. DYNAMIC: dock takes the opaque style only when windows are close to it. + + + 'DEFAULT' @@ -10615,7 +10483,7 @@ index 0000000..3e4f68a + + false + Manually set the min and max opacity -+ For Adaptive and Dynamic modes, the min/max opacity values will be given by 'min-alpha' and 'max-alpha'. ++ For the dynamic mode, the min/max opacity values will be given by 'min-alpha' and 'max-alpha'. + + + 0.2 @@ -10795,7 +10663,7 @@ index 0000000..3e4f68a + + + 'minimize' -+ Action when shit+clicking on a running app ++ Action when shift+clicking on a running app + Set the action that is executed when shift+clicking on the icon of a running application + + @@ -11062,10 +10930,10 @@ index 0000000..3e4f68a + diff --git a/extensions/dash-to-dock/prefs.js b/extensions/dash-to-dock/prefs.js new file mode 100644 -index 0000000..d8d8b94 +index 0000000..a72b139 --- /dev/null +++ b/extensions/dash-to-dock/prefs.js -@@ -0,0 +1,868 @@ +@@ -0,0 +1,861 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Gio = imports.gi.Gio; @@ -11073,7 +10941,6 @@ index 0000000..d8d8b94 +const GObject = imports.gi.GObject; +const Gtk = imports.gi.Gtk; +const Gdk = imports.gi.Gdk; -+const Lang = imports.lang; +const Mainloop = imports.mainloop; + +// Use __ () and N__() for the extension gettext domain, and reuse @@ -11084,7 +10951,6 @@ index 0000000..d8d8b94 + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); -+const Convenience = Me.imports.convenience; + +const SCALE_UPDATE_TIMEOUT = 500; +const DEFAULT_ICONS_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ]; @@ -11092,7 +10958,6 @@ index 0000000..d8d8b94 +const TransparencyMode = { + DEFAULT: 0, + FIXED: 1, -+ ADAPTIVE: 2, + DYNAMIC: 3 +}; + @@ -11152,11 +11017,10 @@ index 0000000..d8d8b94 + } +} + -+const Settings = new Lang.Class({ -+ Name: 'DashToDock.Settings', ++var Settings = class DashToDock_Settings { + -+ _init: function() { -+ this._settings = Convenience.getSettings('org.gnome.shell.extensions.dash-to-dock'); ++ constructor() { ++ this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.dash-to-dock'); + + this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL); + @@ -11169,11 +11033,11 @@ index 0000000..d8d8b94 + this.widget.add(this._notebook); + + // Set a reasonable initial window height -+ this.widget.connect('realize', Lang.bind(this, function() { ++ this.widget.connect('realize', () => { + let window = this.widget.get_toplevel(); + let [default_width, default_height] = window.get_default_size(); + window.resize(default_width, 650); -+ })); ++ }); + + // Timeout to delay the update of the settings + this._dock_size_timeout = 0; @@ -11182,17 +11046,145 @@ index 0000000..d8d8b94 + + this._bindSettings(); + -+ this._builder.connect_signals_full(Lang.bind(this, this._connector)); -+ }, ++ this._builder.connect_signals_full(this._connector.bind(this)); ++ } + + /** + * Connect signals + */ -+ _connector: function(builder, object, signal, handler) { -+ object.connect(signal, Lang.bind(this, this._SignalHandler[handler])); -+ }, ++ _connector(builder, object, signal, handler) { ++ /**init ++ * Object containing all signals defined in the glade file ++ */ ++ const SignalHandler = { ++ dock_display_combo_changed_cb(combo) { ++ this._settings.set_int('preferred-monitor', this._monitors[combo.get_active()]); ++ }, ++ ++ 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_format_value_cb(scale, value) { ++ return Math.round(value * 100) + ' %'; ++ }, ++ ++ dock_size_scale_value_changed_cb(scale) { ++ // Avoid settings the size consinuosly ++ if (this._dock_size_timeout > 0) ++ Mainloop.source_remove(this._dock_size_timeout); ++ ++ this._dock_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, () => { ++ this._settings.set_double('height-fraction', scale.get_value()); ++ this._dock_size_timeout = 0; ++ return GLib.SOURCE_REMOVE; ++ }); ++ }, ++ ++ icon_size_scale_format_value_cb(scale, value) { ++ return value + ' px'; ++ }, ++ ++ icon_size_scale_value_changed_cb(scale) { ++ // Avoid settings the size consinuosly ++ if (this._icon_size_timeout > 0) ++ Mainloop.source_remove(this._icon_size_timeout); ++ ++ this._icon_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, () => { ++ this._settings.set_int('dash-max-icon-size', scale.get_value()); ++ this._icon_size_timeout = 0; ++ return GLib.SOURCE_REMOVE; ++ }); ++ }, ++ ++ custom_opacity_scale_value_changed_cb(scale) { ++ // Avoid settings the opacity consinuosly as it's change is animated ++ if (this._opacity_timeout > 0) ++ Mainloop.source_remove(this._opacity_timeout); ++ ++ this._opacity_timeout = Mainloop.timeout_add(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) ++ Mainloop.source_remove(this._opacity_timeout); ++ ++ this._opacity_timeout = Mainloop.timeout_add(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) ++ Mainloop.source_remove(this._opacity_timeout); ++ ++ this._opacity_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, () => { ++ this._settings.set_double('max-alpha', scale.get_value()); ++ this._opacity_timeout = 0; ++ return GLib.SOURCE_REMOVE; ++ }); ++ }, ++ ++ custom_opacity_scale_format_value_cb(scale, value) { ++ return Math.round(value * 100) + ' %'; ++ }, ++ ++ min_opacity_scale_format_value_cb(scale, value) { ++ return Math.round(value * 100) + ' %'; ++ }, ++ ++ max_opacity_scale_format_value_cb(scale, value) { ++ return Math.round(value * 100) + ' %'; ++ }, ++ ++ 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); ++ } ++ } ++ ++ object.connect(signal, SignalHandler[handler].bind(this)); ++ } + -+ _bindSettings: function() { ++ _bindSettings() { + // Position and size panel + + // Monitor options @@ -11295,7 +11287,7 @@ index 0000000..d8d8b94 + //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', Lang.bind(this, function() { ++ this._builder.get_object('intelligent_autohide_button').connect('clicked', () => { + + let dialog = new Gtk.Dialog({ title: __('Intelligent autohide customization'), + transient_for: this.widget.get_toplevel(), @@ -11351,7 +11343,7 @@ index 0000000..d8d8b94 + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + -+ dialog.connect('response', Lang.bind(this, function(dialog, id) { ++ 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', @@ -11366,11 +11358,11 @@ index 0000000..d8d8b94 + dialog.destroy(); + } + return; -+ })); ++ }); + + dialog.show_all(); + -+ })); ++ }); + + // size options + this._builder.get_object('dock_size_scale').set_value(this._settings.get_double('height-fraction')); @@ -11459,28 +11451,28 @@ index 0000000..d8d8b94 + 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', Lang.bind (this, function(widget) { ++ 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', Lang.bind (this, function(widget) { ++ 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', Lang.bind (this, function(widget) { ++ 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', Lang.bind (this, function(widget) { ++ 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', Lang.bind (this, function(widget) { ++ }); ++ 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', Lang.bind(this, function() { ++ this._builder.get_object('overlay_button').connect('clicked', () => { + + let dialog = new Gtk.Dialog({ title: __('Show dock and application numbers'), + transient_for: this.widget.get_toplevel(), @@ -11498,7 +11490,7 @@ index 0000000..d8d8b94 + 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', Lang.bind(this, function() {setShortcut(this._settings);})); ++ this._settings.connect('changed::shortcut-text', () => {setShortcut(this._settings);}); + this._settings.bind('shortcut-text', + this._builder.get_object('shortcut_entry'), + 'text', @@ -11517,7 +11509,7 @@ index 0000000..d8d8b94 + 'value', + Gio.SettingsBindFlags.DEFAULT); + -+ dialog.connect('response', Lang.bind(this, function(dialog, id) { ++ 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']; @@ -11530,14 +11522,13 @@ index 0000000..d8d8b94 + dialog.destroy(); + } + return; -+ })); ++ }); + + dialog.show_all(); -+ -+ })); ++ }); + + // Create dialog for middle-click options -+ this._builder.get_object('middle_click_options_button').connect('clicked', Lang.bind(this, function() { ++ 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_toplevel(), @@ -11570,7 +11561,7 @@ index 0000000..d8d8b94 + 'active-id', + Gio.SettingsBindFlags.DEFAULT); + -+ dialog.connect('response', Lang.bind(this, function(dialog, id) { ++ 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']; @@ -11586,11 +11577,11 @@ index 0000000..d8d8b94 + dialog.destroy(); + } + return; -+ })); ++ }); + + dialog.show_all(); + -+ })); ++ }); + + // Appearance Panel + @@ -11604,23 +11595,23 @@ index 0000000..d8d8b94 + ); + this._builder.get_object('running_indicators_combo').connect( + 'changed', -+ Lang.bind (this, function(widget) { ++ (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', Lang.bind(this, function() { ++ 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', Lang.bind(this, function() { ++ 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_toplevel(), @@ -11647,22 +11638,22 @@ index 0000000..d8d8b94 + 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::color', Lang.bind(this, function(button) { ++ this._builder.get_object('dot_color_colorbutton').connect('notify::color', (button) => { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('custom-theme-running-dots-color', hexString); -+ })); ++ }); + + 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::color', Lang.bind(this, function(button) { ++ this._builder.get_object('dot_border_color_colorbutton').connect('notify::color', (button) => { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('custom-theme-running-dots-border-color', hexString); -+ })); ++ }); + + this._settings.bind('custom-theme-running-dots-border-width', + this._builder.get_object('dot_border_width_spin_button'), @@ -11670,16 +11661,16 @@ index 0000000..d8d8b94 + Gio.SettingsBindFlags.DEFAULT); + + -+ dialog.connect('response', Lang.bind(this, function(dialog, id) { ++ 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.show_all(); + -+ })); ++ }); + + 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); @@ -11688,12 +11679,12 @@ index 0000000..d8d8b94 + 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::color', Lang.bind(this, function(button) { ++ this._builder.get_object('custom_background_color').connect('notify::color', (button) => { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('background-color', hexString); -+ })); ++ }); + + // Opacity + this._builder.get_object('customize_opacity_combo').set_active( @@ -11701,9 +11692,9 @@ index 0000000..d8d8b94 + ); + this._builder.get_object('customize_opacity_combo').connect( + 'changed', -+ Lang.bind (this, function(widget) { ++ (widget) => { + this._settings.set_enum('transparency-mode', widget.get_active()); -+ }) ++ } + ); + + this._builder.get_object('custom_opacity_scale').set_value(this._settings.get_double('background-opacity')); @@ -11711,30 +11702,28 @@ index 0000000..d8d8b94 + 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', Lang.bind(this, function() { ++ 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.ADAPTIVE && -+ this._settings.get_enum('transparency-mode') !== TransparencyMode.DYNAMIC) { ++ 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', Lang.bind(this, function() { -+ if (this._settings.get_enum('transparency-mode') !== TransparencyMode.ADAPTIVE && -+ this._settings.get_enum('transparency-mode') !== TransparencyMode.DYNAMIC) { ++ 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', Lang.bind(this, function() { ++ this._builder.get_object('dynamic_opacity_button').connect('clicked', () => { + + let dialog = new Gtk.Dialog({ title: __('Cutomize opacity'), + transient_for: this.widget.get_toplevel(), @@ -11770,15 +11759,15 @@ index 0000000..d8d8b94 + this._settings.get_double('max-alpha') + ); + -+ dialog.connect('response', Lang.bind(this, function(dialog, id) { ++ 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.show_all(); -+ })); ++ }); + + + this._settings.bind('unity-backlit-items', @@ -11793,139 +11782,11 @@ index 0000000..d8d8b94 + // About Panel + + this._builder.get_object('extension_version').set_label(Me.metadata.version.toString()); -+ }, -+ -+ /** -+ * Object containing all signals defined in the glade file -+ */ -+ _SignalHandler: { -+ dock_display_combo_changed_cb: function(combo) { -+ this._settings.set_int('preferred-monitor', this._monitors[combo.get_active()]); -+ }, -+ -+ position_top_button_toggled_cb: function(button) { -+ if (button.get_active()) -+ this._settings.set_enum('dock-position', 0); -+ }, -+ -+ position_right_button_toggled_cb: function(button) { -+ if (button.get_active()) -+ this._settings.set_enum('dock-position', 1); -+ }, -+ -+ position_bottom_button_toggled_cb: function(button) { -+ if (button.get_active()) -+ this._settings.set_enum('dock-position', 2); -+ }, -+ -+ position_left_button_toggled_cb: function(button) { -+ if (button.get_active()) -+ this._settings.set_enum('dock-position', 3); -+ }, -+ -+ icon_size_combo_changed_cb: function(combo) { -+ this._settings.set_int('dash-max-icon-size', this._allIconSizes[combo.get_active()]); -+ }, -+ -+ dock_size_scale_format_value_cb: function(scale, value) { -+ return Math.round(value*100)+ ' %'; -+ }, -+ -+ dock_size_scale_value_changed_cb: function(scale) { -+ // Avoid settings the size consinuosly -+ if (this._dock_size_timeout > 0) -+ Mainloop.source_remove(this._dock_size_timeout); -+ -+ this._dock_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { -+ this._settings.set_double('height-fraction', scale.get_value()); -+ this._dock_size_timeout = 0; -+ return GLib.SOURCE_REMOVE; -+ })); -+ }, -+ -+ icon_size_scale_format_value_cb: function(scale, value) { -+ return value+ ' px'; -+ }, -+ -+ icon_size_scale_value_changed_cb: function(scale) { -+ // Avoid settings the size consinuosly -+ if (this._icon_size_timeout > 0) -+ Mainloop.source_remove(this._icon_size_timeout); -+ -+ this._icon_size_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { -+ this._settings.set_int('dash-max-icon-size', scale.get_value()); -+ this._icon_size_timeout = 0; -+ return GLib.SOURCE_REMOVE; -+ })); -+ }, -+ -+ custom_opacity_scale_value_changed_cb: function(scale) { -+ // Avoid settings the opacity consinuosly as it's change is animated -+ if (this._opacity_timeout > 0) -+ Mainloop.source_remove(this._opacity_timeout); -+ -+ this._opacity_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { -+ this._settings.set_double('background-opacity', scale.get_value()); -+ this._opacity_timeout = 0; -+ return GLib.SOURCE_REMOVE; -+ })); -+ }, -+ -+ min_opacity_scale_value_changed_cb: function(scale) { -+ // Avoid settings the opacity consinuosly as it's change is animated -+ if (this._opacity_timeout > 0) -+ Mainloop.source_remove(this._opacity_timeout); -+ -+ this._opacity_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { -+ this._settings.set_double('min-alpha', scale.get_value()); -+ this._opacity_timeout = 0; -+ return GLib.SOURCE_REMOVE; -+ })); -+ }, -+ -+ max_opacity_scale_value_changed_cb: function(scale) { -+ // Avoid settings the opacity consinuosly as it's change is animated -+ if (this._opacity_timeout > 0) -+ Mainloop.source_remove(this._opacity_timeout); -+ -+ this._opacity_timeout = Mainloop.timeout_add(SCALE_UPDATE_TIMEOUT, Lang.bind(this, function() { -+ this._settings.set_double('max-alpha', scale.get_value()); -+ this._opacity_timeout = 0; -+ return GLib.SOURCE_REMOVE; -+ })); -+ }, -+ -+ custom_opacity_scale_format_value_cb: function(scale, value) { -+ return Math.round(value*100) + ' %'; -+ }, -+ -+ min_opacity_scale_format_value_cb: function(scale, value) { -+ return Math.round(value*100) + ' %'; -+ }, -+ -+ max_opacity_scale_format_value_cb: function(scale, value) { -+ return Math.round(value*100) + ' %'; -+ }, -+ -+ all_windows_radio_button_toggled_cb: function(button) { -+ if (button.get_active()) -+ this._settings.set_enum('intellihide-mode', 0); -+ }, -+ -+ focus_application_windows_radio_button_toggled_cb: function(button) { -+ if (button.get_active()) -+ this._settings.set_enum('intellihide-mode', 1); -+ }, -+ -+ maximized_windows_radio_button_toggled_cb: function(button) { -+ if (button.get_active()) -+ this._settings.set_enum('intellihide-mode', 2); -+ } + } -+}); ++}; + +function init() { -+ Convenience.initTranslations(); ++ ExtensionUtils.initTranslations(); +} + +function buildPrefsWidget() { @@ -11936,10 +11797,10 @@ index 0000000..d8d8b94 +} diff --git a/extensions/dash-to-dock/stylesheet.css b/extensions/dash-to-dock/stylesheet.css new file mode 100644 -index 0000000..6e9bf38 +index 0000000..26cc960 --- /dev/null +++ b/extensions/dash-to-dock/stylesheet.css -@@ -0,0 +1,109 @@ +@@ -0,0 +1,175 @@ +/* Shrink the dash by reducing padding and border radius */ +#dashtodockContainer.shrink #dash, +#dashtodockContainer.dashtodock #dash { @@ -12030,31 +11891,98 @@ index 0000000..6e9bf38 + +#dashtodockContainer.running-dots .app-well-app.focused .overview-icon, +#dashtodockContainer.dashtodock .app-well-app.focused .overview-icon { -+ background-color: rgba(238, 238, 236, 0.1); ++ background-color: rgba(238, 238, 236, 0.2); +} + +#dashtodockContainer.dashtodock #dash { + background: #2e3436; +} + ++/* ++ * 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.opaque { ++} ++ ++#dashtodockContainer.transparent { ++} ++ +#dashtodockContainer .number-overlay { + color: rgba(255,255,255,1); + background-color: rgba(0,0,0,0.8); + text-align: center; +} + ++#dashtodockContainer .notification-badge { ++ color: rgba(255,255,255,1); ++ background-color: rgba(255,0,0,1.0); ++ 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.bottom .metro.running3.focused, ++#dashtodockContainer.bottom .metro.running4.focused, ++#dashtodockContainer.top .metro.running2.focused, ++#dashtodockContainer.top .metro.running3.focused, ++#dashtodockContainer.top .metro.running4.focused { ++ background-image: url('./media/highlight_stacked_bg.svg'); ++ background-position: 0px 0px; ++ background-size: contain; ++} ++ ++#dashtodockContainer.left .metro.running2.focused, ++#dashtodockContainer.left .metro.running3.focused, ++#dashtodockContainer.left .metro.running4.focused, ++#dashtodockContainer.right .metro.running2.focused, ++#dashtodockContainer.right .metro.running3.focused, ++#dashtodockContainer.right .metro.running4.focused { ++ background-image: url('./media/highlight_stacked_bg_h.svg'); ++ background-position: 0px 0px; ++ background-size: contain; ++} +\ No newline at end of file diff --git a/extensions/dash-to-dock/theming.js b/extensions/dash-to-dock/theming.js new file mode 100644 -index 0000000..4b18d1a +index 0000000..596574d --- /dev/null +++ b/extensions/dash-to-dock/theming.js -@@ -0,0 +1,672 @@ +@@ -0,0 +1,569 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; @@ -12062,7 +11990,6 @@ index 0000000..4b18d1a +const GLib = imports.gi.GLib; +const Gtk = imports.gi.Gtk; +const Signals = imports.signals; -+const Lang = imports.lang; +const Meta = imports.gi.Meta; +const Shell = imports.gi.Shell; +const St = imports.gi.St; @@ -12086,26 +12013,20 @@ index 0000000..4b18d1a +/* + * DEFAULT: transparency given by theme + * FIXED: constant transparency chosen by user -+ * ADAPTIVE: apply 'transparent' style to dock AND panel when -+ * no windows are close to the dock OR panel. -+ * When dock is hidden, the dock 'transparent' style only -+ * apply to itself. + * DYNAMIC: apply 'transparent' style when no windows are close to the dock + * */ +const TransparencyMode = { + DEFAULT: 0, + FIXED: 1, -+ ADAPTIVE: 2, + DYNAMIC: 3 +}; + +/** + * Manage theme customization and custom theme support + */ -+var ThemeManager = new Lang.Class({ -+ Name: 'DashToDock.ThemeManager', ++var ThemeManager = class DashToDock_ThemeManager { + -+ _init: function(settings, dock) { ++ constructor(settings, dock) { + this._settings = settings; + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._bindSettingsChanges(); @@ -12121,40 +12042,40 @@ index 0000000..4b18d1a + // When theme changes re-obtain default background color + St.ThemeContext.get_for_stage (global.stage), + 'changed', -+ Lang.bind(this, this.updateCustomTheme) ++ this.updateCustomTheme.bind(this) + ], [ + // update :overview pseudoclass + Main.overview, + 'showing', -+ Lang.bind(this, this._onOverviewShowing) ++ this._onOverviewShowing.bind(this) + ], [ + Main.overview, + 'hiding', -+ Lang.bind(this, this._onOverviewHiding) ++ this._onOverviewHiding.bind(this) + ]); + + this._updateCustomStyleClasses(); + + // destroy themeManager when the managed actor is destroyed (e.g. extension unload) + // in order to disconnect signals -+ this._actor.connect('destroy', Lang.bind(this, this.destroy)); ++ this._actor.connect('destroy', this.destroy.bind(this)); + -+ }, ++ } + -+ destroy: function() { ++ destroy() { + this._signalsHandler.destroy(); + this._transparency.destroy(); -+ }, ++ } + -+ _onOverviewShowing: function() { ++ _onOverviewShowing() { + this._actor.add_style_pseudo_class('overview'); -+ }, ++ } + -+ _onOverviewHiding: function() { ++ _onOverviewHiding() { + this._actor.remove_style_pseudo_class('overview'); -+ }, ++ } + -+ _updateDashOpacity: function() { ++ _updateDashOpacity() { + let newAlpha = this._settings.get_double('background-opacity'); + + let [backgroundColor, borderColor] = this._getDefaultColors(); @@ -12183,9 +12104,9 @@ index 0000000..4b18d1a + borderColor.blue + ',' + + borderAlpha + ')'; + -+ }, ++ } + -+ _getDefaultColors: function() { ++ _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()) @@ -12212,9 +12133,9 @@ index 0000000..4b18d1a + let borderColor = themeNode.get_border_color(side); + + return [backgroundColor, borderColor]; -+ }, ++ } + -+ _updateDashColor: function() { ++ _updateDashColor() { + // Retrieve the color. If needed we will adjust it before passing it to + // this._transparency. + let [backgroundColor, borderColor] = this._getDefaultColors(); @@ -12225,7 +12146,7 @@ index 0000000..4b18d1a + if (this._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 'adaptive' or 'dynamic' transparency modes, ++ // 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; + if (this._settings.get_enum('transparency-mode') == TransparencyMode.FIXED) @@ -12241,9 +12162,9 @@ index 0000000..4b18d1a + this._customizedBorder = this._customizedBackground; + } + this._transparency.setColor(backgroundColor); -+ }, ++ } + -+ _updateCustomStyleClasses: function() { ++ _updateCustomStyleClasses() { + if (this._settings.get_boolean('apply-custom-theme')) + this._actor.add_style_class_name('dashtodock'); + else @@ -12268,20 +12189,20 @@ index 0000000..4b18d1a + } else { + this._actor.remove_style_class_name('straight-corner'); + } -+ }, ++ } + -+ updateCustomTheme: function() { ++ updateCustomTheme() { + this._updateCustomStyleClasses(); + this._updateDashOpacity(); + this._updateDashColor(); + this._adjustTheme(); + this._dash._redisplay(); -+ }, ++ } + + /** + * Reimported back and adapted from atomdock + */ -+ _adjustTheme: function() { ++ _adjustTheme() { + // Prevent shell crash if the actor is not on the stage. + // It happens enabling/disabling repeatedly the extension + if (!this._dash._container.get_stage()) @@ -12358,9 +12279,9 @@ index 0000000..4b18d1a + 'transition-delay: 0s; transition-duration: 0.250s;'; + this._dash._container.set_style(newStyle); + } -+ }, ++ } + -+ _bindSettingsChanges: function() { ++ _bindSettingsChanges() { + let keys = ['transparency-mode', + 'customize-alphas', + 'min-alpha', @@ -12378,21 +12299,20 @@ index 0000000..4b18d1a + this._signalsHandler.add([ + this._settings, + 'changed::' + key, -+ Lang.bind(this, this.updateCustomTheme) ++ this.updateCustomTheme.bind(this) + ]); + }, this); + } -+}); ++}; + +/** + * The following class is based on the following upstream commit: + * https://git.gnome.org/browse/gnome-shell/commit/?id=447bf55e45b00426ed908b1b1035f472c2466956 + * Transparency when free-floating + */ -+const Transparency = new Lang.Class({ -+ Name: 'DashToDock.Transparency', ++var Transparency = class DashToDock_Transparency { + -+ _init: function(settings, dock) { ++ constructor(settings, dock) { + this._settings = settings; + this._dash = dock.dash; + this._actor = this._dash._container; @@ -12401,6 +12321,7 @@ index 0000000..4b18d1a + this._panel = Main.panel; + this._position = Utils.getPosition(this._settings); + ++ // 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'; @@ -12408,61 +12329,65 @@ index 0000000..4b18d1a + this._opaqueAlphaBorder = '0.5'; + this._transparentTransition = '0ms'; + this._opaqueTransition = '0ms'; -+ -+ this._updateStyles(); ++ this._base_actor_style = ""; + + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._injectionsHandler = new Utils.InjectionsHandler(); + this._trackedWindows = new Map(); -+ }, ++ } + -+ enable: function() { ++ 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', -+ Lang.bind(this, this._onWindowActorAdded) ++ this._onWindowActorAdded.bind(this) + ], [ + global.window_group, + 'actor-removed', -+ Lang.bind(this, this._onWindowActorRemoved) ++ this._onWindowActorRemoved.bind(this) + ], [ + global.window_manager, + 'switch-workspace', -+ Lang.bind(this, this._updateSolidStyle) ++ this._updateSolidStyle.bind(this) + ], [ + Main.overview, + 'hiding', -+ Lang.bind(this, this._updateSolidStyle) ++ this._updateSolidStyle.bind(this) + ], [ + Main.overview, + 'showing', -+ Lang.bind(this, this._updateSolidStyle) ++ this._updateSolidStyle.bind(this) + ]); + + // Window signals -+ global.get_window_actors().forEach(function(win) { ++ 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. -+ if (win.get_meta_window().get_wm_class() !== 'Gnome-shell') -+ this._onWindowActorAdded(null, win); ++ return child instanceof Meta.WindowActor && ++ child.get_meta_window().get_wm_class() !== 'Gnome-shell'; ++ }).forEach(function(win) { ++ this._onWindowActorAdded(null, win); + }, this); + -+ if (this._settings.get_enum('transparency-mode') === TransparencyMode.ADAPTIVE) -+ this._enableAdaptive(); -+ + if (this._actor.get_stage()) + this._updateSolidStyle(); + -+ this.emit('transparency-enabled'); -+ }, ++ this._updateStyles(); ++ this._updateSolidStyle(); + -+ disable: function() { -+ this._disableAdaptive(); ++ this.emit('transparency-enabled'); ++ } + ++ disable() { + // ensure I never double-register/inject + // although it should never happen + this._signalsHandler.removeWithLabel('transparency'); @@ -12474,23 +12399,23 @@ index 0000000..4b18d1a + this._trackedWindows.clear(); + + this.emit('transparency-disabled'); -+ }, ++ } + -+ destroy: function() { ++ destroy() { + this.disable(); + this._signalsHandler.destroy(); + this._injectionsHandler.destroy(); -+ }, ++ } + -+ _onWindowActorAdded: function(container, metaWindowActor) { ++ _onWindowActorAdded(container, metaWindowActor) { + let signalIds = []; + ['allocation-changed', 'notify::visible'].forEach(s => { -+ signalIds.push(metaWindowActor.connect(s, Lang.bind(this, this._updateSolidStyle))); ++ signalIds.push(metaWindowActor.connect(s, this._updateSolidStyle.bind(this))); + }); + this._trackedWindows.set(metaWindowActor, signalIds); -+ }, ++ } + -+ _onWindowActorRemoved: function(container, metaWindowActor) { ++ _onWindowActorRemoved(container, metaWindowActor) { + if (!this._trackedWindows.get(metaWindowActor)) + return; + @@ -12499,33 +12424,29 @@ index 0000000..4b18d1a + }); + this._trackedWindows.delete(metaWindowActor); + this._updateSolidStyle(); -+ }, ++ } + -+ _updateSolidStyle: function() { -+ let isNear = this._dockIsNear() || this._panelIsNear(); ++ _updateSolidStyle() { ++ let isNear = this._dockIsNear(); + if (isNear) { + this._actor.set_style(this._opaque_style); -+ if (this._panel._updateSolidStyle && this._adaptiveEnabled) { -+ if (this._settings.get_boolean('dock-fixed') || this._panelIsNear()) -+ this._panel._addStyleClassName('solid'); -+ else -+ this._panel._removeStyleClassName('solid'); -+ } ++ this._dockActor.remove_style_class_name('transparent'); ++ this._dockActor.add_style_class_name('opaque'); + } + else { + this._actor.set_style(this._transparent_style); -+ if (this._panel._updateSolidStyle && this._adaptiveEnabled) -+ this._panel._removeStyleClassName('solid'); ++ this._dockActor.remove_style_class_name('opaque'); ++ this._dockActor.add_style_class_name('transparent'); + } + + this.emit('solid-style-updated', isNear); -+ }, ++ } + -+ _dockIsNear: function() { ++ _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.screen.get_active_workspace(); ++ 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 && @@ -12553,7 +12474,7 @@ index 0000000..4b18d1a + threshold = topCoord - this._actor.get_height() * factor; + + let scale = St.ThemeContext.get_for_stage(global.stage).scale_factor; -+ let isNearEnough = windows.some(Lang.bind(this, function(metaWindow) { ++ let isNearEnough = windows.some((metaWindow) => { + let coord; + if (this._position === St.Side.LEFT) { + coord = metaWindow.get_frame_rect().x; @@ -12571,53 +12492,22 @@ index 0000000..4b18d1a + coord = metaWindow.get_frame_rect().y + metaWindow.get_frame_rect().height; + return coord > threshold - 5 * scale; + } -+ })); -+ -+ return isNearEnough; -+ }, -+ -+ _panelIsNear: function() { -+ if (!this._panel._updateSolidStyle || -+ this._settings.get_enum('transparency-mode') !== TransparencyMode.ADAPTIVE) -+ return false; -+ -+ if (this._panel.actor.has_style_pseudo_class('overview') || !Main.sessionMode.hasWindows) { -+ this._panel._removeStyleClassName('solid'); -+ return false; -+ } -+ -+ /* Get all the windows in the active workspace that are in the -+ * primary monitor and visible */ -+ let activeWorkspace = global.screen.get_active_workspace(); -+ let windows = activeWorkspace.list_windows().filter(function(metaWindow) { -+ return metaWindow.is_on_primary_monitor() && -+ metaWindow.showing_on_its_workspace() && -+ metaWindow.get_window_type() != Meta.WindowType.DESKTOP; + }); + -+ /* Check if at least one window is near enough to the panel */ -+ let [, panelTop] = this._panel.actor.get_transformed_position(); -+ let panelBottom = panelTop + this._panel.actor.get_height(); -+ let scale = St.ThemeContext.get_for_stage(global.stage).scale_factor; -+ let isNearEnough = windows.some(Lang.bind(this._panel, function(metaWindow) { -+ let verticalPosition = metaWindow.get_frame_rect().y; -+ return verticalPosition < panelBottom + 5 * scale; -+ })); -+ + return isNearEnough; -+ }, ++ } + -+ _updateStyles: function() { ++ _updateStyles() { + this._getAlphas(); + -+ this._transparent_style = ++ 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._opaque_style = this._base_actor_style + + 'background-color: rgba(' + + this._backgroundColor + ', ' + this._opaqueAlpha + ');' + + 'border-color: rgba(' + @@ -12625,27 +12515,27 @@ index 0000000..4b18d1a + 'transition-duration: ' + this._opaqueTransition + 'ms;'; + + this.emit('styles-updated'); -+ }, ++ } + -+ setColor: function(color) { ++ setColor(color) { + this._backgroundColor = color.red + ',' + color.green + ',' + color.blue; + this._updateStyles(); -+ }, ++ } + -+ _getAlphas: function() { ++ _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('opaque'); ++ 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('transparent'); ++ 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; @@ -12659,108 +12549,42 @@ index 0000000..4b18d1a + this._transparentAlpha = this._settings.get_double('min-alpha'); + this._transparentAlphaBorder = this._transparentAlpha / 2; + } -+ -+ if (this._settings.get_enum('transparency-mode') === TransparencyMode.ADAPTIVE && -+ this._panel._updateSolidStyle) { -+ themeNode = this._panel.actor.get_theme_node(); -+ if (this._panel.actor.has_style_class_name('solid')) { -+ this._opaqueTransition = themeNode.get_transition_duration(); -+ this._panel._removeStyleClassName('solid'); -+ themeNode = this._panel.actor.get_theme_node(); -+ this._transparentTransition = themeNode.get_transition_duration(); -+ this._panel._addStyleClassName('solid'); -+ } -+ else { -+ this._transparentTransition = themeNode.get_transition_duration(); -+ this._panel._addStyleClassName('solid'); -+ themeNode = this._panel.actor.get_theme_node(); -+ this._opaqueTransition = themeNode.get_transition_duration(); -+ this._panel._removeStyleClassName('solid'); -+ } -+ } -+ }, -+ -+ _enableAdaptive: function() { -+ if (!this._panel._updateSolidStyle || -+ this._dash._monitorIndex !== Main.layoutManager.primaryIndex) -+ return; -+ -+ this._adaptiveEnabled = true; -+ -+ function UpdateSolidStyle() { -+ return; -+ } -+ -+ this._injectionsHandler.addWithLabel('adaptive', [ -+ this._panel, -+ '_updateSolidStyle', -+ UpdateSolidStyle -+ ]); -+ -+ // Once we injected the new function, we need to disconnect and -+ // reconnect all window signals. -+ for (let key of this._panel._trackedWindows.keys()) -+ this._panel._trackedWindows.get(key).forEach(id => { -+ key.disconnect(id); -+ }); -+ -+ for (let win of this._panel._trackedWindows.keys()) -+ this._panel._onWindowActorAdded(null, win); -+ }, -+ -+ _disableAdaptive: function() { -+ if (!this._adaptiveEnabled) -+ return; -+ -+ this._injectionsHandler.removeWithLabel('adaptive'); -+ this._adaptiveEnabled = false; -+ -+ // Once we removed the injection, we need to disconnect and -+ // reconnect all window signals. -+ for (let key of this._panel._trackedWindows.keys()) -+ this._panel._trackedWindows.get(key).forEach(id => { -+ key.disconnect(id); -+ }); -+ -+ for (let win of this._panel._trackedWindows.keys()) -+ this._panel._onWindowActorAdded(null, win); + } -+}); ++}; +Signals.addSignalMethods(Transparency.prototype); diff --git a/extensions/dash-to-dock/utils.js b/extensions/dash-to-dock/utils.js new file mode 100644 -index 0000000..6514649 +index 0000000..d315bd9 --- /dev/null +++ b/extensions/dash-to-dock/utils.js -@@ -0,0 +1,255 @@ +@@ -0,0 +1,258 @@ +const Clutter = imports.gi.Clutter; -+const Lang = imports.lang; ++const Meta = imports.gi.Meta; +const St = imports.gi.St; + +/** + * Simplify global signals and function injections handling + * abstract class + */ -+const BasicHandler = new Lang.Class({ -+ Name: 'DashToDock.BasicHandler', ++const BasicHandler = class DashToDock_BasicHandler { + -+ _init: function() { ++ constructor() { + this._storage = new Object(); -+ }, ++ } + -+ add: function(/* unlimited 3-long array arguments */) { ++ add(/* unlimited 3-long array arguments */) { + // Convert arguments object to array, concatenate with generic + let args = Array.concat('generic', Array.slice(arguments)); + // Call addWithLabel with ags as if they were passed arguments + this.addWithLabel.apply(this, args); -+ }, ++ } + -+ destroy: function() { ++ destroy() { + for( let label in this._storage ) + this.removeWithLabel(label); -+ }, ++ } + -+ addWithLabel: function(label /* plus unlimited 3-long array arguments*/) { ++ addWithLabel(label /* plus unlimited 3-long array arguments*/) { + if (this._storage[label] == undefined) + this._storage[label] = new Array(); + @@ -12769,79 +12593,85 @@ index 0000000..6514649 + let item = this._storage[label]; + item.push(this._create(arguments[i])); + } -+ }, ++ } + -+ removeWithLabel: function(label) { ++ 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: function(item) { ++ _create(item) { + throw new Error('no implementation of _create in ' + this); -+ }, ++ } + + /** + * Correctly delete single element + */ -+ _remove: function(item) { ++ _remove(item) { + throw new Error('no implementation of _remove in ' + this); + } -+}); ++}; + +/** + * Manage global signals + */ -+var GlobalSignalsHandler = new Lang.Class({ -+ Name: 'DashToDock.GlobalSignalHandler', -+ Extends: BasicHandler, ++var GlobalSignalsHandler = class DashToDock_GlobalSignalHandler extends BasicHandler { + -+ _create: function(item) { ++ _create(item) { + let object = item[0]; + let event = item[1]; + let callback = item[2] + let id = object.connect(event, callback); + + return [object, id]; -+ }, ++ } + -+ _remove: function(item) { ++ _remove(item) { + item[0].disconnect(item[1]); + } -+}); ++}; + +/** + * Color manipulation utilities + */ -+var ColorUtils = { ++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 -+ ColorLuminance: function(r, g, b, dlum) { ++ static ColorLuminance(r, g, b, dlum) { + let rgbString = '#'; + -+ rgbString += Math.round(Math.min(Math.max(r*(1+dlum), 0), 255)).toString(16); -+ rgbString += Math.round(Math.min(Math.max(g*(1+dlum), 0), 255)).toString(16); -+ rgbString += Math.round(Math.min(Math.max(b*(1+dlum), 0), 255)).toString(16); ++ 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. -+ HSVtoRGB: function(h, s, v) { ++ static HSVtoRGB(h, s, v) { + if (arguments.length === 1) { + s = h.s; + v = h.v; @@ -12872,14 +12702,14 @@ index 0000000..6514649 + 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. -+ RGBtoHSV: function (r, g, b) { ++ static RGBtoHSV(r, g, b) { + if (arguments.length === 1) { + r = r.r; + g = r.g; @@ -12920,11 +12750,9 @@ index 0000000..6514649 + * Manage function injection: both instances and prototype can be overridden + * and restored + */ -+var InjectionsHandler = new Lang.Class({ -+ Name: 'DashToDock.InjectionsHandler', -+ Extends: BasicHandler, ++var InjectionsHandler = class DashToDock_InjectionsHandler extends BasicHandler { + -+ _create: function(item) { ++ _create(item) { + let object = item[0]; + let name = item[1]; + let injectedFunction = item[2]; @@ -12932,15 +12760,15 @@ index 0000000..6514649 + + object[name] = injectedFunction; + return [object, name, injectedFunction, original]; -+ }, ++ } + -+ _remove: function(item) { ++ _remove(item) { + let object = item[0]; + let name = item[1]; + let original = item[3]; + object[name] = original; + } -+}); ++}; + +/** + * Return the actual position reverseing left and right in rtl @@ -12990,10 +12818,10 @@ index 0000000..6514649 +} diff --git a/extensions/dash-to-dock/windowPreview.js b/extensions/dash-to-dock/windowPreview.js new file mode 100644 -index 0000000..4b99aa8 +index 0000000..ea98f27 --- /dev/null +++ b/extensions/dash-to-dock/windowPreview.js -@@ -0,0 +1,630 @@ +@@ -0,0 +1,578 @@ +/* + * Credits: + * This file is based on code from the Dash to Panel extension by Jason DeRose @@ -13002,7 +12830,6 @@ index 0000000..4b99aa8 + */ +const Clutter = imports.gi.Clutter; +const GLib = imports.gi.GLib; -+const Lang = imports.lang; +const St = imports.gi.St; +const Mainloop = imports.mainloop; +const Main = imports.ui.main; @@ -13019,16 +12846,13 @@ index 0000000..4b99aa8 +const PREVIEW_MAX_WIDTH = 250; +const PREVIEW_MAX_HEIGHT = 150; + -+const WindowPreviewMenu = new Lang.Class({ -+ Name: 'WindowPreviewMenu', -+ Extends: PopupMenu.PopupMenu, -+ -+ _init: function(source, settings) { -+ this._dtdSettings = settings; ++var WindowPreviewMenu = class DashToDock_WindowPreviewMenu extends PopupMenu.PopupMenu { + ++ constructor(source, settings) { + let side = Utils.getPosition(settings); ++ super(source.actor, 0.5, side); + -+ this.parent(source.actor, 0.5, side); ++ this._dtdSettings = settings; + + // We want to keep the item hovered while the menu is up + this.blockSourceEvents = true; @@ -13043,11 +12867,11 @@ index 0000000..4b99aa8 + this.actor.hide(); + + // Chain our visibility and lifecycle to that of the source -+ this._mappedId = this._source.actor.connect('notify::mapped', Lang.bind(this, function () { ++ this._mappedId = this._source.actor.connect('notify::mapped', () => { + if (!this._source.actor.mapped) + this.close(); -+ })); -+ this._destroyId = this._source.actor.connect('destroy', Lang.bind(this, this.destroy)); ++ }); ++ this._destroyId = this._source.actor.connect('destroy', this.destroy.bind(this)); + + Main.uiGroup.add_actor(this.actor); + @@ -13056,16 +12880,18 @@ index 0000000..4b99aa8 + this._boxPointer._arrowSide = side; + this._boxPointer._userArrowSide = side; + ++ this.connect('destroy', this._onDestroy.bind(this)); ++ } ++ ++ _redisplay() { ++ if (this._previewBox) ++ this._previewBox.destroy(); + this._previewBox = new WindowPreviewList(this._source, this._dtdSettings); + this.addMenuItem(this._previewBox); -+ }, -+ -+ _redisplay: function() { -+ this._previewBox._shownInitially = false; + this._previewBox._redisplay(); -+ }, ++ } + -+ popup: function() { ++ popup() { + let windows = this._source.getInterestingWindows(); + if (windows.length > 0) { + this._redisplay(); @@ -13073,35 +12899,29 @@ index 0000000..4b99aa8 + this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); + this._source.emit('sync-tooltip'); + } -+ }, ++ } + -+ destroy: function () { ++ _onDestroy() { + if (this._mappedId) + this._source.actor.disconnect(this._mappedId); + + if (this._destroyId) + this._source.actor.disconnect(this._destroyId); -+ -+ this.parent(); + } ++}; + -+}); -+ -+const WindowPreviewList = new Lang.Class({ -+ Name: 'WindowPreviewMenuSection', -+ Extends: PopupMenu.PopupMenuSection, ++var WindowPreviewList = class DashToDock_WindowPreviewList extends PopupMenu.PopupMenuSection { + -+ _init: function(source, settings) { ++ constructor(source, settings) { ++ super(); + this._dtdSettings = settings; + -+ this.parent(); -+ + this.actor = new St.ScrollView({ name: 'dashtodockWindowScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, + vscrollbar_policy: Gtk.PolicyType.NEVER, + enable_mouse_scrolling: true }); + -+ this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent )); ++ this.actor.connect('scroll-event', this._onScrollEvent.bind(this)); + + let position = Utils.getPosition(this._dtdSettings); + this.isHorizontal = position == St.Side.BOTTOM || position == St.Side.TOP; @@ -13115,19 +12935,18 @@ index 0000000..4b99aa8 + this._source = source; + this.app = source.app; + -+ this._redisplayId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay)); ++ this._redisplayId = Main.initializeDeferredWork(this.actor, this._redisplay.bind(this)); + -+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); ++ this.actor.connect('destroy', this._onDestroy.bind(this)); + this._stateChangedId = this.app.connect('windows-changed', -+ Lang.bind(this, -+ this._queueRedisplay)); -+ }, ++ this._queueRedisplay.bind(this)); ++ } + -+ _queueRedisplay: function () { ++ _queueRedisplay () { + Main.queueDeferredWork(this._redisplayId); -+ }, ++ } + -+ _onScrollEvent: function(actor, event) { ++ _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; @@ -13171,28 +12990,19 @@ index 0000000..4b99aa8 + adjustment.set_value(adjustment.get_value() + delta); + + return Clutter.EVENT_STOP; -+ }, ++ } + -+ _onDestroy: function() { ++ _onDestroy() { + this.app.disconnect(this._stateChangedId); + this._stateChangedId = 0; -+ }, ++ } + -+ _createPreviewItem: function(window) { ++ _createPreviewItem(window) { + let preview = new WindowPreviewMenuItem(window); + return preview; -+ }, -+ -+ _redisplay: function () { -+ // Remove separator -+ let nonWinItem = this._getMenuItems().filter(function(actor) { -+ return !actor._window; -+ }); -+ for (let i = 0; i < nonWinItem.length; i++) { -+ let item = nonWinItem[i]; -+ item.destroy(); -+ } ++ } + ++ _redisplay () { + let children = this._getMenuItems().filter(function(actor) { + return actor._window; + }); @@ -13202,8 +13012,10 @@ index 0000000..4b99aa8 + return actor._window; + }); + -+ // All app windows -+ let newWin = this._source.getInterestingWindows().sort(this.sortWindowsCompareFunction); ++ // 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 = []; @@ -13267,26 +13079,6 @@ index 0000000..4b99aa8 + item.actor.destroy(); + } + -+ // Separate windows from other workspaces -+ let ws_index = global.screen.get_active_workspace_index(); -+ let separator_index = 0; -+ for (let i = 0; i < newWin.length; i++) -+ if (newWin[i].get_workspace().index() == ws_index) -+ separator_index++; -+ -+ if (separator_index > 0 && separator_index !== newWin.length) { -+ let separatorItem = new PopupMenu.PopupSeparatorMenuItem(); -+ if (this.isHorizontal) { -+ separatorItem._separator.set_x_expand(false); -+ separatorItem._separator.set_y_expand(true); -+ separatorItem._separator.set_name('dashtodockPreviewSeparator'); -+ separatorItem._separator.add_style_class_name('popup-separator-menu-item-horizontal'); -+ separatorItem._separator.set_x_align(Clutter.ActorAlign.CENTER); -+ separatorItem._separator.set_y_align(Clutter.ActorAlign.FILL); -+ } -+ this.addMenuItem(separatorItem, separator_index); -+ } -+ + // Skip animations on first run when adding the initial set + // of items, to avoid all items zooming in at once + let animate = this._shownInitially; @@ -13321,9 +13113,9 @@ index 0000000..4b99aa8 + this.actor.add_style_pseudo_class('scrolled'); + else + this.actor.remove_style_pseudo_class('scrolled'); -+ }, ++ } + -+ _needsScrollbar: function() { ++ _needsScrollbar() { + let topMenu = this._getTopMenu(); + let topThemeNode = topMenu.actor.get_theme_node(); + if (this.isHorizontal) { @@ -13336,36 +13128,23 @@ index 0000000..4b99aa8 + return topMaxHeight >= 0 && topNaturalHeight >= topMaxHeight; + } + -+ }, ++ } + -+ isAnimatingOut: function() { ++ isAnimatingOut() { + return this.actor.get_children().reduce(function(result, actor) { + return result || actor.animatingOut; + }, false); -+ }, -+ -+ sortWindowsCompareFunction: function(windowA, windowB) { -+ let ws_index = global.screen.get_active_workspace_index(); -+ let winA_inActiveWS = windowA.get_workspace().index() == ws_index; -+ let winB_inActiveWS = windowB.get_workspace().index() == ws_index; -+ -+ // Only change the order if winA is not in the current WS, while winB is -+ if (!winA_inActiveWS && winB_inActiveWS) -+ return 1; -+ -+ return 0; + } -+}); ++}; + -+const WindowPreviewMenuItem = new Lang.Class({ -+ Name: 'WindowPreviewMenuItem', -+ Extends: PopupMenu.PopupBaseMenuItem, ++var WindowPreviewMenuItem = class DashToDock_WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem { ++ ++ constructor(window, params) { ++ super(params); + -+ _init: function(window, params) { + this._window = window; + this._destroyId = 0; + this._windowAddedId = 0; -+ this.parent(params); + + // We don't want this: it adds spacing on the left of the item. + this.actor.remove_child(this._ornamentLabel); @@ -13381,12 +13160,13 @@ index 0000000..4b99aa8 + 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', Lang.bind(this, this._closeWindow)); ++ this.closeButton.connect('clicked', this._closeWindow.bind(this)); + + let overlayGroup = new Clutter.Actor({layout_manager: new Clutter.BinLayout() }); + @@ -13398,9 +13178,9 @@ index 0000000..4b99aa8 + let labelBin = new St.Bin({ child: label, + x_align: St.Align.MIDDLE}); + -+ this._windowTitleId = this._window.connect('notify::title', Lang.bind(this, function() { ++ this._windowTitleId = this._window.connect('notify::title', () => { + label.set_text(this._window.get_title()); -+ })); ++ }); + + let box = new St.BoxLayout({ vertical: true, + reactive:true, @@ -13410,19 +13190,19 @@ index 0000000..4b99aa8 + this.actor.add_actor(box); + + this.actor.connect('enter-event', -+ Lang.bind(this, this._onEnter)); ++ this._onEnter.bind(this)); + this.actor.connect('leave-event', -+ Lang.bind(this, this._onLeave)); ++ this._onLeave.bind(this)); + this.actor.connect('key-focus-in', -+ Lang.bind(this, this._onEnter)); ++ this._onEnter.bind(this)); + this.actor.connect('key-focus-out', -+ Lang.bind(this, this._onLeave)); ++ this._onLeave.bind(this)); + + this._cloneTexture(window); + -+ }, ++ } + -+ _cloneTexture: function(metaWin){ ++ _cloneTexture(metaWin){ + + let mutterWindow = metaWin.get_compositor_private(); + @@ -13430,14 +13210,13 @@ index 0000000..4b99aa8 + // 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_texture().get_size()[0]) { -+ let id = Mainloop.idle_add(Lang.bind(this, -+ function () { -+ // Check if there's still a point in getting the texture, -+ // otherwise this could go on indefinitely -+ if (this.actor && metaWin.get_workspace()) -+ this._cloneTexture(metaWin); -+ return GLib.SOURCE_REMOVE; -+ })); ++ let id = Mainloop.idle_add(() => { ++ // Check if there's still a point in getting the texture, ++ // otherwise this could go on indefinitely ++ if (this.actor && metaWin.get_workspace()) ++ this._cloneTexture(metaWin); ++ return GLib.SOURCE_REMOVE; ++ }); + GLib.Source.set_name_by_id(id, '[dash-to-dock] this._cloneTexture'); + return; + } @@ -13454,24 +13233,24 @@ index 0000000..4b99aa8 + + // 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', Lang.bind(this, function() { ++ 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); -+ }, ++ } + -+ _windowCanClose: function() { ++ _windowCanClose() { + return this._window.can_close() && + !this._hasAttachedDialogs(); -+ }, ++ } + -+ _closeWindow: function(actor) { ++ _closeWindow(actor) { + this._workspace = this._window.get_workspace(); + + // This mechanism is copied from the workspace.js upstream code @@ -13479,13 +13258,12 @@ index 0000000..4b99aa8 + // for instance because asking user confirmation, by monitoring the opening of + // such additional confirmation window + this._windowAddedId = this._workspace.connect('window-added', -+ Lang.bind(this, -+ this._onWindowAdded)); ++ this._onWindowAdded.bind(this)); + + this.deleteAllWindows(); -+ }, ++ } + -+ deleteAllWindows: function() { ++ 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(); @@ -13497,9 +13275,9 @@ index 0000000..4b99aa8 + } + + this._window.delete(global.get_current_time()); -+ }, ++ } + -+ _onWindowAdded: function(workspace, win) { ++ _onWindowAdded(workspace, win) { + let metaWindow = this._window; + + if (win.get_transient_for() == metaWindow) { @@ -13508,36 +13286,35 @@ index 0000000..4b99aa8 + + // use an idle handler to avoid mapping problems - + // see comment in Workspace._windowAdded -+ let id = Mainloop.idle_add(Lang.bind(this, -+ function() { -+ this.emit('activate'); -+ return GLib.SOURCE_REMOVE; -+ })); ++ let id = Mainloop.idle_add(() => { ++ this.emit('activate'); ++ return GLib.SOURCE_REMOVE; ++ }); + GLib.Source.set_name_by_id(id, '[dash-to-dock] this.emit'); + } -+ }, ++ } + -+ _hasAttachedDialogs: function() { ++ _hasAttachedDialogs() { + // count trasient windows + let n=0; + this._window.foreach_transient(function(){n++;}); + return n>0; -+ }, ++ } + -+ _onEnter: function() { ++ _onEnter() { + this._showCloseButton(); + return Clutter.EVENT_PROPAGATE; -+ }, ++ } + -+ _onLeave: function() { ++ _onLeave() { + if (!this._cloneBin.has_pointer && + !this.closeButton.has_pointer) + this._hideCloseButton(); + + return Clutter.EVENT_PROPAGATE; -+ }, ++ } + -+ _idleToggleCloseButton: function() { ++ _idleToggleCloseButton() { + this._idleToggleCloseId = 0; + + if (!this._cloneBin.has_pointer && @@ -13545,9 +13322,9 @@ index 0000000..4b99aa8 + this._hideCloseButton(); + + return GLib.SOURCE_REMOVE; -+ }, ++ } + -+ _showCloseButton: function() { ++ _showCloseButton() { + + if (this._windowCanClose()) { + this.closeButton.show(); @@ -13556,16 +13333,16 @@ index 0000000..4b99aa8 + time: Workspace.CLOSE_BUTTON_FADE_TIME, + transition: 'easeOutQuad' }); + } -+ }, ++ } + -+ _hideCloseButton: function() { ++ _hideCloseButton() { + Tweener.addTween(this.closeButton, + { opacity: 0, + time: Workspace.CLOSE_BUTTON_FADE_TIME, + transition: 'easeInQuad' }); -+ }, ++ } + -+ show: function(animate) { ++ show(animate) { + let fullWidth = this.actor.get_width(); + + this.actor.opacity = 0; @@ -13578,9 +13355,9 @@ index 0000000..4b99aa8 + time: time, + transition: 'easeInOutQuad' + }); -+ }, ++ } + -+ _animateOutAndDestroy: function() { ++ _animateOutAndDestroy() { + Tweener.addTween(this.actor, + { opacity: 0, + time: 0.25, @@ -13592,20 +13369,19 @@ index 0000000..4b99aa8 + time: 0.25, + delay: 0.25, + onCompleteScope: this, -+ onComplete: function() { ++ onComplete() { + this.actor.destroy(); + } + }); -+ }, ++ } + -+ activate: function() { ++ activate() { + this._getTopMenu().close(); + Main.activateWindow(this._window); -+ }, -+ -+ _onDestroy: function() { ++ } + -+ this.parent(); ++ _onDestroy() { ++ super._onDestroy(); + + if (this._windowAddedId > 0) { + this._workspace.disconnect(this._windowAddedId); @@ -13622,28 +13398,28 @@ index 0000000..4b99aa8 + this._windowTitleId = 0; + } + } ++}; + -+}); diff --git a/meson.build b/meson.build -index c16bde1..f9b56cf 100644 +index 6050c32..2909135 100644 --- a/meson.build +++ b/meson.build -@@ -52,6 +52,7 @@ default_extensions += [ +@@ -49,6 +49,7 @@ default_extensions += [ all_extensions = default_extensions all_extensions += [ 'auto-move-windows', + 'dash-to-dock', - 'example', 'native-window-placement', 'top-icons', + 'user-theme' -- -2.20.1 +2.21.0 -From b60180a015533e1f56cde52b853c9384f5532f53 Mon Sep 17 00:00:00 2001 +From 0baadb623f45f5dfa9449e3bd0aa1ee3880852c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 20 May 2015 18:55:47 +0200 -Subject: [PATCH 3/6] Add panel-favorites extension +Subject: [PATCH 3/8] Add panel-favorites extension --- extensions/panel-favorites/extension.js | 267 ++++++++++++++++++++ @@ -13978,35 +13754,35 @@ index 0000000..120adac + -y-offset: 6px; +} diff --git a/meson.build b/meson.build -index f9b56cf..3451585 100644 +index 2909135..e8e00dc 100644 --- a/meson.build +++ b/meson.build -@@ -55,6 +55,7 @@ all_extensions += [ +@@ -51,6 +51,7 @@ all_extensions += [ + 'auto-move-windows', 'dash-to-dock', - 'example', 'native-window-placement', + 'panel-favorites', 'top-icons', 'user-theme' ] -- -2.20.1 +2.21.0 -From 8f79f11a30d3e1bcbb441b50ac1ef0ea3ed2dc47 Mon Sep 17 00:00:00 2001 +From ce4282836905117970b842a5504a92d8b6ea7dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 4 Mar 2016 17:07:21 +0100 -Subject: [PATCH 4/6] Add updates-dialog extension +Subject: [PATCH 4/8] Add updates-dialog extension --- - extensions/updates-dialog/extension.js | 490 ++++++++++++++++++ + extensions/updates-dialog/extension.js | 503 ++++++++++++++++++ extensions/updates-dialog/meson.build | 7 + extensions/updates-dialog/metadata.json.in | 10 + ...hell.extensions.updates-dialog.gschema.xml | 30 ++ extensions/updates-dialog/stylesheet.css | 1 + meson.build | 1 + po/POTFILES.in | 2 + - 7 files changed, 541 insertions(+) + 7 files changed, 554 insertions(+) create mode 100644 extensions/updates-dialog/extension.js create mode 100644 extensions/updates-dialog/meson.build create mode 100644 extensions/updates-dialog/metadata.json.in @@ -14015,10 +13791,10 @@ Subject: [PATCH 4/6] Add updates-dialog extension diff --git a/extensions/updates-dialog/extension.js b/extensions/updates-dialog/extension.js new file mode 100644 -index 0000000..2fa62a5 +index 0000000..59f6dcf --- /dev/null +++ b/extensions/updates-dialog/extension.js -@@ -0,0 +1,490 @@ +@@ -0,0 +1,503 @@ +/* + * Copyright (c) 2015 Red Hat, Inc. + * @@ -14036,23 +13812,16 @@ index 0000000..2fa62a5 + * along with this program; if not, see . + */ + -+const Clutter = imports.gi.Clutter; -+const Gio = imports.gi.Gio; -+const GLib = imports.gi.GLib; -+const Lang = imports.lang; -+const Pango = imports.gi.Pango; -+const PkgKit = imports.gi.PackageKitGlib; -+const Polkit = imports.gi.Polkit; ++/* exported enable disable */ ++ ++const { Clutter, Gio, GLib, PackageKitGlib: PkgKit, Pango, Polkit, St } = imports.gi; +const Signals = imports.signals; -+const St = imports.gi.St; + +const EndSessionDialog = imports.ui.endSessionDialog; -+const Main = imports.ui.main; +const ModalDialog = imports.ui.modalDialog; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); -+const Convenience = Me.imports.convenience; + +const PkIface = ' \ + \ @@ -14126,100 +13895,119 @@ index 0000000..2fa62a5 +let securityUpdates = []; + +function getDetailText(period) { -+ let text = _("Important security updates need to be installed.\n"); -+ if (period < 60) -+ text += ngettext("You can close this dialog and get %d minute to finish your work.", -+ "You can close this dialog and get %d minutes to finish your work.", -+ period).format(period); -+ else -+ text += ngettext("You can close this dialog and get %d hour to finish your work.", -+ "You can close this dialog and get %d hours to finish your work.", -+ Math.floor(period / 60)).format(Math.floor(period / 60)); ++ let text = _('Important security updates need to be installed.\n'); ++ if (period < 60) { ++ text += ngettext( ++ 'You can close this dialog and get %d minute to finish your work.', ++ 'You can close this dialog and get %d minutes to finish your work.', ++ period) ++ .format(period); ++ } else { ++ text += ngettext( ++ 'You can close this dialog and get %d hour to finish your work.', ++ 'You can close this dialog and get %d hours to finish your work.', ++ Math.floor(period / 60)) ++ .format(Math.floor(period / 60)); ++ } + return text; +} + -+const UpdatesDialog = new Lang.Class({ -+ Name: 'UpdatesDialog', -+ Extends: ModalDialog.ModalDialog, -+ -+ _init: function(settings) { -+ this.parent({ styleClass: 'end-session-dialog', -+ destroyOnClose: false }); ++const UpdatesDialog = class extends ModalDialog.ModalDialog { ++ constructor(settings) { ++ super({ ++ styleClass: 'end-session-dialog', ++ destroyOnClose: false ++ }); + + this._gracePeriod = settings.get_uint('grace-period'); -+ this._gracePeriod = Math.min(Math.max(10, this._gracePeriod), 24*60); ++ this._gracePeriod = Math.min(Math.max(10, this._gracePeriod), 24 * 60); + this._lastWarningPeriod = settings.get_uint('last-warning-period'); -+ this._lastWarningPeriod = Math.min(Math.max(1, this._lastWarningPeriod), this._gracePeriod - 1); ++ this._lastWarningPeriod = Math.min( ++ Math.max(1, this._lastWarningPeriod), ++ this._gracePeriod - 1); + this._lastWarnings = settings.get_uint('last-warnings'); -+ this._lastWarnings = Math.min(Math.max(1, this._lastWarnings), -+ Math.floor((this._gracePeriod - 1) / this._lastWarningPeriod)); -+ -+ let messageLayout = new St.BoxLayout({ vertical: true, -+ style_class: 'end-session-dialog-layout' }); -+ this.contentLayout.add(messageLayout, -+ { x_fill: true, -+ y_fill: true, -+ y_expand: true }); -+ -+ let subjectLabel = new St.Label({ style_class: 'end-session-dialog-subject', -+ style: 'padding-bottom: 1em;', -+ text: _("Important security updates") }); -+ messageLayout.add(subjectLabel, -+ { x_fill: false, -+ y_fill: false, -+ x_align: St.Align.START, -+ y_align: St.Align.START }); -+ -+ this._detailLabel = new St.Label({ style_class: 'end-session-dialog-description', -+ style: 'padding-bottom: 0em;', -+ text: getDetailText(this._gracePeriod) }); ++ this._lastWarnings = Math.min( ++ Math.max(1, this._lastWarnings), ++ Math.floor((this._gracePeriod - 1) / this._lastWarningPeriod)); ++ ++ let messageLayout = new St.BoxLayout({ ++ vertical: true, ++ style_class: 'end-session-dialog-layout' ++ }); ++ this.contentLayout.add(messageLayout, { ++ x_fill: true, ++ y_fill: true, ++ y_expand: true ++ }); ++ ++ let subjectLabel = new St.Label({ ++ style_class: 'end-session-dialog-subject', ++ style: 'padding-bottom: 1em;', ++ text: _('Important security updates') ++ }); ++ messageLayout.add(subjectLabel, { ++ x_fill: false, ++ y_fill: false, ++ x_align: St.Align.START, ++ y_align: St.Align.START ++ }); ++ ++ this._detailLabel = new St.Label({ ++ style_class: 'end-session-dialog-description', ++ style: 'padding-bottom: 0em;', ++ text: getDetailText(this._gracePeriod) ++ }); + this._detailLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; + this._detailLabel.clutter_text.line_wrap = true; + -+ messageLayout.add(this._detailLabel, -+ { y_fill: true, -+ y_align: St.Align.START }); ++ messageLayout.add(this._detailLabel, { ++ y_fill: true, ++ y_align: St.Align.START ++ }); + -+ let buttons = [{ action: Lang.bind(this, this.close), -+ label: _("Close"), -+ key: Clutter.Escape }, -+ { action: Lang.bind(this, this._done), -+ label: _("Restart & Install") }]; ++ let buttons = [{ ++ action: this.close.bind(this), ++ label: _('Close'), ++ key: Clutter.Escape ++ }, { ++ action: this._done.bind(this), ++ label: _('Restart & Install') ++ }]; + + this.setButtons(buttons); + + this._openTimeoutId = 0; -+ this.connect('destroy', Lang.bind(this, this._clearOpenTimeout)); ++ this.connect('destroy', this._clearOpenTimeout.bind(this)); + + this._startTimer(); -+ }, ++ } + -+ _clearOpenTimeout: function() { ++ _clearOpenTimeout() { + if (this._openTimeoutId > 0) { + GLib.source_remove(this._openTimeoutId); + this._openTimeoutId = 0; + } -+ }, ++ } + -+ tryOpen: function() { ++ tryOpen() { + if (this._openTimeoutId > 0 || this.open()) + return; + -+ this._openTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1, -+ Lang.bind(this, function() { -+ if (!this.open()) -+ return GLib.SOURCE_CONTINUE; ++ this._openTimeoutId = GLib.timeout_add_seconds( ++ GLib.PRIORITY_DEFAULT, 1, () => { ++ if (!this.open()) ++ return GLib.SOURCE_CONTINUE; + -+ this._clearOpenTimeout(); -+ return GLib.SOURCE_REMOVE; -+ })); -+ }, ++ this._clearOpenTimeout(); ++ return GLib.SOURCE_REMOVE; ++ }); ++ } + -+ _startTimer: function() { -+ this._secondsLeft = this._gracePeriod*60; ++ _startTimer() { ++ this._secondsLeft = this._gracePeriod * 60; + -+ this._timerId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1, Lang.bind(this, -+ function() { ++ this._timerId = GLib.timeout_add_seconds( ++ GLib.PRIORITY_DEFAULT, 1, () => { + this._secondsLeft -= 1; + let minutesLeft = this._secondsLeft / 60; + let periodLeft = Math.floor(minutesLeft); @@ -14233,40 +14021,42 @@ index 0000000..2fa62a5 + + if (this._secondsLeft > 0) { + if (this._secondsLeft < 60) { -+ let seconds = EndSessionDialog._roundSecondsToInterval(this._gracePeriod*60, this._secondsLeft, 10); ++ let seconds = EndSessionDialog._roundSecondsToInterval( ++ this._gracePeriod * 60, this._secondsLeft, 10); + this._detailLabel.text = -+ _("Important security updates need to be installed now.\n") + -+ ngettext("This computer will restart in %d second.", -+ "This computer will restart in %d seconds.", -+ seconds).format(seconds); ++ _('Important security updates need to be installed now.\n') + ++ ngettext( ++ 'This computer will restart in %d second.', ++ 'This computer will restart in %d seconds.', ++ seconds).format(seconds); + } + return GLib.SOURCE_CONTINUE; + } + + this._done(); + return GLib.SOURCE_REMOVE; -+ })); -+ this.connect('destroy', Lang.bind(this, function() { ++ }); ++ this.connect('destroy', () => { + if (this._timerId > 0) { + GLib.source_remove(this._timerId); + this._timerId = 0; + } -+ })); -+ }, ++ }); ++ } + -+ _done: function() { ++ _done() { + this.emit('done'); + this.destroy(); -+ }, ++ } + -+ getState: function() { ++ getState() { + return [this._gracePeriod, this._lastWarningPeriod, this._lastWarnings, this._secondsLeft]; -+ }, ++ } + -+ setState: function(state) { ++ setState(state) { + [this._gracePeriod, this._lastWarningPeriod, this._lastWarnings, this._secondsLeft] = state; -+ }, -+}); ++ } ++}; +Signals.addSignalMethods(UpdatesDialog.prototype); + +function showDialog() { @@ -14275,13 +14065,13 @@ index 0000000..2fa62a5 + + updatesDialog = new UpdatesDialog(extensionSettings); + updatesDialog.tryOpen(); -+ updatesDialog.connect('destroy', function() { updatesDialog = null; }); -+ updatesDialog.connect('done', function() { ++ updatesDialog.connect('destroy', () => updatesDialog = null); ++ updatesDialog.connect('done', () => { + if (pkOfflineProxy.TriggerAction == 'power-off' || + pkOfflineProxy.TriggerAction == 'reboot') { + loginManagerProxy.RebootRemote(false); + } else { -+ pkOfflineProxy.TriggerRemote('reboot', function(result, error) { ++ pkOfflineProxy.TriggerRemote('reboot', (result, error) => { + if (!error) + loginManagerProxy.RebootRemote(false); + else @@ -14332,7 +14122,7 @@ index 0000000..2fa62a5 + if (!pkProxy) + return; + -+ pkProxy.CreateTransactionRemote(function(result, error) { ++ pkProxy.CreateTransactionRemote((result, error) => { + if (error) { + log('Error creating PackageKit transaction: %s'.format(error.message)); + checkUpdatesDone(); @@ -14340,30 +14130,30 @@ index 0000000..2fa62a5 + } + + new PkTransactionProxy(Gio.DBus.system, -+ 'org.freedesktop.PackageKit', -+ String(result), -+ function(proxy, error) { -+ if (!error) { -+ proxy.SetHintsRemote( -+ ['background=true', 'interactive=false'], -+ function(result, error) { -+ if (error) { -+ log('Error connecting to PackageKit: %s'.format(error.message)); -+ checkUpdatesDone(); -+ return; -+ } -+ callback(proxy); -+ }); -+ } else { -+ log('Error connecting to PackageKit: %s'.format(error.message)); -+ } -+ }); ++ 'org.freedesktop.PackageKit', ++ String(result), ++ (proxy, error) => { ++ if (!error) { ++ proxy.SetHintsRemote( ++ ['background=true', 'interactive=false'], ++ (result, error) => { ++ if (error) { ++ log('Error connecting to PackageKit: %s'.format(error.message)); ++ checkUpdatesDone(); ++ return; ++ } ++ callback(proxy); ++ }); ++ } else { ++ log('Error connecting to PackageKit: %s'.format(error.message)); ++ } ++ }); + }); +} + +function pkUpdatePackages(proxy) { -+ proxy.connectSignal('Finished', function(p, e, params) { -+ let [exit, runtime] = params; ++ proxy.connectSignal('Finished', (p, e, params) => { ++ let [exit, runtime_] = params; + + if (exit == PkgKit.ExitEnum.CANCELLED_PRIORITY) { + // try again @@ -14378,14 +14168,14 @@ index 0000000..2fa62a5 +} + +function pkGetUpdates(proxy) { -+ proxy.connectSignal('Package', function(p, e, params) { -+ let [info, packageId, summary] = params; ++ proxy.connectSignal('Package', (p, e, params) => { ++ let [info, packageId, summary_] = params; + + if (info == PkgKit.InfoEnum.SECURITY) + securityUpdates.push(packageId); + }); -+ proxy.connectSignal('Finished', function(p, e, params) { -+ let [exit, runtime] = params; ++ proxy.connectSignal('Finished', (p, e, params) => { ++ let [exit, runtime_] = params; + + if (exit == PkgKit.ExitEnum.SUCCESS) { + if (securityUpdates.length > 0) { @@ -14426,71 +14216,70 @@ index 0000000..2fa62a5 + +function initSystemProxies() { + new PkProxy(Gio.DBus.system, -+ 'org.freedesktop.PackageKit', -+ '/org/freedesktop/PackageKit', -+ function(proxy, error) { -+ if (!error) { -+ pkProxy = proxy; -+ let id = pkProxy.connectSignal('UpdatesChanged', checkUpdates); -+ pkProxy._signalId = id; -+ checkUpdates(); -+ } else { -+ log('Error connecting to PackageKit: %s'.format(error.message)); -+ } -+ }, -+ cancellable); ++ 'org.freedesktop.PackageKit', ++ '/org/freedesktop/PackageKit', ++ (proxy, error) => { ++ if (!error) { ++ pkProxy = proxy; ++ let id = pkProxy.connectSignal('UpdatesChanged', checkUpdates); ++ pkProxy._signalId = id; ++ checkUpdates(); ++ } else { ++ log('Error connecting to PackageKit: %s'.format(error.message)); ++ } ++ }, ++ cancellable); + new PkOfflineProxy(Gio.DBus.system, -+ 'org.freedesktop.PackageKit', -+ '/org/freedesktop/PackageKit', -+ function(proxy, error) { -+ if (!error) { -+ pkOfflineProxy = proxy; -+ let id = pkOfflineProxy.connect('g-properties-changed', syncState); -+ pkOfflineProxy._signalId = id; -+ syncState(); -+ } else { -+ log('Error connecting to PackageKit: %s'.format(error.message)); -+ } -+ }, -+ cancellable); ++ 'org.freedesktop.PackageKit', ++ '/org/freedesktop/PackageKit', ++ (proxy, error) => { ++ if (!error) { ++ pkOfflineProxy = proxy; ++ let id = pkOfflineProxy.connect('g-properties-changed', syncState); ++ pkOfflineProxy._signalId = id; ++ syncState(); ++ } else { ++ log('Error connecting to PackageKit: %s'.format(error.message)); ++ } ++ }, ++ cancellable); + new LoginManagerProxy(Gio.DBus.system, -+ 'org.freedesktop.login1', -+ '/org/freedesktop/login1', -+ function(proxy, error) { -+ if (!error) { -+ proxy.CanRebootRemote(cancellable, function(result, error) { -+ if (!error && result == 'yes') { -+ loginManagerProxy = proxy; -+ syncState(); -+ } else { -+ log('Reboot is not available'); -+ } -+ }); -+ } else { -+ log('Error connecting to Login manager: %s'.format(error.message)); -+ } -+ }, -+ cancellable); -+} -+ -+function init(metadata) { ++ 'org.freedesktop.login1', ++ '/org/freedesktop/login1', ++ (proxy, error) => { ++ if (!error) { ++ proxy.CanRebootRemote(cancellable, (result, error) => { ++ if (!error && result == 'yes') { ++ loginManagerProxy = proxy; ++ syncState(); ++ } else { ++ log('Reboot is not available'); ++ } ++ }); ++ } else { ++ log('Error connecting to Login manager: %s'.format(error.message)); ++ } ++ }, ++ cancellable); +} + +function enable() { + cancellable = new Gio.Cancellable(); -+ extensionSettings = Convenience.getSettings(); -+ Polkit.Permission.new("org.freedesktop.packagekit.trigger-offline-update", -+ null, cancellable, function(p, result) { -+ try { -+ let permission = Polkit.Permission.new_finish(result); -+ if (permission && permission.allowed) -+ initSystemProxies(); -+ else -+ throw(new Error('not allowed')); -+ } catch(e) { -+ log('No permission to trigger offline updates: %s'.format(e.toString())); -+ } -+ }); ++ extensionSettings = ExtensionUtils.getSettings(); ++ Polkit.Permission.new('org.freedesktop.packagekit.trigger-offline-update', ++ null, ++ cancellable, ++ (p, result) => { ++ try { ++ let permission = Polkit.Permission.new_finish(result); ++ if (permission && permission.allowed) ++ initSystemProxies(); ++ else ++ throw (new Error('not allowed')); ++ } catch (e) { ++ log('No permission to trigger offline updates: %s'.format(e.toString())); ++ } ++ }); +} + +function disable() { @@ -14582,10 +14371,10 @@ index 0000000..25134b6 @@ -0,0 +1 @@ +/* This extensions requires no special styling */ diff --git a/meson.build b/meson.build -index 3451585..08a243e 100644 +index e8e00dc..d129e6c 100644 --- a/meson.build +++ b/meson.build -@@ -57,6 +57,7 @@ all_extensions += [ +@@ -53,6 +53,7 @@ all_extensions += [ 'native-window-placement', 'panel-favorites', 'top-icons', @@ -14594,10 +14383,10 @@ index 3451585..08a243e 100644 ] diff --git a/po/POTFILES.in b/po/POTFILES.in -index d98ca1b..43a817f 100644 +index 9c1438a..55f0e9a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in -@@ -15,6 +15,8 @@ extensions/native-window-placement/org.gnome.shell.extensions.native-window-plac +@@ -10,6 +10,8 @@ extensions/native-window-placement/org.gnome.shell.extensions.native-window-plac extensions/places-menu/extension.js extensions/places-menu/placeDisplay.js extensions/screenshot-window-sizer/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml @@ -14607,13 +14396,13 @@ index d98ca1b..43a817f 100644 extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml extensions/window-list/extension.js -- -2.20.1 +2.21.0 -From 3602940b74b9b138d9eb51b4ad2fe6cdacacbfd0 Mon Sep 17 00:00:00 2001 +From 75c1b568c0bc93c1218fdd1d9d1caa4b9c1d723e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 1 Jun 2017 23:57:14 +0200 -Subject: [PATCH 5/6] Add no-hot-corner extension +Subject: [PATCH 5/8] Add no-hot-corner extension --- extensions/no-hot-corner/extension.js | 31 +++++++++++++++++++++++ @@ -14698,69 +14487,581 @@ index 0000000..25134b6 @@ -0,0 +1 @@ +/* This extensions requires no special styling */ diff --git a/meson.build b/meson.build -index 08a243e..201c484 100644 +index d129e6c..6f27f46 100644 --- a/meson.build +++ b/meson.build -@@ -55,6 +55,7 @@ all_extensions += [ +@@ -51,6 +51,7 @@ all_extensions += [ + 'auto-move-windows', 'dash-to-dock', - 'example', 'native-window-placement', + 'no-hot-corner', 'panel-favorites', 'top-icons', 'updates-dialog', -- -2.20.1 +2.21.0 + + +From c165b79227f0702ecd5cb9f6b25ba5cede47a334 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 26 Mar 2019 19:44:43 +0100 +Subject: [PATCH 6/8] Add window-grouper extension + +--- + extensions/window-grouper/extension.js | 109 ++++++++++ + extensions/window-grouper/meson.build | 8 + + extensions/window-grouper/metadata.json.in | 11 + + ...hell.extensions.window-grouper.gschema.xml | 9 + + extensions/window-grouper/prefs.js | 191 ++++++++++++++++++ + extensions/window-grouper/stylesheet.css | 1 + + meson.build | 3 +- + 7 files changed, 331 insertions(+), 1 deletion(-) + create mode 100644 extensions/window-grouper/extension.js + create mode 100644 extensions/window-grouper/meson.build + create mode 100644 extensions/window-grouper/metadata.json.in + create mode 100644 extensions/window-grouper/org.gnome.shell.extensions.window-grouper.gschema.xml + create mode 100644 extensions/window-grouper/prefs.js + create mode 100644 extensions/window-grouper/stylesheet.css + +diff --git a/extensions/window-grouper/extension.js b/extensions/window-grouper/extension.js +new file mode 100644 +index 0000000..f66a764 +--- /dev/null ++++ b/extensions/window-grouper/extension.js +@@ -0,0 +1,109 @@ ++// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- ++/* exported init */ ++ ++const { Shell } = imports.gi; ++ ++const ExtensionUtils = imports.misc.extensionUtils; ++ ++class WindowMover { ++ constructor() { ++ this._settings = ExtensionUtils.getSettings(); ++ this._appSystem = Shell.AppSystem.get_default(); ++ this._appConfigs = new Set(); ++ this._appData = new Map(); ++ ++ this._appsChangedId = this._appSystem.connect( ++ 'installed-changed', this._updateAppData.bind(this)); ++ ++ this._settings.connect('changed', this._updateAppConfigs.bind(this)); ++ this._updateAppConfigs(); ++ } ++ ++ _updateAppConfigs() { ++ this._appConfigs.clear(); ++ ++ this._settings.get_strv('application-list').forEach(appId => { ++ this._appConfigs.add(appId); ++ }); ++ ++ this._updateAppData(); ++ } ++ ++ _updateAppData() { ++ let ids = [...this._appConfigs.values()]; ++ let removedApps = [...this._appData.keys()].filter( ++ a => !ids.includes(a.id) ++ ); ++ removedApps.forEach(app => { ++ app.disconnect(this._appData.get(app).windowsChangedId); ++ this._appData.delete(app); ++ }); ++ ++ let addedApps = ids.map(id => this._appSystem.lookup_app(id)).filter( ++ app => app != null && !this._appData.has(app) ++ ); ++ addedApps.forEach(app => { ++ let data = { ++ windows: app.get_windows(), ++ windowsChangedId: app.connect( ++ 'windows-changed', this._appWindowsChanged.bind(this)) ++ }; ++ this._appData.set(app, data); ++ }); ++ } ++ ++ destroy() { ++ if (this._appsChangedId) { ++ this._appSystem.disconnect(this._appsChangedId); ++ this._appsChangedId = 0; ++ } ++ ++ if (this._settings) { ++ this._settings.run_dispose(); ++ this._settings = null; ++ } ++ ++ this._appConfigs.clear(); ++ this._updateAppData(); ++ } ++ ++ _appWindowsChanged(app) { ++ let data = this._appData.get(app); ++ let windows = app.get_windows(); ++ ++ // If get_compositor_private() returns non-NULL on a removed windows, ++ // the window still exists and is just moved to a different workspace ++ // or something; assume it'll be added back immediately, so keep it ++ // to avoid moving it again ++ windows.push(...data.windows.filter( ++ w => !windows.includes(w) && w.get_compositor_private() != null ++ )); ++ ++ windows.filter(w => !data.windows.includes(w)).forEach(window => { ++ let leader = data.windows.find(w => w.get_pid() == window.get_pid()); ++ if (leader) ++ window.change_workspace(leader.get_workspace()); ++ }); ++ data.windows = windows; ++ } ++} ++ ++class Extension { ++ constructor() { ++ this._winMover = null; ++ } ++ ++ enable() { ++ this._winMover = new WindowMover(); ++ } ++ ++ disable() { ++ this._winMover.destroy(); ++ this._winMover = null; ++ } ++} ++ ++function init() { ++ ExtensionUtils.initTranslations(); ++ return new Extension(); ++} +diff --git a/extensions/window-grouper/meson.build b/extensions/window-grouper/meson.build +new file mode 100644 +index 0000000..c55a783 +--- /dev/null ++++ b/extensions/window-grouper/meson.build +@@ -0,0 +1,8 @@ ++extension_data += configure_file( ++ input: metadata_name + '.in', ++ output: metadata_name, ++ configuration: metadata_conf ++) ++ ++extension_sources += files('prefs.js') ++extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml') +diff --git a/extensions/window-grouper/metadata.json.in b/extensions/window-grouper/metadata.json.in +new file mode 100644 +index 0000000..aa202c8 +--- /dev/null ++++ b/extensions/window-grouper/metadata.json.in +@@ -0,0 +1,11 @@ ++{ ++ "extension-id": "@extension_id@", ++ "uuid": "@uuid@", ++ "settings-schema": "@gschemaname@", ++ "gettext-domain": "@gettext_domain@", ++ "name": "Window grouper", ++ "description": "Keep windows that belong to the same process on the same workspace.", ++ "shell-version": [ "@shell_current@" ], ++ "original-authors": [ "fmuellner@redhat.com" ], ++ "url": "@url@" ++} +diff --git a/extensions/window-grouper/org.gnome.shell.extensions.window-grouper.gschema.xml b/extensions/window-grouper/org.gnome.shell.extensions.window-grouper.gschema.xml +new file mode 100644 +index 0000000..ee052a6 +--- /dev/null ++++ b/extensions/window-grouper/org.gnome.shell.extensions.window-grouper.gschema.xml +@@ -0,0 +1,9 @@ ++ ++ ++ ++ [ ] ++ Application that should be grouped ++ A list of application ids ++ ++ ++ +diff --git a/extensions/window-grouper/prefs.js b/extensions/window-grouper/prefs.js +new file mode 100644 +index 0000000..d7b748e +--- /dev/null ++++ b/extensions/window-grouper/prefs.js +@@ -0,0 +1,191 @@ ++// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- ++/* exported init buildPrefsWidget */ ++ ++const { Gio, GObject, Gtk } = imports.gi; ++ ++const ExtensionUtils = imports.misc.extensionUtils; ++const Gettext = imports.gettext.domain('gnome-shell-extensions'); ++const _ = Gettext.gettext; ++const N_ = e => e; ++ ++const SETTINGS_KEY = 'application-list'; ++ ++const Columns = { ++ APPINFO: 0, ++ DISPLAY_NAME: 1, ++ ICON: 2 ++}; ++ ++const Widget = GObject.registerClass({ ++ GTypeName: 'WindowGrouperPrefsWidget', ++}, class Widget extends Gtk.Grid { ++ _init(params) { ++ super._init(params); ++ this.set_orientation(Gtk.Orientation.VERTICAL); ++ ++ this._settings = ExtensionUtils.getSettings(); ++ this._settings.connect('changed', this._refresh.bind(this)); ++ this._changedPermitted = false; ++ ++ this._store = new Gtk.ListStore(); ++ this._store.set_column_types([Gio.AppInfo, GObject.TYPE_STRING, Gio.Icon]); ++ ++ let scrolled = new Gtk.ScrolledWindow({ shadow_type: Gtk.ShadowType.IN }); ++ scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); ++ this.add(scrolled); ++ ++ ++ this._treeView = new Gtk.TreeView({ ++ model: this._store, ++ headers_visible: false, ++ hexpand: true, ++ vexpand: true ++ }); ++ this._treeView.get_selection().set_mode(Gtk.SelectionMode.SINGLE); ++ ++ let appColumn = new Gtk.TreeViewColumn({ ++ sort_column_id: Columns.DISPLAY_NAME, ++ spacing: 12 ++ }); ++ let iconRenderer = new Gtk.CellRendererPixbuf({ ++ stock_size: Gtk.IconSize.DIALOG, ++ xpad: 12, ++ ypad: 12 ++ }); ++ appColumn.pack_start(iconRenderer, false); ++ appColumn.add_attribute(iconRenderer, 'gicon', Columns.ICON); ++ let nameRenderer = new Gtk.CellRendererText(); ++ appColumn.pack_start(nameRenderer, true); ++ appColumn.add_attribute(nameRenderer, 'text', Columns.DISPLAY_NAME); ++ this._treeView.append_column(appColumn); ++ ++ scrolled.add(this._treeView); ++ ++ let toolbar = new Gtk.Toolbar({ icon_size: Gtk.IconSize.SMALL_TOOLBAR }); ++ toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR); ++ this.add(toolbar); ++ ++ let newButton = new Gtk.ToolButton({ ++ icon_name: 'list-add-symbolic' ++ }); ++ newButton.connect('clicked', this._createNew.bind(this)); ++ toolbar.add(newButton); ++ ++ let delButton = new Gtk.ToolButton({ ++ icon_name: 'list-remove-symbolic' ++ }); ++ delButton.connect('clicked', this._deleteSelected.bind(this)); ++ toolbar.add(delButton); ++ ++ let selection = this._treeView.get_selection(); ++ selection.connect('changed', () => { ++ delButton.sensitive = selection.count_selected_rows() > 0; ++ }); ++ delButton.sensitive = selection.count_selected_rows() > 0; ++ ++ this._changedPermitted = true; ++ this._refresh(); ++ } ++ ++ _createNew() { ++ let dialog = new Gtk.AppChooserDialog({ ++ heading: _('Select an application for which grouping should apply'), ++ transient_for: this.get_toplevel(), ++ modal: true ++ }); ++ ++ dialog.get_widget().show_all = true; ++ ++ dialog.connect('response', (dialog, id) => { ++ if (id != Gtk.ResponseType.OK) { ++ dialog.destroy(); ++ return; ++ } ++ ++ let appInfo = dialog.get_app_info(); ++ if (!appInfo) { ++ dialog.destroy(); ++ return; ++ } ++ ++ this._changedPermitted = false; ++ this._appendItem(appInfo.get_id()); ++ this._changedPermitted = true; ++ ++ let iter = this._store.append(); ++ this._store.set(iter, ++ [Columns.APPINFO, Columns.ICON, Columns.DISPLAY_NAME], ++ [appInfo, appInfo.get_icon(), appInfo.get_display_name()]); ++ ++ dialog.destroy(); ++ }); ++ dialog.show_all(); ++ } ++ ++ _deleteSelected() { ++ let [any, model_, iter] = this._treeView.get_selection().get_selected(); ++ ++ if (any) { ++ let appInfo = this._store.get_value(iter, Columns.APPINFO); ++ ++ this._changedPermitted = false; ++ this._removeItem(appInfo.get_id()); ++ this._changedPermitted = true; ++ this._store.remove(iter); ++ } ++ } ++ ++ _refresh() { ++ if (!this._changedPermitted) ++ // Ignore this notification, model is being modified outside ++ return; ++ ++ this._store.clear(); ++ ++ let currentItems = this._settings.get_strv(SETTINGS_KEY); ++ let validItems = []; ++ for (let i = 0; i < currentItems.length; i++) { ++ let id = currentItems[i]; ++ let appInfo = Gio.DesktopAppInfo.new(id); ++ if (!appInfo) ++ continue; ++ validItems.push(currentItems[i]); ++ ++ let iter = this._store.append(); ++ this._store.set(iter, ++ [Columns.APPINFO, Columns.ICON, Columns.DISPLAY_NAME], ++ [appInfo, appInfo.get_icon(), appInfo.get_display_name()]); ++ } ++ ++ if (validItems.length != currentItems.length) // some items were filtered out ++ this._settings.set_strv(SETTINGS_KEY, validItems); ++ } ++ ++ _appendItem(id) { ++ let currentItems = this._settings.get_strv(SETTINGS_KEY); ++ currentItems.push(id); ++ this._settings.set_strv(SETTINGS_KEY, currentItems); ++ } ++ ++ _removeItem(id) { ++ let currentItems = this._settings.get_strv(SETTINGS_KEY); ++ let index = currentItems.indexOf(id); ++ ++ if (index < 0) ++ return; ++ currentItems.splice(index, 1); ++ this._settings.set_strv(SETTINGS_KEY, currentItems); ++ } ++}); ++ ++ ++function init() { ++ ExtensionUtils.initTranslations(); ++} ++ ++function buildPrefsWidget() { ++ let widget = new Widget({ margin: 12 }); ++ widget.show_all(); ++ ++ return widget; ++} +diff --git a/extensions/window-grouper/stylesheet.css b/extensions/window-grouper/stylesheet.css +new file mode 100644 +index 0000000..25134b6 +--- /dev/null ++++ b/extensions/window-grouper/stylesheet.css +@@ -0,0 +1 @@ ++/* This extensions requires no special styling */ +diff --git a/meson.build b/meson.build +index 6f27f46..4b9d138 100644 +--- a/meson.build ++++ b/meson.build +@@ -55,7 +55,8 @@ all_extensions += [ + 'panel-favorites', + 'top-icons', + 'updates-dialog', +- 'user-theme' ++ 'user-theme', ++ 'window-grouper' + ] + + enabled_extensions = get_option('enable_extensions') +-- +2.21.0 + + +From be2ec13b3a876b4c4bcf91ee9e537b89c06e4e3f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 26 Mar 2019 21:32:09 +0100 +Subject: [PATCH 7/8] Add disable-screenshield extension + +--- + extensions/disable-screenshield/extension.js | 27 +++++++++++++++++++ + extensions/disable-screenshield/meson.build | 5 ++++ + .../disable-screenshield/metadata.json.in | 9 +++++++ + .../disable-screenshield/stylesheet.css | 1 + + meson.build | 1 + + 5 files changed, 43 insertions(+) + create mode 100644 extensions/disable-screenshield/extension.js + create mode 100644 extensions/disable-screenshield/meson.build + create mode 100644 extensions/disable-screenshield/metadata.json.in + create mode 100644 extensions/disable-screenshield/stylesheet.css + +diff --git a/extensions/disable-screenshield/extension.js b/extensions/disable-screenshield/extension.js +new file mode 100644 +index 0000000..91204c0 +--- /dev/null ++++ b/extensions/disable-screenshield/extension.js +@@ -0,0 +1,27 @@ ++/* exported enable disable */ ++ ++const ScreenShield = imports.ui.screenShield; ++ ++let _onUserBecameActiveOrig; ++ ++function _onUserBecameActiveInjected() { ++ this.idleMonitor.remove_watch(this._becameActiveId); ++ this._becameActiveId = 0; ++ ++ this._longLightbox.hide(); ++ this._shortLightbox.hide(); ++ ++ this.deactivate(false); ++} ++ ++function enable() { ++ _onUserBecameActiveOrig = ++ ScreenShield.ScreenShield.prototype._onUserBecameActive; ++ ScreenShield.ScreenShield.prototype._onUserBecameActive = ++ _onUserBecameActiveInjected; ++} ++ ++function disable() { ++ ScreenShield.ScreenShield.prototype._onUserBecameActive = ++ _onUserBecameActiveOrig; ++} +diff --git a/extensions/disable-screenshield/meson.build b/extensions/disable-screenshield/meson.build +new file mode 100644 +index 0000000..48504f6 +--- /dev/null ++++ b/extensions/disable-screenshield/meson.build +@@ -0,0 +1,5 @@ ++extension_data += configure_file( ++ input: metadata_name + '.in', ++ output: metadata_name, ++ configuration: metadata_conf ++) +diff --git a/extensions/disable-screenshield/metadata.json.in b/extensions/disable-screenshield/metadata.json.in +new file mode 100644 +index 0000000..074429f +--- /dev/null ++++ b/extensions/disable-screenshield/metadata.json.in +@@ -0,0 +1,9 @@ ++{ ++ "extension-id": "@extension_id@", ++ "uuid": "@uuid@", ++ "name": "Disable Screen Shield", ++ "description": "Disable screen shield when screen lock is disabled", ++ "shell-version": [ "@shell_current@" ], ++ "original-authors": [ "lgpasquale@gmail.com" ], ++ "url": "@url@" ++} +diff --git a/extensions/disable-screenshield/stylesheet.css b/extensions/disable-screenshield/stylesheet.css +new file mode 100644 +index 0000000..25134b6 +--- /dev/null ++++ b/extensions/disable-screenshield/stylesheet.css +@@ -0,0 +1 @@ ++/* This extensions requires no special styling */ +diff --git a/meson.build b/meson.build +index 4b9d138..cf855a0 100644 +--- a/meson.build ++++ b/meson.build +@@ -50,6 +50,7 @@ all_extensions = default_extensions + all_extensions += [ + 'auto-move-windows', + 'dash-to-dock', ++ 'disable-screenshield', + 'native-window-placement', + 'no-hot-corner', + 'panel-favorites', +-- +2.21.0 -From 74d8ce6acd4c1a61de25d796f63e4f1f79180ed4 Mon Sep 17 00:00:00 2001 +From 0b1da0ee4e8669bb3ba5d7fef5cf436c7bbcea88 Mon Sep 17 00:00:00 2001 From: Carlos Soriano Date: Mon, 13 Aug 2018 17:28:41 +0200 -Subject: [PATCH 6/6] Add desktop icons extension +Subject: [PATCH 8/8] Add desktop icons extension --- + .../desktop-icons/createFolderDialog.js | 164 ++++ extensions/desktop-icons/createThumbnail.js | 35 + - extensions/desktop-icons/dbusUtils.js | 74 ++ - extensions/desktop-icons/desktopGrid.js | 664 +++++++++++++++ - extensions/desktop-icons/desktopIconsUtil.js | 60 ++ - extensions/desktop-icons/desktopManager.js | 701 ++++++++++++++++ + extensions/desktop-icons/dbusUtils.js | 103 +++ + extensions/desktop-icons/desktopGrid.js | 692 +++++++++++++++ + extensions/desktop-icons/desktopIconsUtil.js | 123 +++ + extensions/desktop-icons/desktopManager.js | 752 ++++++++++++++++ extensions/desktop-icons/extension.js | 71 ++ - extensions/desktop-icons/fileItem.js | 771 ++++++++++++++++++ - extensions/desktop-icons/meson.build | 18 + + extensions/desktop-icons/fileItem.js | 800 ++++++++++++++++++ + extensions/desktop-icons/meson.build | 19 + extensions/desktop-icons/metadata.json.in | 11 + - extensions/desktop-icons/po/LINGUAS | 12 + + extensions/desktop-icons/po/LINGUAS | 19 + extensions/desktop-icons/po/POTFILES.in | 4 + - extensions/desktop-icons/po/cs.po | 136 +++ - extensions/desktop-icons/po/da.po | 136 +++ - extensions/desktop-icons/po/de.po | 136 +++ - extensions/desktop-icons/po/es.po | 186 +++++ - extensions/desktop-icons/po/fi.po | 136 +++ + extensions/desktop-icons/po/cs.po | 195 +++++ + extensions/desktop-icons/po/da.po | 159 ++++ + extensions/desktop-icons/po/de.po | 192 +++++ + extensions/desktop-icons/po/es.po | 218 +++++ + extensions/desktop-icons/po/fi.po | 191 +++++ extensions/desktop-icons/po/fr.po | 164 ++++ - extensions/desktop-icons/po/id.po | 135 +++ - extensions/desktop-icons/po/it.po | 152 ++++ + extensions/desktop-icons/po/fur.po | 187 ++++ + extensions/desktop-icons/po/hr.po | 186 ++++ + extensions/desktop-icons/po/hu.po | 190 +++++ + extensions/desktop-icons/po/id.po | 190 +++++ + extensions/desktop-icons/po/it.po | 189 +++++ + extensions/desktop-icons/po/ja.po | 187 ++++ extensions/desktop-icons/po/meson.build | 1 + - extensions/desktop-icons/po/pl.po | 157 ++++ - extensions/desktop-icons/po/pt_BR.po | 163 ++++ + extensions/desktop-icons/po/nl.po | 188 ++++ + extensions/desktop-icons/po/pl.po | 193 +++++ + extensions/desktop-icons/po/pt_BR.po | 199 +++++ extensions/desktop-icons/po/ru.po | 153 ++++ + extensions/desktop-icons/po/sv.po | 197 +++++ + extensions/desktop-icons/po/tr.po | 191 +++++ extensions/desktop-icons/po/zh_TW.po | 135 +++ extensions/desktop-icons/prefs.js | 159 ++++ extensions/desktop-icons/schemas/meson.build | 6 + ...shell.extensions.desktop-icons.gschema.xml | 25 + - extensions/desktop-icons/stylesheet.css | 33 + + extensions/desktop-icons/stylesheet.css | 38 + meson.build | 1 + po/cs.po | 161 ++++ po/da.po | 161 ++++ po/de.po | 161 ++++ po/es.po | 222 ++++- po/fi.po | 167 +++- - po/fr.po | 190 +++++ + po/fr.po | 188 ++++ po/id.po | 159 ++++ po/it.po | 177 ++++ - po/pl.po | 183 +++++ + po/pl.po | 183 ++++ po/pt_BR.po | 197 ++++- po/ru.po | 179 ++++ po/zh_TW.po | 165 +++- - 41 files changed, 6527 insertions(+), 30 deletions(-) + 49 files changed, 8617 insertions(+), 30 deletions(-) + create mode 100644 extensions/desktop-icons/createFolderDialog.js create mode 100755 extensions/desktop-icons/createThumbnail.js create mode 100644 extensions/desktop-icons/dbusUtils.js create mode 100644 extensions/desktop-icons/desktopGrid.js @@ -14778,20 +15079,197 @@ Subject: [PATCH 6/6] Add desktop icons extension create mode 100644 extensions/desktop-icons/po/es.po create mode 100644 extensions/desktop-icons/po/fi.po create mode 100644 extensions/desktop-icons/po/fr.po + create mode 100644 extensions/desktop-icons/po/fur.po + create mode 100644 extensions/desktop-icons/po/hr.po + create mode 100644 extensions/desktop-icons/po/hu.po create mode 100644 extensions/desktop-icons/po/id.po create mode 100644 extensions/desktop-icons/po/it.po + create mode 100644 extensions/desktop-icons/po/ja.po create mode 100644 extensions/desktop-icons/po/meson.build + create mode 100644 extensions/desktop-icons/po/nl.po create mode 100644 extensions/desktop-icons/po/pl.po create mode 100644 extensions/desktop-icons/po/pt_BR.po create mode 100644 extensions/desktop-icons/po/ru.po + create mode 100644 extensions/desktop-icons/po/sv.po + create mode 100644 extensions/desktop-icons/po/tr.po create mode 100644 extensions/desktop-icons/po/zh_TW.po create mode 100644 extensions/desktop-icons/prefs.js create mode 100644 extensions/desktop-icons/schemas/meson.build create mode 100644 extensions/desktop-icons/schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml create mode 100644 extensions/desktop-icons/stylesheet.css -diff --git a/extensions/desktop-icons/createThumbnail.js b/extensions/desktop-icons/createThumbnail.js -new file mode 100755 +diff --git a/extensions/desktop-icons/createFolderDialog.js b/extensions/desktop-icons/createFolderDialog.js +new file mode 100644 +index 0000000..f3e40e9 +--- /dev/null ++++ b/extensions/desktop-icons/createFolderDialog.js +@@ -0,0 +1,164 @@ ++/* Desktop Icons GNOME Shell extension ++ * ++ * Copyright (C) 2019 Andrea Azzaronea ++ * ++ * 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 . ++ */ ++ ++const { Clutter, GObject, GLib, Gio, St } = imports.gi; ++ ++const Signals = imports.signals; ++ ++const Dialog = imports.ui.dialog; ++const Gettext = imports.gettext.domain('desktop-icons'); ++const ModalDialog = imports.ui.modalDialog; ++const ShellEntry = imports.ui.shellEntry; ++const Tweener = imports.ui.tweener; ++ ++const ExtensionUtils = imports.misc.extensionUtils; ++const Me = ExtensionUtils.getCurrentExtension(); ++const DesktopIconsUtil = Me.imports.desktopIconsUtil; ++const Extension = Me.imports.extension; ++ ++const _ = Gettext.gettext; ++ ++const DIALOG_GROW_TIME = 0.1; ++ ++var CreateFolderDialog = class extends ModalDialog.ModalDialog { ++ ++ constructor() { ++ super({ styleClass: 'create-folder-dialog' }); ++ ++ this._buildLayout(); ++ } ++ ++ _buildLayout() { ++ let label = new St.Label({ style_class: 'create-folder-dialog-label', ++ text: _('New folder name') }); ++ this.contentLayout.add(label, { x_align: St.Align.START }); ++ ++ this._entry = new St.Entry({ style_class: 'create-folder-dialog-entry', ++ can_focus: true }); ++ this._entry.clutter_text.connect('activate', this._onEntryActivate.bind(this)); ++ this._entry.clutter_text.connect('text-changed', this._onTextChanged.bind(this)); ++ ShellEntry.addContextMenu(this._entry); ++ this.contentLayout.add(this._entry); ++ this.setInitialKeyFocus(this._entry); ++ ++ this._errorBox = new St.BoxLayout({ style_class: 'create-folder-dialog-error-box', ++ visible: false }); ++ this.contentLayout.add(this._errorBox, { expand: true }); ++ ++ this._errorMessage = new St.Label({ style_class: 'create-folder-dialog-error-label' }); ++ this._errorMessage.clutter_text.line_wrap = true; ++ this._errorBox.add(this._errorMessage, { expand: true, ++ x_align: St.Align.START, ++ x_fill: false, ++ y_align: St.Align.MIDDLE, ++ y_fill: false }); ++ ++ this._createButton = this.addButton({ action: this._onCreateButton.bind(this), ++ label: _('Create') }); ++ this.addButton({ action: this.close.bind(this), ++ label: _('Cancel'), ++ key: Clutter.Escape }); ++ this._onTextChanged(); ++ } ++ ++ _showError(message) { ++ this._errorMessage.set_text(message); ++ ++ if (!this._errorBox.visible) { ++ let [errorBoxMinHeight, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1); ++ let parentActor = this._errorBox.get_parent(); ++ ++ Tweener.addTween(parentActor, ++ { height: parentActor.height + errorBoxNaturalHeight, ++ time: DIALOG_GROW_TIME, ++ transition: 'easeOutQuad', ++ onComplete: () => { ++ parentActor.set_height(-1); ++ this._errorBox.show(); ++ } ++ }); ++ } ++ } ++ ++ _hideError() { ++ if (this._errorBox.visible) { ++ let [errorBoxMinHeight, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1); ++ let parentActor = this._errorBox.get_parent(); ++ ++ Tweener.addTween(parentActor, ++ { height: parentActor.height - errorBoxNaturalHeight, ++ time: DIALOG_GROW_TIME, ++ transition: 'easeOutQuad', ++ onComplete: () => { ++ parentActor.set_height(-1); ++ this._errorBox.hide(); ++ this._errorMessage.set_text(''); ++ } ++ }); ++ } ++ } ++ ++ _onCreateButton() { ++ this._onEntryActivate(); ++ } ++ ++ _onEntryActivate() { ++ if (!this._createButton.reactive) ++ return; ++ ++ this.emit('response', this._entry.get_text()); ++ this.close(); ++ } ++ ++ _onTextChanged() { ++ let text = this._entry.get_text(); ++ let is_valid = true; ++ ++ let found_name = false; ++ for(let name of Extension.desktopManager.getDesktopFileNames()) { ++ if (name === text) { ++ found_name = true; ++ break; ++ } ++ } ++ ++ if (text.trim().length == 0) { ++ is_valid = false; ++ this._hideError(); ++ } else if (text.includes('/')) { ++ is_valid = false; ++ this._showError(_('Folder names cannot contain “/”.')); ++ } else if (text === '.') { ++ is_valid = false; ++ this._showError(_('A folder cannot be called “.”.')); ++ } else if (text === '..') { ++ is_valid = false; ++ this._showError(_('A folder cannot be called “..”.')); ++ } else if (text.startsWith('.')) { ++ this._showError(_('Folders with “.” at the beginning of their name are hidden.')); ++ } else if (found_name) { ++ this._showError(_('There is already a file or folder with that name.')); ++ is_valid = false; ++ } else { ++ this._hideError(); ++ } ++ ++ this._createButton.reactive = is_valid; ++ } ++}; ++Signals.addSignalMethods(CreateFolderDialog.prototype); +diff --git a/extensions/desktop-icons/createThumbnail.js b/extensions/desktop-icons/createThumbnail.js +new file mode 100755 index 0000000..212f6b7 --- /dev/null +++ b/extensions/desktop-icons/createThumbnail.js @@ -14833,11 +15311,12 @@ index 0000000..212f6b7 + thumbnailFactory.save_thumbnail(thumbnailPixbuf, fileUri, modifiedTime); diff --git a/extensions/desktop-icons/dbusUtils.js b/extensions/desktop-icons/dbusUtils.js new file mode 100644 -index 0000000..ba9e912 +index 0000000..19fe987 --- /dev/null +++ b/extensions/desktop-icons/dbusUtils.js -@@ -0,0 +1,74 @@ +@@ -0,0 +1,103 @@ +const Gio = imports.gi.Gio; ++const GLib = imports.gi.GLib; +var NautilusFileOperationsProxy; +var FreeDesktopFileManagerProxy; + @@ -14911,12 +15390,40 @@ index 0000000..ba9e912 + } + ); +} ++ ++function openFileWithOtherApplication(filePath) { ++ let fdList = new Gio.UnixFDList(); ++ let channel = GLib.IOChannel.new_file(filePath, "r"); ++ fdList.append(channel.unix_get_fd()); ++ channel.set_close_on_unref(true); ++ let builder = GLib.VariantBuilder.new(GLib.VariantType.new("a{sv}")); ++ let options = builder.end(); ++ let parameters = GLib.Variant.new_tuple([GLib.Variant.new_string("0"), ++ GLib.Variant.new_handle(0), ++ options]); ++ Gio.bus_get(Gio.BusType.SESSION, null, ++ (source, result) => { ++ let dbus_connection = Gio.bus_get_finish(result); ++ dbus_connection.call_with_unix_fd_list("org.freedesktop.portal.Desktop", ++ "/org/freedesktop/portal/desktop", ++ "org.freedesktop.portal.OpenURI", ++ "OpenFile", ++ parameters, ++ GLib.VariantType.new("o"), ++ Gio.DBusCallFlags.NONE, ++ -1, ++ fdList, ++ null, ++ null); ++ } ++ ); ++} diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js new file mode 100644 -index 0000000..83ca2cc +index 0000000..a2d1f12 --- /dev/null +++ b/extensions/desktop-icons/desktopGrid.js -@@ -0,0 +1,664 @@ +@@ -0,0 +1,692 @@ +/* Desktop Icons GNOME Shell extension + * + * Copyright (C) 2017 Carlos Soriano @@ -14937,7 +15444,6 @@ index 0000000..83ca2cc + +const Gtk = imports.gi.Gtk; +const Clutter = imports.gi.Clutter; -+const Lang = imports.lang; +const St = imports.gi.St; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; @@ -14950,9 +15456,11 @@ index 0000000..83ca2cc +const BoxPointer = imports.ui.boxpointer; +const PopupMenu = imports.ui.popupMenu; +const GrabHelper = imports.ui.grabHelper; ++const Config = imports.misc.config; + +const ExtensionUtils = imports.misc.extensionUtils; +const Me = ExtensionUtils.getCurrentExtension(); ++const CreateFolderDialog = Me.imports.createFolderDialog; +const Extension = Me.imports.extension; +const FileItem = Me.imports.fileItem; +const Prefs = Me.imports.prefs; @@ -14977,6 +15485,7 @@ index 0000000..83ca2cc +var StoredCoordinates = { + PRESERVE: 0, + OVERWRITE:1, ++ ASSIGN:2, +}; + +class Placeholder extends St.Bin { @@ -14999,7 +15508,14 @@ index 0000000..83ca2cc + row_homogeneous: true + }); + -+ this.actor = new St.Widget(); ++ this._actorLayout = new Clutter.BinLayout({ ++ x_align: Clutter.BinAlignment.FIXED, ++ y_align: Clutter.BinAlignment.FIXED ++ }); ++ ++ this.actor = new St.Widget({ ++ layout_manager: this._actorLayout ++ }); + this.actor._delegate = this; + + this._grid = new St.Widget({ @@ -15025,7 +15541,7 @@ index 0000000..83ca2cc + index: monitorIndex, + work_area: true + }); -+ this._grid.add_constraint(this._monitorConstraint); ++ this.actor.add_constraint(this._monitorConstraint); + + this._addDesktopBackgroundMenu(); + @@ -15102,17 +15618,27 @@ index 0000000..83ca2cc + this._bgManager = null; + } + -+ _omNewFolderClicked() { -+ let dir = DesktopIconsUtil.getDesktopDir().get_child(_('New Folder')); -+ DBusUtils.NautilusFileOperationsProxy.CreateFolderRemote(dir.get_uri(), -+ (result, error) => { -+ if (error) -+ throw new Error('Error creating new folder: ' + error.message); -+ } -+ ); ++ _onNewFolderClicked() { ++ ++ let dialog = new CreateFolderDialog.CreateFolderDialog(); ++ ++ dialog.connect('response', (dialog, name) => { ++ let dir = DesktopIconsUtil.getDesktopDir().get_child(name); ++ DBusUtils.NautilusFileOperationsProxy.CreateFolderRemote(dir.get_uri(), ++ (result, error) => { ++ if (error) ++ throw new Error('Error creating new folder: ' + error.message); ++ } ++ ); ++ }); ++ ++ dialog.open(); + } + + _parseClipboardText(text) { ++ if (text === null) ++ return [false, false, null]; ++ + let lines = text.split('\n'); + let [mime, action, ...files] = lines; + @@ -15192,9 +15718,9 @@ index 0000000..83ca2cc + _onOpenDesktopInFilesClicked() { + Gio.AppInfo.launch_default_for_uri_async(DesktopIconsUtil.getDesktopDir().get_uri(), + null, null, -+ (source, res) => { ++ (source, result) => { + try { -+ Gio.AppInfo.launch_default_for_uri_finish(res); ++ Gio.AppInfo.launch_default_for_uri_finish(result); + } catch (e) { + log('Error opening Desktop in Files: ' + e.message); + } @@ -15204,9 +15730,7 @@ index 0000000..83ca2cc + + _onOpenTerminalClicked() { + let desktopPath = DesktopIconsUtil.getDesktopDir().get_path(); -+ let command = DesktopIconsUtil.getTerminalCommand(desktopPath); -+ -+ Util.spawnCommandLine(command); ++ DesktopIconsUtil.launchTerminal(desktopPath); + } + + _syncUndoRedo() { @@ -15222,7 +15746,7 @@ index 0000000..83ca2cc + _createDesktopBackgroundMenu() { + let menu = new PopupMenu.PopupMenu(Main.layoutManager.dummyCursor, + 0, St.Side.TOP); -+ menu.addAction(_("New Folder"), () => this._omNewFolderClicked()); ++ menu.addAction(_("New Folder"), () => this._onNewFolderClicked()); + menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this._pasteMenuItem = menu.addAction(_("Paste"), () => this._onPasteClicked()); + this._undoMenuItem = menu.addAction(_("Undo"), () => this._onUndoClicked()); @@ -15253,12 +15777,13 @@ index 0000000..83ca2cc + Clipboard.get_text(CLIPBOARD_TYPE, + (clipBoard, text) => { + let [valid, is_cut, files] = this._parseClipboardText(text); -+ this._pasteMenuItem.actor.visible = valid; ++ this._pasteMenuItem.setSensitive(valid); + } + ); + } + } + ); ++ this._pasteMenuItem.setSensitive(false); + + return menu; + } @@ -15272,7 +15797,7 @@ index 0000000..83ca2cc + this.actor._desktopBackgroundManager.ignoreRelease(); + } + -+ _addFileItemTo(fileItem, column, row, overwriteCoordinates) { ++ _addFileItemTo(fileItem, column, row, coordinatesAction) { + let placeholder = this.layout.get_child_at(column, row); + placeholder.child = fileItem.actor; + this._fileItems.push(fileItem); @@ -15286,18 +15811,18 @@ index 0000000..83ca2cc + * Also store the new possition if it has been moved by the user, + * and not triggered by a screen change. + */ -+ if ((fileItem.savedCoordinates == null) || (overwriteCoordinates == StoredCoordinates.OVERWRITE)) { ++ if ((fileItem.savedCoordinates == null) || (coordinatesAction == StoredCoordinates.OVERWRITE)) { + let [fileX, fileY] = placeholder.get_transformed_position(); + fileItem.savedCoordinates = [Math.round(fileX), Math.round(fileY)]; + } + } + -+ addFileItemCloseTo(fileItem, x, y, overwriteCoordinates) { -+ let [column, row] = this._getEmptyPlaceClosestTo(x, y); -+ this._addFileItemTo(fileItem, column, row, overwriteCoordinates); ++ addFileItemCloseTo(fileItem, x, y, coordinatesAction) { ++ let [column, row] = this._getEmptyPlaceClosestTo(x, y, coordinatesAction); ++ this._addFileItemTo(fileItem, column, row, coordinatesAction); + } + -+ _getEmptyPlaceClosestTo(x, y) { ++ _getEmptyPlaceClosestTo(x, y, coordinatesAction) { + let maxColumns = this._getMaxColumns(); + let maxRows = this._getMaxRows(); + @@ -15322,6 +15847,8 @@ index 0000000..83ca2cc + continue; + + let [proposedX, proposedY] = placeholder.get_transformed_position(); ++ if (coordinatesAction == StoredCoordinates.ASSIGN) ++ return [column, row]; + let distance = DesktopIconsUtil.distanceBetweenPoints(proposedX, proposedY, x, y); + if (distance < minDistance) { + found = true; @@ -15430,7 +15957,7 @@ index 0000000..83ca2cc + acceptDrop(source, actor, x, y, time) { + /* Coordinates are relative to the grid, we want to transform them to + * absolute coordinates to work across monitors */ -+ let [gridX, gridY] = this._grid.get_transformed_position(); ++ let [gridX, gridY] = this.actor.get_transformed_position(); + let [absoluteX, absoluteY] = [x + gridX, y + gridY]; + return Extension.desktopManager.acceptDrop(absoluteX, absoluteY); + } @@ -15510,7 +16037,7 @@ index 0000000..83ca2cc + renameContent.add_child(this._renameEntry); + renameContent.add_child(renameButtonsBox); + -+ this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP, { can_focus: false, x_expand: true }); ++ this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP, { can_focus: false, x_expand: false }); + this.actor = this._boxPointer.actor; + this.actor.style_class = 'popup-menu-boxpointer'; + this.actor.add_style_class_name('popup-menu'); @@ -15534,9 +16061,12 @@ index 0000000..83ca2cc + } + + this._boxPointer.setPosition(this._source.actor, 0.5); -+ this._boxPointer.show(BoxPointer.PopupAnimation.FADE | -+ BoxPointer.PopupAnimation.SLIDE, -+ null); ++ if (ExtensionUtils.versionCheck(['3.28', '3.30'], Config.PACKAGE_VERSION)) ++ this._boxPointer.show(BoxPointer.PopupAnimation.FADE | ++ BoxPointer.PopupAnimation.SLIDE); ++ else ++ this._boxPointer.open(BoxPointer.PopupAnimation.FADE | ++ BoxPointer.PopupAnimation.SLIDE); + + this.emit('open-state-changed', true); + } @@ -15547,8 +16077,13 @@ index 0000000..83ca2cc + + this._grabHelper.ungrab({ actor: this.actor }); + -+ this._boxPointer.hide(BoxPointer.PopupAnimation.FADE | -+ BoxPointer.PopupAnimation.SLIDE); ++ if (ExtensionUtils.versionCheck(['3.28', '3.30'], Config.PACKAGE_VERSION)) ++ this._boxPointer.hide(BoxPointer.PopupAnimation.FADE | ++ BoxPointer.PopupAnimation.SLIDE); ++ else ++ this._boxPointer.close(BoxPointer.PopupAnimation.FADE | ++ BoxPointer.PopupAnimation.SLIDE); ++ + this._isOpen = false; + this.emit('open-state-changed', false); + } @@ -15560,9 +16095,9 @@ index 0000000..83ca2cc + + this._popup(); + this._renameEntry.grab_key_focus(); -+ this._renameEntry.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false) -+ let allChars = fileItem.displayName.length; -+ this._renameEntry.clutter_text.set_selection(0, allChars); ++ this._renameEntry.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); ++ let extensionOffset = DesktopIconsUtil.getFileExtensionOffset(fileItem.displayName, fileItem.isDirectory); ++ this._renameEntry.clutter_text.set_selection(0, extensionOffset); + } + + _onRenameAccepted() { @@ -15583,10 +16118,10 @@ index 0000000..83ca2cc +Signals.addSignalMethods(RenamePopup.prototype); diff --git a/extensions/desktop-icons/desktopIconsUtil.js b/extensions/desktop-icons/desktopIconsUtil.js new file mode 100644 -index 0000000..95f8e8b +index 0000000..0aea654 --- /dev/null +++ b/extensions/desktop-icons/desktopIconsUtil.js -@@ -0,0 +1,60 @@ +@@ -0,0 +1,123 @@ +/* Desktop Icons GNOME Shell extension + * + * Copyright (C) 2017 Carlos Soriano @@ -15605,6 +16140,7 @@ index 0000000..95f8e8b + * along with this program. If not, see . + */ + ++const Gtk = imports.gi.Gtk; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const ExtensionUtils = imports.misc.extensionUtils; @@ -15625,12 +16161,45 @@ index 0000000..95f8e8b + return Math.max(Math.min(value, max), min); +}; + -+function getTerminalCommand(workdir) { ++function launchTerminal(workdir) { + let terminalSettings = new Gio.Settings({ schema_id: TERMINAL_SCHEMA }); + let exec = terminalSettings.get_string(EXEC_KEY); -+ let command = `${exec} --working-directory=${workdir}`; ++ let argv = [exec, `--working-directory=${workdir}`]; + -+ return command; ++ /* The following code has been extracted from GNOME Shell's ++ * source code in Misc.Util.trySpawn function and modified to ++ * set the working directory. ++ * ++ * https://gitlab.gnome.org/GNOME/gnome-shell/blob/gnome-3-30/js/misc/util.js ++ */ ++ ++ var success, pid; ++ try { ++ [success, pid] = GLib.spawn_async(workdir, argv, null, ++ GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, ++ null); ++ } catch (err) { ++ /* Rewrite the error in case of ENOENT */ ++ if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) { ++ throw new GLib.SpawnError({ code: GLib.SpawnError.NOENT, ++ message: _("Command not found") }); ++ } else if (err instanceof GLib.Error) { ++ // The exception from gjs contains an error string like: ++ // Error invoking GLib.spawn_command_line_async: Failed to ++ // execute child process "foo" (No such file or directory) ++ // We are only interested in the part in the parentheses. (And ++ // we can't pattern match the text, since it gets localized.) ++ let message = err.message.replace(/.*\((.+)\)/, '$1'); ++ throw new (err.constructor)({ code: err.code, ++ message: message }); ++ } else { ++ throw err; ++ } ++ } ++ // Dummy child watch; we don't want to double-fork internally ++ // because then we lose the parent-child relationship, which ++ // can break polkit. See https://bugzilla.redhat.com//show_bug.cgi?id=819275 ++ GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, () => {}); +} + +function distanceBetweenPoints(x, y, x2, y2) { @@ -15647,12 +16216,41 @@ index 0000000..95f8e8b + } + return extraFolders; +} ++ ++function getFileExtensionOffset(filename, isDirectory) { ++ let offset = filename.length; ++ ++ if (!isDirectory) { ++ let doubleExtensions = ['.gz', '.bz2', '.sit', '.Z', '.bz', '.xz']; ++ for (let extension of doubleExtensions) { ++ if (filename.endsWith(extension)) { ++ offset -= extension.length; ++ filename = filename.substring(0, offset); ++ break; ++ } ++ } ++ let lastDot = filename.lastIndexOf('.'); ++ if (lastDot > 0) ++ offset = lastDot; ++ } ++ return offset; ++} ++ ++function getGtkClassBackgroundColor(classname, state) { ++ let widget = new Gtk.WidgetPath(); ++ widget.append_type(Gtk.Widget); ++ ++ let context = new Gtk.StyleContext(); ++ context.set_path(widget); ++ context.add_class(classname); ++ return context.get_background_color(state); ++} diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js new file mode 100644 -index 0000000..37e0014 +index 0000000..d8f548f --- /dev/null +++ b/extensions/desktop-icons/desktopManager.js -@@ -0,0 +1,701 @@ +@@ -0,0 +1,752 @@ +/* Desktop Icons GNOME Shell extension + * + * Copyright (C) 2017 Carlos Soriano @@ -15671,11 +16269,11 @@ index 0000000..37e0014 + * along with this program. If not, see . + */ + ++const Gtk = imports.gi.Gtk; +const Clutter = imports.gi.Clutter; +const GObject = imports.gi.GObject; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; -+const Lang = imports.lang; +const St = imports.gi.St; +const Mainloop = imports.mainloop; +const Meta = imports.gi.Meta; @@ -15738,7 +16336,7 @@ index 0000000..37e0014 + this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._recreateDesktopIcons()); + this._rubberBand = new St.Widget({ style_class: 'rubber-band' }); + this._rubberBand.hide(); -+ Main.layoutManager.uiGroup.add_child(this._rubberBand); ++ Main.layoutManager._backgroundGroup.add_child(this._rubberBand); + this._grabHelper = new GrabHelper.GrabHelper(global.stage); + + this._addDesktopIcons(); @@ -15751,6 +16349,7 @@ index 0000000..37e0014 + }); + + this._selection = new Set(); ++ this._currentSelection = new Set(); + this._inDrag = false; + this._dragXStart = Number.POSITIVE_INFINITY; + this._dragYStart = Number.POSITIVE_INFINITY; @@ -15759,6 +16358,7 @@ index 0000000..37e0014 + startRubberBand(x, y) { + this._rubberBandInitialX = x; + this._rubberBandInitialY = y; ++ this._initRubberBandColor(); + this._updateRubberBand(x, y); + this._rubberBand.show(); + this._grabHelper.grab({ actor: global.stage }); @@ -15767,6 +16367,20 @@ index 0000000..37e0014 + this.endRubberBand(); + }); + this._rubberBandId = global.stage.connect('motion-event', (actor, event) => { ++ /* In some cases, when the user starts a rubberband selection and ends it ++ * (by releasing the left button) over a window instead of doing it over ++ * the desktop, the stage doesn't receive the "button-release" event. ++ * This happens currently with, at least, Dash to Dock extension, but ++ * it probably also happens with other applications or extensions. ++ * To fix this, we also end the rubberband selection if we detect mouse ++ * motion in the stage without the left button pressed during a ++ * rubberband selection. ++ * */ ++ let button = event.get_state(); ++ if (!(button & Clutter.ModifierType.BUTTON1_MASK)) { ++ this.endRubberBand(); ++ return; ++ } + [x, y] = event.get_coords(); + this._updateRubberBand(x, y); + let x0, y0, x1, y1; @@ -15784,8 +16398,8 @@ index 0000000..37e0014 + y1 = this._rubberBandInitialY; + y0 = y; + } -+ for(let [fileUri, fileItem] of this._fileItems) { -+ fileItem.emit('selected', true, ++ for (let [fileUri, fileItem] of this._fileItems) { ++ fileItem.emit('selected', true, true, + fileItem.intersectsWith(x0, y0, x1 - x0, y1 - y0)); + } + }); @@ -15799,6 +16413,9 @@ index 0000000..37e0014 + global.stage.disconnect(this._stageReleaseEventId); + this._rubberBandId = 0; + this._stageReleaseEventId = 0; ++ ++ this._selection = new Set([...this._selection, ...this._currentSelection]); ++ this._currentSelection.clear(); + } + + _updateRubberBand(currentX, currentY) { @@ -15823,7 +16440,7 @@ index 0000000..37e0014 + let newGrid = new DesktopGrid.DesktopGrid(bgManager); + newGrid.actor.connect('destroy', (actor) => { + // if a grid loses its actor, remove it from the grid list -+ for(let grid in this._desktopGrids) ++ for (let grid in this._desktopGrids) + if (this._desktopGrids[grid].actor == actor) { + delete this._desktopGrids[grid]; + break; @@ -15840,11 +16457,20 @@ index 0000000..37e0014 + this._desktopGrids = {}; + } + ++ /** ++ * Initialize rubberband color from the GTK rubberband class ++ * */ ++ _initRubberBandColor() { ++ let rgba = DesktopIconsUtil.getGtkClassBackgroundColor('rubberband', Gtk.StateFlags.NORMAL); ++ let background_color = ++ 'rgba(' + rgba.red * 255 + ', ' + rgba.green * 255 + ', ' + rgba.blue * 255 + ', 0.4)'; ++ this._rubberBand.set_style('background-color: ' + background_color); ++ } ++ + async _scanFiles() { + for (let [fileItem, id] of this._fileItemHandlers) + fileItem.disconnect(id); + this._fileItemHandlers = new Map(); -+ this._fileItems = new Map(); + + if (!this._unixMode) { + let desktopDir = DesktopIconsUtil.getDesktopDir(); @@ -15856,14 +16482,16 @@ index 0000000..37e0014 + } + + try { ++ let tmpFileItems = new Map(); + for (let [file, info, extra] of await this._enumerateDesktop()) { + let fileItem = new FileItem.FileItem(file, info, extra); -+ this._fileItems.set(fileItem.file.get_uri(), fileItem); ++ tmpFileItems.set(fileItem.file.get_uri(), fileItem); + let id = fileItem.connect('selected', + this._onFileItemSelected.bind(this)); + + this._fileItemHandlers.set(fileItem, id); + } ++ this._fileItems = tmpFileItems; + } catch (e) { + if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) + log(`Error loading desktop files ${e.message}`); @@ -15873,6 +16501,14 @@ index 0000000..37e0014 + this.scheduleReLayoutChildren(); + } + ++ getDesktopFileNames () { ++ let fileList = []; ++ for (let [uri, item] of this._fileItems) { ++ fileList.push(item.fileName); ++ } ++ return fileList; ++ } ++ + _enumerateDesktop() { + return new Promise((resolve, reject) => { + if (this._desktopEnumerateCancellable) @@ -15885,16 +16521,16 @@ index 0000000..37e0014 + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_DEFAULT, + this._desktopEnumerateCancellable, -+ (o, res) => { ++ (source, result) => { + try { -+ let fileEnum = desktopDir.enumerate_children_finish(res); ++ let fileEnum = source.enumerate_children_finish(result); + let resultGenerator = function *() { + let info; -+ while ((info = fileEnum.next_file(null))) -+ yield [fileEnum.get_child(info), info, Prefs.FileType.NONE]; + for (let [newFolder, extras] of DesktopIconsUtil.getExtraFolders()) { + yield [newFolder, newFolder.query_info(DesktopIconsUtil.DEFAULT_ATTRIBUTES, Gio.FileQueryInfoFlags.NONE, this._desktopEnumerateCancellable), extras]; + } ++ while ((info = fileEnum.next_file(null))) ++ yield [fileEnum.get_child(info), info, Prefs.FileType.NONE]; + }.bind(this); + resolve(resultGenerator()); + } catch (e) { @@ -15917,13 +16553,17 @@ index 0000000..37e0014 + } + + checkIfSpecialFilesAreSelected() { -+ for(let fileItem of this._selection) { ++ for (let fileItem of this._selection) { + if (fileItem.isSpecial) + return true; + } + return false; + } + ++ getNumberOfSelectedItems() { ++ return this._selection.size; ++ } ++ + get writableByOthers() { + return this._writableByOthers; + } @@ -15965,9 +16605,9 @@ index 0000000..37e0014 + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_DEFAULT, + this._queryFileInfoCancellable, -+ (source, res) => { ++ (source, result) => { + try { -+ let info = source.query_info_finish(res); ++ let info = source.query_info_finish(result); + this._queryFileInfoCancellable = null; + + this._unixMode = info.get_attribute_uint32(Gio.FILE_ATTRIBUTE_UNIX_MODE); @@ -16202,11 +16842,18 @@ index 0000000..37e0014 + } + + _addFileItemCloseTo(item) { -+ let [x, y] = (item.savedCoordinates == null) ? [0, 0] : item.savedCoordinates; ++ let coordinates; ++ let x = 0; ++ let y = 0; ++ let coordinatesAction = DesktopGrid.StoredCoordinates.ASSIGN; ++ if (item.savedCoordinates != null) { ++ [x, y] = item.savedCoordinates; ++ coordinatesAction = DesktopGrid.StoredCoordinates.PRESERVE; ++ } + let monitorIndex = findMonitorIndexForPos(x, y); + let desktopGrid = this._desktopGrids[monitorIndex]; + try { -+ desktopGrid.addFileItemCloseTo(item, x, y, DesktopGrid.StoredCoordinates.PRESERVE); ++ desktopGrid.addFileItemCloseTo(item, x, y, coordinatesAction); + } catch (e) { + log(`Error adding children to desktop: ${e.message}`); + } @@ -16273,24 +16920,26 @@ index 0000000..37e0014 + }); + } + -+ _onFileItemSelected(fileItem, keepCurrentSelection, addToSelection) { ++ _onFileItemSelected(fileItem, keepCurrentSelection, rubberBandSelection, addToSelection) { + + if (!keepCurrentSelection && !this._inDrag) + this.clearSelection(); + ++ let selection = keepCurrentSelection && rubberBandSelection ? this._currentSelection : this._selection; + if (addToSelection) -+ this._selection.add(fileItem); ++ selection.add(fileItem); + else -+ this._selection.delete(fileItem); ++ selection.delete(fileItem); + -+ for(let [fileUri, fileItem] of this._fileItems) -+ fileItem.isSelected = this._selection.has(fileItem); ++ for (let [fileUri, fileItem] of this._fileItems) ++ fileItem.isSelected = this._currentSelection.has(fileItem) || this._selection.has(fileItem); + } + + clearSelection() { + for (let [fileUri, fileItem] of this._fileItems) + fileItem.isSelected = false; + this._selection = new Set(); ++ this._currentSelection = new Set(); + } + + _getClipboardText(isCopy) { @@ -16356,7 +17005,7 @@ index 0000000..37e0014 +} diff --git a/extensions/desktop-icons/extension.js b/extensions/desktop-icons/extension.js new file mode 100644 -index 0000000..e5ca440 +index 0000000..4b960ab --- /dev/null +++ b/extensions/desktop-icons/extension.js @@ -0,0 +1,71 @@ @@ -16431,13 +17080,12 @@ index 0000000..e5ca440 + Main.layoutManager._addBackgroundMenu = addBackgroundMenuOrig; + Main.overview.shouldToggleByCornerOrButton = oldShouldToggleByCornerOrButtonFunction; +} -\ No newline at end of file diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js new file mode 100644 -index 0000000..75c1d23 +index 0000000..e6f4f2c --- /dev/null +++ b/extensions/desktop-icons/fileItem.js -@@ -0,0 +1,771 @@ +@@ -0,0 +1,800 @@ +/* Desktop Icons GNOME Shell extension + * + * Copyright (C) 2017 Carlos Soriano @@ -16456,10 +17104,10 @@ index 0000000..75c1d23 + * along with this program. If not, see . + */ + ++const Gtk = imports.gi.Gtk; +const Clutter = imports.gi.Clutter; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; -+const Lang = imports.lang; +const St = imports.gi.St; +const Pango = imports.gi.Pango; +const Meta = imports.gi.Meta; @@ -16623,12 +17271,16 @@ index 0000000..75c1d23 + this._loadThumbnailDataCancellable.cancel(); + + /* Desktop file */ -+ if (this._monitorDesktopFileId) ++ if (this._monitorDesktopFileId) { + this._monitorDesktopFile.disconnect(this._monitorDesktopFileId); ++ this._monitorDesktopFile.cancel(); ++ } + + /* Trash */ -+ if (this._monitorTrashDir) ++ if (this._monitorTrashDir) { + this._monitorTrashDir.disconnect(this._monitorTrashId); ++ this._monitorTrashDir.cancel(); ++ } + if (this._queryTrashInfoCancellable) + this._queryTrashInfoCancellable.cancel(); + if (this._scheduleTrashRefreshId) @@ -16643,9 +17295,9 @@ index 0000000..75c1d23 + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_DEFAULT, + this._queryFileInfoCancellable, -+ (source, res) => { ++ (source, result) => { + try { -+ let newFileInfo = source.query_info_finish(res); ++ let newFileInfo = source.query_info_finish(result); + this._queryFileInfoCancellable = null; + this._updateMetadataFromFileInfo(newFileInfo); + if (rebuild) { @@ -16690,7 +17342,7 @@ index 0000000..75c1d23 + this._fileType = fileInfo.get_file_type(); + this._isDirectory = this._fileType == Gio.FileType.DIRECTORY; + this._isSpecial = this._fileExtra != Prefs.FileType.NONE; -+ this._attributeHidden = fileInfo.get_is_hidden(); ++ this._isHidden = fileInfo.get_is_hidden() | fileInfo.get_is_backup(); + this._isSymlink = fileInfo.get_is_symlink(); + this._modifiedTime = this._fileInfo.get_attribute_uint64("time::modified"); + /* @@ -16747,9 +17399,9 @@ index 0000000..75c1d23 + this._loadThumbnailDataCancellable = new Gio.Cancellable(); + let thumbnailFile = Gio.File.new_for_path(thumbnail); + thumbnailFile.load_bytes_async(this._loadThumbnailDataCancellable, -+ (obj, res) => { ++ (source, result) => { + try { -+ let [thumbnailData, etag_out] = obj.load_bytes_finish(res); ++ let [thumbnailData, etag_out] = source.load_bytes_finish(result); + let thumbnailStream = Gio.MemoryInputStream.new_from_bytes(thumbnailData); + let thumbnailPixbuf = GdkPixbuf.Pixbuf.new_from_stream(thumbnailStream, null); + @@ -16803,9 +17455,9 @@ index 0000000..75c1d23 + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_DEFAULT, + this._queryTrashInfoCancellable, -+ (source, res) => { ++ (source, result) => { + try { -+ this._fileInfo = source.query_info_finish(res); ++ this._fileInfo = source.query_info_finish(result); + this._queryTrashInfoCancellable = null; + this._updateIcon(); + } catch(error) { @@ -16823,7 +17475,7 @@ index 0000000..75c1d23 + } + + get isHidden() { -+ return this._fileInfo.get_is_hidden(); ++ return this._isHidden; + } + + _createEmblemedStIcon(icon, iconName) { @@ -16879,9 +17531,9 @@ index 0000000..75c1d23 + + Gio.AppInfo.launch_default_for_uri_async(this.file.get_uri(), + null, null, -+ (source, res) => { ++ (source, result) => { + try { -+ Gio.AppInfo.launch_default_for_uri_finish(res); ++ Gio.AppInfo.launch_default_for_uri_finish(result); + } catch (e) { + log('Error opening file ' + this.file.get_uri() + ': ' + e.message); + } @@ -16946,9 +17598,9 @@ index 0000000..75c1d23 + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_LOW, + null, -+ (source, res) => { ++ (source, result) => { + try { -+ source.set_attributes_finish(res); ++ source.set_attributes_finish(result); + this._refreshMetadataAsync(true); + } catch(e) { + log(`Failed to set metadata::trusted: ${e.message}`); @@ -16972,17 +17624,13 @@ index 0000000..75c1d23 + Gio.FileQueryInfoFlags.NONE, + GLib.PRIORITY_LOW, + null, -+ (source, res) => { ++ (source, result) => { + try { -+ source.set_attributes_finish (res); ++ source.set_attributes_finish (result); + } catch(e) { + log(`Failed to set unix mode: ${e.message}`); + } + }); -+ this._file.set_attributes_from_info(info, -+ Gio.FileQueryInfoFlags.NONE, -+ GLib.PRIORITY_LOW, -+ null); + } + } + @@ -16990,6 +17638,21 @@ index 0000000..75c1d23 + return !this.trustedDesktopFile && this._fileExtra == Prefs.FileType.NONE; + } + ++ _doOpenWith() { ++ DBusUtils.openFileWithOtherApplication(this.file.get_path()); ++ } ++ ++ _getSelectionStyle() { ++ let rgba = DesktopIconsUtil.getGtkClassBackgroundColor('view', Gtk.StateFlags.SELECTED); ++ let background_color = ++ 'rgba(' + rgba.red * 255 + ', ' + rgba.green * 255 + ', ' + rgba.blue * 255 + ', 0.6)'; ++ let border_color = ++ 'rgba(' + rgba.red * 255 + ', ' + rgba.green * 255 + ', ' + rgba.blue * 255 + ', 0.8)'; ++ ++ return 'background-color: ' + background_color + ';' + ++ 'border-color: ' + border_color + ';' ++ } ++ + _createMenu() { + this._menuManager = new PopupMenu.PopupMenuManager({ actor: this.actor }); + let side = St.Side.LEFT; @@ -16999,6 +17662,11 @@ index 0000000..75c1d23 + this._menu.addAction(_('Open'), () => this.doOpen()); + switch (this._fileExtra) { + case Prefs.FileType.NONE: ++ if (!this._isDirectory) ++ this._actionOpenWith = this._menu.addAction(_('Open With Other Application'), () => this._doOpenWith()); ++ else ++ this._actionOpenWith = null; ++ this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this._actionCut = this._menu.addAction(_('Cut'), () => this._onCutClicked()); + this._actionCopy = this._menu.addAction(_('Copy'), () => this._onCopyClicked()); + if (this.canRename()) @@ -17032,16 +17700,19 @@ index 0000000..75c1d23 + } + + _onOpenTerminalClicked () { -+ let command = DesktopIconsUtil.getTerminalCommand(this.file.get_path()); -+ Util.spawnCommandLine(command); ++ DesktopIconsUtil.launchTerminal(this.file.get_path()); + } + + _onPressButton(actor, event) { + let button = event.get_button(); + if (button == 3) { + if (!this.isSelected) -+ this.emit('selected', false, true); ++ this.emit('selected', false, false, true); + this._menu.toggle(); ++ if (this._actionOpenWith) { ++ let allowOpenWith = (Extension.desktopManager.getNumberOfSelectedItems() == 1); ++ this._actionOpenWith.setSensitive(allowOpenWith); ++ } + let specialFilesSelected = Extension.desktopManager.checkIfSpecialFilesAreSelected(); + if (this._actionCut) + this._actionCut.setSensitive(!specialFilesSelected); @@ -17059,7 +17730,7 @@ index 0000000..75c1d23 + let shiftPressed = !!(event.get_state() & Clutter.ModifierType.SHIFT_MASK); + let controlPressed = !!(event.get_state() & Clutter.ModifierType.CONTROL_MASK); + if (!this.isSelected) { -+ this.emit('selected', shiftPressed || controlPressed, true); ++ this.emit('selected', shiftPressed || controlPressed, false, true); + } + } + return Clutter.EVENT_STOP; @@ -17102,7 +17773,7 @@ index 0000000..75c1d23 + let controlPressed = !!(event.get_state() & Clutter.ModifierType.CONTROL_MASK); + if ((event.get_click_count() == 1) && Prefs.CLICK_POLICY_SINGLE && !shiftPressed && !controlPressed) + this.doOpen(); -+ this.emit('selected', shiftPressed || controlPressed, true); ++ this.emit('selected', shiftPressed || controlPressed, false, true); + return Clutter.EVENT_STOP; + } + if ((event.get_click_count() == 2) && (!Prefs.CLICK_POLICY_SINGLE)) @@ -17158,10 +17829,12 @@ index 0000000..75c1d23 + if (isSelected == this._isSelected) + return; + -+ if (isSelected) -+ this._container.add_style_pseudo_class('selected'); -+ else -+ this._container.remove_style_pseudo_class('selected'); ++ if (isSelected) { ++ this._container.set_style(this._getSelectionStyle()); ++ } else { ++ this._container.set_style('background-color: transparent'); ++ this._container.set_style('border-color: transparent'); ++ } + + this._isSelected = isSelected; + } @@ -17197,6 +17870,10 @@ index 0000000..75c1d23 + !this._writableByOthers; + } + ++ get fileName() { ++ return this._fileInfo.get_name(); ++ } ++ + get displayName() { + if (this.trustedDesktopFile) + return this._desktopFile.get_name(); @@ -17211,10 +17888,10 @@ index 0000000..75c1d23 +Signals.addSignalMethods(FileItem.prototype); diff --git a/extensions/desktop-icons/meson.build b/extensions/desktop-icons/meson.build new file mode 100644 -index 0000000..4e03db1 +index 0000000..8431af6 --- /dev/null +++ b/extensions/desktop-icons/meson.build -@@ -0,0 +1,18 @@ +@@ -0,0 +1,19 @@ +extension_data += configure_file( + input: metadata_name + '.in', + output: metadata_name, @@ -17224,6 +17901,7 @@ index 0000000..4e03db1 +extension_schemas += files(join_paths('schemas', metadata_conf.get('gschemaname') + '.gschema.xml')) + +extension_sources += files( ++ 'createFolderDialog.js', + 'createThumbnail.js', + 'dbusUtils.js', + 'desktopGrid.js', @@ -17252,21 +17930,28 @@ index 0000000..78cabf0 +} diff --git a/extensions/desktop-icons/po/LINGUAS b/extensions/desktop-icons/po/LINGUAS new file mode 100644 -index 0000000..bc8bc5d +index 0000000..65b7521 --- /dev/null +++ b/extensions/desktop-icons/po/LINGUAS -@@ -0,0 +1,12 @@ +@@ -0,0 +1,19 @@ +cs +da +de +es +fi +fr ++fur ++hr ++hu +id +it ++ja ++nl +pl +pt_BR +ru ++sv ++tr +zh_TW diff --git a/extensions/desktop-icons/po/POTFILES.in b/extensions/desktop-icons/po/POTFILES.in new file mode 100644 @@ -17281,152 +17966,211 @@ index 0000000..7c2ebd3 \ No newline at end of file diff --git a/extensions/desktop-icons/po/cs.po b/extensions/desktop-icons/po/cs.po new file mode 100644 -index 0000000..1da4122 +index 0000000..f5f9db4 --- /dev/null +++ b/extensions/desktop-icons/po/cs.po -@@ -0,0 +1,136 @@ +@@ -0,0 +1,195 @@ +# Czech translation for desktop-icons. +# Copyright (C) 2018 desktop-icons's COPYRIGHT HOLDER +# This file is distributed under the same license as the desktop-icons package. +# Marek Černocký , 2018. ++# Milan Zink , 2018. +# +msgid "" +msgstr "" +"Project-Id-Version: desktop-icons master\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" +"icons/issues\n" -+"POT-Creation-Date: 2018-10-01 20:15+0000\n" -+"PO-Revision-Date: 2018-10-02 11:10+0200\n" -+"Last-Translator: Marek Černocký \n" -+"Language-Team: čeština \n" ++"POT-Creation-Date: 2019-03-01 12:49+0000\n" ++"PO-Revision-Date: 2019-03-02 18:02+0100\n" ++"Last-Translator: Daniel Rusek \n" ++"Language-Team: Czech \n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" -+"X-Generator: Gtranslator 2.91.7\n" ++"X-Generator: Poedit 2.2.1\n" + -+#: prefs.js:89 ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Název nové složky" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Vytvořit" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Zrušit" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Názvy složek nesmí obsahovat „/“." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Složka se nemůže jmenovat „.“." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Složka se nemůže jmenovat „..“." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Složky s „.“ na začátku jejich názvu jsou skryty." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Soubor nebo složka s tímto názvem již existuje." ++ ++#: prefs.js:102 +msgid "Size for the desktop icons" +msgstr "Velikost ikon na pracovní ploše" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Small" +msgstr "malé" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Standard" +msgstr "standardní" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Large" +msgstr "velké" + -+#: prefs.js:89 -+msgid "Huge" -+msgstr "obrovské" -+ -+#: prefs.js:90 ++#: prefs.js:103 +msgid "Show the personal folder in the desktop" +msgstr "Zobrazovat osobní složku na pracovní ploše" + -+#: prefs.js:91 ++#: prefs.js:104 +msgid "Show the trash icon in the desktop" +msgstr "Zobrazovat ikonu koše na pracovní ploše" + -+#: desktopGrid.js:178 desktopGrid.js:297 ++#: desktopGrid.js:320 +msgid "New Folder" +msgstr "Nová složka" + -+#: desktopGrid.js:299 ++#: desktopGrid.js:322 +msgid "Paste" +msgstr "Vložit" + -+#: desktopGrid.js:300 ++#: desktopGrid.js:323 +msgid "Undo" +msgstr "Zpět" + -+#: desktopGrid.js:301 ++#: desktopGrid.js:324 +msgid "Redo" +msgstr "Znovu" + -+#: desktopGrid.js:303 -+msgid "Open Desktop in Files" -+msgstr "Otevřít plochu v Souborech" ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Zobrazit plochu v Souborech" + -+#: desktopGrid.js:304 -+msgid "Open Terminal" -+msgstr "Otevřít terminál" ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Otevřít v terminálu" + -+#: desktopGrid.js:306 ++#: desktopGrid.js:329 +msgid "Change Background…" +msgstr "Změnit pozadí…" + -+#: desktopGrid.js:307 ++#: desktopGrid.js:331 +msgid "Display Settings" +msgstr "Zobrazit nastavení" + -+#: desktopGrid.js:308 ++#: desktopGrid.js:332 +msgid "Settings" +msgstr "Nastavení" + -+#: fileItem.js:226 ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Zadejte název souboru…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "Budiž" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Nepovolit spouštění" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Povolit spouštění" ++ ++#: fileItem.js:574 +msgid "Open" +msgstr "Otevřít" + -+#: fileItem.js:229 ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Otevřít pomocí jiné aplikace" ++ ++#: fileItem.js:582 +msgid "Cut" +msgstr "Vyjmout" + -+#: fileItem.js:230 ++#: fileItem.js:583 +msgid "Copy" +msgstr "Kopírovat" + -+#: fileItem.js:231 ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Přejmenovat…" ++ ++#: fileItem.js:586 +msgid "Move to Trash" +msgstr "Přesunout do koše" + -+#: fileItem.js:235 -+msgid "Empty trash" ++#: fileItem.js:596 ++msgid "Empty Trash" +msgstr "Vyprázdnit koš" + -+#: fileItem.js:241 ++#: fileItem.js:602 +msgid "Properties" +msgstr "Vlastnosti" + -+#: fileItem.js:243 ++#: fileItem.js:604 +msgid "Show in Files" +msgstr "Zobrazit v Souborech" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 +msgid "Icon size" +msgstr "Velikost ikon" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 +msgid "Set the size for the desktop icons." +msgstr "Nastavit velikost pro ikony na pracovní ploše." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 +msgid "Show personal folder" +msgstr "Zobrazovat osobní složku" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 +msgid "Show the personal folder in the desktop." +msgstr "Zobrazovat osobní složku na pracovní ploše." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 +msgid "Show trash icon" +msgstr "Zobrazovat koš" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 +msgid "Show the trash icon in the desktop." +msgstr "Zobrazovat ikonu koše na pracovní ploše." ++ ++#~ msgid "Huge" ++#~ msgstr "obrovské" ++ ++#~ msgid "Ok" ++#~ msgstr "Ok" diff --git a/extensions/desktop-icons/po/da.po b/extensions/desktop-icons/po/da.po new file mode 100644 -index 0000000..98f2617 +index 0000000..d3f51f0 --- /dev/null +++ b/extensions/desktop-icons/po/da.po -@@ -0,0 +1,136 @@ +@@ -0,0 +1,159 @@ +# Danish translation for desktop-icons. +# Copyright (C) 2018 desktop-icons's COPYRIGHT HOLDER +# This file is distributed under the same license as the desktop-icons package. @@ -17437,294 +18181,373 @@ index 0000000..98f2617 +"Project-Id-Version: desktop-icons master\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" +"icons/issues\n" -+"POT-Creation-Date: 2018-10-26 12:04+0000\n" -+"PO-Revision-Date: 2018-10-27 16:42+0200\n" ++"POT-Creation-Date: 2019-01-15 10:59+0000\n" ++"PO-Revision-Date: 2019-02-09 11:35+0100\n" ++"Last-Translator: Alan Mortensen \n" +"Language-Team: Danish \n" +"Language: da\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" -+"Last-Translator: Alan Mortensen \n" +"X-Generator: Poedit 2.0.6\n" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Size for the desktop icons" +msgstr "Størrelsen på skrivebordsikoner" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Small" +msgstr "Små" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Standard" +msgstr "Standard" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Large" +msgstr "Store" + -+#: prefs.js:89 -+msgid "Huge" -+msgstr "Enorme" -+ -+#: prefs.js:90 ++#: prefs.js:103 +msgid "Show the personal folder in the desktop" +msgstr "Vis den personlige mappe på skrivebordet" + -+#: prefs.js:91 ++#: prefs.js:104 +msgid "Show the trash icon in the desktop" +msgstr "Vis papirkurvsikonet på skrivebordet" + -+#: desktopGrid.js:178 desktopGrid.js:297 ++#: desktopGrid.js:187 desktopGrid.js:306 +msgid "New Folder" +msgstr "Ny mappe" + -+#: desktopGrid.js:299 ++#: desktopGrid.js:308 +msgid "Paste" +msgstr "Indsæt" + -+#: desktopGrid.js:300 ++#: desktopGrid.js:309 +msgid "Undo" +msgstr "Fortryd" + -+#: desktopGrid.js:301 ++#: desktopGrid.js:310 +msgid "Redo" +msgstr "Omgør" + -+#: desktopGrid.js:303 -+msgid "Open Desktop in Files" -+msgstr "Åbn skrivebordet i Filer" ++#: desktopGrid.js:312 ++msgid "Show Desktop in Files" ++msgstr "Vis skrivebordet i Filer" + -+#: desktopGrid.js:304 -+msgid "Open Terminal" -+msgstr "Åbn Terminal" ++#: desktopGrid.js:313 fileItem.js:586 ++msgid "Open in Terminal" ++msgstr "Åbn i terminal" + -+#: desktopGrid.js:306 ++#: desktopGrid.js:315 +msgid "Change Background…" +msgstr "Skift baggrund …" + -+#: desktopGrid.js:307 ++#: desktopGrid.js:317 +msgid "Display Settings" +msgstr "Skærmindstillinger" + -+#: desktopGrid.js:308 ++#: desktopGrid.js:318 +msgid "Settings" +msgstr "Indstillinger" + -+#: fileItem.js:385 ++#: desktopGrid.js:559 ++msgid "Enter file name…" ++msgstr "Indtast filnavn …" ++ ++#: desktopGrid.js:563 ++msgid "OK" ++msgstr "OK" ++ ++#: desktopGrid.js:569 ++msgid "Cancel" ++msgstr "Annullér" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Tillad ikke opstart" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Tillad opstart" ++ ++#: fileItem.js:559 +msgid "Open" +msgstr "Åbn" + -+#: fileItem.js:388 ++#: fileItem.js:562 +msgid "Cut" +msgstr "Klip" + -+#: fileItem.js:389 ++#: fileItem.js:563 +msgid "Copy" +msgstr "Kopiér" + -+#: fileItem.js:390 ++#: fileItem.js:565 ++msgid "Rename…" ++msgstr "Omdøb …" ++ ++#: fileItem.js:566 +msgid "Move to Trash" +msgstr "Flyt til papirkurven" + -+#: fileItem.js:394 -+msgid "Empty trash" ++#: fileItem.js:576 ++msgid "Empty Trash" +msgstr "Tøm papirkurven" + -+#: fileItem.js:400 ++#: fileItem.js:582 +msgid "Properties" +msgstr "Egenskaber" + -+#: fileItem.js:402 ++#: fileItem.js:584 +msgid "Show in Files" +msgstr "Vis i Filer" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 +msgid "Icon size" +msgstr "Ikonstørrelse" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 +msgid "Set the size for the desktop icons." +msgstr "Angiv størrelsen på skrivebordsikoner." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 +msgid "Show personal folder" +msgstr "Vis personlig mappe" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 +msgid "Show the personal folder in the desktop." +msgstr "Vis den personlige mappe på skrivebordet." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 +msgid "Show trash icon" +msgstr "Vis papirkurvsikon" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 +msgid "Show the trash icon in the desktop." +msgstr "Vis papirkurvsikonet på skrivebordet." ++ ++#~ msgid "Huge" ++#~ msgstr "Enorme" diff --git a/extensions/desktop-icons/po/de.po b/extensions/desktop-icons/po/de.po new file mode 100644 -index 0000000..e2b0fb3 +index 0000000..ed5a257 --- /dev/null +++ b/extensions/desktop-icons/po/de.po -@@ -0,0 +1,136 @@ +@@ -0,0 +1,192 @@ +# German translation for desktop-icons. +# Copyright (C) 2018 desktop-icons's COPYRIGHT HOLDER +# This file is distributed under the same license as the desktop-icons package. +# Mario Blättermann , 2018. ++# rugk , 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: desktop-icons master\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" +"icons/issues\n" -+"POT-Creation-Date: 2018-10-02 21:39+0000\n" -+"PO-Revision-Date: 2018-10-03 21:28+0200\n" -+"Last-Translator: Mario Blättermann \n" ++"POT-Creation-Date: 2019-03-07 22:46+0000\n" ++"PO-Revision-Date: 2019-03-09 15:42+0100\n" ++"Last-Translator: Tim Sabsch \n" +"Language-Team: German \n" +"Language: de\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: Poedit 2.1.1\n" ++"X-Generator: Poedit 2.2.1\n" + -+#: prefs.js:89 ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Neuer Ordner" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Erstellen" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Abbrechen" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Ordnernamen dürfen kein »/« enthalten." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Ein Ordner darf nicht ».« genannt werden." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Ein Ordner darf nicht »..« genannt werden." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Ordner mit ».« am Anfang sind verborgen." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Es gibt bereits eine Datei oder einen Ordner mit diesem Namen." ++ ++#: prefs.js:102 +msgid "Size for the desktop icons" +msgstr "Größe der Arbeitsflächensymbole" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Small" +msgstr "Klein" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Standard" +msgstr "Standard" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Large" +msgstr "Groß" + -+#: prefs.js:89 -+msgid "Huge" -+msgstr "Riesig" -+ -+#: prefs.js:90 ++#: prefs.js:103 +msgid "Show the personal folder in the desktop" +msgstr "Den persönlichen Ordner auf der Arbeitsfläche anzeigen" + -+#: prefs.js:91 ++#: prefs.js:104 +msgid "Show the trash icon in the desktop" +msgstr "Papierkorb-Symbol auf der Arbeitsfläche anzeigen" + -+#: desktopGrid.js:178 desktopGrid.js:297 ++#: desktopGrid.js:320 +msgid "New Folder" +msgstr "Neuer Ordner" + -+#: desktopGrid.js:299 ++#: desktopGrid.js:322 +msgid "Paste" +msgstr "Einfügen" + -+#: desktopGrid.js:300 ++#: desktopGrid.js:323 +msgid "Undo" +msgstr "Rückgängig" + -+#: desktopGrid.js:301 ++#: desktopGrid.js:324 +msgid "Redo" +msgstr "Wiederholen" + -+#: desktopGrid.js:303 -+msgid "Open Desktop in Files" -+msgstr "Arbeitsfläche in Dateiverwaltung öffnen" ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Schreibtisch in Dateien anzeigen" + -+#: desktopGrid.js:304 -+msgid "Open Terminal" -+msgstr "Terminal öffnen" ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Im Terminal öffnen" + -+#: desktopGrid.js:306 ++#: desktopGrid.js:329 +msgid "Change Background…" +msgstr "Hintergrund ändern …" + -+#: desktopGrid.js:307 ++#: desktopGrid.js:331 +msgid "Display Settings" +msgstr "Anzeigeeinstellungen" + -+#: desktopGrid.js:308 ++#: desktopGrid.js:332 +msgid "Settings" +msgstr "Einstellungen" + -+#: fileItem.js:226 ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Dateinamen eingeben …" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "OK" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Start nicht erlauben" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Start erlauben" ++ ++#: fileItem.js:574 +msgid "Open" +msgstr "Öffnen" + -+#: fileItem.js:229 ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Mit anderer Anwendung öffnen" ++ ++#: fileItem.js:582 +msgid "Cut" +msgstr "Ausschneiden" + -+#: fileItem.js:230 ++#: fileItem.js:583 +msgid "Copy" +msgstr "Kopieren" + -+#: fileItem.js:231 ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Umbenennen …" ++ ++#: fileItem.js:586 +msgid "Move to Trash" +msgstr "In den Papierkorb verschieben" + -+#: fileItem.js:235 -+msgid "Empty trash" ++#: fileItem.js:596 ++msgid "Empty Trash" +msgstr "Papierkorb leeren" + -+#: fileItem.js:241 ++#: fileItem.js:602 +msgid "Properties" +msgstr "Eigenschaften" + -+#: fileItem.js:243 ++#: fileItem.js:604 +msgid "Show in Files" +msgstr "In Dateiverwaltung anzeigen" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 +msgid "Icon size" +msgstr "Symbolgröße" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 +msgid "Set the size for the desktop icons." +msgstr "Die Größe der Arbeitsflächensymbole festlegen." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 +msgid "Show personal folder" +msgstr "Persönlichen Ordner anzeigen" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 +msgid "Show the personal folder in the desktop." +msgstr "Den persönlichen Ordner auf der Arbeitsfläche anzeigen." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 +msgid "Show trash icon" +msgstr "Papierkorb-Symbol anzeigen" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 +msgid "Show the trash icon in the desktop." +msgstr "Das Papierkorb-Symbol auf der Arbeitsfläche anzeigen." ++ ++#~ msgid "Huge" ++#~ msgstr "Riesig" diff --git a/extensions/desktop-icons/po/es.po b/extensions/desktop-icons/po/es.po new file mode 100644 -index 0000000..05b47c2 +index 0000000..8cc87da --- /dev/null +++ b/extensions/desktop-icons/po/es.po -@@ -0,0 +1,186 @@ +@@ -0,0 +1,218 @@ +# 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. +# Sergio Costas , 2018. -+# Daniel Mustieles , 2018, 2019. ++# Daniel Mustieles , 2018-2019. +# +msgid "" +msgstr "" -+"Project-Id-Version: PACKAGE VERSION\n" ++"Project-Id-Version: 1.0\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" +"icons/issues\n" -+"POT-Creation-Date: 2018-12-14 09:12+0000\n" -+"PO-Revision-Date: 2019-01-08 16:12+0100\n" ++"POT-Creation-Date: 2019-03-01 12:11+0000\n" ++"PO-Revision-Date: 2019-03-04 10:37+0100\n" +"Last-Translator: Daniel Mustieles \n" +"Language-Team: es \n" +"Language: es\n" @@ -17732,7 +18555,40 @@ index 0000000..05b47c2 +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" -+"X-Generator: Gtranslator 2.91.7\n" ++"X-Generator: Gtranslator 3.31.90\n" ++ ++#: createFolderDialog.js:48 ++#| msgid "New Folder" ++msgid "New folder name" ++msgstr "Nombre de la nueva carpeta" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Crear" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Cancelar" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Los nombres de carpetas no pueden contener «/»." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Una carpeta no se puede llamar «.»." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Una carpeta no se puede llamar «..»." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Las carpetas cuyo nombre empieza por «.» están ocultas." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Ya hay un archivo o carpeta con ese nombre." + +#: prefs.js:102 +msgid "Size for the desktop icons" @@ -17750,10 +18606,6 @@ index 0000000..05b47c2 +msgid "Large" +msgstr "Grande" + -+#: prefs.js:102 -+msgid "Huge" -+msgstr "Inmenso" -+ +#: prefs.js:103 +msgid "Show the personal folder in the desktop" +msgstr "Mostrar la carpeta personal en el escritorio" @@ -17762,118 +18614,121 @@ index 0000000..05b47c2 +msgid "Show the trash icon in the desktop" +msgstr "Mostrar la papelera en el escritorio" + -+#: desktopGrid.js:182 desktopGrid.js:301 ++#: desktopGrid.js:320 +msgid "New Folder" +msgstr "Nueva carpeta" + -+#: desktopGrid.js:303 ++#: desktopGrid.js:322 +msgid "Paste" +msgstr "Pegar" + -+#: desktopGrid.js:304 ++#: desktopGrid.js:323 +msgid "Undo" +msgstr "Deshacer" + -+#: desktopGrid.js:305 ++#: desktopGrid.js:324 +msgid "Redo" +msgstr "Rehacer" + -+#: desktopGrid.js:307 -+msgid "Open Desktop in Files" -+msgstr "Abrir el escritorio en Files" ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Mostrar el escritorio en Archivos" + -+#: desktopGrid.js:308 -+msgid "Open Terminal" -+msgstr "Abrir un terminal" ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Abrir en una terminal" + -+#: desktopGrid.js:310 ++#: desktopGrid.js:329 +msgid "Change Background…" +msgstr "Cambiar el fondo..." + -+#: desktopGrid.js:311 ++#: desktopGrid.js:331 +msgid "Display Settings" +msgstr "Configuración de pantalla" + -+#: desktopGrid.js:312 ++#: desktopGrid.js:332 +msgid "Settings" +msgstr "Configuración" + -+#: desktopGrid.js:568 ++#: desktopGrid.js:576 +msgid "Enter file name…" +msgstr "Introduzca el nombre del archivo…" + -+#: desktopGrid.js:572 ++#: desktopGrid.js:580 +msgid "OK" +msgstr "Aceptar" + -+#: desktopGrid.js:578 -+msgid "Cancel" -+msgstr "Cancelar" -+ -+#: fileItem.js:485 ++#: fileItem.js:490 +msgid "Don’t Allow Launching" +msgstr "No permitir lanzar" + -+#: fileItem.js:487 ++#: fileItem.js:492 +msgid "Allow Launching" +msgstr "Permitir lanzar" + -+#: fileItem.js:550 ++#: fileItem.js:574 +msgid "Open" +msgstr "Abrir" + -+#: fileItem.js:553 ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Abrir con otra aplicación" ++ ++#: fileItem.js:582 +msgid "Cut" +msgstr "Cortar" + -+#: fileItem.js:554 ++#: fileItem.js:583 +msgid "Copy" +msgstr "Copiar" + -+#: fileItem.js:556 -+msgid "Rename" -+msgstr "Renombrar" ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Renombrar…" + -+#: fileItem.js:557 ++#: fileItem.js:586 +msgid "Move to Trash" +msgstr "Mover a la papelera" + -+#: fileItem.js:567 ++#: fileItem.js:596 +msgid "Empty Trash" +msgstr "Vaciar la papelera" + -+#: fileItem.js:573 ++#: fileItem.js:602 +msgid "Properties" +msgstr "Propiedades" + -+#: fileItem.js:575 ++#: fileItem.js:604 +msgid "Show in Files" +msgstr "Mostrar en Files" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 +msgid "Icon size" +msgstr "Tamaño de los iconos" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 +msgid "Set the size for the desktop icons." +msgstr "Establece el tamaño de los iconos del escritorio." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 +msgid "Show personal folder" +msgstr "Mostrar la carpeta personal" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 +msgid "Show the personal folder in the desktop." +msgstr "Mostrar la carpeta personal en el escritorio." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 +msgid "Show trash icon" +msgstr "Mostrar la papelera" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 +msgid "Show the trash icon in the desktop." +msgstr "Mostrar la papelera en el escritorio." + ++#~ msgid "Huge" ++#~ msgstr "Inmenso" ++ +#~ msgid "Ok" +#~ msgstr "Aceptar" + @@ -17899,10 +18754,10 @@ index 0000000..05b47c2 +#~ msgstr "Muestra la carpeta Vídeos en el escritorio." diff --git a/extensions/desktop-icons/po/fi.po b/extensions/desktop-icons/po/fi.po new file mode 100644 -index 0000000..216e5c1 +index 0000000..71ac40d --- /dev/null +++ b/extensions/desktop-icons/po/fi.po -@@ -0,0 +1,136 @@ +@@ -0,0 +1,191 @@ +# Finnish translation for desktop-icons. +# Copyright (C) 2018 desktop-icons's COPYRIGHT HOLDER +# This file is distributed under the same license as the desktop-icons package. @@ -17913,132 +18768,187 @@ index 0000000..216e5c1 +"Project-Id-Version: desktop-icons master\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" +"icons/issues\n" -+"POT-Creation-Date: 2018-10-14 08:09+0000\n" -+"PO-Revision-Date: 2018-10-14 12:44+0300\n" ++"POT-Creation-Date: 2019-03-01 12:11+0000\n" ++"PO-Revision-Date: 2019-03-02 11:29+0200\n" ++"Last-Translator: Jiri Grönroos \n" +"Language-Team: Finnish \n" +"Language: fi\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" -+"Last-Translator: Jiri Grönroos \n" +"X-Generator: Poedit 2.0.6\n" + -+#: prefs.js:89 ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Uusi kansion nimi" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Luo" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Peru" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Kansion nimi ei voi sisältää merkkiä “/”." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Kansion nimi ei voi olla “.”." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Kansion nimi ei voi olla “..”." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Kansiot, joiden nimi alkaa merkillä “.”, ovat piilotettuja." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Nimi on jo toisen tiedoston tai kansion käytössä." ++ ++#: prefs.js:102 +msgid "Size for the desktop icons" +msgstr "Työpöytäkuvakkeiden koko" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Small" +msgstr "Pieni" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Standard" +msgstr "Normaali" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Large" +msgstr "Suuri" + -+#: prefs.js:89 -+msgid "Huge" -+msgstr "Valtava" -+ -+#: prefs.js:90 ++#: prefs.js:103 +msgid "Show the personal folder in the desktop" +msgstr "Näytä kotikansio työpöydällä" + -+#: prefs.js:91 ++#: prefs.js:104 +msgid "Show the trash icon in the desktop" +msgstr "Näytä roskakorin kuvake työpöydällä" + -+#: desktopGrid.js:178 desktopGrid.js:297 ++#: desktopGrid.js:320 +msgid "New Folder" +msgstr "Uusi kansio" + -+#: desktopGrid.js:299 ++#: desktopGrid.js:322 +msgid "Paste" +msgstr "Liitä" + -+#: desktopGrid.js:300 ++#: desktopGrid.js:323 +msgid "Undo" +msgstr "Kumoa" + -+#: desktopGrid.js:301 ++#: desktopGrid.js:324 +msgid "Redo" +msgstr "Tee uudeleen" + -+#: desktopGrid.js:303 -+msgid "Open Desktop in Files" -+msgstr "Avaa työpöytä tiedostonhallinnassa" ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Näytä työpöytä tiedostonhallinnassa" + -+#: desktopGrid.js:304 -+msgid "Open Terminal" -+msgstr "Avaa pääte" ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Avaa päätteessä" + -+#: desktopGrid.js:306 ++#: desktopGrid.js:329 +msgid "Change Background…" +msgstr "Vaihda taustakuvaa…" + -+#: desktopGrid.js:307 ++#: desktopGrid.js:331 +msgid "Display Settings" +msgstr "Näytön asetukset" + -+#: desktopGrid.js:308 ++#: desktopGrid.js:332 +msgid "Settings" +msgstr "Asetukset" + -+#: fileItem.js:211 ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Anna tiedostonimi…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "OK" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Älä salli käynnistämistä" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Salli käynnistäminen" ++ ++#: fileItem.js:574 +msgid "Open" +msgstr "Avaa" + -+#: fileItem.js:214 ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Avaa toisella sovelluksella" ++ ++#: fileItem.js:582 +msgid "Cut" +msgstr "Leikkaa" + -+#: fileItem.js:215 ++#: fileItem.js:583 +msgid "Copy" +msgstr "Kopioi" + -+#: fileItem.js:216 ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Nimeä uudelleen…" ++ ++#: fileItem.js:586 +msgid "Move to Trash" +msgstr "Siirrä roskakoriin" + -+#: fileItem.js:220 -+msgid "Empty trash" ++#: fileItem.js:596 ++msgid "Empty Trash" +msgstr "Tyhjennä roskakori" + -+#: fileItem.js:226 ++#: fileItem.js:602 +msgid "Properties" +msgstr "Ominaisuudet" + -+#: fileItem.js:228 ++#: fileItem.js:604 +msgid "Show in Files" +msgstr "Näytä tiedostonhallinnassa" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 +msgid "Icon size" +msgstr "Kuvakekoko" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 +msgid "Set the size for the desktop icons." +msgstr "Aseta työpöytäkuvakkeiden koko." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 +msgid "Show personal folder" +msgstr "Näytä kotikansio" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 +msgid "Show the personal folder in the desktop." +msgstr "Näytä kotikansio työpöydällä." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 +msgid "Show trash icon" +msgstr "Näytä roskakorin kuvake" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 +msgid "Show the trash icon in the desktop." +msgstr "Näytä roskakorin kuvake työpöydällä." ++ ++#~ msgid "Huge" ++#~ msgstr "Valtava" diff --git a/extensions/desktop-icons/po/fr.po b/extensions/desktop-icons/po/fr.po new file mode 100644 index 0000000..13e8f3a @@ -18209,305 +19119,1171 @@ index 0000000..13e8f3a + +#~ msgid "Ok" +#~ msgstr "Valider" -diff --git a/extensions/desktop-icons/po/id.po b/extensions/desktop-icons/po/id.po +diff --git a/extensions/desktop-icons/po/fur.po b/extensions/desktop-icons/po/fur.po new file mode 100644 -index 0000000..c145d1a +index 0000000..3ab6129 --- /dev/null -+++ b/extensions/desktop-icons/po/id.po -@@ -0,0 +1,135 @@ -+# Indonesian translation for desktop-icons. -+# Copyright (C) 2018 desktop-icons's COPYRIGHT HOLDER ++++ b/extensions/desktop-icons/po/fur.po +@@ -0,0 +1,187 @@ ++# Friulian translation for desktop-icons. ++# Copyright (C) 2019 desktop-icons's COPYRIGHT HOLDER +# This file is distributed under the same license as the desktop-icons package. -+# FIRST AUTHOR , YEAR. ++# Fabio Tomat , 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: desktop-icons master\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" +"icons/issues\n" -+"POT-Creation-Date: 2018-10-02 09:18+0000\n" -+"PO-Revision-Date: 2018-10-02 20:30+0700\n" -+"Language-Team: Indonesian \n" -+"Language: id\n" ++"POT-Creation-Date: 2019-03-01 12:11+0000\n" ++"PO-Revision-Date: 2019-03-05 22:20+0100\n" ++"Last-Translator: Fabio Tomat \n" ++"Language-Team: Friulian \n" ++"Language: fur\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" -+"Last-Translator: Kukuh Syafaat \n" -+"X-Generator: Poedit 2.0.6\n" ++"X-Generator: Poedit 2.2.1\n" + -+#: prefs.js:89 ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Gnûf non de cartele" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Cree" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Anule" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "I nons des cartelis no puedin contignî il caratar “/”" ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Une cartele no pues jessi clamade “.”." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Une cartele no pues jessi clamade “..”." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Lis cartelis cul “.” al inizi dal lôr non a son platadis." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Un file o une cartele cul stes non e esist za." ++ ++#: prefs.js:102 +msgid "Size for the desktop icons" -+msgstr "Ukuran untuk ikon destop" ++msgstr "Dimension pes iconis dal scritori" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Small" -+msgstr "Kecil" ++msgstr "Piçule" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Standard" -+msgstr "Standar" ++msgstr "Standard" + -+#: prefs.js:89 ++#: prefs.js:102 +msgid "Large" -+msgstr "Besar" -+ -+#: prefs.js:89 -+msgid "Huge" -+msgstr "Sangat besar" ++msgstr "Largje" + -+#: prefs.js:90 ++#: prefs.js:103 +msgid "Show the personal folder in the desktop" -+msgstr "Tampilkan folder pribadi di destop" ++msgstr "Mostre la cartele personâl intal scritori" + -+#: prefs.js:91 ++#: prefs.js:104 +msgid "Show the trash icon in the desktop" -+msgstr "Tampilkan ikon tong sampah di destop" ++msgstr "Mostre la icone de scovacere intal scritori" + -+#: desktopGrid.js:178 desktopGrid.js:297 ++#: desktopGrid.js:320 +msgid "New Folder" -+msgstr "Folder Baru" ++msgstr "Gnove cartele" + -+#: desktopGrid.js:299 ++#: desktopGrid.js:322 +msgid "Paste" -+msgstr "Tempel" ++msgstr "Tache" + -+#: desktopGrid.js:300 ++#: desktopGrid.js:323 +msgid "Undo" -+msgstr "Tak Jadi" ++msgstr "Anule" + -+#: desktopGrid.js:301 ++#: desktopGrid.js:324 +msgid "Redo" -+msgstr "Jadi Lagi" ++msgstr "Torne fâ" + -+#: desktopGrid.js:303 -+msgid "Open Desktop in Files" -+msgstr "Buka Destop pada Berkas" ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Mostre Scritori in File" + -+#: desktopGrid.js:304 -+msgid "Open Terminal" -+msgstr "Buka Terminal" ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Vierç in Terminâl" + -+#: desktopGrid.js:306 ++#: desktopGrid.js:329 +msgid "Change Background…" -+msgstr "Ubah Latar Belakang…" ++msgstr "Cambie sfont…" + -+#: desktopGrid.js:307 ++#: desktopGrid.js:331 +msgid "Display Settings" -+msgstr "Pengaturan Tampilan" ++msgstr "Impostazions visôr" + -+#: desktopGrid.js:308 ++#: desktopGrid.js:332 +msgid "Settings" -+msgstr "Pengaturan" ++msgstr "Impostazions" + -+#: fileItem.js:226 ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Inserìs il non dal file…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "Va ben" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "No sta permeti inviament" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Permet inviament" ++ ++#: fileItem.js:574 +msgid "Open" -+msgstr "Buka" ++msgstr "Vierç" + -+#: fileItem.js:229 ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Vierç cuntune altre aplicazion" ++ ++#: fileItem.js:582 +msgid "Cut" -+msgstr "Potong" ++msgstr "Taie" + -+#: fileItem.js:230 ++#: fileItem.js:583 +msgid "Copy" -+msgstr "Salin" ++msgstr "Copie" + -+#: fileItem.js:231 ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Cambie non..." ++ ++#: fileItem.js:586 +msgid "Move to Trash" -+msgstr "Pindahkan ke Tong Sampah" ++msgstr "Sposte te scovacere" + -+#: fileItem.js:235 -+msgid "Empty trash" -+msgstr "Kosongkan Tong Sampah" ++#: fileItem.js:596 ++msgid "Empty Trash" ++msgstr "Disvuede scovacere" + -+#: fileItem.js:241 ++#: fileItem.js:602 +msgid "Properties" -+msgstr "Properti" ++msgstr "Propietâts" + -+#: fileItem.js:243 ++#: fileItem.js:604 +msgid "Show in Files" -+msgstr "Tampilkan pada Berkas" ++msgstr "Mostre in File" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 +msgid "Icon size" -+msgstr "Ukuran ikon" ++msgstr "Dimension icone" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 +msgid "Set the size for the desktop icons." -+msgstr "Set ukuran untuk ikon destop." ++msgstr "Stabilìs la dimension pes iconis dal scritori." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 +msgid "Show personal folder" -+msgstr "Tampilkan folder pribadi" ++msgstr "Mostre cartele personâl" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 +msgid "Show the personal folder in the desktop." -+msgstr "Tampilkan folder pribadi di destop." ++msgstr "Mostre la cartele personâl intal scritori." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 +msgid "Show trash icon" -+msgstr "Tampilkan ikon tong sampah" ++msgstr "Mostre la icone de scovacere" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 +msgid "Show the trash icon in the desktop." -+msgstr "Tampilkan ikon tong sampah di destop." -diff --git a/extensions/desktop-icons/po/it.po b/extensions/desktop-icons/po/it.po ++msgstr "Mostre la icone de scovacere intal scritori." +diff --git a/extensions/desktop-icons/po/hr.po b/extensions/desktop-icons/po/hr.po new file mode 100644 -index 0000000..38c0572 +index 0000000..0d26696 --- /dev/null -+++ b/extensions/desktop-icons/po/it.po -@@ -0,0 +1,152 @@ -+# SOME DESCRIPTIVE TITLE. -+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -+# This file is distributed under the same license as the PACKAGE package. -+# Massimo Branchini , 2018. ++++ b/extensions/desktop-icons/po/hr.po +@@ -0,0 +1,186 @@ ++# Croatian translation for gnome-shell-extension-desktop-icons ++# Copyright (c) 2019 Rosetta Contributors and Canonical Ltd 2019 ++# This file is distributed under the same license as the gnome-shell-extension-desktop-icons package. ++# FIRST AUTHOR , 2019. +# +msgid "" +msgstr "" -+"Project-Id-Version: desktop-icons master\n" -+"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" -+"icons/issues\n" -+"POT-Creation-Date: 2018-11-29 09:07+0000\n" -+"PO-Revision-Date: 2018-12-05 11:14+0100\n" -+"Last-Translator: Massimo Branchini \n" -+"Language-Team: Italian \n" -+"Language: it\n" ++"Project-Id-Version: gnome-shell-extension-desktop-icons\n" ++"Report-Msgid-Bugs-To: FULL NAME \n" ++"POT-Creation-Date: 2019-03-05 11:27+0000\n" ++"PO-Revision-Date: 2019-03-23 16:03+0000\n" ++"Last-Translator: gogo \n" ++"Language-Team: Croatian \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: Poedit 2.2\n" ++"X-Launchpad-Export-Date: 2019-03-27 09:36+0000\n" ++"X-Generator: Launchpad (build 18910)\n" + -+#: prefs.js:93 ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Novi naziv mape" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Stvori" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Odustani" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Naziv mape ne može sadržavati “/”." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Mapa se ne može nazvati “.”." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Mapa se ne može nazvati “..”." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Mape sa “.” na početku njihovih naziva su skrivene." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Već postoji datoteka ili mapa s tim nazivom." ++ ++#: prefs.js:102 +msgid "Size for the desktop icons" -+msgstr "Dimensione delle icone della scrivania" ++msgstr "Veličina ikona radne površine" + -+#: prefs.js:93 ++#: prefs.js:102 +msgid "Small" -+msgstr "Piccola" ++msgstr "Male" + -+#: prefs.js:93 ++#: prefs.js:102 +msgid "Standard" -+msgstr "Normale" ++msgstr "Standardne" + -+#: prefs.js:93 ++#: prefs.js:102 +msgid "Large" -+msgstr "Grande" ++msgstr "Velike" + -+#: prefs.js:93 -+msgid "Huge" -+msgstr "Enorme" -+ -+#: prefs.js:94 ++#: prefs.js:103 +msgid "Show the personal folder in the desktop" -+msgstr "Mostra la cartella personale sulla scrivania" ++msgstr "Prikaži osobnu mapu na radnoj površini" + -+#: prefs.js:95 ++#: prefs.js:104 +msgid "Show the trash icon in the desktop" -+msgstr "Mostra il cestino sulla scrivania" ++msgstr "Prikaži mapu smeća na radnoj površini" + -+#: desktopGrid.js:185 desktopGrid.js:304 ++#: desktopGrid.js:320 +msgid "New Folder" -+msgstr "Nuova cartella" ++msgstr "Nova mapa" + -+#: desktopGrid.js:306 ++#: desktopGrid.js:322 +msgid "Paste" -+msgstr "Incolla" ++msgstr "Zalijepi" + -+#: desktopGrid.js:307 ++#: desktopGrid.js:323 +msgid "Undo" -+msgstr "Annulla" ++msgstr "Poništi" + -+#: desktopGrid.js:308 ++#: desktopGrid.js:324 +msgid "Redo" -+msgstr "Ripeti" ++msgstr "Ponovi" + -+#: desktopGrid.js:310 -+msgid "Open Desktop in Files" -+msgstr "Apri la scrivania in File" ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Prikaži radnu površinu u Datotekama" + -+#: desktopGrid.js:311 -+msgid "Open Terminal" -+msgstr "Apri un terminale" ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Otvori u Terminalu" + -+#: desktopGrid.js:313 ++#: desktopGrid.js:329 +msgid "Change Background…" -+msgstr "Cambia lo sfondo…" ++msgstr "Promijeni pozadinu…" + -+#: desktopGrid.js:314 ++#: desktopGrid.js:331 +msgid "Display Settings" -+msgstr "Impostazioni dello schermo" ++msgstr "Postavke zaslona" + -+#: desktopGrid.js:315 ++#: desktopGrid.js:332 +msgid "Settings" -+msgstr "Impostazioni" ++msgstr "Postavke" + -+#: desktopGrid.js:569 ++#: desktopGrid.js:576 +msgid "Enter file name…" -+msgstr "Indicare un nome per il file…" ++msgstr "Upiši naziv datoteke…" + -+#: desktopGrid.js:573 -+msgid "Ok" -+msgstr "Ok" ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "U redu" + -+#: desktopGrid.js:579 -+msgid "Cancel" -+msgstr "Annulla" ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Ne dopuštaj pokretanje" + -+#: fileItem.js:393 ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Dopusti pokretanje" ++ ++#: fileItem.js:574 +msgid "Open" -+msgstr "Apri" ++msgstr "Otvori" + -+#: fileItem.js:396 ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Otvori s drugom aplikacijom" ++ ++#: fileItem.js:582 ++msgid "Cut" ++msgstr "Izreži" ++ ++#: fileItem.js:583 ++msgid "Copy" ++msgstr "Kopiraj" ++ ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Preimenuj…" ++ ++#: fileItem.js:586 ++msgid "Move to Trash" ++msgstr "Premjesti u smeće" ++ ++#: fileItem.js:596 ++msgid "Empty Trash" ++msgstr "Isprazni smeće" ++ ++#: fileItem.js:602 ++msgid "Properties" ++msgstr "Svojstva" ++ ++#: fileItem.js:604 ++msgid "Show in Files" ++msgstr "Prikaži u Datotekama" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 ++msgid "Icon size" ++msgstr "Veličina ikona" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++msgid "Set the size for the desktop icons." ++msgstr "Postavi veličinu ikona radne površine." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 ++msgid "Show personal folder" ++msgstr "Prikaži osobnu mapu" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++msgid "Show the personal folder in the desktop." ++msgstr "Prikaži osobnu mapu na radnoj površini." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 ++msgid "Show trash icon" ++msgstr "Prikaži ikonu smeća" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++msgid "Show the trash icon in the desktop." ++msgstr "Prikaži ikonu smeća na radnoj površini." +diff --git a/extensions/desktop-icons/po/hu.po b/extensions/desktop-icons/po/hu.po +new file mode 100644 +index 0000000..a350dd1 +--- /dev/null ++++ b/extensions/desktop-icons/po/hu.po +@@ -0,0 +1,190 @@ ++# Hungarian translation for desktop-icons. ++# Copyright (C) 2019 The Free Software Foundation, inc. ++# This file is distributed under the same license as the desktop-icons package. ++# ++# Balázs Úr , 2019. ++msgid "" ++msgstr "" ++"Project-Id-Version: desktop-icons master\n" ++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-i" ++"cons/issues\n" ++"POT-Creation-Date: 2019-03-01 12:11+0000\n" ++"PO-Revision-Date: 2019-03-07 23:45+0100\n" ++"Last-Translator: Balázs Úr \n" ++"Language-Team: Hungarian \n" ++"Language: hu\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" ++ ++#: createFolderDialog.js:48 ++#| msgid "New Folder" ++msgid "New folder name" ++msgstr "Új mappa neve" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Létrehozás" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Mégse" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "A mappanevek nem tartalmazhatnak „/” karaktert." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Egy mappának nem lehet „.” a neve." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Egy mappának nem lehet „..” a neve." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "A „.” karakterrel kezdődő nevű mappák rejtettek." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Már van egy fájl vagy mappa azzal a névvel." ++ ++#: prefs.js:102 ++msgid "Size for the desktop icons" ++msgstr "Az asztali ikonok mérete" ++ ++#: prefs.js:102 ++msgid "Small" ++msgstr "Kicsi" ++ ++#: prefs.js:102 ++msgid "Standard" ++msgstr "Szabványos" ++ ++#: prefs.js:102 ++msgid "Large" ++msgstr "Nagy" ++ ++#: prefs.js:103 ++msgid "Show the personal folder in the desktop" ++msgstr "A személyes mappa megjelenítése az asztalon" ++ ++#: prefs.js:104 ++msgid "Show the trash icon in the desktop" ++msgstr "A kuka ikon megjelenítése az asztalon" ++ ++#: desktopGrid.js:320 ++msgid "New Folder" ++msgstr "Új mappa" ++ ++#: desktopGrid.js:322 ++msgid "Paste" ++msgstr "Beillesztés" ++ ++#: desktopGrid.js:323 ++msgid "Undo" ++msgstr "Visszavonás" ++ ++#: desktopGrid.js:324 ++msgid "Redo" ++msgstr "Újra" ++ ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Asztal megjelenítése a Fájlokban" ++ ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Megnyitás terminálban" ++ ++#: desktopGrid.js:329 ++msgid "Change Background…" ++msgstr "Háttér megváltoztatása…" ++ ++#: desktopGrid.js:331 ++msgid "Display Settings" ++msgstr "Megjelenítés beállításai" ++ ++#: desktopGrid.js:332 ++msgid "Settings" ++msgstr "Beállítások" ++ ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Adjon meg egy fájlnevet…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "Rendben" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Ne engedélyezzen indítást" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Indítás engedélyezése" ++ ++#: fileItem.js:574 ++msgid "Open" ++msgstr "Megnyitás" ++ ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Megnyitás egyéb alkalmazással" ++ ++#: fileItem.js:582 ++msgid "Cut" ++msgstr "Kivágás" ++ ++#: fileItem.js:583 ++msgid "Copy" ++msgstr "Másolás" ++ ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Átnevezés…" ++ ++#: fileItem.js:586 ++msgid "Move to Trash" ++msgstr "Áthelyezés a Kukába" ++ ++#: fileItem.js:596 ++msgid "Empty Trash" ++msgstr "Kuka ürítése" ++ ++#: fileItem.js:602 ++msgid "Properties" ++msgstr "Tulajdonságok" ++ ++#: fileItem.js:604 ++msgid "Show in Files" ++msgstr "Megjelenítés a Fájlokban" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 ++msgid "Icon size" ++msgstr "Ikonméret" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++msgid "Set the size for the desktop icons." ++msgstr "Az asztali ikonok méretének beállítása." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 ++msgid "Show personal folder" ++msgstr "Személyes mappa megjelenítése" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++msgid "Show the personal folder in the desktop." ++msgstr "A személyes mappa megjelenítése az asztalon." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 ++msgid "Show trash icon" ++msgstr "Kuka ikon megjelenítése" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++msgid "Show the trash icon in the desktop." ++msgstr "A kuka ikon megjelenítése az asztalon." ++ +diff --git a/extensions/desktop-icons/po/id.po b/extensions/desktop-icons/po/id.po +new file mode 100644 +index 0000000..b809c3d +--- /dev/null ++++ b/extensions/desktop-icons/po/id.po +@@ -0,0 +1,190 @@ ++# Indonesian translation for desktop-icons. ++# Copyright (C) 2018 desktop-icons's COPYRIGHT HOLDER ++# This file is distributed under the same license as the desktop-icons package. ++# Kukuh Syafaat , 2018, 2019. ++# ++msgid "" ++msgstr "" ++"Project-Id-Version: desktop-icons master\n" ++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" ++"icons/issues\n" ++"POT-Creation-Date: 2019-03-01 12:11+0000\n" ++"PO-Revision-Date: 2019-03-02 19:13+0700\n" ++"Last-Translator: Kukuh Syafaat \n" ++"Language-Team: Indonesian \n" ++"Language: id\n" ++"MIME-Version: 1.0\n" ++"Content-Type: text/plain; charset=UTF-8\n" ++"Content-Transfer-Encoding: 8bit\n" ++"X-Generator: Poedit 2.2.1\n" ++ ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Nama folder baru" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Buat" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Batal" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Nama folder tak boleh memuat \"/\"." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Sebuah folder tak bisa dinamai \".\"." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Sebuah folder tak bisa dinamai \"..\"." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Folder dengan \".\" di awal nama mereka disembunyikan." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Folder dengan nama itu sudah ada." ++ ++#: prefs.js:102 ++msgid "Size for the desktop icons" ++msgstr "Ukuran untuk ikon destop" ++ ++#: prefs.js:102 ++msgid "Small" ++msgstr "Kecil" ++ ++#: prefs.js:102 ++msgid "Standard" ++msgstr "Standar" ++ ++#: prefs.js:102 ++msgid "Large" ++msgstr "Besar" ++ ++#: prefs.js:103 ++msgid "Show the personal folder in the desktop" ++msgstr "Tampilkan folder pribadi di destop" ++ ++#: prefs.js:104 ++msgid "Show the trash icon in the desktop" ++msgstr "Tampilkan ikon tong sampah di destop" ++ ++#: desktopGrid.js:320 ++msgid "New Folder" ++msgstr "Folder Baru" ++ ++#: desktopGrid.js:322 ++msgid "Paste" ++msgstr "Tempel" ++ ++#: desktopGrid.js:323 ++msgid "Undo" ++msgstr "Tak Jadi" ++ ++#: desktopGrid.js:324 ++msgid "Redo" ++msgstr "Jadi Lagi" ++ ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Tampilkan Destop pada Berkas" ++ ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Buka dalam Terminal" ++ ++#: desktopGrid.js:329 ++msgid "Change Background…" ++msgstr "Ubah Latar Belakang…" ++ ++#: desktopGrid.js:331 ++msgid "Display Settings" ++msgstr "Pengaturan Tampilan" ++ ++#: desktopGrid.js:332 ++msgid "Settings" ++msgstr "Pengaturan" ++ ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Masukkan nama berkas…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "OK" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Jangan Izinkan Peluncuran" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Izinkan Peluncuran" ++ ++#: fileItem.js:574 ++msgid "Open" ++msgstr "Buka" ++ ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Buka Dengan Aplikasi Lain" ++ ++#: fileItem.js:582 ++msgid "Cut" ++msgstr "Potong" ++ ++#: fileItem.js:583 ++msgid "Copy" ++msgstr "Salin" ++ ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Ganti Nama…" ++ ++#: fileItem.js:586 ++msgid "Move to Trash" ++msgstr "Pindahkan ke Tong Sampah" ++ ++#: fileItem.js:596 ++msgid "Empty Trash" ++msgstr "Kosongkan Tong Sampah" ++ ++#: fileItem.js:602 ++msgid "Properties" ++msgstr "Properti" ++ ++#: fileItem.js:604 ++msgid "Show in Files" ++msgstr "Tampilkan pada Berkas" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 ++msgid "Icon size" ++msgstr "Ukuran ikon" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++msgid "Set the size for the desktop icons." ++msgstr "Set ukuran untuk ikon destop." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 ++msgid "Show personal folder" ++msgstr "Tampilkan folder pribadi" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++msgid "Show the personal folder in the desktop." ++msgstr "Tampilkan folder pribadi di destop." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 ++msgid "Show trash icon" ++msgstr "Tampilkan ikon tong sampah" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++msgid "Show the trash icon in the desktop." ++msgstr "Tampilkan ikon tong sampah di destop." ++ ++#~ msgid "Huge" ++#~ msgstr "Sangat besar" +diff --git a/extensions/desktop-icons/po/it.po b/extensions/desktop-icons/po/it.po +new file mode 100644 +index 0000000..5001da4 +--- /dev/null ++++ b/extensions/desktop-icons/po/it.po +@@ -0,0 +1,189 @@ ++# Italian translation for desktop-icons. ++# Copyright (C) 2019 desktop-icons's COPYRIGHT HOLDER ++# This file is distributed under the same license as the desktop-icons package. ++# Massimo Branchini , 2019. ++# Milo Casagrande , 2019. ++# ++msgid "" ++msgstr "" ++"Project-Id-Version: desktop-icons master\n" ++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" ++"icons/issues\n" ++"POT-Creation-Date: 2019-03-01 12:11+0000\n" ++"PO-Revision-Date: 2019-03-12 09:51+0100\n" ++"Last-Translator: Milo Casagrande \n" ++"Language-Team: Italian \n" ++"Language: it\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: Poedit 2.2.1\n" ++ ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Nuova cartella" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Crea" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Annulla" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "I nomi di cartelle non possono contenere il carattere «/»" ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Una cartella non può essere chiamata «.»." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Una cartella non può essere chiamata «..»." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Cartelle il cui nome inizia con «.» sono nascoste." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Esiste già un file o una cartella con quel nome." ++ ++#: prefs.js:102 ++msgid "Size for the desktop icons" ++msgstr "Dimensione delle icone della scrivania" ++ ++#: prefs.js:102 ++msgid "Small" ++msgstr "Piccola" ++ ++#: prefs.js:102 ++msgid "Standard" ++msgstr "Normale" ++ ++#: prefs.js:102 ++msgid "Large" ++msgstr "Grande" ++ ++#: prefs.js:103 ++msgid "Show the personal folder in the desktop" ++msgstr "Mostra la cartella personale sulla scrivania" ++ ++#: prefs.js:104 ++msgid "Show the trash icon in the desktop" ++msgstr "Mostra il cestino sulla scrivania" ++ ++#: desktopGrid.js:320 ++msgid "New Folder" ++msgstr "Nuova cartella" ++ ++#: desktopGrid.js:322 ++msgid "Paste" ++msgstr "Incolla" ++ ++#: desktopGrid.js:323 ++msgid "Undo" ++msgstr "Annulla" ++ ++#: desktopGrid.js:324 ++msgid "Redo" ++msgstr "Ripeti" ++ ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Mostra la scrivania in File" ++ ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Apri in Terminale" ++ ++#: desktopGrid.js:329 ++msgid "Change Background…" ++msgstr "Cambia lo sfondo…" ++ ++#: desktopGrid.js:331 ++msgid "Display Settings" ++msgstr "Impostazioni dello schermo" ++ ++#: desktopGrid.js:332 ++msgid "Settings" ++msgstr "Impostazioni" ++ ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Indicare un nome per il file…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "Ok" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Non permettere l'esecuzione" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Permetti l'esecuzione" ++ ++#: fileItem.js:574 ++msgid "Open" ++msgstr "Apri" ++ ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Apri con altra applicazione" ++ ++#: fileItem.js:582 ++msgid "Cut" ++msgstr "Taglia" ++ ++#: fileItem.js:583 ++msgid "Copy" ++msgstr "Copia" ++ ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Rinomina…" ++ ++#: fileItem.js:586 ++msgid "Move to Trash" ++msgstr "Sposta nel cestino" ++ ++#: fileItem.js:596 ++msgid "Empty Trash" ++msgstr "Svuota il cestino" ++ ++#: fileItem.js:602 ++msgid "Properties" ++msgstr "Proprietà" ++ ++#: fileItem.js:604 ++msgid "Show in Files" ++msgstr "Mostra in File" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 ++msgid "Icon size" ++msgstr "Dimensione dell'icona" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++msgid "Set the size for the desktop icons." ++msgstr "Imposta la grandezza delle icone della scrivania." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 ++msgid "Show personal folder" ++msgstr "Mostra la cartella personale" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++msgid "Show the personal folder in the desktop." ++msgstr "Mostra la cartella personale sulla scrivania." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 ++msgid "Show trash icon" ++msgstr "Mostra il cestino" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++msgid "Show the trash icon in the desktop." ++msgstr "Mostra il cestino sulla scrivania." +diff --git a/extensions/desktop-icons/po/ja.po b/extensions/desktop-icons/po/ja.po +new file mode 100644 +index 0000000..3b103e0 +--- /dev/null ++++ b/extensions/desktop-icons/po/ja.po +@@ -0,0 +1,187 @@ ++# Japanese translation for desktop-icons. ++# Copyright (C) 2019 desktop-icons's COPYRIGHT HOLDER ++# This file is distributed under the same license as the desktop-icons package. ++# sicklylife , 2019. ++# ++msgid "" ++msgstr "" ++"Project-Id-Version: desktop-icons master\n" ++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" ++"icons/issues\n" ++"POT-Creation-Date: 2019-03-14 12:56+0000\n" ++"PO-Revision-Date: 2019-03-15 06:30+0000\n" ++"Last-Translator: sicklylife \n" ++"Language-Team: Japanese \n" ++"Language: ja\n" ++"MIME-Version: 1.0\n" ++"Content-Type: text/plain; charset=UTF-8\n" ++"Content-Transfer-Encoding: 8bit\n" ++"Plural-Forms: nplurals=1; plural=0;\n" ++ ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "新しいフォルダー名" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "作成" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "キャンセル" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "“/”は、フォルダー名に含められません。" ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "“.”という名前をフォルダーに付けられません。" ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "“..”という名前をフォルダーに付けられません。" ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "名前が“.”で始まるフォルダーは、隠しフォルダーになります。" ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "その名前のファイルかフォルダーがすでに存在します。" ++ ++#: prefs.js:102 ++msgid "Size for the desktop icons" ++msgstr "デスクトップアイコンのサイズ" ++ ++#: prefs.js:102 ++msgid "Small" ++msgstr "小さい" ++ ++#: prefs.js:102 ++msgid "Standard" ++msgstr "標準" ++ ++#: prefs.js:102 ++msgid "Large" ++msgstr "大きい" ++ ++#: prefs.js:103 ++msgid "Show the personal folder in the desktop" ++msgstr "デスクトップにホームフォルダーを表示する" ++ ++#: prefs.js:104 ++msgid "Show the trash icon in the desktop" ++msgstr "デスクトップにゴミ箱を表示する" ++ ++#: desktopGrid.js:320 ++msgid "New Folder" ++msgstr "新しいフォルダー" ++ ++#: desktopGrid.js:322 ++msgid "Paste" ++msgstr "貼り付け" ++ ++#: desktopGrid.js:323 ++msgid "Undo" ++msgstr "元に戻す" ++ ++#: desktopGrid.js:324 ++msgid "Redo" ++msgstr "やり直す" ++ ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "“ファイル”でデスクトップを表示する" ++ ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "端末を開く" ++ ++#: desktopGrid.js:329 ++msgid "Change Background…" ++msgstr "背景を変更する…" ++ ++#: desktopGrid.js:331 ++msgid "Display Settings" ++msgstr "ディスプレイの設定" ++ ++#: desktopGrid.js:332 ++msgid "Settings" ++msgstr "設定" ++ ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "ファイル名を入力してください…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "OK" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "起動を許可しない" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "起動を許可する" ++ ++#: fileItem.js:574 ++msgid "Open" ++msgstr "開く" ++ ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "別のアプリケーションで開く" ++ ++#: fileItem.js:582 +msgid "Cut" -+msgstr "Taglia" ++msgstr "切り取り" + -+#: fileItem.js:397 ++#: fileItem.js:583 +msgid "Copy" -+msgstr "Copia" ++msgstr "コピー" + -+#: fileItem.js:398 -+msgid "Rename" -+msgstr "Rinomina" ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "名前の変更…" + -+#: fileItem.js:399 ++#: fileItem.js:586 +msgid "Move to Trash" -+msgstr "Sposta nel cestino" ++msgstr "ゴミ箱へ移動する" + -+#: fileItem.js:403 ++#: fileItem.js:596 +msgid "Empty Trash" -+msgstr "Svuota il cestino" ++msgstr "ゴミ箱を空にする" + -+#: fileItem.js:409 ++#: fileItem.js:602 +msgid "Properties" -+msgstr "Proprietà" ++msgstr "プロパティ" + -+#: fileItem.js:411 ++#: fileItem.js:604 +msgid "Show in Files" -+msgstr "Mostra in File" ++msgstr "“ファイル”で表示する" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 +msgid "Icon size" -+msgstr "Dimensione dell'icona" ++msgstr "アイコンサイズ" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 +msgid "Set the size for the desktop icons." -+msgstr "Imposta la grandezza delle icone della scrivania." ++msgstr "デスクトップのアイコンサイズを設定します。" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 +msgid "Show personal folder" -+msgstr "Mostra la cartella personale" ++msgstr "ホームフォルダーを表示する" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 +msgid "Show the personal folder in the desktop." -+msgstr "Mostra la cartella personale sulla scrivania." ++msgstr "デスクトップにホームフォルダーを表示します。" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 +msgid "Show trash icon" -+msgstr "Mostra il cestino" ++msgstr "ゴミ箱アイコンを表示する" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 +msgid "Show the trash icon in the desktop." -+msgstr "Mostra il cestino sulla scrivania." ++msgstr "デスクトップにゴミ箱のアイコンを表示します。" diff --git a/extensions/desktop-icons/po/meson.build b/extensions/desktop-icons/po/meson.build new file mode 100644 index 0000000..b2e9e42 @@ -18515,12 +20291,206 @@ index 0000000..b2e9e42 +++ b/extensions/desktop-icons/po/meson.build @@ -0,0 +1 @@ +i18n.gettext (meson.project_name (), preset: 'glib') +diff --git a/extensions/desktop-icons/po/nl.po b/extensions/desktop-icons/po/nl.po +new file mode 100644 +index 0000000..b2f7dab +--- /dev/null ++++ b/extensions/desktop-icons/po/nl.po +@@ -0,0 +1,188 @@ ++# Dutch translation for desktop-icons. ++# Copyright (C) 2019 desktop-icons's COPYRIGHT HOLDER ++# This file is distributed under the same license as the desktop-icons package. ++# Nathan Follens , 2019. ++# ++msgid "" ++msgstr "" ++"Project-Id-Version: desktop-icons master\n" ++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" ++"icons/issues\n" ++"POT-Creation-Date: 2019-03-01 12:11+0000\n" ++"PO-Revision-Date: 2019-03-04 19:46+0100\n" ++"Last-Translator: Nathan Follens \n" ++"Language-Team: Dutch \n" ++"Language: nl\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: Poedit 2.2.1\n" ++ ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Nieuwe mapnaam" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Aanmaken" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Annuleren" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Mapnamen kunnen geen ‘/’ bevatten." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Een map kan niet ‘.’ worden genoemd." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Een map kan niet ‘..’ worden genoemd." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Mappen waarvan de naam begint met ‘.’ zijn verborgen." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Er bestaat al een bestand of map met die naam." ++ ++#: prefs.js:102 ++msgid "Size for the desktop icons" ++msgstr "Grootte van bureaubladpictogrammen" ++ ++#: prefs.js:102 ++msgid "Small" ++msgstr "Klein" ++ ++#: prefs.js:102 ++msgid "Standard" ++msgstr "Standaard" ++ ++#: prefs.js:102 ++msgid "Large" ++msgstr "Groot" ++ ++#: prefs.js:103 ++msgid "Show the personal folder in the desktop" ++msgstr "Toon de persoonlijke map op het bureaublad" ++ ++#: prefs.js:104 ++msgid "Show the trash icon in the desktop" ++msgstr "Toon het prullenbakpictogram op het bureaublad" ++ ++#: desktopGrid.js:320 ++msgid "New Folder" ++msgstr "Nieuwe map" ++ ++#: desktopGrid.js:322 ++msgid "Paste" ++msgstr "Plakken" ++ ++#: desktopGrid.js:323 ++msgid "Undo" ++msgstr "Ongedaan maken" ++ ++#: desktopGrid.js:324 ++msgid "Redo" ++msgstr "Opnieuw" ++ ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Bureaublad tonen in Bestanden" ++ ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Openen in terminalvenster" ++ ++#: desktopGrid.js:329 ++msgid "Change Background…" ++msgstr "Achtergrond aanpassen…" ++ ++#: desktopGrid.js:331 ++msgid "Display Settings" ++msgstr "Scherminstellingen" ++ ++#: desktopGrid.js:332 ++msgid "Settings" ++msgstr "Instellingen" ++ ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Voer bestandsnaam in…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "Oké" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Toepassingen starten niet toestaan" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Toepassingen starten toestaan" ++ ++#: fileItem.js:574 ++msgid "Open" ++msgstr "Openen" ++ ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Met andere toepassing openen" ++ ++#: fileItem.js:582 ++msgid "Cut" ++msgstr "Knippen" ++ ++#: fileItem.js:583 ++msgid "Copy" ++msgstr "Kopiëren" ++ ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Hernoemen…" ++ ++#: fileItem.js:586 ++msgid "Move to Trash" ++msgstr "Verplaatsen naar prullenbak" ++ ++#: fileItem.js:596 ++msgid "Empty Trash" ++msgstr "Prullenbak legen" ++ ++#: fileItem.js:602 ++msgid "Properties" ++msgstr "Eigenschappen" ++ ++#: fileItem.js:604 ++msgid "Show in Files" ++msgstr "Tonen in Bestanden" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 ++msgid "Icon size" ++msgstr "Pictogramgrootte" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++msgid "Set the size for the desktop icons." ++msgstr "Stel de grootte van de bureaubladpictogrammen in." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 ++msgid "Show personal folder" ++msgstr "Persoonlijke map tonen" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++msgid "Show the personal folder in the desktop." ++msgstr "Toon de persoonlijke map op het bureaublad." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 ++msgid "Show trash icon" ++msgstr "Prullenbakpictogram tonen" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++msgid "Show the trash icon in the desktop." ++msgstr "Toon het prullenbakpictogram op het bureaublad." diff --git a/extensions/desktop-icons/po/pl.po b/extensions/desktop-icons/po/pl.po new file mode 100644 -index 0000000..32ae8ef +index 0000000..f57b3be --- /dev/null +++ b/extensions/desktop-icons/po/pl.po -@@ -0,0 +1,157 @@ +@@ -0,0 +1,193 @@ +# Polish translation for desktop-icons. +# Copyright © 2018-2019 the desktop-icons authors. +# This file is distributed under the same license as the desktop-icons package. @@ -18532,8 +20502,8 @@ index 0000000..32ae8ef +"Project-Id-Version: desktop-icons\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" +"icons/issues\n" -+"POT-Creation-Date: 2019-01-15 10:59+0000\n" -+"PO-Revision-Date: 2019-01-15 20:57+0100\n" ++"POT-Creation-Date: 2019-04-29 14:11+0000\n" ++"PO-Revision-Date: 2019-05-01 13:03+0200\n" +"Last-Translator: Piotr Drąg \n" +"Language-Team: Polish \n" +"Language: pl\n" @@ -18543,6 +20513,38 @@ index 0000000..32ae8ef +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" + ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Nazwa nowego katalogu" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Utwórz" ++ ++#: createFolderDialog.js:74 desktopGrid.js:592 ++msgid "Cancel" ++msgstr "Anuluj" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Nazwy katalogów nie mogą zawierać znaku „/”." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Katalog nie może mieć nazwy „.”." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Katalog nie może mieć nazwy „..”." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Katalogi z „.” na początku nazwy są ukryte." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Plik lub katalog o tej nazwie już istnieje." ++ +#: prefs.js:102 +msgid "Size for the desktop icons" +msgstr "Rozmiar ikon na pulpicie" @@ -18567,91 +20569,95 @@ index 0000000..32ae8ef +msgid "Show the trash icon in the desktop" +msgstr "Kosz na pulpicie" + -+#: desktopGrid.js:187 desktopGrid.js:306 ++#: desktopGrid.js:323 +msgid "New Folder" +msgstr "Nowy katalog" + -+#: desktopGrid.js:308 ++#: desktopGrid.js:325 +msgid "Paste" +msgstr "Wklej" + -+#: desktopGrid.js:309 ++#: desktopGrid.js:326 +msgid "Undo" +msgstr "Cofnij" + -+#: desktopGrid.js:310 ++#: desktopGrid.js:327 +msgid "Redo" +msgstr "Ponów" + -+#: desktopGrid.js:312 ++#: desktopGrid.js:329 +msgid "Show Desktop in Files" +msgstr "Wyświetl pulpit w menedżerze plików" + -+#: desktopGrid.js:313 fileItem.js:586 ++#: desktopGrid.js:330 fileItem.js:610 +msgid "Open in Terminal" +msgstr "Otwórz w terminalu" + -+#: desktopGrid.js:315 ++#: desktopGrid.js:332 +msgid "Change Background…" +msgstr "Zmień tło…" + -+#: desktopGrid.js:317 ++#: desktopGrid.js:334 +msgid "Display Settings" +msgstr "Ustawienia ekranu" + -+#: desktopGrid.js:318 ++#: desktopGrid.js:335 +msgid "Settings" +msgstr "Ustawienia" + -+#: desktopGrid.js:559 ++#: desktopGrid.js:582 +msgid "Enter file name…" +msgstr "Nazwa pliku…" + -+#: desktopGrid.js:563 ++#: desktopGrid.js:586 +msgid "OK" +msgstr "OK" + -+#: desktopGrid.js:569 -+msgid "Cancel" -+msgstr "Anuluj" ++#: desktopIconsUtil.js:61 ++msgid "Command not found" ++msgstr "Nie odnaleziono polecenia" + -+#: fileItem.js:490 ++#: fileItem.js:494 +msgid "Don’t Allow Launching" +msgstr "Nie zezwalaj na uruchamianie" + -+#: fileItem.js:492 ++#: fileItem.js:496 +msgid "Allow Launching" +msgstr "Zezwól na uruchamianie" + -+#: fileItem.js:559 ++#: fileItem.js:578 +msgid "Open" +msgstr "Otwórz" + -+#: fileItem.js:562 ++#: fileItem.js:582 ++msgid "Open With Other Application" ++msgstr "Otwórz za pomocą innego programu" ++ ++#: fileItem.js:586 +msgid "Cut" +msgstr "Wytnij" + -+#: fileItem.js:563 ++#: fileItem.js:587 +msgid "Copy" +msgstr "Skopiuj" + -+#: fileItem.js:565 ++#: fileItem.js:589 +msgid "Rename…" +msgstr "Zmień nazwę…" + -+#: fileItem.js:566 ++#: fileItem.js:590 +msgid "Move to Trash" +msgstr "Przenieś do kosza" + -+#: fileItem.js:576 ++#: fileItem.js:600 +msgid "Empty Trash" +msgstr "Opróżnij kosz" + -+#: fileItem.js:582 ++#: fileItem.js:606 +msgid "Properties" +msgstr "Właściwości" + -+#: fileItem.js:584 ++#: fileItem.js:608 +msgid "Show in Files" +msgstr "Wyświetl w menedżerze plików" + @@ -18680,30 +20686,63 @@ index 0000000..32ae8ef +msgstr "Wyświetla kosz na pulpicie." diff --git a/extensions/desktop-icons/po/pt_BR.po b/extensions/desktop-icons/po/pt_BR.po new file mode 100644 -index 0000000..42162f2 +index 0000000..8d61c72 --- /dev/null +++ b/extensions/desktop-icons/po/pt_BR.po -@@ -0,0 +1,163 @@ +@@ -0,0 +1,199 @@ +# Brazilian Portuguese translation for desktop-icons. -+# Copyright (C) 2018 desktop-icons's COPYRIGHT HOLDER ++# Copyright (C) 2019 desktop-icons's COPYRIGHT HOLDER +# This file is distributed under the same license as the desktop-icons package. +# Enrico Nicoletto , 2018. -+# Rafael Fontenelle , 2018. ++# Rafael Fontenelle , 2018-2019. ++# +msgid "" +msgstr "" +"Project-Id-Version: desktop-icons master\n" -+"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/" -+"desktop-icons/issues\n" -+"POT-Creation-Date: 2018-12-14 09:12+0000\n" -+"PO-Revision-Date: 2018-12-17 01:01-0200\n" ++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" ++"icons/issues\n" ++"POT-Creation-Date: 2019-04-29 14:11+0000\n" ++"PO-Revision-Date: 2019-04-29 17:35-0300\n" +"Last-Translator: Rafael Fontenelle \n" +"Language-Team: Brazilian Portuguese \n" +"Language: pt_BR\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: Virtaal 1.0.0-beta1\n" ++"Plural-Forms: nplurals=2; plural=(n > 1)\n" ++"X-Generator: Gtranslator 3.32.0\n" ++ ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Nome da nova pasta" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Criar" ++ ++#: createFolderDialog.js:74 desktopGrid.js:592 ++msgid "Cancel" ++msgstr "Cancelar" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Nomes de pastas não podem conter “/”." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Uma pasta não pode ser chamada “.”." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Uma pasta não pode ser chamada “..”." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Pastas com “.” no começo de seus nomes são ocultas." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Já existe um arquivo ou uma pasta com esse nome." + +#: prefs.js:102 +msgid "Size for the desktop icons" @@ -18721,10 +20760,6 @@ index 0000000..42162f2 +msgid "Large" +msgstr "Grande" + -+#: prefs.js:102 -+msgid "Huge" -+msgstr "Enorme" -+ +#: prefs.js:103 +msgid "Show the personal folder in the desktop" +msgstr "Mostrar a pasta pessoal na área de trabalho" @@ -18733,118 +20768,125 @@ index 0000000..42162f2 +msgid "Show the trash icon in the desktop" +msgstr "Mostrar o ícone da lixeira na área de trabalho" + -+#: desktopGrid.js:182 desktopGrid.js:301 ++#: desktopGrid.js:323 +msgid "New Folder" +msgstr "Nova pasta" + -+#: desktopGrid.js:303 ++#: desktopGrid.js:325 +msgid "Paste" +msgstr "Colar" + -+#: desktopGrid.js:304 ++#: desktopGrid.js:326 +msgid "Undo" +msgstr "Desfazer" + -+#: desktopGrid.js:305 ++#: desktopGrid.js:327 +msgid "Redo" +msgstr "Refazer" + -+#: desktopGrid.js:307 -+msgid "Open Desktop in Files" -+msgstr "Abrir área de trabalho no Arquivos" ++#: desktopGrid.js:329 ++msgid "Show Desktop in Files" ++msgstr "Mostrar a área de trabalho no Arquivos" + -+#: desktopGrid.js:308 -+msgid "Open Terminal" -+msgstr "Abrir terminal" ++#: desktopGrid.js:330 fileItem.js:610 ++msgid "Open in Terminal" ++msgstr "Abrir no terminal" + -+#: desktopGrid.js:310 ++#: desktopGrid.js:332 +msgid "Change Background…" +msgstr "Alterar plano de fundo…" + -+#: desktopGrid.js:311 ++#: desktopGrid.js:334 +msgid "Display Settings" +msgstr "Configurações de exibição" + -+#: desktopGrid.js:312 ++#: desktopGrid.js:335 +msgid "Settings" +msgstr "Configurações" + -+#: desktopGrid.js:568 ++#: desktopGrid.js:582 +msgid "Enter file name…" +msgstr "Insira um nome de arquivo…" + -+#: desktopGrid.js:572 ++#: desktopGrid.js:586 +msgid "OK" +msgstr "OK" + -+#: desktopGrid.js:578 -+msgid "Cancel" -+msgstr "Cancelar" ++#: desktopIconsUtil.js:61 ++msgid "Command not found" ++msgstr "Comando não encontrado" + -+#: fileItem.js:485 ++#: fileItem.js:494 +msgid "Don’t Allow Launching" +msgstr "Não permitir iniciar" + -+#: fileItem.js:487 ++#: fileItem.js:496 +msgid "Allow Launching" +msgstr "Permitir iniciar" + -+#: fileItem.js:550 ++#: fileItem.js:578 +msgid "Open" +msgstr "Abrir" + -+#: fileItem.js:553 ++#: fileItem.js:582 ++msgid "Open With Other Application" ++msgstr "Abrir com outro aplicativo" ++ ++#: fileItem.js:586 +msgid "Cut" +msgstr "Recortar" + -+#: fileItem.js:554 ++#: fileItem.js:587 +msgid "Copy" +msgstr "Copiar" + -+#: fileItem.js:556 -+msgid "Rename" -+msgstr "Renomear" ++#: fileItem.js:589 ++msgid "Rename…" ++msgstr "Renomear…" + -+#: fileItem.js:557 ++#: fileItem.js:590 +msgid "Move to Trash" +msgstr "Mover para a lixeira" + -+#: fileItem.js:567 ++#: fileItem.js:600 +msgid "Empty Trash" +msgstr "Esvaziar lixeira" + -+#: fileItem.js:573 ++#: fileItem.js:606 +msgid "Properties" +msgstr "Propriedades" + -+#: fileItem.js:575 ++#: fileItem.js:608 +msgid "Show in Files" +msgstr "Mostrar no Arquivos" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 +msgid "Icon size" +msgstr "Tamanho do ícone" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 +msgid "Set the size for the desktop icons." +msgstr "Define o tamanho para os ícones da área de trabalho." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 +msgid "Show personal folder" +msgstr "Mostrar pasta pessoal" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 +msgid "Show the personal folder in the desktop." +msgstr "Mostra a pasta pessoal na área de trabalho." + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 +msgid "Show trash icon" +msgstr "Mostrar ícone da lixeira" + -+#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 +msgid "Show the trash icon in the desktop." +msgstr "Mostra o ícone da lixeira na área de trabalho." + ++#~ msgid "Huge" ++#~ msgstr "Enorme" ++ +#~ msgid "Ok" +#~ msgstr "Ok" diff --git a/extensions/desktop-icons/po/ru.po b/extensions/desktop-icons/po/ru.po @@ -19006,6 +21048,406 @@ index 0000000..4094f16 +#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 +msgid "Show the trash icon in the desktop." +msgstr "Показывать значок корзины на рабочем столе." +diff --git a/extensions/desktop-icons/po/sv.po b/extensions/desktop-icons/po/sv.po +new file mode 100644 +index 0000000..928cbe9 +--- /dev/null ++++ b/extensions/desktop-icons/po/sv.po +@@ -0,0 +1,197 @@ ++# Swedish translation for desktop-icons. ++# Copyright © 2018, 2019 desktop-icons's COPYRIGHT HOLDER ++# This file is distributed under the same license as the desktop-icons package. ++# Anders Jonsson , 2018, 2019. ++# Josef Andersson , 2019. ++# ++msgid "" ++msgstr "" ++"Project-Id-Version: desktop-icons master\n" ++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" ++"icons/issues\n" ++"POT-Creation-Date: 2019-03-01 12:11+0000\n" ++"PO-Revision-Date: 2019-03-11 21:50+0100\n" ++"Last-Translator: Anders Jonsson \n" ++"Language-Team: Swedish \n" ++"Language: sv\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: Poedit 2.2.1\n" ++ ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Nytt mappnamn" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Skapa" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "Avbryt" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Mappnamn kan inte innehålla ”/”." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "En mapp kan inte kallas ”.”." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "En mapp kan inte kallas ”..”." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Mappar med ”.” i början på sitt namn är dolda." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Det finns redan en fil eller mapp med det namnet" ++ ++#: prefs.js:102 ++msgid "Size for the desktop icons" ++msgstr "Storlek för skrivbordsikonerna" ++ ++#: prefs.js:102 ++msgid "Small" ++msgstr "Liten" ++ ++#: prefs.js:102 ++msgid "Standard" ++msgstr "Standard" ++ ++#: prefs.js:102 ++msgid "Large" ++msgstr "Stor" ++ ++# TODO: *ON* the desktop? ++#: prefs.js:103 ++msgid "Show the personal folder in the desktop" ++msgstr "Visa den personliga mappen på skrivbordet" ++ ++# TODO: *ON* the desktop? ++#: prefs.js:104 ++msgid "Show the trash icon in the desktop" ++msgstr "Visa papperskorgsikonen på skrivbordet" ++ ++#: desktopGrid.js:320 ++msgid "New Folder" ++msgstr "Ny mapp" ++ ++#: desktopGrid.js:322 ++msgid "Paste" ++msgstr "Klistra in" ++ ++#: desktopGrid.js:323 ++msgid "Undo" ++msgstr "Ångra" ++ ++#: desktopGrid.js:324 ++msgid "Redo" ++msgstr "Gör om" ++ ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Visa skrivbord i Filer" ++ ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Öppna i terminal" ++ ++#: desktopGrid.js:329 ++msgid "Change Background…" ++msgstr "Ändra bakgrund…" ++ ++#: desktopGrid.js:331 ++msgid "Display Settings" ++msgstr "Visningsinställningar" ++ ++#: desktopGrid.js:332 ++msgid "Settings" ++msgstr "Inställningar" ++ ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Ange filnamn…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "OK" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Tillåt ej programstart" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Tillåt programstart" ++ ++#: fileItem.js:574 ++msgid "Open" ++msgstr "Öppna" ++ ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Öppna med annat program" ++ ++#: fileItem.js:582 ++msgid "Cut" ++msgstr "Klipp ut" ++ ++#: fileItem.js:583 ++msgid "Copy" ++msgstr "Kopiera" ++ ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Byt namn…" ++ ++#: fileItem.js:586 ++msgid "Move to Trash" ++msgstr "Flytta till papperskorgen" ++ ++#: fileItem.js:596 ++msgid "Empty Trash" ++msgstr "Töm papperskorgen" ++ ++#: fileItem.js:602 ++msgid "Properties" ++msgstr "Egenskaper" ++ ++#: fileItem.js:604 ++msgid "Show in Files" ++msgstr "Visa i Filer" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 ++msgid "Icon size" ++msgstr "Ikonstorlek" ++ ++# TODO: *ON* the desktop? ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++msgid "Set the size for the desktop icons." ++msgstr "Ställ in storleken för skrivbordsikonerna." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 ++msgid "Show personal folder" ++msgstr "Visa personlig mapp" ++ ++# TODO: *ON* the desktop? ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++msgid "Show the personal folder in the desktop." ++msgstr "Visa den personliga mappen på skrivbordet." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 ++msgid "Show trash icon" ++msgstr "Visa papperskorgsikon" ++ ++# TODO: *ON* the desktop? ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++msgid "Show the trash icon in the desktop." ++msgstr "Visa papperskorgsikonen på skrivbordet." ++ ++#~ msgid "Huge" ++#~ msgstr "Enorm" +diff --git a/extensions/desktop-icons/po/tr.po b/extensions/desktop-icons/po/tr.po +new file mode 100644 +index 0000000..2e5f5a7 +--- /dev/null ++++ b/extensions/desktop-icons/po/tr.po +@@ -0,0 +1,191 @@ ++# Turkish translation for desktop-icons. ++# Copyright (C) 2000-2019 desktop-icons's COPYRIGHT HOLDER ++# This file is distributed under the same license as the desktop-icons package. ++# ++# Sabri Ünal , 2019. ++# Serdar Sağlam , 2019 ++# Emin Tufan Çetin , 2019. ++# ++msgid "" ++msgstr "" ++"Project-Id-Version: \n" ++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-" ++"icons/issues\n" ++"POT-Creation-Date: 2019-03-09 14:47+0000\n" ++"PO-Revision-Date: 2019-03-13 13:43+0300\n" ++"Last-Translator: Emin Tufan Çetin \n" ++"Language-Team: Türkçe \n" ++"Language: tr\n" ++"MIME-Version: 1.0\n" ++"Content-Type: text/plain; charset=UTF-8\n" ++"Content-Transfer-Encoding: 8bit\n" ++"X-Generator: Gtranslator 3.30.1\n" ++"Plural-Forms: nplurals=1; plural=0;\n" ++ ++#: createFolderDialog.js:48 ++msgid "New folder name" ++msgstr "Yeni klasör adı" ++ ++#: createFolderDialog.js:72 ++msgid "Create" ++msgstr "Oluştur" ++ ++#: createFolderDialog.js:74 desktopGrid.js:586 ++msgid "Cancel" ++msgstr "İptal" ++ ++#: createFolderDialog.js:145 ++msgid "Folder names cannot contain “/”." ++msgstr "Klasör adları “/” içeremez." ++ ++#: createFolderDialog.js:148 ++msgid "A folder cannot be called “.”." ++msgstr "Bir klasör “.” olarak adlandırılamaz." ++ ++#: createFolderDialog.js:151 ++msgid "A folder cannot be called “..”." ++msgstr "Bir klasör “..” olarak adlandırılamaz." ++ ++#: createFolderDialog.js:153 ++msgid "Folders with “.” at the beginning of their name are hidden." ++msgstr "Adlarının başında “.” bulunan klasörler gizlenir." ++ ++#: createFolderDialog.js:155 ++msgid "There is already a file or folder with that name." ++msgstr "Zaten bu adda bir dosya veya klasör var." ++ ++#: prefs.js:102 ++msgid "Size for the desktop icons" ++msgstr "Masaüstü simgeleri boyutu" ++ ++#: prefs.js:102 ++msgid "Small" ++msgstr "Küçük" ++ ++#: prefs.js:102 ++msgid "Standard" ++msgstr "Standart" ++ ++#: prefs.js:102 ++msgid "Large" ++msgstr "Büyük" ++ ++#: prefs.js:103 ++msgid "Show the personal folder in the desktop" ++msgstr "Kişisel klasörü masaüstünde göster" ++ ++#: prefs.js:104 ++msgid "Show the trash icon in the desktop" ++msgstr "Çöp kutusunu masaüstünde göster" ++ ++#: desktopGrid.js:320 ++msgid "New Folder" ++msgstr "Yeni Klasör" ++ ++#: desktopGrid.js:322 ++msgid "Paste" ++msgstr "Yapıştır" ++ ++#: desktopGrid.js:323 ++msgid "Undo" ++msgstr "Geri Al" ++ ++#: desktopGrid.js:324 ++msgid "Redo" ++msgstr "Yinele" ++ ++#: desktopGrid.js:326 ++msgid "Show Desktop in Files" ++msgstr "Masaüstünü Dosyalarʼda Göster" ++ ++#: desktopGrid.js:327 fileItem.js:606 ++msgid "Open in Terminal" ++msgstr "Uçbirimde Aç" ++ ++#: desktopGrid.js:329 ++msgid "Change Background…" ++msgstr "Arka Planı Değiştir…" ++ ++#: desktopGrid.js:331 ++msgid "Display Settings" ++msgstr "Görüntü Ayarları" ++ ++#: desktopGrid.js:332 ++msgid "Settings" ++msgstr "Ayarlar" ++ ++#: desktopGrid.js:576 ++msgid "Enter file name…" ++msgstr "Dosya adını gir…" ++ ++#: desktopGrid.js:580 ++msgid "OK" ++msgstr "Tamam" ++ ++#: fileItem.js:490 ++msgid "Don’t Allow Launching" ++msgstr "Başlatmaya İzin Verme" ++ ++#: fileItem.js:492 ++msgid "Allow Launching" ++msgstr "Başlatmaya İzin Ver" ++ ++#: fileItem.js:574 ++msgid "Open" ++msgstr "Aç" ++ ++#: fileItem.js:578 ++msgid "Open With Other Application" ++msgstr "Başka Uygulamayla Aç" ++ ++#: fileItem.js:582 ++msgid "Cut" ++msgstr "Kes" ++ ++#: fileItem.js:583 ++msgid "Copy" ++msgstr "Kopyala" ++ ++#: fileItem.js:585 ++msgid "Rename…" ++msgstr "Yeniden Adlandır…" ++ ++#: fileItem.js:586 ++msgid "Move to Trash" ++msgstr "Çöpe Taşı" ++ ++#: fileItem.js:596 ++msgid "Empty Trash" ++msgstr "Çöpü Boşalt" ++ ++#: fileItem.js:602 ++msgid "Properties" ++msgstr "Özellikler" ++ ++#: fileItem.js:604 ++msgid "Show in Files" ++msgstr "Dosyalarʼda Göster" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11 ++msgid "Icon size" ++msgstr "Simge boyutu" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12 ++msgid "Set the size for the desktop icons." ++msgstr "Masaüstü simgelerinin boyutunu ayarla." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16 ++msgid "Show personal folder" ++msgstr "Kişisel klasörü göster" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17 ++msgid "Show the personal folder in the desktop." ++msgstr "Kişisel klasörü masaüstünde göster." ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21 ++msgid "Show trash icon" ++msgstr "Çöp kutusunu göster" ++ ++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22 ++msgid "Show the trash icon in the desktop." ++msgstr "Çöp kutusu simgesini masaüstünde göster." diff --git a/extensions/desktop-icons/po/zh_TW.po b/extensions/desktop-icons/po/zh_TW.po new file mode 100644 index 0000000..8ce4ab9 @@ -19149,7 +21591,7 @@ index 0000000..8ce4ab9 +msgstr "在桌面顯示垃圾桶圖示。" diff --git a/extensions/desktop-icons/prefs.js b/extensions/desktop-icons/prefs.js new file mode 100644 -index 0000000..0a5b1ce +index 0000000..4b8d986 --- /dev/null +++ b/extensions/desktop-icons/prefs.js @@ -0,0 +1,159 @@ @@ -19251,7 +21693,7 @@ index 0000000..0a5b1ce +} + +function buildPrefsWidget() { -+ ++ initTranslations(); + let frame = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, border_width: 10, spacing: 10 }); + + frame.add(buildSelector('icon-size', _("Size for the desktop icons"), { 'small': _("Small"), 'standard': _("Standard"), 'large': _("Large") })); @@ -19357,10 +21799,10 @@ index 0000000..bb4e50f + diff --git a/extensions/desktop-icons/stylesheet.css b/extensions/desktop-icons/stylesheet.css new file mode 100644 -index 0000000..82209d7 +index 0000000..17d4b32 --- /dev/null +++ b/extensions/desktop-icons/stylesheet.css -@@ -0,0 +1,33 @@ +@@ -0,0 +1,38 @@ +.file-item { + padding: 4px; + border: 1px; @@ -19371,15 +21813,6 @@ index 0000000..82209d7 + background-color: rgba(238, 238, 238, 0.2); +} + -+.file-item:selected { -+ background-color: rgba(74, 144, 217, 0.6); -+ border-color: rgba(74, 144, 217, 0.8); -+} -+ -+.rubber-band { -+ background-color: rgba(74, 144, 238, 0.4); -+} -+ +.name-label { + text-shadow: 1px 1px black; + color: white; @@ -19394,13 +21827,27 @@ index 0000000..82209d7 + min-width: 300px; + margin: 6px; +} ++ ++.create-folder-dialog-entry { ++ width: 20em; ++ margin-bottom: 6px; ++} ++ ++.create-folder-dialog-label { ++ padding-bottom: .4em; ++} ++ ++.create-folder-dialog-error-box { ++ padding-top: 16px; ++ spacing: 6px; ++} diff --git a/meson.build b/meson.build -index 201c484..99a4738 100644 +index cf855a0..6e8c41f 100644 --- a/meson.build +++ b/meson.build -@@ -36,6 +36,7 @@ uuid_suffix = '@gnome-shell-extensions.gcampax.github.com' +@@ -33,6 +33,7 @@ uuid_suffix = '@gnome-shell-extensions.gcampax.github.com' + classic_extensions = [ - 'alternate-tab', 'apps-menu', + 'desktop-icons', 'places-menu', @@ -20463,17 +22910,18 @@ index e036448..73b33cc 100644 #~ msgstr "Asettaa telakan kuvakkeiden koon." diff --git a/po/fr.po b/po/fr.po -index 2b01d33..3f9826f 100644 +index 6825d0d..a61cc76 100644 --- a/po/fr.po +++ b/po/fr.po -@@ -1,11 +1,30 @@ +@@ -1,3 +1,5 @@ +# #-#-#-#-# fr.po (gnome-shell-extensions master) #-#-#-#-# +# #-#-#-#-# fr.po (gnome-shell-extensions master) #-#-#-#-# # French translation for gnome-shell-extensions. # Copyright (C) 2011-12 Listed translators # This file is distributed under the same license as the gnome-shell-extensions package. - # Claude Paroz , 2011. +@@ -5,8 +7,25 @@ # Alain Lojewski , 2012-2013. + # Charles Monzat , 2018. # +# #-#-#-#-# fr.po (desktop-icons master) #-#-#-#-# +# French translation for desktop-icons. @@ -20495,9 +22943,9 @@ index 2b01d33..3f9826f 100644 +"#-#-#-#-# fr.po (gnome-shell-extensions master) #-#-#-#-#\n" +"#-#-#-#-# fr.po (gnome-shell-extensions master) #-#-#-#-#\n" "Project-Id-Version: gnome-shell-extensions master\n" - "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-" - "shell&keywords=I18N+L10N&component=extensions\n" -@@ -18,6 +37,34 @@ msgstr "" + "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/" + "issues\n" +@@ -19,6 +38,33 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" @@ -20528,14 +22976,13 @@ index 2b01d33..3f9826f 100644 +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" -+"X-Generator: Gtranslator 3.30.0\n" + "X-Generator: Gtranslator 3.30.0\n" #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3 - msgid "GNOME Classic" -@@ -362,8 +409,151 @@ msgstr "Nom" - msgid "Workspace %d" - msgstr "Espace de travail %d" - +@@ -354,9 +400,151 @@ msgstr "Espace de travail %d" + #~ msgstr "" + #~ "Retarder les changements de focus en mode souris jusqu’à ce que le " + #~ "pointeur arrête de bouger" +#: prefs.js:102 +msgid "Size for the desktop icons" +msgstr "Taille des icônes du bureau" @@ -20675,7 +23122,7 @@ index 2b01d33..3f9826f 100644 +#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23 +msgid "Show the trash icon in the desktop." +msgstr "Montrer la corbeille sur le bureau." -+ + #~ msgid "CPU" #~ msgstr "CPU" @@ -21959,5 +24406,5 @@ index 74a95f8..8a675aa 100644 #~ msgstr "Dock 的位置" -- -2.20.1 +2.21.0 diff --git a/SOURCES/more-classic-classic-mode.patch b/SOURCES/more-classic-classic-mode.patch new file mode 100644 index 0000000..5f0d85b --- /dev/null +++ b/SOURCES/more-classic-classic-mode.patch @@ -0,0 +1,3270 @@ +From e8425ac158bda015b09861bab4224ca2fdd2b50f Mon Sep 17 00:00:00 2001 +From: Jakub Steiner +Date: Mon, 15 Jul 2019 23:40:09 +0200 +Subject: [PATCH 01/30] classic: hover state for panel buttons + +- prelight before active +- lighten up slightly, similar to what the default does (inverted) + +Fixes https://gitlab.gnome.org/GNOME/gnome-shell-extensions/issues/169 +--- + data/gnome-classic.scss | 14 ++++++++------ + 1 file changed, 8 insertions(+), 6 deletions(-) + +diff --git a/data/gnome-classic.scss b/data/gnome-classic.scss +index 9e23506..9c0e06e 100644 +--- a/data/gnome-classic.scss ++++ b/data/gnome-classic.scss +@@ -32,18 +32,20 @@ $variant: 'light'; + font-weight: normal; + color: $fg_color; + text-shadow: none; ++ &:hover { ++ color: lighten($fg_color,10%); ++ text-shadow: none; ++ & .system-status-icon { icon-shadow: none; } ++ } + &:active, &:overview, &:focus, &:checked { + // Trick due to St limitations. It needs a background to draw + // a box-shadow +- background-color: $selected_bg_color !important; +- color: $selected_fg_color !important; ++ background-color: $selected_bg_color; ++ color: $selected_fg_color; + box-shadow: none; + & > .system-status-icon { icon-shadow: none; } + } +- &:hover { +- text-shadow: none; +- & .system-status-icon { icon-shadow: none; } +- } ++ + .app-menu-icon { width: 0; height: 0; margin: 0; } // shell's display:none; :D + + .system-status-icon { +-- +2.21.0 + + +From fcbb1b1d8956d7447973a9d5ffaa4fede8d359ee Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 18 Jul 2019 00:39:49 +0200 +Subject: [PATCH 02/30] apps-menu: Add drop-shadow to application icons + +... to make sure they are readable on light backgrounds. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/issues/168 +--- + extensions/apps-menu/extension.js | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js +index cc399c6..1f95c16 100644 +--- a/extensions/apps-menu/extension.js ++++ b/extensions/apps-menu/extension.js +@@ -103,7 +103,9 @@ class ApplicationMenuItem extends PopupMenu.PopupBaseMenuItem { + } + + _updateIcon() { +- this._iconBin.set_child(this.getDragActor()); ++ let icon = this.getDragActor(); ++ icon.style_class = 'icon-dropshadow'; ++ this._iconBin.set_child(icon); + } + } + +-- +2.21.0 + + +From 904e632c62aab6cd89a849a01c56b7c0f123eee8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 29 May 2019 10:17:20 +0000 +Subject: [PATCH 03/30] places-menu: Don't hardcode position + +The extension currently assumes that we have the "Activities" button +at the left of the top bar. This is currently true, not only in the +regular session, but also in GNOME classic where the button is hidden +(but still present). + +However this is about to change: We will stop taking over the button +from the apps-menu extension, and instead disable "Activities" from +the session mode definition. + +Prepare for this by adding the places menu before the application menu +instead of assuming a hardcoded position. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/69 +--- + extensions/places-menu/extension.js | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/extensions/places-menu/extension.js b/extensions/places-menu/extension.js +index c477a4a..5c038ae 100644 +--- a/extensions/places-menu/extension.js ++++ b/extensions/places-menu/extension.js +@@ -135,9 +135,9 @@ let _indicator; + function enable() { + _indicator = new PlacesMenu; + +- let pos = 1; ++ let pos = Main.sessionMode.panel.left.indexOf('appMenu'); + if ('apps-menu' in Main.panel.statusArea) +- pos = 2; ++ pos++; + Main.panel.addToStatusArea('places-menu', _indicator, pos, 'left'); + } + +-- +2.21.0 + + +From 2b1eb285d0c0e113a9be2bd801e1692b48fcfd78 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 29 May 2019 08:32:03 +0000 +Subject: [PATCH 04/30] apps-menu: Stop taking over Activities button + +We don't want the "Activities" button in GNOME Classic, but the current +way of handling it is confusing: + + - the button is hidden, but the corresponding hot corner + sometimes works (when the application menu isn't open) + + - the button is effectively moved inside the menu, although + it's clearly not an app or category + + - the apps-menu can be used independent from classic mode, in + which case removing the "Activities" button may not be wanted + +Address those points by removing any handling of the activities button +from the apps-menu extension. We will remove it again from the classic +session via a session mode tweak. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/69 +--- + extensions/apps-menu/extension.js | 67 +++---------------------------- + 1 file changed, 6 insertions(+), 61 deletions(-) + +diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js +index 1f95c16..865a87e 100644 +--- a/extensions/apps-menu/extension.js ++++ b/extensions/apps-menu/extension.js +@@ -25,22 +25,6 @@ const NAVIGATION_REGION_OVERSHOOT = 50; + Gio._promisify(Gio._LocalFilePrototype, 'query_info_async', 'query_info_finish'); + Gio._promisify(Gio._LocalFilePrototype, 'set_attributes_async', 'set_attributes_finish'); + +-class ActivitiesMenuItem extends PopupMenu.PopupBaseMenuItem { +- constructor(button) { +- super(); +- this._button = button; +- let label = new St.Label({ text: _('Activities Overview') }); +- this.actor.add_child(label); +- this.actor.label_actor = label; +- } +- +- activate(event) { +- this._button.menu.toggle(); +- Main.overview.toggle(); +- super.activate(event); +- } +-} +- + class ApplicationMenuItem extends PopupMenu.PopupBaseMenuItem { + constructor(button, app) { + super(); +@@ -235,21 +219,6 @@ class ApplicationsMenu extends PopupMenu.PopupMenu { + return false; + } + +- open(animate) { +- this._button.hotCorner.setBarrierSize(0); +- if (this._button.hotCorner.actor) // fallback corner +- this._button.hotCorner.actor.hide(); +- super.open(animate); +- } +- +- close(animate) { +- let size = Main.layoutManager.panelBox.height; +- this._button.hotCorner.setBarrierSize(size); +- if (this._button.hotCorner.actor) // fallback corner +- this._button.hotCorner.actor.show(); +- super.close(animate); +- } +- + toggle() { + if (this.isOpen) { + this._button.selectCategory(null); +@@ -383,7 +352,7 @@ Signals.addSignalMethods(DesktopTarget.prototype); + + let ApplicationsButton = GObject.registerClass( + class ApplicationsButton extends PanelMenu.Button { +- _init() { ++ _init(includeIcon) { + super._init(1.0, null, false); + + this.setMenu(new ApplicationsMenu(this, 1.0, St.Side.TOP, this)); +@@ -400,7 +369,8 @@ class ApplicationsButton extends PanelMenu.Button { + '/usr/share/icons/hicolor/scalable/apps/start-here.svg'); + this._icon = new St.Icon({ + gicon: new Gio.FileIcon({ file: iconFile }), +- style_class: 'panel-logo-icon' ++ style_class: 'panel-logo-icon', ++ visible: includeIcon + }); + hbox.add_actor(this._icon); + +@@ -416,8 +386,6 @@ class ApplicationsButton extends PanelMenu.Button { + this.name = 'panelApplications'; + this.label_actor = this._label; + +- this.connect('captured-event', this._onCapturedEvent.bind(this)); +- + this._showingId = Main.overview.connect('showing', () => { + this.add_accessible_state (Atk.StateType.CHECKED); + }); +@@ -459,10 +427,6 @@ class ApplicationsButton extends PanelMenu.Button { + } + } + +- get hotCorner() { +- return Main.layoutManager.hotCorners[Main.layoutManager.primaryIndex]; +- } +- + _createVertSeparator() { + let separator = new St.DrawingArea({ + style_class: 'calendar-vertical-separator', +@@ -489,14 +453,6 @@ class ApplicationsButton extends PanelMenu.Button { + this._desktopTarget.destroy(); + } + +- _onCapturedEvent(actor, event) { +- if (event.type() == Clutter.EventType.BUTTON_PRESS) { +- if (!Main.overview.shouldToggleByCornerOrButton()) +- return true; +- } +- return false; +- } +- + _onMenuKeyPress(actor, event) { + let symbol = event.get_key_symbol(); + if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) { +@@ -640,14 +596,6 @@ class ApplicationsButton extends PanelMenu.Button { + y_align: St.Align.START + }); + +- let activities = new ActivitiesMenuItem(this); +- this.leftBox.add(activities.actor, { +- expand: false, +- x_fill: true, +- y_fill: false, +- y_align: St.Align.START +- }); +- + this.applicationsBox = new St.BoxLayout({ vertical: true }); + this.applicationsScrollBox.add_actor(this.applicationsBox); + this.categoriesBox = new St.BoxLayout({ vertical: true }); +@@ -759,19 +707,16 @@ class ApplicationsButton extends PanelMenu.Button { + }); + + let appsMenuButton; +-let activitiesButton; + + function enable() { +- activitiesButton = Main.panel.statusArea['activities']; +- activitiesButton.container.hide(); +- appsMenuButton = new ApplicationsButton(); +- Main.panel.addToStatusArea('apps-menu', appsMenuButton, 1, 'left'); ++ let index = Main.sessionMode.panel.left.indexOf('activities') + 1; ++ appsMenuButton = new ApplicationsButton(index == 0); ++ Main.panel.addToStatusArea('apps-menu', appsMenuButton, index, 'left'); + } + + function disable() { + Main.panel.menuManager.removeMenu(appsMenuButton.menu); + appsMenuButton.destroy(); +- activitiesButton.container.show(); + } + + function init() { +-- +2.21.0 + + +From 45b5f9b8f73032a87017131d8f29b429a8b75ef1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 7 Jun 2019 14:30:16 +0000 +Subject: [PATCH 05/30] apps-menu: Stop hiding the overview when toggled + +Now that the extension no longer doubles as the "Activities" button, +that behavior is confusing. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/69 +--- + extensions/apps-menu/extension.js | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js +index 865a87e..1e2882b 100644 +--- a/extensions/apps-menu/extension.js ++++ b/extensions/apps-menu/extension.js +@@ -220,12 +220,8 @@ class ApplicationsMenu extends PopupMenu.PopupMenu { + } + + toggle() { +- if (this.isOpen) { ++ if (this.isOpen) + this._button.selectCategory(null); +- } else { +- if (Main.overview.visible) +- Main.overview.hide(); +- } + super.toggle(); + } + } +-- +2.21.0 + + +From 0f143dc87bd501a44843aad7d0a1cd0d20ad4d31 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 7 Jun 2019 20:07:19 +0000 +Subject: [PATCH 06/30] apps-menu: Hide overview when launching app + +Now that we no longer hide the overview when the menu is opened, +it is possible to activate menu entries from the overview. Start +hiding the overview in that case, which is consistent with app +launching elsewhere. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/69 +--- + extensions/apps-menu/extension.js | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js +index 1e2882b..3dbe43f 100644 +--- a/extensions/apps-menu/extension.js ++++ b/extensions/apps-menu/extension.js +@@ -66,6 +66,8 @@ class ApplicationMenuItem extends PopupMenu.PopupBaseMenuItem { + this._button.selectCategory(null); + this._button.menu.toggle(); + super.activate(event); ++ ++ Main.overview.hide(); + } + + setActive(active, params) { +-- +2.21.0 + + +From 72f956cc589d9789ae6ad7b99c1dfd60f9a9f8e3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 29 May 2019 09:44:30 +0000 +Subject: [PATCH 07/30] classic: Disable overview + +The overview is one of the defining features of GNOME 3, and thus +almost by definition at odds with the classic session, which +emulates a traditional GNOME 2 desktop. + +Even with the less prominent placement inside the application menu +it never quite fit in - it doesn't help that besides the different +UI paradigma, the overview keeps its "normal" styling which differs +greatly with classic's normal mode. + +So besides removing the "Activities" button via the session mode +definition, now that the apps-menu extension doesn't replace it anymore, +disable the overview completely in the classic session. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/69 +--- + data/classic.json.in | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/data/classic.json.in b/data/classic.json.in +index fdb3762..c1c0544 100644 +--- a/data/classic.json.in ++++ b/data/classic.json.in +@@ -1,8 +1,9 @@ + { + "parentMode": "user", + "stylesheetName": "gnome-classic.css", ++ "hasOverview": false, + "enabledExtensions": [@CLASSIC_EXTENSIONS@], +- "panel": { "left": ["activities", "appMenu"], ++ "panel": { "left": ["appMenu"], + "center": [], + "right": ["a11y", "keyboard", "dateMenu", "aggregateMenu"] + } +-- +2.21.0 + + +From 6277f55210a2f1a3283b3eaad7ae1f2cf2f48d8b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 14 May 2019 19:51:22 +0200 +Subject: [PATCH 08/30] window-list: Add window picker button +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With the latest changes, GNOME Classic has become so classic that it +is bordering dull. Salvage at least a tiny piece of GNOME 3 in form +of a window-pick button which toggles an exposé-like reduced overview. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/73 +--- + extensions/window-list/classic.css | 20 +- + extensions/window-list/extension.js | 36 +++- + extensions/window-list/meson.build | 2 +- + extensions/window-list/stylesheet.css | 27 ++- + extensions/window-list/windowPicker.js | 260 +++++++++++++++++++++++++ + 5 files changed, 332 insertions(+), 13 deletions(-) + create mode 100644 extensions/window-list/windowPicker.js + +diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css +index f3c44a3..c506bea 100644 +--- a/extensions/window-list/classic.css ++++ b/extensions/window-list/classic.css +@@ -6,14 +6,13 @@ + height: 2.25em ; + } + +- .bottom-panel .window-button > StWidget { ++ .bottom-panel .window-button > StWidget, ++ .bottom-panel .window-picker-toggle > StWidget { + background-gradient-drection: vertical; + background-color: #fff; + background-gradient-start: #fff; + background-gradient-end: #eee; + color: #000; +- -st-natural-width: 18.7em; +- max-width: 18.75em; + color: #2e3436; + background-color: #eee; + border-radius: 2px; +@@ -22,7 +21,17 @@ + text-shadow: 0 0 transparent; + } + +- .bottom-panel .window-button:hover > StWidget { ++ .bottom-panel .window-button > StWidget { ++ -st-natural-width: 18.7em; ++ max-width: 18.75em; ++ } ++ ++ .bottom-panel .window-picker-toggle > StWidet { ++ border: 1px solid rgba(0,0,0,0.3); ++ } ++ ++ .bottom-panel .window-button:hover > StWidget, ++ .bottom-panel .window-picker-toggle:hover > StWidget { + background-color: #f9f9f9; + } + +@@ -31,7 +40,8 @@ + box-shadow: inset 1px 1px 2px rgba(0,0,0,0.5); + } + +- .bottom-panel .window-button.focused > StWidget { ++ .bottom-panel .window-button.focused > StWidget, ++ .bottom-panel .window-picker-toggle:checked > StWidget { + background-color: #ddd; + box-shadow: inset 1px 1px 1px rgba(0,0,0,0.5); + } +diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js +index e1ea742..b2784b4 100644 +--- a/extensions/window-list/extension.js ++++ b/extensions/window-list/extension.js +@@ -3,11 +3,14 @@ const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St } = imports.gi; + + const DND = imports.ui.dnd; + const Main = imports.ui.main; ++const Overview = imports.ui.overview; + const PanelMenu = imports.ui.panelMenu; + const PopupMenu = imports.ui.popupMenu; ++const Tweener = imports.ui.tweener; + + const ExtensionUtils = imports.misc.extensionUtils; + const Me = ExtensionUtils.getCurrentExtension(); ++const { WindowPicker, WindowPickerToggle } = Me.imports.windowPicker; + + const Gettext = imports.gettext.domain('gnome-shell-extensions'); + const _ = Gettext.gettext; +@@ -787,6 +790,12 @@ class WindowList { + let box = new St.BoxLayout({ x_expand: true, y_expand: true }); + this.actor.add_actor(box); + ++ let toggle = new WindowPickerToggle(); ++ box.add_actor(toggle); ++ ++ toggle.connect('notify::checked', ++ this._updateWindowListVisibility.bind(this)); ++ + let layout = new Clutter.BoxLayout({ homogeneous: true }); + this._windowList = new St.Widget({ + style_class: 'window-list', +@@ -936,6 +945,19 @@ class WindowList { + this._workspaceIndicator.actor.visible = hasWorkspaces && workspacesOnMonitor; + } + ++ _updateWindowListVisibility() { ++ let visible = !Main.windowPicker.visible; ++ ++ Tweener.addTween(this._windowList, { ++ opacity: visible ? 255 : 0, ++ transition: 'ease-out-quad', ++ time: Overview.ANIMATION_TIME ++ }); ++ ++ this._windowList.reactive = visible; ++ this._windowList.get_children().forEach(c => c.reactive = visible); ++ } ++ + _getPreferredUngroupedWindowListWidth() { + if (this._windowList.get_n_children() == 0) + return this._windowList.get_preferred_width(-1)[1]; +@@ -1206,7 +1228,7 @@ class WindowList { + class Extension { + constructor() { + this._windowLists = null; +- this._injections = {}; ++ this._hideOverviewOrig = Main.overview.hide; + } + + enable() { +@@ -1221,6 +1243,13 @@ class Extension { + Main.layoutManager.connect('monitors-changed', + this._buildWindowLists.bind(this)); + ++ Main.windowPicker = new WindowPicker(); ++ ++ Main.overview.hide = () => { ++ Main.windowPicker.close(); ++ this._hideOverviewOrig.call(Main.overview); ++ }; ++ + this._buildWindowLists(); + } + +@@ -1251,6 +1280,11 @@ class Extension { + windowList.actor.destroy(); + }); + this._windowLists = null; ++ ++ Main.windowPicker.actor.destroy(); ++ delete Main.windowPicker; ++ ++ Main.overview.hide = this._hideOverviewOrig; + } + + someWindowListContains(actor) { +diff --git a/extensions/window-list/meson.build b/extensions/window-list/meson.build +index b4aa4db..5b1f5f5 100644 +--- a/extensions/window-list/meson.build ++++ b/extensions/window-list/meson.build +@@ -4,7 +4,7 @@ extension_data += configure_file( + configuration: metadata_conf + ) + +-extension_sources += files('prefs.js') ++extension_sources += files('prefs.js', 'windowPicker.js') + extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml') + + if classic_mode_enabled +diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css +index f5285cb..91383ab 100644 +--- a/extensions/window-list/stylesheet.css ++++ b/extensions/window-list/stylesheet.css +@@ -26,9 +26,8 @@ + spacing: 4px; + } + +-.window-button > StWidget { +- -st-natural-width: 18.75em; +- max-width: 18.75em; ++.window-button > StWidget, ++.window-picker-toggle > StWidget { + color: #bbb; + background-color: black; + border-radius: 4px; +@@ -37,7 +36,21 @@ + text-shadow: 1px 1px 4px rgba(0,0,0,0.8); + } + +-.window-button:hover > StWidget { ++.window-picker-toggle { ++ padding: 3px; ++} ++ ++.window-picker-toggle > StWidet { ++ border: 1px solid rgba(255,255,255,0.3); ++} ++ ++.window-button > StWidget { ++ -st-natural-width: 18.75em; ++ max-width: 18.75em; ++} ++ ++.window-button:hover > StWidget, ++.window-picker-toggle:hover > StWidget { + color: white; + background-color: #1f1f1f; + } +@@ -47,12 +60,14 @@ + box-shadow: inset 2px 2px 4px rgba(255,255,255,0.5); + } + +-.window-button.focused > StWidget { ++.window-button.focused > StWidget, ++.window-picker-toggle:checked > StWidget { + color: white; + box-shadow: inset 1px 1px 4px rgba(255,255,255,0.7); + } + +-.window-button.focused:active > StWidget { ++.window-button.focused:active > StWidget, ++.window-picker-toggle:checked:active > StWidget { + box-shadow: inset 2px 2px 4px rgba(255,255,255,0.7); + } + +diff --git a/extensions/window-list/windowPicker.js b/extensions/window-list/windowPicker.js +new file mode 100644 +index 0000000..024fd80 +--- /dev/null ++++ b/extensions/window-list/windowPicker.js +@@ -0,0 +1,260 @@ ++/* exported WindowPicker, WindowPickerToggle */ ++const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi; ++const Signals = imports.signals; ++ ++const Layout = imports.ui.layout; ++const Main = imports.ui.main; ++const Overview = imports.ui.overview; ++const { WorkspacesDisplay } = imports.ui.workspacesView; ++ ++let MyWorkspacesDisplay = class extends WorkspacesDisplay { ++ constructor() { ++ super(); ++ ++ this.actor.add_constraint( ++ new Layout.MonitorConstraint({ ++ primary: true, ++ work_area: true ++ })); ++ ++ this.actor.connect('destroy', this._onDestroy.bind(this)); ++ ++ this._workareasChangedId = global.display.connect('workareas-changed', ++ this._onWorkAreasChanged.bind(this)); ++ this._onWorkAreasChanged(); ++ } ++ ++ show(...args) { ++ if (this._scrollEventId == 0) ++ this._scrollEventId = Main.windowPicker.connect('scroll-event', ++ this._onScrollEvent.bind(this)); ++ ++ super.show(...args); ++ } ++ ++ hide(...args) { ++ if (this._scrollEventId > 0) ++ Main.windowPicker.disconnect(this._scrollEventId); ++ this._scrollEventId = 0; ++ ++ super.hide(...args); ++ } ++ ++ _onWorkAreasChanged() { ++ let { primaryIndex } = Main.layoutManager; ++ let workarea = Main.layoutManager.getWorkAreaForMonitor(primaryIndex); ++ this.setWorkspacesFullGeometry(workarea); ++ } ++ ++ _updateWorkspacesViews() { ++ super._updateWorkspacesViews(); ++ ++ this._workspacesViews.forEach(v => { ++ Main.layoutManager.overviewGroup.remove_actor(v.actor); ++ Main.windowPicker.actor.add_actor(v.actor); ++ }); ++ } ++ ++ _onDestroy() { ++ if (this._workareasChangedId) ++ global.display.disconnect(this._workareasChangedId); ++ this._workareasChangedId = 0; ++ } ++}; ++ ++var WindowPicker = class { ++ constructor() { ++ this._visible = false; ++ this._modal = false; ++ ++ this.actor = new Clutter.Actor(); ++ ++ this.actor.connect('destroy', this._onDestroy.bind(this)); ++ ++ global.bind_property('screen-width', ++ this.actor, 'width', ++ GObject.BindingFlags.SYNC_CREATE); ++ global.bind_property('screen-height', ++ this.actor, 'height', ++ GObject.BindingFlags.SYNC_CREATE); ++ ++ this._backgroundGroup = new Meta.BackgroundGroup({ reactive: true }); ++ this.actor.add_child(this._backgroundGroup); ++ ++ this._backgroundGroup.connect('scroll-event', (a, ev) => { ++ this.emit('scroll-event', ev); ++ }); ++ ++ // Trick WorkspacesDisplay constructor into adding actions here ++ let addActionOrig = Main.overview.addAction; ++ Main.overview.addAction = a => this._backgroundGroup.add_action(a); ++ ++ this._workspacesDisplay = new MyWorkspacesDisplay(); ++ this.actor.add_child(this._workspacesDisplay.actor); ++ ++ Main.overview.addAction = addActionOrig; ++ ++ this._bgManagers = []; ++ ++ this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', ++ this._updateBackgrounds.bind(this)); ++ this._updateBackgrounds(); ++ ++ Main.uiGroup.insert_child_below(this.actor, global.window_group); ++ } ++ ++ get visible() { ++ return this._visible; ++ } ++ ++ open() { ++ if (this._visible) ++ return; ++ ++ this._visible = true; ++ ++ if (!this._syncGrab()) ++ return; ++ ++ this._fakeOverviewVisible(true); ++ this._shadeBackgrounds(); ++ this._fakeOverviewAnimation(); ++ this._workspacesDisplay.show(false); ++ ++ this.emit('open-state-changed', this._visible); ++ } ++ ++ close() { ++ if (!this._visible) ++ return; ++ ++ this._visible = false; ++ ++ if (!this._syncGrab()) ++ return; ++ ++ this._workspacesDisplay.animateFromOverview(false); ++ this._unshadeBackgrounds(); ++ this._fakeOverviewAnimation(() => { ++ this._workspacesDisplay.hide(); ++ this._fakeOverviewVisible(false); ++ }); ++ ++ this.emit('open-state-changed', this._visible); ++ } ++ ++ _fakeOverviewAnimation(onComplete) { ++ Main.overview.animationInProgress = true; ++ GLib.timeout_add( ++ GLib.PRIORITY_DEFAULT, ++ Overview.ANIMATION_TIME * 1000, ++ () => { ++ Main.overview.animationInProgress = false; ++ if (onComplete) ++ onComplete(); ++ }); ++ } ++ ++ _fakeOverviewVisible(visible) { ++ // Fake overview state for WorkspacesDisplay ++ Main.overview.visible = visible; ++ ++ // Hide real windows ++ Main.layoutManager._inOverview = visible; ++ Main.layoutManager._updateVisibility(); ++ } ++ ++ _syncGrab() { ++ if (this._visible) { ++ if (this._modal) ++ return true; ++ ++ this._modal = Main.pushModal(this.actor, { ++ actionMode: Shell.ActionMode.OVERVIEW ++ }); ++ ++ if (!this._modal) { ++ this.hide(); ++ return false; ++ } ++ } else if (this._modal) { ++ Main.popModal(this.actor); ++ this._modal = false; ++ } ++ return true; ++ } ++ ++ _onDestroy() { ++ if (this._monitorsChangedId) ++ Main.layoutManager.disconnect(this._monitorsChangedId); ++ this._monitorsChangedId = 0; ++ } ++ ++ _updateBackgrounds() { ++ Main.overview._updateBackgrounds.call(this); ++ } ++ ++ _shadeBackgrounds() { ++ Main.overview._shadeBackgrounds.call(this); ++ } ++ ++ _unshadeBackgrounds() { ++ Main.overview._unshadeBackgrounds.call(this); ++ } ++}; ++Signals.addSignalMethods(WindowPicker.prototype); ++ ++var WindowPickerToggle = GObject.registerClass( ++class WindowPickerToggle extends St.Button { ++ _init() { ++ let iconBin = new St.Widget({ ++ layout_manager: new Clutter.BinLayout() ++ }); ++ iconBin.add_child(new St.Icon({ ++ icon_name: 'focus-windows-symbolic', ++ icon_size: 16, ++ x_expand: true, ++ y_expand: true, ++ x_align: Clutter.ActorAlign.CENTER, ++ y_align: Clutter.ActorAlign.CENTER ++ })); ++ super._init({ ++ style_class: 'window-picker-toggle', ++ child: iconBin, ++ visible: !Main.sessionMode.hasOverview, ++ x_fill: true, ++ y_fill: true, ++ toggle_mode: true ++ }); ++ ++ this._overlayKeyId = 0; ++ ++ this.connect('destroy', this._onDestroy.bind(this)); ++ ++ this.connect('notify::checked', () => { ++ if (this.checked) ++ Main.windowPicker.open(); ++ else ++ Main.windowPicker.close(); ++ }); ++ ++ if (!Main.sessionMode.hasOverview) { ++ this._overlayKeyId = global.display.connect('overlay-key', () => { ++ if (!Main.windowPicker.visible) ++ Main.windowPicker.open(); ++ else ++ Main.windowPicker.close(); ++ }); ++ } ++ ++ Main.windowPicker.connect('open-state-changed', () => { ++ this.checked = Main.windowPicker.visible; ++ }); ++ } ++ ++ _onDestroy() { ++ if (this._overlayKeyId) ++ global.display.disconnect(this._overlayKeyId); ++ this._overlayKeyId == 0; ++ } ++}); +-- +2.21.0 + + +From 5d82db41ac53a1c7462e1ee69b155588b3e321fc Mon Sep 17 00:00:00 2001 +From: Jakub Steiner +Date: Mon, 15 Jul 2019 23:03:41 +0200 +Subject: [PATCH 09/30] classic: Update window-list styling + +Make buttons flatter, rounder to match default styling. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/82 +--- + extensions/window-list/classic.css | 25 +++++++++---------------- + 1 file changed, 9 insertions(+), 16 deletions(-) + +diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css +index c506bea..cc967e0 100644 +--- a/extensions/window-list/classic.css ++++ b/extensions/window-list/classic.css +@@ -4,21 +4,18 @@ + border-top-width: 1px; + border-bottom-width: 0px; + height: 2.25em ; ++ padding: 2px; + } + + .bottom-panel .window-button > StWidget, + .bottom-panel .window-picker-toggle > StWidget { +- background-gradient-drection: vertical; +- background-color: #fff; +- background-gradient-start: #fff; +- background-gradient-end: #eee; +- color: #000; + color: #2e3436; + background-color: #eee; +- border-radius: 2px; ++ border-radius: 3px; + padding: 3px 6px 1px; +- box-shadow: inset -1px -1px 1px rgba(0,0,0,0.5); +- text-shadow: 0 0 transparent; ++ box-shadow: none; ++ text-shadow: none; ++ border: 1px solid rgba(0,0,0,0.2); + } + + .bottom-panel .window-button > StWidget { +@@ -26,10 +23,6 @@ + max-width: 18.75em; + } + +- .bottom-panel .window-picker-toggle > StWidet { +- border: 1px solid rgba(0,0,0,0.3); +- } +- + .bottom-panel .window-button:hover > StWidget, + .bottom-panel .window-picker-toggle:hover > StWidget { + background-color: #f9f9f9; +@@ -37,13 +30,13 @@ + + .bottom-panel .window-button:active > StWidget, + .bottom-panel .window-button:focus > StWidget { +- box-shadow: inset 1px 1px 2px rgba(0,0,0,0.5); ++ box-shadow: inset 0 1px 3px rgba(0,0,0,0.1); + } + + .bottom-panel .window-button.focused > StWidget, + .bottom-panel .window-picker-toggle:checked > StWidget { +- background-color: #ddd; +- box-shadow: inset 1px 1px 1px rgba(0,0,0,0.5); ++ background-color: #ccc; ++ box-shadow: inset 0 1px 3px rgba(0,0,0,0.1); + } + + .bottom-panel .window-button.focused:hover > StWidget { +@@ -52,5 +45,5 @@ + + .bottom-panel .window-button.minimized > StWidget { + color: #888; +- box-shadow: inset -1px -1px 1px rgba(0,0,0,0.5); ++ box-shadow: none; + } +-- +2.21.0 + + +From 479a8907063970fb6f7e08cea9a2cd6f2e518b84 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 5 Jun 2019 00:23:13 +0000 +Subject: [PATCH 10/30] window-list: Split out workspaceIndicator + +The extension has grown unwieldily big, so before starting to improve +on the workspace indicator, move it to its own source file. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/70 +--- + extensions/window-list/extension.js | 130 +----------------- + extensions/window-list/meson.build | 2 +- + extensions/window-list/workspaceIndicator.js | 135 +++++++++++++++++++ + 3 files changed, 138 insertions(+), 129 deletions(-) + create mode 100644 extensions/window-list/workspaceIndicator.js + +diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js +index b2784b4..1f854aa 100644 +--- a/extensions/window-list/extension.js ++++ b/extensions/window-list/extension.js +@@ -1,16 +1,16 @@ + /* exported init */ +-const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell, St } = imports.gi; ++const { Clutter, Gio, GLib, Gtk, Meta, Shell, St } = imports.gi; + + const DND = imports.ui.dnd; + const Main = imports.ui.main; + const Overview = imports.ui.overview; +-const PanelMenu = imports.ui.panelMenu; + const PopupMenu = imports.ui.popupMenu; + const Tweener = imports.ui.tweener; + + const ExtensionUtils = imports.misc.extensionUtils; + const Me = ExtensionUtils.getCurrentExtension(); + const { WindowPicker, WindowPickerToggle } = Me.imports.windowPicker; ++const { WorkspaceIndicator } = Me.imports.workspaceIndicator; + + const Gettext = imports.gettext.domain('gnome-shell-extensions'); + const _ = Gettext.gettext; +@@ -647,132 +647,6 @@ class AppButton extends BaseButton { + } + + +-let WorkspaceIndicator = GObject.registerClass( +-class WorkspaceIndicator extends PanelMenu.Button { +- _init() { +- super._init(0.0, _('Workspace Indicator'), true); +- this.setMenu(new PopupMenu.PopupMenu(this, 0.0, St.Side.BOTTOM)); +- this.add_style_class_name('window-list-workspace-indicator'); +- this.menu.actor.remove_style_class_name('panel-menu'); +- +- let container = new St.Widget({ +- layout_manager: new Clutter.BinLayout(), +- x_expand: true, +- y_expand: true +- }); +- this.add_actor(container); +- +- let workspaceManager = global.workspace_manager; +- +- this._currentWorkspace = workspaceManager.get_active_workspace().index(); +- this.statusLabel = new St.Label({ +- text: this._getStatusText(), +- x_align: Clutter.ActorAlign.CENTER, +- y_align: Clutter.ActorAlign.CENTER +- }); +- container.add_actor(this.statusLabel); +- +- this.workspacesItems = []; +- +- this._workspaceManagerSignals = []; +- this._workspaceManagerSignals.push(workspaceManager.connect('notify::n-workspaces', +- this._updateMenu.bind(this))); +- this._workspaceManagerSignals.push(workspaceManager.connect_after('workspace-switched', +- this._updateIndicator.bind(this))); +- +- this.connect('scroll-event', this._onScrollEvent.bind(this)); +- this._updateMenu(); +- +- this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' }); +- this._settingsChangedId = +- this._settings.connect('changed::workspace-names', +- this._updateMenu.bind(this)); +- } +- +- _onDestroy() { +- for (let i = 0; i < this._workspaceManagerSignals.length; i++) +- global.workspace_manager.disconnect(this._workspaceManagerSignals[i]); +- +- if (this._settingsChangedId) { +- this._settings.disconnect(this._settingsChangedId); +- this._settingsChangedId = 0; +- } +- +- super._onDestroy(); +- } +- +- _updateIndicator() { +- this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); +- this._currentWorkspace = global.workspace_manager.get_active_workspace().index(); +- this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); +- +- this.statusLabel.set_text(this._getStatusText()); +- } +- +- _getStatusText() { +- let workspaceManager = global.workspace_manager; +- let current = workspaceManager.get_active_workspace().index(); +- let total = workspaceManager.n_workspaces; +- +- return '%d / %d'.format(current + 1, total); +- } +- +- _updateMenu() { +- let workspaceManager = global.workspace_manager; +- +- this.menu.removeAll(); +- this.workspacesItems = []; +- this._currentWorkspace = workspaceManager.get_active_workspace().index(); +- +- for (let i = 0; i < workspaceManager.n_workspaces; i++) { +- let name = Meta.prefs_get_workspace_name(i); +- let item = new PopupMenu.PopupMenuItem(name); +- item.workspaceId = i; +- +- item.connect('activate', (item, _event) => { +- this._activate(item.workspaceId); +- }); +- +- if (i == this._currentWorkspace) +- item.setOrnament(PopupMenu.Ornament.DOT); +- +- this.menu.addMenuItem(item); +- this.workspacesItems[i] = item; +- } +- +- this.statusLabel.set_text(this._getStatusText()); +- } +- +- _activate(index) { +- let workspaceManager = global.workspace_manager; +- +- if (index >= 0 && index < workspaceManager.n_workspaces) { +- let metaWorkspace = workspaceManager.get_workspace_by_index(index); +- metaWorkspace.activate(global.get_current_time()); +- } +- } +- +- _onScrollEvent(actor, event) { +- let direction = event.get_scroll_direction(); +- let diff = 0; +- if (direction == Clutter.ScrollDirection.DOWN) { +- diff = 1; +- } else if (direction == Clutter.ScrollDirection.UP) { +- diff = -1; +- } else { +- return; +- } +- +- let newIndex = this._currentWorkspace + diff; +- this._activate(newIndex); +- } +- +- _allocate(actor, box, flags) { +- if (actor.get_n_children() > 0) +- actor.get_first_child().allocate(box, flags); +- } +-}); +- + class WindowList { + constructor(perMonitor, monitor) { + this._perMonitor = perMonitor; +diff --git a/extensions/window-list/meson.build b/extensions/window-list/meson.build +index 5b1f5f5..34d7c3f 100644 +--- a/extensions/window-list/meson.build ++++ b/extensions/window-list/meson.build +@@ -4,7 +4,7 @@ extension_data += configure_file( + configuration: metadata_conf + ) + +-extension_sources += files('prefs.js', 'windowPicker.js') ++extension_sources += files('prefs.js', 'windowPicker.js', 'workspaceIndicator.js') + extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml') + + if classic_mode_enabled +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +new file mode 100644 +index 0000000..fb3ffe7 +--- /dev/null ++++ b/extensions/window-list/workspaceIndicator.js +@@ -0,0 +1,135 @@ ++/* exported WorkspaceIndicator */ ++const { Clutter, Gio, GObject, Meta, St } = imports.gi; ++ ++const PanelMenu = imports.ui.panelMenu; ++const PopupMenu = imports.ui.popupMenu; ++ ++const Gettext = imports.gettext.domain('gnome-shell-extensions'); ++const _ = Gettext.gettext; ++ ++var WorkspaceIndicator = GObject.registerClass( ++class WorkspaceIndicator extends PanelMenu.Button { ++ _init() { ++ super._init(0.0, _('Workspace Indicator'), true); ++ this.setMenu(new PopupMenu.PopupMenu(this, 0.0, St.Side.BOTTOM)); ++ this.add_style_class_name('window-list-workspace-indicator'); ++ this.menu.actor.remove_style_class_name('panel-menu'); ++ ++ let container = new St.Widget({ ++ layout_manager: new Clutter.BinLayout(), ++ x_expand: true, ++ y_expand: true ++ }); ++ this.add_actor(container); ++ ++ let workspaceManager = global.workspace_manager; ++ ++ this._currentWorkspace = workspaceManager.get_active_workspace().index(); ++ this.statusLabel = new St.Label({ ++ text: this._getStatusText(), ++ x_align: Clutter.ActorAlign.CENTER, ++ y_align: Clutter.ActorAlign.CENTER ++ }); ++ container.add_actor(this.statusLabel); ++ ++ this.workspacesItems = []; ++ ++ this._workspaceManagerSignals = [ ++ workspaceManager.connect('notify::n-workspaces', ++ this._updateMenu.bind(this)), ++ workspaceManager.connect_after('workspace-switched', ++ this._updateIndicator.bind(this)) ++ ]; ++ ++ this.connect('scroll-event', this._onScrollEvent.bind(this)); ++ this._updateMenu(); ++ ++ this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' }); ++ this._settingsChangedId = this._settings.connect( ++ 'changed::workspace-names', this._updateMenu.bind(this)); ++ } ++ ++ _onDestroy() { ++ for (let i = 0; i < this._workspaceManagerSignals.length; i++) ++ global.workspace_manager.disconnect(this._workspaceManagerSignals[i]); ++ ++ if (this._settingsChangedId) { ++ this._settings.disconnect(this._settingsChangedId); ++ this._settingsChangedId = 0; ++ } ++ ++ super._onDestroy(); ++ } ++ ++ _updateIndicator() { ++ this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); ++ this._currentWorkspace = global.workspace_manager.get_active_workspace().index(); ++ this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); ++ ++ this.statusLabel.set_text(this._getStatusText()); ++ } ++ ++ _getStatusText() { ++ let workspaceManager = global.workspace_manager; ++ let current = workspaceManager.get_active_workspace().index(); ++ let total = workspaceManager.n_workspaces; ++ ++ return '%d / %d'.format(current + 1, total); ++ } ++ ++ _updateMenu() { ++ let workspaceManager = global.workspace_manager; ++ ++ this.menu.removeAll(); ++ this.workspacesItems = []; ++ this._currentWorkspace = workspaceManager.get_active_workspace().index(); ++ ++ for (let i = 0; i < workspaceManager.n_workspaces; i++) { ++ let name = Meta.prefs_get_workspace_name(i); ++ let item = new PopupMenu.PopupMenuItem(name); ++ item.workspaceId = i; ++ ++ item.connect('activate', (item, _event) => { ++ this._activate(item.workspaceId); ++ }); ++ ++ if (i == this._currentWorkspace) ++ item.setOrnament(PopupMenu.Ornament.DOT); ++ ++ this.menu.addMenuItem(item); ++ this.workspacesItems[i] = item; ++ } ++ ++ this.statusLabel.set_text(this._getStatusText()); ++ } ++ ++ _activate(index) { ++ let workspaceManager = global.workspace_manager; ++ ++ if (index >= 0 && index < workspaceManager.n_workspaces) { ++ let metaWorkspace = workspaceManager.get_workspace_by_index(index); ++ metaWorkspace.activate(global.get_current_time()); ++ } ++ } ++ ++ _onScrollEvent(actor, event) { ++ let direction = event.get_scroll_direction(); ++ let diff = 0; ++ if (direction == Clutter.ScrollDirection.DOWN) { ++ diff = 1; ++ } else if (direction == Clutter.ScrollDirection.UP) { ++ diff = -1; ++ } else { ++ return; ++ } ++ ++ let newIndex = this._currentWorkspace + diff; ++ this._activate(newIndex); ++ } ++ ++ _allocate(actor, box, flags) { ++ if (actor.get_n_children() > 0) ++ actor.get_first_child().allocate(box, flags); ++ } ++}); ++ +-- +2.21.0 + + +From 3380c9ca5c85a61101bf916a2b326c478d83475e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 5 Jun 2019 17:39:53 +0000 +Subject: [PATCH 11/30] window-list: Use a more specific GTypeName for + workspace indicator + +Now that the class inherits from GObject, the generic name easily +conflicts with other classes otherwise, for example with the one +from the workspace-indicator extension. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/70 +--- + extensions/window-list/workspaceIndicator.js | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +index fb3ffe7..8ac43eb 100644 +--- a/extensions/window-list/workspaceIndicator.js ++++ b/extensions/window-list/workspaceIndicator.js +@@ -7,8 +7,9 @@ const PopupMenu = imports.ui.popupMenu; + const Gettext = imports.gettext.domain('gnome-shell-extensions'); + const _ = Gettext.gettext; + +-var WorkspaceIndicator = GObject.registerClass( +-class WorkspaceIndicator extends PanelMenu.Button { ++var WorkspaceIndicator = GObject.registerClass({ ++ GTypeName: 'WindowListWorkspaceIndicator' ++}, class WorkspaceIndicator extends PanelMenu.Button { + _init() { + super._init(0.0, _('Workspace Indicator'), true); + this.setMenu(new PopupMenu.PopupMenu(this, 0.0, St.Side.BOTTOM)); +-- +2.21.0 + + +From ad21dfc00c53420794f940e8710b60d2dd25bb9e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 5 Jun 2019 04:54:50 +0200 +Subject: [PATCH 12/30] window-list: Make some properties private + +There's no reason why they should be public. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/70 +--- + extensions/window-list/workspaceIndicator.js | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +index 8ac43eb..7c0360a 100644 +--- a/extensions/window-list/workspaceIndicator.js ++++ b/extensions/window-list/workspaceIndicator.js +@@ -26,14 +26,14 @@ var WorkspaceIndicator = GObject.registerClass({ + let workspaceManager = global.workspace_manager; + + this._currentWorkspace = workspaceManager.get_active_workspace().index(); +- this.statusLabel = new St.Label({ ++ this._statusLabel = new St.Label({ + text: this._getStatusText(), + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.CENTER + }); +- container.add_actor(this.statusLabel); ++ container.add_actor(this._statusLabel); + +- this.workspacesItems = []; ++ this._workspacesItems = []; + + this._workspaceManagerSignals = [ + workspaceManager.connect('notify::n-workspaces', +@@ -63,11 +63,11 @@ var WorkspaceIndicator = GObject.registerClass({ + } + + _updateIndicator() { +- this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); ++ this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); + this._currentWorkspace = global.workspace_manager.get_active_workspace().index(); +- this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); ++ this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); + +- this.statusLabel.set_text(this._getStatusText()); ++ this._statusLabel.set_text(this._getStatusText()); + } + + _getStatusText() { +@@ -82,7 +82,7 @@ var WorkspaceIndicator = GObject.registerClass({ + let workspaceManager = global.workspace_manager; + + this.menu.removeAll(); +- this.workspacesItems = []; ++ this._workspacesItems = []; + this._currentWorkspace = workspaceManager.get_active_workspace().index(); + + for (let i = 0; i < workspaceManager.n_workspaces; i++) { +@@ -98,10 +98,10 @@ var WorkspaceIndicator = GObject.registerClass({ + item.setOrnament(PopupMenu.Ornament.DOT); + + this.menu.addMenuItem(item); +- this.workspacesItems[i] = item; ++ this._workspacesItems[i] = item; + } + +- this.statusLabel.set_text(this._getStatusText()); ++ this._statusLabel.set_text(this._getStatusText()); + } + + _activate(index) { +-- +2.21.0 + + +From 14515b02845a6fe53c9a76eefc3359183dd8076f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 5 Jun 2019 04:57:39 +0200 +Subject: [PATCH 13/30] window-list: Update workspace names in-place + +There's no good reason to rebuild the entire menu on workspace names +changes, we can simply update the labels in-place. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/70 +--- + extensions/window-list/workspaceIndicator.js | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +index 7c0360a..9888838 100644 +--- a/extensions/window-list/workspaceIndicator.js ++++ b/extensions/window-list/workspaceIndicator.js +@@ -47,7 +47,7 @@ var WorkspaceIndicator = GObject.registerClass({ + + this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' }); + this._settingsChangedId = this._settings.connect( +- 'changed::workspace-names', this._updateMenu.bind(this)); ++ 'changed::workspace-names', this._updateMenuLabels.bind(this)); + } + + _onDestroy() { +@@ -78,6 +78,14 @@ var WorkspaceIndicator = GObject.registerClass({ + return '%d / %d'.format(current + 1, total); + } + ++ _updateMenuLabels() { ++ for (let i = 0; i < this._workspacesItems.length; i++) { ++ let item = this._workspacesItems[i]; ++ let name = Meta.prefs_get_workspace_name(i); ++ item.label.text = name; ++ } ++ } ++ + _updateMenu() { + let workspaceManager = global.workspace_manager; + +-- +2.21.0 + + +From 7ecdd7d2c61694df8ca9f76016bd8113bfbd7b51 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 5 Jun 2019 04:59:19 +0200 +Subject: [PATCH 14/30] window-list: Minor cleanup + +Mutter has a dedicated method for getting the index of the active +workspace, use that instead of getting first the active workspace +and then its index. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/70 +--- + extensions/window-list/workspaceIndicator.js | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +index 9888838..1f2e1c1 100644 +--- a/extensions/window-list/workspaceIndicator.js ++++ b/extensions/window-list/workspaceIndicator.js +@@ -25,7 +25,7 @@ var WorkspaceIndicator = GObject.registerClass({ + + let workspaceManager = global.workspace_manager; + +- this._currentWorkspace = workspaceManager.get_active_workspace().index(); ++ this._currentWorkspace = workspaceManager.get_active_workspace_index(); + this._statusLabel = new St.Label({ + text: this._getStatusText(), + x_align: Clutter.ActorAlign.CENTER, +@@ -64,7 +64,7 @@ var WorkspaceIndicator = GObject.registerClass({ + + _updateIndicator() { + this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); +- this._currentWorkspace = global.workspace_manager.get_active_workspace().index(); ++ this._currentWorkspace = global.workspace_manager.get_active_workspace_index(); + this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); + + this._statusLabel.set_text(this._getStatusText()); +@@ -72,7 +72,7 @@ var WorkspaceIndicator = GObject.registerClass({ + + _getStatusText() { + let workspaceManager = global.workspace_manager; +- let current = workspaceManager.get_active_workspace().index(); ++ let current = workspaceManager.get_active_workspace_index(); + let total = workspaceManager.n_workspaces; + + return '%d / %d'.format(current + 1, total); +@@ -91,7 +91,7 @@ var WorkspaceIndicator = GObject.registerClass({ + + this.menu.removeAll(); + this._workspacesItems = []; +- this._currentWorkspace = workspaceManager.get_active_workspace().index(); ++ this._currentWorkspace = workspaceManager.get_active_workspace_index(); + + for (let i = 0; i < workspaceManager.n_workspaces; i++) { + let name = Meta.prefs_get_workspace_name(i); +-- +2.21.0 + + +From 42ef09c097b297ee68207c4f439ec40e5998baa0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 5 Jun 2019 05:11:34 +0200 +Subject: [PATCH 15/30] window-list: Improve workspace label styling + +The border currently looks off - it extends all the way vertically +and leaves zero spacing to the label horizontally. Fix both issues +by setting appropriate padding/margins. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/70 +--- + extensions/window-list/stylesheet.css | 8 +++----- + extensions/window-list/workspaceIndicator.js | 13 ++++++++----- + 2 files changed, 11 insertions(+), 10 deletions(-) + +diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css +index 91383ab..bab8f76 100644 +--- a/extensions/window-list/stylesheet.css ++++ b/extensions/window-list/stylesheet.css +@@ -85,13 +85,11 @@ + height: 24px; + } + +-.window-list-workspace-indicator { +- padding: 3px; +-} +- +-.window-list-workspace-indicator > StWidget { ++.window-list-workspace-indicator .status-label-bin { + background-color: rgba(200, 200, 200, .3); + border: 1px solid #cccccc; ++ padding: 0 3px; ++ margin: 3px 0; + } + + .notification { +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +index 1f2e1c1..598c516 100644 +--- a/extensions/window-list/workspaceIndicator.js ++++ b/extensions/window-list/workspaceIndicator.js +@@ -26,12 +26,15 @@ var WorkspaceIndicator = GObject.registerClass({ + let workspaceManager = global.workspace_manager; + + this._currentWorkspace = workspaceManager.get_active_workspace_index(); +- this._statusLabel = new St.Label({ +- text: this._getStatusText(), +- x_align: Clutter.ActorAlign.CENTER, +- y_align: Clutter.ActorAlign.CENTER ++ this._statusLabel = new St.Label({ text: this._getStatusText() }); ++ ++ this._statusBin = new St.Bin({ ++ style_class: 'status-label-bin', ++ x_expand: true, ++ y_expand: true, ++ child: this._statusLabel + }); +- container.add_actor(this._statusLabel); ++ container.add_actor(this._statusBin); + + this._workspacesItems = []; + +-- +2.21.0 + + +From 0bf800b529ddfdc8663c63ff5fbf4ba5ac5d64d3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 5 Jun 2019 05:08:31 +0200 +Subject: [PATCH 16/30] window-list: Refactor workspace signal handlers + +We are about to support a separate representation if horizontal +workspaces are used. To prepare for that, rename the handlers to +something more generic and split out menu-specific bits into a +dedicated help function. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/70 +--- + extensions/window-list/workspaceIndicator.js | 25 +++++++++++++++----- + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +index 598c516..78ca97e 100644 +--- a/extensions/window-list/workspaceIndicator.js ++++ b/extensions/window-list/workspaceIndicator.js +@@ -40,9 +40,9 @@ var WorkspaceIndicator = GObject.registerClass({ + + this._workspaceManagerSignals = [ + workspaceManager.connect('notify::n-workspaces', +- this._updateMenu.bind(this)), ++ this._nWorkspacesChanged.bind(this)), + workspaceManager.connect_after('workspace-switched', +- this._updateIndicator.bind(this)) ++ this._onWorkspaceSwitched.bind(this)) + ]; + + this.connect('scroll-event', this._onScrollEvent.bind(this)); +@@ -65,14 +65,27 @@ var WorkspaceIndicator = GObject.registerClass({ + super._onDestroy(); + } + +- _updateIndicator() { +- this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); +- this._currentWorkspace = global.workspace_manager.get_active_workspace_index(); +- this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); ++ _onWorkspaceSwitched() { ++ let workspaceManager = global.workspace_manager; ++ this._currentWorkspace = workspaceManager.get_active_workspace_index(); ++ ++ this._updateMenuOrnament(); + + this._statusLabel.set_text(this._getStatusText()); + } + ++ _nWorkspacesChanged() { ++ this._updateMenu(); ++ } ++ ++ _updateMenuOrnament() { ++ for (let i = 0; i < this._workspacesItems.length; i++) { ++ this._workspacesItems[i].setOrnament(i == this._currentWorkspace ++ ? PopupMenu.Ornament.DOT ++ : PopupMenu.Ornament.NONE); ++ } ++ } ++ + _getStatusText() { + let workspaceManager = global.workspace_manager; + let current = workspaceManager.get_active_workspace_index(); +-- +2.21.0 + + +From 263aeea7be1e5bd244664bb3aefd9b81d8a80e32 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 5 Jun 2019 02:53:38 +0000 +Subject: [PATCH 17/30] window-list: Support horizontal workspace layout + +Unlike in GNOME 2, the workspace indicator we display in the window list +isn't a workspace switcher, but a menu button that allows switching +workspaces via its menu. The reason for that is that a horizontal +in-place switcher would be at odds with the vertical workspace layout +used in GNOME 3. + +However that reasoning doesn't apply when the layout is changed to a +horizontal one, so replace the button with a traditional workspace +switcher in that case. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/70 +--- + extensions/window-list/classic.css | 9 +++ + extensions/window-list/stylesheet.css | 29 +++++++++ + extensions/window-list/workspaceIndicator.js | 66 +++++++++++++++++++- + 3 files changed, 103 insertions(+), 1 deletion(-) + +diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css +index cc967e0..c533473 100644 +--- a/extensions/window-list/classic.css ++++ b/extensions/window-list/classic.css +@@ -47,3 +47,12 @@ + color: #888; + box-shadow: none; + } ++ ++/* workspace switcher */ ++.window-list-workspace-indicator .workspace { ++ background-color: #ddd; ++} ++ ++.window-list-workspace-indicator .workspace.active { ++ background-color: #ccc; ++} +diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css +index bab8f76..ad5978a 100644 +--- a/extensions/window-list/stylesheet.css ++++ b/extensions/window-list/stylesheet.css +@@ -92,6 +92,35 @@ + margin: 3px 0; + } + ++.window-list-workspace-indicator .workspaces-box { ++ spacing: 3px; ++ padding: 3px; ++} ++ ++.window-list-workspace-indicator .workspace { ++ border: 1px solid #cccccc; ++ width: 52px; ++} ++ ++.window-list-workspace-indicator .workspace:first-child:last-child:ltr, ++.window-list-workspace-indicator .workspace:first-child:last-child:rtl { ++ border-radius: 4px; ++} ++ ++.window-list-workspace-indicator .workspace:first-child:ltr, ++.window-list-workspace-indicator .workspace:last-child:rtl { ++ border-radius: 4px 0 0 4px; ++} ++ ++.window-list-workspace-indicator .workspace:first-child:rtl, ++.window-list-workspace-indicator .workspace:last-child:ltr { ++ border-radius: 0 4px 4px 0; ++} ++ ++.window-list-workspace-indicator .workspace.active { ++ background-color: rgba(200, 200, 200, .3); ++} ++ + .notification { + font-weight: normal; + } +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +index 78ca97e..1258ed2 100644 +--- a/extensions/window-list/workspaceIndicator.js ++++ b/extensions/window-list/workspaceIndicator.js +@@ -7,6 +7,25 @@ const PopupMenu = imports.ui.popupMenu; + const Gettext = imports.gettext.domain('gnome-shell-extensions'); + const _ = Gettext.gettext; + ++let WorkspaceThumbnail = GObject.registerClass({ ++ GTypeName: 'WindowListWorkspaceThumbnail' ++}, class WorkspaceThumbnail extends St.Button { ++ _init(index) { ++ super._init({ ++ style_class: 'workspace' ++ }); ++ ++ this._index = index; ++ } ++ ++ // eslint-disable-next-line camelcase ++ on_clicked() { ++ let ws = global.workspace_manager.get_workspace_by_index(this._index); ++ if (ws) ++ ws.activate(global.get_current_time()); ++ } ++}); ++ + var WorkspaceIndicator = GObject.registerClass({ + GTypeName: 'WindowListWorkspaceIndicator' + }, class WorkspaceIndicator extends PanelMenu.Button { +@@ -36,17 +55,30 @@ var WorkspaceIndicator = GObject.registerClass({ + }); + container.add_actor(this._statusBin); + ++ this._thumbnailsBox = new St.BoxLayout({ ++ style_class: 'workspaces-box', ++ y_expand: true, ++ reactive: true ++ }); ++ this._thumbnailsBox.connect('scroll-event', ++ this._onScrollEvent.bind(this)); ++ container.add_actor(this._thumbnailsBox); ++ + this._workspacesItems = []; + + this._workspaceManagerSignals = [ + workspaceManager.connect('notify::n-workspaces', + this._nWorkspacesChanged.bind(this)), + workspaceManager.connect_after('workspace-switched', +- this._onWorkspaceSwitched.bind(this)) ++ this._onWorkspaceSwitched.bind(this)), ++ workspaceManager.connect('notify::layout-rows', ++ this._onWorkspaceOrientationChanged.bind(this)) + ]; + + this.connect('scroll-event', this._onScrollEvent.bind(this)); + this._updateMenu(); ++ this._updateThumbnails(); ++ this._onWorkspaceOrientationChanged(); + + this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' }); + this._settingsChangedId = this._settings.connect( +@@ -65,17 +97,27 @@ var WorkspaceIndicator = GObject.registerClass({ + super._onDestroy(); + } + ++ _onWorkspaceOrientationChanged() { ++ let vertical = global.workspace_manager.layout_rows == -1; ++ this.reactive = vertical; ++ ++ this._statusBin.visible = vertical; ++ this._thumbnailsBox.visible = !vertical; ++ } ++ + _onWorkspaceSwitched() { + let workspaceManager = global.workspace_manager; + this._currentWorkspace = workspaceManager.get_active_workspace_index(); + + this._updateMenuOrnament(); ++ this._updateActiveThumbnail(); + + this._statusLabel.set_text(this._getStatusText()); + } + + _nWorkspacesChanged() { + this._updateMenu(); ++ this._updateThumbnails(); + } + + _updateMenuOrnament() { +@@ -86,6 +128,16 @@ var WorkspaceIndicator = GObject.registerClass({ + } + } + ++ _updateActiveThumbnail() { ++ let thumbs = this._thumbnailsBox.get_children(); ++ for (let i = 0; i < thumbs.length; i++) { ++ if (i == this._currentWorkspace) ++ thumbs[i].add_style_class_name('active'); ++ else ++ thumbs[i].remove_style_class_name('active'); ++ } ++ } ++ + _getStatusText() { + let workspaceManager = global.workspace_manager; + let current = workspaceManager.get_active_workspace_index(); +@@ -128,6 +180,18 @@ var WorkspaceIndicator = GObject.registerClass({ + this._statusLabel.set_text(this._getStatusText()); + } + ++ _updateThumbnails() { ++ let workspaceManager = global.workspace_manager; ++ ++ this._thumbnailsBox.destroy_all_children(); ++ ++ for (let i = 0; i < workspaceManager.n_workspaces; i++) { ++ let thumb = new WorkspaceThumbnail(i); ++ this._thumbnailsBox.add_actor(thumb); ++ } ++ this._updateActiveThumbnail(); ++ } ++ + _activate(index) { + let workspaceManager = global.workspace_manager; + +-- +2.21.0 + + +From 2a2958831f51968089262b1e41bc908a69ef6834 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 5 Jun 2019 03:31:16 +0000 +Subject: [PATCH 18/30] classic: Add 'horizontal-workspaces' extension + +Vertical workspaces are another defining characteristics of GNOME 3, +and thus rather un-classic. That switch was driven by the overall +layout of the overview, and now that we disable the overview in +GNOME Classic, we can just return to the traditional workspace +layout as well. + +Add a small extension that does just that. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/72 +--- + extensions/horizontal-workspaces/extension.js | 18 ++++++++++++++++++ + extensions/horizontal-workspaces/meson.build | 5 +++++ + .../horizontal-workspaces/metadata.json.in | 10 ++++++++++ + .../horizontal-workspaces/stylesheet.css | 1 + + meson.build | 1 + + 5 files changed, 35 insertions(+) + create mode 100644 extensions/horizontal-workspaces/extension.js + create mode 100644 extensions/horizontal-workspaces/meson.build + create mode 100644 extensions/horizontal-workspaces/metadata.json.in + create mode 100644 extensions/horizontal-workspaces/stylesheet.css + +diff --git a/extensions/horizontal-workspaces/extension.js b/extensions/horizontal-workspaces/extension.js +new file mode 100644 +index 0000000..b3937ce +--- /dev/null ++++ b/extensions/horizontal-workspaces/extension.js +@@ -0,0 +1,18 @@ ++/* exported enable disable */ ++const { Meta } = imports.gi; ++ ++function enable() { ++ global.workspace_manager.override_workspace_layout( ++ Meta.DisplayCorner.TOPLEFT, ++ false, ++ 1, ++ -1); ++} ++ ++function disable() { ++ global.workspace_manager.override_workspace_layout( ++ Meta.DisplayCorner.TOPLEFT, ++ false, ++ -1, ++ 1); ++} +diff --git a/extensions/horizontal-workspaces/meson.build b/extensions/horizontal-workspaces/meson.build +new file mode 100644 +index 0000000..48504f6 +--- /dev/null ++++ b/extensions/horizontal-workspaces/meson.build +@@ -0,0 +1,5 @@ ++extension_data += configure_file( ++ input: metadata_name + '.in', ++ output: metadata_name, ++ configuration: metadata_conf ++) +diff --git a/extensions/horizontal-workspaces/metadata.json.in b/extensions/horizontal-workspaces/metadata.json.in +new file mode 100644 +index 0000000..f109e06 +--- /dev/null ++++ b/extensions/horizontal-workspaces/metadata.json.in +@@ -0,0 +1,10 @@ ++{ ++"extension-id": "@extension_id@", ++"uuid": "@uuid@", ++"settings-schema": "@gschemaname@", ++"gettext-domain": "@gettext_domain@", ++"name": "Horizontal workspaces", ++"description": "Use a horizontal workspace layout", ++"shell-version": [ "@shell_current@" ], ++"url": "@url@" ++} +diff --git a/extensions/horizontal-workspaces/stylesheet.css b/extensions/horizontal-workspaces/stylesheet.css +new file mode 100644 +index 0000000..25134b6 +--- /dev/null ++++ b/extensions/horizontal-workspaces/stylesheet.css +@@ -0,0 +1 @@ ++/* This extensions requires no special styling */ +diff --git a/meson.build b/meson.build +index 32743ed..23bd5ad 100644 +--- a/meson.build ++++ b/meson.build +@@ -34,6 +34,7 @@ uuid_suffix = '@gnome-shell-extensions.gcampax.github.com' + classic_extensions = [ + 'apps-menu', + 'desktop-icons', ++ 'horizontal-workspaces', + 'places-menu', + 'launch-new-instance', + 'top-icons', +-- +2.21.0 + + +From 6a7b057028a1e4264312974d3ca21e16f5c07776 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 11 Jun 2019 23:01:20 +0000 +Subject: [PATCH 19/30] window-list: Turn workspace thumbs into drop targets + +It makes some sense to allow using the workspace indicator for moving +windows between workspaces as well as for workspace switching. This +applies particularly in GNOME classic after we disabled the overview +there, so that there is again a non-shortcut way of moving windows +between workspaces. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/74 +--- + extensions/window-list/workspaceIndicator.js | 27 ++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +index 1258ed2..4831768 100644 +--- a/extensions/window-list/workspaceIndicator.js ++++ b/extensions/window-list/workspaceIndicator.js +@@ -1,6 +1,8 @@ + /* exported WorkspaceIndicator */ + const { Clutter, Gio, GObject, Meta, St } = imports.gi; + ++const DND = imports.ui.dnd; ++const Main = imports.ui.main; + const PanelMenu = imports.ui.panelMenu; + const PopupMenu = imports.ui.popupMenu; + +@@ -16,6 +18,31 @@ let WorkspaceThumbnail = GObject.registerClass({ + }); + + this._index = index; ++ this._delegate = this; // needed for DND ++ } ++ ++ acceptDrop(source) { ++ if (!source.realWindow) ++ return false; ++ ++ let window = source.realWindow.get_meta_window(); ++ this._moveWindow(window); ++ return true; ++ } ++ ++ handleDragOver(source) { ++ if (source.realWindow) ++ return DND.DragMotionResult.MOVE_DROP; ++ else ++ return DND.DragMotionResult.CONTINUE; ++ } ++ ++ ++ _moveWindow(window) { ++ let monitorIndex = Main.layoutManager.findIndexForActor(this); ++ if (monitorIndex != window.get_monitor()) ++ window.move_to_monitor(monitorIndex); ++ window.change_workspace_by_index(this._index, false); + } + + // eslint-disable-next-line camelcase +-- +2.21.0 + + +From 7dca894705ddfd73016f4d073f6fe486563ce324 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 26 Jun 2019 23:55:58 +0000 +Subject: [PATCH 20/30] window-list: Show previews in workspace switcher + +Currently the new horizontal workspace switcher only shows a series of +buttons, with no indication of the workspaces' contents. Go full GNOME 2 +and add tiny draggable preview rectangles that represent the windows +on a particular workspace. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/74 +--- + extensions/window-list/classic.css | 10 ++ + extensions/window-list/stylesheet.css | 10 ++ + extensions/window-list/workspaceIndicator.js | 154 ++++++++++++++++++- + 3 files changed, 173 insertions(+), 1 deletion(-) + +diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css +index c533473..7079d3e 100644 +--- a/extensions/window-list/classic.css ++++ b/extensions/window-list/classic.css +@@ -56,3 +56,13 @@ + .window-list-workspace-indicator .workspace.active { + background-color: #ccc; + } ++ ++.window-list-window-preview { ++ background-color: #ededed; ++ border: 1px solid #ccc; ++} ++ ++.window-list-window-preview.active { ++ background-color: #f6f5f4; ++ border: 2px solid #888; ++} +diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css +index ad5978a..79d56ba 100644 +--- a/extensions/window-list/stylesheet.css ++++ b/extensions/window-list/stylesheet.css +@@ -121,6 +121,16 @@ + background-color: rgba(200, 200, 200, .3); + } + ++.window-list-window-preview { ++ background-color: #252525; ++ border: 1px solid #ccc; ++} ++ ++.window-list-window-preview.active { ++ background-color: #353535; ++ border: 2px solid #ccc; ++} ++ + .notification { + font-weight: normal; + } +diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js +index 4831768..ca47611 100644 +--- a/extensions/window-list/workspaceIndicator.js ++++ b/extensions/window-list/workspaceIndicator.js +@@ -9,16 +9,131 @@ const PopupMenu = imports.ui.popupMenu; + const Gettext = imports.gettext.domain('gnome-shell-extensions'); + const _ = Gettext.gettext; + ++let WindowPreview = GObject.registerClass({ ++ GTypeName: 'WindowListWindowPreview' ++}, class WindowPreview extends St.Button { ++ _init(window) { ++ super._init({ ++ style_class: 'window-list-window-preview' ++ }); ++ ++ this._delegate = this; ++ DND.makeDraggable(this, { restoreOnSuccess: true }); ++ ++ this._window = window; ++ ++ this.connect('destroy', this._onDestroy.bind(this)); ++ ++ this._sizeChangedId = this._window.connect('size-changed', ++ this._relayout.bind(this)); ++ this._positionChangedId = this._window.connect('position-changed', ++ this._relayout.bind(this)); ++ this._minimizedChangedId = this._window.connect('notify::minimized', ++ this._relayout.bind(this)); ++ this._monitorEnteredId = global.display.connect('window-entered-monitor', ++ this._relayout.bind(this)); ++ this._monitorLeftId = global.display.connect('window-left-monitor', ++ this._relayout.bind(this)); ++ ++ // Do initial layout when we get a parent ++ let id = this.connect('parent-set', () => { ++ this.disconnect(id); ++ if (!this.get_parent()) ++ return; ++ this._laterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { ++ this._laterId = 0; ++ this._relayout(); ++ return false; ++ }); ++ }); ++ ++ this._focusChangedId = global.display.connect('notify::focus-window', ++ this._onFocusChanged.bind(this)); ++ this._onFocusChanged(); ++ } ++ ++ // needed for DND ++ get realWindow() { ++ return this._window.get_compositor_private(); ++ } ++ ++ _onDestroy() { ++ this._window.disconnect(this._sizeChangedId); ++ this._window.disconnect(this._positionChangedId); ++ this._window.disconnect(this._minimizedChangedId); ++ global.display.disconnect(this._monitorEnteredId); ++ global.display.disconnect(this._monitorLeftId); ++ global.display.disconnect(this._focusChangedId); ++ if (this._laterId) ++ Meta.later_remove(this._laterId); ++ } ++ ++ _onFocusChanged() { ++ if (global.display.focus_window == this._window) ++ this.add_style_class_name('active'); ++ else ++ this.remove_style_class_name('active'); ++ } ++ ++ _relayout() { ++ let monitor = Main.layoutManager.findIndexForActor(this); ++ this.visible = monitor == this._window.get_monitor() && ++ this._window.showing_on_its_workspace(); ++ ++ if (!this.visible) ++ return; ++ ++ let workArea = Main.layoutManager.getWorkAreaForMonitor(monitor); ++ let hscale = this.get_parent().allocation.get_width() / workArea.width; ++ let vscale = this.get_parent().allocation.get_height() / workArea.height; ++ ++ let frameRect = this._window.get_frame_rect(); ++ this.set_size( ++ Math.round(Math.min(frameRect.width, workArea.width) * hscale), ++ Math.round(Math.min(frameRect.height, workArea.height) * vscale)); ++ this.set_position( ++ Math.round(frameRect.x * hscale), ++ Math.round(frameRect.y * vscale)); ++ } ++}); ++ + let WorkspaceThumbnail = GObject.registerClass({ + GTypeName: 'WindowListWorkspaceThumbnail' + }, class WorkspaceThumbnail extends St.Button { + _init(index) { + super._init({ +- style_class: 'workspace' ++ style_class: 'workspace', ++ child: new Clutter.Actor({ ++ layout_manager: new Clutter.BinLayout(), ++ clip_to_allocation: true ++ }), ++ x_fill: true, ++ y_fill: true + }); + ++ this.connect('destroy', this._onDestroy.bind(this)); ++ + this._index = index; + this._delegate = this; // needed for DND ++ ++ this._windowPreviews = new Map(); ++ ++ let workspaceManager = global.workspace_manager; ++ this._workspace = workspaceManager.get_workspace_by_index(index); ++ ++ this._windowAddedId = this._workspace.connect('window-added', ++ (ws, window) => { ++ this._addWindow(window); ++ }); ++ this._windowRemovedId = this._workspace.connect('window-removed', ++ (ws, window) => { ++ this._removeWindow(window); ++ }); ++ this._restackedId = global.display.connect('restacked', ++ this._onRestacked.bind(this)); ++ ++ this._workspace.list_windows().forEach(w => this._addWindow(w)); ++ this._onRestacked(); + } + + acceptDrop(source) { +@@ -37,6 +152,37 @@ let WorkspaceThumbnail = GObject.registerClass({ + return DND.DragMotionResult.CONTINUE; + } + ++ _addWindow(window) { ++ if (this._windowPreviews.has(window)) ++ return; ++ ++ let preview = new WindowPreview(window); ++ preview.connect('clicked', (a, btn) => this.emit('clicked', btn)); ++ this._windowPreviews.set(window, preview); ++ this.child.add_child(preview); ++ } ++ ++ _removeWindow(window) { ++ let preview = this._windowPreviews.get(window); ++ if (!preview) ++ return; ++ ++ this._windowPreviews.delete(window); ++ preview.destroy(); ++ } ++ ++ _onRestacked() { ++ let lastPreview = null; ++ let windows = global.get_window_actors().map(a => a.meta_window); ++ for (let i = 0; i < windows.length; i++) { ++ let preview = this._windowPreviews.get(windows[i]); ++ if (!preview) ++ continue; ++ ++ this.child.set_child_above_sibling(preview, lastPreview); ++ lastPreview = preview; ++ } ++ } + + _moveWindow(window) { + let monitorIndex = Main.layoutManager.findIndexForActor(this); +@@ -51,6 +197,12 @@ let WorkspaceThumbnail = GObject.registerClass({ + if (ws) + ws.activate(global.get_current_time()); + } ++ ++ _onDestroy() { ++ this._workspace.disconnect(this._windowAddedId); ++ this._workspace.disconnect(this._windowRemovedId); ++ global.display.disconnect(this._restackedId); ++ } + }); + + var WorkspaceIndicator = GObject.registerClass({ +-- +2.21.0 + + +From 77b9d4fee20d84816cb64bfa6b95fddd589b4788 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sat, 29 Jun 2019 01:24:54 +0200 +Subject: [PATCH 21/30] workspace-indicator: Fix whitespace error + +We only want a single space before and after operators, not at least +one. Unfortunately eslint only enforces the latter ... + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/71 +--- + extensions/workspace-indicator/extension.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js +index 3be1268..c3c4d5f 100644 +--- a/extensions/workspace-indicator/extension.js ++++ b/extensions/workspace-indicator/extension.js +@@ -109,7 +109,7 @@ class WorkspaceIndicator extends PanelMenu.Button { + _activate(index) { + let workspaceManager = global.workspace_manager; + +- if (index >= 0 && index < workspaceManager.n_workspaces) { ++ if (index >= 0 && index < workspaceManager.n_workspaces) { + let metaWorkspace = workspaceManager.get_workspace_by_index(index); + metaWorkspace.activate(global.get_current_time()); + } +-- +2.21.0 + + +From a68ef2096fed7580f7177991e354910add1ab79c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sun, 9 Jun 2019 22:58:29 +0000 +Subject: [PATCH 22/30] workspace-indicator: Make some properties private + +There's no reason why they should be public. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/71 +--- + extensions/workspace-indicator/extension.js | 30 ++++++++++----------- + 1 file changed, 15 insertions(+), 15 deletions(-) + +diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js +index c3c4d5f..e052181 100644 +--- a/extensions/workspace-indicator/extension.js ++++ b/extensions/workspace-indicator/extension.js +@@ -23,14 +23,14 @@ class WorkspaceIndicator extends PanelMenu.Button { + let workspaceManager = global.workspace_manager; + + this._currentWorkspace = workspaceManager.get_active_workspace().index(); +- this.statusLabel = new St.Label({ ++ this._statusLabel = new St.Label({ + y_align: Clutter.ActorAlign.CENTER, + text: this._labelText() + }); + +- this.add_actor(this.statusLabel); ++ this.add_actor(this._statusLabel); + +- this.workspacesItems = []; ++ this._workspacesItems = []; + this._workspaceSection = new PopupMenu.PopupMenuSection(); + this.menu.addMenuItem(this._workspaceSection); + +@@ -46,7 +46,7 @@ class WorkspaceIndicator extends PanelMenu.Button { + this._createWorkspacesSection(); + + //styling +- this.statusLabel.add_style_class_name('panel-workspace-indicator'); ++ this._statusLabel.add_style_class_name('panel-workspace-indicator'); + + this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA }); + this._settingsChangedId = +@@ -67,11 +67,11 @@ class WorkspaceIndicator extends PanelMenu.Button { + } + + _updateIndicator() { +- this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); ++ this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); + this._currentWorkspace = global.workspace_manager.get_active_workspace().index(); +- this.workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); ++ this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); + +- this.statusLabel.set_text(this._labelText()); ++ this._statusLabel.set_text(this._labelText()); + } + + _labelText(workspaceIndex) { +@@ -86,24 +86,24 @@ class WorkspaceIndicator extends PanelMenu.Button { + let workspaceManager = global.workspace_manager; + + this._workspaceSection.removeAll(); +- this.workspacesItems = []; ++ this._workspacesItems = []; + this._currentWorkspace = workspaceManager.get_active_workspace().index(); + + let i = 0; + for (; i < workspaceManager.n_workspaces; i++) { +- this.workspacesItems[i] = new PopupMenu.PopupMenuItem(this._labelText(i)); +- this._workspaceSection.addMenuItem(this.workspacesItems[i]); +- this.workspacesItems[i].workspaceId = i; +- this.workspacesItems[i].label_actor = this.statusLabel; +- this.workspacesItems[i].connect('activate', (actor, _event) => { ++ this._workspacesItems[i] = new PopupMenu.PopupMenuItem(this._labelText(i)); ++ this._workspaceSection.addMenuItem(this._workspacesItems[i]); ++ this._workspacesItems[i].workspaceId = i; ++ this._workspacesItems[i].label_actor = this._statusLabel; ++ this._workspacesItems[i].connect('activate', (actor, _event) => { + this._activate(actor.workspaceId); + }); + + if (i == this._currentWorkspace) +- this.workspacesItems[i].setOrnament(PopupMenu.Ornament.DOT); ++ this._workspacesItems[i].setOrnament(PopupMenu.Ornament.DOT); + } + +- this.statusLabel.set_text(this._labelText()); ++ this._statusLabel.set_text(this._labelText()); + } + + _activate(index) { +-- +2.21.0 + + +From 7e74dd6e331846564898ed220d58eb54cad83524 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sun, 9 Jun 2019 23:03:55 +0000 +Subject: [PATCH 23/30] workspace-indicator: Update workspace names in-place + +There's no good reason to rebuild the entire menu on workspace names +changes, we can simply update the labels in-place. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/71 +--- + extensions/workspace-indicator/extension.js | 11 ++++++++--- + 1 file changed, 8 insertions(+), 3 deletions(-) + +diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js +index e052181..205ee36 100644 +--- a/extensions/workspace-indicator/extension.js ++++ b/extensions/workspace-indicator/extension.js +@@ -49,9 +49,9 @@ class WorkspaceIndicator extends PanelMenu.Button { + this._statusLabel.add_style_class_name('panel-workspace-indicator'); + + this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA }); +- this._settingsChangedId = +- this._settings.connect(`changed::${WORKSPACE_KEY}`, +- this._createWorkspacesSection.bind(this)); ++ this._settingsChangedId = this._settings.connect( ++ `changed::${WORKSPACE_KEY}`, ++ this._updateMenuLabels.bind(this)); + } + + _onDestroy() { +@@ -82,6 +82,11 @@ class WorkspaceIndicator extends PanelMenu.Button { + return Meta.prefs_get_workspace_name(workspaceIndex); + } + ++ _updateMenuLabels() { ++ for (let i = 0; i < this._workspacesItems.length; i++) ++ this._workspacesItems[i].label.text = this._labelText(i); ++ } ++ + _createWorkspacesSection() { + let workspaceManager = global.workspace_manager; + +-- +2.21.0 + + +From dfcd296cf33de8a3e739c340734332a63f2c01f3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sun, 9 Jun 2019 23:05:00 +0000 +Subject: [PATCH 24/30] workspace-indicator: Minor cleanup + +Mutter has a dedicated method for getting the index of the active +workspace, use that instead of getting first the active workspace +and then its index. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/71 +--- + extensions/workspace-indicator/extension.js | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js +index 205ee36..7ebc1f0 100644 +--- a/extensions/workspace-indicator/extension.js ++++ b/extensions/workspace-indicator/extension.js +@@ -22,7 +22,7 @@ class WorkspaceIndicator extends PanelMenu.Button { + + let workspaceManager = global.workspace_manager; + +- this._currentWorkspace = workspaceManager.get_active_workspace().index(); ++ this._currentWorkspace = workspaceManager.get_active_workspace_index(); + this._statusLabel = new St.Label({ + y_align: Clutter.ActorAlign.CENTER, + text: this._labelText() +@@ -68,7 +68,7 @@ class WorkspaceIndicator extends PanelMenu.Button { + + _updateIndicator() { + this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); +- this._currentWorkspace = global.workspace_manager.get_active_workspace().index(); ++ this._currentWorkspace = global.workspace_manager.get_active_workspace_index(); + this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); + + this._statusLabel.set_text(this._labelText()); +@@ -92,7 +92,7 @@ class WorkspaceIndicator extends PanelMenu.Button { + + this._workspaceSection.removeAll(); + this._workspacesItems = []; +- this._currentWorkspace = workspaceManager.get_active_workspace().index(); ++ this._currentWorkspace = workspaceManager.get_active_workspace_index(); + + let i = 0; + for (; i < workspaceManager.n_workspaces; i++) { +@@ -131,7 +131,7 @@ class WorkspaceIndicator extends PanelMenu.Button { + return; + } + +- let newIndex = global.workspace_manager.get_active_workspace().index() + diff; ++ let newIndex = global.workspace_manager.get_active_workspace_index() + diff; + this._activate(newIndex); + } + }); +-- +2.21.0 + + +From 00d1e9637f0b7f51b271c384fb55ecaea673bb70 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sun, 9 Jun 2019 23:09:12 +0000 +Subject: [PATCH 25/30] workspace-indicator: Refactor workspace signal handlers + +We are about to support a separate representation if horizontal +workspaces are used. To prepare for that, rename the handlers to +something more generic and split out menu-specific bits into a +dedicated help function. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/71 +--- + extensions/workspace-indicator/extension.js | 31 ++++++++++++++------- + 1 file changed, 21 insertions(+), 10 deletions(-) + +diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js +index 7ebc1f0..34fc275 100644 +--- a/extensions/workspace-indicator/extension.js ++++ b/extensions/workspace-indicator/extension.js +@@ -34,13 +34,12 @@ class WorkspaceIndicator extends PanelMenu.Button { + this._workspaceSection = new PopupMenu.PopupMenuSection(); + this.menu.addMenuItem(this._workspaceSection); + +- this._workspaceManagerSignals = []; +- this._workspaceManagerSignals.push(workspaceManager.connect_after('workspace-added', +- this._createWorkspacesSection.bind(this))); +- this._workspaceManagerSignals.push(workspaceManager.connect_after('workspace-removed', +- this._createWorkspacesSection.bind(this))); +- this._workspaceManagerSignals.push(workspaceManager.connect_after('workspace-switched', +- this._updateIndicator.bind(this))); ++ this._workspaceManagerSignals = [ ++ workspaceManager.connect_after('notify::n-workspaces', ++ this._nWorkspacesChanged.bind(this)), ++ workspaceManager.connect_after('workspace-switched', ++ this._onWorkspaceSwitched.bind(this)) ++ ]; + + this.connect('scroll-event', this._onScrollEvent.bind(this)); + this._createWorkspacesSection(); +@@ -66,14 +65,26 @@ class WorkspaceIndicator extends PanelMenu.Button { + super._onDestroy(); + } + +- _updateIndicator() { +- this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.NONE); ++ _onWorkspaceSwitched() { + this._currentWorkspace = global.workspace_manager.get_active_workspace_index(); +- this._workspacesItems[this._currentWorkspace].setOrnament(PopupMenu.Ornament.DOT); ++ ++ this._updateMenuOrnament(); + + this._statusLabel.set_text(this._labelText()); + } + ++ _nWorkspacesChanged() { ++ this._createWorkspacesSection(); ++ } ++ ++ _updateMenuOrnament() { ++ for (let i = 0; i < this._workspacesItems.length; i++) { ++ this._workspacesItems[i].setOrnament(i == this._currentWorkspace ++ ? PopupMenu.Ornament.DOT ++ : PopupMenu.Ornament.NONE); ++ } ++ } ++ + _labelText(workspaceIndex) { + if (workspaceIndex == undefined) { + workspaceIndex = this._currentWorkspace; +-- +2.21.0 + + +From 0834d04691de28f3a216578e55335c6e9b3e4fad Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sun, 9 Jun 2019 23:17:35 +0000 +Subject: [PATCH 26/30] workspace-indicator: Minor cleanup + +Pass the style class at construction time instead of setting it later. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/71 +--- + extensions/workspace-indicator/extension.js | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js +index 34fc275..672b98d 100644 +--- a/extensions/workspace-indicator/extension.js ++++ b/extensions/workspace-indicator/extension.js +@@ -24,6 +24,7 @@ class WorkspaceIndicator extends PanelMenu.Button { + + this._currentWorkspace = workspaceManager.get_active_workspace_index(); + this._statusLabel = new St.Label({ ++ style_class: 'panel-workspace-indicator', + y_align: Clutter.ActorAlign.CENTER, + text: this._labelText() + }); +@@ -44,9 +45,6 @@ class WorkspaceIndicator extends PanelMenu.Button { + this.connect('scroll-event', this._onScrollEvent.bind(this)); + this._createWorkspacesSection(); + +- //styling +- this._statusLabel.add_style_class_name('panel-workspace-indicator'); +- + this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA }); + this._settingsChangedId = this._settings.connect( + `changed::${WORKSPACE_KEY}`, +-- +2.21.0 + + +From 07fca6b1ee27a1eaf97027e4353ab46ea9cb745e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sun, 9 Jun 2019 23:45:24 +0000 +Subject: [PATCH 27/30] workspace-indicator: Support horizontal workspace + layout + +Just like we did for the workspace indicator in the window-list, improve +the handling of horizontal workspace layouts by showing the switcher +in-place instead of delegating the functionality to a menu. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/71 +--- + extensions/workspace-indicator/extension.js | 76 ++++++++++++++++++- + extensions/workspace-indicator/stylesheet.css | 18 ++++- + 2 files changed, 90 insertions(+), 4 deletions(-) + +diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js +index 672b98d..48019da 100644 +--- a/extensions/workspace-indicator/extension.js ++++ b/extensions/workspace-indicator/extension.js +@@ -15,11 +15,38 @@ const ExtensionUtils = imports.misc.extensionUtils; + const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; + const WORKSPACE_KEY = 'workspace-names'; + ++let WorkspaceThumbnail = GObject.registerClass({ ++ GTypeName: 'WorkspaceIndicatorWorkspaceThumbnail' ++}, class WorkspaceThumbnail extends St.Button { ++ _init(index) { ++ super._init({ ++ style_class: 'workspace', ++ }); ++ ++ this._index = index; ++ } ++ ++ // eslint-disable-next-line camelcase ++ on_clicked() { ++ let ws = global.workspace_manager.get_workspace_by_index(this._index); ++ if (ws) ++ ws.activate(global.get_current_time()); ++ } ++}); ++ ++ + let WorkspaceIndicator = GObject.registerClass( + class WorkspaceIndicator extends PanelMenu.Button { + _init() { + super._init(0.0, _('Workspace Indicator')); + ++ let container = new St.Widget({ ++ layout_manager: new Clutter.BinLayout(), ++ x_expand: true, ++ y_expand: true ++ }); ++ this.add_actor(container); ++ + let workspaceManager = global.workspace_manager; + + this._currentWorkspace = workspaceManager.get_active_workspace_index(); +@@ -29,7 +56,15 @@ class WorkspaceIndicator extends PanelMenu.Button { + text: this._labelText() + }); + +- this.add_actor(this._statusLabel); ++ container.add_actor(this._statusLabel); ++ ++ this._thumbnailsBox = new St.BoxLayout({ ++ style_class: 'panel-workspace-indicator-box', ++ y_expand: true, ++ reactive: true ++ }); ++ ++ container.add_actor(this._thumbnailsBox); + + this._workspacesItems = []; + this._workspaceSection = new PopupMenu.PopupMenuSection(); +@@ -39,11 +74,16 @@ class WorkspaceIndicator extends PanelMenu.Button { + workspaceManager.connect_after('notify::n-workspaces', + this._nWorkspacesChanged.bind(this)), + workspaceManager.connect_after('workspace-switched', +- this._onWorkspaceSwitched.bind(this)) ++ this._onWorkspaceSwitched.bind(this)), ++ workspaceManager.connect('notify::layout-rows', ++ this._onWorkspaceOrientationChanged.bind(this)) + ]; + + this.connect('scroll-event', this._onScrollEvent.bind(this)); ++ this._thumbnailsBox.connect('scroll-event', this._onScrollEvent.bind(this)); + this._createWorkspacesSection(); ++ this._updateThumbnails(); ++ this._onWorkspaceOrientationChanged(); + + this._settings = new Gio.Settings({ schema_id: WORKSPACE_SCHEMA }); + this._settingsChangedId = this._settings.connect( +@@ -63,16 +103,26 @@ class WorkspaceIndicator extends PanelMenu.Button { + super._onDestroy(); + } + ++ _onWorkspaceOrientationChanged() { ++ let vertical = global.workspace_manager.layout_rows == -1; ++ this.reactive = vertical; ++ ++ this._statusLabel.visible = vertical; ++ this._thumbnailsBox.visible = !vertical; ++ } ++ + _onWorkspaceSwitched() { + this._currentWorkspace = global.workspace_manager.get_active_workspace_index(); + + this._updateMenuOrnament(); ++ this._updateActiveThumbnail(); + + this._statusLabel.set_text(this._labelText()); + } + + _nWorkspacesChanged() { + this._createWorkspacesSection(); ++ this._updateThumbnails(); + } + + _updateMenuOrnament() { +@@ -83,6 +133,16 @@ class WorkspaceIndicator extends PanelMenu.Button { + } + } + ++ _updateActiveThumbnail() { ++ let thumbs = this._thumbnailsBox.get_children(); ++ for (let i = 0; i < thumbs.length; i++) { ++ if (i == this._currentWorkspace) ++ thumbs[i].add_style_class_name('active'); ++ else ++ thumbs[i].remove_style_class_name('active'); ++ } ++ } ++ + _labelText(workspaceIndex) { + if (workspaceIndex == undefined) { + workspaceIndex = this._currentWorkspace; +@@ -120,6 +180,18 @@ class WorkspaceIndicator extends PanelMenu.Button { + this._statusLabel.set_text(this._labelText()); + } + ++ _updateThumbnails() { ++ let workspaceManager = global.workspace_manager; ++ ++ this._thumbnailsBox.destroy_all_children(); ++ ++ for (let i = 0; i < workspaceManager.n_workspaces; i++) { ++ let thumb = new WorkspaceThumbnail(i); ++ this._thumbnailsBox.add_actor(thumb); ++ } ++ this._updateActiveThumbnail(); ++ } ++ + _activate(index) { + let workspaceManager = global.workspace_manager; + +diff --git a/extensions/workspace-indicator/stylesheet.css b/extensions/workspace-indicator/stylesheet.css +index 1271f1c..a15081e 100644 +--- a/extensions/workspace-indicator/stylesheet.css ++++ b/extensions/workspace-indicator/stylesheet.css +@@ -1,5 +1,19 @@ +-.panel-workspace-indicator { ++.panel-workspace-indicator, ++.panel-workspace-indicator-box .workspace { + padding: 0 8px; +- background-color: rgba(200, 200, 200, .5); + border: 1px solid #cccccc; + } ++ ++.panel-workspace-indicator, ++.panel-workspace-indicator-box .workspace.active { ++ background-color: rgba(200, 200, 200, .5); ++} ++ ++.panel-workspace-indicator-box .workspace { ++ background-color: rgba(200, 200, 200, .3); ++ border-left-width: 0; ++} ++ ++.panel-workspace-indicator-box .workspace:first-child { ++ border-left-width: 1px; ++} +-- +2.21.0 + + +From 58496daaf5591e86238d7ab7f470b5ad7797b3e3 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 28 Jun 2019 11:33:16 +0200 +Subject: [PATCH 28/30] workspace-indicator: Show previews in workspace + switcher + +Currently the new horizontal workspace switcher only shows a series of +buttons, with no indication of the workspaces' contents. Go full GNOME 2 +and add tiny draggable preview rectangles that represent the windows +on a particular workspace. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/77 +--- + extensions/workspace-indicator/extension.js | 194 +++++++++++++++++- + extensions/workspace-indicator/stylesheet.css | 22 +- + 2 files changed, 209 insertions(+), 7 deletions(-) + +diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js +index 48019da..69eef88 100644 +--- a/extensions/workspace-indicator/extension.js ++++ b/extensions/workspace-indicator/extension.js +@@ -2,28 +2,199 @@ + /* exported init enable disable */ + + const { Clutter, Gio, GObject, Meta, St } = imports.gi; ++ ++const DND = imports.ui.dnd; ++const ExtensionUtils = imports.misc.extensionUtils; ++const Main = imports.ui.main; + const PanelMenu = imports.ui.panelMenu; + const PopupMenu = imports.ui.popupMenu; + + const Gettext = imports.gettext.domain('gnome-shell-extensions'); + const _ = Gettext.gettext; + +-const Main = imports.ui.main; +- +-const ExtensionUtils = imports.misc.extensionUtils; +- + const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; + const WORKSPACE_KEY = 'workspace-names'; + ++let WindowPreview = GObject.registerClass({ ++ GTypeName: 'WorkspaceIndicatorWindowPreview' ++}, class WindowPreview extends St.Button { ++ _init(window) { ++ super._init({ ++ style_class: 'workspace-indicator-window-preview' ++ }); ++ ++ this._delegate = this; ++ DND.makeDraggable(this, { restoreOnSuccess: true }); ++ ++ this._window = window; ++ ++ this.connect('destroy', this._onDestroy.bind(this)); ++ ++ this._sizeChangedId = this._window.connect('size-changed', ++ this._relayout.bind(this)); ++ this._positionChangedId = this._window.connect('position-changed', ++ this._relayout.bind(this)); ++ this._minimizedChangedId = this._window.connect('notify::minimized', ++ this._relayout.bind(this)); ++ this._monitorEnteredId = global.display.connect('window-entered-monitor', ++ this._relayout.bind(this)); ++ this._monitorLeftId = global.display.connect('window-left-monitor', ++ this._relayout.bind(this)); ++ ++ // Do initial layout when we get a parent ++ let id = this.connect('parent-set', () => { ++ this.disconnect(id); ++ if (!this.get_parent()) ++ return; ++ this._laterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { ++ this._laterId = 0; ++ this._relayout(); ++ return false; ++ }); ++ }); ++ ++ this._focusChangedId = global.display.connect('notify::focus-window', ++ this._onFocusChanged.bind(this)); ++ this._onFocusChanged(); ++ } ++ ++ // needed for DND ++ get realWindow() { ++ return this._window.get_compositor_private(); ++ } ++ ++ _onDestroy() { ++ this._window.disconnect(this._sizeChangedId); ++ this._window.disconnect(this._positionChangedId); ++ this._window.disconnect(this._minimizedChangedId); ++ global.display.disconnect(this._monitorEnteredId); ++ global.display.disconnect(this._monitorLeftId); ++ global.display.disconnect(this._focusChangedId); ++ if (this._laterId) ++ Meta.later_remove(this._laterId); ++ } ++ ++ _onFocusChanged() { ++ if (global.display.focus_window == this._window) ++ this.add_style_class_name('active'); ++ else ++ this.remove_style_class_name('active'); ++ } ++ ++ _relayout() { ++ let monitor = Main.layoutManager.findIndexForActor(this); ++ this.visible = monitor == this._window.get_monitor() && ++ this._window.showing_on_its_workspace(); ++ ++ if (!this.visible) ++ return; ++ ++ let workArea = Main.layoutManager.getWorkAreaForMonitor(monitor); ++ let hscale = this.get_parent().allocation.get_width() / workArea.width; ++ let vscale = this.get_parent().allocation.get_height() / workArea.height; ++ ++ let frameRect = this._window.get_frame_rect(); ++ this.set_size( ++ Math.round(Math.min(frameRect.width, workArea.width) * hscale), ++ Math.round(Math.min(frameRect.height, workArea.height) * vscale)); ++ this.set_position( ++ Math.round(frameRect.x * hscale), ++ Math.round(frameRect.y * vscale)); ++ } ++}); ++ + let WorkspaceThumbnail = GObject.registerClass({ + GTypeName: 'WorkspaceIndicatorWorkspaceThumbnail' + }, class WorkspaceThumbnail extends St.Button { + _init(index) { + super._init({ + style_class: 'workspace', ++ child: new Clutter.Actor({ ++ layout_manager: new Clutter.BinLayout(), ++ clip_to_allocation: true ++ }), ++ x_fill: true, ++ y_fill: true + }); + ++ this.connect('destroy', this._onDestroy.bind(this)); ++ + this._index = index; ++ this._delegate = this; // needed for DND ++ ++ this._windowPreviews = new Map(); ++ ++ let workspaceManager = global.workspace_manager; ++ this._workspace = workspaceManager.get_workspace_by_index(index); ++ ++ this._windowAddedId = this._workspace.connect('window-added', ++ (ws, window) => { ++ this._addWindow(window); ++ }); ++ this._windowRemovedId = this._workspace.connect('window-removed', ++ (ws, window) => { ++ this._removeWindow(window); ++ }); ++ this._restackedId = global.display.connect('restacked', ++ this._onRestacked.bind(this)); ++ ++ this._workspace.list_windows().forEach(w => this._addWindow(w)); ++ this._onRestacked(); ++ } ++ ++ acceptDrop(source) { ++ if (!source.realWindow) ++ return false; ++ ++ let window = source.realWindow.get_meta_window(); ++ this._moveWindow(window); ++ return true; ++ } ++ ++ handleDragOver(source) { ++ if (source.realWindow) ++ return DND.DragMotionResult.MOVE_DROP; ++ else ++ return DND.DragMotionResult.CONTINUE; ++ } ++ ++ _addWindow(window) { ++ if (this._windowPreviews.has(window)) ++ return; ++ ++ let preview = new WindowPreview(window); ++ preview.connect('clicked', (a, btn) => this.emit('clicked', btn)); ++ this._windowPreviews.set(window, preview); ++ this.child.add_child(preview); ++ } ++ ++ _removeWindow(window) { ++ let preview = this._windowPreviews.get(window); ++ if (!preview) ++ return; ++ ++ this._windowPreviews.delete(window); ++ preview.destroy(); ++ } ++ ++ _onRestacked() { ++ let lastPreview = null; ++ let windows = global.get_window_actors().map(a => a.meta_window); ++ for (let i = 0; i < windows.length; i++) { ++ let preview = this._windowPreviews.get(windows[i]); ++ if (!preview) ++ continue; ++ ++ this.child.set_child_above_sibling(preview, lastPreview); ++ lastPreview = preview; ++ } ++ } ++ ++ _moveWindow(window) { ++ let monitorIndex = Main.layoutManager.findIndexForActor(this); ++ if (monitorIndex != window.get_monitor()) ++ window.move_to_monitor(monitorIndex); ++ window.change_workspace_by_index(this._index, false); + } + + // eslint-disable-next-line camelcase +@@ -32,8 +203,13 @@ let WorkspaceThumbnail = GObject.registerClass({ + if (ws) + ws.activate(global.get_current_time()); + } +-}); + ++ _onDestroy() { ++ this._workspace.disconnect(this._windowAddedId); ++ this._workspace.disconnect(this._windowRemovedId); ++ global.display.disconnect(this._restackedId); ++ } ++}); + + let WorkspaceIndicator = GObject.registerClass( + class WorkspaceIndicator extends PanelMenu.Button { +@@ -100,6 +276,8 @@ class WorkspaceIndicator extends PanelMenu.Button { + this._settingsChangedId = 0; + } + ++ Main.panel.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); ++ + super._onDestroy(); + } + +@@ -109,6 +287,12 @@ class WorkspaceIndicator extends PanelMenu.Button { + + this._statusLabel.visible = vertical; + this._thumbnailsBox.visible = !vertical; ++ ++ // Disable offscreen-redirect when showing the workspace switcher ++ // so that clip-to-allocation works ++ Main.panel.set_offscreen_redirect(vertical ++ ? Clutter.OffscreenRedirect.ALWAYS ++ : Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY); + } + + _onWorkspaceSwitched() { +diff --git a/extensions/workspace-indicator/stylesheet.css b/extensions/workspace-indicator/stylesheet.css +index a15081e..8c101e7 100644 +--- a/extensions/workspace-indicator/stylesheet.css ++++ b/extensions/workspace-indicator/stylesheet.css +@@ -1,9 +1,17 @@ +-.panel-workspace-indicator, +-.panel-workspace-indicator-box .workspace { ++.panel-workspace-indicator { + padding: 0 8px; + border: 1px solid #cccccc; + } + ++.panel-workspace-indicator-box { ++ padding: 2px 0; ++} ++ ++.panel-workspace-indicator-box .workspace { ++ border: 1px solid #cccccc; ++ width: 48px; ++} ++ + .panel-workspace-indicator, + .panel-workspace-indicator-box .workspace.active { + background-color: rgba(200, 200, 200, .5); +@@ -17,3 +25,13 @@ + .panel-workspace-indicator-box .workspace:first-child { + border-left-width: 1px; + } ++ ++.workspace-indicator-window-preview { ++ background-color: #252525; ++ border: 1px solid #ccc; ++} ++ ++.workspace-indicator-window-preview { ++ background-color: #353535; ++ border: 2px solid #ccc; ++} +-- +2.21.0 + + +From 06674bf6aff9fb4ae2224a448ba928c1687b5f6b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 2 Jul 2019 17:39:55 +0200 +Subject: [PATCH 29/30] window-list: Move super-key handling into WindowPicker + +We have an option to put a window list on each monitor, so we may have +more than one window picker toggle. We don't want each of those try to +toggle the window picker simultanuously, so move handling of the super +key directly into the picker. + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/80 +--- + extensions/window-list/windowPicker.js | 34 ++++++++++++-------------- + 1 file changed, 15 insertions(+), 19 deletions(-) + +diff --git a/extensions/window-list/windowPicker.js b/extensions/window-list/windowPicker.js +index 024fd80..ba0a697 100644 +--- a/extensions/window-list/windowPicker.js ++++ b/extensions/window-list/windowPicker.js +@@ -67,6 +67,8 @@ var WindowPicker = class { + this._visible = false; + this._modal = false; + ++ this._overlayKeyId = 0; ++ + this.actor = new Clutter.Actor(); + + this.actor.connect('destroy', this._onDestroy.bind(this)); +@@ -101,6 +103,15 @@ var WindowPicker = class { + this._updateBackgrounds(); + + Main.uiGroup.insert_child_below(this.actor, global.window_group); ++ ++ if (!Main.sessionMode.hasOverview) { ++ this._overlayKeyId = global.display.connect('overlay-key', () => { ++ if (!this._visible) ++ this.open(); ++ else ++ this.close(); ++ }); ++ } + } + + get visible() { +@@ -188,6 +199,10 @@ var WindowPicker = class { + if (this._monitorsChangedId) + Main.layoutManager.disconnect(this._monitorsChangedId); + this._monitorsChangedId = 0; ++ ++ if (this._overlayKeyId) ++ global.display.disconnect(this._overlayKeyId); ++ this._overlayKeyId = 0; + } + + _updateBackgrounds() { +@@ -227,10 +242,6 @@ class WindowPickerToggle extends St.Button { + toggle_mode: true + }); + +- this._overlayKeyId = 0; +- +- this.connect('destroy', this._onDestroy.bind(this)); +- + this.connect('notify::checked', () => { + if (this.checked) + Main.windowPicker.open(); +@@ -238,23 +249,8 @@ class WindowPickerToggle extends St.Button { + Main.windowPicker.close(); + }); + +- if (!Main.sessionMode.hasOverview) { +- this._overlayKeyId = global.display.connect('overlay-key', () => { +- if (!Main.windowPicker.visible) +- Main.windowPicker.open(); +- else +- Main.windowPicker.close(); +- }); +- } +- + Main.windowPicker.connect('open-state-changed', () => { + this.checked = Main.windowPicker.visible; + }); + } +- +- _onDestroy() { +- if (this._overlayKeyId) +- global.display.disconnect(this._overlayKeyId); +- this._overlayKeyId == 0; +- } + }); +-- +2.21.0 + + +From c37d082487cce3548844c150d1976bf1735552c8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 2 Jul 2019 18:12:31 +0200 +Subject: [PATCH 30/30] window-list: Handle closing window picker with Escape + +Just like the overview can be closed with Escape, it makes sense to +allow the same for the window picker (in addition to pressing super +repeatedly). + +https://gitlab.gnome.org/GNOME/gnome-shell-extensions/merge_requests/80 +--- + extensions/window-list/windowPicker.js | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/extensions/window-list/windowPicker.js b/extensions/window-list/windowPicker.js +index ba0a697..12a7627 100644 +--- a/extensions/window-list/windowPicker.js ++++ b/extensions/window-list/windowPicker.js +@@ -68,6 +68,7 @@ var WindowPicker = class { + this._modal = false; + + this._overlayKeyId = 0; ++ this._stageKeyPressId = 0; + + this.actor = new Clutter.Actor(); + +@@ -132,6 +133,16 @@ var WindowPicker = class { + this._fakeOverviewAnimation(); + this._workspacesDisplay.show(false); + ++ this._stageKeyPressId = global.stage.connect('key-press-event', ++ (a, event) => { ++ let sym = event.get_key_symbol(); ++ if (sym == Clutter.KEY_Escape) { ++ this.close(); ++ return Clutter.EVENT_STOP; ++ } ++ return Clutter.EVENT_PROPAGATE; ++ }); ++ + this.emit('open-state-changed', this._visible); + } + +@@ -151,6 +162,9 @@ var WindowPicker = class { + this._fakeOverviewVisible(false); + }); + ++ global.stage.disconnect(this._stageKeyPressId); ++ this._stageKeyPressId = 0; ++ + this.emit('open-state-changed', this._visible); + } + +@@ -203,6 +217,10 @@ var WindowPicker = class { + if (this._overlayKeyId) + global.display.disconnect(this._overlayKeyId); + this._overlayKeyId = 0; ++ ++ if (this._stageKeyPressId) ++ global.stage.disconnect(this._stageKeyPressId); ++ this._stageKeyPressId = 0; + } + + _updateBackgrounds() { +-- +2.21.0 + diff --git a/SOURCES/resurrect-system-monitor.patch b/SOURCES/resurrect-system-monitor.patch index 5e8829e..9c4daf4 100644 --- a/SOURCES/resurrect-system-monitor.patch +++ b/SOURCES/resurrect-system-monitor.patch @@ -1,7 +1,7 @@ -From 901e1b32939d27b0b0edabe99705fd3066d360ba Mon Sep 17 00:00:00 2001 +From 7c3b0af4fde0b542089f2b0c84250404eef0ecca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 17 May 2017 19:13:50 +0200 -Subject: [PATCH 1/4] extensions: Resurrect systemMonitor extension +Subject: [PATCH 1/5] extensions: Resurrect systemMonitor extension The extension was removed upstream because: - it hooks into the message tray that was removed @@ -476,134 +476,419 @@ index 0000000..13f95ec + font-weight: bold; +} diff --git a/meson.build b/meson.build -index 201c484..cde2d34 100644 +index 6e8c41f..6764f9a 100644 --- a/meson.build +++ b/meson.build -@@ -57,6 +57,7 @@ all_extensions += [ +@@ -55,6 +55,7 @@ all_extensions += [ 'native-window-placement', 'no-hot-corner', 'panel-favorites', + 'systemMonitor', 'top-icons', 'updates-dialog', - 'user-theme' + 'user-theme', -- -2.20.1 +2.21.0 -From a0583c021dd74378618139d760b2c4d6d528f11a Mon Sep 17 00:00:00 2001 +From ddf4d70df56321366a2cb8b89689d59be4dbb718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= -Date: Wed, 17 May 2017 19:31:58 +0200 -Subject: [PATCH 2/4] systemMonitor: Move indicators to calendar +Date: Fri, 17 May 2019 22:55:48 +0000 +Subject: [PATCH 2/5] systemMonitor: Modernise code -The message tray joined the invisible choir, so we have to find -a new home for the extension UI. The message list in the calendar -drop-down looks like the best option, given that it replaced the -old tray (and also took over the old keyboard shortcut to bring -it up quickly). + - port to ES6 classes + - replace Lang.bind() + - destructure imports + - fix style issues (stray/missing spaces/semi-colons, indent, ...) --- - extensions/systemMonitor/extension.js | 56 ++++++++++++------------- - extensions/systemMonitor/stylesheet.css | 14 ------- - 2 files changed, 28 insertions(+), 42 deletions(-) + extensions/systemMonitor/extension.js | 377 +++++++++++++------------- + 1 file changed, 192 insertions(+), 185 deletions(-) diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js -index 7b09df0..1388a1f 100644 +index 7b09df0..89f8916 100644 --- a/extensions/systemMonitor/extension.js +++ b/extensions/systemMonitor/extension.js -@@ -4,10 +4,12 @@ const Clutter = imports.gi.Clutter; - const GTop = imports.gi.GTop; - const Lang = imports.lang; - const Mainloop = imports.mainloop; -+const Signals = imports.signals; - const St = imports.gi.St; - const Shell = imports.gi.Shell; +@@ -1,22 +1,16 @@ + /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ +-const Clutter = imports.gi.Clutter; +-const GTop = imports.gi.GTop; +-const Lang = imports.lang; +-const Mainloop = imports.mainloop; +-const St = imports.gi.St; +-const Shell = imports.gi.Shell; ++/* exported init */ + ++const { Clutter, GLib, GTop, Shell, St } = imports.gi; ++ ++const ExtensionUtils = imports.misc.extensionUtils; const Main = imports.ui.main; -+const MessageList = imports.ui.messageList; const Tweener = imports.ui.tweener; const Gettext = imports.gettext.domain('gnome-shell-extensions'); -@@ -29,18 +31,21 @@ const Indicator = new Lang.Class({ + const _ = Gettext.gettext; + +-const ExtensionUtils = imports.misc.extensionUtils; +-const Me = ExtensionUtils.getCurrentExtension(); +-const Convenience = Me.imports.convenience; +- + const INDICATOR_UPDATE_INTERVAL = 500; + const INDICATOR_NUM_GRID_LINES = 3; - _init: function() { +@@ -24,32 +18,38 @@ const ITEM_LABEL_SHOW_TIME = 0.15; + const ITEM_LABEL_HIDE_TIME = 0.1; + const ITEM_HOVER_TIMEOUT = 300; + +-const Indicator = new Lang.Class({ +- Name: 'SystemMonitor.Indicator', +- +- _init: function() { ++const Indicator = class { ++ constructor() { this._initValues(); - this.drawing_area = new St.DrawingArea({ reactive: true }); -+ this.drawing_area = new St.DrawingArea(); - this.drawing_area.connect('repaint', Lang.bind(this, this._draw)); +- this.drawing_area.connect('repaint', Lang.bind(this, this._draw)); - this.drawing_area.connect('button-press-event', function() { -+ -+ this.actor = new St.Button({ style_class: "message message-content extension-systemMonitor-indicator-area", -+ x_expand: true, x_fill: true, -+ y_fill: true, can_focus: true }); -+ this.actor.add_actor(this.drawing_area); -+ -+ this.actor.connect('clicked', function() { ++ this._drawingArea = new St.DrawingArea({ reactive: true }); ++ this._drawingArea.connect('repaint', this._draw.bind(this)); ++ this._drawingArea.connect('button-press-event', () => { let app = Shell.AppSystem.get_default().lookup_app('gnome-system-monitor.desktop'); app.open_new_window(-1); -- return true; -- }); + return true; + }); - this.actor = new St.Bin({ style_class: "extension-systemMonitor-indicator-area", - reactive: true, track_hover: true, - x_fill: true, y_fill: true }); - this.actor.add_actor(this.drawing_area); -+ Main.overview.hide(); -+ Main.panel.closeCalendar(); ++ this.actor = new St.Bin({ ++ style_class: 'extension-systemMonitor-indicator-area', ++ reactive: true, ++ track_hover: true, ++ x_fill: true, ++ y_fill: true + }); ++ this.actor.add_actor(this._drawingArea); - this._timeout = Mainloop.timeout_add(INDICATOR_UPDATE_INTERVAL, Lang.bind(this, function () { - this._updateValues(); -@@ -73,6 +78,7 @@ const Indicator = new Lang.Class({ +- this._timeout = Mainloop.timeout_add(INDICATOR_UPDATE_INTERVAL, Lang.bind(this, function () { +- this._updateValues(); +- this.drawing_area.queue_repaint(); +- return true; +- })); +- }, ++ this.actor.connect('destroy', this._onDestroy.bind(this)); + +- showLabel: function() { ++ this._timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, ++ INDICATOR_UPDATE_INTERVAL, ++ () => { ++ this._updateValues(); ++ this._drawingArea.queue_repaint(); ++ return GLib.SOURCE_CONTINUE; ++ }); ++ } ++ ++ showLabel() { + if (this.label == null) + return; + +@@ -58,12 +58,10 @@ const Indicator = new Lang.Class({ + + let [stageX, stageY] = this.actor.get_transformed_position(); + +- let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1; +- let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1; ++ let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1; + +- let labelWidth = this.label.width; +- let labelHeight = this.label.height; +- let xOffset = Math.floor((itemWidth - labelWidth) / 2) ++ let labelWidth = this.label.width; ++ let xOffset = Math.floor((itemWidth - labelWidth) / 2); + + let x = stageX + xOffset; + +@@ -73,48 +71,51 @@ const Indicator = new Lang.Class({ let y = stageY - this.label.get_height() - yOffset; this.label.set_position(x, y); -+ this.label.get_parent().set_child_above_sibling(this.label, null); - Tweener.addTween(this.label, - { opacity: 255, - time: ITEM_LABEL_SHOW_TIME, -@@ -100,6 +106,14 @@ const Indicator = new Lang.Class({ - }); - }, +- Tweener.addTween(this.label, +- { opacity: 255, +- time: ITEM_LABEL_SHOW_TIME, +- transition: 'easeOutQuad', +- }); +- }, +- +- setLabelText: function(text) { ++ Tweener.addTween(this.label, { ++ opacity: 255, ++ time: ITEM_LABEL_SHOW_TIME, ++ transition: 'easeOutQuad', ++ }); ++ } ++ ++ setLabelText(text) { + if (this.label == null) +- this.label = new St.Label({ style_class: 'extension-systemMonitor-indicator-label'}); ++ this.label = new St.Label({ ++ style_class: 'extension-systemMonitor-indicator-label' ++ }); -+ /* MessageList.Message boilerplate */ -+ canClose: function() { -+ return false; -+ }, + this.label.set_text(text); + Main.layoutManager.addChrome(this.label); + this.label.hide(); +- }, +- +- hideLabel: function () { +- Tweener.addTween(this.label, +- { opacity: 0, +- time: ITEM_LABEL_HIDE_TIME, +- transition: 'easeOutQuad', +- onComplete: Lang.bind(this, function() { +- this.label.hide(); +- }) +- }); +- }, +- +- destroy: function() { +- Mainloop.source_remove(this._timeout); ++ } + ++ hideLabel() { ++ Tweener.addTween(this.label, { ++ opacity: 0, ++ time: ITEM_LABEL_HIDE_TIME, ++ transition: 'easeOutQuad', ++ onComplete: () => this.label.hide() ++ }); ++ } + -+ clear: function() { -+ }, ++ destroy() { + this.actor.destroy(); +- if (this.label) +- this.label.destroy(); +- }, ++ } ++ ++ _onDestroy() { ++ GLib.source_remove(this._timeout); + - destroy: function() { - Mainloop.source_remove(this._timeout); ++ if (this.label) ++ this.label.destroy(); ++ } + +- _initValues: function() { +- }, ++ _initValues() { ++ } -@@ -194,6 +208,7 @@ const Indicator = new Lang.Class({ +- _updateValues: function() { +- }, ++ _updateValues() { ++ } + +- _draw: function(area) { ++ _draw(area) { + let [width, height] = area.get_surface_size(); + let themeNode = this.actor.get_theme_node(); + let cr = area.get_context(); +@@ -123,12 +124,12 @@ const Indicator = new Lang.Class({ + let color = themeNode.get_color(this.gridColor); + let gridOffset = Math.floor(height / (INDICATOR_NUM_GRID_LINES + 1)); + for (let i = 1; i <= INDICATOR_NUM_GRID_LINES; ++i) { +- cr.moveTo(0, i * gridOffset + .5); +- cr.lineTo(width, i * gridOffset + .5); ++ cr.moveTo(0, i * gridOffset + .5); ++ cr.lineTo(width, i * gridOffset + .5); + } + Clutter.cairo_set_source_color(cr, color); + cr.setLineWidth(1); +- cr.setDash([4,1], 0); ++ cr.setDash([4, 1], 0); + cr.stroke(); + + //draw the foreground +@@ -155,12 +156,12 @@ const Indicator = new Lang.Class({ + let renderStats = this.renderStats; + + // Make sure we don't have more sample points than pixels +- renderStats.map(Lang.bind(this, function(k){ ++ renderStats.map(k => { + let stat = this.stats[k]; + if (stat.values.length > width) { + stat.values = stat.values.slice(stat.values.length - width, stat.values.length); + } +- })); ++ }); + + for (let i = 0; i < renderStats.length; ++i) { + let stat = this.stats[renderStats[i]]; +@@ -178,10 +179,10 @@ const Indicator = new Lang.Class({ + cr.lineTo(0, height); + cr.closePath(); + } else { +- let nextStat = this.stats[renderStats[i+1]]; ++ let nextStat = this.stats[renderStats[i + 1]]; + makePath(nextStat.values, true); + } +- cr.closePath() ++ cr.closePath(); + Clutter.cairo_set_source_color(cr, color); + cr.fill(); + +@@ -193,40 +194,42 @@ const Indicator = new Lang.Class({ + cr.stroke(); } } - }); -+Signals.addSignalMethods(Indicator.prototype); // For MessageList.Message compat +-}); +- +-const CpuIndicator = new Lang.Class({ +- Name: 'SystemMonitor.CpuIndicator', +- Extends: Indicator, ++}; - const CpuIndicator = new Lang.Class({ - Name: 'SystemMonitor.CpuIndicator', -@@ -302,9 +317,7 @@ const Extension = new Lang.Class({ - }, +- _init: function() { +- this.parent(); ++const CpuIndicator = class extends Indicator { ++ constructor() { ++ super(); - enable: function() { + this.gridColor = '-grid-color'; +- this.renderStats = [ 'cpu-user', 'cpu-sys', 'cpu-iowait' ]; ++ this.renderStats = ['cpu-user', 'cpu-sys', 'cpu-iowait']; + + // Make sure renderStats is sorted as necessary for rendering +- let renderStatOrder = {'cpu-total': 0, 'cpu-user': 1, 'cpu-sys': 2, 'cpu-iowait': 3}; +- this.renderStats = this.renderStats.sort(function(a,b) { ++ let renderStatOrder = { ++ 'cpu-total': 0, ++ 'cpu-user': 1, ++ 'cpu-sys': 2, ++ 'cpu-iowait': 3 ++ }; ++ this.renderStats = this.renderStats.sort((a, b) => { + return renderStatOrder[a] - renderStatOrder[b]; + }); + +- this.setLabelText(_("CPU")); +- }, ++ this.setLabelText(_('CPU')); ++ } + +- _initValues: function() { ++ _initValues() { + this._prev = new GTop.glibtop_cpu; + GTop.glibtop_get_cpu(this._prev); + + this.stats = { +- 'cpu-user': {color: '-cpu-user-color', values: []}, +- 'cpu-sys': {color: '-cpu-sys-color', values: []}, +- 'cpu-iowait': {color: '-cpu-iowait-color', values: []}, +- 'cpu-total': {color: '-cpu-total-color', values: []} +- }; +- }, +- +- _updateValues: function() { ++ 'cpu-user': { color: '-cpu-user-color', values: [] }, ++ 'cpu-sys': { color: '-cpu-sys-color', values: [] }, ++ 'cpu-iowait': { color: '-cpu-iowait-color', values: [] }, ++ 'cpu-total': { color: '-cpu-total-color', values: [] } ++ }; ++ } ++ ++ _updateValues() { + let cpu = new GTop.glibtop_cpu; + let t = 0.0; + GTop.glibtop_get_cpu(cpu); +@@ -246,37 +249,34 @@ const CpuIndicator = new Lang.Class({ + + this._prev = cpu; + } +-}); ++}; + +-const MemoryIndicator = new Lang.Class({ +- Name: 'SystemMonitor.MemoryIndicator', +- Extends: Indicator, +- +- _init: function() { +- this.parent(); ++const MemoryIndicator = class extends Indicator { ++ constructor() { ++ super(); + + this.gridColor = '-grid-color'; +- this.renderStats = [ 'mem-user', 'mem-other', 'mem-cached' ]; ++ this.renderStats = ['mem-user', 'mem-other', 'mem-cached']; + + // Make sure renderStats is sorted as necessary for rendering + let renderStatOrder = { 'mem-cached': 0, 'mem-other': 1, 'mem-user': 2 }; +- this.renderStats = this.renderStats.sort(function(a,b) { ++ this.renderStats = this.renderStats.sort((a, b) => { + return renderStatOrder[a] - renderStatOrder[b]; + }); + +- this.setLabelText(_("Memory")); +- }, ++ this.setLabelText(_('Memory')); ++ } + +- _initValues: function() { ++ _initValues() { + this.mem = new GTop.glibtop_mem; + this.stats = { +- 'mem-user': { color: "-mem-user-color", values: [] }, +- 'mem-other': { color: "-mem-other-color", values: [] }, +- 'mem-cached': { color: "-mem-cached-color", values: [] } +- }; +- }, ++ 'mem-user': { color: '-mem-user-color', values: [] }, ++ 'mem-other': { color: '-mem-other-color', values: [] }, ++ 'mem-cached': { color: '-mem-cached-color', values: [] } ++ }; ++ } + +- _updateValues: function() { ++ _updateValues() { + GTop.glibtop_get_mem(this.mem); + + let t = this.mem.user / this.mem.total; +@@ -286,90 +286,97 @@ const MemoryIndicator = new Lang.Class({ + t += this.mem.cached / this.mem.total; + this.stats['mem-cached'].values.push(t); + } +-}); ++}; + + const INDICATORS = [CpuIndicator, MemoryIndicator]; + +-const Extension = new Lang.Class({ +- Name: 'SystemMonitor.Extension', +- +- _init: function() { +- Convenience.initTranslations(); +- +- this._showLabelTimeoutId = 0; +- this._resetHoverTimeoutId = 0; +- this._labelShowing = false; +- }, +- +- enable: function() { - this._box = new St.BoxLayout({ style_class: 'extension-systemMonitor-container', - x_align: Clutter.ActorAlign.START, - x_expand: true }); -+ this._section = new MessageList.MessageListSection(_("System Monitor")); - this._indicators = [ ]; - - for (let i = 0; i < INDICATORS.length; i++) { -@@ -313,31 +326,18 @@ const Extension = new Lang.Class({ - indicator.actor.connect('notify::hover', Lang.bind(this, function() { - this._onHover(indicator); - })); +- this._indicators = [ ]; +- +- for (let i = 0; i < INDICATORS.length; i++) { +- let indicator = new (INDICATORS[i])(); +- +- indicator.actor.connect('notify::hover', Lang.bind(this, function() { +- this._onHover(indicator); +- })); - this._box.add_actor(indicator.actor); -+ this._section.addMessage(indicator, false); - this._indicators.push(indicator); - } - +- this._indicators.push(indicator); +- } +- - this._boxHolder = new St.BoxLayout({ x_expand: true, - y_expand: true, - x_align: Clutter.ActorAlign.START, @@ -614,23 +899,285 @@ index 7b09df0..1388a1f 100644 - - this._boxHolder.add_child(this._box); - this._boxHolder.add_child(menuButton); -+ Main.panel.statusArea.dateMenu._messageList._addSection(this._section); -+ this._section.actor.get_parent().set_child_at_index(this._section.actor, 0); - }, - - disable: function() { - this._indicators.forEach(function(i) { i.destroy(); }); - +- }, +- +- disable: function() { +- this._indicators.forEach(function(i) { i.destroy(); }); +- - let menuButton = Main.messageTray._messageTrayMenuButton.actor; - this._boxHolder.remove_child(menuButton); - Main.messageTray.actor.add_child(menuButton); - - this._box.destroy(); - this._boxHolder.destroy(); +- }, +- +- _onHover: function (item) { ++class Extension { ++ constructor() { ++ ExtensionUtils.initTranslations(); ++ ++ this._showLabelTimeoutId = 0; ++ this._resetHoverTimeoutId = 0; ++ this._labelShowing = false; ++ } ++ ++ enable() { ++ this._box = new St.BoxLayout({ ++ style_class: 'extension-systemMonitor-container', ++ x_align: Clutter.ActorAlign.START, ++ x_expand: true ++ }); ++ this._indicators = []; ++ ++ for (let i = 0; i < INDICATORS.length; i++) { ++ let indicator = new (INDICATORS[i])(); ++ ++ indicator.actor.connect('notify::hover', () => { ++ this._onHover(indicator); ++ }); ++ this._box.add_actor(indicator.actor); ++ this._indicators.push(indicator); ++ } ++ ++ this._boxHolder = new St.BoxLayout({ ++ x_expand: true, ++ y_expand: true, ++ x_align: Clutter.ActorAlign.START, ++ }); ++ let menuButton = Main.messageTray._messageTrayMenuButton.actor; ++ Main.messageTray.actor.remove_child(menuButton); ++ Main.messageTray.actor.add_child(this._boxHolder); ++ ++ this._boxHolder.add_child(this._box); ++ this._boxHolder.add_child(menuButton); ++ } ++ ++ disable() { ++ this._indicators.forEach(i => i.destroy()); ++ ++ let menuButton = Main.messageTray._messageTrayMenuButton.actor; ++ this._boxHolder.remove_child(menuButton); ++ Main.messageTray.actor.add_child(menuButton); ++ ++ this._box.destroy(); ++ this._boxHolder.destroy(); ++ } ++ ++ _onHover(item) { + if (item.actor.get_hover()) { +- if (this._showLabelTimeoutId == 0) { +- let timeout = this._labelShowing ? 0 : ITEM_HOVER_TIMEOUT; +- this._showLabelTimeoutId = Mainloop.timeout_add(timeout, +- Lang.bind(this, function() { +- this._labelShowing = true; +- item.showLabel(); +- return false; +- })); +- if (this._resetHoverTimeoutId > 0) { +- Mainloop.source_remove(this._resetHoverTimeoutId); +- this._resetHoverTimeoutId = 0; +- } ++ if (this._showLabelTimeoutId) ++ return; ++ ++ let timeout = this._labelShowing ? 0 : ITEM_HOVER_TIMEOUT; ++ this._showLabelTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, ++ timeout, ++ () => { ++ this._labelShowing = true; ++ item.showLabel(); ++ this._showLabelTimeoutId = 0; ++ return GLib.SOURCE_REMOVE; ++ }); ++ ++ if (this._resetHoverTimeoutId > 0) { ++ GLib.source_remove(this._resetHoverTimeoutId); ++ this._resetHoverTimeoutId = 0; + } + } else { + if (this._showLabelTimeoutId > 0) +- Mainloop.source_remove(this._showLabelTimeoutId); ++ GLib.source_remove(this._showLabelTimeoutId); + this._showLabelTimeoutId = 0; + item.hideLabel(); +- if (this._labelShowing) { +- this._resetHoverTimeoutId = Mainloop.timeout_add(ITEM_HOVER_TIMEOUT, +- Lang.bind(this, function() { +- this._labelShowing = false; +- return false; +- })); +- } ++ if (!this._labelShowing) ++ return; ++ ++ this._resetHoverTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, ++ ITEM_HOVER_TIMEOUT, ++ () => { ++ this._labelShowing = false; ++ return GLib.SOURCE_REMOVE; ++ }); + } +- }, +-}); ++ } ++} + + function init() { + return new Extension(); +-- +2.21.0 + + +From e7ea49cd416e8ede9767f5ade46a06764d1e9a5b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 17 May 2017 19:31:58 +0200 +Subject: [PATCH 3/5] systemMonitor: Move indicators to calendar + +The message tray joined the invisible choir, so we have to find +a new home for the extension UI. The message list in the calendar +drop-down looks like the best option, given that it replaced the +old tray (and also took over the old keyboard shortcut to bring +it up quickly). +--- + extensions/systemMonitor/extension.js | 65 ++++++++++++------------- + extensions/systemMonitor/stylesheet.css | 14 ------ + 2 files changed, 31 insertions(+), 48 deletions(-) + +diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js +index 89f8916..0188960 100644 +--- a/extensions/systemMonitor/extension.js ++++ b/extensions/systemMonitor/extension.js +@@ -3,9 +3,11 @@ + /* exported init */ + + const { Clutter, GLib, GTop, Shell, St } = imports.gi; ++const Signals = imports.signals; + + const ExtensionUtils = imports.misc.extensionUtils; + const Main = imports.ui.main; ++const MessageList = imports.ui.messageList; + const Tweener = imports.ui.tweener; + + const Gettext = imports.gettext.domain('gnome-shell-extensions'); +@@ -21,22 +23,25 @@ const ITEM_HOVER_TIMEOUT = 300; + const Indicator = class { + constructor() { + this._initValues(); +- this._drawingArea = new St.DrawingArea({ reactive: true }); ++ this._drawingArea = new St.DrawingArea(); + this._drawingArea.connect('repaint', this._draw.bind(this)); +- this._drawingArea.connect('button-press-event', () => { ++ ++ this.actor = new St.Button({ ++ style_class: 'message message-content extension-systemMonitor-indicator-area', ++ child: this._drawingArea, ++ x_expand: true, ++ x_fill: true, ++ y_fill: true, ++ can_focus: true ++ }); ++ ++ this.actor.connect('clicked', () => { + let app = Shell.AppSystem.get_default().lookup_app('gnome-system-monitor.desktop'); + app.open_new_window(-1); +- return true; +- }); + +- this.actor = new St.Bin({ +- style_class: 'extension-systemMonitor-indicator-area', +- reactive: true, +- track_hover: true, +- x_fill: true, +- y_fill: true ++ Main.overview.hide(); ++ Main.panel.closeCalendar(); + }); +- this.actor.add_actor(this._drawingArea); + + this.actor.connect('destroy', this._onDestroy.bind(this)); + +@@ -71,6 +76,7 @@ const Indicator = class { + let y = stageY - this.label.get_height() - yOffset; + + this.label.set_position(x, y); ++ this.label.get_parent().set_child_above_sibling(this.label, null); + Tweener.addTween(this.label, { + opacity: 255, + time: ITEM_LABEL_SHOW_TIME, +@@ -98,6 +104,14 @@ const Indicator = class { + }); + } + ++ /* MessageList.Message boilerplate */ ++ canClose() { ++ return false; ++ } ++ ++ clear() { ++ } ++ + destroy() { + this.actor.destroy(); + } +@@ -195,6 +209,7 @@ const Indicator = class { + } + } + }; ++Signals.addSignalMethods(Indicator.prototype); // For MessageList.Message compat + + const CpuIndicator = class extends Indicator { + constructor() { +@@ -300,11 +315,7 @@ class Extension { + } + + enable() { +- this._box = new St.BoxLayout({ +- style_class: 'extension-systemMonitor-container', +- x_align: Clutter.ActorAlign.START, +- x_expand: true +- }); ++ this._section = new MessageList.MessageListSection(_('System Monitor')); + this._indicators = []; + + for (let i = 0; i < INDICATORS.length; i++) { +@@ -313,32 +324,18 @@ class Extension { + indicator.actor.connect('notify::hover', () => { + this._onHover(indicator); + }); +- this._box.add_actor(indicator.actor); ++ this._section.addMessage(indicator, false); + this._indicators.push(indicator); + } + +- this._boxHolder = new St.BoxLayout({ +- x_expand: true, +- y_expand: true, +- x_align: Clutter.ActorAlign.START, +- }); +- let menuButton = Main.messageTray._messageTrayMenuButton.actor; +- Main.messageTray.actor.remove_child(menuButton); +- Main.messageTray.actor.add_child(this._boxHolder); +- +- this._boxHolder.add_child(this._box); +- this._boxHolder.add_child(menuButton); ++ Main.panel.statusArea.dateMenu._messageList._addSection(this._section); ++ this._section.actor.get_parent().set_child_at_index(this._section.actor, 0); + } + + disable() { + this._indicators.forEach(i => i.destroy()); + +- let menuButton = Main.messageTray._messageTrayMenuButton.actor; +- this._boxHolder.remove_child(menuButton); +- Main.messageTray.actor.add_child(menuButton); +- +- this._box.destroy(); +- this._boxHolder.destroy(); + Main.panel.statusArea.dateMenu._messageList._removeSection(this._section); - }, + } - _onHover: function (item) { + _onHover(item) { diff --git a/extensions/systemMonitor/stylesheet.css b/extensions/systemMonitor/stylesheet.css index 13f95ec..978ac12 100644 --- a/extensions/systemMonitor/stylesheet.css @@ -662,70 +1209,67 @@ index 13f95ec..978ac12 100644 .extension-systemMonitor-indicator-label { -- -2.20.1 +2.21.0 -From a56d2c1c5546b6f1a6bf66f168874860b427bf9f Mon Sep 17 00:00:00 2001 +From f73fe9cfb5f9dbd6647e4eb30a9af0fb7ff79219 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 18 May 2017 16:20:07 +0200 -Subject: [PATCH 3/4] systemMonitor: Handle clicks on section title +Subject: [PATCH 4/5] systemMonitor: Handle clicks on section title While on 3.24.x only the event section still has a clickable title, it's a generic message list feature in previous versions. It's easy enough to support with a small subclass, so use that instead of the generic baseclass. -Fixes: #3 +Fixes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions3 --- - extensions/systemMonitor/extension.js | 20 +++++++++++++++++++- - 1 file changed, 19 insertions(+), 1 deletion(-) + extensions/systemMonitor/extension.js | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js -index 1388a1f..9c010d8 100644 +index 0188960..b4d5a9d 100644 --- a/extensions/systemMonitor/extension.js +++ b/extensions/systemMonitor/extension.js -@@ -303,6 +303,24 @@ const MemoryIndicator = new Lang.Class({ +@@ -303,6 +303,21 @@ const MemoryIndicator = class extends Indicator { } - }); + }; -+const SystemMonitorSection = new Lang.Class({ -+ Name: 'SystemMonitorSection', -+ Extends: MessageList.MessageListSection, -+ -+ _init: function() { -+ this.parent(_("System Monitor")); -+ }, ++class SystemMonitorSection extends MessageList.MessageListSection { ++ constructor() { ++ super(_('System Monitor')); ++ } + -+ _onTitleClicked: function() { -+ this.parent(); ++ _onTitleClicked() { ++ super._onTitleClicked(); + + let appSys = Shell.AppSystem.get_default(); + let app = appSys.lookup_app('gnome-system-monitor.desktop'); + if (app) + app.open_new_window(-1); + } -+}); ++} + const INDICATORS = [CpuIndicator, MemoryIndicator]; - const Extension = new Lang.Class({ -@@ -317,7 +335,7 @@ const Extension = new Lang.Class({ - }, + class Extension { +@@ -315,7 +330,7 @@ class Extension { + } - enable: function() { -- this._section = new MessageList.MessageListSection(_("System Monitor")); -+ this._section = new SystemMonitorSection(); - this._indicators = [ ]; + enable() { +- this._section = new MessageList.MessageListSection(_('System Monitor')); ++ this._section = new SystemMonitorSection(); + this._indicators = []; - for (let i = 0; i < INDICATORS.length; i++) { + for (let i = 0; i < INDICATORS.length; i++) { -- -2.20.1 +2.21.0 -From 0b22b3fb2f05a098408437d9cd48482fddc24766 Mon Sep 17 00:00:00 2001 +From df76e98d6bbac7dccc86f66e82eac2977fb5ed87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 18 May 2017 18:00:17 +0200 -Subject: [PATCH 4/4] systemMonitor: Provide classic styling +Subject: [PATCH 5/5] systemMonitor: Provide classic styling The indicator tooltips currently don't work out in classic mode (dark text on dark background), so provide some mode-specific @@ -763,5 +1307,5 @@ index 48504f6..b6548b1 100644 + extension_data += files('classic.css') +endif -- -2.20.1 +2.21.0 diff --git a/SPECS/gnome-shell-extensions.spec b/SPECS/gnome-shell-extensions.spec index 76b4678..17b241d 100644 --- a/SPECS/gnome-shell-extensions.spec +++ b/SPECS/gnome-shell-extensions.spec @@ -5,13 +5,12 @@ %global pkg_prefix gnome-shell-extension Name: gnome-shell-extensions -Version: 3.28.1 -Release: 8%{?dist} +Version: 3.32.1 +Release: 10%{?dist} Summary: Modify and extend GNOME Shell functionality and behavior Group: User Interface/Desktops -# The entire source code is GPLv2+ except lib/convenience.js which is BSD -License: GPLv2+ and BSD +License: GPLv2+ URL: http://wiki.gnome.org/Projects/GnomeShell/Extensions Source0: http://ftp.gnome.org/pub/GNOME/sources/%{name}/%{major_version}/%{name}-%{version}.tar.xz Source1: gnome-classic.desktop @@ -28,24 +27,25 @@ Requires: gnome-shell >= %{min_gs_version} BuildArch: noarch Patch0001: 0001-Update-style.patch -Patch0002: 0001-classic-Shade-panel-in-overview.patch -Patch0003: 0001-apps-menu-add-logo-icon-to-Applications-menu.patch -Patch0004: add-extra-extensions.patch -Patch0005: 0001-apps-menu-Explicitly-set-label_actor.patch -Patch0006: resurrect-system-monitor.patch -Patch0007: 0001-common-get-rid-of-weird-drop-shadow-nex-to-app-menu.patch -Patch0008: 0001-Include-top-icons-in-classic-session.patch +Patch0002: 0001-apps-menu-add-logo-icon-to-Applications-menu.patch +Patch0003: add-extra-extensions.patch +Patch0004: 0001-apps-menu-Explicitly-set-label_actor.patch +Patch0005: resurrect-system-monitor.patch +Patch0006: 0001-Include-top-icons-in-classic-session.patch +Patch0007: more-classic-classic-mode.patch +Patch0008: 0001-apps-menu-Add-missing-chain-up.patch %description GNOME Shell Extensions is a collection of extensions providing additional and optional functionality to GNOME Shell. Enabled extensions: - * alternate-tab * apps-menu * auto-move-windows * dash-to-dock + * disable-screenshield * desktop-icons + * horizontal-workspaces * drive-menu * launch-new-instance * native-window-placement @@ -68,6 +68,7 @@ License: GPLv2+ Requires: gnome-shell >= %{min_gs_version} # Dock extension no longer provided by GNOME Shell extensions >= 3.7.1 Obsoletes: %{pkg_prefix}-dock < 3.7.1 +Obsoletes: %{pkg_prefix}-alternate-tab < 3.31.2 # Alternative-status-menu extension no longer provided by GNOME Shell extensions >= 3.9.5 Obsoletes: %{pkg_prefix}-alternative-status-menu < 3.9.5 # Xrandr-indicator extension no longer provided by GNOME Shell extensions >= 3.9.5 @@ -88,9 +89,9 @@ This package provides common data files shared by various extensions. Summary: GNOME "classic" mode session Group: User Interface/Desktops License: GPLv2+ -Requires: %{pkg_prefix}-alternate-tab = %{version}-%{release} Requires: %{pkg_prefix}-apps-menu = %{version}-%{release} Requires: %{pkg_prefix}-desktop-icons = %{version}-%{release} +Requires: %{pkg_prefix}-horizontal-workspaces = %{version}-%{release} Requires: %{pkg_prefix}-launch-new-instance = %{version}-%{release} Requires: %{pkg_prefix}-places-menu = %{version}-%{release} Requires: %{pkg_prefix}-window-list = %{version}-%{release} @@ -110,17 +111,6 @@ This package contains the required components for the GNOME Shell "classic" mode, which aims to provide a GNOME 2-like user interface. -%package -n %{pkg_prefix}-alternate-tab -Summary: Classic Alt+Tab behavior for GNOME Shell -Group: User Interface/Desktops -License: GPLv2+ -Requires: %{pkg_prefix}-common = %{version}-%{release} - -%description -n %{pkg_prefix}-alternate-tab -This GNOME Shell extension changes Alt+Tab to be window-based instead of -app-based. - - %package -n %{pkg_prefix}-apps-menu Summary: Application menu for GNOME Shell Group: User Interface/Desktops @@ -154,6 +144,26 @@ Requires: %{pkg_prefix}-common = %{version}-%{release} This GNOME Shell extension makes the dash available outside the activities overview. +%package -n %{pkg_prefix}-disable-screenshield +Summary: Disable GNOME Shell screen shield if lock is disabled +Group: User Interface/Desktops +License: GPLv2+ +Requires: %{pkg_prefix}-common = %{version}-%{release} + +%description -n %{pkg_prefix}-disable-screenshield +This GNOME Shell extension disabled the screen shield if screen locking is disabled. + + +%package -n %{pkg_prefix}-horizontal-workspaces +Summary: Desktop icons support for the classic experience +Group: User Interface/Desktops +License: GPLv3+ +Requires: %{pkg_prefix}-common = %{version}-%{release} + +%description -n %{pkg_prefix}-horizontal-workspaces +This GNOME Shell extension adds desktop icons support as seen in GNOME 2 + + %package -n %{pkg_prefix}-desktop-icons Summary: Desktop icons support for the classic experience Group: User Interface/Desktops @@ -283,6 +293,16 @@ This GNOME Shell extension enables loading a GNOME Shell theme from ~/.themes//gnome-shell/. +%package -n %{pkg_prefix}-window-grouper +Summary: Keep windows that belong to the same process on the same workspace +Group: User Interface/Desktops +License: GPLv2+ +Requires: %{pkg_prefix}-common = %{version}-%{release} + +%description -n %{pkg_prefix}-window-grouper +This GNOME Shell extension keeps windows that belong to the same process on the same workspace. + + %package -n %{pkg_prefix}-window-list Summary: Display a window list at the bottom of the screen in GNOME Shell Group: User Interface/Desktops @@ -323,6 +343,7 @@ workspaces. %meson -Dextension_set="all" -Dclassic_mode=true %meson_build + %install %meson_install @@ -334,15 +355,12 @@ cp $RPM_BUILD_ROOT%{_datadir}/xsessions/gnome-classic.desktop \ cp $RPM_SOURCE_DIR/gnome-classic-wayland.desktop $RPM_BUILD_ROOT%{_datadir}/wayland-sessions cp $RPM_SOURCE_DIR/gnome-classic.desktop $RPM_BUILD_ROOT%{_datadir}/xsessions -# Drop useless example extension -rm -r $RPM_BUILD_ROOT%{_datadir}/gnome-shell/extensions/example*/ -rm $RPM_BUILD_ROOT%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.example.gschema.xml - %find_lang %{name} %files -n %{pkg_prefix}-common -f %{name}.lang -%doc COPYING NEWS README.md +%doc NEWS README.md +%license COPYING %files -n gnome-classic-session @@ -353,11 +371,7 @@ rm $RPM_BUILD_ROOT%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.exampl %{_datadir}/gnome-shell/theme/gnome-classic.css %{_datadir}/xsessions/gnome-classic.desktop %{_datadir}/wayland-sessions/gnome-classic-wayland.desktop -%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.classic-overrides.gschema.xml - -%files -n %{pkg_prefix}-alternate-tab -%{_datadir}/gnome-shell/extensions/alternate-tab*/ - +%{_datadir}/glib-2.0/schemas/00_org.gnome.shell.extensions.classic.gschema.override %files -n %{pkg_prefix}-apps-menu %{_datadir}/gnome-shell/extensions/apps-menu*/ @@ -373,6 +387,14 @@ rm $RPM_BUILD_ROOT%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.exampl %{_datadir}/gnome-shell/extensions/dash-to-dock*/ +%files -n %{pkg_prefix}-disable-screenshield +%{_datadir}/gnome-shell/extensions/disable-screenshield*/ + + +%files -n %{pkg_prefix}-horizontal-workspaces +%{_datadir}/gnome-shell/extensions/horizontal-workspaces*/ + + %files -n %{pkg_prefix}-desktop-icons %{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml %{_datadir}/gnome-shell/extensions/desktop-icons*/ @@ -426,6 +448,11 @@ rm $RPM_BUILD_ROOT%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.exampl %{_datadir}/gnome-shell/extensions/user-theme*/ +%files -n %{pkg_prefix}-window-grouper +%{_datadir}/gnome-shell/extensions/window-grouper*/ +%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.window-grouper.gschema.xml + + %files -n %{pkg_prefix}-window-list %{_datadir}/gnome-shell/extensions/window-list*/ %{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.window-list.gschema.xml @@ -440,6 +467,57 @@ rm $RPM_BUILD_ROOT%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.exampl %changelog +* Wed Jul 24 2019 Florian Müllner - 3.32.1-10 +- Drop obsolete downstream style patch +- Keep classic notification styling + Related: #1731372 + +* Thu Jul 18 2019 Florian Müllner - 3.32.1-9 +- Backport classic style improvements + Resolves: #1726093 + +* Thu Jul 04 2019 Florian Müllner - 3.32.1-8 +- Allow closing window picker with Escape + Resolves: #1725854 + +* Sat Jun 29 2019 Florian Müllner - 3.32-1-7 +- Add window thumbnails to workspace switcher + Resolves: #1723467 +- Fix apps-menu not disabling itself entirely + Resolves: #1722047 + +* Tue Jun 25 2019 Florian Müllner - 3.32-1-6 +- Fix new classic mode issues: + - stray signal handler with overlay key + Resolves: #1722844 + - improve DND support: + + don't consider regular windows + (it doesn't work well, and GNOME 2 didn't support it either) + + indicate that workspace thumbs are drop targets + Related: #1704360 + +* Tue Jun 18 2019 Florian Müllner - 3.32.1-5 +- Small refinements after design feedback: + - use default icon size in picker button to avoid blurriness + - use shortcut to open window picker + Resolves: #1721195 + +* Tue Jun 18 2019 Florian Müllner - 3.32.1-4 +- Don't add apps-menu logo when activities button is present + Resolves: #1721195 + +* Wed Jun 12 2019 Florian Müllner - 3.32.1-3 +- Make classic mode more classic + Resolves: #1704360 + +* Fri May 31 2019 Florian Müllner - 3.32.1-2 +- Fix top-icons sizing issue + Resolves: #1715765 + +* Thu May 23 2019 Florian Müllner - 3.32.1-1 +- Update to 3.32.1 + Resolves: #1713453 + * Mon Feb 11 2019 Florian Müllner - 3.28.1-8 - Update desktop-icons extension to 19.01 Resolves: #1666739