From cf9da3e90c86622babb68d80ae553bc3a3703cdf Mon Sep 17 00:00:00 2001
From: CentOS Sources <bugs@centos.org>
Date: Thu, 28 Jan 2021 16:10:32 +0000
Subject: [PATCH] import gnome-shell-extensions-3.32.1-13.el8

---
 .gitignore                                    |     1 +
 .gnome-shell-extensions.metadata              |     1 +
 ...Include-top-icons-in-classic-session.patch |    32 +
 ...-Update-desktop-icons-gettext-domain.patch |    83 +
 SOURCES/0001-Update-style.patch               |    98 +
 .../0001-apps-menu-Add-missing-chain-up.patch |    33 +
 ...apps-menu-Explicitly-set-label_actor.patch |    40 +
 ...u-add-logo-icon-to-Applications-menu.patch |    32 +
 ...1-dashToDock-Handle-no-overview-case.patch |   208 +
 ...op-icons-Update-Japanese-translation.patch |    31 +
 ...lid-current-mode-selected-in-Prefere.patch |    55 +
 SOURCES/add-extra-extensions.patch            | 26742 ++++++++++++++++
 SOURCES/gnome-classic-wayland.desktop         |    27 +
 SOURCES/gnome-classic.desktop                 |    27 +
 SOURCES/more-classic-classic-mode.patch       |  3270 ++
 SOURCES/resurrect-system-monitor.patch        |  1311 +
 SPECS/gnome-shell-extensions.spec             |  1025 +
 17 files changed, 33016 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 .gnome-shell-extensions.metadata
 create mode 100644 SOURCES/0001-Include-top-icons-in-classic-session.patch
 create mode 100644 SOURCES/0001-Update-desktop-icons-gettext-domain.patch
 create mode 100644 SOURCES/0001-Update-style.patch
 create mode 100644 SOURCES/0001-apps-menu-Add-missing-chain-up.patch
 create mode 100644 SOURCES/0001-apps-menu-Explicitly-set-label_actor.patch
 create mode 100644 SOURCES/0001-apps-menu-add-logo-icon-to-Applications-menu.patch
 create mode 100644 SOURCES/0001-dashToDock-Handle-no-overview-case.patch
 create mode 100644 SOURCES/0001-desktop-icons-Update-Japanese-translation.patch
 create mode 100644 SOURCES/0001-window-list-Invalid-current-mode-selected-in-Prefere.patch
 create mode 100644 SOURCES/add-extra-extensions.patch
 create mode 100644 SOURCES/gnome-classic-wayland.desktop
 create mode 100644 SOURCES/gnome-classic.desktop
 create mode 100644 SOURCES/more-classic-classic-mode.patch
 create mode 100644 SOURCES/resurrect-system-monitor.patch
 create mode 100644 SPECS/gnome-shell-extensions.spec

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3529e4d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+SOURCES/gnome-shell-extensions-3.32.1.tar.xz
diff --git a/.gnome-shell-extensions.metadata b/.gnome-shell-extensions.metadata
new file mode 100644
index 0000000..4e2ddcc
--- /dev/null
+++ b/.gnome-shell-extensions.metadata
@@ -0,0 +1 @@
+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
new file mode 100644
index 0000000..9c5283f
--- /dev/null
+++ b/SOURCES/0001-Include-top-icons-in-classic-session.patch
@@ -0,0 +1,32 @@
+From a3db60786407481efbfc4875f887d03b58f0a7b7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Fri, 23 Feb 2018 16:56:46 +0100
+Subject: [PATCH] Include top-icons in classic session
+
+---
+ meson.build | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/meson.build b/meson.build
+index 6764f9a..32743ed 100644
+--- a/meson.build
++++ b/meson.build
+@@ -36,6 +36,7 @@ classic_extensions = [
+   'desktop-icons',
+   'places-menu',
+   'launch-new-instance',
++  'top-icons',
+   'window-list'
+ ]
+ 
+@@ -56,7 +57,6 @@ all_extensions += [
+   'no-hot-corner',
+   'panel-favorites',
+   'systemMonitor',
+-  'top-icons',
+   'updates-dialog',
+   'user-theme',
+   'window-grouper'
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-Update-desktop-icons-gettext-domain.patch b/SOURCES/0001-Update-desktop-icons-gettext-domain.patch
new file mode 100644
index 0000000..454989d
--- /dev/null
+++ b/SOURCES/0001-Update-desktop-icons-gettext-domain.patch
@@ -0,0 +1,83 @@
+From f5e47cd8ca32ae433f6906b01a509c5a304894d9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Sat, 24 Oct 2020 01:14:44 +0200
+Subject: [PATCH] Update desktop-icons gettext domain
+
+---
+ extensions/desktop-icons/createFolderDialog.js | 2 +-
+ extensions/desktop-icons/desktopGrid.js        | 2 +-
+ extensions/desktop-icons/fileItem.js           | 2 +-
+ extensions/desktop-icons/prefs.js              | 8 +++++---
+ 4 files changed, 8 insertions(+), 6 deletions(-)
+
+diff --git a/extensions/desktop-icons/createFolderDialog.js b/extensions/desktop-icons/createFolderDialog.js
+index f3e40e9..5038762 100644
+--- a/extensions/desktop-icons/createFolderDialog.js
++++ b/extensions/desktop-icons/createFolderDialog.js
+@@ -21,7 +21,7 @@ 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 Gettext = imports.gettext.domain('gnome-shell-extensions');
+ const ModalDialog = imports.ui.modalDialog;
+ const ShellEntry = imports.ui.shellEntry;
+ const Tweener = imports.ui.tweener;
+diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js
+index a2d1f12..94d2dfd 100644
+--- a/extensions/desktop-icons/desktopGrid.js
++++ b/extensions/desktop-icons/desktopGrid.js
+@@ -44,7 +44,7 @@ const Util = imports.misc.util;
+ 
+ const Clipboard = St.Clipboard.get_default();
+ const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD;
+-const Gettext = imports.gettext.domain('desktop-icons');
++const Gettext = imports.gettext.domain('gnome-shell-extensions');
+ 
+ const _ = Gettext.gettext;
+ 
+diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
+index 0c6a54d..d6d43c9 100644
+--- a/extensions/desktop-icons/fileItem.js
++++ b/extensions/desktop-icons/fileItem.js
+@@ -42,7 +42,7 @@ const Prefs = Me.imports.prefs;
+ const DBusUtils = Me.imports.dbusUtils;
+ const DesktopIconsUtil = Me.imports.desktopIconsUtil;
+ 
+-const Gettext = imports.gettext.domain('desktop-icons');
++const Gettext = imports.gettext.domain('gnome-shell-extensions');
+ 
+ const _ = Gettext.gettext;
+ 
+diff --git a/extensions/desktop-icons/prefs.js b/extensions/desktop-icons/prefs.js
+index 4b8d986..51daf15 100644
+--- a/extensions/desktop-icons/prefs.js
++++ b/extensions/desktop-icons/prefs.js
+@@ -26,7 +26,7 @@ const Gettext = imports.gettext;
+ 
+ const Config = imports.misc.config;
+ 
+-var _ = Gettext.domain('desktop-icons').gettext;
++var _ = Gettext.domain('gnome-shell-extensions').gettext;
+ 
+ const SCHEMA_NAUTILUS = 'org.gnome.nautilus.preferences';
+ const SCHEMA_GTK = 'org.gtk.Settings.FileChooser';
+@@ -51,11 +51,13 @@ var CLICK_POLICY_SINGLE = false;
+ function initTranslations() {
+     let extension = ExtensionUtils.getCurrentExtension();
+ 
++    let domain = extension.metadata['gettext-domain'] || 'desktop-icons';
++
+     let localedir = extension.dir.get_child('locale');
+     if (localedir.query_exists(null))
+-        Gettext.bindtextdomain('desktop-icons', localedir.get_path());
++        Gettext.bindtextdomain(domain, localedir.get_path());
+     else
+-        Gettext.bindtextdomain('desktop-icons', Config.LOCALEDIR);
++        Gettext.bindtextdomain(domain, Config.LOCALEDIR);
+ }
+ 
+ function init() {
+-- 
+2.21.1
+
diff --git a/SOURCES/0001-Update-style.patch b/SOURCES/0001-Update-style.patch
new file mode 100644
index 0000000..8173ded
--- /dev/null
+++ b/SOURCES/0001-Update-style.patch
@@ -0,0 +1,98 @@
+From e768ad73e2d68b3f1567051675ba0539a75e3105 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Sat, 18 May 2019 19:37:05 +0200
+Subject: [PATCH] Update style
+
+---
+ 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 a6357ba..62d9c82 100644
+--- a/data/gnome-shell-sass/_common.scss
++++ b/data/gnome-shell-sass/_common.scss
+@@ -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 {
++      padding-right: .4em;
++      icon-size: 1em;
++    }
++
+     .system-status-icon { icon-size: 1.09em; padding: 0 5px; }
+     .unlock-screen &,
+     .login-screen &,
+@@ -1406,6 +1424,14 @@ StScrollBar {
+ 
+   }
+ 
++  .app-well-hover-text {
++      text-align: center;
++      color: $osd_fg_color;
++      background-color: $osd_bg_color;
++      border-radius: 5px;
++      padding: 3px;
++  }
++
+   .app-well-app-running-dot { //running apps indicator
+     width: 10px; height: 3px;
+     background-color: $selected_bg_color;
+@@ -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; }
+-  .login-dialog-message-hint { padding-top: 0; padding-bottom: 20px; }
++  .login-dialog-message-hint, .login-dialog-message {
++    color: darken($osd_fg_color, 20%);
++    padding-top: 0;
++    padding-bottom: 20px;
++    min-height: 2.75em;
++  }
+   .login-dialog-user-selection-box { padding: 100px 0px; }
+   .login-dialog-not-listed-label {
+     padding-left: 2px;
+@@ -1856,6 +1887,10 @@ StScrollBar {
+       padding-bottom: 12px;
+       spacing: 8px;
+       width: 23em;
++      .login-dialog-timed-login-indicator {
++          height: 2px;
++          background-color: darken($fg_color,40%);
++      }
+   }
+ 
+   .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?= <fmuellner@gnome.org>
+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
new file mode 100644
index 0000000..131ea79
--- /dev/null
+++ b/SOURCES/0001-apps-menu-Explicitly-set-label_actor.patch
@@ -0,0 +1,40 @@
+From 52ee25effa3debb21307e33ac223cf48ac7bc57a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Thu, 17 Mar 2016 17:15:38 +0100
+Subject: [PATCH] apps-menu: Explicitly set label_actor
+
+For some reason orca fails to pick up the label of category items,
+so set the label_actor explicitly as workaround.
+---
+ extensions/apps-menu/extension.js | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
+index d62e3d7..cc399c6 100644
+--- a/extensions/apps-menu/extension.js
++++ b/extensions/apps-menu/extension.js
+@@ -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(label);
++        this.actor.label_actor = label;
+     }
+ 
+     activate(event) {
+@@ -120,7 +122,9 @@ class CategoryMenuItem extends PopupMenu.PopupBaseMenuItem {
+         else
+             name = _('Favorites');
+ 
+-        this.actor.add_child(new St.Label({ text: name }));
++        let label = new St.Label({ text: name });
++        this.actor.add_child(label);
++        this.actor.label_actor = label;
+         this.actor.connect('motion-event', this._onMotionEvent.bind(this));
+     }
+ 
+-- 
+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
new file mode 100644
index 0000000..973c077
--- /dev/null
+++ b/SOURCES/0001-apps-menu-add-logo-icon-to-Applications-menu.patch
@@ -0,0 +1,32 @@
+From 3e3634b59455da0cbae1de4af0ce5cf97be8b80d Mon Sep 17 00:00:00 2001
+From: Ray Strode <rstrode@redhat.com>
+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 | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
+index d7ba570..d62e3d7 100644
+--- a/extensions/apps-menu/extension.js
++++ b/extensions/apps-menu/extension.js
+@@ -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'
++        });
++        hbox.add_actor(this._icon);
++
+         this._label = new St.Label({
+             text: _('Applications'),
+             y_expand: true,
+-- 
+2.21.0
+
diff --git a/SOURCES/0001-dashToDock-Handle-no-overview-case.patch b/SOURCES/0001-dashToDock-Handle-no-overview-case.patch
new file mode 100644
index 0000000..e7a2cdc
--- /dev/null
+++ b/SOURCES/0001-dashToDock-Handle-no-overview-case.patch
@@ -0,0 +1,208 @@
+From 3c62051c0a154ae987bb0126e8adb6cd86aa69a2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Mon, 24 Feb 2020 16:17:05 +0100
+Subject: [PATCH] dashToDock: Handle no-overview case
+
+There is no longer an overview in GNOME Classic, so in order to be
+used in that environment, the extension must deal with that case.
+---
+ extensions/dash-to-dock/docking.js | 122 ++++++++++++++++-------------
+ 1 file changed, 68 insertions(+), 54 deletions(-)
+
+diff --git a/extensions/dash-to-dock/docking.js b/extensions/dash-to-dock/docking.js
+index d35094b..2b8353a 100644
+--- a/extensions/dash-to-dock/docking.js
++++ b/extensions/dash-to-dock/docking.js
+@@ -233,7 +233,7 @@ var DockedDash = class DashToDock {
+         // Create a new dash object
+         this.dash = new MyDash.MyDash(this._settings, this._remoteModel, this._monitorIndex);
+ 
+-        if (!this._settings.get_boolean('show-show-apps-button'))
++        if (Main.overview.isDummy || !this._settings.get_boolean('show-show-apps-button'))
+             this.dash.hideShowAppsButton();
+ 
+         // Create the main actor and the containers for sliding in and out and
+@@ -272,45 +272,11 @@ var DockedDash = class DashToDock {
+         this.dash.actor.add_constraint(this.constrainSize);
+ 
+         this._signalsHandler.add([
+-            Main.overview,
+-            'item-drag-begin',
+-            this._onDragStart.bind(this)
+-        ], [
+-            Main.overview,
+-            'item-drag-end',
+-            this._onDragEnd.bind(this)
+-        ], [
+-            Main.overview,
+-            'item-drag-cancelled',
+-            this._onDragEnd.bind(this)
+-        ], [
+             // update when workarea changes, for instance if  other extensions modify the struts
+             //(like moving th panel at the bottom)
+             global.display,
+             'workareas-changed',
+             this._resetPosition.bind(this)
+-        ], [
+-            Main.overview,
+-            'showing',
+-            this._onOverviewShowing.bind(this)
+-        ], [
+-            Main.overview,
+-            'hiding',
+-            this._onOverviewHiding.bind(this)
+-        ], [
+-            // Hide on appview
+-            Main.overview.viewSelector,
+-            'page-changed',
+-            this._pageChanged.bind(this)
+-        ], [
+-            Main.overview.viewSelector,
+-            'page-empty',
+-            this._onPageEmpty.bind(this)
+-        ], [
+-            // Ensure the ShowAppsButton status is kept in sync
+-            Main.overview.viewSelector._showAppsButton,
+-            'notify::checked',
+-            this._syncShowAppsButtonToggled.bind(this)
+         ], [
+             global.display,
+             'in-fullscreen-changed',
+@@ -325,15 +291,6 @@ var DockedDash = class DashToDock {
+             this.dash,
+             'icon-size-changed',
+             () => { Main.overview.dashIconSize = this.dash.iconSize; }
+-        ], [
+-            // This duplicate the similar signal which is in owerview.js.
+-            // Being connected and thus executed later this effectively
+-            // overwrite any attempt to use the size of the default dash
+-            //which given the customization is usually much smaller.
+-            // I can't easily disconnect the original signal
+-            Main.overview._controls.dash,
+-            'icon-size-changed',
+-            () => { Main.overview.dashIconSize = this.dash.iconSize; }
+         ], [
+             // sync hover after a popupmenu is closed
+             this.dash,
+@@ -341,6 +298,53 @@ var DockedDash = class DashToDock {
+             () => { this._box.sync_hover() }
+         ]);
+ 
++        if (!Main.overview.isDummy) {
++            this._signalsHandler.add([
++                Main.overview,
++                'item-drag-begin',
++                this._onDragStart.bind(this)
++            ], [
++                Main.overview,
++                'item-drag-end',
++                this._onDragEnd.bind(this)
++            ], [
++                Main.overview,
++                'item-drag-cancelled',
++                this._onDragEnd.bind(this)
++            ], [
++                Main.overview,
++                'showing',
++                this._onOverviewShowing.bind(this)
++            ], [
++                Main.overview,
++                'hiding',
++                this._onOverviewHiding.bind(this)
++            ], [
++                // Hide on appview
++                Main.overview.viewSelector,
++                'page-changed',
++                this._pageChanged.bind(this)
++            ], [
++                Main.overview.viewSelector,
++                'page-empty',
++                this._onPageEmpty.bind(this)
++            ], [
++                // Ensure the ShowAppsButton status is kept in sync
++                Main.overview.viewSelector._showAppsButton,
++                'notify::checked',
++                this._syncShowAppsButtonToggled.bind(this)
++            ], [
++                // This duplicate the similar signal which is in owerview.js.
++                // Being connected and thus executed later this effectively
++                // overwrite any attempt to use the size of the default dash
++                //which given the customization is usually much smaller.
++                // I can't easily disconnect the original signal
++                Main.overview._controls.dash,
++                'icon-size-changed',
++                () => { Main.overview.dashIconSize = this.dash.iconSize; }
++            ]);
++        }
++
+         this._injectionsHandler = new Utils.InjectionsHandler();
+         this._themeManager = new Theming.ThemeManager(this._settings, this);
+ 
+@@ -370,14 +374,17 @@ var DockedDash = class DashToDock {
+         this._dashSpacer = new OverviewControls.DashSpacer();
+         this._dashSpacer.setDashActor(this._box);
+ 
+-        if (this._position == St.Side.LEFT)
+-            Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? -1 : 0); // insert on first
+-        else if (this._position ==  St.Side.RIGHT)
+-            Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? 0 : -1); // insert on last
+-        else if (this._position == St.Side.TOP)
+-            Main.overview._overview.insert_child_at_index(this._dashSpacer, 0);
+-        else if (this._position == St.Side.BOTTOM)
+-            Main.overview._overview.insert_child_at_index(this._dashSpacer, -1);
++        if (!Main.overview.isDummy) {
++            const { _controls, _overview } = Main.overview;
++            if (this._position == St.Side.LEFT)
++                _controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? -1 : 0); // insert on first
++            else if (this._position ==  St.Side.RIGHT)
++                _controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? 0 : -1); // insert on last
++            else if (this._position == St.Side.TOP)
++                _overview.insert_child_at_index(this._dashSpacer, 0);
++            else if (this._position == St.Side.BOTTOM)
++                _overview.insert_child_at_index(this._dashSpacer, -1);
++        }
+ 
+         // Add dash container actor and the container to the Chrome.
+         this.actor.set_child(this._slider);
+@@ -412,7 +419,7 @@ var DockedDash = class DashToDock {
+ 
+         // Since Gnome 3.8 dragging an app without having opened the overview before cause the attemp to
+         //animate a null target since some variables are not initialized when the viewSelector is created
+-        if (Main.overview.viewSelector._activePage == null)
++        if (!Main.overview.isDummy && Main.overview.viewSelector._activePage == null)
+             Main.overview.viewSelector._activePage = Main.overview.viewSelector._workspacesPage;
+ 
+         this._updateVisibilityMode();
+@@ -493,7 +500,8 @@ var DockedDash = class DashToDock {
+             this._settings,
+             'changed::show-show-apps-button',
+             () => {
+-                    if (this._settings.get_boolean('show-show-apps-button'))
++                    if (!Main.overview.isDummy &&
++                        this._settings.get_boolean('show-show-apps-button'))
+                         this.dash.showShowAppsButton();
+                     else
+                         this.dash.hideShowAppsButton();
+@@ -1681,6 +1689,9 @@ var DockManager = class DashToDock_DockManager {
+         // set stored icon size  to the new dash
+         Main.overview.dashIconSize = this._allDocks[0].dash.iconSize;
+ 
++        if (Main.overview.isDummy)
++            return;
++
+         // Hide usual Dash
+         Main.overview._controls.dash.actor.hide();
+ 
+@@ -1707,6 +1718,9 @@ var DockManager = class DashToDock_DockManager {
+     }
+ 
+     _restoreDash() {
++        if (Main.overview.isDummy)
++            return;
++
+         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
+-- 
+2.25.0
+
diff --git a/SOURCES/0001-desktop-icons-Update-Japanese-translation.patch b/SOURCES/0001-desktop-icons-Update-Japanese-translation.patch
new file mode 100644
index 0000000..43b3826
--- /dev/null
+++ b/SOURCES/0001-desktop-icons-Update-Japanese-translation.patch
@@ -0,0 +1,31 @@
+From 0a7248c75c084a83852aa3d0e7a36ccebd365b81 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Wed, 27 Jan 2021 11:51:28 +0100
+Subject: [PATCH] desktop-icons: Update Japanese translation
+
+---
+ po/ja.po | 7 +------
+ 1 file changed, 1 insertion(+), 6 deletions(-)
+
+diff --git a/po/ja.po b/po/ja.po
+index df5646d..4d780b9 100644
+--- a/po/ja.po
++++ b/po/ja.po
+@@ -293,13 +293,8 @@ msgid "Workspace %d"
+ msgstr "ワークスペース %d"
+ 
+ #: desktopGrid.js:334
+-#, fuzzy
+ msgid "Display Settings"
+-msgstr ""
+-"#-#-#-#-#  ja.po (gnome-shell-extensions master)  #-#-#-#-#\n"
+-"ディスプレイ設定\n"
+-"#-#-#-#-#  ja.po (desktop-icons master)  #-#-#-#-#\n"
+-"ディスプレイの設定"
++msgstr "ディスプレイ設定"
+ 
+ #: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
+ #, fuzzy
+-- 
+2.29.2
+
diff --git a/SOURCES/0001-window-list-Invalid-current-mode-selected-in-Prefere.patch b/SOURCES/0001-window-list-Invalid-current-mode-selected-in-Prefere.patch
new file mode 100644
index 0000000..cf9d160
--- /dev/null
+++ b/SOURCES/0001-window-list-Invalid-current-mode-selected-in-Prefere.patch
@@ -0,0 +1,55 @@
+From b4eeaf7ea12fa7d9713e80371490d8060396b3cb Mon Sep 17 00:00:00 2001
+From: Milan Crha <mcrha@redhat.com>
+Date: Fri, 17 Apr 2020 09:21:42 +0200
+Subject: [PATCH] window-list: Invalid current mode selected in Preferences
+
+It seems that gtk+ resets the active radio whenever a new radio button
+is added into the group, thus rather restore the current mode after
+the group is fully populated.
+
+https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/119
+---
+ extensions/window-list/prefs.js | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
+index 78792b5..17e9799 100644
+--- a/extensions/window-list/prefs.js
++++ b/extensions/window-list/prefs.js
+@@ -50,6 +50,7 @@ class WindowListPrefsWidget extends Gtk.Grid {
+         };
+ 
+         let radio = null;
++        let currentRadio = null;
+         for (let i = 0; i < modes.length; i++) {
+             let mode = modes[i];
+             let label = modeLabels[mode];
+@@ -59,18 +60,24 @@ class WindowListPrefsWidget extends Gtk.Grid {
+             }
+ 
+             radio = new Gtk.RadioButton({
+-                active: currentMode == mode,
++                active: !i,
+                 label: label,
+                 group: radio
+             });
+             grid.add(radio);
+ 
++            if (currentMode === mode)
++                currentRadio = radio;
++
+             radio.connect('toggled', button => {
+                 if (button.active)
+                     this._settings.set_string('grouping-mode', mode);
+             });
+         }
+ 
++        if (currentRadio)
++            currentRadio.active = true;
++
+         let check = new Gtk.CheckButton({
+             label: _('Show on all monitors'),
+             margin_top: 6
+-- 
+2.26.2
+
diff --git a/SOURCES/add-extra-extensions.patch b/SOURCES/add-extra-extensions.patch
new file mode 100644
index 0000000..a869226
--- /dev/null
+++ b/SOURCES/add-extra-extensions.patch
@@ -0,0 +1,26742 @@
+From ed28c7abd7c324dc6071ff96309854b1f5d48761 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Wed, 20 May 2015 17:44:50 +0200
+Subject: [PATCH 1/8] Add top-icons extension
+
+---
+ 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
+ create mode 100644 extensions/top-icons/stylesheet.css
+
+diff --git a/extensions/top-icons/extension.js b/extensions/top-icons/extension.js
+new file mode 100644
+index 0000000..a8eec13
+--- /dev/null
++++ b/extensions/top-icons/extension.js
+@@ -0,0 +1,96 @@
++// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
++/* exported init */
++
++const { Clutter, Shell, St } = imports.gi;
++const Main = imports.ui.main;
++const PanelMenu = imports.ui.panelMenu;
++const System = imports.system;
++
++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'
++];
++
++class SysTray {
++    constructor() {
++        this._icons = [];
++        this._tray = null;
++    }
++
++    _onTrayIconAdded(o, icon) {
++        let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : '';
++        if (STANDARD_TRAY_ICON_IMPLEMENTATIONS.includes(wmClass))
++            return;
++
++        let button = new PanelMenu.Button(0.5, null, true);
++
++        let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
++        let iconSize = PANEL_ICON_SIZE * scaleFactor;
++
++        icon.set({
++            width: iconSize,
++            height: iconSize,
++            x_align: Clutter.ActorAlign.CENTER,
++            y_align: Clutter.ActorAlign.CENTER
++        });
++
++        let iconBin = new St.Widget({
++            layout_manager: new Clutter.BinLayout()
++        });
++        iconBin.add_actor(icon);
++        button.add_actor(iconBin);
++
++        this._icons.push(icon);
++
++        button.connect('button-release-event', (actor, event) => {
++            icon.click(event);
++        });
++        button.connect('key-press-event', (actor, event) => {
++            icon.click(event);
++        });
++
++        icon.connect('destroy', () => {
++            button.destroy();
++        });
++
++        let role = wmClass || `${icon}`;
++        Main.panel.addToStatusArea(role, button);
++    }
++
++    _onTrayIconRemoved(o, icon) {
++        let parent = icon.get_parent();
++        parent.destroy();
++        this._icons.splice(this._icons.indexOf(icon), 1);
++    }
++
++    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.actor);
++    }
++
++    disable() {
++        this._icons.forEach(icon => icon.get_parent().destroy());
++        this._icons = [];
++
++        this._tray = null;
++        System.gc(); // force finalizing tray to unmanage screen
++    }
++}
++
++function init() {
++    return new SysTray();
++}
+diff --git a/extensions/top-icons/meson.build b/extensions/top-icons/meson.build
+new file mode 100644
+index 0000000..48504f6
+--- /dev/null
++++ b/extensions/top-icons/meson.build
+@@ -0,0 +1,5 @@
++extension_data += configure_file(
++  input: metadata_name + '.in',
++  output: metadata_name,
++  configuration: metadata_conf
++)
+diff --git a/extensions/top-icons/metadata.json.in b/extensions/top-icons/metadata.json.in
+new file mode 100644
+index 0000000..f1e2436
+--- /dev/null
++++ b/extensions/top-icons/metadata.json.in
+@@ -0,0 +1,10 @@
++{
++"extension-id": "@extension_id@",
++"uuid": "@uuid@",
++"settings-schema": "@gschemaname@",
++"gettext-domain": "@gettext_domain@",
++"name": "Top Icons",
++"description": "Shows legacy tray icons on top",
++"shell-version": [ "@shell_current@" ],
++"url": "http://94.247.144.115/repo/topicons/"
++}
+diff --git a/extensions/top-icons/stylesheet.css b/extensions/top-icons/stylesheet.css
+new file mode 100644
+index 0000000..25134b6
+--- /dev/null
++++ b/extensions/top-icons/stylesheet.css
+@@ -0,0 +1 @@
++/* This extensions requires no special styling */
+diff --git a/meson.build b/meson.build
+index b987f2d..6050c32 100644
+--- a/meson.build
++++ b/meson.build
+@@ -50,6 +50,7 @@ all_extensions = default_extensions
+ all_extensions += [
+   'auto-move-windows',
+   'native-window-placement',
++  'top-icons',
+   'user-theme'
+ ]
+ 
+-- 
+2.21.1
+
+
+From b99f1a2ead84c4fe494a387a032715f2973fbfa7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Wed, 20 May 2015 18:05:41 +0200
+Subject: [PATCH 2/8] Add dash-to-dock extension
+
+---
+ 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        |  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              |  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 +
+ 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/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
+ create mode 100644 extensions/dash-to-dock/org.gnome.shell.extensions.dash-to-dock.gschema.xml
+ create mode 100644 extensions/dash-to-dock/prefs.js
+ create mode 100644 extensions/dash-to-dock/stylesheet.css
+ create mode 100644 extensions/dash-to-dock/theming.js
+ create mode 100644 extensions/dash-to-dock/utils.js
+ create mode 100644 extensions/dash-to-dock/windowPreview.js
+
+diff --git a/extensions/dash-to-dock/Settings.ui b/extensions/dash-to-dock/Settings.ui
+new file mode 100644
+index 0000000..c141eff
+--- /dev/null
++++ b/extensions/dash-to-dock/Settings.ui
+@@ -0,0 +1,3335 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<!-- Generated with glade 3.20.0 -->
++<interface>
++  <requires lib="gtk+" version="3.18"/>
++  <object class="GtkAdjustment" id="animation_time_adjustment">
++    <property name="upper">1</property>
++    <property name="step_increment">0.050000000000000003</property>
++    <property name="page_increment">0.25</property>
++  </object>
++  <object class="GtkBox" id="box_middle_click_options">
++    <property name="visible">True</property>
++    <property name="can_focus">False</property>
++    <property name="margin_left">12</property>
++    <property name="margin_right">12</property>
++    <property name="margin_top">12</property>
++    <property name="margin_bottom">12</property>
++    <property name="orientation">vertical</property>
++    <child>
++      <object class="GtkFrame" id="frame_middle_click_options">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label_xalign">0</property>
++        <property name="shadow_type">in</property>
++        <child>
++          <object class="GtkListBox" id="listbox_middle_click_options">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="selection_mode">none</property>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow11">
++                <property name="width_request">100</property>
++                <property name="height_request">80</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="buitin_theme7">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkLabel" id="builtin_theme_description4">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">When set to minimize, double clicking minimizes all the windows of the application.</property>
++                        <property name="wrap">True</property>
++                        <property name="max_width_chars">40</property>
++                        <property name="xalign">0</property>
++                        <style>
++                          <class name="dim-label"/>
++                        </style>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="builtin_theme_label4">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Shift+Click action</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkComboBoxText" id="shift_click_action_combo">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="valign">center</property>
++                        <items>
++                          <item translatable="yes">Raise window</item>
++                          <item translatable="yes">Minimize window</item>
++                          <item translatable="yes">Launch new instance</item>
++                          <item translatable="yes">Cycle through windows</item>
++                          <item translatable="yes">Minimize or overview</item>
++                          <item translatable="yes">Show window previews</item>
++                          <item translatable="yes">Minimize or show previews</item>
++                          <item translatable="yes">Focus or show previews</item>
++                          <item translatable="yes">Quit</item>
++                        </items>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                        <property name="height">2</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow_middle_click">
++                <property name="width_request">100</property>
++                <property name="height_request">80</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="grid_middle_click">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkLabel" id="description_middle_click">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Behavior for Middle-Click.</property>
++                        <property name="wrap">True</property>
++                        <property name="max_width_chars">40</property>
++                        <property name="xalign">0</property>
++                        <style>
++                          <class name="dim-label"/>
++                        </style>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="label_middle_click">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Middle-Click action</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkComboBoxText" id="middle_click_action_combo">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="valign">center</property>
++                        <items>
++                          <item translatable="yes">Raise window</item>
++                          <item translatable="yes">Minimize window</item>
++                          <item translatable="yes">Launch new instance</item>
++                          <item translatable="yes">Cycle through windows</item>
++                          <item translatable="yes">Minimize or overview</item>
++                          <item translatable="yes">Show window previews</item>
++                          <item translatable="yes">Minimize or show previews</item>
++                          <item translatable="yes">Focus or show previews</item>
++                          <item translatable="yes">Quit</item>
++                        </items>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                        <property name="height">2</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow_shift_middle_click">
++                <property name="width_request">100</property>
++                <property name="height_request">80</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="grid_shift_middle_click">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkLabel" id="description_shift_middle_click">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Behavior for Shift+Middle-Click.</property>
++                        <property name="wrap">True</property>
++                        <property name="max_width_chars">40</property>
++                        <property name="xalign">0</property>
++                        <style>
++                          <class name="dim-label"/>
++                        </style>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="label_shift_middle_click">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Shift+Middle-Click action</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkComboBoxText" id="shift_middle_click_action_combo">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="valign">center</property>
++                        <items>
++                          <item translatable="yes">Raise window</item>
++                          <item translatable="yes">Minimize window</item>
++                          <item translatable="yes">Launch new instance</item>
++                          <item translatable="yes">Cycle through windows</item>
++                          <item translatable="yes">Minimize or overview</item>
++                          <item translatable="yes">Show window previews</item>
++                          <item translatable="yes">Minimize or show previews</item>
++                          <item translatable="yes">Focus or show previews</item>
++                          <item translatable="yes">Quit</item>
++                        </items>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                        <property name="height">2</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++          </object>
++        </child>
++        <child type="label_item">
++          <placeholder/>
++        </child>
++      </object>
++      <packing>
++        <property name="expand">False</property>
++        <property name="fill">True</property>
++        <property name="position">0</property>
++      </packing>
++    </child>
++  </object>
++  <object class="GtkAdjustment" id="custom_opacity_adjustement">
++    <property name="upper">1</property>
++    <property name="step_increment">0.01</property>
++    <property name="page_increment">0.10000000000000001</property>
++  </object>
++  <object class="GtkAdjustment" id="dock_size_adjustment">
++    <property name="lower">0.33000000000000002</property>
++    <property name="upper">1</property>
++    <property name="step_increment">0.01</property>
++    <property name="page_increment">0.10000000000000001</property>
++  </object>
++  <object class="GtkAdjustment" id="dot_border_width_adjustment">
++    <property name="upper">10</property>
++    <property name="step_increment">1</property>
++    <property name="page_increment">5</property>
++  </object>
++  <object class="GtkBox" id="running_dots_advance_settings_box">
++    <property name="visible">True</property>
++    <property name="can_focus">False</property>
++    <property name="margin_left">12</property>
++    <property name="margin_right">12</property>
++    <property name="margin_top">12</property>
++    <property name="margin_bottom">12</property>
++    <property name="orientation">vertical</property>
++    <child>
++      <object class="GtkFrame" id="frame1">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label_xalign">0</property>
++        <property name="shadow_type">in</property>
++        <child>
++          <object class="GtkListBox" id="listbox7">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="selection_mode">none</property>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow10">
++                <property name="width_request">100</property>
++                <property name="height_request">80</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkBox" id="dot_style_box">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="orientation">vertical</property>
++                    <property name="spacing">12</property>
++                    <child>
++                      <object class="GtkBox">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="unity_backlit_items_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="valign">center</property>
++                            <property name="label" translatable="yes">Enable Unity7 like glossy backlit items</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="expand">True</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkSwitch" id="unity_backlit_items_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="valign">center</property>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                      </object>
++                      <packing>
++                        <property name="expand">False</property>
++                        <property name="fill">True</property>
++                        <property name="position">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkBox">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <child>
++                          <object class="GtkLabel" id="dominant_color_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="halign">start</property>
++                            <property name="label" translatable="yes">Use dominant color</property>
++                          </object>
++                          <packing>
++                            <property name="expand">True</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkSwitch" id="dominant_color_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                      </object>
++                      <packing>
++                        <property name="expand">False</property>
++                        <property name="fill">True</property>
++                        <property name="position">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkGrid" id="grid1">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkSwitch" id="dot_style_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="label4">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Customize indicator style</property>
++                            <property name="justify">fill</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                      </object>
++                      <packing>
++                        <property name="expand">False</property>
++                        <property name="fill">True</property>
++                        <property name="position">2</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkBox" id="dot_style_settings_box">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_bottom">1</property>
++                        <property name="orientation">vertical</property>
++                        <property name="spacing">12</property>
++                        <child>
++                          <object class="GtkBox" id="dot_color_box">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">32</property>
++                            <child>
++                              <object class="GtkLabel" id="dot_color_label">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="label" translatable="yes">Color</property>
++                                <property name="xalign">0</property>
++                              </object>
++                              <packing>
++                                <property name="expand">True</property>
++                                <property name="fill">True</property>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkColorButton" id="dot_color_colorbutton">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">True</property>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="border_color_box">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">32</property>
++                            <child>
++                              <object class="GtkLabel" id="dot_border_color_label">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="label" translatable="yes">Border color</property>
++                                <property name="xalign">0</property>
++                              </object>
++                              <packing>
++                                <property name="expand">True</property>
++                                <property name="fill">True</property>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkColorButton" id="dot_border_color_colorbutton">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">True</property>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="box_boder_width_box">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">32</property>
++                            <child>
++                              <object class="GtkLabel" id="dot_border_width_label">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="label" translatable="yes">Border width</property>
++                                <property name="xalign">0</property>
++                              </object>
++                              <packing>
++                                <property name="expand">True</property>
++                                <property name="fill">True</property>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkSpinButton" id="dot_border_width_spin_button">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="adjustment">dot_border_width_adjustment</property>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                      <packing>
++                        <property name="expand">False</property>
++                        <property name="fill">True</property>
++                        <property name="position">3</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++          </object>
++        </child>
++        <child type="label_item">
++          <placeholder/>
++        </child>
++      </object>
++      <packing>
++        <property name="expand">False</property>
++        <property name="fill">True</property>
++        <property name="position">0</property>
++      </packing>
++    </child>
++  </object>
++  <object class="GtkAdjustment" id="hide_timeout_adjustment">
++    <property name="upper">1</property>
++    <property name="step_increment">0.050000000000000003</property>
++    <property name="page_increment">0.25</property>
++  </object>
++  <object class="GtkAdjustment" id="icon_size_adjustment">
++    <property name="lower">16</property>
++    <property name="upper">128</property>
++    <property name="step_increment">1</property>
++    <property name="page_increment">10</property>
++  </object>
++  <object class="GtkNotebook" id="settings_notebook">
++    <property name="visible">True</property>
++    <property name="can_focus">True</property>
++    <property name="margin_left">6</property>
++    <property name="margin_right">6</property>
++    <property name="margin_top">6</property>
++    <property name="margin_bottom">6</property>
++    <child>
++      <object class="GtkBox" id="position_and_size">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="margin_left">24</property>
++        <property name="margin_right">24</property>
++        <property name="margin_top">24</property>
++        <property name="margin_bottom">24</property>
++        <property name="orientation">vertical</property>
++        <property name="spacing">24</property>
++        <child>
++          <object class="GtkFrame" id="dock_display">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkListBox" id="dock_display_listbox">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="selection_mode">none</property>
++                <child>
++                  <object class="GtkListBoxRow" id="dock_monitor_listboxrow">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="dock_monitor_grid">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="dock_monitor_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Show the dock on</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkComboBoxText" id="dock_monitor_combo">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="valign">center</property>
++                            <signal name="changed" handler="dock_display_combo_changed_cb" swapped="no"/>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkCheckButton" id="multi_monitor_button">
++                            <property name="label" translatable="yes">Show on all monitors.</property>
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="margin_top">12</property>
++                            <property name="xalign">0</property>
++                            <property name="draw_indicator">True</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">2</property>
++                            <property name="width">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <placeholder/>
++                        </child>
++                        <child>
++                          <placeholder/>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child>
++                  <object class="GtkListBoxRow" id="dock_position_listboxrow">
++                    <property name="width_request">100</property>
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkBox" id="dock_position_box">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="dock_position_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Position on screen</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="dock_position_butttons_box">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">32</property>
++                            <child>
++                              <object class="GtkRadioButton" id="position_left_button">
++                                <property name="label" translatable="yes">Left</property>
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">False</property>
++                                <property name="halign">end</property>
++                                <property name="valign">center</property>
++                                <property name="xalign">0</property>
++                                <property name="draw_indicator">True</property>
++                                <signal name="toggled" handler="position_left_button_toggled_cb" swapped="no"/>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkRadioButton" id="position_bottom_button">
++                                <property name="label" translatable="yes">Bottom</property>
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">False</property>
++                                <property name="halign">center</property>
++                                <property name="xalign">0</property>
++                                <property name="draw_indicator">True</property>
++                                <property name="group">position_left_button</property>
++                                <signal name="toggled" handler="position_bottom_button_toggled_cb" swapped="no"/>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkRadioButton" id="position_top_button">
++                                <property name="label" translatable="yes">Top</property>
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">False</property>
++                                <property name="halign">center</property>
++                                <property name="xalign">0</property>
++                                <property name="image_position">bottom</property>
++                                <property name="draw_indicator">True</property>
++                                <property name="group">position_left_button</property>
++                                <signal name="toggled" handler="position_top_button_toggled_cb" swapped="no"/>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">2</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkRadioButton" id="position_right_button">
++                                <property name="label" translatable="yes">Right</property>
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">False</property>
++                                <property name="valign">center</property>
++                                <property name="xalign">0</property>
++                                <property name="draw_indicator">True</property>
++                                <property name="group">position_left_button</property>
++                                <signal name="toggled" handler="position_right_button_toggled_cb" swapped="no"/>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">3</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">0</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkFrame" id="intelligent_autohide_frame">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkListBox" id="listbox3">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="selection_mode">none</property>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow14">
++                    <property name="width_request">100</property>
++                    <property name="height_request">80</property>
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="intelligent_autohide_grid">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="builtin_theme_description7">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Hide the dock when it obstructs a window of the current application. More refined settings are available.</property>
++                            <property name="wrap">True</property>
++                            <property name="xalign">0</property>
++                            <style>
++                              <class name="dim-label"/>
++                            </style>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="builtin_theme_label8">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Intelligent autohide</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="box3">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">6</property>
++                            <child>
++                              <object class="GtkButton" id="intelligent_autohide_button">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">True</property>
++                                <property name="halign">center</property>
++                                <property name="valign">center</property>
++                                <property name="xalign">0.46000000834465027</property>
++                                <child>
++                                  <object class="GtkImage" id="image">
++                                    <property name="visible">True</property>
++                                    <property name="can_focus">False</property>
++                                    <property name="icon_name">emblem-system-symbolic</property>
++                                  </object>
++                                </child>
++                                <style>
++                                  <class name="circular"/>
++                                </style>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkSwitch" id="intelligent_autohide_switch">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="halign">end</property>
++                                <property name="valign">center</property>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                            <property name="height">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">1</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkFrame" id="size_frame">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkListBox" id="size_listbox">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="selection_mode">none</property>
++                <child>
++                  <object class="GtkListBoxRow" id="dock_size_listboxrow">
++                    <property name="width_request">100</property>
++                    <property name="height_request">80</property>
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="dock_size_grid">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="dock_size_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="label" translatable="yes">Dock size limit</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkScale" id="dock_size_scale">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="valign">baseline</property>
++                            <property name="hexpand">True</property>
++                            <property name="adjustment">dock_size_adjustment</property>
++                            <property name="round_digits">0</property>
++                            <property name="digits">2</property>
++                            <property name="value_pos">right</property>
++                            <signal name="format-value" handler="dock_size_scale_format_value_cb" swapped="no"/>
++                            <signal name="value-changed" handler="dock_size_scale_value_changed_cb" swapped="no"/>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkCheckButton" id="dock_size_extend_checkbutton">
++                            <property name="label" translatable="yes">Panel mode: extend to the screen edge</property>
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="margin_top">12</property>
++                            <property name="xalign">0</property>
++                            <property name="draw_indicator">True</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                            <property name="width">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child>
++                  <object class="GtkListBoxRow" id="icon_size_listboxrow">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="icon_size_grid">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="builtin_theme_label6">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="label" translatable="yes">Icon size limit</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkScale" id="icon_size_scale">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="valign">baseline</property>
++                            <property name="hexpand">True</property>
++                            <property name="adjustment">icon_size_adjustment</property>
++                            <property name="round_digits">1</property>
++                            <property name="digits">0</property>
++                            <property name="value_pos">right</property>
++                            <signal name="format-value" handler="icon_size_scale_format_value_cb" swapped="no"/>
++                            <signal name="value-changed" handler="icon_size_scale_value_changed_cb" swapped="no"/>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkCheckButton" id="icon_size_fixed_checkbutton">
++                            <property name="label" translatable="yes">Fixed icon size: scroll to reveal other icons</property>
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="margin_top">12</property>
++                            <property name="xalign">0</property>
++                            <property name="draw_indicator">True</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                            <property name="width">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">2</property>
++          </packing>
++        </child>
++      </object>
++    </child>
++    <child type="tab">
++      <object class="GtkLabel" id="general_label">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label" translatable="yes">Position and size</property>
++      </object>
++      <packing>
++        <property name="tab_fill">False</property>
++      </packing>
++    </child>
++    <child>
++      <object class="GtkBox" id="apps">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="margin_left">24</property>
++        <property name="margin_right">24</property>
++        <property name="margin_top">24</property>
++        <property name="margin_bottom">24</property>
++        <property name="orientation">vertical</property>
++        <property name="spacing">24</property>
++        <child>
++          <object class="GtkFrame" id="customize_theme1">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkListBox" id="listbox9">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="selection_mode">none</property>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow6">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="shrink_dash1">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkSwitch" id="show_favorite_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="halign">end</property>
++                            <property name="valign">center</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="shrink_dash_label1">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Show favorite applications</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow16">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="shrink_dash2">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkSwitch" id="show_running_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="halign">end</property>
++                            <property name="valign">center</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="shrink_dash_label2">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Show running applications</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkCheckButton" id="application_button_isolation_button">
++                            <property name="label" translatable="yes">Isolate workspaces.</property>
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="margin_top">12</property>
++                            <property name="xalign">0</property>
++                            <property name="draw_indicator">True</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">2</property>
++                            <property name="width">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkCheckButton" id="application_button_monitor_isolation_button">
++                            <property name="label" translatable="yes">Isolate monitors.</property>
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="margin_top">12</property>
++                            <property name="xalign">0</property>
++                            <property name="draw_indicator">True</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">3</property>
++                            <property name="width">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkCheckButton" id="windows_preview_button">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="margin_top">3</property>
++                            <property name="xalign">0</property>
++                            <property name="draw_indicator">True</property>
++                            <child>
++                              <object class="GtkLabel" id="windows_previews_label">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="label" translatable="yes">Show open windows previews.</property>
++                                <property name="use_markup">True</property>
++                              </object>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                            <property name="width">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow17">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="shrink_dash3">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkSwitch" id="show_applications_button_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="halign">end</property>
++                            <property name="valign">center</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                            <property name="height">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="shrink_dash_description1">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">If disabled, these settings are accessible from gnome-tweak-tool or the extension website.</property>
++                            <property name="wrap">True</property>
++                            <property name="xalign">0</property>
++                            <style>
++                              <class name="dim-label"/>
++                            </style>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="shrink_dash_label3">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Show &lt;i&gt;Applications&lt;/i&gt; icon</property>
++                            <property name="use_markup">True</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkCheckButton" id="application_button_first_button">
++                            <property name="label" translatable="yes">Move the applications button at the beginning of the dock.</property>
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="margin_top">12</property>
++                            <property name="xalign">0</property>
++                            <property name="draw_indicator">True</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">2</property>
++                            <property name="width">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkCheckButton" id="application_button_animation_button">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="margin_top">3</property>
++                            <property name="xalign">0</property>
++                            <property name="yalign">0.43000000715255737</property>
++                            <property name="draw_indicator">True</property>
++                            <child>
++                              <object class="GtkLabel" id="label3">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="label" translatable="yes">Animate &lt;i&gt;Show Applications&lt;/i&gt;.</property>
++                                <property name="use_markup">True</property>
++                              </object>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">3</property>
++                            <property name="width">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">0</property>
++          </packing>
++        </child>
++      </object>
++      <packing>
++        <property name="position">1</property>
++      </packing>
++    </child>
++    <child type="tab">
++      <object class="GtkLabel" id="launchers_label">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label" translatable="yes">Launchers</property>
++      </object>
++      <packing>
++        <property name="position">1</property>
++        <property name="tab_fill">False</property>
++      </packing>
++    </child>
++    <child>
++      <object class="GtkBox" id="behaviour">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="margin_left">24</property>
++        <property name="margin_right">24</property>
++        <property name="margin_top">24</property>
++        <property name="margin_bottom">24</property>
++        <property name="orientation">vertical</property>
++        <property name="spacing">24</property>
++        <child>
++          <object class="GtkFrame" id="hot_keys_frame">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkListBox" id="hot_keys_listbox">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="selection_mode">none</property>
++                <child>
++                  <object class="GtkListBoxRow" id="hot_keys_listboxrow">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="hot_keys_grid">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="hot_keys_description">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Enable Super+(0-9) as shortcuts to activate apps. It can also be used together with Shift and Ctrl.</property>
++                            <property name="use_markup">True</property>
++                            <property name="wrap">True</property>
++                            <property name="xalign">0</property>
++                            <style>
++                              <class name="dim-label"/>
++                            </style>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="hot_keys_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Use keyboard shortcuts to activate apps</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="overlay_box">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">6</property>
++                            <child>
++                              <object class="GtkButton" id="overlay_button">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">True</property>
++                                <property name="halign">center</property>
++                                <property name="valign">center</property>
++                                <property name="xalign">0.46000000834465027</property>
++                                <child>
++                                  <object class="GtkImage" id="image_overlay">
++                                    <property name="visible">True</property>
++                                    <property name="can_focus">False</property>
++                                    <property name="icon_name">emblem-system-symbolic</property>
++                                  </object>
++                                </child>
++                                <style>
++                                  <class name="circular"/>
++                                </style>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkSwitch" id="hot_keys_switch">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="halign">end</property>
++                                <property name="valign">center</property>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                            <property name="height">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">1</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkFrame" id="built_in_theme_frame3">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkListBox" id="listbox6">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="selection_mode">none</property>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow9">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="buitin_theme5">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="builtin_theme_description5">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Behaviour when clicking on the icon of a running application.</property>
++                            <property name="wrap">True</property>
++                            <property name="xalign">0</property>
++                            <style>
++                              <class name="dim-label"/>
++                            </style>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="builtin_theme_label5">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Click action</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="click_box">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">6</property>
++                            <child>
++                              <object class="GtkButton" id="middle_click_options_button">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">True</property>
++                                <property name="valign">center</property>
++                                <child>
++                                  <object class="GtkImage" id="middle_click_image">
++                                    <property name="visible">True</property>
++                                    <property name="can_focus">False</property>
++                                    <property name="icon_name">emblem-system-symbolic</property>
++                                  </object>
++                                </child>
++                                <style>
++                                  <class name="circular"/>
++                                </style>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkComboBoxText" id="click_action_combo">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="valign">center</property>
++                                <items>
++                                  <item translatable="yes">Raise window</item>
++                                  <item translatable="yes">Minimize</item>
++                                  <item translatable="yes">Launch new instance</item>
++                                  <item translatable="yes">Cycle through windows</item>
++                                  <item translatable="yes">Minimize or overview</item>
++                                  <item translatable="yes">Show window previews</item>
++                                  <item translatable="yes">Minimize or show previews</item>
++                                  <item translatable="yes">Focus or show previews</item>
++                                </items>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                            <property name="height">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">2</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkFrame" id="built_in_theme_frame_scroll">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkListBox" id="listbox5">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="selection_mode">none</property>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow_scroll">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="buitin_theme_scroll">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="builtin_theme_description_scroll">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Behaviour when scrolling on the icon of an application.</property>
++                            <property name="wrap">True</property>
++                            <property name="xalign">0</property>
++                            <style>
++                              <class name="dim-label"/>
++                            </style>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="builtin_theme_label_scroll">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Scroll action</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="click_box_scroll">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">6</property>
++                            <child>
++                              <object class="GtkComboBoxText" id="scroll_action_combo">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="valign">center</property>
++                                <items>
++                                  <item translatable="yes">Do nothing</item>
++                                  <item translatable="yes">Cycle through windows</item>
++                                  <item translatable="yes">Switch workspace</item>
++                                </items>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                            <property name="height">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">3</property>
++          </packing>
++        </child>
++      </object>
++      <packing>
++        <property name="position">2</property>
++      </packing>
++    </child>
++    <child type="tab">
++      <object class="GtkLabel" id="behaviour_label">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label" translatable="yes">Behavior</property>
++      </object>
++      <packing>
++        <property name="position">2</property>
++        <property name="tab_fill">False</property>
++      </packing>
++    </child>
++    <child>
++      <object class="GtkBox" id="appearance">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="margin_left">24</property>
++        <property name="margin_right">24</property>
++        <property name="margin_top">24</property>
++        <property name="margin_bottom">24</property>
++        <property name="orientation">vertical</property>
++        <property name="spacing">24</property>
++        <child>
++          <object class="GtkFrame" id="built_in_theme_frame">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkListBox" id="listbox1">
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <property name="selection_mode">none</property>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow1">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="buitin_theme">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="builtin_theme_description">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Few customizations meant to integrate the dock with the default GNOME theme. Alternatively, specific options can be enabled below.</property>
++                            <property name="wrap">True</property>
++                            <property name="xalign">0</property>
++                            <style>
++                              <class name="dim-label"/>
++                            </style>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="builtin_theme_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Use built-in theme</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkSwitch" id="builtin_theme_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="halign">end</property>
++                            <property name="valign">center</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                            <property name="height">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">0</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkFrame" id="customize_theme">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label_xalign">0</property>
++            <property name="shadow_type">in</property>
++            <child>
++              <object class="GtkListBox" id="listbox2">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="selection_mode">none</property>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow2">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="shrink_dash">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkSwitch" id="shrink_dash_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="halign">end</property>
++                            <property name="valign">center</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                            <property name="height">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="shrink_dash_description">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Save space reducing padding and border radius.</property>
++                            <property name="xalign">0</property>
++                            <style>
++                              <class name="dim-label"/>
++                            </style>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="shrink_dash_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Shrink the dash</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow3">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="running_dots">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="running_dots_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Customize windows counter indicators</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="box4">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">6</property>
++                            <child>
++                              <object class="GtkButton" id="running_indicators_advance_settings_button">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">True</property>
++                                <property name="halign">center</property>
++                                <property name="valign">center</property>
++                                <property name="xalign">0.46000000834465027</property>
++                                <child>
++                                  <object class="GtkImage" id="image1">
++                                    <property name="visible">True</property>
++                                    <property name="can_focus">False</property>
++                                    <property name="icon_name">emblem-system-symbolic</property>
++                                  </object>
++                                </child>
++                                <style>
++                                  <class name="circular"/>
++                                </style>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkComboBoxText" id="running_indicators_combo">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <items>
++                                  <item translatable="yes">Default</item>
++                                  <item translatable="yes">Dots</item>
++                                  <item translatable="yes">Squares</item>
++                                  <item translatable="yes">Dashes</item>
++                                  <item translatable="yes">Segmented</item>
++                                  <item translatable="yes">Solid</item>
++                                  <item translatable="yes">Ciliora</item>
++                                  <item translatable="yes">Metro</item>
++                                </items>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                            <property name="height">2</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <placeholder/>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child>
++                  <object class="GtkListBoxRow" id="custom_background_color_listboxrow">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkGrid" id="custom_background_color_grid">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="custom_background_color_description">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Set the background color for the dash.</property>
++                            <property name="wrap">True</property>
++                            <property name="xalign">0</property>
++                            <style>
++                              <class name="dim-label"/>
++                            </style>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="custom_background_color_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Customize the dash color</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="custom_background_color_box">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="spacing">6</property>
++                            <child>
++                              <object class="GtkColorButton" id="custom_background_color">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="receives_default">True</property>
++                                <property name="halign">center</property>
++                                <property name="valign">center</property>
++                                <property name="xalign">0.46000000834465027</property>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkSwitch" id="custom_background_color_switch">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="halign">end</property>
++                                <property name="valign">center</property>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                            <property name="height">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow4">
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkBox" id="box2">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="orientation">vertical</property>
++                        <child>
++                          <object class="GtkGrid" id="customize_opacity">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="margin_left">12</property>
++                            <property name="margin_right">12</property>
++                            <property name="margin_top">12</property>
++                            <property name="margin_bottom">12</property>
++                            <property name="column_spacing">32</property>
++                            <child>
++                              <object class="GtkLabel" id="customize_opacity_description">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="hexpand">True</property>
++                                <property name="label" translatable="yes">Tune the dash background opacity.</property>
++                                <property name="xalign">0</property>
++                                <style>
++                                  <class name="dim-label"/>
++                                </style>
++                              </object>
++                              <packing>
++                                <property name="left_attach">0</property>
++                                <property name="top_attach">1</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkLabel" id="customize_opacity_label">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="hexpand">True</property>
++                                <property name="label" translatable="yes">Customize opacity</property>
++                                <property name="xalign">0</property>
++                              </object>
++                              <packing>
++                                <property name="left_attach">0</property>
++                                <property name="top_attach">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkBox" id="customize_opacity_box">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="spacing">6</property>
++                                <child>
++                                  <object class="GtkButton" id="dynamic_opacity_button">
++                                    <property name="visible">True</property>
++                                    <property name="can_focus">True</property>
++                                    <property name="receives_default">True</property>
++                                    <property name="halign">center</property>
++                                    <property name="valign">center</property>
++                                    <child>
++                                      <object class="GtkImage" id="dynamic_opacity_image">
++                                        <property name="visible">True</property>
++                                        <property name="can_focus">False</property>
++                                        <property name="icon_name">emblem-system-symbolic</property>
++                                      </object>
++                                    </child>
++                                    <style>
++                                      <class name="circular"/>
++                                    </style>
++                                  </object>
++                                  <packing>
++                                    <property name="expand">False</property>
++                                    <property name="fill">True</property>
++                                    <property name="position">0</property>
++                                  </packing>
++                                </child>
++                                <child>
++                                  <object class="GtkComboBoxText" id="customize_opacity_combo">
++                                    <property name="visible">True</property>
++                                    <property name="can_focus">False</property>
++                                    <property name="valign">center</property>
++                                    <items>
++                                      <item translatable="yes">Default</item>
++                                      <item translatable="yes">Fixed</item>
++                                      <item translatable="yes">Dynamic</item>
++                                    </items>
++                                  </object>
++                                  <packing>
++                                    <property name="expand">False</property>
++                                    <property name="fill">True</property>
++                                    <property name="position">1</property>
++                                  </packing>
++                                </child>
++                              </object>
++                              <packing>
++                                <property name="left_attach">1</property>
++                                <property name="top_attach">0</property>
++                                <property name="height">2</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkBox" id="custom_opacity">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="margin_left">12</property>
++                            <property name="margin_right">12</property>
++                            <property name="margin_top">12</property>
++                            <property name="margin_bottom">12</property>
++                            <property name="spacing">32</property>
++                            <child>
++                              <object class="GtkLabel" id="custom_opacity_label">
++                                <property name="visible">True</property>
++                                <property name="can_focus">False</property>
++                                <property name="label" translatable="yes">Opacity</property>
++                              </object>
++                              <packing>
++                                <property name="expand">False</property>
++                                <property name="fill">True</property>
++                                <property name="position">0</property>
++                              </packing>
++                            </child>
++                            <child>
++                              <object class="GtkScale" id="custom_opacity_scale">
++                                <property name="visible">True</property>
++                                <property name="can_focus">True</property>
++                                <property name="adjustment">custom_opacity_adjustement</property>
++                                <property name="lower_stepper_sensitivity">on</property>
++                                <property name="restrict_to_fill_level">False</property>
++                                <property name="fill_level">0</property>
++                                <property name="round_digits">0</property>
++                                <property name="digits">2</property>
++                                <property name="value_pos">right</property>
++                                <signal name="format-value" handler="custom_opacity_scale_format_value_cb" swapped="no"/>
++                                <signal name="value-changed" handler="custom_opacity_scale_value_changed_cb" swapped="no"/>
++                              </object>
++                              <packing>
++                                <property name="expand">True</property>
++                                <property name="fill">True</property>
++                                <property name="position">1</property>
++                              </packing>
++                            </child>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++                <child>
++                  <object class="GtkListBoxRow" id="listboxrow_rnd_border">
++                    <property name="width_request">100</property>
++                    <property name="height_request">80</property>
++                    <property name="visible">True</property>
++                    <property name="can_focus">True</property>
++                    <child>
++                      <object class="GtkBox">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="force_straight_corner_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="valign">center</property>
++                            <property name="xpad">12</property>
++                            <property name="label" translatable="yes">Force straight corner
++</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="expand">True</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkSwitch" id="force_straight_corner_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="valign">center</property>
++                            <property name="margin_left">3</property>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="padding">12</property>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                      </object>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child type="label_item">
++              <placeholder/>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">1</property>
++          </packing>
++        </child>
++      </object>
++      <packing>
++        <property name="position">3</property>
++      </packing>
++    </child>
++    <child type="tab">
++      <object class="GtkLabel" id="appearance_label">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label" translatable="yes">Appearance</property>
++      </object>
++      <packing>
++        <property name="position">3</property>
++        <property name="tab_fill">False</property>
++      </packing>
++    </child>
++    <child>
++      <object class="GtkBox" id="about">
++        <property name="can_focus">False</property>
++        <property name="margin_top">24</property>
++        <property name="margin_bottom">24</property>
++        <property name="hexpand">True</property>
++        <property name="vexpand">True</property>
++        <property name="orientation">vertical</property>
++        <property name="spacing">5</property>
++        <child>
++          <object class="GtkImage" id="logo">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="pixbuf">./media/logo.svg</property>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="padding">10</property>
++            <property name="position">0</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkLabel" id="extension_name">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label">&lt;b&gt;Dash to Dock&lt;/b&gt;</property>
++            <property name="use_markup">True</property>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">1</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkBox" id="box1">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="halign">center</property>
++            <child>
++              <object class="GtkLabel" id="extension_version_label">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="halign">end</property>
++                <property name="label" translatable="yes">version: </property>
++              </object>
++              <packing>
++                <property name="expand">False</property>
++                <property name="fill">True</property>
++                <property name="position">0</property>
++              </packing>
++            </child>
++            <child>
++              <object class="GtkLabel" id="extension_version">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="halign">start</property>
++                <property name="label">...</property>
++              </object>
++              <packing>
++                <property name="expand">False</property>
++                <property name="fill">True</property>
++                <property name="position">1</property>
++              </packing>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">2</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkLabel" id="extension_description">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="label" translatable="yes">Moves the dash out of the overview transforming it in a dock</property>
++            <property name="justify">center</property>
++            <property name="wrap">True</property>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">3</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkBox" id="box10">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="halign">center</property>
++            <property name="spacing">5</property>
++            <child>
++              <object class="GtkLabel" id="label15">
++                <property name="visible">True</property>
++                <property name="can_focus">False</property>
++                <property name="label" translatable="yes">Created by</property>
++              </object>
++              <packing>
++                <property name="expand">False</property>
++                <property name="fill">True</property>
++                <property name="position">0</property>
++              </packing>
++            </child>
++            <child>
++              <object class="GtkLabel" id="label16">
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <property name="label">Michele (&lt;a href="mailto:micxgx@gmail.com"&gt;micxgx@gmail.com&lt;/a&gt;)</property>
++                <property name="use_markup">True</property>
++              </object>
++              <packing>
++                <property name="expand">False</property>
++                <property name="fill">True</property>
++                <property name="position">1</property>
++              </packing>
++            </child>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">4</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkLinkButton" id="homepage_link">
++            <property name="label" translatable="yes">Webpage</property>
++            <property name="visible">True</property>
++            <property name="can_focus">True</property>
++            <property name="receives_default">True</property>
++            <property name="events"/>
++            <property name="halign">center</property>
++            <property name="relief">none</property>
++            <property name="uri">https://micheleg.github.io/dash-to-dock/</property>
++          </object>
++          <packing>
++            <property name="expand">False</property>
++            <property name="fill">True</property>
++            <property name="position">5</property>
++          </packing>
++        </child>
++        <child>
++          <object class="GtkLabel" id="label1">
++            <property name="visible">True</property>
++            <property name="can_focus">True</property>
++            <property name="valign">end</property>
++            <property name="label" translatable="yes">&lt;span size="small"&gt;This program comes with ABSOLUTELY NO WARRANTY.
++See the &lt;a href="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html"&gt;GNU General Public License, version 2 or later&lt;/a&gt; for details.&lt;/span&gt;</property>
++            <property name="use_markup">True</property>
++            <property name="justify">center</property>
++            <property name="wrap">True</property>
++          </object>
++          <packing>
++            <property name="expand">True</property>
++            <property name="fill">True</property>
++            <property name="position">6</property>
++          </packing>
++        </child>
++      </object>
++      <packing>
++        <property name="position">4</property>
++      </packing>
++    </child>
++    <child type="tab">
++      <object class="GtkLabel" id="about_label">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label" translatable="yes">About</property>
++      </object>
++      <packing>
++        <property name="position">4</property>
++        <property name="tab_fill">False</property>
++      </packing>
++    </child>
++  </object>
++  <object class="GtkAdjustment" id="max_opacity_adjustement">
++    <property name="upper">1</property>
++    <property name="step_increment">0.01</property>
++    <property name="page_increment">0.10000000000000001</property>
++  </object>
++  <object class="GtkAdjustment" id="min_opacity_adjustement">
++    <property name="upper">1</property>
++    <property name="step_increment">0.01</property>
++    <property name="page_increment">0.10000000000000001</property>
++  </object>
++  <object class="GtkBox" id="advanced_transparency_dialog">
++    <property name="visible">True</property>
++    <property name="can_focus">False</property>
++    <property name="margin_left">12</property>
++    <property name="margin_right">12</property>
++    <property name="margin_top">12</property>
++    <property name="margin_bottom">12</property>
++    <property name="orientation">vertical</property>
++    <child>
++      <object class="GtkFrame" id="advanced_transparency_frame">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label_xalign">0</property>
++        <property name="shadow_type">in</property>
++        <child>
++          <object class="GtkListBox" id="advanced_transparency_listbox">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="selection_mode">none</property>
++            <child>
++              <object class="GtkListBoxRow" id="advanced_transparency_listboxrow">
++                <property name="width_request">100</property>
++                <property name="height_request">80</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkBox" id="advanced_transparency_box">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="orientation">vertical</property>
++                    <property name="spacing">12</property>
++                    <child>
++                      <object class="GtkGrid" id="advanced_transparency_grid">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="column_spacing">32</property>
++                        <child>
++                          <object class="GtkSwitch" id="customize_alphas_switch">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">1</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkLabel" id="customize_alphas_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="hexpand">True</property>
++                            <property name="label" translatable="yes">Customize minimum and maximum opacity values</property>
++                            <property name="justify">fill</property>
++                            <property name="xalign">0</property>
++                          </object>
++                          <packing>
++                            <property name="left_attach">0</property>
++                            <property name="top_attach">0</property>
++                          </packing>
++                        </child>
++                      </object>
++                      <packing>
++                        <property name="expand">False</property>
++                        <property name="fill">True</property>
++                        <property name="position">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkBox" id="min_alpha_box">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="min_alpha_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="label" translatable="yes">Minimum opacity</property>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkScale" id="min_alpha_scale">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="adjustment">min_opacity_adjustement</property>
++                            <property name="lower_stepper_sensitivity">on</property>
++                            <property name="restrict_to_fill_level">False</property>
++                            <property name="fill_level">0</property>
++                            <property name="round_digits">0</property>
++                            <property name="digits">2</property>
++                            <property name="value_pos">right</property>
++                            <signal name="format-value" handler="min_opacity_scale_format_value_cb" swapped="no"/>
++                            <signal name="value-changed" handler="min_opacity_scale_value_changed_cb" swapped="no"/>
++                          </object>
++                          <packing>
++                            <property name="expand">True</property>
++                            <property name="fill">True</property>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                      </object>
++                      <packing>
++                        <property name="expand">False</property>
++                        <property name="fill">True</property>
++                        <property name="position">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkBox" id="max_alpha_box">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="margin_left">12</property>
++                        <property name="margin_right">12</property>
++                        <property name="margin_top">12</property>
++                        <property name="margin_bottom">12</property>
++                        <property name="spacing">32</property>
++                        <child>
++                          <object class="GtkLabel" id="max_alpha_label">
++                            <property name="visible">True</property>
++                            <property name="can_focus">False</property>
++                            <property name="label" translatable="yes">Maximum opacity</property>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkScale" id="max_alpha_scale">
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="adjustment">max_opacity_adjustement</property>
++                            <property name="lower_stepper_sensitivity">on</property>
++                            <property name="restrict_to_fill_level">False</property>
++                            <property name="fill_level">0</property>
++                            <property name="round_digits">0</property>
++                            <property name="digits">2</property>
++                            <property name="value_pos">right</property>
++                            <signal name="format-value" handler="max_opacity_scale_format_value_cb" swapped="no"/>
++                            <signal name="value-changed" handler="max_opacity_scale_value_changed_cb" swapped="no"/>
++                          </object>
++                          <packing>
++                            <property name="expand">True</property>
++                            <property name="fill">True</property>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                      </object>
++                      <packing>
++                        <property name="expand">False</property>
++                        <property name="fill">True</property>
++                        <property name="position">1</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++          </object>
++        </child>
++        <child type="label_item">
++          <placeholder/>
++        </child>
++      </object>
++      <packing>
++        <property name="expand">False</property>
++        <property name="fill">True</property>
++        <property name="position">0</property>
++      </packing>
++    </child>
++  </object>
++  <object class="GtkAdjustment" id="pressure_threshold_adjustment">
++    <property name="upper">1000</property>
++    <property name="step_increment">50</property>
++    <property name="page_increment">250</property>
++  </object>
++  <object class="GtkAdjustment" id="shortcut_time_adjustment">
++    <property name="upper">10</property>
++    <property name="step_increment">0.25</property>
++    <property name="page_increment">1</property>
++  </object>
++  <object class="GtkBox" id="box_overlay_shortcut">
++    <property name="visible">True</property>
++    <property name="can_focus">False</property>
++    <property name="margin_left">12</property>
++    <property name="margin_right">12</property>
++    <property name="margin_top">12</property>
++    <property name="margin_bottom">12</property>
++    <property name="orientation">vertical</property>
++    <child>
++      <object class="GtkFrame" id="frame_overlay_show_dock">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label_xalign">0</property>
++        <property name="shadow_type">in</property>
++        <child>
++          <object class="GtkListBox" id="listbox_overlay_shortcut">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="selection_mode">none</property>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow_overlay_shortcut">
++                <property name="width_request">100</property>
++                <property name="height_request">80</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="grid_overlay">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkSwitch" id="overlay_switch">
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="halign">end</property>
++                        <property name="valign">center</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                        <property name="height">2</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="overlay_label">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Number overlay</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="overlay_description">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="label" translatable="yes">Temporarily show the application numbers over the icons, corresponding to the shortcut.</property>
++                        <property name="wrap">True</property>
++                        <property name="max_width_chars">40</property>
++                        <property name="xalign">0</property>
++                        <style>
++                          <class name="dim-label"/>
++                        </style>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow_show_dock">
++                <property name="width_request">100</property>
++                <property name="height_request">80</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="grid_show_dock">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkSwitch" id="show_dock_switch">
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="halign">end</property>
++                        <property name="valign">center</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                        <property name="height">2</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="show_dock_label">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Show the dock if it is hidden</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="show_dock_description">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="label" translatable="yes">If using autohide, the dock will appear for a short time when triggering the shortcut.</property>
++                        <property name="wrap">True</property>
++                        <property name="max_width_chars">40</property>
++                        <property name="xalign">0</property>
++                        <style>
++                          <class name="dim-label"/>
++                        </style>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow_extra_shortcut">
++                <property name="width_request">100</property>
++                <property name="height_request">80</property>
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="grid_shortcut">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkEntry" id="shortcut_entry">
++                        <property name="can_focus">True</property>
++                        <property name="valign">center</property>
++                        <property name="width_chars">12</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="shortcut_label">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Shortcut for the options above</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="shortcut_description">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="label" translatable="yes">Syntax: &lt;Shift&gt;, &lt;Ctrl&gt;, &lt;Alt&gt;, &lt;Super&gt;</property>
++                        <property name="wrap">True</property>
++                        <property name="max_width_chars">40</property>
++                        <property name="xalign">0</property>
++                        <style>
++                          <class name="dim-label"/>
++                        </style>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <placeholder/>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow_timeout">
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="grid_timeout">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="hexpand">True</property>
++                    <property name="row_spacing">6</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkSpinButton" id="timeout_spinbutton">
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="halign">end</property>
++                        <property name="adjustment">shortcut_time_adjustment</property>
++                        <property name="digits">3</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="shortcut_timeout_label">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Hide timeout (s)</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++          </object>
++        </child>
++        <child type="label_item">
++          <placeholder/>
++        </child>
++      </object>
++      <packing>
++        <property name="expand">False</property>
++        <property name="fill">True</property>
++        <property name="position">0</property>
++      </packing>
++    </child>
++  </object>
++  <object class="GtkAdjustment" id="show_timeout_adjustment">
++    <property name="upper">1</property>
++    <property name="step_increment">0.050000000000000003</property>
++    <property name="page_increment">0.25</property>
++  </object>
++  <object class="GtkBox" id="intelligent_autohide_advanced_settings_box">
++    <property name="visible">True</property>
++    <property name="can_focus">False</property>
++    <property name="margin_left">12</property>
++    <property name="margin_right">12</property>
++    <property name="margin_top">12</property>
++    <property name="margin_bottom">12</property>
++    <property name="orientation">vertical</property>
++    <child>
++      <object class="GtkFrame" id="intelligent_autohide_advanced_settings_frame">
++        <property name="visible">True</property>
++        <property name="can_focus">False</property>
++        <property name="label_xalign">0</property>
++        <property name="shadow_type">in</property>
++        <child>
++          <object class="GtkListBox" id="listbox4">
++            <property name="visible">True</property>
++            <property name="can_focus">False</property>
++            <property name="selection_mode">none</property>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow8">
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="buitin_theme2">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkLabel" id="builtin_theme_description2">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Show the dock by mouse hover on the screen edge.</property>
++                        <property name="wrap">True</property>
++                        <property name="xalign">0</property>
++                        <style>
++                          <class name="dim-label"/>
++                        </style>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="builtin_theme_label2">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Autohide</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkSwitch" id="autohide_switch">
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="halign">end</property>
++                        <property name="valign">center</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                        <property name="height">2</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkCheckButton" id="require_pressure_checkbutton">
++                        <property name="label" translatable="yes">Push to show: require pressure to show the dock</property>
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="receives_default">False</property>
++                        <property name="xalign">0</property>
++                        <property name="draw_indicator">True</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">3</property>
++                        <property name="width">2</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkCheckButton" id="autohide_enable_in_fullscreen_checkbutton">
++                        <property name="label" translatable="yes">Enable in fullscreen mode</property>
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="receives_default">False</property>
++                        <property name="margin_top">12</property>
++                        <property name="xalign">0</property>
++                        <property name="draw_indicator">True</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">2</property>
++                        <property name="width">2</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow15">
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="intellihide_grid">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkLabel" id="builtin_theme_description3">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Show the dock when it doesn't obstruct application windows.</property>
++                        <property name="wrap">True</property>
++                        <property name="xalign">0</property>
++                        <style>
++                          <class name="dim-label"/>
++                        </style>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="builtin_theme_label3">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Dodge windows</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkSwitch" id="intellihide_switch">
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="halign">end</property>
++                        <property name="valign">center</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                        <property name="height">2</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkBox" id="intellihide_mode_box">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="orientation">vertical</property>
++                        <child>
++                          <object class="GtkRadioButton" id="all_windows_radio_button">
++                            <property name="label" translatable="yes">All windows</property>
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="margin_top">12</property>
++                            <property name="xalign">0</property>
++                            <property name="active">True</property>
++                            <property name="draw_indicator">True</property>
++                            <signal name="toggled" handler="all_windows_radio_button_toggled_cb" swapped="no"/>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">0</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkRadioButton" id="focus_application_windows_radio_button">
++                            <property name="label" translatable="yes">Only focused application's windows</property>
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="xalign">0</property>
++                            <property name="active">True</property>
++                            <property name="draw_indicator">True</property>
++                            <property name="group">all_windows_radio_button</property>
++                            <signal name="toggled" handler="focus_application_windows_radio_button_toggled_cb" swapped="no"/>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">1</property>
++                          </packing>
++                        </child>
++                        <child>
++                          <object class="GtkRadioButton" id="maximized_windows_radio_button">
++                            <property name="label" translatable="yes">Only maximized windows</property>
++                            <property name="visible">True</property>
++                            <property name="can_focus">True</property>
++                            <property name="receives_default">False</property>
++                            <property name="xalign">0</property>
++                            <property name="active">True</property>
++                            <property name="draw_indicator">True</property>
++                            <property name="group">all_windows_radio_button</property>
++                            <signal name="toggled" handler="maximized_windows_radio_button_toggled_cb" swapped="no"/>
++                          </object>
++                          <packing>
++                            <property name="expand">False</property>
++                            <property name="fill">True</property>
++                            <property name="position">2</property>
++                          </packing>
++                        </child>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">2</property>
++                        <property name="width">2</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++            <child>
++              <object class="GtkListBoxRow" id="listboxrow5">
++                <property name="visible">True</property>
++                <property name="can_focus">True</property>
++                <child>
++                  <object class="GtkGrid" id="grid2">
++                    <property name="visible">True</property>
++                    <property name="can_focus">False</property>
++                    <property name="margin_left">12</property>
++                    <property name="margin_right">12</property>
++                    <property name="margin_top">12</property>
++                    <property name="margin_bottom">12</property>
++                    <property name="hexpand">True</property>
++                    <property name="row_spacing">6</property>
++                    <property name="column_spacing">32</property>
++                    <child>
++                      <object class="GtkSpinButton" id="animation_duration_spinbutton">
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="halign">end</property>
++                        <property name="adjustment">animation_time_adjustment</property>
++                        <property name="digits">3</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="label2">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Animation duration (s)</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">0</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkSpinButton" id="hide_timeout_spinbutton">
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="halign">end</property>
++                        <property name="adjustment">hide_timeout_adjustment</property>
++                        <property name="digits">3</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkSpinButton" id="show_timeout_spinbutton">
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="halign">end</property>
++                        <property name="adjustment">show_timeout_adjustment</property>
++                        <property name="digits">3</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">2</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkSpinButton" id="pressure_threshold_spinbutton">
++                        <property name="visible">True</property>
++                        <property name="can_focus">True</property>
++                        <property name="text">0.000</property>
++                        <property name="adjustment">pressure_threshold_adjustment</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">1</property>
++                        <property name="top_attach">3</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="label9">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Hide timeout (s)</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">1</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="show_timeout_label">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Show timeout (s)</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">2</property>
++                      </packing>
++                    </child>
++                    <child>
++                      <object class="GtkLabel" id="pressure_threshold_label">
++                        <property name="visible">True</property>
++                        <property name="can_focus">False</property>
++                        <property name="hexpand">True</property>
++                        <property name="label" translatable="yes">Pressure threshold</property>
++                        <property name="xalign">0</property>
++                      </object>
++                      <packing>
++                        <property name="left_attach">0</property>
++                        <property name="top_attach">3</property>
++                      </packing>
++                    </child>
++                  </object>
++                </child>
++              </object>
++            </child>
++          </object>
++        </child>
++        <child type="label_item">
++          <placeholder/>
++        </child>
++      </object>
++      <packing>
++        <property name="expand">False</property>
++        <property name="fill">True</property>
++        <property name="position">0</property>
++      </packing>
++    </child>
++  </object>
++</interface>
+diff --git a/extensions/dash-to-dock/appIconIndicators.js b/extensions/dash-to-dock/appIconIndicators.js
+new file mode 100644
+index 0000000..ddff512
+--- /dev/null
++++ b/extensions/dash-to-dock/appIconIndicators.js
+@@ -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 Pango = imports.gi.Pango;
++const Shell = imports.gi.Shell;
++const St = imports.gi.St;
++
++const Util = imports.misc.util;
++
++const Me = imports.misc.extensionUtils.getCurrentExtension();
++const Utils = Me.imports.utils;
++
++let tracker = Shell.WindowTracker.get_default();
++
++const RunningIndicatorStyle = {
++    DEFAULT: 0,
++    DOTS: 1,
++    SQUARES: 2,
++    DASHES: 3,
++    SEGMENTED: 4,
++    SOLID: 5,
++    CILIORA: 6,
++    METRO: 7
++};
++
++const MAX_WINDOWS_CLASSES = 4;
++
++
++/*
++ * This is the main indicator class to be used. The desired bahviour is
++ * obtained by composing the desired classes below based on the settings.
++ *
++ */
++var AppIconIndicator = class DashToDock_AppIconIndicator {
++
++    constructor(source, settings) {
++        this._indicators = [];
++
++        // Unity indicators always enabled for now
++        let unityIndicator = new UnityIndicator(source, settings);
++        this._indicators.push(unityIndicator);
++
++        // Choose the style for the running indicators
++        let runningIndicator = null;
++        let runningIndicatorStyle;
++
++        if (settings.get_boolean('apply-custom-theme' )) {
++            runningIndicatorStyle = RunningIndicatorStyle.DOTS;
++        } else {
++            runningIndicatorStyle = settings.get_enum('running-indicator-style');
++        }
++
++        switch (runningIndicatorStyle) {
++            case RunningIndicatorStyle.DEFAULT:
++                runningIndicator = new RunningIndicatorDefault(source, settings);
++                break;
++
++            case RunningIndicatorStyle.DOTS:
++                runningIndicator = new RunningIndicatorDots(source, settings);
++                break;
++
++            case RunningIndicatorStyle.SQUARES:
++                runningIndicator = new RunningIndicatorSquares(source, settings);
++                break;
++
++            case RunningIndicatorStyle.DASHES:
++                runningIndicator = new RunningIndicatorDashes(source, settings);
++            break;
++
++            case RunningIndicatorStyle.SEGMENTED:
++                runningIndicator = new RunningIndicatorSegmented(source, settings);
++                break;
++
++            case RunningIndicatorStyle.SOLID:
++                runningIndicator = new RunningIndicatorSolid(source, settings);
++                break;
++
++            case RunningIndicatorStyle.CILIORA:
++                runningIndicator = new RunningIndicatorCiliora(source, settings);
++                break;
++
++            case RunningIndicatorStyle.METRO:
++                runningIndicator = new RunningIndicatorMetro(source, settings);
++            break;
++
++            default:
++                runningIndicator = new RunningIndicatorBase(source, settings);
++        }
++
++        this._indicators.push(runningIndicator);
++    }
++
++    update() {
++        for (let i=0; i<this._indicators.length; i++){
++            let indicator = this._indicators[i];
++            indicator.update();
++        }
++    }
++
++    destroy() {
++        for (let i=0; i<this._indicators.length; i++){
++            let indicator = this._indicators[i];
++            indicator.destroy();
++        }
++    }
++}
++
++/*
++ * Base class to be inherited by all indicators of any kind
++*/
++var IndicatorBase = class DashToDock_IndicatorBase {
++
++    constructor(source, settings) {
++        this._settings = settings;
++        this._source = source;
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++
++        this._sourceDestroyId = this._source.actor.connect('destroy', () => {
++            this._signalsHandler.destroy();
++        });
++    }
++
++    update() {
++    }
++
++    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.
++ *
++ */
++var RunningIndicatorBase = class DashToDock_RunningIndicatorBase extends IndicatorBase {
++
++    constructor(source, settings) {
++        super(source, settings)
++
++        this._side =  Utils.getPosition(this._settings);
++        this._nWindows = 0;
++
++        this._dominantColorExtractor = new DominantColorExtractor(this._source.app);
++
++        // These statuses take into account the workspace/monitor isolation
++        this._isFocused = false;
++        this._isRunning = false;
++    }
++
++    update() {
++        // Limit to 1 to MAX_WINDOWS_CLASSES  windows classes
++        this._nWindows = Math.min(this._source.getInterestingWindows().length, MAX_WINDOWS_CLASSES);
++
++        // We need to check the number of windows, as the focus might be
++        // happening on another monitor if using isolation
++        if (tracker.focus_app == this._source.app && this._nWindows > 0)
++            this._isFocused = true;
++        else
++            this._isFocused = false;
++
++        // In the case of workspace isolation, we need to hide the dots of apps with
++        // no windows in the current workspace
++        if (this._source.app.state != Shell.AppState.STOPPED  && this._nWindows > 0)
++            this._isRunning = true;
++        else
++            this._isRunning = false;
++
++        this._updateCounterClass();
++        this._updateFocusClass();
++        this._updateDefaultDot();
++    }
++
++    _updateCounterClass() {
++        for (let i = 1; i <= MAX_WINDOWS_CLASSES; i++) {
++            let className = 'running' + i;
++            if (i != this._nWindows)
++                this._source.actor.remove_style_class_name(className);
++            else
++                this._source.actor.add_style_class_name(className);
++        }
++    }
++
++    _updateFocusClass() {
++        if (this._isFocused)
++            this._source.actor.add_style_class_name('focused');
++        else
++            this._source.actor.remove_style_class_name('focused');
++    }
++
++    _updateDefaultDot() {
++        if (this._isRunning)
++            this._source._dot.show();
++        else
++            this._source._dot.hide();
++    }
++
++    _hideDefaultDot() {
++        // I use opacity to hide the default dot because the show/hide function
++        // are used by the parent class.
++        this._source._dot.opacity = 0;
++    }
++
++    _restoreDefaultDot() {
++        this._source._dot.opacity = 255;
++    }
++
++    _enableBacklight() {
++
++        let colorPalette = this._dominantColorExtractor._getColorPalette();
++
++        // Fallback
++        if (colorPalette === null) {
++            this._source._iconContainer.set_style(
++                'border-radius: 5px;' +
++                'background-gradient-direction: vertical;' +
++                'background-gradient-start: #e0e0e0;' +
++                'background-gradient-end: darkgray;'
++            );
++
++           return;
++        }
++
++        this._source._iconContainer.set_style(
++            'border-radius: 5px;' +
++            'background-gradient-direction: vertical;' +
++            'background-gradient-start: ' + colorPalette.original + ';' +
++            'background-gradient-end: ' +  colorPalette.darker + ';'
++        );
++
++    }
++
++    _disableBacklight() {
++        this._source._iconContainer.set_style(null);
++    }
++
++    destroy() {
++        this._disableBacklight();
++        // Remove glossy background if the children still exists
++        if (this._source._iconContainer.get_children().length > 1)
++            this._source._iconContainer.get_children()[1].set_style(null);
++        this._restoreDefaultDot();
++
++        super.destroy();
++    }
++};
++
++// We add a css class so third parties themes can limit their indicaor customization
++// to the case we do nothing
++var RunningIndicatorDefault = class DashToDock_RunningIndicatorDefault extends RunningIndicatorBase {
++
++    constructor(source, settings) {
++        super(source, settings);
++        this._source.actor.add_style_class_name('default');
++    }
++
++    destory() {
++        this._source.actor.remove_style_class_name('default');
++        super.destroy();
++    }
++};
++
++var RunningIndicatorDots = class DashToDock_RunningIndicatorDots extends RunningIndicatorBase {
++
++    constructor(source, settings) {
++        super(source, settings)
++
++        this._hideDefaultDot();
++
++        this._area = new St.DrawingArea({x_expand: true, y_expand: true});
++
++        // We draw for the bottom case and rotate the canvas for other placements
++        //set center of rotatoins to the center
++        this._area.set_pivot_point(0.5, 0.5);
++        // prepare transformation matrix
++        let m = new Cogl.Matrix();
++        m.init_identity();
++
++        switch (this._side) {
++        case St.Side.TOP:
++            m.xx = -1;
++            m.rotate(180, 0, 0, 1);
++            break
++
++        case St.Side.BOTTOM:
++            // nothing
++            break;
++
++        case St.Side.LEFT:
++            m.yy = -1;
++            m.rotate(90, 0, 0, 1);
++            break;
++
++        case St.Side.RIGHT:
++            m.rotate(-90, 0, 0, 1);
++            break
++        }
++
++        this._area.set_transform(m);
++
++        this._area.connect('repaint', this._updateIndicator.bind(this));
++        this._source._iconContainer.add_child(this._area);
++
++        let keys = ['custom-theme-running-dots-color',
++                   'custom-theme-running-dots-border-color',
++                   'custom-theme-running-dots-border-width',
++                   'custom-theme-customize-running-dots',
++                   'unity-backlit-items',
++                   'running-indicator-dominant-color'];
++
++        keys.forEach(function(key) {
++            this._signalsHandler.add([
++                this._settings,
++                'changed::' + key,
++                this.update.bind(this)
++            ]);
++        }, this);
++
++        // Apply glossy background
++        // TODO: move to enable/disableBacklit to apply itonly to the running apps?
++        // TODO: move to css class for theming support
++        this._glossyBackgroundStyle = 'background-image: url(\'' + Me.path + '/media/glossy.svg\');' +
++                                      'background-size: contain;';
++    }
++
++    update() {
++        super.update();
++
++        // Enable / Disable the backlight of running apps
++        if (!this._settings.get_boolean('apply-custom-theme') && this._settings.get_boolean('unity-backlit-items')) {
++            this._source._iconContainer.get_children()[1].set_style(this._glossyBackgroundStyle);
++            if (this._isRunning)
++                this._enableBacklight();
++            else
++                this._disableBacklight();
++        } else {
++            this._disableBacklight();
++            this._source._iconContainer.get_children()[1].set_style(null);
++        }
++
++        if (this._area)
++            this._area.queue_repaint();
++    }
++
++     _computeStyle() {
++
++        let [width, height] = this._area.get_surface_size();
++        this._width = height;
++        this._height = width;
++
++        // By defaut re-use the style - background color, and border width and color -
++        // of the default dot
++        let themeNode = this._source._dot.get_theme_node();
++        this._borderColor = themeNode.get_border_color(this._side);
++        this._borderWidth = themeNode.get_border_width(this._side);
++        this._bodyColor = themeNode.get_background_color();
++
++        if (!this._settings.get_boolean('apply-custom-theme')) {
++            // Adjust for the backlit case
++            if (this._settings.get_boolean('unity-backlit-items')) {
++                // Use dominant color for dots too if the backlit is enables
++                let colorPalette = this._dominantColorExtractor._getColorPalette();
++
++                // Slightly adjust the styling
++                this._borderWidth = 2;
++
++                if (colorPalette !== null) {
++                    this._borderColor = Clutter.color_from_string(colorPalette.lighter)[1] ;
++                    this._bodyColor = Clutter.color_from_string(colorPalette.darker)[1];
++                } else {
++                    // Fallback
++                    this._borderColor = Clutter.color_from_string('white')[1];
++                    this._bodyColor = Clutter.color_from_string('gray')[1];
++                }
++            }
++
++            // Apply dominant color if requested
++            if (this._settings.get_boolean('running-indicator-dominant-color')) {
++                let colorPalette = this._dominantColorExtractor._getColorPalette();
++                if (colorPalette !== null) {
++                    this._bodyColor = Clutter.color_from_string(colorPalette.original)[1];
++                }
++            }
++
++            // Finally, use customize style if requested
++            if (this._settings.get_boolean('custom-theme-customize-running-dots')) {
++                this._borderColor = Clutter.color_from_string(this._settings.get_string('custom-theme-running-dots-border-color'))[1];
++                this._borderWidth = this._settings.get_int('custom-theme-running-dots-border-width');
++                this._bodyColor =  Clutter.color_from_string(this._settings.get_string('custom-theme-running-dots-color'))[1];
++            }
++        }
++
++        // Define the radius as an arbitrary size, but keep large enough to account
++        // for the drawing of the border.
++        this._radius = Math.max(this._width/22, this._borderWidth/2);
++        this._padding = 0; // distance from the margin
++        this._spacing = this._radius + this._borderWidth; // separation between the dots
++     }
++
++    _updateIndicator() {
++
++        let area = this._area;
++        let cr = this._area.get_context();
++
++        this._computeStyle();
++        this._drawIndicator(cr);
++        cr.$dispose();
++    }
++
++    _drawIndicator(cr) {
++        // Draw the required numbers of dots
++        let n = this._nWindows;
++
++        cr.setLineWidth(this._borderWidth);
++        Clutter.cairo_set_source_color(cr, this._borderColor);
++
++        // draw for the bottom case:
++        cr.translate((this._width - (2*n)*this._radius - (n-1)*this._spacing)/2, this._height - this._padding);
++        for (let i = 0; i < n; i++) {
++            cr.newSubPath();
++            cr.arc((2*i+1)*this._radius + i*this._spacing, -this._radius - this._borderWidth/2, this._radius, 0, 2*Math.PI);
++        }
++
++        cr.strokePreserve();
++        Clutter.cairo_set_source_color(cr, this._bodyColor);
++        cr.fill();
++    }
++
++    destroy() {
++        this._area.destroy();
++        super.destroy();
++    }
++};
++
++// Adapted from dash-to-panel by Jason DeRose
++// https://github.com/jderose9/dash-to-panel
++var RunningIndicatorCiliora = class DashToDock_RunningIndicatorCiliora extends RunningIndicatorDots {
++
++    _drawIndicator(cr) {
++        if (this._isRunning) {
++
++            let size =  Math.max(this._width/20, this._borderWidth);
++            let spacing = size; // separation between the dots
++            let lineLength = this._width - (size*(this._nWindows-1)) - (spacing*(this._nWindows-1));
++            let padding = this._borderWidth;
++            // For the backlit case here we don't want the outer border visible
++            if (this._settings.get_boolean('unity-backlit-items') && !this._settings.get_boolean('custom-theme-customize-running-dots'))
++                padding = 0;
++            let yOffset = this._height - padding - size;
++
++            cr.setLineWidth(this._borderWidth);
++            Clutter.cairo_set_source_color(cr, this._borderColor);
++
++            cr.translate(0, yOffset);
++            cr.newSubPath();
++            cr.rectangle(0, 0, lineLength, size);
++            for (let i = 1; i < this._nWindows; i++) {
++                cr.newSubPath();
++                cr.rectangle(lineLength + (i*spacing) + ((i-1)*size), 0, size, size);
++            }
++
++            cr.strokePreserve();
++            Clutter.cairo_set_source_color(cr, this._bodyColor);
++            cr.fill();
++        }
++    }
++};
++
++// Adapted from dash-to-panel by Jason DeRose
++// https://github.com/jderose9/dash-to-panel
++var RunningIndicatorSegmented = class DashToDock_RunningIndicatorSegmented extends RunningIndicatorDots {
++
++    _drawIndicator(cr) {
++        if (this._isRunning) {
++            let size =  Math.max(this._width/20, this._borderWidth);
++            let spacing = Math.ceil(this._width/18); // separation between the dots
++            let dashLength = Math.ceil((this._width - ((this._nWindows-1)*spacing))/this._nWindows);
++            let lineLength = this._width - (size*(this._nWindows-1)) - (spacing*(this._nWindows-1));
++            let padding = this._borderWidth;
++            // For the backlit case here we don't want the outer border visible
++            if (this._settings.get_boolean('unity-backlit-items') && !this._settings.get_boolean('custom-theme-customize-running-dots'))
++                padding = 0;
++            let yOffset = this._height - padding - size;
++
++            cr.setLineWidth(this._borderWidth);
++            Clutter.cairo_set_source_color(cr, this._borderColor);
++
++            cr.translate(0, yOffset);
++            for (let i = 0; i < this._nWindows; i++) {
++                cr.newSubPath();
++                cr.rectangle(i*dashLength + i*spacing, 0, dashLength, size);
++            }
++
++            cr.strokePreserve();
++            Clutter.cairo_set_source_color(cr, this._bodyColor);
++            cr.fill()
++        }
++    }
++};
++
++// Adapted from dash-to-panel by Jason DeRose
++// https://github.com/jderose9/dash-to-panel
++var RunningIndicatorSolid = class DashToDock_RunningIndicatorSolid extends RunningIndicatorDots {
++
++    _drawIndicator(cr) {
++        if (this._isRunning) {
++
++            let size =  Math.max(this._width/20, this._borderWidth);
++            let padding = this._borderWidth;
++            // For the backlit case here we don't want the outer border visible
++            if (this._settings.get_boolean('unity-backlit-items') && !this._settings.get_boolean('custom-theme-customize-running-dots'))
++                padding = 0;
++            let yOffset = this._height - padding - size;
++
++            cr.setLineWidth(this._borderWidth);
++            Clutter.cairo_set_source_color(cr, this._borderColor);
++
++            cr.translate(0, yOffset);
++            cr.newSubPath();
++            cr.rectangle(0, 0, this._width, size);
++
++            cr.strokePreserve();
++            Clutter.cairo_set_source_color(cr, this._bodyColor);
++            cr.fill();
++
++        }
++    }
++};
++
++// Adapted from dash-to-panel by Jason DeRose
++// https://github.com/jderose9/dash-to-panel
++var RunningIndicatorSquares = class DashToDock_RunningIndicatorSquares extends RunningIndicatorDots {
++
++    _drawIndicator(cr) {
++        if (this._isRunning) {
++            let size =  Math.max(this._width/11, this._borderWidth);
++            let padding = this._borderWidth;
++            let spacing = Math.ceil(this._width/18); // separation between the dots
++            let yOffset = this._height - padding - size;
++
++            cr.setLineWidth(this._borderWidth);
++            Clutter.cairo_set_source_color(cr, this._borderColor);
++
++            cr.translate(Math.floor((this._width - this._nWindows*size - (this._nWindows-1)*spacing)/2), yOffset);
++            for (let i = 0; i < this._nWindows; i++) {
++                cr.newSubPath();
++                cr.rectangle(i*size + i*spacing, 0, size, size);
++            }
++            cr.strokePreserve();
++            Clutter.cairo_set_source_color(cr, this._bodyColor);
++            cr.fill();
++        }
++    }
++}
++
++// Adapted from dash-to-panel by Jason DeRose
++// https://github.com/jderose9/dash-to-panel
++var RunningIndicatorDashes = class DashToDock_RunningIndicatorDashes extends RunningIndicatorDots {
++
++    _drawIndicator(cr) {
++        if (this._isRunning) {
++            let size =  Math.max(this._width/20, this._borderWidth);
++            let padding = this._borderWidth;
++            let spacing = Math.ceil(this._width/18); // separation between the dots
++            let dashLength = Math.floor(this._width/4) - spacing;
++            let yOffset = this._height - padding - size;
++
++            cr.setLineWidth(this._borderWidth);
++            Clutter.cairo_set_source_color(cr, this._borderColor);
++
++            cr.translate(Math.floor((this._width - this._nWindows*dashLength - (this._nWindows-1)*spacing)/2), yOffset);
++            for (let i = 0; i < this._nWindows; i++) {
++                cr.newSubPath();
++                cr.rectangle(i*dashLength + i*spacing, 0, dashLength, size);
++            }
++
++            cr.strokePreserve();
++            Clutter.cairo_set_source_color(cr, this._bodyColor);
++            cr.fill();
++        }
++    }
++}
++
++// Adapted from dash-to-panel by Jason DeRose
++// https://github.com/jderose9/dash-to-panel
++var RunningIndicatorMetro = class DashToDock_RunningIndicatorMetro extends RunningIndicatorDots {
++
++    constructor(source, settings) {
++        super(source, settings);
++        this._source.actor.add_style_class_name('metro');
++    }
++
++    destroy() {
++        this._source.actor.remove_style_class_name('metro');
++        super.destroy();
++    }
++
++    _drawIndicator(cr) {
++        if (this._isRunning) {
++            let size =  Math.max(this._width/20, this._borderWidth);
++            let padding = 0;
++            // For the backlit case here we don't want the outer border visible
++            if (this._settings.get_boolean('unity-backlit-items') && !this._settings.get_boolean('custom-theme-customize-running-dots'))
++                padding = 0;
++            let yOffset = this._height - padding - size;
++
++            let n = this._nWindows;
++            if(n <= 1) {
++                cr.translate(0, yOffset);
++                Clutter.cairo_set_source_color(cr, this._bodyColor);
++                cr.newSubPath();
++                cr.rectangle(0, 0, this._width, size);
++                cr.fill();
++            } else {
++                let blackenedLength = (1/48)*this._width; // need to scale with the SVG for the stacked highlight
++                let darkenedLength = this._isFocused ? (2/48)*this._width : (10/48)*this._width;
++                let blackenedColor = this._bodyColor.shade(.3);
++                let darkenedColor = this._bodyColor.shade(.7);
++
++                cr.translate(0, yOffset);
++
++                Clutter.cairo_set_source_color(cr, this._bodyColor);
++                cr.newSubPath();
++                cr.rectangle(0, 0, this._width - darkenedLength - blackenedLength, size);
++                cr.fill();
++                Clutter.cairo_set_source_color(cr, blackenedColor);
++                cr.newSubPath();
++                cr.rectangle(this._width - darkenedLength - blackenedLength, 0, 1, size);
++                cr.fill();
++                Clutter.cairo_set_source_color(cr, darkenedColor);
++                cr.newSubPath();
++                cr.rectangle(this._width - darkenedLength, 0, darkenedLength, size);
++                cr.fill();
++            }
++        }
++    }
++}
++
++/*
++ * Unity like notification and progress indicators
++ */
++var UnityIndicator = class DashToDock_UnityIndicator extends IndicatorBase {
++
++    constructor(source, settings) {
++
++        super(source, settings);
++
++        this._notificationBadgeLabel = new St.Label();
++        this._notificationBadgeBin = new St.Bin({
++            child: this._notificationBadgeLabel,
++            x_align: St.Align.END, y_align: St.Align.START,
++            x_expand: true, y_expand: true
++        });
++        this._notificationBadgeLabel.add_style_class_name('notification-badge');
++        this._notificationBadgeCount = 0;
++        this._notificationBadgeBin.hide();
++
++        this._source._iconContainer.add_child(this._notificationBadgeBin);
++        this._source._iconContainer.connect('allocation-changed', this.updateNotificationBadge.bind(this));
++
++        this._remoteEntries = [];
++        this._source.remoteModel.lookupById(this._source.app.id).forEach(
++            (entry) => {
++                this.insertEntryRemote(entry);
++            }
++        );
++
++        this._signalsHandler.add([
++            this._source.remoteModel,
++            'entry-added',
++            this._onLauncherEntryRemoteAdded.bind(this)
++        ], [
++            this._source.remoteModel,
++            'entry-removed',
++            this._onLauncherEntryRemoteRemoved.bind(this)
++        ])
++    }
++
++    _onLauncherEntryRemoteAdded(remoteModel, entry) {
++        if (!entry || !entry.appId())
++            return;
++        if (this._source && this._source.app && this._source.app.id == entry.appId()) {
++            this.insertEntryRemote(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() {
++        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;
++        let font_size = Math.max(10, Math.round(logicalNatWidth / 5));
++        let margin_left = Math.round(logicalNatWidth / 4);
++
++        this._notificationBadgeLabel.set_style(
++           'font-size: ' + font_size + 'px;' +
++           'margin-left: ' + margin_left + 'px;'
++        );
++
++        this._notificationBadgeBin.width = Math.round(logicalNatWidth - margin_left);
++        this._notificationBadgeLabel.clutter_text.ellipsize = Pango.EllipsizeMode.MIDDLE;
++    }
++
++    _notificationBadgeCountToText(count) {
++        if (count <= 9999) {
++            return count.toString();
++        } else if (count < 1e5) {
++            let thousands = count / 1e3;
++            return thousands.toFixed(1).toString() + "k";
++        } else if (count < 1e6) {
++            let thousands = count / 1e3;
++            return thousands.toFixed(0).toString() + "k";
++        } else if (count < 1e8) {
++            let millions = count / 1e6;
++            return millions.toFixed(1).toString() + "M";
++        } else if (count < 1e9) {
++            let millions = count / 1e6;
++            return millions.toFixed(0).toString() + "M";
++        } else {
++            let billions = count / 1e9;
++            return billions.toFixed(1).toString() + "B";
++        }
++    }
++
++    setNotificationBadge(count) {
++        this._notificationBadgeCount = count;
++        let text = this._notificationBadgeCountToText(count);
++        this._notificationBadgeLabel.set_text(text);
++    }
++
++    toggleNotificationBadge(activate) {
++        if (activate && this._notificationBadgeCount > 0) {
++            this.updateNotificationBadge();
++            this._notificationBadgeBin.show();
++        }
++        else
++            this._notificationBadgeBin.hide();
++    }
++
++    _showProgressOverlay() {
++        if (this._progressOverlayArea) {
++            this._updateProgressOverlay();
++            return;
++        }
++
++        this._progressOverlayArea = new St.DrawingArea({x_expand: true, y_expand: true});
++        this._progressOverlayArea.connect('repaint', () => {
++            this._drawProgressOverlay(this._progressOverlayArea);
++        });
++
++        this._source._iconContainer.add_child(this._progressOverlayArea);
++        this._updateProgressOverlay();
++    }
++
++    _hideProgressOverlay() {
++        if (this._progressOverlayArea)
++            this._progressOverlayArea.destroy();
++        this._progressOverlayArea = null;
++    }
++
++    _updateProgressOverlay() {
++        if (this._progressOverlayArea)
++            this._progressOverlayArea.queue_repaint();
++    }
++
++    _drawProgressOverlay(area) {
++        let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
++        let [surfaceWidth, surfaceHeight] = area.get_surface_size();
++        let cr = area.get_context();
++
++        let iconSize = this._source.icon.iconSize * scaleFactor;
++
++        let x = Math.floor((surfaceWidth - iconSize) / 2);
++        let y = Math.floor((surfaceHeight - iconSize) / 2);
++
++        let lineWidth = Math.floor(1.0 * scaleFactor);
++        let padding = Math.floor(iconSize * 0.05);
++        let width = iconSize - 2.0*padding;
++        let height = Math.floor(Math.min(18.0*scaleFactor, 0.20*iconSize));
++        x += padding;
++        y += iconSize - height - padding;
++
++        cr.setLineWidth(lineWidth);
++
++        // Draw the outer stroke
++        let stroke = new Cairo.LinearGradient(0, y, 0, y + height);
++        let fill = null;
++        stroke.addColorStopRGBA(0.5, 0.5, 0.5, 0.5, 0.1);
++        stroke.addColorStopRGBA(0.9, 0.8, 0.8, 0.8, 0.4);
++        Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill);
++
++        // Draw the background
++        x += lineWidth;
++        y += lineWidth;
++        width -= 2.0*lineWidth;
++        height -= 2.0*lineWidth;
++
++        stroke = Cairo.SolidPattern.createRGBA(0.20, 0.20, 0.20, 0.9);
++        fill = new Cairo.LinearGradient(0, y, 0, y + height);
++        fill.addColorStopRGBA(0.4, 0.25, 0.25, 0.25, 1.0);
++        fill.addColorStopRGBA(0.9, 0.35, 0.35, 0.35, 1.0);
++        Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, width, height, true, true, stroke, fill);
++
++        // Draw the finished bar
++        x += lineWidth;
++        y += lineWidth;
++        width -= 2.0*lineWidth;
++        height -= 2.0*lineWidth;
++
++        let finishedWidth = Math.ceil(this._progress * width);
++        stroke = Cairo.SolidPattern.createRGBA(0.8, 0.8, 0.8, 1.0);
++        fill = Cairo.SolidPattern.createRGBA(0.9, 0.9, 0.9, 1.0);
++
++        if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
++            Utils.drawRoundedLine(cr, x + lineWidth/2.0 + width - finishedWidth, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill);
++        else
++            Utils.drawRoundedLine(cr, x + lineWidth/2.0, y + lineWidth/2.0, finishedWidth, height, true, true, stroke, fill);
++
++        cr.$dispose();
++    }
++
++    setProgress(progress) {
++        this._progress = Math.min(Math.max(progress, 0.0), 1.0);
++        this._updateProgressOverlay();
++    }
++
++    toggleProgressOverlay(activate) {
++        if (activate) {
++            this._showProgressOverlay();
++        }
++        else {
++            this._hideProgressOverlay();
++        }
++    }
++
++    insertEntryRemote(remote) {
++        if (!remote || this._remoteEntries.indexOf(remote) !== -1)
++            return;
++
++        this._remoteEntries.push(remote);
++        this._selectEntryRemote(remote);
++    }
++
++    removeEntryRemote(remote) {
++        if (!remote || this._remoteEntries.indexOf(remote) == -1)
++            return;
++
++        this._remoteEntries.splice(this._remoteEntries.indexOf(remote), 1);
++
++        if (this._remoteEntries.length > 0) {
++            this._selectEntryRemote(this._remoteEntries[this._remoteEntries.length-1]);
++        } else {
++            this.setNotificationBadge(0);
++            this.toggleNotificationBadge(false);
++            this.setProgress(0);
++            this.toggleProgressOverlay(false);
++        }
++    }
++
++    _selectEntryRemote(remote) {
++        if (!remote)
++            return;
++
++        this._signalsHandler.removeWithLabel('entry-remotes');
++
++        this._signalsHandler.addWithLabel('entry-remotes',
++        [
++            remote,
++            'count-changed',
++            (remote, value) => {
++                this.setNotificationBadge(value);
++            }
++        ], [
++            remote,
++            'count-visible-changed',
++            (remote, value) => {
++                this.toggleNotificationBadge(value);
++            }
++        ], [
++            remote,
++            'progress-changed',
++            (remote, value) => {
++                this.setProgress(value);
++            }
++        ], [
++            remote,
++            'progress-visible-changed',
++            (remote, value) => {
++                this.toggleProgressOverlay(value);
++            }
++        ]);
++
++        this.setNotificationBadge(remote.count());
++        this.toggleNotificationBadge(remote.countVisible());
++        this.setProgress(remote.progress());
++        this.toggleProgressOverlay(remote.progressVisible());
++    }
++}
++
++
++// We need an icons theme object, this is the only way I managed to get
++// pixel buffers that can be used for calculating the backlight color
++let themeLoader = null;
++
++// Global icon cache. Used for Unity7 styling.
++let iconCacheMap = new Map();
++// Max number of items to store
++// We don't expect to ever reach this number, but let's put an hard limit to avoid
++// even the remote possibility of the cached items to grow indefinitely.
++const MAX_CACHED_ITEMS = 1000;
++// When the size exceed it, the oldest 'n' ones are deleted
++const  BATCH_SIZE_TO_DELETE = 50;
++// The icon size used to extract the dominant color
++const DOMINANT_COLOR_ICON_SIZE = 64;
++
++// Compute dominant color frim the app icon.
++// The color is cached for efficiency.
++var DominantColorExtractor = class DashToDock_DominantColorExtractor {
++
++    constructor(app) {
++        this._app = app;
++    }
++
++    /**
++     * Try to get the pixel buffer for the current icon, if not fail gracefully
++     */
++    _getIconPixBuf() {
++        let iconTexture = this._app.create_icon_texture(16);
++
++        if (themeLoader === null) {
++            let ifaceSettings = new Gio.Settings({ schema: "org.gnome.desktop.interface" });
++
++            themeLoader = new Gtk.IconTheme(),
++            themeLoader.set_custom_theme(ifaceSettings.get_string('icon-theme')); // Make sure the correct theme is loaded
++        }
++
++        // Unable to load the icon texture, use fallback
++        if (iconTexture instanceof St.Icon === false) {
++            return null;
++        }
++
++        iconTexture = iconTexture.get_gicon();
++
++        // Unable to load the icon texture, use fallback
++        if (iconTexture === null) {
++            return null;
++        }
++
++        if (iconTexture instanceof Gio.FileIcon) {
++            // Use GdkPixBuf to load the pixel buffer from the provided file path
++            return GdkPixbuf.Pixbuf.new_from_file(iconTexture.get_file().get_path());
++        }
++
++        // Get the pixel buffer from the icon theme
++        let icon_info = themeLoader.lookup_icon(iconTexture.get_names()[0], DOMINANT_COLOR_ICON_SIZE, 0);
++        if (icon_info !== null)
++            return icon_info.load_icon();
++        else
++            return null;
++    }
++
++    /**
++     * The backlight color choosing algorithm was mostly ported to javascript from the
++     * Unity7 C++ source of Canonicals:
++     * https://bazaar.launchpad.net/~unity-team/unity/trunk/view/head:/launcher/LauncherIcon.cpp
++     * so it more or less works the same way.
++     */
++    _getColorPalette() {
++        if (iconCacheMap.get(this._app.get_id())) {
++            // We already know the answer
++            return iconCacheMap.get(this._app.get_id());
++        }
++
++        let pixBuf = this._getIconPixBuf();
++        if (pixBuf == null)
++            return null;
++
++        let pixels = pixBuf.get_pixels(),
++            offset = 0;
++
++        let total  = 0,
++            rTotal = 0,
++            gTotal = 0,
++            bTotal = 0;
++
++        let resample_y = 1,
++            resample_x = 1;
++
++        // Resampling of large icons
++        // We resample icons larger than twice the desired size, as the resampling
++        // to a size s
++        // DOMINANT_COLOR_ICON_SIZE < s < 2*DOMINANT_COLOR_ICON_SIZE,
++        // most of the case exactly DOMINANT_COLOR_ICON_SIZE as the icon size is tipycally
++        // a multiple of it.
++        let width = pixBuf.get_width();
++        let height = pixBuf.get_height();
++
++        // Resample
++        if (height >= 2* DOMINANT_COLOR_ICON_SIZE)
++            resample_y = Math.floor(height/DOMINANT_COLOR_ICON_SIZE);
++
++        if (width >= 2* DOMINANT_COLOR_ICON_SIZE)
++            resample_x = Math.floor(width/DOMINANT_COLOR_ICON_SIZE);
++
++        if (resample_x !==1 || resample_y !== 1)
++            pixels = this._resamplePixels(pixels, resample_x, resample_y);
++
++        // computing the limit outside the for (where it would be repeated at each iteration)
++        // for performance reasons
++        let limit = pixels.length;
++        for (let offset = 0; offset < limit; offset+=4) {
++            let r = pixels[offset],
++                g = pixels[offset + 1],
++                b = pixels[offset + 2],
++                a = pixels[offset + 3];
++
++            let saturation = (Math.max(r,g, b) - Math.min(r,g, b));
++            let relevance  = 0.1 * 255 * 255 + 0.9 * a * saturation;
++
++            rTotal += r * relevance;
++            gTotal += g * relevance;
++            bTotal += b * relevance;
++
++            total += relevance;
++        }
++
++        total = total * 255;
++
++        let r = rTotal / total,
++            g = gTotal / total,
++            b = bTotal / total;
++
++        let hsv = Utils.ColorUtils.RGBtoHSV(r * 255, g * 255, b * 255);
++
++        if (hsv.s > 0.15)
++            hsv.s = 0.65;
++        hsv.v = 0.90;
++
++        let rgb = Utils.ColorUtils.HSVtoRGB(hsv.h, hsv.s, hsv.v);
++
++        // Cache the result.
++        let backgroundColor = {
++            lighter:  Utils.ColorUtils.ColorLuminance(rgb.r, rgb.g, rgb.b, 0.2),
++            original: Utils.ColorUtils.ColorLuminance(rgb.r, rgb.g, rgb.b, 0),
++            darker:   Utils.ColorUtils.ColorLuminance(rgb.r, rgb.g, rgb.b, -0.5)
++        };
++
++        if (iconCacheMap.size >= MAX_CACHED_ITEMS) {
++            //delete oldest cached values (which are in order of insertions)
++            let ctr=0;
++            for (let key of iconCacheMap.keys()) {
++                if (++ctr > BATCH_SIZE_TO_DELETE)
++                    break;
++                iconCacheMap.delete(key);
++            }
++        }
++
++        iconCacheMap.set(this._app.get_id(), backgroundColor);
++
++        return backgroundColor;
++    }
++
++    /**
++     * Downsample large icons before scanning for the backlight color to
++     * improve performance.
++     *
++     * @param pixBuf
++     * @param pixels
++     * @param resampleX
++     * @param resampleY
++     *
++     * @return [];
++     */
++    _resamplePixels (pixels, resampleX, resampleY) {
++        let resampledPixels = [];
++        // computing the limit outside the for (where it would be repeated at each iteration)
++        // for performance reasons
++        let limit = pixels.length / (resampleX * resampleY) / 4;
++        for (let i = 0; i < limit; i++) {
++            let pixel = i * resampleX * resampleY;
++
++            resampledPixels.push(pixels[pixel * 4]);
++            resampledPixels.push(pixels[pixel * 4 + 1]);
++            resampledPixels.push(pixels[pixel * 4 + 2]);
++            resampledPixels.push(pixels[pixel * 4 + 3]);
++        }
++
++        return resampledPixels;
++    }
++};
+diff --git a/extensions/dash-to-dock/appIcons.js b/extensions/dash-to-dock/appIcons.js
+new file mode 100644
+index 0000000..3b28304
+--- /dev/null
++++ b/extensions/dash-to-dock/appIcons.js
+@@ -0,0 +1,1172 @@
++// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
++
++const Clutter = imports.gi.Clutter;
++const GdkPixbuf = imports.gi.GdkPixbuf
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++const Gtk = imports.gi.Gtk;
++const Signals = imports.signals;
++const Meta = imports.gi.Meta;
++const Shell = imports.gi.Shell;
++const St = imports.gi.St;
++const Mainloop = imports.mainloop;
++
++// Use __ () and N__() for the extension gettext domain, and reuse
++// the shell domain with the default _() and N_()
++const Gettext = imports.gettext.domain('dashtodock');
++const __ = Gettext.gettext;
++const N__ = function(e) { return e };
++
++const AppDisplay = imports.ui.appDisplay;
++const AppFavorites = imports.ui.appFavorites;
++const Dash = imports.ui.dash;
++const DND = imports.ui.dnd;
++const IconGrid = imports.ui.iconGrid;
++const Main = imports.ui.main;
++const PopupMenu = imports.ui.popupMenu;
++const Tweener = imports.ui.tweener;
++const Util = imports.misc.util;
++const Workspace = imports.ui.workspace;
++
++const Me = imports.misc.extensionUtils.getCurrentExtension();
++const Utils = Me.imports.utils;
++const WindowPreview = Me.imports.windowPreview;
++const AppIconIndicators = Me.imports.appIconIndicators;
++
++let tracker = Shell.WindowTracker.get_default();
++
++let DASH_ITEM_LABEL_SHOW_TIME = Dash.DASH_ITEM_LABEL_SHOW_TIME;
++
++const clickAction = {
++    SKIP: 0,
++    MINIMIZE: 1,
++    LAUNCH: 2,
++    CYCLE_WINDOWS: 3,
++    MINIMIZE_OR_OVERVIEW: 4,
++    PREVIEWS: 5,
++    MINIMIZE_OR_PREVIEWS: 6,
++    FOCUS_OR_PREVIEWS: 7,
++    QUIT: 8,
++};
++
++const scrollAction = {
++    DO_NOTHING: 0,
++    CYCLE_WINDOWS: 1,
++    SWITCH_WORKSPACE: 2
++};
++
++let recentlyClickedAppLoopId = 0;
++let recentlyClickedApp = null;
++let recentlyClickedAppWindows = null;
++let recentlyClickedAppIndex = 0;
++let recentlyClickedAppMonitor = -1;
++
++/**
++ * Extend AppIcon
++ *
++ * - Pass settings to the constructor and bind settings changes
++ * - Apply a css class based on the number of windows of each application (#N);
++ * - Customized indicators for running applications in place of the default "dot" style which is hidden (#N);
++ *   a class of the form "running#N" is applied to the AppWellIcon actor.
++ *   like the original .running one.
++ * - Add a .focused style to the focused app
++ * - Customize click actions.
++ * - Update minimization animation target
++ * - Update menu if open on windows change
++ */
++var MyAppIcon = class DashToDock_AppIcon extends AppDisplay.AppIcon {
++
++    // settings are required inside.
++    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;
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++        this.remoteModel = remoteModel;
++        this._indicator = null;
++
++        this._updateIndicatorStyle();
++
++        // Monitor windows-changes instead of app state.
++        // Keep using the same Id and function callback (that is extended)
++        if (this._stateChangedId > 0) {
++            this.app.disconnect(this._stateChangedId);
++            this._stateChangedId = 0;
++        }
++
++        this._windowsChangedId = this.app.connect('windows-changed',
++                                                  this.onWindowsChanged.bind(this));
++        this._focusAppChangeId = tracker.connect('notify::focus-app',
++                                                 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
++        // of any application opened or moved to a different desktop),
++        // we restrict this signal to  the case when 'isolate-monitors' is true,
++        // and if there are at least 2 monitors.
++        if (this._dtdSettings.get_boolean('isolate-monitors') &&
++            Main.layoutManager.monitors.length > 1) {
++            this._signalsHandler.removeWithLabel('isolate-monitors');
++            this._signalsHandler.addWithLabel('isolate-monitors', [
++                global.display,
++                'window-entered-monitor',
++                this._onWindowEntered.bind(this)
++            ]);
++        }
++
++        this._progressOverlayArea = null;
++        this._progress = 0;
++
++        let keys = ['apply-custom-theme',
++                   'running-indicator-style',
++                    ];
++
++        keys.forEach(function(key) {
++            this._signalsHandler.add([
++                this._dtdSettings,
++                'changed::' + key,
++                this._updateIndicatorStyle.bind(this)
++            ]);
++        }, this);
++
++        this._dtdSettings.connect('changed::scroll-action', () => {
++            this._optionalScrollCycleWindows();
++        });
++        this._optionalScrollCycleWindows();
++
++        this._numberOverlay();
++
++        this._previewMenuManager = null;
++        this._previewMenu = null;
++    }
++
++    _onDestroy() {
++        super._onDestroy();
++
++        // This is necessary due to an upstream bug
++        // https://bugzilla.gnome.org/show_bug.cgi?id=757556
++        // It can be safely removed once it get solved upstrea.
++        if (this._menu)
++            this._menu.close(false);
++
++        // Disconect global signals
++
++        if (this._windowsChangedId > 0)
++            this.app.disconnect(this._windowsChangedId);
++        this._windowsChangedId = 0;
++
++        if (this._focusAppChangeId > 0) {
++            tracker.disconnect(this._focusAppChangeId);
++            this._focusAppChangeId = 0;
++        }
++
++        this._signalsHandler.destroy();
++
++        if (this._scrollEventHandler)
++            this.actor.disconnect(this._scrollEventHandler);
++    }
++
++    // TOOD Rename this function
++    _updateIndicatorStyle() {
++
++        if (this._indicator !== null) {
++            this._indicator.destroy();
++            this._indicator = null;
++        }
++        this._indicator = new AppIconIndicators.AppIconIndicator(this, this._dtdSettings);
++        this._indicator.update();
++    }
++
++    _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() {
++        if (this._scrollEventHandler) {
++            this.actor.disconnect(this._scrollEventHandler);
++            this._scrollEventHandler = 0;
++        }
++
++        let isEnabled = this._dtdSettings.get_enum('scroll-action') === scrollAction.CYCLE_WINDOWS;
++        if (!isEnabled) return;
++        this._scrollEventHandler = this.actor.connect('scroll-event',
++                                                      this.onScrollEvent.bind(this));
++    }
++
++    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
++        // case we use workspace isolation,
++        let appIsRunning = this.app.state == Shell.AppState.RUNNING
++            && this.getInterestingWindows().length > 0;
++
++        if (!appIsRunning)
++            return false
++
++        if (this._optionalScrollCycleWindowsDeadTimeId > 0)
++            return false;
++        else
++            this._optionalScrollCycleWindowsDeadTimeId = Mainloop.timeout_add(250, () => {
++                this._optionalScrollCycleWindowsDeadTimeId = 0;
++            });
++
++        let direction = null;
++
++        switch (event.get_scroll_direction()) {
++        case Clutter.ScrollDirection.UP:
++            direction = Meta.MotionDirection.UP;
++            break;
++        case Clutter.ScrollDirection.DOWN:
++            direction = Meta.MotionDirection.DOWN;
++            break;
++        case Clutter.ScrollDirection.SMOOTH:
++            let [dx, dy] = event.get_scroll_delta();
++            if (dy < 0)
++                direction = Meta.MotionDirection.UP;
++            else if (dy > 0)
++                direction = Meta.MotionDirection.DOWN;
++            break;
++        }
++
++        let focusedApp = tracker.focus_app;
++        if (!Main.overview._shown) {
++            let reversed = direction === Meta.MotionDirection.UP;
++            if (this.app == focusedApp)
++                this._cycleThroughWindows(reversed);
++            else {
++                // Activate the first window
++                let windows = this.getInterestingWindows();
++                if (windows.length > 0) {
++                    let w = windows[0];
++                    Main.activateWindow(w);
++                }
++            }
++        }
++        else
++            this.app.activate();
++        return true;
++    }
++
++    onWindowsChanged() {
++
++        if (this._menu && this._menu.isOpen)
++            this._menu.update();
++
++        this._indicator.update();
++        this.updateIconGeometry();
++    }
++
++    /**
++     * Update taraget for minimization animation
++     */
++    updateIconGeometry() {
++        // If (for unknown reason) the actor is not on the stage the reported size
++        // and position are random values, which might exceeds the integer range
++        // resulting in an error when assigned to the a rect. This is a more like
++        // a workaround to prevent flooding the system with errors.
++        if (this.actor.get_stage() == null)
++            return;
++
++        let rect = new Meta.Rectangle();
++
++        [rect.x, rect.y] = this.actor.get_transformed_position();
++        [rect.width, rect.height] = this.actor.get_transformed_size();
++
++        let windows = this.app.get_windows();
++        if (this._dtdSettings.get_boolean('multi-monitor')){
++            let monitorIndex = this.monitorIndex;
++            windows = windows.filter(function(w) {
++                return w.get_monitor() == monitorIndex;
++            });
++        }
++        windows.forEach(function(w) {
++            w.set_icon_geometry(rect);
++        });
++    }
++
++    _updateRunningStyle() {
++        // The logic originally in this function has been moved to
++        // AppIconIndicatorBase._updateDefaultDot(). However it cannot be removed as
++        // it called by the parent constructor.
++    }
++
++    popupMenu() {
++        this._removeMenuTimeout();
++        this.actor.fake_release();
++        this._draggable.fakeRelease();
++
++        if (!this._menu) {
++            this._menu = new MyAppIconMenu(this, this._dtdSettings);
++            this._menu.connect('activate-window', (menu, window) => {
++                this.activateWindow(window);
++            });
++            this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
++                if (!isPoppedUp)
++                    this._onMenuPoppedDown();
++                else {
++                    // Setting the max-height is s useful if part of the menu is
++                    // scrollable so the minimum height is smaller than the natural height.
++                    let monitor_index = Main.layoutManager.findIndexForActor(this.actor);
++                    let workArea = Main.layoutManager.getWorkAreaForMonitor(monitor_index);
++                    let position = Utils.getPosition(this._dtdSettings);
++                    this._isHorizontal = ( position == St.Side.TOP ||
++                                           position == St.Side.BOTTOM);
++                    // If horizontal also remove the height of the dash
++                    let additional_margin = this._isHorizontal && !this._dtdSettings.get_boolean('dock-fixed') ? Main.overview._dash.actor.height : 0;
++                    let verticalMargins = this._menu.actor.margin_top + this._menu.actor.margin_bottom;
++                    // Also set a max width to the menu, so long labels (long windows title) get truncated
++                    this._menu.actor.style = ('max-height: ' + Math.round(workArea.height - additional_margin - verticalMargins) + 'px;' +
++                                              'max-width: 400px');
++                }
++            });
++            let id = Main.overview.connect('hiding', () => {
++                this._menu.close();
++            });
++            this._menu.actor.connect('destroy', function() {
++                Main.overview.disconnect(id);
++            });
++
++            this._menuManager.addMenu(this._menu);
++        }
++
++        this.emit('menu-state-changed', true);
++
++        this.actor.set_hover(true);
++        this._menu.popup();
++        this._menuManager.ignoreRelease();
++        this.emit('sync-tooltip');
++
++        return false;
++    }
++
++    _onFocusAppChanged() {
++        this._indicator.update();
++    }
++
++    activate(button) {
++        let event = Clutter.get_current_event();
++        let modifiers = event ? event.get_state() : 0;
++        let focusedApp = tracker.focus_app;
++
++        // Only consider SHIFT and CONTROL as modifiers (exclude SUPER, CAPS-LOCK, etc.)
++        modifiers = modifiers & (Clutter.ModifierType.SHIFT_MASK | Clutter.ModifierType.CONTROL_MASK);
++
++        // We don't change the CTRL-click behaviour: in such case we just chain
++        // up the parent method and return.
++        if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
++                // Keep default behaviour: launch new window
++                // By calling the parent method I make it compatible
++                // with other extensions tweaking ctrl + click
++                super.activate(button);
++                return;
++        }
++
++        // We check what type of click we have and if the modifier SHIFT is
++        // being used. We then define what buttonAction should be for this
++        // event.
++        let buttonAction = 0;
++        if (button && button == 2 ) {
++            if (modifiers & Clutter.ModifierType.SHIFT_MASK)
++                buttonAction = this._dtdSettings.get_enum('shift-middle-click-action');
++            else
++                buttonAction = this._dtdSettings.get_enum('middle-click-action');
++        }
++        else if (button && button == 1) {
++            if (modifiers & Clutter.ModifierType.SHIFT_MASK)
++                buttonAction = this._dtdSettings.get_enum('shift-click-action');
++            else
++                buttonAction = this._dtdSettings.get_enum('click-action');
++        }
++
++        // We check if the app is running, and that the # of windows is > 0 in
++        // case we use workspace isolation.
++        let windows = this.getInterestingWindows();
++        let appIsRunning = this.app.state == Shell.AppState.RUNNING
++            && windows.length > 0;
++
++        // Some action modes (e.g. MINIMIZE_OR_OVERVIEW) require overview to remain open
++        // This variable keeps track of this
++        let shouldHideOverview = true;
++
++        // We customize the action only when the application is already running
++        if (appIsRunning) {
++            switch (buttonAction) {
++            case clickAction.MINIMIZE:
++                // In overview just activate the app, unless the acion is explicitely
++                // requested with a keyboard modifier
++                if (!Main.overview._shown || modifiers){
++                    // If we have button=2 or a modifier, allow minimization even if
++                    // the app is not focused
++                    if (this.app == focusedApp || button == 2 || modifiers & Clutter.ModifierType.SHIFT_MASK) {
++                        // minimize all windows on double click and always in the case of primary click without
++                        // additional modifiers
++                        let click_count = 0;
++                        if (Clutter.EventType.CLUTTER_BUTTON_PRESS)
++                            click_count = event.get_click_count();
++                        let all_windows = (button == 1 && ! modifiers) || click_count > 1;
++                        this._minimizeWindow(all_windows);
++                    }
++                    else
++                        this._activateAllWindows();
++                }
++                else {
++                    let w = windows[0];
++                    Main.activateWindow(w);
++                }
++                break;
++
++            case clickAction.MINIMIZE_OR_OVERVIEW:
++                // When a single window is present, toggle minimization
++                // If only one windows is present toggle minimization, but only when trigggered with the
++                // simple click action (no modifiers, no middle click).
++                if (windows.length == 1 && !modifiers && button == 1) {
++                    let w = windows[0];
++                    if (this.app == focusedApp) {
++                        // Window is raised, minimize it
++                        this._minimizeWindow(w);
++                    } else {
++                        // Window is minimized, raise it
++                        Main.activateWindow(w);
++                    }
++                    // Launch overview when multiple windows are present
++                    // TODO: only show current app windows when gnome shell API will allow it
++                } else {
++                    shouldHideOverview = false;
++                    Main.overview.toggle();
++                }
++                break;
++
++            case clickAction.CYCLE_WINDOWS:
++                if (!Main.overview._shown){
++                    if (this.app == focusedApp)
++                        this._cycleThroughWindows();
++                    else {
++                        // Activate the first window
++                        let w = windows[0];
++                        Main.activateWindow(w);
++                    }
++                }
++                else
++                    this.app.activate();
++                break;
++
++            case clickAction.FOCUS_OR_PREVIEWS:
++                if (this.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;
++
++            case clickAction.PREVIEWS:
++                if (!Main.overview._shown) {
++                    // If only one windows is present just switch to it, but only when trigggered with the
++                    // simple click action (no modifiers, no middle click).
++                    if (windows.length == 1 && !modifiers && button == 1) {
++                        let w = windows[0];
++                        Main.activateWindow(w);
++                    } else
++                        this._windowPreviews();
++                }
++                else {
++                    this.app.activate();
++                }
++                break;
++
++            case clickAction.MINIMIZE_OR_PREVIEWS:
++                // When a single window is present, toggle minimization
++                // If only one windows is present toggle minimization, but only when trigggered with the
++                // simple click action (no modifiers, no middle click).
++                if (!Main.overview._shown){
++                    if (windows.length == 1 && !modifiers && button == 1) {
++                        let w = windows[0];
++                        if (this.app == focusedApp) {
++                            // Window is raised, minimize it
++                            this._minimizeWindow(w);
++                        } else {
++                            // Window is minimized, raise it
++                            Main.activateWindow(w);
++                        }
++                    } else {
++                        // Launch previews when multiple windows are present
++                        this._windowPreviews();
++                    }
++                } else {
++                    this.app.activate();
++                }
++                break;
++
++            case clickAction.QUIT:
++                this.closeAllWindows();
++                break;
++
++            case clickAction.SKIP:
++                let w = windows[0];
++                Main.activateWindow(w);
++                break;
++            }
++        }
++        else {
++            this.launchNewWindow();
++        }
++
++        // Hide overview except when action mode requires it
++        if(shouldHideOverview) {
++            Main.overview.hide();
++        }
++    }
++
++    shouldShowTooltip() {
++        return this.actor.hover && (!this._menu || !this._menu.isOpen) &&
++                            (!this._previewMenu || !this._previewMenu.isOpen);
++    }
++
++    _windowPreviews() {
++        if (!this._previewMenu) {
++            this._previewMenuManager = new PopupMenu.PopupMenuManager(this);
++
++            this._previewMenu = new WindowPreview.WindowPreviewMenu(this, this._dtdSettings);
++
++            this._previewMenuManager.addMenu(this._previewMenu);
++
++            this._previewMenu.connect('open-state-changed', (menu, isPoppedUp) => {
++                if (!isPoppedUp)
++                    this._onMenuPoppedDown();
++            });
++            let id = Main.overview.connect('hiding', () => {
++                this._previewMenu.close();
++            });
++            this._previewMenu.actor.connect('destroy', function() {
++                Main.overview.disconnect(id);
++            });
++
++        }
++
++        if (this._previewMenu.isOpen)
++            this._previewMenu.close();
++        else
++            this._previewMenu.popup();
++
++        return false;
++    }
++
++    // Try to do the right thing when attempting to launch a new window of an app. In
++    // particular, if the application doens't allow to launch a new window, activate
++    // the existing window instead.
++    launchNewWindow(p) {
++        let appInfo = this.app.get_app_info();
++        let actions = appInfo.list_actions();
++        if (this.app.can_open_new_window()) {
++            this.animateLaunch();
++            // This is used as a workaround for a bug resulting in no new windows being opened
++            // for certain running applications when calling open_new_window().
++            //
++            // https://bugzilla.gnome.org/show_bug.cgi?id=756844
++            //
++            // Similar to what done when generating the popupMenu entries, if the application provides
++            // a "New Window" action, use it instead of directly requesting a new window with
++            // open_new_window(), which fails for certain application, notably Nautilus.
++            if (actions.indexOf('new-window') == -1) {
++                this.app.open_new_window(-1);
++            }
++            else {
++                let i = actions.indexOf('new-window');
++                if (i !== -1)
++                    this.app.launch_action(actions[i], global.get_current_time(), -1);
++            }
++        }
++        else {
++            // Try to manually activate the first window. Otherwise, when the app is activated by
++            // switching to a different workspace, a launch spinning icon is shown and disappers only
++            // after a timeout.
++            let windows = this.app.get_windows();
++            if (windows.length > 0)
++                Main.activateWindow(windows[0])
++            else
++                this.app.activate();
++        }
++    }
++
++    _numberOverlay() {
++        // Add label for a Hot-Key visual aid
++        this._numberOverlayLabel = new St.Label();
++        this._numberOverlayBin = new St.Bin({
++            child: this._numberOverlayLabel,
++            x_align: St.Align.START, y_align: St.Align.START,
++            x_expand: true, y_expand: true
++        });
++        this._numberOverlayLabel.add_style_class_name('number-overlay');
++        this._numberOverlayOrder = -1;
++        this._numberOverlayBin.hide();
++
++        this._iconContainer.add_child(this._numberOverlayBin);
++
++    }
++
++    updateNumberOverlay() {
++        // We apply an overall scale factor that might come from a HiDPI monitor.
++        // Clutter dimensions are in physical pixels, but CSS measures are in logical
++        // pixels, so make sure to consider the scale.
++        let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
++        // Set the font size to something smaller than the whole icon so it is
++        // still visible. The border radius is large to make the shape circular
++        let [minWidth, natWidth] = this._iconContainer.get_preferred_width(-1);
++        let font_size = Math.round(Math.max(12, 0.3*natWidth) / scaleFactor);
++        let size = Math.round(font_size*1.2);
++        this._numberOverlayLabel.set_style(
++           'font-size: ' + font_size + 'px;' +
++           'border-radius: ' + this.icon.iconSize + 'px;' +
++           'width: ' + size + 'px; height: ' + size +'px;'
++        );
++    }
++
++    setNumberOverlay(number) {
++        this._numberOverlayOrder = number;
++        this._numberOverlayLabel.set_text(number.toString());
++    }
++
++    toggleNumberOverlay(activate) {
++        if (activate && this._numberOverlayOrder > -1) {
++            this.updateNumberOverlay();
++            this._numberOverlayBin.show();
++        }
++        else
++            this._numberOverlayBin.hide();
++    }
++
++    _minimizeWindow(param) {
++        // Param true make all app windows minimize
++        let windows = this.getInterestingWindows();
++        let current_workspace = global.workspace_manager.get_active_workspace();
++        for (let i = 0; i < windows.length; i++) {
++            let w = windows[i];
++            if (w.get_workspace() == current_workspace && w.showing_on_its_workspace()) {
++                w.minimize();
++                // Just minimize one window. By specification it should be the
++                // focused window on the current workspace.
++                if(!param)
++                    break;
++            }
++        }
++    }
++
++    // By default only non minimized windows are activated.
++    // This activates all windows in the current workspace.
++    _activateAllWindows() {
++        // First activate first window so workspace is switched if needed.
++        // We don't do this if isolation is on!
++        if (!this._dtdSettings.get_boolean('isolate-workspaces') &&
++            !this._dtdSettings.get_boolean('isolate-monitors'))
++            this.app.activate();
++
++        // then activate all other app windows in the current workspace
++        let windows = this.getInterestingWindows();
++        let activeWorkspace = global.workspace_manager.get_active_workspace_index();
++
++        if (windows.length <= 0)
++            return;
++
++        let activatedWindows = 0;
++
++        for (let i = windows.length - 1; i >= 0; i--) {
++            if (windows[i].get_workspace().index() == activeWorkspace) {
++                Main.activateWindow(windows[i]);
++                activatedWindows++;
++            }
++        }
++    }
++
++    //This closes all windows of the app.
++    closeAllWindows() {
++        let windows = this.getInterestingWindows();
++        for (let i = 0; i < windows.length; i++)
++            windows[i].delete(global.get_current_time());
++    }
++
++    _cycleThroughWindows(reversed) {
++        // Store for a little amount of time last clicked app and its windows
++        // since the order changes upon window interaction
++        let MEMORY_TIME=3000;
++
++        let app_windows = this.getInterestingWindows();
++
++        if (app_windows.length <1)
++            return
++
++        if (recentlyClickedAppLoopId > 0)
++            Mainloop.source_remove(recentlyClickedAppLoopId);
++        recentlyClickedAppLoopId = Mainloop.timeout_add(MEMORY_TIME, this._resetRecentlyClickedApp);
++
++        // If there isn't already a list of windows for the current app,
++        // or the stored list is outdated, use the current windows list.
++        let monitorIsolation = this._dtdSettings.get_boolean('isolate-monitors');
++        if (!recentlyClickedApp ||
++            recentlyClickedApp.get_id() != this.app.get_id() ||
++            recentlyClickedAppWindows.length != app_windows.length ||
++            (recentlyClickedAppMonitor != this.monitorIndex && monitorIsolation)) {
++            recentlyClickedApp = this.app;
++            recentlyClickedAppWindows = app_windows;
++            recentlyClickedAppMonitor = this.monitorIndex;
++            recentlyClickedAppIndex = 0;
++        }
++
++        if (reversed) {
++            recentlyClickedAppIndex--;
++            if (recentlyClickedAppIndex < 0) recentlyClickedAppIndex = recentlyClickedAppWindows.length - 1;
++        } else {
++            recentlyClickedAppIndex++;
++        }
++        let index = recentlyClickedAppIndex % recentlyClickedAppWindows.length;
++        let window = recentlyClickedAppWindows[index];
++
++        Main.activateWindow(window);
++    }
++
++    _resetRecentlyClickedApp() {
++        if (recentlyClickedAppLoopId > 0)
++            Mainloop.source_remove(recentlyClickedAppLoopId);
++        recentlyClickedAppLoopId=0;
++        recentlyClickedApp =null;
++        recentlyClickedAppWindows = null;
++        recentlyClickedAppIndex = 0;
++        recentlyClickedAppMonitor = -1;
++
++        return false;
++    }
++
++    // Filter out unnecessary windows, for instance
++    // nautilus desktop window.
++    getInterestingWindows() {
++        return getInterestingWindows(this.app, this._dtdSettings, this.monitorIndex);
++    }
++};
++/**
++ * Extend AppIconMenu
++ *
++ * - Pass settings to the constructor
++ * - set popup arrow side based on dash orientation
++ * - Add close windows option based on quitfromdash extension
++ *   (https://github.com/deuill/shell-extension-quitfromdash)
++ * - Add open windows thumbnails instead of list
++ * - update menu when application windows change
++ */
++const MyAppIconMenu = class DashToDock_MyAppIconMenu extends AppDisplay.AppIconMenu {
++
++    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
++        super(source);
++
++        // Change the initialized side where required.
++        this._arrowSide = side;
++        this._boxPointer._arrowSide = side;
++        this._boxPointer._userArrowSide = side;
++
++        this._dtdSettings = settings;
++    }
++
++    _redisplay() {
++        this.removeAll();
++
++        if (this._dtdSettings.get_boolean('show-windows-preview')) {
++            // Display the app windows menu items and the separator between windows
++            // of the current desktop and other windows.
++
++            this._allWindowsMenuItem = new PopupMenu.PopupSubMenuMenuItem(__('All Windows'), false);
++            this._allWindowsMenuItem.actor.hide();
++            this.addMenuItem(this._allWindowsMenuItem);
++
++            if (!this._source.app.is_window_backed()) {
++                this._appendSeparator();
++
++                let appInfo = this._source.app.get_app_info();
++                let actions = appInfo.list_actions();
++                if (this._source.app.can_open_new_window() &&
++                    actions.indexOf('new-window') == -1) {
++                    this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
++                    this._newWindowMenuItem.connect('activate', () => {
++                        if (this._source.app.state == Shell.AppState.STOPPED)
++                            this._source.animateLaunch();
++
++                        this._source.app.open_new_window(-1);
++                        this.emit('activate-window', null);
++                    });
++                    this._appendSeparator();
++                }
++
++
++                if (AppDisplay.discreteGpuAvailable &&
++                    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', () => {
++                        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', (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');
++
++                if (canFavorite) {
++                    this._appendSeparator();
++
++                    let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
++
++                    if (isFavorite) {
++                        let item = this._appendMenuItem(_("Remove from Favorites"));
++                        item.connect('activate', () => {
++                            let favs = AppFavorites.getAppFavorites();
++                            favs.removeFavorite(this._source.app.get_id());
++                        });
++                    } else {
++                        let item = this._appendMenuItem(_("Add to Favorites"));
++                        item.connect('activate', () => {
++                            let favs = AppFavorites.getAppFavorites();
++                            favs.addFavorite(this._source.app.get_id());
++                        });
++                    }
++                }
++
++                if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) {
++                    this._appendSeparator();
++                    let item = this._appendMenuItem(_("Show Details"));
++                    item.connect('activate', () => {
++                        let id = this._source.app.get_id();
++                        let args = GLib.Variant.new('(ss)', [id, '']);
++                        Gio.DBus.get(Gio.BusType.SESSION, null,
++                            function(o, res) {
++                                let bus = Gio.DBus.get_finish(res);
++                                bus.call('org.gnome.Software',
++                                         '/org/gnome/Software',
++                                         'org.gtk.Actions', 'Activate',
++                                         GLib.Variant.new('(sava{sv})',
++                                                          ['details', [args], null]),
++                                         null, 0, -1, null, null);
++                                Main.overview.hide();
++                            });
++                    });
++                }
++            }
++
++        } else {
++            super._redisplay();
++        }
++
++        // quit menu
++        this._appendSeparator();
++        this._quitfromDashMenuItem = this._appendMenuItem(_("Quit"));
++        this._quitfromDashMenuItem.connect('activate', () => {
++            this._source.closeAllWindows();
++        });
++
++        this.update();
++    }
++
++    // update menu content when application windows change. This is desirable as actions
++    // acting on windows (closing) are performed while the menu is shown.
++    update() {
++
++      if(this._dtdSettings.get_boolean('show-windows-preview')){
++
++          let windows = this._source.getInterestingWindows();
++
++          // update, show or hide the quit menu
++          if ( windows.length > 0) {
++              let quitFromDashMenuText = "";
++              if (windows.length == 1)
++                  this._quitfromDashMenuItem.label.set_text(_("Quit"));
++              else
++                  this._quitfromDashMenuItem.label.set_text(_("Quit %d Windows").format(windows.length));
++
++              this._quitfromDashMenuItem.actor.show();
++
++          } else {
++              this._quitfromDashMenuItem.actor.hide();
++          }
++
++          // update, show, or hide the allWindows menu
++          // Check if there are new windows not already displayed. In such case, repopulate the allWindows
++          // menu. Windows removal is already handled by each preview being connected to the destroy signal
++          let old_windows = this._allWindowsMenuItem.menu._getMenuItems().map(function(item){
++              return item._window;
++          });
++
++          let new_windows = windows.filter(function(w) {return old_windows.indexOf(w) < 0;});
++          if (new_windows.length > 0) {
++              this._populateAllWindowMenu(windows);
++
++              // Try to set the width to that of the submenu.
++              // TODO: can't get the actual size, getting a bit less.
++              // Temporary workaround: add 15px to compensate
++              this._allWindowsMenuItem.actor.width =  this._allWindowsMenuItem.menu.actor.width + 15;
++
++          }
++
++          // The menu is created hidden and never hidded after being shown. Instead, a singlal
++          // connected to its items destroy will set is insensitive if no more windows preview are shown.
++          if (windows.length > 0){
++              this._allWindowsMenuItem.actor.show();
++              this._allWindowsMenuItem.setSensitive(true);
++          }
++
++          // Update separators
++          this._getMenuItems().forEach(this._updateSeparatorVisibility.bind(this));
++      }
++
++
++    }
++
++    _populateAllWindowMenu(windows) {
++
++        this._allWindowsMenuItem.menu.removeAll();
++
++            if (windows.length > 0) {
++
++                let activeWorkspace = global.workspace_manager.get_active_workspace();
++                let separatorShown =  windows[0].get_workspace() != activeWorkspace;
++
++                for (let i = 0; i < windows.length; i++) {
++                    let window = windows[i];
++                    if (!separatorShown && window.get_workspace() != activeWorkspace) {
++                        this._allWindowsMenuItem.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++                        separatorShown = true;
++                    }
++
++                    let item = new WindowPreview.WindowPreviewMenuItem(window);
++                    this._allWindowsMenuItem.menu.addMenuItem(item);
++                    item.connect('activate', () => {
++                        this.emit('activate-window', window);
++                    });
++
++                    // This is to achieve a more gracefull transition when the last windows is closed.
++                    item.connect('destroy', () => {
++                        if(this._allWindowsMenuItem.menu._getMenuItems().length == 1) // It's still counting the item just going to be destroyed
++                            this._allWindowsMenuItem.setSensitive(false);
++                    });
++                }
++            }
++    }
++};
++Signals.addSignalMethods(MyAppIconMenu.prototype);
++
++// Filter out unnecessary windows, for instance
++// nautilus desktop window.
++function getInterestingWindows(app, settings, monitorIndex) {
++    let windows = app.get_windows().filter(function(w) {
++        return !w.skip_taskbar;
++    });
++
++    // When using workspace isolation, we filter out windows
++    // that are not in the current workspace
++    if (settings.get_boolean('isolate-workspaces'))
++        windows = windows.filter(function(w) {
++            return w.get_workspace().index() == global.workspace_manager.get_active_workspace_index();
++        });
++
++    if (settings.get_boolean('isolate-monitors'))
++        windows = windows.filter(function(w) {
++            return w.get_monitor() == monitorIndex;
++        });
++
++    return windows;
++}
++
++/**
++ * A wrapper class around the ShowAppsIcon class.
++ *
++ * - Pass settings to the constructor
++ * - set label position based on dash orientation (Note, I am reusing most machinery of the appIcon class)
++ * - implement a popupMenu based on the AppIcon code (Note, I am reusing most machinery of the appIcon class)
++ *
++ * I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973.
++ * thus use this pattern where the real showAppsIcon object is encaptulated, and a reference to it will be properly wired upon
++ * use of this class in place of the original showAppsButton.
++ *
++ */
++
++var ShowAppsIconWrapper = class DashToDock_ShowAppsIconWrapper {
++    constructor(settings) {
++        this._dtdSettings = settings;
++        this.realShowAppsIcon = new Dash.ShowAppsIcon();
++
++        /* the variable equivalent to toggleButton has a different name in the appIcon class
++        (actor): duplicate reference to easily reuse appIcon methods */
++        this.actor = this.realShowAppsIcon.toggleButton;
++
++        // Re-use appIcon methods
++        this._removeMenuTimeout = AppDisplay.AppIcon.prototype._removeMenuTimeout;
++        this._setPopupTimeout = AppDisplay.AppIcon.prototype._setPopupTimeout;
++        this._onButtonPress = AppDisplay.AppIcon.prototype._onButtonPress;
++        this._onKeyboardPopupMenu = AppDisplay.AppIcon.prototype._onKeyboardPopupMenu;
++        this._onLeaveEvent = AppDisplay.AppIcon.prototype._onLeaveEvent;
++        this._onTouchEvent = AppDisplay.AppIcon.prototype._onTouchEvent;
++        this._onMenuPoppedDown = AppDisplay.AppIcon.prototype._onMenuPoppedDown;
++
++        // No action on clicked (showing of the appsview is controlled elsewhere)
++        this._onClicked = (actor, button) => {
++            this._removeMenuTimeout();
++        };
++
++        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.realShowAppsIcon._dtdSettings = settings;
++        this.realShowAppsIcon.showLabel = itemShowLabel;
++    }
++
++    popupMenu() {
++        this._removeMenuTimeout();
++        this.actor.fake_release();
++
++        if (!this._menu) {
++            this._menu = new MyShowAppsIconMenu(this, this._dtdSettings);
++            this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
++                if (!isPoppedUp)
++                    this._onMenuPoppedDown();
++            });
++            let id = Main.overview.connect('hiding', () => {
++                this._menu.close();
++            });
++            this._menu.actor.connect('destroy', function() {
++                Main.overview.disconnect(id);
++            });
++            this._menuManager.addMenu(this._menu);
++        }
++
++        //this.emit('menu-state-changed', true);
++
++        this.actor.set_hover(true);
++        this._menu.popup();
++        this._menuManager.ignoreRelease();
++        this.emit('sync-tooltip');
++
++        return false;
++    }
++};
++Signals.addSignalMethods(ShowAppsIconWrapper.prototype);
++
++
++/**
++ * A menu for the showAppsIcon
++ */
++var MyShowAppsIconMenu = class DashToDock_MyShowAppsIconMenu extends MyAppIconMenu {
++    _redisplay() {
++        this.removeAll();
++
++        /* Translators: %s is "Settings", which is automatically translated. You
++           can also translate the full message if this fits better your language. */
++        let name = __('Dash to Dock %s').format(_('Settings'))
++        let item = this._appendMenuItem(name);
++
++        item.connect('activate', function () {
++            Util.spawn(["gnome-shell-extension-prefs", Me.metadata.uuid]);
++        });
++    }
++};
++
++/**
++ * This function is used for both extendShowAppsIcon and extendDashItemContainer
++ */
++function itemShowLabel()  {
++    // Check if the label is still present at all. When switching workpaces, the
++    // item might have been destroyed in between.
++    if (!this._labelText || this.label.get_stage() == null)
++      return;
++
++    this.label.set_text(this._labelText);
++    this.label.opacity = 0;
++    this.label.show();
++
++    let [stageX, stageY] = this.get_transformed_position();
++    let node = this.label.get_theme_node();
++
++    let itemWidth  = this.allocation.x2 - this.allocation.x1;
++    let itemHeight = this.allocation.y2 - this.allocation.y1;
++
++    let labelWidth = this.label.get_width();
++    let labelHeight = this.label.get_height();
++
++    let x, y, xOffset, yOffset;
++
++    let position = Utils.getPosition(this._dtdSettings);
++    this._isHorizontal = ((position == St.Side.TOP) || (position == St.Side.BOTTOM));
++    let labelOffset = node.get_length('-x-offset');
++
++    switch (position) {
++    case St.Side.LEFT:
++        yOffset = Math.floor((itemHeight - labelHeight) / 2);
++        y = stageY + yOffset;
++        xOffset = labelOffset;
++        x = stageX + this.get_width() + xOffset;
++        break;
++    case St.Side.RIGHT:
++        yOffset = Math.floor((itemHeight - labelHeight) / 2);
++        y = stageY + yOffset;
++        xOffset = labelOffset;
++        x = Math.round(stageX) - labelWidth - xOffset;
++        break;
++    case St.Side.TOP:
++        y = stageY + labelOffset + itemHeight;
++        xOffset = Math.floor((itemWidth - labelWidth) / 2);
++        x = stageX + xOffset;
++        break;
++    case St.Side.BOTTOM:
++        yOffset = labelOffset;
++        y = stageY - labelHeight - yOffset;
++        xOffset = Math.floor((itemWidth - labelWidth) / 2);
++        x = stageX + xOffset;
++        break;
++    }
++
++    // keep the label inside the screen border
++    // Only needed fot the x coordinate.
++
++    // Leave a few pixel gap
++    let gap = 5;
++    let monitor = Main.layoutManager.findMonitorForActor(this);
++    if (x - monitor.x < gap)
++        x += monitor.x - x + labelOffset;
++    else if (x + labelWidth > monitor.x + monitor.width - gap)
++        x -= x + labelWidth - (monitor.x + monitor.width) + gap;
++
++    this.label.set_position(x, y);
++    Tweener.addTween(this.label, {
++        opacity: 255,
++        time: DASH_ITEM_LABEL_SHOW_TIME,
++        transition: 'easeOutQuad',
++    });
++}
+diff --git a/extensions/dash-to-dock/dash.js b/extensions/dash-to-dock/dash.js
+new file mode 100644
+index 0000000..a646256
+--- /dev/null
++++ b/extensions/dash-to-dock/dash.js
+@@ -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 Meta = imports.gi.Meta;
++const Shell = imports.gi.Shell;
++const St = imports.gi.St;
++const Mainloop = imports.mainloop;
++
++const AppDisplay = imports.ui.appDisplay;
++const AppFavorites = imports.ui.appFavorites;
++const Dash = imports.ui.dash;
++const DND = imports.ui.dnd;
++const IconGrid = imports.ui.iconGrid;
++const Main = imports.ui.main;
++const PopupMenu = imports.ui.popupMenu;
++const Tweener = imports.ui.tweener;
++const Util = imports.misc.util;
++const Workspace = imports.ui.workspace;
++
++const Me = imports.misc.extensionUtils.getCurrentExtension();
++const Utils = Me.imports.utils;
++const AppIcons = Me.imports.appIcons;
++
++let DASH_ANIMATION_TIME = Dash.DASH_ANIMATION_TIME;
++let DASH_ITEM_LABEL_HIDE_TIME = Dash.DASH_ITEM_LABEL_HIDE_TIME;
++let DASH_ITEM_HOVER_TIMEOUT = Dash.DASH_ITEM_HOVER_TIMEOUT;
++
++/**
++ * Extend DashItemContainer
++ *
++ * - Pass settings to the constructor
++ * - set label position based on dash orientation
++ *
++ *  I can't subclass the original object because of this: https://bugzilla.gnome.org/show_bug.cgi?id=688973.
++ *  thus use this ugly pattern.
++ */
++function extendDashItemContainer(dashItemContainer, settings) {
++    dashItemContainer._dtdSettings = settings;
++    dashItemContainer.showLabel = AppIcons.itemShowLabel;
++}
++
++/**
++ * This class is a fork of the upstream DashActor class (ui.dash.js)
++ *
++ * Summary of changes:
++ * - passed settings to class as parameter
++ * - modified chldBox calculations for when 'show-apps-at-top' option is checked
++ * - handle horizontal dash
++ */
++var MyDashActor = GObject.registerClass(
++class DashToDock_MyDashActor extends St.Widget {
++
++    _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);
++
++        this._position = Utils.getPosition(settings);
++        this._isHorizontal = ((this._position == St.Side.TOP) ||
++                               (this._position == St.Side.BOTTOM));
++
++        let layout = new Clutter.BoxLayout({
++            orientation: this._isHorizontal ? Clutter.Orientation.HORIZONTAL : Clutter.Orientation.VERTICAL
++        });
++
++        super._init({
++            name: 'dash',
++            layout_manager: layout,
++            clip_to_allocation: true
++        });
++
++        // 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);
++    }
++
++    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] = this.get_children();
++        let [showAppsMinHeight, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
++        let [showAppsMinWidth, showAppsNatWidth] = showAppsButton.get_preferred_width(availHeight);
++
++        let offset_x = this._isHorizontal?showAppsNatWidth:0;
++        let offset_y = this._isHorizontal?0:showAppsNatHeight;
++
++        let childBox = new Clutter.ActorBox();
++        if ((this._dtdSettings.get_boolean('show-apps-at-top') && !this._isHorizontal)
++            || (this._dtdSettings.get_boolean('show-apps-at-top') && !this._rtl)
++            || (!this._dtdSettings.get_boolean('show-apps-at-top') && this._isHorizontal && this._rtl)) {
++            childBox.x1 = contentBox.x1 + offset_x;
++            childBox.y1 = contentBox.y1 + offset_y;
++            childBox.x2 = contentBox.x2;
++            childBox.y2 = contentBox.y2;
++            appIcons.allocate(childBox, flags);
++
++            childBox.y1 = contentBox.y1;
++            childBox.x1 = contentBox.x1;
++            childBox.x2 = contentBox.x1 + showAppsNatWidth;
++            childBox.y2 = contentBox.y1 + showAppsNatHeight;
++            showAppsButton.allocate(childBox, flags);
++        }
++        else {
++            childBox.x1 = contentBox.x1;
++            childBox.y1 = contentBox.y1;
++            childBox.x2 = contentBox.x2 - offset_x;
++            childBox.y2 = contentBox.y2 - offset_y;
++            appIcons.allocate(childBox, flags);
++
++            childBox.x2 = contentBox.x2;
++            childBox.y2 = contentBox.y2;
++            childBox.x1 = contentBox.x2 - showAppsNatWidth;
++            childBox.y1 = contentBox.y2 - showAppsNatHeight;
++            showAppsButton.allocate(childBox, flags);
++        }
++    }
++
++    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.layout_manager.get_preferred_width(this, forHeight);
++
++        let themeNode = this.get_theme_node();
++        let [, showAppsButton] = this.get_children();
++        let [minWidth, ] = showAppsButton.get_preferred_height(forHeight);
++
++        return [minWidth, natWidth];
++    }
++
++    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.layout_manager.get_preferred_height(this, forWidth);
++
++        let themeNode = this.get_theme_node();
++        let [, showAppsButton] = this.get_children();
++        let [minHeight, ] = showAppsButton.get_preferred_height(forWidth);
++
++        return [minHeight, natHeight];
++    }
++});
++
++const baseIconSizes = [16, 22, 24, 32, 48, 64, 96, 128];
++
++/**
++ * This class is a fork of the upstream dash class (ui.dash.js)
++ *
++ * Summary of changes:
++ * - disconnect global signals adding a destroy method;
++ * - play animations even when not in overview mode
++ * - set a maximum icon size
++ * - show running and/or favorite applications
++ * - emit a custom signal when an app icon is added
++ * - hide showApps label when the custom menu is shown.
++ * - add scrollview
++ *   ensure actor is visible on keyfocus inseid the scrollview
++ * - add 128px icon size, might be usefull for hidpi display
++ * - sync minimization application target position.
++ * - keep running apps ordered.
++ */
++var MyDash = class DashToDock_MyDash {
++
++    constructor(settings, remoteModel, monitorIndex) {
++        this._dtdSettings = settings;
++
++        // Initialize icon variables and size
++        this._maxHeight = -1;
++        this.iconSize = this._dtdSettings.get_int('dash-max-icon-size');
++        this._availableIconSizes = baseIconSizes;
++        this._shownInitially = false;
++        this._initializeIconSize(this.iconSize);
++
++        this._remoteModel = remoteModel;
++        this._monitorIndex = monitorIndex;
++        this._position = Utils.getPosition(settings);
++        this._isHorizontal = ((this._position == St.Side.TOP) ||
++                               (this._position == St.Side.BOTTOM));
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++
++        this._dragPlaceholder = null;
++        this._dragPlaceholderPos = -1;
++        this._animatingPlaceholdersCount = 0;
++        this._showLabelTimeoutId = 0;
++        this._resetHoverTimeoutId = 0;
++        this._ensureAppIconVisibilityTimeoutId = 0;
++        this._labelShowing = false;
++
++        this._container = new MyDashActor(settings);
++        this._scrollView = new St.ScrollView({
++            name: 'dashtodockDashScrollview',
++            hscrollbar_policy: Gtk.PolicyType.NEVER,
++            vscrollbar_policy: Gtk.PolicyType.NEVER,
++            enable_mouse_scrolling: false
++        });
++
++        this._scrollView.connect('scroll-event', this._onScrollEvent.bind(this));
++
++        this._box = new St.BoxLayout({
++            vertical: !this._isHorizontal,
++            clip_to_allocation: false,
++            x_align: Clutter.ActorAlign.START,
++            y_align: Clutter.ActorAlign.START
++        });
++        this._box._delegate = this;
++        this._container.add_actor(this._scrollView);
++        this._scrollView.add_actor(this._box);
++
++        // 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', (showAppsIconWrapper, opened) => {
++            this._itemMenuStateChanged(showAppsIconWrapper, opened);
++        });
++        // an instance of the showAppsIcon class is encapsulated in the wrapper
++        this._showAppsIcon = showAppsIconWrapper.realShowAppsIcon;
++
++        this._showAppsIcon.childScale = 1;
++        this._showAppsIcon.childOpacity = 255;
++        this._showAppsIcon.icon.setIconSize(this.iconSize);
++        this._hookUpLabel(this._showAppsIcon);
++
++        this.showAppsButton = this._showAppsIcon.toggleButton;
++
++        this._container.add_actor(this._showAppsIcon);
++
++        let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
++        this.actor = new St.Bin({
++            child: this._container,
++            y_align: St.Align.START,
++            x_align: rtl ? St.Align.END : St.Align.START
++        });
++
++        if (this._isHorizontal) {
++            this.actor.connect('notify::width', () => {
++                if (this._maxHeight != this.actor.width)
++                    this._queueRedisplay();
++                this._maxHeight = this.actor.width;
++            });
++        }
++        else {
++            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', this._updateAppsIconGeometry.bind(this));
++        let scrollViewAdjustment = this._isHorizontal ? this._scrollView.hscroll.adjustment : this._scrollView.vscroll.adjustment;
++        scrollViewAdjustment.connect('notify::value', this._updateAppsIconGeometry.bind(this));
++
++        this._workId = Main.initializeDeferredWork(this._box, this._redisplay.bind(this));
++
++        this._settings = new Gio.Settings({
++            schema_id: 'org.gnome.shell'
++        });
++
++        this._appSystem = Shell.AppSystem.get_default();
++
++        this._signalsHandler.add([
++            this._appSystem,
++            'installed-changed',
++            () => {
++                AppFavorites.getAppFavorites().reload();
++                this._queueRedisplay();
++            }
++        ], [
++            AppFavorites.getAppFavorites(),
++            'changed',
++            this._queueRedisplay.bind(this)
++        ], [
++            this._appSystem,
++            'app-state-changed',
++            this._queueRedisplay.bind(this)
++        ], [
++            Main.overview,
++            'item-drag-begin',
++            this._onDragBegin.bind(this)
++        ], [
++            Main.overview,
++            'item-drag-end',
++            this._onDragEnd.bind(this)
++        ], [
++            Main.overview,
++            'item-drag-cancelled',
++            this._onDragCancelled.bind(this)
++        ]);
++    }
++
++    destroy() {
++        this._signalsHandler.destroy();
++    }
++
++    _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;
++
++        // reset timeout to avid conflicts with the mousehover event
++        if (this._ensureAppIconVisibilityTimeoutId > 0) {
++            Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId);
++            this._ensureAppIconVisibilityTimeoutId = 0;
++        }
++
++        // Skip to avoid double events mouse
++        if (event.is_pointer_emulated())
++            return Clutter.EVENT_STOP;
++
++        let adjustment, delta;
++
++        if (this._isHorizontal)
++            adjustment = this._scrollView.get_hscroll_bar().get_adjustment();
++        else
++            adjustment = this._scrollView.get_vscroll_bar().get_adjustment();
++
++        let increment = adjustment.step_increment;
++
++        switch (event.get_scroll_direction()) {
++        case Clutter.ScrollDirection.UP:
++            delta = -increment;
++            break;
++        case Clutter.ScrollDirection.DOWN:
++            delta = +increment;
++            break;
++        case Clutter.ScrollDirection.SMOOTH:
++            let [dx, dy] = event.get_scroll_delta();
++            delta = dy * increment;
++            // Also consider horizontal component, for instance touchpad
++            if (this._isHorizontal)
++                delta += dx * increment;
++            break;
++        }
++
++        adjustment.set_value(adjustment.get_value() + delta);
++
++        return Clutter.EVENT_STOP;
++    }
++
++    _onDragBegin() {
++        this._dragCancelled = false;
++        this._dragMonitor = {
++            dragMotion: this._onDragMotion.bind(this)
++        };
++        DND.addDragMonitor(this._dragMonitor);
++
++        if (this._box.get_n_children() == 0) {
++            this._emptyDropTarget = new Dash.EmptyDropTargetItem();
++            this._box.insert_child_at_index(this._emptyDropTarget, 0);
++            this._emptyDropTarget.show(true);
++        }
++    }
++
++    _onDragCancelled() {
++        this._dragCancelled = true;
++        this._endDrag();
++    }
++
++    _onDragEnd() {
++        if (this._dragCancelled)
++            return;
++
++        this._endDrag();
++    }
++
++    _endDrag() {
++        this._clearDragPlaceholder();
++        this._clearEmptyDropTarget();
++        this._showAppsIcon.setDragApp(null);
++        DND.removeDragMonitor(this._dragMonitor);
++    }
++
++    _onDragMotion(dragEvent) {
++        let app = Dash.getAppFromSource(dragEvent.source);
++        if (app == null)
++            return DND.DragMotionResult.CONTINUE;
++
++        let showAppsHovered = this._showAppsIcon.contains(dragEvent.targetActor);
++
++        if (!this._box.contains(dragEvent.targetActor) || showAppsHovered)
++            this._clearDragPlaceholder();
++
++        if (showAppsHovered)
++            this._showAppsIcon.setDragApp(app);
++        else
++            this._showAppsIcon.setDragApp(null);
++
++        return DND.DragMotionResult.CONTINUE;
++    }
++
++    _appIdListToHash(apps) {
++        let ids = {};
++        for (let i = 0; i < apps.length; i++)
++            ids[apps[i].get_id()] = apps[i];
++        return ids;
++    }
++
++    _queueRedisplay() {
++        Main.queueDeferredWork(this._workId);
++    }
++
++    _hookUpLabel(item, appIcon) {
++        item.child.connect('notify::hover', () => {
++            this._syncLabel(item, appIcon);
++        });
++
++        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', () => {
++                this._syncLabel(item, appIcon);
++            });
++        }
++    }
++
++    _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', () => {
++                appIcon.actor.opacity = 50;
++            });
++            appIcon._draggable.connect('drag-end', () => {
++                appIcon.actor.opacity = 255;
++            });
++        }
++
++        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', () => {
++            if (appIcon.actor.hover) {
++                this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, () => {
++                    ensureActorVisibleInScrollView(this._scrollView, appIcon.actor);
++                    this._ensureAppIconVisibilityTimeoutId = 0;
++                    return GLib.SOURCE_REMOVE;
++                });
++            }
++            else {
++                if (this._ensureAppIconVisibilityTimeoutId > 0) {
++                    Mainloop.source_remove(this._ensureAppIconVisibilityTimeoutId);
++                    this._ensureAppIconVisibilityTimeoutId = 0;
++                }
++            }
++        });
++
++        appIcon.actor.connect('clicked', (actor) => {
++            ensureActorVisibleInScrollView(this._scrollView, 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
++            // coordinates. Thus correct for the shift which is going to be applied to the scrollview.
++            if (appIcon._menu) {
++                appIcon._menu._boxPointer.xOffset = -x_shift;
++                appIcon._menu._boxPointer.yOffset = -y_shift;
++            }
++        });
++
++        // Override default AppIcon label_actor, now the
++        // accessible_name is set at DashItemContainer.setLabelText
++        appIcon.actor.label_actor = null;
++        item.setLabelText(app.get_name());
++
++        appIcon.icon.setIconSize(this.iconSize);
++        this._hookUpLabel(item, appIcon);
++
++        return item;
++    }
++
++    /**
++     * Return an array with the "proper" appIcons currently in the dash
++     */
++    getAppIcons() {
++        // Only consider children which are "proper"
++        // icons (i.e. ignoring drag placeholders) and which are not
++        // animating out (which means they will be destroyed at the end of
++        // the animation)
++        let iconChildren = this._box.get_children().filter(function(actor) {
++            return actor.child &&
++                   actor.child._delegate &&
++                   actor.child._delegate.icon &&
++                   !actor.animatingOut;
++        });
++
++        let appIcons = iconChildren.map(function(actor) {
++            return actor.child._delegate;
++        });
++
++      return appIcons;
++    }
++
++    _updateAppsIconGeometry() {
++        let appIcons = this.getAppIcons();
++        appIcons.forEach(function(icon) {
++            icon.updateIconGeometry();
++        });
++    }
++
++    _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) {
++            if (this._showLabelTimeoutId > 0) {
++                Mainloop.source_remove(this._showLabelTimeoutId);
++                this._showLabelTimeoutId = 0;
++            }
++
++            item.hideLabel();
++        }
++        else {
++            // I want to listen from outside when a menu is closed. I used to
++            // add a custom signal to the appIcon, since gnome 3.8 the signal
++            // calling this callback was added upstream.
++            this.emit('menu-closed');
++        }
++    }
++
++    _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, () => {
++                    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);
++                    this._resetHoverTimeoutId = 0;
++                }
++            }
++        }
++        else {
++            if (this._showLabelTimeoutId > 0)
++                Mainloop.source_remove(this._showLabelTimeoutId);
++            this._showLabelTimeoutId = 0;
++            item.hideLabel();
++            if (this._labelShowing) {
++                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() {
++        // For the icon size, we only consider children which are "proper"
++        // icons (i.e. ignoring drag placeholders) and which are not
++        // animating out (which means they will be destroyed at the end of
++        // the animation)
++        let iconChildren = this._box.get_children().filter(function(actor) {
++            return actor.child &&
++                   actor.child._delegate &&
++                   actor.child._delegate.icon &&
++                   !actor.animatingOut;
++        });
++
++        iconChildren.push(this._showAppsIcon);
++
++        if (this._maxHeight == -1)
++            return;
++
++        // Check if the container is present in the stage. This avoids critical
++        // errors when unlocking the screen
++        if (!this._container.get_stage())
++            return;
++
++        let themeNode = this._container.get_theme_node();
++        let maxAllocation = new Clutter.ActorBox({
++            x1: 0,
++            y1: 0,
++            x2: this._isHorizontal ? this._maxHeight : 42 /* whatever */,
++            y2: this._isHorizontal ? 42 : this._maxHeight
++        });
++        let maxContent = themeNode.get_content_box(maxAllocation);
++        let availHeight;
++        if (this._isHorizontal)
++            availHeight = maxContent.x2 - maxContent.x1;
++        else
++            availHeight = maxContent.y2 - maxContent.y1;
++        let spacing = themeNode.get_length('spacing');
++
++        let firstButton = iconChildren[0].child;
++        let firstIcon = firstButton._delegate.icon;
++
++        let minHeight, natHeight, minWidth, natWidth;
++
++        // Enforce the current icon size during the size request
++        firstIcon.setIconSize(this.iconSize);
++        [minHeight, natHeight] = firstButton.get_preferred_height(-1);
++        [minWidth, natWidth] = firstButton.get_preferred_width(-1);
++
++        let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
++        let iconSizes = this._availableIconSizes.map(function(s) {
++            return s * scaleFactor;
++        });
++
++        // Subtract icon padding and box spacing from the available height
++        if (this._isHorizontal)
++            availHeight -= iconChildren.length * (natWidth - this.iconSize * scaleFactor) +
++                           (iconChildren.length - 1) * spacing;
++        else
++            availHeight -= iconChildren.length * (natHeight - this.iconSize * scaleFactor) +
++                           (iconChildren.length - 1) * spacing;
++
++        let availSize = availHeight / iconChildren.length;
++
++
++        let newIconSize = this._availableIconSizes[0];
++        for (let i = 0; i < iconSizes.length; i++) {
++            if (iconSizes[i] < availSize)
++                newIconSize = this._availableIconSizes[i];
++        }
++
++        if (newIconSize == this.iconSize)
++            return;
++
++        let oldIconSize = this.iconSize;
++        this.iconSize = newIconSize;
++        this.emit('icon-size-changed');
++
++        let scale = oldIconSize / newIconSize;
++        for (let i = 0; i < iconChildren.length; i++) {
++            let icon = iconChildren[i].child._delegate.icon;
++
++            // Set the new size immediately, to keep the icons' sizes
++            // in sync with this.iconSize
++            icon.setIconSize(this.iconSize);
++
++            // Don't animate the icon size change when the overview
++            // is transitioning, or when initially filling
++            // the dash
++            if (Main.overview.animationInProgress ||
++                !this._shownInitially)
++                continue;
++
++            let [targetWidth, targetHeight] = icon.icon.get_size();
++
++            // Scale the icon's texture to the previous size and
++            // tween to the new size
++            icon.icon.set_size(icon.icon.width * scale,
++                               icon.icon.height * scale);
++
++            Tweener.addTween(icon.icon,
++                             { width: targetWidth,
++                               height: targetHeight,
++                               time: DASH_ANIMATION_TIME,
++                               transition: 'easeOutQuad',
++                             });
++        }
++    }
++
++    _redisplay() {
++        let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
++
++        let running = this._appSystem.get_running();
++        if (this._dtdSettings.get_boolean('isolate-workspaces') ||
++            this._dtdSettings.get_boolean('isolate-monitors')) {
++            // When using isolation, we filter out apps that have no windows in
++            // the current workspace
++            let settings = this._dtdSettings;
++            let monitorIndex = this._monitorIndex;
++            running = running.filter(function(_app) {
++                return AppIcons.getInterestingWindows(_app, settings, monitorIndex).length != 0;
++            });
++        }
++
++        let children = this._box.get_children().filter(function(actor) {
++            return actor.child &&
++                   actor.child._delegate &&
++                   actor.child._delegate.app;
++        });
++        // Apps currently in the dash
++        let oldApps = children.map(function(actor) {
++            return actor.child._delegate.app;
++        });
++        // Apps supposed to be in the dash
++        let newApps = [];
++
++        if (this._dtdSettings.get_boolean('show-favorites')) {
++            for (let id in favorites)
++                newApps.push(favorites[id]);
++        }
++
++        // We reorder the running apps so that they don't change position on the
++        // dash with every redisplay() call
++        if (this._dtdSettings.get_boolean('show-running')) {
++            // First: add the apps from the oldApps list that are still running
++            for (let i = 0; i < oldApps.length; i++) {
++                let index = running.indexOf(oldApps[i]);
++                if (index > -1) {
++                    let app = running.splice(index, 1)[0];
++                    if (this._dtdSettings.get_boolean('show-favorites') && (app.get_id() in favorites))
++                        continue;
++                    newApps.push(app);
++                }
++            }
++            // Second: add the new apps
++            for (let i = 0; i < running.length; i++) {
++                let app = running[i];
++                if (this._dtdSettings.get_boolean('show-favorites') && (app.get_id() in favorites))
++                    continue;
++                newApps.push(app);
++            }
++        }
++
++        // Figure out the actual changes to the list of items; we iterate
++        // over both the list of items currently in the dash and the list
++        // of items expected there, and collect additions and removals.
++        // Moves are both an addition and a removal, where the order of
++        // the operations depends on whether we encounter the position
++        // where the item has been added first or the one from where it
++        // was removed.
++        // There is an assumption that only one item is moved at a given
++        // time; when moving several items at once, everything will still
++        // end up at the right position, but there might be additional
++        // additions/removals (e.g. it might remove all the launchers
++        // and add them back in the new order even if a smaller set of
++        // additions and removals is possible).
++        // If above assumptions turns out to be a problem, we might need
++        // to use a more sophisticated algorithm, e.g. Longest Common
++        // Subsequence as used by diff.
++
++        let addedItems = [];
++        let removedActors = [];
++
++        let newIndex = 0;
++        let oldIndex = 0;
++        while ((newIndex < newApps.length) || (oldIndex < oldApps.length)) {
++            // No change at oldIndex/newIndex
++            if (oldApps[oldIndex] && oldApps[oldIndex] == newApps[newIndex]) {
++                oldIndex++;
++                newIndex++;
++                continue;
++            }
++
++            // App removed at oldIndex
++            if (oldApps[oldIndex] && (newApps.indexOf(oldApps[oldIndex]) == -1)) {
++                removedActors.push(children[oldIndex]);
++                oldIndex++;
++                continue;
++            }
++
++            // App added at newIndex
++            if (newApps[newIndex] && (oldApps.indexOf(newApps[newIndex]) == -1)) {
++                let newItem = this._createAppItem(newApps[newIndex]);
++                addedItems.push({ app: newApps[newIndex],
++                                  item: newItem,
++                                  pos: newIndex });
++                newIndex++;
++                continue;
++            }
++
++            // App moved
++            let insertHere = newApps[newIndex + 1] && (newApps[newIndex + 1] == oldApps[oldIndex]);
++            let alreadyRemoved = removedActors.reduce(function(result, actor) {
++                let removedApp = actor.child._delegate.app;
++                return result || removedApp == newApps[newIndex];
++            }, false);
++
++            if (insertHere || alreadyRemoved) {
++                let newItem = this._createAppItem(newApps[newIndex]);
++                addedItems.push({
++                    app: newApps[newIndex],
++                    item: newItem,
++                    pos: newIndex + removedActors.length
++                });
++                newIndex++;
++            }
++            else {
++                removedActors.push(children[oldIndex]);
++                oldIndex++;
++            }
++        }
++
++        for (let i = 0; i < addedItems.length; i++)
++            this._box.insert_child_at_index(addedItems[i].item,
++                                            addedItems[i].pos);
++
++        for (let i = 0; i < removedActors.length; i++) {
++            let item = removedActors[i];
++
++            // Don't animate item removal when the overview is transitioning
++            if (!Main.overview.animationInProgress)
++                item.animateOutAndDestroy();
++            else
++                item.destroy();
++        }
++
++        this._adjustIconSize();
++
++        for (let i = 0; i < addedItems.length; i++)
++            // Emit a custom signal notifying that a new item has been added
++            this.emit('item-added', addedItems[i]);
++
++        // Skip animations on first run when adding the initial set
++        // of items, to avoid all items zooming in at once
++
++        let animate = this._shownInitially &&
++            !Main.overview.animationInProgress;
++
++        if (!this._shownInitially)
++            this._shownInitially = true;
++
++        for (let i = 0; i < addedItems.length; i++)
++            addedItems[i].item.show(animate);
++
++        // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744
++        // Without it, StBoxLayout may use a stale size cache
++        this._box.queue_relayout();
++
++        // This is required for icon reordering when the scrollview is used.
++        this._updateAppsIconGeometry();
++
++        // This will update the size, and the corresponding number for each icon
++        this._updateNumberOverlay();
++    }
++
++    _updateNumberOverlay() {
++        let appIcons = this.getAppIcons();
++        let counter = 1;
++        appIcons.forEach(function(icon) {
++            if (counter < 10){
++                icon.setNumberOverlay(counter);
++                counter++;
++            }
++            else if (counter == 10) {
++                icon.setNumberOverlay(0);
++                counter++;
++            }
++            else {
++                // No overlay after 10
++                icon.setNumberOverlay(-1);
++            }
++            icon.updateNumberOverlay();
++        });
++
++    }
++
++    toggleNumberOverlay(activate) {
++        let appIcons = this.getAppIcons();
++        appIcons.forEach(function(icon) {
++            icon.toggleNumberOverlay(activate);
++        });
++    }
++
++    _initializeIconSize(max_size) {
++        let max_allowed = baseIconSizes[baseIconSizes.length-1];
++        max_size = Math.min(max_size, max_allowed);
++
++        if (this._dtdSettings.get_boolean('icon-size-fixed'))
++            this._availableIconSizes = [max_size];
++        else {
++            this._availableIconSizes = baseIconSizes.filter(function(val) {
++                return (val<max_size);
++            });
++            this._availableIconSizes.push(max_size);
++        }
++    }
++
++    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() {
++        let children = this._box.get_children().filter(function(actor) {
++            return actor.child &&
++                actor.child._delegate &&
++                actor.child._delegate.icon;
++        });
++        for (let i = 0; i < children.length; i++) {
++            let item = children[i];
++            item.destroy();
++        }
++
++        // to avoid ugly animations, just suppress them like when dash is first loaded.
++        this._shownInitially = false;
++        this._redisplay();
++
++    }
++
++    _clearDragPlaceholder() {
++        if (this._dragPlaceholder) {
++            this._animatingPlaceholdersCount++;
++            this._dragPlaceholder.animateOutAndDestroy();
++            this._dragPlaceholder.connect('destroy', () => {
++                this._animatingPlaceholdersCount--;
++            });
++            this._dragPlaceholder = null;
++        }
++        this._dragPlaceholderPos = -1;
++    }
++
++    _clearEmptyDropTarget() {
++        if (this._emptyDropTarget) {
++            this._emptyDropTarget.animateOutAndDestroy();
++            this._emptyDropTarget = null;
++        }
++    }
++
++    handleDragOver(source, actor, x, y, time) {
++        let app = Dash.getAppFromSource(source);
++
++        // Don't allow favoriting of transient apps
++        if (app == null || app.is_window_backed())
++            return DND.DragMotionResult.NO_DROP;
++
++        if (!this._settings.is_writable('favorite-apps') || !this._dtdSettings.get_boolean('show-favorites'))
++            return DND.DragMotionResult.NO_DROP;
++
++        let favorites = AppFavorites.getAppFavorites().getFavorites();
++        let numFavorites = favorites.length;
++
++        let favPos = favorites.indexOf(app);
++
++        let children = this._box.get_children();
++        let numChildren = children.length;
++        let boxHeight = 0;
++        for (let i = 0; i < numChildren; i++)
++            boxHeight += this._isHorizontal?children[i].width:children[i].height;
++
++        // Keep the placeholder out of the index calculation; assuming that
++        // the remove target has the same size as "normal" items, we don't
++        // need to do the same adjustment there.
++        if (this._dragPlaceholder) {
++            boxHeight -= this._isHorizontal?this._dragPlaceholder.width:this._dragPlaceholder.height;
++            numChildren--;
++        }
++
++        let pos;
++        if (!this._emptyDropTarget) {
++            pos = Math.floor((this._isHorizontal?x:y) * numChildren / boxHeight);
++            if (pos >  numChildren)
++                pos = numChildren;
++        }
++        else
++            pos = 0; // always insert at the top when dash is empty
++
++        // Take into account childredn position in rtl
++        if (this._isHorizontal && (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL))
++            pos = numChildren - pos;
++
++        if ((pos != this._dragPlaceholderPos) && (pos <= numFavorites) && (this._animatingPlaceholdersCount == 0)) {
++            this._dragPlaceholderPos = pos;
++
++            // Don't allow positioning before or after self
++            if ((favPos != -1) && (pos == favPos || pos == favPos + 1)) {
++                this._clearDragPlaceholder();
++                return DND.DragMotionResult.CONTINUE;
++            }
++
++            // If the placeholder already exists, we just move
++            // it, but if we are adding it, expand its size in
++            // an animation
++            let fadeIn;
++            if (this._dragPlaceholder) {
++                this._dragPlaceholder.destroy();
++                fadeIn = false;
++            }
++            else
++                fadeIn = true;
++
++            this._dragPlaceholder = new Dash.DragPlaceholderItem();
++            this._dragPlaceholder.child.set_width (this.iconSize);
++            this._dragPlaceholder.child.set_height (this.iconSize / 2);
++            this._box.insert_child_at_index(this._dragPlaceholder,
++                                            this._dragPlaceholderPos);
++            this._dragPlaceholder.show(fadeIn);
++            // Ensure the next and previous icon are visible when moving the placeholder
++            // (I assume there's room for both of them)
++            if (this._dragPlaceholderPos > 1)
++                ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[this._dragPlaceholderPos-1]);
++            if (this._dragPlaceholderPos < this._box.get_children().length-1)
++                ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[this._dragPlaceholderPos+1]);
++        }
++
++        // Remove the drag placeholder if we are not in the
++        // "favorites zone"
++        if (pos > numFavorites)
++            this._clearDragPlaceholder();
++
++        if (!this._dragPlaceholder)
++            return DND.DragMotionResult.NO_DROP;
++
++        let srcIsFavorite = (favPos != -1);
++
++        if (srcIsFavorite)
++            return DND.DragMotionResult.MOVE_DROP;
++
++        return DND.DragMotionResult.COPY_DROP;
++    }
++
++    /**
++     * Draggable target interface
++     */
++    acceptDrop(source, actor, x, y, time) {
++        let app = Dash.getAppFromSource(source);
++
++        // Don't allow favoriting of transient apps
++        if (app == null || app.is_window_backed())
++            return false;
++
++        if (!this._settings.is_writable('favorite-apps') || !this._dtdSettings.get_boolean('show-favorites'))
++            return false;
++
++        let id = app.get_id();
++
++        let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
++
++        let srcIsFavorite = (id in favorites);
++
++        let favPos = 0;
++        let children = this._box.get_children();
++        for (let i = 0; i < this._dragPlaceholderPos; i++) {
++            if (this._dragPlaceholder && (children[i] == this._dragPlaceholder))
++                continue;
++
++            let childId = children[i].child._delegate.app.get_id();
++            if (childId == id)
++                continue;
++            if (childId in favorites)
++                favPos++;
++        }
++
++        // No drag placeholder means we don't wan't to favorite the app
++        // and we are dragging it to its original position
++        if (!this._dragPlaceholder)
++            return true;
++
++        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() {
++        this.showAppsButton.visible = true
++        this.showAppsButton.set_width(-1)
++        this.showAppsButton.set_height(-1)
++    }
++
++    hideShowAppsButton() {
++        this.showAppsButton.hide()
++        this.showAppsButton.set_width(0)
++        this.showAppsButton.set_height(0)
++    }
++};
++
++Signals.addSignalMethods(MyDash.prototype);
++
++/**
++ * This is a copy of the same function in utils.js, but also adjust horizontal scrolling
++ * and perform few further cheks on the current value to avoid changing the values when
++ * it would be clamp to the current one in any case.
++ * Return the amount of shift applied
++ */
++function ensureActorVisibleInScrollView(scrollView, actor) {
++    let adjust_v = true;
++    let adjust_h = true;
++
++    let vadjustment = scrollView.vscroll.adjustment;
++    let hadjustment = scrollView.hscroll.adjustment;
++    let [vvalue, vlower, vupper, vstepIncrement, vpageIncrement, vpageSize] = vadjustment.get_values();
++    let [hvalue, hlower, hupper, hstepIncrement, hpageIncrement, hpageSize] = hadjustment.get_values();
++
++    let [hvalue0, vvalue0] = [hvalue, vvalue];
++
++    let voffset = 0;
++    let hoffset = 0;
++    let fade = scrollView.get_effect('fade');
++    if (fade) {
++        voffset = fade.vfade_offset;
++        hoffset = fade.hfade_offset;
++    }
++
++    let box = actor.get_allocation_box();
++    let y1 = box.y1, y2 = box.y2, x1 = box.x1, x2 = box.x2;
++
++    let parent = actor.get_parent();
++    while (parent != scrollView) {
++        if (!parent)
++            throw new Error('Actor not in scroll view');
++
++        let box = parent.get_allocation_box();
++        y1 += box.y1;
++        y2 += box.y1;
++        x1 += box.x1;
++        x2 += box.x1;
++        parent = parent.get_parent();
++    }
++
++    if (y1 < vvalue + voffset)
++        vvalue = Math.max(0, y1 - voffset);
++    else if (vvalue < vupper - vpageSize && y2 > vvalue + vpageSize - voffset)
++        vvalue = Math.min(vupper -vpageSize, y2 + voffset - vpageSize);
++
++    if (x1 < hvalue + hoffset)
++        hvalue = Math.max(0, x1 - hoffset);
++    else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset)
++        hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize);
++
++    if (vvalue !== vvalue0) {
++        Tweener.addTween(vadjustment, { value: vvalue,
++            time: Util.SCROLL_TIME,
++            transition: 'easeOutQuad'
++        });
++    }
++
++    if (hvalue !== hvalue0) {
++        Tweener.addTween(hadjustment,
++                         { value: hvalue,
++                           time: Util.SCROLL_TIME,
++                           transition: 'easeOutQuad' });
++    }
++
++    return [hvalue- hvalue0, vvalue - vvalue0];
++}
+diff --git a/extensions/dash-to-dock/docking.js b/extensions/dash-to-dock/docking.js
+new file mode 100644
+index 0000000..d35094b
+--- /dev/null
++++ b/extensions/dash-to-dock/docking.js
+@@ -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 Meta = imports.gi.Meta;
++const Shell = imports.gi.Shell;
++const St = imports.gi.St;
++const Mainloop = imports.mainloop;
++const Params = imports.misc.params;
++
++const Main = imports.ui.main;
++const Dash = imports.ui.dash;
++const IconGrid = imports.ui.iconGrid;
++const Overview = imports.ui.overview;
++const OverviewControls = imports.ui.overviewControls;
++const PointerWatcher = imports.ui.pointerWatcher;
++const Tweener = imports.ui.tweener;
++const Signals = imports.signals;
++const ViewSelector = imports.ui.viewSelector;
++const WorkspaceSwitcherPopup= imports.ui.workspaceSwitcherPopup;
++const Layout = imports.ui.layout;
++const LayoutManager = imports.ui.main.layoutManager;
++
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++const Utils = Me.imports.utils;
++const Intellihide = Me.imports.intellihide;
++const Theming = Me.imports.theming;
++const MyDash = Me.imports.dash;
++const LauncherAPI = Me.imports.launcherAPI;
++
++const DOCK_DWELL_CHECK_INTERVAL = 100;
++
++var State = {
++    HIDDEN:  0,
++    SHOWING: 1,
++    SHOWN:   2,
++    HIDING:  3
++};
++
++const scrollAction = {
++    DO_NOTHING: 0,
++    CYCLE_WINDOWS: 1,
++    SWITCH_WORKSPACE: 2
++};
++
++/**
++ * A simple St.Widget with one child whose allocation takes into account the
++ * slide out of its child via the _slidex parameter ([0:1]).
++ *
++ * Required since I want to track the input region of this container which is
++ * based on its allocation even if the child overlows the parent actor. By doing
++ * this the region of the dash that is slideout is not steling anymore the input
++ * regions making the extesion usable when the primary monitor is the right one.
++ *
++ * The 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.
++*/
++var DashSlideContainer = GObject.registerClass(
++class DashToDock_DashSlideContainer extends St.Widget {
++
++    _init(params) {
++        // Default local params
++        let localDefaults = {
++            side: St.Side.LEFT,
++            initialSlideValue: 1
++        }
++
++        let localParams = Params.parse(params, localDefaults, true);
++
++        if (params) {
++            // Remove local params before passing the params to the parent
++            // constructor to avoid errors.
++            let prop;
++            for (prop in localDefaults) {
++                if ((prop in params))
++                    delete params[prop];
++            }
++        }
++
++        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);
++
++        if (this._child == null)
++            return;
++
++        let availWidth = box.x2 - box.x1;
++        let availHeight = box.y2 - box.y1;
++        let [, , natChildWidth, natChildHeight] =
++            this._child.get_preferred_size();
++
++        let childWidth = natChildWidth;
++        let childHeight = natChildHeight;
++
++        let childBox = new Clutter.ActorBox();
++
++        let slideoutSize = this._slideoutSize;
++
++        if (this._side == St.Side.LEFT) {
++            childBox.x1 = (this._slidex -1) * (childWidth - slideoutSize);
++            childBox.x2 = slideoutSize + this._slidex*(childWidth - slideoutSize);
++            childBox.y1 = 0;
++            childBox.y2 = childBox.y1 + childHeight;
++        }
++        else if ((this._side == St.Side.RIGHT) || (this._side == St.Side.BOTTOM)) {
++            childBox.x1 = 0;
++            childBox.x2 = childWidth;
++            childBox.y1 = 0;
++            childBox.y2 = childBox.y1 + childHeight;
++        }
++        else if (this._side == St.Side.TOP) {
++            childBox.x1 = 0;
++            childBox.x2 = childWidth;
++            childBox.y1 = (this._slidex -1) * (childHeight - slideoutSize);
++            childBox.y2 = slideoutSize + this._slidex * (childHeight - slideoutSize);
++        }
++
++        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
++     */
++    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;
++        }
++        return [minWidth, natWidth];
++    }
++
++    /**
++     * Just the child height but taking into account the slided out part
++     */
++    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;
++        }
++        return [minHeight, natHeight];
++    }
++
++    /**
++     * I was expecting it to be a virtual function... stil I don't understand
++     * how things work.
++     */
++    add_child(actor) {
++        // I'm supposed to have only on child
++        if (this._child !== null)
++            this.remove_child(actor);
++
++        this._child = actor;
++        super.add_child(actor);
++    }
++
++    set slidex(value) {
++        this._slidex = value;
++        this._child.queue_relayout();
++    }
++
++    get slidex() {
++        return this._slidex;
++    }
++});
++
++var DockedDash = class DashToDock {
++
++    constructor(settings, remoteModel, monitorIndex) {
++        this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
++
++        // Load settings
++        this._settings = settings;
++        this._remoteModel = remoteModel;
++        this._monitorIndex = monitorIndex;
++        // Connect global signals
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++
++        this._bindSettingsChanges();
++
++        this._position = Utils.getPosition(settings);
++        this._isHorizontal = ((this._position == St.Side.TOP) || (this._position == St.Side.BOTTOM));
++
++        // Temporary ignore hover events linked to autohide for whatever reason
++        this._ignoreHover = false;
++        this._oldignoreHover = null;
++        // This variables are linked to the settings regardles of autohide or intellihide
++        // being temporary disable. Get set by _updateVisibilityMode;
++        this._autohideIsEnabled = null;
++        this._intellihideIsEnabled = null;
++        this._fixedIsEnabled = null;
++
++        // Create intellihide object to monitor windows overlapping
++        this._intellihide = new Intellihide.Intellihide(this._settings, this._monitorIndex);
++
++        // initialize dock state
++        this._dockState = State.HIDDEN;
++
++        // Put dock on the required monitor
++        this._monitor = Main.layoutManager.monitors[this._monitorIndex];
++
++        // this store size and the position where the dash is shown;
++        // used by intellihide module to check window overlap.
++        this.staticBox = new Clutter.ActorBox();
++
++        // Initialize pressure barrier variables
++        this._canUsePressure = false;
++        this._pressureBarrier = null;
++        this._barrier = null;
++        this._removeBarrierTimeoutId = 0;
++
++        // Initialize dwelling system variables
++        this._dockDwelling = false;
++        this._dockWatch = null;
++        this._dockDwellUserTime = 0;
++        this._dockDwellTimeoutId = 0
++
++        // Create a new dash object
++        this.dash = new MyDash.MyDash(this._settings, this._remoteModel, this._monitorIndex);
++
++        if (!this._settings.get_boolean('show-show-apps-button'))
++            this.dash.hideShowAppsButton();
++
++        // Create the main actor and the containers for sliding in and out and
++        // centering, turn on track hover
++
++        let positionStyleClass = ['top', 'right', 'bottom', 'left'];
++        // This is the centering actor
++        this.actor = new St.Bin({
++            name: 'dashtodockContainer',
++            reactive: false,
++            style_class: positionStyleClass[this._position],
++            x_align: this._isHorizontal?St.Align.MIDDLE:St.Align.START,
++            y_align: this._isHorizontal?St.Align.START:St.Align.MIDDLE
++        });
++        this.actor._delegate = this;
++
++        // This is the sliding actor whose allocation is to be tracked for input regions
++        this._slider = new DashSlideContainer({
++            side: this._position,
++            initialSlideValue: 0
++        });
++
++        // This is the actor whose hover status us tracked for autohide
++        this._box = new St.BoxLayout({
++            name: 'dashtodockBox',
++            reactive: true,
++            track_hover: true
++        });
++        this._box.connect('notify::hover', this._hoverChanged.bind(this));
++
++        // Create and apply height constraint to the dash. It's controlled by this.actor height
++        this.constrainSize = new Clutter.BindConstraint({
++            source: this.actor,
++            coordinate: this._isHorizontal?Clutter.BindCoordinate.WIDTH:Clutter.BindCoordinate.HEIGHT
++        });
++        this.dash.actor.add_constraint(this.constrainSize);
++
++        this._signalsHandler.add([
++            Main.overview,
++            'item-drag-begin',
++            this._onDragStart.bind(this)
++        ], [
++            Main.overview,
++            'item-drag-end',
++            this._onDragEnd.bind(this)
++        ], [
++            Main.overview,
++            'item-drag-cancelled',
++            this._onDragEnd.bind(this)
++        ], [
++            // update when workarea changes, for instance if  other extensions modify the struts
++            //(like moving th panel at the bottom)
++            global.display,
++            'workareas-changed',
++            this._resetPosition.bind(this)
++        ], [
++            Main.overview,
++            'showing',
++            this._onOverviewShowing.bind(this)
++        ], [
++            Main.overview,
++            'hiding',
++            this._onOverviewHiding.bind(this)
++        ], [
++            // Hide on appview
++            Main.overview.viewSelector,
++            'page-changed',
++            this._pageChanged.bind(this)
++        ], [
++            Main.overview.viewSelector,
++            'page-empty',
++            this._onPageEmpty.bind(this)
++        ], [
++            // Ensure the ShowAppsButton status is kept in sync
++            Main.overview.viewSelector._showAppsButton,
++            'notify::checked',
++            this._syncShowAppsButtonToggled.bind(this)
++        ], [
++            global.display,
++            'in-fullscreen-changed',
++            this._updateBarrier.bind(this)
++        ], [
++            // Monitor windows overlapping
++            this._intellihide,
++            'status-changed',
++            this._updateDashVisibility.bind(this)
++        ], [
++            // Keep dragged icon consistent in size with this dash
++            this.dash,
++            'icon-size-changed',
++            () => { Main.overview.dashIconSize = this.dash.iconSize; }
++        ], [
++            // This duplicate the similar signal which is in owerview.js.
++            // Being connected and thus executed later this effectively
++            // overwrite any attempt to use the size of the default dash
++            //which given the customization is usually much smaller.
++            // I can't easily disconnect the original signal
++            Main.overview._controls.dash,
++            'icon-size-changed',
++            () => { 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();
++        this._themeManager = new Theming.ThemeManager(this._settings, this);
++
++        // Since the actor is not a topLevel child and its parent is now not added to the Chrome,
++        // the allocation change of the parent container (slide in and slideout) doesn't trigger
++        // anymore an update of the input regions. Force the update manually.
++        this.actor.connect('notify::allocation',
++                                              Main.layoutManager._queueUpdateRegions.bind(Main.layoutManager));
++
++        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'))
++            this._enableExtraFeatures();
++        // Load optional features that need to be activated once per dock
++        this._optionalScrollWorkspaceSwitch();
++
++         // Delay operations that require the shell to be fully loaded and with
++         // user theme applied.
++
++        this._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.
++        // It gets restored on extension unload.
++        this._dashSpacer = new OverviewControls.DashSpacer();
++        this._dashSpacer.setDashActor(this._box);
++
++        if (this._position == St.Side.LEFT)
++            Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? -1 : 0); // insert on first
++        else if (this._position ==  St.Side.RIGHT)
++            Main.overview._controls._group.insert_child_at_index(this._dashSpacer, this._rtl ? 0 : -1); // insert on last
++        else if (this._position == St.Side.TOP)
++            Main.overview._overview.insert_child_at_index(this._dashSpacer, 0);
++        else if (this._position == St.Side.BOTTOM)
++            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);
++        this._slider.add_child(this._box);
++        this._box.add_actor(this.dash.actor);
++
++        // Add aligning container without tracking it for input region
++        Main.uiGroup.add_child(this.actor);
++
++        if (this._settings.get_boolean('dock-fixed')) {
++            // Note: tracking the fullscreen directly on the slider actor causes some hiccups when fullscreening
++            // windows of certain applications
++            Main.layoutManager._trackActor(this.actor, {affectsInputRegion: false, trackFullscreen: true});
++            Main.layoutManager._trackActor(this._slider, {affectsStruts: true});
++        }
++        else
++            Main.layoutManager._trackActor(this._slider);
++
++        // Set initial position
++        this._resetDepth();
++        this._resetPosition();
++    }
++
++    _initialize() {
++        if (this._paintId > 0) {
++            this.actor.disconnect(this._paintId);
++            this._paintId=0;
++        }
++
++        // Apply custome css class according to the settings
++        this._themeManager.updateCustomTheme();
++
++        // Since Gnome 3.8 dragging an app without having opened the overview before cause the attemp to
++        //animate a null target since some variables are not initialized when the viewSelector is created
++        if (Main.overview.viewSelector._activePage == null)
++            Main.overview.viewSelector._activePage = Main.overview.viewSelector._workspacesPage;
++
++        this._updateVisibilityMode();
++
++        // In case we are already inside the overview when the extension is loaded,
++        // for instance on unlocking the screen if it was locked with the overview open.
++        if (Main.overview.visibleTarget) {
++            this._onOverviewShowing();
++            this._pageChanged();
++        }
++
++        // Setup pressure barrier (GS38+ only)
++        this._updatePressureBarrier();
++        this._updateBarrier();
++
++        // setup dwelling system if pressure barriers are not available
++        this._setupDockDwellIfNeeded();
++    }
++
++    destroy() {
++        // Disconnect global signals
++        this._signalsHandler.destroy();
++        // The dash, intellihide and themeManager have global signals as well internally
++        this.dash.destroy();
++        this._intellihide.destroy();
++        this._themeManager.destroy();
++
++        this._injectionsHandler.destroy();
++
++        // Destroy main clutter actor: this should be sufficient removing it and
++        // destroying  all its children
++        this.actor.destroy();
++
++        // Remove barrier timeout
++        if (this._removeBarrierTimeoutId > 0)
++            Mainloop.source_remove(this._removeBarrierTimeoutId);
++
++        // Remove existing barrier
++        this._removeBarrier();
++
++        // Remove pointer watcher
++        if (this._dockWatch) {
++            PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch);
++            this._dockWatch = null;
++        }
++
++        // Remove the dashSpacer
++        this._dashSpacer.destroy();
++
++    }
++
++    _bindSettingsChanges() {
++        this._signalsHandler.add([
++            this._settings,
++            'changed::scroll-action',
++            () => { this._optionalScrollWorkspaceSwitch(); }
++        ], [
++            this._settings,
++            'changed::dash-max-icon-size',
++            () => { this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); }
++        ], [
++            this._settings,
++            'changed::icon-size-fixed',
++            () => { this.dash.setIconSize(this._settings.get_int('dash-max-icon-size')); }
++        ], [
++            this._settings,
++            'changed::show-favorites',
++            () => { this.dash.resetAppIcons(); }
++        ], [
++            this._settings,
++            'changed::show-running',
++            () => { this.dash.resetAppIcons(); }
++        ], [
++            this._settings,
++            'changed::show-apps-at-top',
++            () => { this.dash.resetAppIcons(); }
++        ], [
++            this._settings,
++            'changed::show-show-apps-button',
++            () => {
++                    if (this._settings.get_boolean('show-show-apps-button'))
++                        this.dash.showShowAppsButton();
++                    else
++                        this.dash.hideShowAppsButton();
++            }
++        ], [
++            this._settings,
++            'changed::dock-fixed',
++            () => {
++                    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);
++                        Main.layoutManager._trackActor(this._slider, {affectsStruts: true});
++                    } else {
++                        Main.layoutManager._untrackActor(this.actor);
++                        Main.layoutManager._untrackActor(this._slider);
++                        Main.layoutManager._trackActor(this._slider);
++                    }
++
++                    this._resetPosition();
++
++                    // Add or remove barrier depending on if dock-fixed
++                    this._updateBarrier();
++
++                    this._updateVisibilityMode();
++            }
++        ], [
++            this._settings,
++            'changed::intellihide',
++            this._updateVisibilityMode.bind(this)
++        ], [
++            this._settings,
++            'changed::intellihide-mode',
++            () => { this._intellihide.forceUpdate(); }
++        ], [
++            this._settings,
++            'changed::autohide',
++            () => {
++                    this._updateVisibilityMode();
++                    this._updateBarrier();
++            }
++        ], [
++            this._settings,
++            'changed::autohide-in-fullscreen',
++            this._updateBarrier.bind(this)
++        ],
++        [
++            this._settings,
++            'changed::extend-height',
++            this._resetPosition.bind(this)
++        ], [
++            this._settings,
++            'changed::height-fraction',
++            this._resetPosition.bind(this)
++        ], [
++            this._settings,
++            'changed::require-pressure-to-show',
++            () => {
++                    // Remove pointer watcher
++                    if (this._dockWatch) {
++                        PointerWatcher.getPointerWatcher()._removeWatch(this._dockWatch);
++                        this._dockWatch = null;
++                    }
++                    this._setupDockDwellIfNeeded();
++                    this._updateBarrier();
++            }
++        ], [
++            this._settings,
++            'changed::pressure-threshold',
++            () => {
++                    this._updatePressureBarrier();
++                    this._updateBarrier();
++            }
++        ]);
++
++    }
++
++    /**
++     * This is call when visibility settings change
++     */
++    _updateVisibilityMode() {
++        if (this._settings.get_boolean('dock-fixed')) {
++            this._fixedIsEnabled = true;
++            this._autohideIsEnabled = false;
++            this._intellihideIsEnabled = false;
++        }
++        else {
++            this._fixedIsEnabled = false;
++            this._autohideIsEnabled = this._settings.get_boolean('autohide')
++            this._intellihideIsEnabled = this._settings.get_boolean('intellihide')
++        }
++
++        if (this._intellihideIsEnabled)
++            this._intellihide.enable();
++        else
++            this._intellihide.disable();
++
++        this._updateDashVisibility();
++    }
++
++    /**
++     * Show/hide dash based on, in order of priority:
++     * overview visibility
++     * fixed mode
++     * intellihide
++     * autohide
++     * overview visibility
++     */
++    _updateDashVisibility() {
++        if (Main.overview.visibleTarget)
++            return;
++
++        if (this._fixedIsEnabled) {
++            this._removeAnimations();
++            this._animateIn(this._settings.get_double('animation-time'), 0);
++        }
++        else if (this._intellihideIsEnabled) {
++            if (this._intellihide.getOverlapStatus()) {
++                this._ignoreHover = false;
++                // Do not hide if autohide is enabled and mouse is hover
++                if (!this._box.hover || !this._autohideIsEnabled)
++                    this._animateOut(this._settings.get_double('animation-time'), 0);
++            }
++            else {
++                this._ignoreHover = true;
++                this._removeAnimations();
++                this._animateIn(this._settings.get_double('animation-time'), 0);
++            }
++        }
++        else {
++            if (this._autohideIsEnabled) {
++                this._ignoreHover = false;
++                global.sync_pointer();
++
++                if (this._box.hover)
++                    this._animateIn(this._settings.get_double('animation-time'), 0);
++                else
++                    this._animateOut(this._settings.get_double('animation-time'), 0);
++            }
++            else
++                this._animateOut(this._settings.get_double('animation-time'), 0);
++        }
++    }
++
++    _onOverviewShowing() {
++        this._ignoreHover = true;
++        this._intellihide.disable();
++        this._removeAnimations();
++        this._animateIn(this._settings.get_double('animation-time'), 0);
++    }
++
++    _onOverviewHiding() {
++        this._ignoreHover = false;
++        this._intellihide.enable();
++        this._updateDashVisibility();
++    }
++
++    _hoverChanged() {
++        if (!this._ignoreHover) {
++            // Skip if dock is not in autohide mode for instance because it is shown
++            // by intellihide.
++            if (this._autohideIsEnabled) {
++                if (this._box.hover)
++                    this._show();
++                else
++                    this._hide();
++            }
++        }
++    }
++
++    getDockState() {
++        return this._dockState;
++    }
++
++    _show() {
++        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,
++                // always give priority to show
++                this._removeAnimations();
++
++            this.emit('showing');
++            this._animateIn(this._settings.get_double('animation-time'), 0);
++        }
++    }
++
++    _hide() {
++        // If no hiding animation is running or queued
++        if ((this._dockState == State.SHOWN) || (this._dockState == State.SHOWING)) {
++            let delay;
++
++            if (this._dockState == State.SHOWING)
++                //if a show already started, let it finish; queue hide without removing the show.
++                // to obtain this I increase the delay to avoid the overlap and interference
++                // between the animations
++                delay = this._settings.get_double('hide-delay') + this._settings.get_double('animation-time');
++            else
++                delay = this._settings.get_double('hide-delay');
++
++            this.emit('hiding');
++            this._animateOut(this._settings.get_double('animation-time'), delay);
++        }
++    }
++
++    _animateIn(time, delay) {
++        this._dockState = State.SHOWING;
++
++        Tweener.addTween(this._slider, {
++            slidex: 1,
++            time: time,
++            delay: delay,
++            transition: 'easeOutQuad',
++            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, this._removeBarrier.bind(this));
++            }
++        });
++    }
++
++    _animateOut(time, delay) {
++        this._dockState = State.HIDING;
++        Tweener.addTween(this._slider, {
++            slidex: 0,
++            time: time,
++            delay: delay ,
++            transition: 'easeOutQuad',
++            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() {
++        // 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, this._checkDockDwell.bind(this));
++            this._dockDwelling = false;
++            this._dockDwellUserTime = 0;
++        }
++    }
++
++    _checkDockDwell(x, y) {
++
++        let workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitor.index)
++        let shouldDwell;
++        // Check for the correct screen edge, extending the sensitive area to the whole workarea,
++        // minus 1 px to avoid conflicting with other active corners.
++        if (this._position == St.Side.LEFT)
++            shouldDwell = (x == this._monitor.x) && (y > workArea.y) && (y < workArea.y + workArea.height);
++        else if (this._position == St.Side.RIGHT)
++            shouldDwell = (x == this._monitor.x + this._monitor.width - 1) && (y > workArea.y) && (y < workArea.y + workArea.height);
++        else if (this._position == St.Side.TOP)
++            shouldDwell = (y == this._monitor.y) && (x > workArea.x) && (x < workArea.x + workArea.width);
++        else if (this._position == St.Side.BOTTOM)
++            shouldDwell = (y == this._monitor.y + this._monitor.height - 1) && (x > workArea.x) && (x < workArea.x + workArea.width);
++
++        if (shouldDwell) {
++            // We only set up dwell timeout when the user is not hovering over the dock
++            // already (!this._box.hover).
++            // The _dockDwelling variable is used so that we only try to
++            // fire off one dock dwell - if it fails (because, say, the user has the mouse down),
++            // we don't try again until the user moves the mouse up and down again.
++            if (!this._dockDwelling && !this._box.hover && (this._dockDwellTimeoutId == 0)) {
++                // Save the interaction timestamp so we can detect user input
++                let focusWindow = global.display.focus_window;
++                this._dockDwellUserTime = focusWindow ? focusWindow.user_time : 0;
++
++                this._dockDwellTimeoutId = Mainloop.timeout_add(this._settings.get_double('show-delay') * 1000,
++                                                                this._dockDwellTimeout.bind(this));
++                GLib.Source.set_name_by_id(this._dockDwellTimeoutId, '[dash-to-dock] this._dockDwellTimeout');
++            }
++            this._dockDwelling = true;
++        }
++        else {
++            this._cancelDockDwell();
++            this._dockDwelling = false;
++        }
++    }
++
++    _cancelDockDwell() {
++        if (this._dockDwellTimeoutId != 0) {
++            Mainloop.source_remove(this._dockDwellTimeoutId);
++            this._dockDwellTimeoutId = 0;
++        }
++    }
++
++    _dockDwellTimeout() {
++        this._dockDwellTimeoutId = 0;
++
++        if (!this._settings.get_boolean('autohide-in-fullscreen') && this._monitor.inFullscreen)
++            return GLib.SOURCE_REMOVE;
++
++        // We don't want to open the tray when a modal dialog
++        // is up, so we check the modal count for that. When we are in the
++        // overview we have to take the overview's modal push into account
++        if (Main.modalCount > (Main.overview.visible ? 1 : 0))
++            return GLib.SOURCE_REMOVE;
++
++        // If the user interacted with the focus window since we started the tray
++        // dwell (by clicking or typing), don't activate the message tray
++        let focusWindow = global.display.focus_window;
++        let currentUserTime = focusWindow ? focusWindow.user_time : 0;
++        if (currentUserTime != this._dockDwellUserTime)
++            return GLib.SOURCE_REMOVE;
++
++        // Reuse the pressure version function, the logic is the same
++        this._onPressureSensed();
++        return GLib.SOURCE_REMOVE;
++    }
++
++    _updatePressureBarrier() {
++        this._canUsePressure = global.display.supports_extended_barriers();
++        let pressureThreshold = this._settings.get_double('pressure-threshold');
++
++        // Remove existing pressure barrier
++        if (this._pressureBarrier) {
++            this._pressureBarrier.destroy();
++            this._pressureBarrier = null;
++        }
++
++        if (this._barrier) {
++            this._barrier.destroy();
++            this._barrier = null;
++        }
++
++        // Create new pressure barrier based on pressure threshold setting
++        if (this._canUsePressure) {
++            this._pressureBarrier = new Layout.PressureBarrier(pressureThreshold, this._settings.get_double('show-delay')*1000,
++                                Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW);
++            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() {
++        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, () => {
++            triggerTimeoutId = 0;
++
++            let [x, y, mods] = global.get_pointer();
++            let shouldHide = true;
++            switch (this._position) {
++            case St.Side.LEFT:
++                if (x <= this.staticBox.x2 &&
++                    x >= this._monitor.x &&
++                    y >= this._monitor.y &&
++                    y <= this._monitor.y + this._monitor.height) {
++                    shouldHide = false;
++                }
++                break;
++            case St.Side.RIGHT:
++                if (x >= this.staticBox.x1 &&
++                    x <= this._monitor.x + this._monitor.width &&
++                    y >= this._monitor.y &&
++                    y <= this._monitor.y + this._monitor.height) {
++                    shouldHide = false;
++                }
++                break;
++            case St.Side.TOP:
++                if (x >= this._monitor.x &&
++                    x <= this._monitor.x + this._monitor.width &&
++                    y <= this.staticBox.y2 &&
++                    y >= this._monitor.y) {
++                    shouldHide = false;
++                }
++                break;
++            case St.Side.BOTTOM:
++                if (x >= this._monitor.x &&
++                    x <= this._monitor.x + this._monitor.width &&
++                    y >= this.staticBox.y1 &&
++                    y <= this._monitor.y + this._monitor.height) {
++                    shouldHide = false;
++                }
++            }
++            if (shouldHide) {
++                this._hoverChanged();
++                return GLib.SOURCE_REMOVE;
++            }
++            else {
++                return GLib.SOURCE_CONTINUE;
++            }
++
++        });
++
++        this._show();
++    }
++
++    /**
++     * Remove pressure barrier
++     */
++    _removeBarrier() {
++        if (this._barrier) {
++            if (this._pressureBarrier)
++                this._pressureBarrier.removeBarrier(this._barrier);
++            this._barrier.destroy();
++            this._barrier = null;
++        }
++        this._removeBarrierTimeoutId = 0;
++        return false;
++    }
++
++    /**
++     * Update pressure barrier size
++     */
++    _updateBarrier() {
++        // Remove existing barrier
++        this._removeBarrier();
++
++        // The barrier needs to be removed in fullscreen with autohide disabled, otherwise the mouse can
++        // get trapped on monitor.
++        if (this._monitor.inFullscreen && !this._settings.get_boolean('autohide-in-fullscreen'))
++            return
++
++        // Manually reset pressure barrier
++        // This is necessary because we remove the pressure barrier when it is triggered to show the dock
++        if (this._pressureBarrier) {
++            this._pressureBarrier._reset();
++            this._pressureBarrier._isTriggered = false;
++        }
++
++        // Create new barrier
++        // The barrier extends to the whole workarea, minus 1 px to avoid conflicting with other active corners
++        // Note: dash in fixed position doesn't use pressure barrier.
++        if (this._canUsePressure && this._autohideIsEnabled && this._settings.get_boolean('require-pressure-to-show')) {
++            let x1, x2, y1, y2, direction;
++            let workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitor.index)
++
++            if (this._position == St.Side.LEFT) {
++                x1 = this._monitor.x + 1;
++                x2 = x1;
++                y1 = workArea.y + 1;
++                y2 = workArea.y + workArea.height - 1;
++                direction = Meta.BarrierDirection.POSITIVE_X;
++            }
++            else if (this._position == St.Side.RIGHT) {
++                x1 = this._monitor.x + this._monitor.width - 1;
++                x2 = x1;
++                y1 = workArea.y + 1;
++                y2 = workArea.y + workArea.height - 1;
++                direction = Meta.BarrierDirection.NEGATIVE_X;
++            }
++            else if (this._position == St.Side.TOP) {
++                x1 = workArea.x + 1;
++                x2 = workArea.x + workArea.width - 1;
++                y1 = this._monitor.y;
++                y2 = y1;
++                direction = Meta.BarrierDirection.POSITIVE_Y;
++            }
++            else if (this._position == St.Side.BOTTOM) {
++                x1 = workArea.x + 1;
++                x2 = workArea.x + workArea.width - 1;
++                y1 = this._monitor.y + this._monitor.height;
++                y2 = y1;
++                direction = Meta.BarrierDirection.NEGATIVE_Y;
++            }
++
++            this._barrier = new Meta.Barrier({
++                display: global.display,
++                x1: x1,
++                x2: x2,
++                y1: y1,
++                y2: y2,
++                directions: direction
++            });
++            if (this._pressureBarrier)
++                this._pressureBarrier.addBarrier(this._barrier);
++        }
++    }
++
++    _isPrimaryMonitor() {
++        return (this._monitorIndex == Main.layoutManager.primaryIndex);
++    }
++
++    _resetPosition() {
++        // Ensure variables linked to settings are updated.
++        this._updateVisibilityMode();
++
++        let extendHeight = this._settings.get_boolean('extend-height');
++
++        // Note: do not use the workarea coordinates in the direction on which the dock is placed,
++        // to avoid a loop [position change -> workArea change -> position change] with
++        // fixed dock.
++        let workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitorIndex);
++
++        // Reserve space for the dash on the overview
++        // if the dock is on the primary monitor
++        if (this._isPrimaryMonitor())
++            this._dashSpacer.show();
++        else
++            // No space is required in the overview of the dash
++            this._dashSpacer.hide();
++
++        let fraction = this._settings.get_double('height-fraction');
++
++        if (extendHeight)
++            fraction = 1;
++        else if ((fraction < 0) || (fraction > 1))
++            fraction = 0.95;
++
++        let anchor_point;
++
++        if (this._isHorizontal) {
++            this.actor.width = Math.round( fraction * workArea.width);
++
++            let pos_y;
++            if (this._position == St.Side.BOTTOM) {
++                pos_y =  this._monitor.y + this._monitor.height;
++                anchor_point = Clutter.Gravity.SOUTH_WEST;
++            }
++            else {
++                pos_y = this._monitor.y;
++                anchor_point = Clutter.Gravity.NORTH_WEST;
++            }
++
++            this.actor.move_anchor_point_from_gravity(anchor_point);
++            this.actor.x = workArea.x + Math.round((1 - fraction) / 2 * workArea.width);
++            this.actor.y = pos_y;
++
++            if (extendHeight) {
++                this.dash._container.set_width(this.actor.width);
++                this.actor.add_style_class_name('extended');
++            }
++            else {
++                this.dash._container.set_width(-1);
++                this.actor.remove_style_class_name('extended');
++            }
++        }
++        else {
++            this.actor.height = Math.round(fraction * workArea.height);
++
++            let pos_x;
++            if (this._position == St.Side.RIGHT) {
++                pos_x =  this._monitor.x + this._monitor.width;
++                anchor_point = Clutter.Gravity.NORTH_EAST;
++            }
++            else {
++                pos_x =  this._monitor.x;
++                anchor_point = Clutter.Gravity.NORTH_WEST;
++            }
++
++            this.actor.move_anchor_point_from_gravity(anchor_point);
++            this.actor.x = pos_x;
++            this.actor.y = workArea.y + Math.round((1 - fraction) / 2 * workArea.height);
++
++            if (extendHeight) {
++                this.dash._container.set_height(this.actor.height);
++                this.actor.add_style_class_name('extended');
++            }
++            else {
++                this.dash._container.set_height(-1);
++                this.actor.remove_style_class_name('extended');
++            }
++        }
++
++        this._y0 = this.actor.y;
++    }
++
++    // Set the dash at the correct depth in z
++    _resetDepth() {
++        // Keep the dash below the modalDialogGroup
++        Main.layoutManager.uiGroup.set_child_below_sibling(this.actor, Main.layoutManager.modalDialogGroup);
++    }
++
++    _updateStaticBox() {
++        this.staticBox.init_rect(
++            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() {
++        Tweener.removeTweens(this._slider);
++    }
++
++    _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() {
++        // Restore drag default dash stack order
++        this._resetDepth();
++        if (this._oldignoreHover !== null)
++            this._ignoreHover  = this._oldignoreHover;
++        this._oldignoreHover = null;
++        this._box.sync_hover();
++        if (Main.overview._shown)
++            this._pageChanged();
++    }
++
++    _pageChanged() {
++        let activePage = Main.overview.viewSelector.getActivePage();
++        let dashVisible = (activePage == ViewSelector.ViewPage.WINDOWS ||
++                           activePage == ViewSelector.ViewPage.APPS);
++
++        if (dashVisible)
++            this._animateIn(this._settings.get_double('animation-time'), 0);
++        else
++            this._animateOut(this._settings.get_double('animation-time'), 0);
++    }
++
++    _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,
++         * as it's done for the upstream dashSpacer.
++         *
++         * Moreover, hiding the spacer ensure the appGrid allocaton is triggered.
++         * This matter as the appview spring animation is triggered by to first reallocaton of the appGrid,
++         * (See appDisplay.js, line 202 on GNOME Shell 3.14:
++         *                             this._grid.actor.connect('notify::allocation', ...)
++         * which in turn seems to be triggered by changes in the other actors in the overview.
++         * Normally, as far as I could understand, either the dashSpacer being hidden or the workspacesThumbnails
++         * sliding out would trigger the allocation. However, with no stock dash
++         * and no thumbnails, which happen if the user configured only 1 and static workspace,
++         * the animation out of icons is not played.
++         */
++
++        let activePage = Main.overview.viewSelector.getActivePage();
++        this._dashSpacer.visible = (this._isHorizontal || activePage == ViewSelector.ViewPage.WINDOWS);
++    }
++
++    /**
++     * Show dock and give key focus to it
++     */
++    _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() {
++        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() {
++        // Restore dash accessibility
++        Main.ctrlAltTabManager.addGroup(
++            this.dash.actor, _('Dash'), 'user-bookmarks-symbolic',
++                {focusCallback: this._onAccessibilityFocus.bind(this)});
++    }
++
++    /**
++     * Switch workspace by scrolling over the dock
++     */
++    _optionalScrollWorkspaceSwitch() {
++        let label = 'optionalScrollWorkspaceSwitch';
++
++        function isEnabled() {
++            return this._settings.get_enum('scroll-action') === scrollAction.SWITCH_WORKSPACE;
++        }
++
++        this._settings.connect('changed::scroll-action', () => {
++            if (isEnabled.bind(this)())
++                enable.bind(this)();
++            else
++                disable.bind(this)();
++        });
++
++        if (isEnabled.bind(this)())
++            enable.bind(this)();
++
++        function enable() {
++            this._signalsHandler.removeWithLabel(label);
++
++            this._signalsHandler.addWithLabel(label, [
++                this._box,
++                'scroll-event',
++                onScrollEvent.bind(this)
++            ]);
++
++            this._optionalScrollWorkspaceSwitchDeadTimeId = 0;
++        }
++
++        function disable() {
++            this._signalsHandler.removeWithLabel(label);
++
++            if (this._optionalScrollWorkspaceSwitchDeadTimeId > 0) {
++                Mainloop.source_remove(this._optionalScrollWorkspaceSwitchDeadTimeId);
++                this._optionalScrollWorkspaceSwitchDeadTimeId = 0;
++            }
++        }
++
++        // This was inspired to desktop-scroller@obsidien.github.com
++        function onScrollEvent(actor, event) {
++            // When in overview change workscape only in windows view
++            if (Main.overview.visible && Main.overview.viewSelector.getActivePage() !== ViewSelector.ViewPage.WINDOWS)
++                return false;
++
++            let activeWs = global.workspace_manager.get_active_workspace();
++            let direction = null;
++
++            switch (event.get_scroll_direction()) {
++            case Clutter.ScrollDirection.UP:
++                direction = Meta.MotionDirection.UP;
++                break;
++            case Clutter.ScrollDirection.DOWN:
++                direction = Meta.MotionDirection.DOWN;
++                break;
++            case Clutter.ScrollDirection.SMOOTH:
++                let [dx, dy] = event.get_scroll_delta();
++                if (dy < 0)
++                    direction = Meta.MotionDirection.UP;
++                else if (dy > 0)
++                    direction = Meta.MotionDirection.DOWN;
++                break;
++            }
++
++            if (direction !== null) {
++                // Prevent scroll events from triggering too many workspace switches
++                // by adding a 250ms deadtime between each scroll event.
++                // Usefull on laptops when using a touchpad.
++
++                // During the deadtime do nothing
++                if (this._optionalScrollWorkspaceSwitchDeadTimeId > 0)
++                    return false;
++                else
++                    this._optionalScrollWorkspaceSwitchDeadTimeId = Mainloop.timeout_add(250, () => {
++                        this._optionalScrollWorkspaceSwitchDeadTimeId = 0;
++                    });
++
++                let ws;
++
++                ws = activeWs.get_neighbor(direction)
++
++                if (Main.wm._workspaceSwitcherPopup == null)
++                    Main.wm._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup();
++                    // Set the actor non reactive, so that it doesn't prevent the
++                    // clicks events from reaching the dash actor. I can't see a reason
++                    // why it should be reactive.
++                    Main.wm._workspaceSwitcherPopup.actor.reactive = false;
++                    Main.wm._workspaceSwitcherPopup.connect('destroy', function() {
++                        Main.wm._workspaceSwitcherPopup = null;
++                    });
++
++                // Do not show wokspaceSwithcer in overview
++                if (!Main.overview.visible)
++                    Main.wm._workspaceSwitcherPopup.display(direction, ws.index());
++                Main.wm.actionMoveWorkspace(ws);
++
++                return true;
++            }
++            else
++                return false;
++        }
++    }
++
++    _activateApp(appIndex) {
++        let children = this.dash._box.get_children().filter(function(actor) {
++                return actor.child &&
++                       actor.child._delegate &&
++                       actor.child._delegate.app;
++        });
++
++        // Apps currently in the dash
++        let apps = children.map(function(actor) {
++                return actor.child._delegate;
++            });
++
++        // Activate with button = 1, i.e. same as left click
++        let button = 1;
++        if (appIndex < apps.length)
++            apps[appIndex].activate(button);
++    }
++};
++
++Signals.addSignalMethods(DockedDash.prototype);
++
++/*
++ * Handle keybaord shortcuts
++ */
++const DashToDock_KeyboardShortcuts_NUM_HOTKEYS = 10;
++
++var KeyboardShortcuts = class DashToDock_KeyboardShortcuts {
++
++    constructor(settings, allDocks){
++        this._settings = settings;
++        this._allDocks = allDocks;
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++
++        this._hotKeysEnabled = false;
++        if (this._settings.get_boolean('hot-keys'))
++            this._enableHotKeys();
++
++        this._signalsHandler.add([
++            this._settings,
++            'changed::hot-keys',
++            () => {
++                    if (this._settings.get_boolean('hot-keys'))
++                        this._enableHotKeys.bind(this)();
++                    else
++                        this._disableHotKeys.bind(this)();
++            }
++        ]);
++
++        this._optionalNumberOverlay();
++    }
++
++    destroy() {
++        // Remove keybindings
++        this._disableHotKeys();
++        this._disableExtraShortcut();
++        this._signalsHandler.destroy();
++    }
++
++    _enableHotKeys() {
++        if (this._hotKeysEnabled)
++            return;
++
++        // Setup keyboard bindings for dash elements
++        let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-'];
++        keys.forEach( function(key) {
++            for (let i = 0; i < DashToDock_KeyboardShortcuts_NUM_HOTKEYS; i++) {
++                let appNum = i;
++                Main.wm.addKeybinding(key + (i + 1), this._settings,
++                                      Meta.KeyBindingFlags.NONE,
++                                      Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW,
++                                      () => {
++                                          this._allDocks[0]._activateApp(appNum);
++                                          this._showOverlay();
++                                      });
++            }
++        }, this);
++
++        this._hotKeysEnabled = true;
++    }
++
++    _disableHotKeys() {
++        if (!this._hotKeysEnabled)
++            return;
++
++        let keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-'];
++        keys.forEach( function(key) {
++            for (let i = 0; i < DashToDock_KeyboardShortcuts_NUM_HOTKEYS; i++)
++                Main.wm.removeKeybinding(key + (i + 1));
++        }, this);
++
++        this._hotKeysEnabled = false;
++    }
++
++    _optionalNumberOverlay() {
++        this._shortcutIsSet = false;
++        // Enable extra shortcut if either 'overlay' or 'show-dock' are true
++        if (this._settings.get_boolean('hot-keys') &&
++           (this._settings.get_boolean('hotkeys-overlay') || this._settings.get_boolean('hotkeys-show-dock')))
++            this._enableExtraShortcut();
++
++        this._signalsHandler.add([
++            this._settings,
++            'changed::hot-keys',
++            this._checkHotkeysOptions.bind(this)
++        ], [
++            this._settings,
++            'changed::hotkeys-overlay',
++            this._checkHotkeysOptions.bind(this)
++        ], [
++            this._settings,
++            'changed::hotkeys-show-dock',
++            this._checkHotkeysOptions.bind(this)
++        ]);
++    }
++
++    _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() {
++        if (!this._shortcutIsSet) {
++            Main.wm.addKeybinding('shortcut', this._settings,
++                                  Meta.KeyBindingFlags.NONE,
++                                  Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW,
++                                  this._showOverlay.bind(this));
++            this._shortcutIsSet = true;
++        }
++    }
++
++    _disableExtraShortcut() {
++        if (this._shortcutIsSet) {
++            Main.wm.removeKeybinding('shortcut');
++            this._shortcutIsSet = false;
++        }
++    }
++
++    _showOverlay() {
++        for (let i = 0; i < this._allDocks.length; i++) {
++            let dock = this._allDocks[i];
++            if (dock._settings.get_boolean('hotkeys-overlay'))
++                dock.dash.toggleNumberOverlay(true);
++
++            // Restart the counting if the shortcut is pressed again
++            if (dock._numberOverlayTimeoutId) {
++                Mainloop.source_remove(dock._numberOverlayTimeoutId);
++                dock._numberOverlayTimeoutId = 0;
++            }
++
++            // Hide the overlay/dock after the timeout
++            let timeout = dock._settings.get_double('shortcut-timeout') * 1000;
++            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')) {
++                let showDock = (dock._intellihideIsEnabled || dock._autohideIsEnabled);
++                if (showDock)
++                    dock._show();
++            }
++        }
++    }
++};
++
++/**
++ * Isolate overview to open new windows for inactive apps
++ * Note: the future implementaion is not fully contained here. Some bits are around in other methods of other classes.
++ * This class just take care of enabling/disabling the option.
++ */
++var WorkspaceIsolation = class DashToDock_WorkspaceIsolation {
++
++    constructor(settings, allDocks) {
++
++        this._settings = settings;
++        this._allDocks = allDocks;
++
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++        this._injectionsHandler = new Utils.InjectionsHandler();
++
++        this._signalsHandler.add([
++            this._settings,
++            'changed::isolate-workspaces',
++            () => {
++                    this._allDocks.forEach(function(dock) {
++                        dock.dash.resetAppIcons();
++                    });
++                    if (this._settings.get_boolean('isolate-workspaces') ||
++                        this._settings.get_boolean('isolate-monitors'))
++                        this._enable.bind(this)();
++                    else
++                        this._disable.bind(this)();
++            }
++        ],[
++            this._settings,
++            'changed::isolate-monitors',
++            () => {
++                    this._allDocks.forEach(function(dock) {
++                        dock.dash.resetAppIcons();
++                    });
++                    if (this._settings.get_boolean('isolate-workspaces') ||
++                        this._settings.get_boolean('isolate-monitors'))
++                        this._enable.bind(this)();
++                    else
++                        this._disable.bind(this)();
++            }
++        ]);
++
++        if (this._settings.get_boolean('isolate-workspaces') ||
++            this._settings.get_boolean('isolate-monitors'))
++            this._enable();
++
++    }
++
++    _enable() {
++
++        // ensure I never double-register/inject
++        // although it should never happen
++        this._disable();
++
++        this._allDocks.forEach(function(dock) {
++            this._signalsHandler.addWithLabel('isolation', [
++                global.display,
++                'restacked',
++                dock.dash._queueRedisplay.bind(dock.dash)
++            ], [
++                global.window_manager,
++                'switch-workspace',
++                dock.dash._queueRedisplay.bind(dock.dash)
++            ]);
++
++            // This last signal is only needed for monitor isolation, as windows
++            // might migrate from one monitor to another without triggering 'restacked'
++            if (this._settings.get_boolean('isolate-monitors'))
++                this._signalsHandler.addWithLabel('isolation', [
++                    global.display,
++                    'window-entered-monitor',
++                    dock.dash._queueRedisplay.bind(dock.dash)
++                ]);
++
++        }, this);
++
++        // here this is the Shell.App
++        function IsolatedOverview() {
++            // These lines take care of Nautilus for icons on Desktop
++            let windows = this.get_windows().filter(function(w) {
++                return w.get_workspace().index() == global.workspace_manager.get_active_workspace_index();
++            });
++            if (windows.length == 1)
++                if (windows[0].skip_taskbar)
++                    return this.open_new_window(-1);
++
++            if (this.is_on_workspace(global.workspace_manager.get_active_workspace()))
++                return Main.activateWindow(windows[0]);
++            return this.open_new_window(-1);
++        }
++
++        this._injectionsHandler.addWithLabel('isolation', [
++            Shell.App.prototype,
++            'activate',
++            IsolatedOverview
++        ]);
++    }
++
++    _disable () {
++        this._signalsHandler.removeWithLabel('isolation');
++        this._injectionsHandler.removeWithLabel('isolation');
++    }
++
++    destroy() {
++        this._signalsHandler.destroy();
++        this._injectionsHandler.destroy();
++    }
++};
++
++
++var DockManager = class DashToDock_DockManager {
++
++    constructor() {
++        this._remoteModel = new LauncherAPI.LauncherEntryRemoteModel();
++        this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.dash-to-dock');
++        this._oldDash = Main.overview._dash;
++        /* Array of all the docks created */
++        this._allDocks = [];
++        this._createDocks();
++
++        // status variable: true when the overview is shown through the dash
++        // applications button.
++        this._forcedOverview = false;
++
++        // Connect relevant signals to the toggling function
++        this._bindSettingsChanges();
++    }
++
++    _toggle() {
++        this._deleteDocks();
++        this._createDocks();
++        this.emit('toggled');
++    }
++
++    _bindSettingsChanges() {
++        // Connect relevant signals to the toggling function
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++        this._signalsHandler.add([
++            Meta.MonitorManager.get(),
++            'monitors-changed',
++            this._toggle.bind(this)
++        ], [
++            this._settings,
++            'changed::multi-monitor',
++            this._toggle.bind(this)
++        ], [
++            this._settings,
++            'changed::preferred-monitor',
++            this._toggle.bind(this)
++        ], [
++            this._settings,
++            'changed::dock-position',
++            this._toggle.bind(this)
++        ], [
++            this._settings,
++            'changed::extend-height',
++            this._adjustPanelCorners.bind(this)
++        ], [
++            this._settings,
++            'changed::dock-fixed',
++            this._adjustPanelCorners.bind(this)
++        ]);
++    }
++
++    _createDocks() {
++
++        // If there are no monitors (headless configurations, but it can also happen temporary while disconnecting
++        // and reconnecting monitors), just do nothing. When a monitor will be connected we we'll be notified and
++        // and thus create the docks. This prevents pointing trying to access monitors throughout the code, were we
++        // are assuming that at least the primary monitor is present.
++        if (Main.layoutManager.monitors.length <= 0) {
++            return;
++        }
++
++        this._preferredMonitorIndex = this._settings.get_int('preferred-monitor');
++        // In case of multi-monitor, we consider the dock on the primary monitor to be the preferred (main) one
++        // regardless of the settings
++        // The dock goes on the primary monitor also if the settings are incosistent (e.g. desired monitor not connected).
++        if (this._settings.get_boolean('multi-monitor') ||
++            this._preferredMonitorIndex < 0 || this._preferredMonitorIndex > Main.layoutManager.monitors.length - 1
++            ) {
++            this._preferredMonitorIndex = Main.layoutManager.primaryIndex;
++        } else {
++            // Gdk and shell monitors numbering differ at least under wayland:
++            // While the primary monitor appears to be always index 0 in Gdk,
++            // the shell can assign a different number (Main.layoutManager.primaryMonitor)
++            // This ensure the indexing in the settings (Gdk) and in the shell are matched,
++            // i.e. that we start counting from the primaryMonitorIndex
++            this._preferredMonitorIndex = (Main.layoutManager.primaryIndex + this._preferredMonitorIndex) % Main.layoutManager.monitors.length ;
++        }
++
++        // First we create the main Dock, to get the extra features to bind to this one
++        let dock = new DockedDash(this._settings, this._remoteModel, this._preferredMonitorIndex);
++        this._mainShowAppsButton = dock.dash.showAppsButton;
++        this._allDocks.push(dock);
++
++        // connect app icon into the view selector
++        dock.dash.showAppsButton.connect('notify::checked', this._onShowAppsButtonToggled.bind(this));
++
++        // Make the necessary changes to Main.overview._dash
++        this._prepareMainDash();
++
++        // Adjust corners if necessary
++        this._adjustPanelCorners();
++
++        if (this._settings.get_boolean('multi-monitor')) {
++            let nMon = Main.layoutManager.monitors.length;
++            for (let iMon = 0; iMon < nMon; iMon++) {
++                if (iMon == this._preferredMonitorIndex)
++                    continue;
++                let dock = new DockedDash(this._settings, this._remoteModel, iMon);
++                this._allDocks.push(dock);
++                // connect app icon into the view selector
++                dock.dash.showAppsButton.connect('notify::checked', this._onShowAppsButtonToggled.bind(this));
++            }
++        }
++
++        // Load optional features. We load *after* the docks are created, since
++        // we need to connect the signals to all dock instances.
++        this._workspaceIsolation = new WorkspaceIsolation(this._settings, this._allDocks);
++        this._keyboardShortcuts = new KeyboardShortcuts(this._settings, this._allDocks);
++    }
++
++    _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;
++
++        // set stored icon size  to the new dash
++        Main.overview.dashIconSize = this._allDocks[0].dash.iconSize;
++
++        // Hide usual Dash
++        Main.overview._controls.dash.actor.hide();
++
++        // Also set dash width to 1, so it's almost not taken into account by code
++        // calculaing the reserved space in the overview. The reason to keep it at 1 is
++        // to allow its visibility change to trigger an allocaion of the appGrid which
++        // in turn is triggergin the appsIcon spring animation, required when no other
++        // actors has this effect, i.e in horizontal mode and without the workspaceThumnails
++        // 1 static workspace only)
++        Main.overview._controls.dash.actor.set_width(1);
++    }
++
++    _deleteDocks() {
++        // Remove extra features
++        this._workspaceIsolation.destroy();
++        this._keyboardShortcuts.destroy();
++
++        // Delete all docks
++        let nDocks = this._allDocks.length;
++        for (let i = nDocks-1; i >= 0; i--) {
++            this._allDocks[i].destroy();
++            this._allDocks.pop();
++        }
++    }
++
++    _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
++        Main.overview._controls.dash._maxHeight = -1;
++
++        // reset stored icon size  to the default dash
++        Main.overview.dashIconSize = Main.overview._controls.dash.iconSize;
++
++        Main.overview._dash = this._oldDash;
++    }
++
++    _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
++        // status (due to the _syncShowAppsButtonToggled function below) and it
++        // has already performed the desired action.
++
++        let animate = this._settings.get_boolean('animate-show-apps');
++        let selector = Main.overview.viewSelector;
++
++        if (selector._showAppsButton.checked !== button.checked) {
++            // find visible view
++            let visibleView;
++            Main.overview.viewSelector.appDisplay._views.every(function(v, index) {
++                if (v.view.actor.visible) {
++                    visibleView = index;
++                    return false;
++                }
++                else
++                    return true;
++            });
++
++            if (button.checked) {
++                // force spring animation triggering.By default the animation only
++                // runs if we are already inside the overview.
++                if (!Main.overview._shown) {
++                    this._forcedOverview = true;
++                    let view = Main.overview.viewSelector.appDisplay._views[visibleView].view;
++                    let grid = view._grid;
++                    if (animate) {
++                        // Animate in the the appview, hide the appGrid to avoiud flashing
++                        // Go to the appView before entering the overview, skipping the workspaces.
++                        // Do this manually avoiding opacity in transitions so that the setting of the opacity
++                        // to 0 doesn't get overwritten.
++                        Main.overview.viewSelector._activePage.opacity = 0;
++                        Main.overview.viewSelector._activePage.hide();
++                        Main.overview.viewSelector._activePage = Main.overview.viewSelector._appsPage;
++                        Main.overview.viewSelector._activePage.show();
++                        grid.actor.opacity = 0;
++
++                        // The animation has to be trigered manually because the AppDisplay.animate
++                        // method is waiting for an allocation not happening, as we skip the workspace view
++                        // 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', () => {
++                            Main.overview.disconnect(overviewShownId);
++                            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;
++                        Main.overview.viewSelector._activePage.show();
++                        grid.actor.opacity = 255;
++                    }
++
++                }
++
++                // Finally show the overview
++                selector._showAppsButton.checked = true;
++                Main.overview.show();
++            }
++            else {
++                if (this._forcedOverview) {
++                    // force exiting overview if needed
++
++                    if (animate) {
++                        // Manually trigger springout animation without activating the
++                        // workspaceView to avoid the zoomout animation. Hide the appPage
++                        // 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, () => {
++                            Main.overview.viewSelector._appsPage.hide();
++                            Main.overview.hide();
++                            selector._showAppsButton.checked = false;
++                            this._forcedOverview = false;
++                        });
++                    }
++                    else {
++                        Main.overview.hide();
++                        this._forcedOverview = false;
++                    }
++                }
++                else {
++                    selector._showAppsButton.checked = false;
++                    this._forcedOverview = false;
++                }
++            }
++        }
++
++        // whenever the button is unactivated even if not by the user still reset the
++        // forcedOverview flag
++        if (button.checked == false)
++            this._forcedOverview = false;
++    }
++
++    destroy() {
++        this._signalsHandler.destroy();
++        this._deleteDocks();
++        this._revertPanelCorners();
++        this._restoreDash();
++        this._remoteModel.destroy();
++    }
++
++    /**
++     * Adjust Panel corners
++     */
++    _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');
++        let fixedIsEnabled = this._settings.get_boolean('dock-fixed');
++        let dockOnPrimary  = this._settings.get_boolean('multi-monitor') ||
++                             this._preferredMonitorIndex == Main.layoutManager.primaryIndex;
++
++        if (!isHorizontal && dockOnPrimary && extendHeight && fixedIsEnabled) {
++            Main.panel._rightCorner.actor.hide();
++            Main.panel._leftCorner.actor.hide();
++        }
++        else
++            this._revertPanelCorners();
++    }
++
++    _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..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 ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++const Docking = Me.imports.docking;
++
++// We declare this with var so it can be accessed by other extensions in
++// GNOME Shell 3.26+ (mozjs52+).
++var dockManager;
++
++function init() {
++    ExtensionUtils.initTranslations('dashtodock');
++}
++
++function enable() {
++    dockManager = new Docking.DockManager();
++}
++
++function disable() {
++    dockManager.destroy();
++
++    dockManager=null;
++}
+diff --git a/extensions/dash-to-dock/intellihide.js b/extensions/dash-to-dock/intellihide.js
+new file mode 100644
+index 0000000..f102ea3
+--- /dev/null
++++ b/extensions/dash-to-dock/intellihide.js
+@@ -0,0 +1,321 @@
++// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
++
++const GLib = imports.gi.GLib;
++const Mainloop = imports.mainloop;
++const Meta = imports.gi.Meta;
++const Shell = imports.gi.Shell;
++
++const Main = imports.ui.main;
++const Signals = imports.signals;
++
++const Me = imports.misc.extensionUtils.getCurrentExtension();
++const Utils = Me.imports.utils;
++
++// A good compromise between reactivity and efficiency; to be tuned.
++const INTELLIHIDE_CHECK_INTERVAL = 100;
++
++const OverlapStatus = {
++    UNDEFINED: -1,
++    FALSE: 0,
++    TRUE: 1
++};
++
++const IntellihideMode = {
++    ALL_WINDOWS: 0,
++    FOCUS_APPLICATION_WINDOWS: 1,
++    MAXIMIZED_WINDOWS : 2
++};
++
++// List of windows type taken into account. Order is important (keep the original
++// enum order).
++const handledWindowTypes = [
++    Meta.WindowType.NORMAL,
++    Meta.WindowType.DOCK,
++    Meta.WindowType.DIALOG,
++    Meta.WindowType.MODAL_DIALOG,
++    Meta.WindowType.TOOLBAR,
++    Meta.WindowType.MENU,
++    Meta.WindowType.UTILITY,
++    Meta.WindowType.SPLASHSCREEN
++];
++
++/**
++ * A rough and ugly implementation of the intellihide behaviour.
++ * Intallihide object: emit 'status-changed' signal when the overlap of windows
++ * with the provided targetBoxClutter.ActorBox changes;
++ */
++var Intellihide = class DashToDock_Intellihide {
++
++    constructor(settings, monitorIndex) {
++        // Load settings
++        this._settings = settings;
++        this._monitorIndex = monitorIndex;
++
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++        this._tracker = Shell.WindowTracker.get_default();
++        this._focusApp = null; // The application whose window is focused.
++        this._topApp = null; // The application whose window is on top on the monitor with the dock.
++
++        this._isEnabled = false;
++        this.status = OverlapStatus.UNDEFINED;
++        this._targetBox = null;
++
++        this._checkOverlapTimeoutContinue = false;
++        this._checkOverlapTimeoutId = 0;
++
++        this._trackedWindows = new Map();
++
++        // Connect global signals
++        this._signalsHandler.add([
++            // Add signals on windows created from now on
++            global.display,
++            'window-created',
++            this._windowCreated.bind(this)
++        ], [
++            // triggered for instance when the window list order changes,
++            // included when the workspace is switched
++            global.display,
++            'restacked',
++            this._checkOverlap.bind(this)
++        ], [
++            // when windows are alwasy on top, the focus window can change
++            // without the windows being restacked. Thus monitor window focus change.
++            this._tracker,
++            'notify::focus-app',
++            this._checkOverlap.bind(this)
++        ], [
++            // update wne monitor changes, for instance in multimonitor when monitor are attached
++            Meta.MonitorManager.get(),
++            'monitors-changed',
++            this._checkOverlap.bind(this)
++        ]);
++    }
++
++    destroy() {
++        // Disconnect global signals
++        this._signalsHandler.destroy();
++
++        // Remove  residual windows signals
++        this.disable();
++    }
++
++    enable() {
++        this._isEnabled = true;
++        this._status = OverlapStatus.UNDEFINED;
++        global.get_window_actors().forEach(function(wa) {
++            this._addWindowSignals(wa);
++        }, this);
++        this._doCheckOverlap();
++    }
++
++    disable() {
++        this._isEnabled = false;
++
++        for (let wa of this._trackedWindows.keys()) {
++            this._removeWindowSignals(wa);
++        }
++        this._trackedWindows.clear();
++
++        if (this._checkOverlapTimeoutId > 0) {
++            Mainloop.source_remove(this._checkOverlapTimeoutId);
++            this._checkOverlapTimeoutId = 0;
++        }
++    }
++
++    _windowCreated(display, metaWindow) {
++        this._addWindowSignals(metaWindow.get_compositor_private());
++    }
++
++    _addWindowSignals(wa) {
++        if (!this._handledWindow(wa))
++            return;
++        let signalId = wa.connect('allocation-changed', this._checkOverlap.bind(this));
++        this._trackedWindows.set(wa, signalId);
++        wa.connect('destroy', this._removeWindowSignals.bind(this));
++    }
++
++    _removeWindowSignals(wa) {
++        if (this._trackedWindows.get(wa)) {
++           wa.disconnect(this._trackedWindows.get(wa));
++           this._trackedWindows.delete(wa);
++        }
++
++    }
++
++    updateTargetBox(box) {
++        this._targetBox = box;
++        this._checkOverlap();
++    }
++
++    forceUpdate() {
++        this._status = OverlapStatus.UNDEFINED;
++        this._doCheckOverlap();
++    }
++
++    getOverlapStatus() {
++        return (this._status == OverlapStatus.TRUE);
++    }
++
++    _checkOverlap() {
++        if (!this._isEnabled || (this._targetBox == null))
++            return;
++
++        /* Limit the number of calls to the doCheckOverlap function */
++        if (this._checkOverlapTimeoutId) {
++            this._checkOverlapTimeoutContinue = true;
++            return
++        }
++
++        this._doCheckOverlap();
++
++        this._checkOverlapTimeoutId = Mainloop.timeout_add(INTELLIHIDE_CHECK_INTERVAL, () => {
++            this._doCheckOverlap();
++            if (this._checkOverlapTimeoutContinue) {
++                this._checkOverlapTimeoutContinue = false;
++                return GLib.SOURCE_CONTINUE;
++            } else {
++                this._checkOverlapTimeoutId = 0;
++                return GLib.SOURCE_REMOVE;
++            }
++        });
++    }
++
++    _doCheckOverlap() {
++
++        if (!this._isEnabled || (this._targetBox == null))
++            return;
++
++        let overlaps = OverlapStatus.FALSE;
++        let windows = global.get_window_actors();
++
++        if (windows.length > 0) {
++            /*
++             * Get the top window on the monitor where the dock is placed.
++             * The idea is that we dont want to overlap with the windows of the topmost application,
++             * event is it's not the focused app -- for instance because in multimonitor the user
++             * select a window in the secondary monitor.
++             */
++
++            let topWindow = null;
++            for (let i = windows.length - 1; i >= 0; i--) {
++                let meta_win = windows[i].get_meta_window();
++                if (this._handledWindow(windows[i]) && (meta_win.get_monitor() == this._monitorIndex)) {
++                    topWindow = meta_win;
++                    break;
++                }
++            }
++
++            if (topWindow !== null) {
++                this._topApp = this._tracker.get_window_app(topWindow);
++                // If there isn't a focused app, use that of the window on top
++                this._focusApp = this._tracker.focus_app || this._topApp
++
++                windows = windows.filter(this._intellihideFilterInteresting, this);
++
++                for (let i = 0;  i < windows.length; i++) {
++                    let win = windows[i].get_meta_window();
++
++                    if (win) {
++                        let rect = win.get_frame_rect();
++
++                        let test = (rect.x < this._targetBox.x2) &&
++                                   (rect.x + rect.width > this._targetBox.x1) &&
++                                   (rect.y < this._targetBox.y2) &&
++                                   (rect.y + rect.height > this._targetBox.y1);
++
++                        if (test) {
++                            overlaps = OverlapStatus.TRUE;
++                            break;
++                        }
++                    }
++                }
++            }
++        }
++
++        if (this._status !== overlaps) {
++            this._status = overlaps;
++            this.emit('status-changed', this._status);
++        }
++
++    }
++
++    // Filter interesting windows to be considered for intellihide.
++    // Consider all windows visible on the current workspace.
++    // Optionally skip windows of other applications
++    _intellihideFilterInteresting(wa) {
++        let meta_win = wa.get_meta_window();
++        if (!this._handledWindow(wa))
++            return false;
++
++        let currentWorkspace = global.workspace_manager.get_active_workspace_index();
++        let wksp = meta_win.get_workspace();
++        let wksp_index = wksp.index();
++
++        // Depending on the intellihide mode, exclude non-relevent windows
++        switch (this._settings.get_enum('intellihide-mode')) {
++            case IntellihideMode.ALL_WINDOWS:
++                // Do nothing
++                break;
++
++            case IntellihideMode.FOCUS_APPLICATION_WINDOWS:
++                // Skip windows of other apps
++                if (this._focusApp) {
++                    // The DropDownTerminal extension is not an application per se
++                    // so we match its window by wm class instead
++                    if (meta_win.get_wm_class() == 'DropDownTerminalWindow')
++                        return true;
++
++                    let currentApp = this._tracker.get_window_app(meta_win);
++                    let focusWindow = global.display.get_focus_window()
++
++                    // Consider half maximized windows side by side
++                    // and windows which are alwayson top
++                    if((currentApp != this._focusApp) && (currentApp != this._topApp)
++                        && !((focusWindow && focusWindow.maximized_vertically && !focusWindow.maximized_horizontally)
++                              && (meta_win.maximized_vertically && !meta_win.maximized_horizontally)
++                              && meta_win.get_monitor() == focusWindow.get_monitor())
++                        && !meta_win.is_above())
++                        return false;
++                }
++                break;
++
++            case IntellihideMode.MAXIMIZED_WINDOWS:
++                // Skip unmaximized windows
++                if (!meta_win.maximized_vertically && !meta_win.maximized_horizontally)
++                    return false;
++                break;
++        }
++
++        if ( wksp_index == currentWorkspace && meta_win.showing_on_its_workspace() )
++            return true;
++        else
++            return false;
++
++    }
++
++    // Filter windows by type
++    // inspired by Opacify@gnome-shell.localdomain.pl
++    _handledWindow(wa) {
++        let metaWindow = wa.get_meta_window();
++
++        if (!metaWindow)
++            return false;
++
++        // The DropDownTerminal extension uses the POPUP_MENU window type hint
++        // so we match its window by wm class instead
++        if (metaWindow.get_wm_class() == 'DropDownTerminalWindow')
++            return true;
++
++        let wtype = metaWindow.get_window_type();
++        for (let i = 0; i < handledWindowTypes.length; i++) {
++            var hwtype = handledWindowTypes[i];
++            if (hwtype == wtype)
++                return true;
++            else if (hwtype > wtype)
++                return false;
++        }
++        return false;
++    }
++};
++
++Signals.addSignalMethods(Intellihide.prototype);
+diff --git a/extensions/dash-to-dock/launcherAPI.js b/extensions/dash-to-dock/launcherAPI.js
+new file mode 100644
+index 0000000..f0b6199
+--- /dev/null
++++ b/extensions/dash-to-dock/launcherAPI.js
+@@ -0,0 +1,239 @@
++// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
++
++const Gio = imports.gi.Gio;
++const Signals = imports.signals;
++
++var LauncherEntryRemoteModel = class DashToDock_LauncherEntryRemoteModel {
++
++    constructor() {
++        this._entriesByDBusName = {};
++
++        this._launcher_entry_dbus_signal_id =
++            Gio.DBus.session.signal_subscribe(null, // sender
++                'com.canonical.Unity.LauncherEntry', // iface
++                null, // member
++                null, // path
++                null, // arg0
++                Gio.DBusSignalFlags.NONE,
++                this._onEntrySignalReceived.bind(this));
++
++        this._dbus_name_owner_changed_signal_id =
++            Gio.DBus.session.signal_subscribe('org.freedesktop.DBus',  // sender
++                'org.freedesktop.DBus',  // interface
++                'NameOwnerChanged',      // member
++                '/org/freedesktop/DBus', // path
++                null,                    // arg0
++                Gio.DBusSignalFlags.NONE,
++                this._onDBusNameOwnerChanged.bind(this));
++
++        this._acquireUnityDBus();
++    }
++
++    destroy() {
++        if (this._launcher_entry_dbus_signal_id) {
++            Gio.DBus.session.signal_unsubscribe(this._launcher_entry_dbus_signal_id);
++        }
++
++        if (this._dbus_name_owner_changed_signal_id) {
++            Gio.DBus.session.signal_unsubscribe(this._dbus_name_owner_changed_signal_id);
++        }
++
++        this._releaseUnityDBus();
++    }
++
++    size() {
++        return Object.keys(this._entriesByDBusName).length;
++    }
++
++    lookupByDBusName(dbusName) {
++        return this._entriesByDBusName.hasOwnProperty(dbusName) ? this._entriesByDBusName[dbusName] : null;
++    }
++
++    lookupById(appId) {
++        let ret = [];
++        for (let dbusName in this._entriesByDBusName) {
++            let entry = this._entriesByDBusName[dbusName];
++            if (entry && entry.appId() == appId) {
++                ret.push(entry);
++            }
++        }
++
++        return ret;
++    }
++
++    addEntry(entry) {
++        let existingEntry = this.lookupByDBusName(entry.dbusName());
++        if (existingEntry) {
++            existingEntry.update(entry);
++        } else {
++            this._entriesByDBusName[entry.dbusName()] = entry;
++            this.emit('entry-added', entry);
++        }
++    }
++
++    removeEntry(entry) {
++        delete this._entriesByDBusName[entry.dbusName()]
++        this.emit('entry-removed', entry);
++    }
++
++    _acquireUnityDBus() {
++        if (!this._unity_bus_id) {
++            Gio.DBus.session.own_name('com.canonical.Unity',
++                Gio.BusNameOwnerFlags.ALLOW_REPLACEMENT, null, null);
++        }
++    }
++
++    _releaseUnityDBus() {
++        if (this._unity_bus_id) {
++            Gio.DBus.session.unown_name(this._unity_bus_id);
++            this._unity_bus_id = 0;
++        }
++    }
++
++    _onEntrySignalReceived(connection, sender_name, object_path,
++        interface_name, signal_name, parameters, user_data) {
++        if (!parameters || !signal_name)
++            return;
++
++        if (signal_name == 'Update') {
++            if (!sender_name) {
++                return;
++            }
++
++            this._handleUpdateRequest(sender_name, parameters);
++        }
++    }
++
++    _onDBusNameOwnerChanged(connection, sender_name, object_path,
++        interface_name, signal_name, parameters, user_data) {
++        if (!parameters || !this.size())
++            return;
++
++        let [name, before, after] = parameters.deep_unpack();
++
++        if (!after) {
++            if (this._entriesByDBusName.hasOwnProperty(before)) {
++                this.removeEntry(this._entriesByDBusName[before]);
++            }
++        }
++    }
++
++    _handleUpdateRequest(senderName, parameters) {
++        if (!senderName || !parameters) {
++            return;
++        }
++
++        let [appUri, properties] = parameters.deep_unpack();
++        let appId = appUri.replace(/(^\w+:|^)\/\//, '');
++        let entry = this.lookupByDBusName(senderName);
++
++        if (entry) {
++            entry.setDBusName(senderName);
++            entry.update(properties);
++        } else {
++            let entry = new LauncherEntryRemote(senderName, appId, properties);
++            this.addEntry(entry);
++        }
++    }
++};
++Signals.addSignalMethods(LauncherEntryRemoteModel.prototype);
++
++var LauncherEntryRemote = class DashToDock_LauncherEntryRemote {
++
++    constructor(dbusName, appId, properties) {
++        this._dbusName = dbusName;
++        this._appId = appId;
++        this._count = 0;
++        this._countVisible = false;
++        this._progress = 0.0;
++        this._progressVisible = false;
++        this.update(properties);
++    }
++
++    appId() {
++        return this._appId;
++    }
++
++    dbusName() {
++        return this._dbusName;
++    }
++
++    count() {
++        return this._count;
++    }
++
++    setCount(count) {
++        if (this._count != count) {
++            this._count = count;
++            this.emit('count-changed', this._count);
++        }
++    }
++
++    countVisible() {
++        return this._countVisible;
++    }
++
++    setCountVisible(countVisible) {
++        if (this._countVisible != countVisible) {
++            this._countVisible = countVisible;
++            this.emit('count-visible-changed', this._countVisible);
++        }
++    }
++
++    progress() {
++        return this._progress;
++    }
++
++    setProgress(progress) {
++        if (this._progress != progress) {
++            this._progress = progress;
++            this.emit('progress-changed', this._progress);
++        }
++    }
++
++    progressVisible() {
++        return this._progressVisible;
++    }
++
++    setProgressVisible(progressVisible) {
++        if (this._progressVisible != progressVisible) {
++            this._progressVisible = progressVisible;
++            this.emit('progress-visible-changed', this._progressVisible);
++        }
++    }
++
++    setDBusName(dbusName) {
++        if (this._dbusName != dbusName) {
++            let oldName = this._dbusName;
++            this._dbusName = dbusName;
++            this.emit('dbus-name-changed', oldName);
++        }
++    }
++
++    update(other) {
++        if (other instanceof LauncherEntryRemote) {
++            this.setDBusName(other.dbusName())
++            this.setCount(other.count());
++            this.setCountVisible(other.countVisible());
++            this.setProgress(other.progress());
++            this.setProgressVisible(other.progressVisible())
++        } else {
++            for (let property in other) {
++                if (other.hasOwnProperty(property)) {
++                    if (property == 'count') {
++                        this.setCount(other[property].get_int64());
++                    } else if (property == 'count-visible') {
++                        this.setCountVisible(other[property].get_boolean());
++                    } if (property == 'progress') {
++                        this.setProgress(other[property].get_double());
++                    } else if (property == 'progress-visible') {
++                        this.setProgressVisible(other[property].get_boolean());
++                    } else {
++                        // Not implemented yet
++                    }
++                }
++            }
++        }
++    }
++};
++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
+index 0000000..55b71ba
+--- /dev/null
++++ b/extensions/dash-to-dock/media/glossy.svg
+@@ -0,0 +1,139 @@
++<?xml version="1.0" encoding="UTF-8" standalone="no"?>
++<!-- Created with Inkscape (http://www.inkscape.org/) -->
++
++<svg
++   xmlns:dc="http://purl.org/dc/elements/1.1/"
++   xmlns:cc="http://creativecommons.org/ns#"
++   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++   xmlns:svg="http://www.w3.org/2000/svg"
++   xmlns="http://www.w3.org/2000/svg"
++   xmlns:xlink="http://www.w3.org/1999/xlink"
++   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
++   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
++   width="18.343554mm"
++   height="18.343554mm"
++   viewBox="0 0 14.674843 14.674842"
++   version="1.1"
++   id="svg4941"
++   sodipodi:docname="glossy.svg"
++   inkscape:version="0.92.1 r15371">
++  <defs
++     id="defs4935">
++    <linearGradient
++       id="linearGradient6812"
++       inkscape:collect="always">
++      <stop
++         style="stop-color:#ffffff;stop-opacity:0;"
++         offset="0"
++         id="stop6810" />
++      <stop
++         style="stop-color:#ffffff;stop-opacity:1;"
++         offset="1"
++         id="stop6808" />
++    </linearGradient>
++    <linearGradient
++       inkscape:collect="always"
++       xlink:href="#linearGradient18962"
++       id="linearGradient35463"
++       gradientUnits="userSpaceOnUse"
++       gradientTransform="matrix(0.29132751,0,0,0.15428114,-54.210829,160.22776)"
++       x1="214.71877"
++       y1="404.36081"
++       x2="214.71877"
++       y2="443.54596" />
++    <linearGradient
++       inkscape:collect="always"
++       id="linearGradient18962">
++      <stop
++         style="stop-color:#ffffff;stop-opacity:1;"
++         offset="0"
++         id="stop18964" />
++      <stop
++         style="stop-color:#ffffff;stop-opacity:0;"
++         offset="1"
++         id="stop18966" />
++    </linearGradient>
++    <linearGradient
++       id="linearGradient18806">
++      <stop
++         style="stop-color:#ff0101;stop-opacity:1;"
++         offset="0"
++         id="stop18808" />
++      <stop
++         style="stop-color:#800000;stop-opacity:1;"
++         offset="1"
++         id="stop18810" />
++    </linearGradient>
++    <radialGradient
++       inkscape:collect="always"
++       xlink:href="#linearGradient6812"
++       id="radialGradient6798"
++       cx="7.3538475"
++       cy="230.28426"
++       fx="7.3538475"
++       fy="230.28426"
++       r="7.2099228"
++       gradientTransform="matrix(5.9484829,-0.0346444,0.01679088,3.0681664,-40.338609,-476.01412)"
++       gradientUnits="userSpaceOnUse" />
++  </defs>
++  <sodipodi:namedview
++     id="base"
++     pagecolor="#ffffff"
++     bordercolor="#666666"
++     borderopacity="1.0"
++     inkscape:pageopacity="0.0"
++     inkscape:pageshadow="2"
++     inkscape:zoom="10.68"
++     inkscape:cx="65.485107"
++     inkscape:cy="29.432163"
++     inkscape:document-units="mm"
++     inkscape:current-layer="layer1"
++     showgrid="false"
++     inkscape:window-width="2560"
++     inkscape:window-height="1406"
++     inkscape:window-x="1920"
++     inkscape:window-y="0"
++     inkscape:window-maximized="1"
++     scale-x="0.8"
++     fit-margin-top="0"
++     fit-margin-left="0"
++     fit-margin-right="0"
++     fit-margin-bottom="0" />
++  <metadata
++     id="metadata4938">
++    <rdf:RDF>
++      <cc:Work
++         rdf:about="">
++        <dc:format>image/svg+xml</dc:format>
++        <dc:type
++           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
++        <dc:title></dc:title>
++      </cc:Work>
++    </rdf:RDF>
++  </metadata>
++  <g
++     inkscape:label="Layer 1"
++     inkscape:groupmode="layer"
++     id="layer1"
++     transform="translate(0,-222.92515)">
++    <rect
++       inkscape:export-ydpi="180"
++       inkscape:export-xdpi="180"
++       inkscape:export-filename="C:\Arbeit\Blog\Tutorials\glossybutton\Glossy_Button_Tutorial.png"
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.35100002;fill:url(#linearGradient35463);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.39747861;marker:none;enable-background:accumulate"
++       id="rect19155"
++       width="14.634871"
++       height="3.7392156"
++       x="0.039808333"
++       y="222.98268"
++       rx="1.5496143"
++       ry="0.82064426" />
++    <rect
++       style="opacity:0.427;fill:url(#radialGradient6798);fill-opacity:1;stroke:#ffffff;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
++       id="rect6706"
++       width="14.363673"
++       height="14.404656"
++       x="0.090466507"
++       y="223.07919" />
++  </g>
++</svg>
+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 @@
++<?xml version="1.0" encoding="UTF-8" standalone="no"?>
++<svg
++   xmlns:dc="http://purl.org/dc/elements/1.1/"
++   xmlns:cc="http://creativecommons.org/ns#"
++   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++   xmlns:svg="http://www.w3.org/2000/svg"
++   xmlns="http://www.w3.org/2000/svg"
++   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
++   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
++   viewBox="-0.7 0 48 48"
++   version="1.1"
++   id="svg10"
++   sodipodi:docname="highlight_stacked_bg.svg"
++   width="48"
++   height="48"
++   inkscape:version="0.92.1 r15371">
++  <metadata
++     id="metadata16">
++    <rdf:RDF>
++      <cc:Work
++         rdf:about="">
++        <dc:format>image/svg+xml</dc:format>
++        <dc:type
++           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
++        <dc:title />
++      </cc:Work>
++    </rdf:RDF>
++  </metadata>
++  <defs
++     id="defs14" />
++  <sodipodi:namedview
++     pagecolor="#ffffff"
++     bordercolor="#666666"
++     borderopacity="1"
++     objecttolerance="10"
++     gridtolerance="10"
++     guidetolerance="10"
++     inkscape:pageopacity="0"
++     inkscape:pageshadow="2"
++     inkscape:window-width="1920"
++     inkscape:window-height="951"
++     id="namedview12"
++     showgrid="false"
++     viewbox-x="-0.7"
++     fit-margin-top="0"
++     fit-margin-left="0"
++     fit-margin-right="0"
++     fit-margin-bottom="0"
++     inkscape:zoom="3.8125"
++     inkscape:cx="-63.872219"
++     inkscape:cy="15.195756"
++     inkscape:window-x="0"
++     inkscape:window-y="27"
++     inkscape:window-maximized="1"
++     inkscape:current-layer="svg10" />
++  <g
++     id="g8"
++     transform="matrix(1,0,0,48,-0.7,0)"
++     style="opacity:0.25;fill:#eeeeee;stroke-width:0.14433756">
++    <rect
++       width="45"
++       height="1"
++       id="rect2"
++       x="0"
++       y="0"
++       style="stroke-width:0.14433756" />
++    <rect
++       x="45"
++       width="1"
++       height="1"
++       id="rect4"
++       y="0"
++       style="opacity:0.2;stroke-width:0.02083333" />
++    <rect
++       x="46"
++       width="2"
++       height="1"
++       id="rect6"
++       y="0"
++       style="opacity:0.6;stroke-width:0.02083333" />
++  </g>
++</svg>
+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 @@
++<?xml version="1.0" encoding="UTF-8" standalone="no"?>
++<svg
++   xmlns:dc="http://purl.org/dc/elements/1.1/"
++   xmlns:cc="http://creativecommons.org/ns#"
++   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++   xmlns:svg="http://www.w3.org/2000/svg"
++   xmlns="http://www.w3.org/2000/svg"
++   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
++   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
++   viewBox="-0.7 0 48 48"
++   version="1.1"
++   id="svg10"
++   sodipodi:docname="highlight_stacked_bg_h.svg"
++   width="48"
++   height="48"
++   inkscape:version="0.92.1 r15371">
++  <metadata
++     id="metadata16">
++    <rdf:RDF>
++      <cc:Work
++         rdf:about="">
++        <dc:format>image/svg+xml</dc:format>
++        <dc:type
++           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
++        <dc:title />
++      </cc:Work>
++    </rdf:RDF>
++  </metadata>
++  <defs
++     id="defs14" />
++  <sodipodi:namedview
++     pagecolor="#ffffff"
++     bordercolor="#666666"
++     borderopacity="1"
++     objecttolerance="10"
++     gridtolerance="10"
++     guidetolerance="10"
++     inkscape:pageopacity="0"
++     inkscape:pageshadow="2"
++     inkscape:window-width="1853"
++     inkscape:window-height="1016"
++     id="namedview12"
++     showgrid="false"
++     viewbox-x="-0.7"
++     fit-margin-top="0"
++     fit-margin-left="0"
++     fit-margin-right="0"
++     fit-margin-bottom="0"
++     inkscape:zoom="3.8125"
++     inkscape:cx="-63.872219"
++     inkscape:cy="15.195756"
++     inkscape:window-x="67"
++     inkscape:window-y="27"
++     inkscape:window-maximized="1"
++     inkscape:current-layer="svg10" />
++  <g
++     id="g8"
++     transform="matrix(0,-1,-48,0,47.3,48)"
++     style="opacity:0.25;fill:#eeeeee;stroke-width:0.14433756">
++    <rect
++       width="45"
++       height="1"
++       id="rect2"
++       x="0"
++       y="0"
++       style="stroke-width:0.14433756" />
++    <rect
++       x="45"
++       width="1"
++       height="1"
++       id="rect4"
++       y="0"
++       style="opacity:0.2;stroke-width:0.02083333" />
++    <rect
++       x="46"
++       width="2"
++       height="1"
++       id="rect6"
++       y="0"
++       style="opacity:0.6;stroke-width:0.02083333" />
++  </g>
++</svg>
+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
+--- /dev/null
++++ b/extensions/dash-to-dock/media/logo.svg
+@@ -0,0 +1,528 @@
++<?xml version="1.0" encoding="UTF-8" standalone="no"?>
++<!-- Created with Inkscape (http://www.inkscape.org/) -->
++
++<svg
++   xmlns:dc="http://purl.org/dc/elements/1.1/"
++   xmlns:cc="http://creativecommons.org/ns#"
++   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
++   xmlns:svg="http://www.w3.org/2000/svg"
++   xmlns="http://www.w3.org/2000/svg"
++   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
++   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
++   width="33.866665mm"
++   height="33.866684mm"
++   viewBox="0 0 33.866665 33.866683"
++   id="svg5179"
++   version="1.1"
++   inkscape:version="0.91 r13725"
++   sodipodi:docname="logo.svg">
++  <defs
++     id="defs5181">
++    <clipPath
++       clipPathUnits="userSpaceOnUse"
++       id="clipPath4379-92-4-9-6-8-0">
++      <rect
++         style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.83189655;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++         id="rect4381-17-7-5-2-0-6"
++         width="19.934219"
++         height="33.52573"
++         x="356.02826"
++         y="457.71631" />
++    </clipPath>
++    <filter
++       style="color-interpolation-filters:sRGB"
++       inkscape:collect="always"
++       id="filter4435-8-5-3-2-13-8"
++       x="-0.22881356"
++       width="1.4576271"
++       y="-0.22881356"
++       height="1.4576271">
++      <feGaussianBlur
++         inkscape:collect="always"
++         stdDeviation="1.0352993"
++         id="feGaussianBlur4437-6-7-9-8-8-1" />
++    </filter>
++    <filter
++       style="color-interpolation-filters:sRGB"
++       inkscape:collect="always"
++       id="filter4365-71-5-7-0-6-2"
++       x="-0.21864407"
++       width="1.437288"
++       y="-0.21864407"
++       height="1.437288">
++      <feGaussianBlur
++         inkscape:collect="always"
++         stdDeviation="0.98928601"
++         id="feGaussianBlur4367-74-5-92-0-6-5" />
++    </filter>
++    <clipPath
++       clipPathUnits="userSpaceOnUse"
++       id="clipPath4379-6-7-5-8-6-01-2">
++      <rect
++         style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.83189655;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++         id="rect4381-1-8-5-2-0-2-7"
++         width="19.934219"
++         height="33.52573"
++         x="356.02826"
++         y="457.71631" />
++    </clipPath>
++    <filter
++       style="color-interpolation-filters:sRGB"
++       inkscape:collect="always"
++       id="filter4435-6-1-2-8-2-2-7"
++       x="-0.22881356"
++       width="1.4576271"
++       y="-0.22881356"
++       height="1.4576271">
++      <feGaussianBlur
++         inkscape:collect="always"
++         stdDeviation="1.0352993"
++         id="feGaussianBlur4437-1-1-3-60-1-4-4" />
++    </filter>
++    <filter
++       style="color-interpolation-filters:sRGB"
++       inkscape:collect="always"
++       id="filter4365-4-5-2-24-7-3-3"
++       x="-0.21864407"
++       width="1.437288"
++       y="-0.21864407"
++       height="1.437288">
++      <feGaussianBlur
++         inkscape:collect="always"
++         stdDeviation="0.98928601"
++         id="feGaussianBlur4367-7-0-7-7-9-0-3" />
++    </filter>
++    <clipPath
++       clipPathUnits="userSpaceOnUse"
++       id="clipPath4379-5-6-0-9-8-7-9">
++      <rect
++         style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.83189655;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++         id="rect4381-6-8-5-9-9-2-4"
++         width="19.934219"
++         height="33.52573"
++         x="356.02826"
++         y="457.71631" />
++    </clipPath>
++    <filter
++       style="color-interpolation-filters:sRGB"
++       inkscape:collect="always"
++       id="filter4435-63-9-2-4-1-2-6"
++       x="-0.22881356"
++       width="1.4576271"
++       y="-0.22881356"
++       height="1.4576271">
++      <feGaussianBlur
++         inkscape:collect="always"
++         stdDeviation="1.0352993"
++         id="feGaussianBlur4437-0-5-6-8-8-9-9" />
++    </filter>
++    <filter
++       style="color-interpolation-filters:sRGB"
++       inkscape:collect="always"
++       id="filter4365-2-4-3-6-3-1-7"
++       x="-0.21864407"
++       width="1.437288"
++       y="-0.21864407"
++       height="1.437288">
++      <feGaussianBlur
++         inkscape:collect="always"
++         stdDeviation="0.98928601"
++         id="feGaussianBlur4367-1-2-5-3-5-8-3" />
++    </filter>
++    <filter
++       inkscape:collect="always"
++       style="color-interpolation-filters:sRGB"
++       id="filter4255"
++       x="-0.20374454"
++       width="1.4074891"
++       y="-0.13779147"
++       height="1.2755829">
++      <feGaussianBlur
++         inkscape:collect="always"
++         stdDeviation="0.25863247"
++         id="feGaussianBlur4257" />
++    </filter>
++  </defs>
++  <sodipodi:namedview
++     id="base"
++     pagecolor="#ffffff"
++     bordercolor="#666666"
++     borderopacity="1.0"
++     inkscape:pageopacity="0.0"
++     inkscape:pageshadow="2"
++     inkscape:zoom="8"
++     inkscape:cx="60.090739"
++     inkscape:cy="60.108985"
++     inkscape:document-units="mm"
++     inkscape:current-layer="layer1"
++     showgrid="false"
++     fit-margin-top="0"
++     fit-margin-left="0"
++     fit-margin-right="0"
++     fit-margin-bottom="0"
++     inkscape:window-width="1861"
++     inkscape:window-height="1023"
++     inkscape:window-x="0"
++     inkscape:window-y="27"
++     inkscape:window-maximized="1" />
++  <metadata
++     id="metadata5184">
++    <rdf:RDF>
++      <cc:Work
++         rdf:about="">
++        <dc:format>image/svg+xml</dc:format>
++        <dc:type
++           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
++        <dc:title />
++      </cc:Work>
++    </rdf:RDF>
++  </metadata>
++  <g
++     inkscape:label="Layer 1"
++     inkscape:groupmode="layer"
++     id="layer1"
++     transform="translate(136.97858,-11.552354)">
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#0055d4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++       id="rect4006-4-6-9-2-0-6"
++       width="33.83363"
++       height="33.859909"
++       x="-136.9473"
++       y="11.552354"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <path
++       inkscape:connector-curvature="0"
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.15440008;marker:none;filter:url(#filter4365-3);enable-background:accumulate"
++       d="m -130.12265,11.559157 c -4.30029,5.691881 -6.67207,12.608761 -6.82289,19.674442 -0.0115,0.54232 -0.0147,1.0766 0,1.62024 0.11433,4.23572 1.04846,8.50668 2.82497,12.565201 l 31.00865,0 0,-33.859883 -27.01073,0 z"
++       id="path6097-2-6-0-89-4"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <path
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
++       d="m -136.9473,18.430158 0,0.7896 0,20.641361 0,0.7896 1.23782,0 2.26288,0 1.60528,0 c 0.68577,0 1.23783,-0.3548 1.23783,-0.7896 l 0,-20.641361 c 0,-0.4398 -0.55206,-0.7896 -1.23783,-0.7896 l -1.60528,0 -2.26288,0 z"
++       id="rect4008-7-9-2-0-3-4"
++       inkscape:connector-curvature="0"
++       sodipodi:nodetypes="ccccccssssccc"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <path
++       inkscape:connector-curvature="0"
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.15;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.15440008;marker:none;filter:url(#filter4365-3);enable-background:accumulate"
++       d="m -119.36792,11.559157 c -10.47023,5.721881 -17.57762,16.847401 -17.57762,29.627402 0,1.43804 0.0897,2.841801 0.26432,4.232481 l 33.5693,0 0,-33.859883 -16.256,0 z"
++       id="path6097-4-5-23-9"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++       id="rect4247-4-4-5-3-8-1"
++       width="33.83363"
++       height="2.1162443"
++       x="-136.9473"
++       y="11.552354"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <path
++       inkscape:connector-curvature="0"
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++       d="m -103.11365,13.668597 0,1.05812 c 0,-0.58196 -0.47338,-1.05812 -1.05731,-1.05812 l 1.05731,0 z"
++       id="rect4272-0-7-8-1-1-3-3-1"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++       id="rect4031-9-9-2-4-2-5"
++       width="4.2292037"
++       height="4.2324886"
++       x="-135.89"
++       y="19.488146"
++       rx="1.0583334"
++       ry="1.0583334"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <path
++       inkscape:connector-curvature="0"
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++       d="m -136.94728,13.668597 0,1.05812 c 0,-0.58196 0.47337,-1.05812 1.0573,-1.05812 l -1.0573,0 z"
++       id="rect4272-0-2-1-74-41-1-6"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <g
++       id="g4353-9-2-1-5-5-4"
++       transform="matrix(0.10331261,0,0,0.10339285,-173.76079,-27.453246)"
++       clip-path="url(#clipPath4379-92-4-9-6-8-0)"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099">
++      <circle
++         r="5.4295697"
++         cy="477.71164"
++         cx="274.13016"
++         transform="matrix(0.94749688,0,0,0.94749688,96.290796,21.848877)"
++         id="path3153-1-7-3-5-60-3-6"
++         style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.42241378;fill:#d7eef4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;filter:url(#filter4435-8-5-3-2-13-8);enable-background:accumulate" />
++      <circle
++         r="5.4295697"
++         cy="477.71164"
++         cx="274.13016"
++         transform="matrix(0.24231546,0,0,0.24231546,289.60229,358.72226)"
++         id="path3153-2-4-1-6-6-9-4-1"
++         style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#d7eef4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;filter:url(#filter4365-71-5-7-0-6-2);enable-background:accumulate" />
++    </g>
++    <g
++       id="g4589-4-1-1-3-6-2"
++       transform="matrix(0.49926208,0,0,0.49964988,-318.21072,-206.05794)"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099">
++      <g
++         clip-path="url(#clipPath4379-6-7-5-8-6-01-2)"
++         transform="matrix(0.20693061,0,0,0.20693061,289.32686,368.5622)"
++         id="g4353-66-1-4-2-6-94-5">
++        <circle
++           r="5.4295697"
++           cy="477.71164"
++           cx="274.13016"
++           style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.42241378;fill:#d7eef4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;filter:url(#filter4435-6-1-2-8-2-2-7);enable-background:accumulate"
++           id="path3153-1-6-4-5-63-7-1-0"
++           transform="matrix(0.94749688,0,0,0.94749688,96.290796,21.848877)" />
++        <circle
++           r="5.4295697"
++           cy="477.71164"
++           cx="274.13016"
++           style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#d7eef4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;filter:url(#filter4365-4-5-2-24-7-3-3);enable-background:accumulate"
++           id="path3153-2-4-7-6-5-8-5-9-5"
++           transform="matrix(0.24231546,0,0,0.24231546,289.60229,358.72226)" />
++      </g>
++      <g
++         clip-path="url(#clipPath4379-5-6-0-9-8-7-9)"
++         transform="matrix(0.20693061,0,0,0.20693061,289.32686,367.53449)"
++         id="g4353-7-2-2-6-4-5-1">
++        <circle
++           r="5.4295697"
++           cy="477.71164"
++           cx="274.13016"
++           style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.42241378;fill:#d7eef4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;filter:url(#filter4435-63-9-2-4-1-2-6);enable-background:accumulate"
++           id="path3153-1-19-3-1-5-5-7-8"
++           transform="matrix(0.94749688,0,0,0.94749688,96.290796,21.848877)" />
++        <circle
++           r="5.4295697"
++           cy="477.71164"
++           cx="274.13016"
++           style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#d7eef4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;filter:url(#filter4365-2-4-3-6-3-1-7);enable-background:accumulate"
++           id="path3153-2-4-5-7-9-9-9-7-6"
++           transform="matrix(0.24231546,0,0,0.24231546,289.60229,358.72226)" />
++      </g>
++    </g>
++    <text
++       xml:space="preserve"
++       style="font-style:normal;font-weight:normal;font-size:1.28805089px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none"
++       x="-124.44726"
++       y="13.10139"
++       id="text4824-5-2-0-4-8"
++       sodipodi:linespacing="125%"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099"
++       transform="scale(0.99961185,1.0003883)"><tspan
++         sodipodi:role="line"
++         id="tspan4826-16-3-8-8-1"
++         x="-124.44726"
++         y="13.10139">Dash to Dock</tspan></text>
++    <text
++       xml:space="preserve"
++       style="font-style:normal;font-weight:normal;font-size:1.28805089px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none"
++       x="-136.50272"
++       y="13.10139"
++       id="text4824-8-8-6-8-7-4"
++       sodipodi:linespacing="125%"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099"
++       transform="scale(0.99961185,1.0003883)"><tspan
++         sodipodi:role="line"
++         id="tspan4826-1-7-7-5-07-5"
++         x="-136.50272"
++         y="13.10139">Michele</tspan></text>
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++       id="rect4031-9-0-8-5-4-0-7-6"
++       width="4.2292037"
++       height="4.2324886"
++       x="-135.89"
++       y="24.778917"
++       rx="1.0583334"
++       ry="1.0583334"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++       id="rect4031-9-0-7-3-3-6-0-1"
++       width="4.2292037"
++       height="4.2324886"
++       x="-135.89"
++       y="30.069445"
++       rx="1.0583334"
++       ry="1.0583334"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.04922473;marker:none;enable-background:accumulate"
++       id="rect4031-9-0-6-5-1-3-9-0"
++       width="4.2292037"
++       height="4.2324886"
++       x="-135.89"
++       y="35.359974"
++       rx="1.0583334"
++       ry="1.0583334"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <path
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.5;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
++       d="m -136.9473,17.901078 0,0.52908 2.42849,0 2.21372,0 c 0.94338,0 1.7016,0.3372 1.7016,0.77704 l 0,20.649921 c 0,0.43476 -0.75822,0.7936 -1.7016,0.7936 l -2.21372,0 -2.42849,0 0,0.52904 0.90862,0 2.64325,0 1.88332,0 c 0.80005,0 1.43727,-0.3712 1.43727,-0.82664 l 0,-21.625361 c 0,-0.46072 -0.63722,-0.82668 -1.43727,-0.82668 l -1.88332,0 -2.64325,0 z"
++       id="rect4008-7-0-0-3-3-3-7-9"
++       inkscape:connector-curvature="0"
++       sodipodi:nodetypes="cccsssscccccssssccc"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <path
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:accumulate"
++       d="m -136.9473,17.901078 0,0.52908 2.42849,0 2.21372,0 c 0.94338,0 1.7016,0.3372 1.7016,0.77704 l 0,20.649921 c 0,0.43476 -0.75822,0.7936 -1.7016,0.7936 l -2.21372,0 -2.42849,0 0,0.52904 0.90862,0 2.64325,0 1.88332,0 c 0.80005,0 1.43727,-0.3712 1.43727,-0.82664 l 0,-21.625361 c 0,-0.46072 -0.63722,-0.82668 -1.43727,-0.82668 l -1.88332,0 -2.64325,0 z"
++       id="rect4008-7-0-0-3-1-5-0-5-5"
++       inkscape:connector-curvature="0"
++       sodipodi:nodetypes="cccsssscccccssssccc"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="44.99099"
++       inkscape:export-ydpi="44.99099" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#f2f2f2;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;filter:url(#filter4365-3);enable-background:accumulate"
++       id="rect6777-7-9-6-9-8"
++       width="20.108335"
++       height="18.256252"
++       x="-125.24149"
++       y="19.139757"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="45"
++       inkscape:export-ydpi="45" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.13229166;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
++       id="rect4923-8-7-8-2"
++       width="3.7041669"
++       height="3.7041669"
++       x="-116.71888"
++       y="30.163927"
++       rx="1.0583334"
++       ry="1.0583334" />
++    <path
++       inkscape:connector-curvature="0"
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.15;fill:#b3b3b3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;filter:url(#filter4365-3);enable-background:accumulate"
++       d="m -111.94623,19.146638 c -5.49508,1.3884 -10.21465,5.00036 -13.29531,9.92188 l 0,8.334361 20.10833,0 0,-18.256241 -6.81302,0 z"
++       id="path6862-84-2-2-6-7"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="45"
++       inkscape:export-ydpi="45" />
++    <path
++       inkscape:connector-curvature="0"
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;filter:url(#filter4365-3);enable-background:accumulate"
++       d="m -125.02657,18.882038 c -0.11728,0 -0.21496,0.0812 -0.21496,0.1984 l 0,0.44648 0,1.2568 0,0.2148 0.21496,0 19.67838,0 0.215,0 0,-0.2148 0,-1.2568 0,-0.44648 c 0,-0.1172 -0.0977,-0.1984 -0.215,-0.1984 l -19.67838,0 z"
++       id="rect6779-5-8-6-4-6"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="45"
++       inkscape:export-ydpi="45" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#999999;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;filter:url(#filter4365-3);enable-background:accumulate"
++       id="rect6779-2-3-9-9-0-8"
++       width="20.108335"
++       height="0.5291667"
++       x="-125.24149"
++       y="20.991808"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="45"
++       inkscape:export-ydpi="45" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#b3b3b3;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;filter:url(#filter4365-3);enable-background:accumulate"
++       id="rect6779-2-4-8-0-7-1-1"
++       width="15.875001"
++       height="0.5291667"
++       x="21.521105"
++       y="105.13315"
++       transform="rotate(90)"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="45"
++       inkscape:export-ydpi="45" />
++    <g
++       id="g6839-1-5-1-33-0"
++       transform="matrix(0.02002288,0.02002284,-0.02002288,0.02002284,-106.62848,-6.0229242)"
++       style="fill:#1a1a1a"
++       inkscape:export-filename="/home/michele/Dropbox/lavori/gnome-shell-extension/icon/g5218.png"
++       inkscape:export-xdpi="45"
++       inkscape:export-ydpi="45">
++      <rect
++         y="616.07727"
++         x="653.01312"
++         height="41.542522"
++         width="11.313708"
++         id="rect6819-8-9-2-56-9"
++         style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;filter:url(#filter4365-3);enable-background:accumulate" />
++      <rect
++         transform="rotate(90)"
++         y="-679.44122"
++         x="631.19165"
++         height="41.542522"
++         width="11.313708"
++         id="rect6819-3-9-4-3-1-5"
++         style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.5;marker:none;filter:url(#filter4365-3);enable-background:accumulate" />
++    </g>
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.13229166;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
++       id="rect4923-6-8-9-1"
++       width="3.7041669"
++       height="3.7041669"
++       x="-123.59805"
++       y="30.163927"
++       rx="1.0583334"
++       ry="1.0583334" />
++    <path
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.26458335;stroke-miterlimit:4;stroke-dasharray:none;marker:none;enable-background:accumulate;opacity:0.866;filter:url(#filter4255)"
++       d="m -121.46776,32.043964 -5e-4,1.742839 -4.9e-4,1.742839 0.71518,-0.708051 0.99716,1.727136 1.33421,-0.770304 -0.99542,-1.724104 0.96903,-0.268366 -1.50959,-0.870995 z"
++       id="path6155-6-0-01-4-5-6-0-0"
++       inkscape:connector-curvature="0"
++       sodipodi:nodetypes="cccccccccc" />
++    <path
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.13229167;stroke-miterlimit:4;stroke-dasharray:none;marker:none;filter:url(#filter4365-3);enable-background:accumulate"
++       d="m -121.86464,32.043964 -5e-4,1.742839 -4.9e-4,1.742839 0.71518,-0.708051 1.05563,1.8284 1.3342,-0.770304 -1.05388,-1.825368 0.96903,-0.268366 -1.50959,-0.870995 z"
++       id="path6155-6-0-8-0-7-97-5"
++       inkscape:connector-curvature="0"
++       sodipodi:nodetypes="cccccccccc" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.13229166;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
++       id="rect4923-4-8-4"
++       width="3.7041669"
++       height="3.7041669"
++       x="-123.59805"
++       y="23.020128"
++       rx="1.0583334"
++       ry="1.0583334" />
++    <rect
++       style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.25;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:0.13229166;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
++       id="rect4923-2-6-7-8"
++       width="3.7041669"
++       height="3.7041669"
++       x="-116.71888"
++       y="23.020128"
++       rx="1.0583334"
++       ry="1.0583334" />
++  </g>
++</svg>
+diff --git a/extensions/dash-to-dock/meson.build b/extensions/dash-to-dock/meson.build
+new file mode 100644
+index 0000000..290374f
+--- /dev/null
++++ b/extensions/dash-to-dock/meson.build
+@@ -0,0 +1,23 @@
++extension_data += configure_file(
++  input: metadata_name + '.in',
++  output: metadata_name,
++  configuration: metadata_conf
++)
++
++extension_sources += files(
++  'appIconIndicators.js',
++  'appIcons.js',
++  'dash.js',
++  'docking.js',
++  'extension.js',
++  'intellihide.js',
++  'launcherAPI.js',
++  'prefs.js',
++  'Settings.ui',
++  'theming.js',
++  'utils.js',
++  'windowPreview.js'
++)
++extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
++
++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..641a935
+--- /dev/null
++++ b/extensions/dash-to-dock/metadata.json.in
+@@ -0,0 +1,12 @@
++{
++"extension-id": "@extension_id@",
++"uuid": "@uuid@",
++"settings-schema": "@gschemaname@",
++"gettext-domain": "@gettext_domain@",
++"original-author": "micxgx@gmail.com",
++"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": 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..9cf371b
+--- /dev/null
++++ b/extensions/dash-to-dock/org.gnome.shell.extensions.dash-to-dock.gschema.xml
+@@ -0,0 +1,540 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<schemalist gettext-domain="gnome-shell-extensions">
++  <enum id='org.gnome.shell.extensions.dash-to-dock.clickAction'>
++    <value value='0' nick='skip'/>
++    <value value='1' nick='minimize'/>
++    <value value='2' nick='launch'/>
++    <value value='3' nick='cycle-windows'/>
++    <value value='4' nick='minimize-or-overview'/>
++    <value value='5' nick='previews'/>
++    <value value='6' nick='minimize-or-previews'/>
++    <value value='7' nick='focus-or-previews'/>
++    <value value='8' nick='quit'/>
++  </enum>
++  <enum id='org.gnome.shell.extensions.dash-to-dock.scrollAction'>
++    <value value='0' nick='do-nothing'/>
++    <value value='1' nick='cycle-windows'/>
++    <value value='2' nick='switch-workspace'/>
++  </enum>
++  <!-- this is mean to Match StSide. LEFT and RIGHT actual position in reversed in
++       rtl languages -->
++  <enum id='org.gnome.shell.extensions.dash-to-dock.position'>
++    <value value='0' nick='TOP'/>
++    <value value='1' nick='RIGHT'/>
++    <value value='2' nick='BOTTOM'/>
++    <value value='3' nick='LEFT'/>
++  </enum>
++  <enum id='org.gnome.shell.extensions.dash-to-dock.intellihide-mode'>
++    <value value='0' nick='ALL_WINDOWS'/>
++    <value value='1' nick='FOCUS_APPLICATION_WINDOWS'/>
++    <value value='2' nick='MAXIMIZED_WINDOWS'/>
++  </enum>
++  <enum id='org.gnome.shell.extensions.dash-to-dock.transparency-mode'>
++    <value value='0' nick='DEFAULT'/>
++    <value value='1' nick='FIXED'/>
++    <value value='3' nick='DYNAMIC'/>
++  </enum>
++    <enum id='org.gnome.shell.extensions.dash-to-dock.running-indicator-style'>
++    <value value='0' nick='DEFAULT'/>
++    <value value='1' nick='DOTS'/>
++    <value value='2' nick='SQUARES'/>
++    <value value='3' nick='DASHES'/>
++    <value value='4' nick='SEGMENTED'/>
++    <value value='5' nick='SOLID'/>
++    <value value='6' nick='CILIORA'/>
++    <value value='7' nick='METRO'/>
++  </enum>
++  <schema path="/org/gnome/shell/extensions/dash-to-dock/" id="org.gnome.shell.extensions.dash-to-dock">
++    <key name="dock-position" enum="org.gnome.shell.extensions.dash-to-dock.position">
++      <default>'LEFT'</default>
++      <summary>Dock position</summary>
++      <description>Dock is shown on the Left, Right, Top or Bottom side of the screen.</description>
++    </key>
++    <key type="d" name="animation-time">
++      <default>0.2</default>
++      <summary>Animation time</summary>
++      <description>Sets the time duration of the autohide effect.</description>
++    </key>
++    <key type="d" name="show-delay">
++      <default>0.25</default>
++      <summary>Show delay</summary>
++      <description>Sets the delay after the mouse reaches the screen border before showing the dock.</description>
++    </key>
++    <key type="d" name="hide-delay">
++      <default>0.20</default>
++      <summary>Show delay</summary>
++      <description>Sets the delay after the mouse left the dock before hiding it.</description>
++    </key>
++    <key type="b" name="custom-background-color">
++      <default>false</default>
++      <summary>Set a custom dash background background color</summary>
++      <description>Sets the color for the dash background.</description>
++    </key>
++    <key type="s" name="background-color">
++      <default>"#ffffff"</default>
++      <summary>Dash background color.</summary>
++      <description>Customize the background color of the dash.</description>
++    </key>
++    <key name="transparency-mode" enum="org.gnome.shell.extensions.dash-to-dock.transparency-mode">
++      <default>'DEFAULT'</default>
++      <summary>Transparency mode for the dock</summary>
++      <description>FIXED: constant transparency. DYNAMIC: dock takes the opaque style only when windows are close to it.</description>
++    </key>
++    <key name="running-indicator-style" enum="org.gnome.shell.extensions.dash-to-dock.running-indicator-style">
++      <default>'DEFAULT'</default>
++      <summary>...</summary>
++      <description>DEFAULT: .... DOTS: ....</description>
++    </key>
++    <key type="b" name="running-indicator-dominant-color">
++      <default>false</default>
++      <summary>Use application icon dominant color for the indicator color</summary>
++      <description></description>
++    </key>
++    <key type="b" name="customize-alphas">
++      <default>false</default>
++      <summary>Manually set the min and max opacity</summary>
++      <description>For the dynamic mode, the min/max opacity values will be given by 'min-alpha' and 'max-alpha'.</description>
++    </key>
++    <key type="d" name="min-alpha">
++      <default>0.2</default>
++      <summary>Opacity of the dash background when free-floating</summary>
++      <description>Sets the opacity of the dash background when no windows are close.</description>
++    </key>
++    <key type="d" name="max-alpha">
++      <default>0.8</default>
++      <summary>Opacity of the dash background when windows are close.</summary>
++      <description>Sets the opacity of the dash background when windows are close.</description>
++    </key>
++    <key type="d" name="background-opacity">
++      <default>0.8</default>
++      <summary>Opacity of the dash background</summary>
++      <description>Sets the opacity of the dash background  when in autohide mode.</description>
++    </key>
++    <key type="b" name="intellihide">
++      <default>true</default>
++      <summary>Dock dodges windows</summary>
++      <description>Enable or disable intellihide mode</description>
++    </key>
++    <key name="intellihide-mode" enum="org.gnome.shell.extensions.dash-to-dock.intellihide-mode">
++      <default>'FOCUS_APPLICATION_WINDOWS'</default>
++      <summary>Define which windows are considered for intellihide.</summary>
++      <description></description>
++    </key>
++    <key type="b" name="autohide">
++      <default>true</default>
++      <summary>Dock shown on mouse over</summary>
++      <description>Enable or disable autohide mode</description>
++    </key>
++    <key type="b" name="require-pressure-to-show">
++      <default>true</default>
++      <summary>Require pressure to show dash</summary>
++      <description>Enable or disable requiring pressure to show the dash</description>
++    </key>
++    <key type="d" name="pressure-threshold">
++      <default>100</default>
++      <summary>Pressure threshold</summary>
++      <description>Sets how much pressure is needed to show the dash.</description>
++    </key>
++    <key type="b" name="autohide-in-fullscreen">
++      <default>false</default>
++      <summary>Enable autohide in fullscreen mode.</summary>
++      <description>Enable autohide in fullscreen mode.</description>
++    </key>
++    <key type="b" name="dock-fixed">
++      <default>false</default>
++      <summary>Dock always visible</summary>
++      <description>Dock is always visible</description>
++    </key>
++    <key type="b" name="scroll-switch-workspace">
++      <default>true</default>
++      <summary>Switch workspace by scrolling over the dock</summary>
++      <description>Add the possibility to switch workspace by mouse scrolling over the dock.</description>
++    </key>
++    <key type="i" name="dash-max-icon-size">
++      <default>48</default>
++      <summary>Maximum dash icon size</summary>
++      <description>Set the allowed maximum dash icon size. Allowed range: 16..64.</description>
++    </key>
++    <key type="b" name="icon-size-fixed">
++      <default>false</default>
++      <summary>Fixed icon size</summary>
++      <description>Keep the icon size fived by scrolling the dock.</description>
++    </key>
++    <key type="b" name="apply-custom-theme">
++      <default>false</default>
++      <summary>Apply custom theme</summary>
++      <description>Apply customization to the dash appearance</description>
++    </key>
++    <key type="b" name="custom-theme-shrink">
++      <default>false</default>
++      <summary>TODO</summary>
++      <description>TODO</description>
++    </key>
++    <key type="b" name="custom-theme-customize-running-dots">
++      <default>false</default>
++      <summary>Customize the style of the running application indicators.</summary>
++      <description>Customize the style of the running application indicators.</description>
++    </key>
++    <key type="s" name="custom-theme-running-dots-color">
++      <default>"#ffffff"</default>
++      <summary>Running application indicators color</summary>
++      <description>Customize the color of the running application indicators.</description>
++    </key>
++    <key type="s" name="custom-theme-running-dots-border-color">
++      <default>"#ffffff"</default>
++      <summary>Running application indicators border color.</summary>
++      <description>Customize the border color of the running application indicators.</description>
++    </key>
++    <key type="i" name="custom-theme-running-dots-border-width">
++      <default>0</default>
++      <summary>Running application indicators border width.</summary>
++      <description>Customize the border width of the running application indicators.</description>
++    </key>
++    <key type="b" name="show-running">
++      <default>true</default>
++      <summary>Show running apps</summary>
++      <description>Show or hide running appplications icons in the dash</description>
++    </key>
++    <key type="b" name="isolate-workspaces">
++      <default>false</default>
++      <summary>Provide workspace isolation</summary>
++      <description>Dash shows only windows from the currentworkspace</description>
++    </key>
++    <key type="b" name="isolate-monitors">
++      <default>false</default>
++      <summary>Provide monitor isolation</summary>
++      <description>Dash shows only windows from the monitor</description>
++    </key>
++    <key type="b" name="show-windows-preview">
++      <default>true</default>
++      <summary>Show preview of the open windows</summary>
++      <description>Replace open windows list with windows previews</description>
++    </key>
++    <key type="b" name="show-favorites">
++      <default>true</default>
++      <summary>Show favorites apps</summary>
++      <description>Show or hide favorite appplications icons in the dash</description>
++    </key>
++    <key type="b" name="show-show-apps-button">
++      <default>true</default>
++      <summary>Show applications button</summary>
++      <description>Show appplications button in the dash</description>
++    </key>
++    <key type="b" name="show-apps-at-top">
++      <default>false</default>
++      <summary>Show application button at top</summary>
++      <description>Show appplication button at top of the dash</description>
++    </key>
++    <key type="b" name="animate-show-apps">
++      <default>true</default>
++      <summary>Animate Show Applications from the desktop</summary>
++      <description>Animate Show Applications from the desktop</description>
++    </key>
++    <key type="b" name="bolt-support">
++      <default>true</default>
++      <summary>Basic compatibility with bolt extensions</summary>
++      <description>Make the extension work properly when bolt extensions is enabled</description>
++    </key>
++    <key type="d" name="height-fraction">
++      <default>0.90</default>
++      <summary>Dock max height (fraction of available space)</summary>
++    </key>
++    <key type="b" name="extend-height">
++      <default>false</default>
++      <summary>Extend the dock container to all the available height</summary>
++    </key>
++    <key type="i" name="preferred-monitor">
++      <default>-1</default>
++      <summary>Monitor on which putting the dock</summary>
++      <description>Set on which monitor to put the dock, use -1 for the primary one</description>
++    </key>
++    <key type="b" name="multi-monitor">
++      <default>false</default>
++      <summary>Enable multi-monitor docks</summary>
++      <description>Show a dock on every monitor</description>
++    </key>
++    <key type="b" name="minimize-shift">
++      <default>true</default>
++      <summary>Minimize on shift+click</summary>
++    </key>
++    <key type="b" name="activate-single-window">
++      <default>true</default>
++      <summary>Activate only one window</summary>
++    </key>
++    <key name="click-action" enum="org.gnome.shell.extensions.dash-to-dock.clickAction">
++      <default>'cycle-windows'</default>
++      <summary>Action when clicking on a running app</summary>
++      <description>Set the action that is executed when clicking on the icon of a running application</description>
++    </key>
++    <key name="scroll-action" enum="org.gnome.shell.extensions.dash-to-dock.scrollAction">
++      <default>'do-nothing'</default>
++      <summary>Action when scrolling app</summary>
++      <description>Set the action that is executed when scrolling on the application icon</description>
++    </key>
++    <key name="shift-click-action" enum="org.gnome.shell.extensions.dash-to-dock.clickAction">
++      <default>'minimize'</default>
++      <summary>Action when shift+clicking on a running app</summary>
++      <description>Set the action that is executed when shift+clicking on the icon of a running application</description>
++    </key>
++    <key name="middle-click-action" enum="org.gnome.shell.extensions.dash-to-dock.clickAction">
++      <default>'launch'</default>
++      <summary>Action when clicking on a running app</summary>
++      <description>Set the action that is executed when middle-clicking on the icon of a running application</description>
++    </key>
++    <key name="shift-middle-click-action" enum="org.gnome.shell.extensions.dash-to-dock.clickAction">
++      <default>'launch'</default>
++      <summary>Action when clicking on a running app</summary>
++      <description>Set the action that is executed when shift+middle-clicking on the icon of a running application</description>
++    </key>
++    <key type="b" name="hot-keys">
++      <default>true</default>
++      <summary>Super Hot-Keys</summary>
++      <description>Launch and switch between dash items using Super+(0-9)</description>
++    </key>
++    <key type="b" name="hotkeys-show-dock">
++      <default>true</default>
++      <summary>Show the dock when using the hotkeys</summary>
++      <description>The dock will be quickly shown so that the number-overlay is visible and app activation is easier</description>
++    </key>
++    <key type="s" name="shortcut-text">
++      <default>"&lt;Super&gt;q"</default>
++      <summary>Keybinding to show the dock and the number overlay.</summary>
++      <description>Behavior depends on hotkeys-show-dock and hotkeys-overlay.</description>
++    </key>
++    <key type="as" name="shortcut">
++      <default><![CDATA[['<Super>q']]]></default>
++      <summary>Keybinding to show the dock and the number overlay.</summary>
++      <description>Behavior depends on hotkeys-show-dock and hotkeys-overlay.</description>
++    </key>
++    <key type="d" name="shortcut-timeout">
++      <default>2</default>
++      <summary>Timeout to hide the dock</summary>
++      <description>Sets the time duration before the dock is hidden again.</description>
++    </key>
++    <key type="b" name="hotkeys-overlay">
++      <default>true</default>
++      <summary>Show the dock when using the hotkeys</summary>
++      <description>The dock will be quickly shown so that the number-overlay is visible and app activation is easier</description>
++    </key>
++    <key name="app-ctrl-hotkey-1" type="as">
++      <default><![CDATA[['<Ctrl><Super>1']]]></default>
++      <summary>Keybinding to launch 1st dash app</summary>
++      <description>
++        Keybinding to launch 1st app.
++      </description>
++    </key>
++    <key name="app-ctrl-hotkey-2" type="as">
++      <default><![CDATA[['<Ctrl><Super>2']]]></default>
++      <summary>Keybinding to launch 2nd dash app</summary>
++      <description>
++        Keybinding to launch 2nd app.
++      </description>
++    </key>
++    <key name="app-ctrl-hotkey-3" type="as">
++      <default><![CDATA[['<Ctrl><Super>3']]]></default>
++      <summary>Keybinding to launch 3rd dash app</summary>
++      <description>
++        Keybinding to launch 3rd app.
++      </description>
++    </key>
++    <key name="app-ctrl-hotkey-4" type="as">
++      <default><![CDATA[['<Ctrl><Super>4']]]></default>
++      <summary>Keybinding to launch 4th dash app</summary>
++      <description>
++        Keybinding to launch 4th app.
++      </description>
++    </key>
++    <key name="app-ctrl-hotkey-5" type="as">
++      <default><![CDATA[['<Ctrl><Super>5']]]></default>
++      <summary>Keybinding to launch 5th dash app</summary>
++      <description>
++        Keybinding to launch 5th app.
++      </description>
++    </key>
++    <key name="app-ctrl-hotkey-6" type="as">
++      <default><![CDATA[['<Ctrl><Super>6']]]></default>
++      <summary>Keybinding to launch 6th dash app</summary>
++      <description>
++        Keybinding to launch 6th app.
++      </description>
++    </key>
++    <key name="app-ctrl-hotkey-7" type="as">
++      <default><![CDATA[['<Ctrl><Super>7']]]></default>
++      <summary>Keybinding to launch 7th dash app</summary>
++      <description>
++        Keybinding to launch 7th app.
++      </description>
++    </key>
++    <key name="app-ctrl-hotkey-8" type="as">
++      <default><![CDATA[['<Ctrl><Super>8']]]></default>
++      <summary>Keybinding to launch 8th dash app</summary>
++      <description>
++        Keybinding to launch 8th app.
++      </description>
++    </key>
++    <key name="app-ctrl-hotkey-9" type="as">
++      <default><![CDATA[['<Ctrl><Super>9']]]></default>
++      <summary>Keybinding to launch 9th dash app</summary>
++      <description>
++        Keybinding to launch 9th app.
++      </description>
++    </key>
++    <key name="app-ctrl-hotkey-10" type="as">
++      <default><![CDATA[['<Ctrl><Super>0']]]></default>
++      <summary>Keybinding to launch 10th dash app</summary>
++      <description>
++        Keybinding to launch 10th app.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-1" type="as">
++      <default><![CDATA[['<Shift><Super>1']]]></default>
++      <summary>Keybinding to trigger 1st dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 1st app with shift behavior.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-2" type="as">
++      <default><![CDATA[['<Shift><Super>2']]]></default>
++      <summary>Keybinding to trigger 2nd dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 2nd app with shift behavior.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-3" type="as">
++      <default><![CDATA[['<Shift><Super>3']]]></default>
++      <summary>Keybinding to trigger 3rd dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 3rd app with shift behavior.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-4" type="as">
++      <default><![CDATA[['<Shift><Super>4']]]></default>
++      <summary>Keybinding to trigger 4th dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 4th app with shift behavior.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-5" type="as">
++      <default><![CDATA[['<Shift><Super>5']]]></default>
++      <summary>Keybinding to trigger 5th dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 5th app with shift behavior.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-6" type="as">
++      <default><![CDATA[['<Shift><Super>6']]]></default>
++      <summary>Keybinding to trigger 6th dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 6th app with shift behavior.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-7" type="as">
++      <default><![CDATA[['<Shift><Super>7']]]></default>
++      <summary>Keybinding to trigger 7th dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 7th app with shift behavior.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-8" type="as">
++      <default><![CDATA[['<Shift><Super>8']]]></default>
++      <summary>Keybinding to trigger 8th dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 8th app with shift behavior.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-9" type="as">
++      <default><![CDATA[['<Shift><Super>9']]]></default>
++      <summary>Keybinding to trigger 9th dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 9th app with shift behavior.
++      </description>
++    </key>
++    <key name="app-shift-hotkey-10" type="as">
++      <default><![CDATA[['<Shift><Super>0']]]></default>
++      <summary>Keybinding to trigger 10th dash app with shift behavior</summary>
++      <description>
++        Keybinding to trigger 10th app with shift behavior.
++      </description>
++    </key>
++    <key name="app-hotkey-1" type="as">
++      <default><![CDATA[['<Super>1']]]></default>
++      <summary>Keybinding to trigger 1st dash app</summary>
++      <description>
++        Keybinding to either show or launch the 1st application in the dash.
++      </description>
++    </key>
++    <key name="app-hotkey-2" type="as">
++      <default><![CDATA[['<Super>2']]]></default>
++      <summary>Keybinding to trigger 2nd dash app</summary>
++      <description>
++        Keybinding to either show or launch the 2nd application in the dash.
++      </description>
++    </key>
++    <key name="app-hotkey-3" type="as">
++      <default><![CDATA[['<Super>3']]]></default>
++      <summary>Keybinding to trigger 3rd dash app</summary>
++      <description>
++        Keybinding to either show or launch the 3rd application in the dash.
++      </description>
++    </key>
++    <key name="app-hotkey-4" type="as">
++      <default><![CDATA[['<Super>4']]]></default>
++      <summary>Keybinding to trigger 4th dash app</summary>
++      <description>
++        Keybinding to either show or launch the 4th application in the dash.
++      </description>
++    </key>
++    <key name="app-hotkey-5" type="as">
++      <default><![CDATA[['<Super>5']]]></default>
++      <summary>Keybinding to trigger 5th dash app</summary>
++      <description>
++        Keybinding to either show or launch the 5th application in the dash.
++      </description>
++    </key>
++    <key name="app-hotkey-6" type="as">
++      <default><![CDATA[['<Super>6']]]></default>
++      <summary>Keybinding to trigger 6th dash app</summary>
++      <description>
++        Keybinding to either show or launch the 6th application in the dash.
++      </description>
++    </key>
++    <key name="app-hotkey-7" type="as">
++      <default><![CDATA[['<Super>7']]]></default>
++      <summary>Keybinding to trigger 7th dash app</summary>
++      <description>
++        Keybinding to either show or launch the 7th application in the dash.
++      </description>
++    </key>
++    <key name="app-hotkey-8" type="as">
++      <default><![CDATA[['<Super>8']]]></default>
++      <summary>Keybinding to trigger 8th dash app</summary>
++      <description>
++        Keybinding to either show or launch the 8th application in the dash.
++      </description>
++    </key>
++    <key name="app-hotkey-9" type="as">
++      <default><![CDATA[['<Super>9']]]></default>
++      <summary>Keybinding to trigger 9th dash app</summary>
++      <description>
++        Keybinding to either show or launch the 9th application in the dash.
++      </description>
++    </key>
++    <key name="app-hotkey-10" type="as">
++      <default><![CDATA[['<Super>0']]]></default>
++      <summary>Keybinding to trigger 10th dash app</summary>
++      <description>
++        Keybinding to either show or launch the 10th application in the dash.
++      </description>
++    </key>
++    <key name="force-straight-corner" type="b">
++      <default>false</default>
++      <summary>Force straight corners in dash</summary>
++      <description>Make the borders in the dash non rounded</description>
++    </key>
++    <key name="unity-backlit-items" type="b">
++      <default>false</default>
++      <summary>Enable unity7 like glossy backlit items</summary>
++      <description>Emulate the unity7 backlit glossy items behaviour</description>
++    </key>
++  </schema>
++</schemalist>
+diff --git a/extensions/dash-to-dock/prefs.js b/extensions/dash-to-dock/prefs.js
+new file mode 100644
+index 0000000..a72b139
+--- /dev/null
++++ b/extensions/dash-to-dock/prefs.js
+@@ -0,0 +1,861 @@
++// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
++
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++const GObject = imports.gi.GObject;
++const Gtk = imports.gi.Gtk;
++const Gdk = imports.gi.Gdk;
++const Mainloop = imports.mainloop;
++
++// Use __ () and N__() for the extension gettext domain, and reuse
++// the shell domain with the default _() and N_()
++const Gettext = imports.gettext.domain('dashtodock');
++const __ = Gettext.gettext;
++const N__ = function(e) { return e };
++
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++
++const SCALE_UPDATE_TIMEOUT = 500;
++const DEFAULT_ICONS_SIZES = [ 128, 96, 64, 48, 32, 24, 16 ];
++
++const TransparencyMode = {
++    DEFAULT:  0,
++    FIXED:    1,
++    DYNAMIC:  3
++};
++
++const RunningIndicatorStyle = {
++    DEFAULT: 0,
++    DOTS: 1,
++    SQUARES: 2,
++    DASHES: 3,
++    SEGMENTED: 4,
++    SOLID: 5,
++    CILIORA: 6,
++    METRO: 7
++};
++
++/**
++ * This function was copied from the activities-config extension
++ * https://github.com/nls1729/acme-code/tree/master/activities-config
++ * by Norman L. Smith.
++ */
++function cssHexString(css) {
++    let rrggbb = '#';
++    let start;
++    for (let loop = 0; loop < 3; loop++) {
++        let end = 0;
++        let xx = '';
++        for (let loop = 0; loop < 2; loop++) {
++            while (true) {
++                let x = css.slice(end, end + 1);
++                if ((x == '(') || (x == ',') || (x == ')'))
++                    break;
++                end++;
++            }
++            if (loop == 0) {
++                end++;
++                start = end;
++            }
++        }
++        xx = parseInt(css.slice(start, end)).toString(16);
++        if (xx.length == 1)
++            xx = '0' + xx;
++        rrggbb += xx;
++        css = css.slice(end);
++    }
++    return rrggbb;
++}
++
++function setShortcut(settings) {
++    let shortcut_text = settings.get_string('shortcut-text');
++    let [key, mods] = Gtk.accelerator_parse(shortcut_text);
++
++    if (Gtk.accelerator_valid(key, mods)) {
++        let shortcut = Gtk.accelerator_name(key, mods);
++        settings.set_strv('shortcut', [shortcut]);
++    }
++    else {
++        settings.set_strv('shortcut', []);
++    }
++}
++
++var Settings = class DashToDock_Settings {
++
++    constructor() {
++        this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.dash-to-dock');
++
++        this._rtl = (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL);
++
++        this._builder = new Gtk.Builder();
++        this._builder.set_translation_domain(Me.metadata['gettext-domain']);
++        this._builder.add_from_file(Me.path + '/Settings.ui');
++
++        this.widget = new Gtk.ScrolledWindow({ hscrollbar_policy: Gtk.PolicyType.NEVER });
++        this._notebook = this._builder.get_object('settings_notebook');
++        this.widget.add(this._notebook);
++
++        // Set a reasonable initial window height
++        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;
++        this._icon_size_timeout = 0;
++        this._opacity_timeout = 0;
++
++        this._bindSettings();
++
++        this._builder.connect_signals_full(this._connector.bind(this));
++    }
++
++    /**
++     * Connect signals
++     */
++    _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() {
++        // Position and size panel
++
++        // Monitor options
++
++        this._monitors = [];
++        // Build options based on the number of monitors and the current settings.
++        let n_monitors = Gdk.Screen.get_default().get_n_monitors();
++        let primary_monitor = Gdk.Screen.get_default().get_primary_monitor();
++
++        let monitor = this._settings.get_int('preferred-monitor');
++
++        // Add primary monitor with index 0, because in GNOME Shell the primary monitor is always 0
++        this._builder.get_object('dock_monitor_combo').append_text(__('Primary monitor'));
++        this._monitors.push(0);
++
++        // Add connected monitors
++        let ctr = 0;
++        for (let i = 0; i < n_monitors; i++) {
++            if (i !== primary_monitor) {
++                ctr++;
++                this._monitors.push(ctr);
++                this._builder.get_object('dock_monitor_combo').append_text(__('Secondary monitor ') + ctr);
++            }
++        }
++
++        // If one of the external monitor is set as preferred, show it even if not attached
++        if ((monitor >= n_monitors) && (monitor !== primary_monitor)) {
++            this._monitors.push(monitor)
++            this._builder.get_object('dock_monitor_combo').append_text(__('Secondary monitor ') + ++ctr);
++        }
++
++        this._builder.get_object('dock_monitor_combo').set_active(this._monitors.indexOf(monitor));
++
++        // Position option
++        let position = this._settings.get_enum('dock-position');
++
++        switch (position) {
++            case 0:
++                this._builder.get_object('position_top_button').set_active(true);
++                break;
++            case 1:
++                this._builder.get_object('position_right_button').set_active(true);
++                break;
++            case 2:
++                this._builder.get_object('position_bottom_button').set_active(true);
++                break;
++            case 3:
++                this._builder.get_object('position_left_button').set_active(true);
++                break;
++        }
++
++        if (this._rtl) {
++            /* Left is Right in rtl as a setting */
++            this._builder.get_object('position_left_button').set_label(__('Right'));
++            this._builder.get_object('position_right_button').set_label(__('Left'));
++        }
++
++        // Intelligent autohide options
++        this._settings.bind('dock-fixed',
++                            this._builder.get_object('intelligent_autohide_switch'),
++                            'active',
++                            Gio.SettingsBindFlags.INVERT_BOOLEAN);
++        this._settings.bind('dock-fixed',
++                            this._builder.get_object('intelligent_autohide_button'),
++                            'sensitive',
++                            Gio.SettingsBindFlags.INVERT_BOOLEAN);
++        this._settings.bind('autohide',
++                            this._builder.get_object('autohide_switch'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('autohide-in-fullscreen',
++                            this._builder.get_object('autohide_enable_in_fullscreen_checkbutton'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('require-pressure-to-show',
++                            this._builder.get_object('require_pressure_checkbutton'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('intellihide',
++                            this._builder.get_object('intellihide_switch'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('animation-time',
++                            this._builder.get_object('animation_duration_spinbutton'),
++                            'value',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('hide-delay',
++                            this._builder.get_object('hide_timeout_spinbutton'),
++                            'value',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('show-delay',
++                            this._builder.get_object('show_timeout_spinbutton'),
++                            'value',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('pressure-threshold',
++                            this._builder.get_object('pressure_threshold_spinbutton'),
++                            'value',
++                            Gio.SettingsBindFlags.DEFAULT);
++
++        //this._builder.get_object('animation_duration_spinbutton').set_value(this._settings.get_double('animation-time'));
++
++        // Create dialog for intelligent autohide advanced settings
++        this._builder.get_object('intelligent_autohide_button').connect('clicked', () => {
++
++            let dialog = new Gtk.Dialog({ title: __('Intelligent autohide customization'),
++                                          transient_for: this.widget.get_toplevel(),
++                                          use_header_bar: true,
++                                          modal: true });
++
++            // GTK+ leaves positive values for application-defined response ids.
++            // Use +1 for the reset action
++            dialog.add_button(__('Reset to defaults'), 1);
++
++            let box = this._builder.get_object('intelligent_autohide_advanced_settings_box');
++            dialog.get_content_area().add(box);
++
++            this._settings.bind('intellihide',
++                            this._builder.get_object('intellihide_mode_box'),
++                            'sensitive',
++                            Gio.SettingsBindFlags.GET);
++
++            // intellihide mode
++
++            let intellihideModeRadioButtons = [
++                this._builder.get_object('all_windows_radio_button'),
++                this._builder.get_object('focus_application_windows_radio_button'),
++                this._builder.get_object('maximized_windows_radio_button')
++            ];
++
++            intellihideModeRadioButtons[this._settings.get_enum('intellihide-mode')].set_active(true);
++
++            this._settings.bind('autohide',
++                            this._builder.get_object('require_pressure_checkbutton'),
++                            'sensitive',
++                            Gio.SettingsBindFlags.GET);
++
++            this._settings.bind('autohide',
++                            this._builder.get_object('autohide_enable_in_fullscreen_checkbutton'),
++                            'sensitive',
++                            Gio.SettingsBindFlags.GET);
++
++            this._settings.bind('require-pressure-to-show',
++                                this._builder.get_object('show_timeout_spinbutton'),
++                                'sensitive',
++                                Gio.SettingsBindFlags.INVERT_BOOLEAN);
++            this._settings.bind('require-pressure-to-show',
++                                this._builder.get_object('show_timeout_label'),
++                                'sensitive',
++                                Gio.SettingsBindFlags.INVERT_BOOLEAN);
++            this._settings.bind('require-pressure-to-show',
++                                this._builder.get_object('pressure_threshold_spinbutton'),
++                                'sensitive',
++                                Gio.SettingsBindFlags.DEFAULT);
++            this._settings.bind('require-pressure-to-show',
++                                this._builder.get_object('pressure_threshold_label'),
++                                'sensitive',
++                                Gio.SettingsBindFlags.DEFAULT);
++
++            dialog.connect('response', (dialog, id) => {
++                if (id == 1) {
++                    // restore default settings for the relevant keys
++                    let keys = ['intellihide', 'autohide', 'intellihide-mode', 'autohide-in-fullscreen', 'require-pressure-to-show',
++                                'animation-time', 'show-delay', 'hide-delay', 'pressure-threshold'];
++                    keys.forEach(function(val) {
++                        this._settings.set_value(val, this._settings.get_default_value(val));
++                    }, this);
++                    intellihideModeRadioButtons[this._settings.get_enum('intellihide-mode')].set_active(true);
++                } else {
++                    // remove the settings box so it doesn't get destroyed;
++                    dialog.get_content_area().remove(box);
++                    dialog.destroy();
++                }
++                return;
++            });
++
++            dialog.show_all();
++
++        });
++
++        // size options
++        this._builder.get_object('dock_size_scale').set_value(this._settings.get_double('height-fraction'));
++        this._builder.get_object('dock_size_scale').add_mark(0.9, Gtk.PositionType.TOP, null);
++        let icon_size_scale = this._builder.get_object('icon_size_scale');
++        icon_size_scale.set_range(8, DEFAULT_ICONS_SIZES[0]);
++        icon_size_scale.set_value(this._settings.get_int('dash-max-icon-size'));
++        DEFAULT_ICONS_SIZES.forEach(function(val) {
++             icon_size_scale.add_mark(val, Gtk.PositionType.TOP, val.toString());
++        });
++
++        // Corrent for rtl languages
++        if (this._rtl) {
++            // Flip value position: this is not done automatically
++            this._builder.get_object('dock_size_scale').set_value_pos(Gtk.PositionType.LEFT);
++            icon_size_scale.set_value_pos(Gtk.PositionType.LEFT);
++            // I suppose due to a bug, having a more than one mark and one above a value of 100
++            // makes the rendering of the marks wrong in rtl. This doesn't happen setting the scale as not flippable
++            // and then manually inverting it
++            icon_size_scale.set_flippable(false);
++            icon_size_scale.set_inverted(true);
++        }
++
++        this._settings.bind('icon-size-fixed', this._builder.get_object('icon_size_fixed_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('extend-height', this._builder.get_object('dock_size_extend_checkbutton'), 'active', Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('extend-height', this._builder.get_object('dock_size_scale'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN);
++
++
++        // Apps panel
++
++        this._settings.bind('show-running',
++                            this._builder.get_object('show_running_switch'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('isolate-workspaces',
++                            this._builder.get_object('application_button_isolation_button'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('isolate-monitors',
++                            this._builder.get_object('application_button_monitor_isolation_button'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('show-windows-preview',
++                            this._builder.get_object('windows_preview_button'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('multi-monitor',
++                            this._builder.get_object('multi_monitor_button'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('show-favorites',
++                            this._builder.get_object('show_favorite_switch'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('show-show-apps-button',
++                            this._builder.get_object('show_applications_button_switch'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('show-apps-at-top',
++                            this._builder.get_object('application_button_first_button'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('show-show-apps-button',
++                            this._builder.get_object('application_button_first_button'),
++                            'sensitive',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('animate-show-apps',
++                            this._builder.get_object('application_button_animation_button'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('show-show-apps-button',
++                            this._builder.get_object('application_button_animation_button'),
++                            'sensitive',
++                            Gio.SettingsBindFlags.DEFAULT);
++
++
++        // Behavior panel
++
++        this._settings.bind('hot-keys',
++                            this._builder.get_object('hot_keys_switch'),
++                            'active',
++                            Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('hot-keys',
++                            this._builder.get_object('overlay_button'),
++                            'sensitive',
++                            Gio.SettingsBindFlags.DEFAULT);
++
++        this._builder.get_object('click_action_combo').set_active(this._settings.get_enum('click-action'));
++        this._builder.get_object('click_action_combo').connect('changed', (widget) => {
++            this._settings.set_enum('click-action', widget.get_active());
++        });
++
++        this._builder.get_object('scroll_action_combo').set_active(this._settings.get_enum('scroll-action'));
++        this._builder.get_object('scroll_action_combo').connect('changed', (widget) => {
++            this._settings.set_enum('scroll-action', widget.get_active());
++        });
++
++        this._builder.get_object('shift_click_action_combo').connect('changed', (widget) => {
++            this._settings.set_enum('shift-click-action', widget.get_active());
++        });
++
++        this._builder.get_object('middle_click_action_combo').connect('changed', (widget) => {
++            this._settings.set_enum('middle-click-action', widget.get_active());
++        });
++        this._builder.get_object('shift_middle_click_action_combo').connect('changed', (widget) => {
++            this._settings.set_enum('shift-middle-click-action', widget.get_active());
++        });
++
++        // Create dialog for number overlay options
++        this._builder.get_object('overlay_button').connect('clicked', () => {
++
++            let dialog = new Gtk.Dialog({ title: __('Show dock and application numbers'),
++                                          transient_for: this.widget.get_toplevel(),
++                                          use_header_bar: true,
++                                          modal: true });
++
++            // GTK+ leaves positive values for application-defined response ids.
++            // Use +1 for the reset action
++            dialog.add_button(__('Reset to defaults'), 1);
++
++            let box = this._builder.get_object('box_overlay_shortcut');
++            dialog.get_content_area().add(box);
++
++            this._builder.get_object('overlay_switch').set_active(this._settings.get_boolean('hotkeys-overlay'));
++            this._builder.get_object('show_dock_switch').set_active(this._settings.get_boolean('hotkeys-show-dock'));
++
++            // We need to update the shortcut 'strv' when the text is modified
++            this._settings.connect('changed::shortcut-text', () => {setShortcut(this._settings);});
++            this._settings.bind('shortcut-text',
++                                this._builder.get_object('shortcut_entry'),
++                                'text',
++                                Gio.SettingsBindFlags.DEFAULT);
++
++            this._settings.bind('hotkeys-overlay',
++                                this._builder.get_object('overlay_switch'),
++                                'active',
++                                Gio.SettingsBindFlags.DEFAULT);
++            this._settings.bind('hotkeys-show-dock',
++                                this._builder.get_object('show_dock_switch'),
++                                'active',
++                                Gio.SettingsBindFlags.DEFAULT);
++            this._settings.bind('shortcut-timeout',
++                                this._builder.get_object('timeout_spinbutton'),
++                                'value',
++                                Gio.SettingsBindFlags.DEFAULT);
++
++            dialog.connect('response', (dialog, id) => {
++                if (id == 1) {
++                    // restore default settings for the relevant keys
++                    let keys = ['shortcut-text', 'hotkeys-overlay', 'hotkeys-show-dock', 'shortcut-timeout'];
++                    keys.forEach(function(val) {
++                        this._settings.set_value(val, this._settings.get_default_value(val));
++                    }, this);
++                } else {
++                    // remove the settings box so it doesn't get destroyed;
++                    dialog.get_content_area().remove(box);
++                    dialog.destroy();
++                }
++                return;
++            });
++
++            dialog.show_all();
++        });
++
++        // Create dialog for middle-click options
++        this._builder.get_object('middle_click_options_button').connect('clicked', () => {
++
++            let dialog = new Gtk.Dialog({ title: __('Customize middle-click behavior'),
++                                          transient_for: this.widget.get_toplevel(),
++                                          use_header_bar: true,
++                                          modal: true });
++
++            // GTK+ leaves positive values for application-defined response ids.
++            // Use +1 for the reset action
++            dialog.add_button(__('Reset to defaults'), 1);
++
++            let box = this._builder.get_object('box_middle_click_options');
++            dialog.get_content_area().add(box);
++
++            this._builder.get_object('shift_click_action_combo').set_active(this._settings.get_enum('shift-click-action'));
++
++            this._builder.get_object('middle_click_action_combo').set_active(this._settings.get_enum('middle-click-action'));
++
++            this._builder.get_object('shift_middle_click_action_combo').set_active(this._settings.get_enum('shift-middle-click-action'));
++
++            this._settings.bind('shift-click-action',
++                                this._builder.get_object('shift_click_action_combo'),
++                                'active-id',
++                                Gio.SettingsBindFlags.DEFAULT);
++            this._settings.bind('middle-click-action',
++                                this._builder.get_object('middle_click_action_combo'),
++                                'active-id',
++                                Gio.SettingsBindFlags.DEFAULT);
++            this._settings.bind('shift-middle-click-action',
++                                this._builder.get_object('shift_middle_click_action_combo'),
++                                'active-id',
++                                Gio.SettingsBindFlags.DEFAULT);
++
++            dialog.connect('response', (dialog, id) => {
++                if (id == 1) {
++                    // restore default settings for the relevant keys
++                    let keys = ['shift-click-action', 'middle-click-action', 'shift-middle-click-action'];
++                    keys.forEach(function(val) {
++                        this._settings.set_value(val, this._settings.get_default_value(val));
++                    }, this);
++                    this._builder.get_object('shift_click_action_combo').set_active(this._settings.get_enum('shift-click-action'));
++                    this._builder.get_object('middle_click_action_combo').set_active(this._settings.get_enum('middle-click-action'));
++                    this._builder.get_object('shift_middle_click_action_combo').set_active(this._settings.get_enum('shift-middle-click-action'));
++                } else {
++                    // remove the settings box so it doesn't get destroyed;
++                    dialog.get_content_area().remove(box);
++                    dialog.destroy();
++                }
++                return;
++            });
++
++            dialog.show_all();
++
++        });
++
++        // Appearance Panel
++
++        this._settings.bind('apply-custom-theme', this._builder.get_object('customize_theme'), 'sensitive', Gio.SettingsBindFlags.INVERT_BOOLEAN | Gio.SettingsBindFlags.GET);
++        this._settings.bind('apply-custom-theme', this._builder.get_object('builtin_theme_switch'), 'active', Gio.SettingsBindFlags.DEFAULT);
++        this._settings.bind('custom-theme-shrink', this._builder.get_object('shrink_dash_switch'), 'active', Gio.SettingsBindFlags.DEFAULT);
++
++        // Running indicators
++        this._builder.get_object('running_indicators_combo').set_active(
++            this._settings.get_enum('running-indicator-style')
++        );
++        this._builder.get_object('running_indicators_combo').connect(
++            'changed',
++            (widget) => {
++                this._settings.set_enum('running-indicator-style', widget.get_active());
++            }
++        );
++
++        if (this._settings.get_enum('running-indicator-style') == RunningIndicatorStyle.DEFAULT)
++            this._builder.get_object('running_indicators_advance_settings_button').set_sensitive(false);
++
++        this._settings.connect('changed::running-indicator-style', () => {
++           if (this._settings.get_enum('running-indicator-style') == RunningIndicatorStyle.DEFAULT)
++               this._builder.get_object('running_indicators_advance_settings_button').set_sensitive(false);
++           else
++               this._builder.get_object('running_indicators_advance_settings_button').set_sensitive(true);
++        });
++
++        // Create dialog for running indicators advanced settings
++        this._builder.get_object('running_indicators_advance_settings_button').connect('clicked', () => {
++
++            let dialog = new Gtk.Dialog({ title: __('Customize running indicators'),
++                                          transient_for: this.widget.get_toplevel(),
++                                          use_header_bar: true,
++                                          modal: true });
++
++            let box = this._builder.get_object('running_dots_advance_settings_box');
++            dialog.get_content_area().add(box);
++
++            this._settings.bind('running-indicator-dominant-color',
++                                this._builder.get_object('dominant_color_switch'),
++                                'active',
++                                Gio.SettingsBindFlags.DEFAULT);
++
++            this._settings.bind('custom-theme-customize-running-dots',
++                                this._builder.get_object('dot_style_switch'),
++                                'active',
++                                Gio.SettingsBindFlags.DEFAULT);
++            this._settings.bind('custom-theme-customize-running-dots',
++                                this._builder.get_object('dot_style_settings_box'),
++                                'sensitive', Gio.SettingsBindFlags.DEFAULT);
++
++            let rgba = new Gdk.RGBA();
++            rgba.parse(this._settings.get_string('custom-theme-running-dots-color'));
++            this._builder.get_object('dot_color_colorbutton').set_rgba(rgba);
++
++            this._builder.get_object('dot_color_colorbutton').connect('notify::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', (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'),
++                                'value',
++                                Gio.SettingsBindFlags.DEFAULT);
++
++
++            dialog.connect('response', (dialog, id) => {
++                // remove the settings box so it doesn't get destroyed;
++                dialog.get_content_area().remove(box);
++                dialog.destroy();
++                return;
++            });
++
++            dialog.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);
++
++        let rgba = new Gdk.RGBA();
++        rgba.parse(this._settings.get_string('background-color'));
++        this._builder.get_object('custom_background_color').set_rgba(rgba);
++
++        this._builder.get_object('custom_background_color').connect('notify::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(
++            this._settings.get_enum('transparency-mode')
++        );
++        this._builder.get_object('customize_opacity_combo').connect(
++            'changed',
++            (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'));
++
++        if (this._settings.get_enum('transparency-mode') !== TransparencyMode.FIXED)
++            this._builder.get_object('custom_opacity_scale').set_sensitive(false);
++
++        this._settings.connect('changed::transparency-mode', () => {
++           if (this._settings.get_enum('transparency-mode') !== TransparencyMode.FIXED)
++               this._builder.get_object('custom_opacity_scale').set_sensitive(false);
++           else
++               this._builder.get_object('custom_opacity_scale').set_sensitive(true);
++        });
++
++        if (this._settings.get_enum('transparency-mode') !== TransparencyMode.DYNAMIC) {
++            this._builder.get_object('dynamic_opacity_button').set_sensitive(false);
++        }
++
++        this._settings.connect('changed::transparency-mode', () => {
++            if (this._settings.get_enum('transparency-mode') !== TransparencyMode.DYNAMIC) {
++                this._builder.get_object('dynamic_opacity_button').set_sensitive(false);
++            }
++            else {
++                this._builder.get_object('dynamic_opacity_button').set_sensitive(true);
++            }
++        });
++
++        // Create dialog for transparency advanced settings
++        this._builder.get_object('dynamic_opacity_button').connect('clicked', () => {
++
++            let dialog = new Gtk.Dialog({ title: __('Cutomize opacity'),
++                                          transient_for: this.widget.get_toplevel(),
++                                          use_header_bar: true,
++                                          modal: true });
++
++            let box = this._builder.get_object('advanced_transparency_dialog');
++            dialog.get_content_area().add(box);
++
++            this._settings.bind(
++                'customize-alphas',
++                this._builder.get_object('customize_alphas_switch'),
++                'active',
++                Gio.SettingsBindFlags.DEFAULT
++            );
++            this._settings.bind(
++                'customize-alphas',
++                this._builder.get_object('min_alpha_scale'),
++                'sensitive',
++                Gio.SettingsBindFlags.DEFAULT
++            );
++            this._settings.bind(
++                'customize-alphas',
++                this._builder.get_object('max_alpha_scale'),
++                'sensitive',
++                Gio.SettingsBindFlags.DEFAULT
++            );
++
++            this._builder.get_object('min_alpha_scale').set_value(
++                this._settings.get_double('min-alpha')
++            );
++            this._builder.get_object('max_alpha_scale').set_value(
++                this._settings.get_double('max-alpha')
++            );
++
++            dialog.connect('response', (dialog, id) => {
++                // remove the settings box so it doesn't get destroyed;
++                dialog.get_content_area().remove(box);
++                dialog.destroy();
++                return;
++            });
++
++            dialog.show_all();
++        });
++
++
++        this._settings.bind('unity-backlit-items',
++            this._builder.get_object('unity_backlit_items_switch'),
++            'active', Gio.SettingsBindFlags.DEFAULT
++        );
++
++        this._settings.bind('force-straight-corner',
++            this._builder.get_object('force_straight_corner_switch'),
++            'active', Gio.SettingsBindFlags.DEFAULT);
++
++        // About Panel
++
++        this._builder.get_object('extension_version').set_label(Me.metadata.version.toString());
++    }
++};
++
++function init() {
++    ExtensionUtils.initTranslations();
++}
++
++function buildPrefsWidget() {
++    let settings = new Settings();
++    let widget = settings.widget;
++    widget.show_all();
++    return widget;
++}
+diff --git a/extensions/dash-to-dock/stylesheet.css b/extensions/dash-to-dock/stylesheet.css
+new file mode 100644
+index 0000000..26cc960
+--- /dev/null
++++ b/extensions/dash-to-dock/stylesheet.css
+@@ -0,0 +1,175 @@
++/* Shrink the dash by reducing padding and border radius */
++#dashtodockContainer.shrink #dash,
++#dashtodockContainer.dashtodock #dash {
++    border:1px;
++    padding:0px;
++}
++
++#dashtodockContainer.shrink.left #dash,
++#dashtodockContainer.dashtodock.left #dash {
++    border-left: 0px;
++    border-radius: 0px 9px 9px 0px;
++}
++
++
++#dashtodockContainer.shrink.right #dash,
++#dashtodockContainer.dashtodock.right #dash {
++    border-right: 0px;
++    border-radius: 9px 0px 0px 9px;
++}
++
++
++#dashtodockContainer.shrink.top #dash,
++#dashtodockContainer.dashtodock.top #dash {
++    border-top: 0px;
++    border-radius: 0px 0px 9px 9px;
++}
++
++#dashtodockContainer.shrink.bottom #dash,
++#dashtodockContainer.dashtodock.bottom #dash {
++    border-bottom: 0px;
++    border-radius: 9px 9px 0px 0px;
++}
++
++#dashtodockContainer.straight-corner #dash,
++#dashtodockContainer.shrink.straight-corner #dash {
++    border-radius: 0px;
++}
++
++/* Scrollview style */
++.bottom #dashtodockDashScrollview,
++.top #dashtodockDashScrollview {
++    -st-hfade-offset: 24px;
++}
++
++.left #dashtodockDashScrollview,
++.right #dashtodockDashScrollview {
++    -st-vfade-offset: 24px;
++}
++
++#dashtodockContainer.running-dots .dash-item-container > StButton,
++#dashtodockContainer.dashtodock .dash-item-container > StButton {
++    transition-duration: 250;
++    background-size: contain;
++}
++
++#dashtodockContainer.shrink .dash-item-container > StButton,
++#dashtodockContainer.dashtodock .dash-item-container > StButton {
++   padding: 1px 2px;
++}
++
++/* Dash height extended to the whole available vertical space */
++#dashtodockContainer.extended.top #dash,
++#dashtodockContainer.extended.right #dash,
++#dashtodockContainer.extended.bottom #dash,
++#dashtodockContainer.extended.left #dash {
++    border-radius: 0;
++}
++
++#dashtodockContainer.extended.top #dash,
++#dashtodockContainer.extended.bottom #dash {
++    border-left:0px;
++    border-right:0px;
++}
++
++#dashtodockContainer.extended.right #dash,
++#dashtodockContainer.extended.left #dash {
++    border-top:0px;
++    border-bottom:0px;
++}
++
++/* Running and focused application style */
++
++#dashtodockContainer.running-dots .app-well-app.running > .overview-icon,
++#dashtodockContainer.dashtodock .app-well-app.running > .overview-icon {
++	background-image:none;
++}
++
++
++#dashtodockContainer.running-dots .app-well-app.focused  .overview-icon,
++#dashtodockContainer.dashtodock .app-well-app.focused  .overview-icon {
++    background-color: rgba(238, 238, 236, 0.2);
++}
++
++#dashtodockContainer.dashtodock #dash {
++    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..596574d
+--- /dev/null
++++ b/extensions/dash-to-dock/theming.js
+@@ -0,0 +1,569 @@
++// -*- 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 Gtk = imports.gi.Gtk;
++const Signals = imports.signals;
++const Meta = imports.gi.Meta;
++const Shell = imports.gi.Shell;
++const St = imports.gi.St;
++const Mainloop = imports.mainloop;
++
++const AppDisplay = imports.ui.appDisplay;
++const AppFavorites = imports.ui.appFavorites;
++const Dash = imports.ui.dash;
++const DND = imports.ui.dnd;
++const IconGrid = imports.ui.iconGrid;
++const Main = imports.ui.main;
++const PopupMenu = imports.ui.popupMenu;
++const Tweener = imports.ui.tweener;
++const Util = imports.misc.util;
++const Workspace = imports.ui.workspace;
++
++const Me = imports.misc.extensionUtils.getCurrentExtension();
++const Dock = Me.imports.docking;
++const Utils = Me.imports.utils;
++
++/*
++ * DEFAULT:  transparency given by theme
++ * FIXED:    constant transparency chosen by user
++ * DYNAMIC:  apply 'transparent' style when no windows are close to the dock
++ * */
++const TransparencyMode = {
++    DEFAULT:  0,
++    FIXED:    1,
++    DYNAMIC:  3
++};
++
++/**
++ * Manage theme customization and custom theme support
++ */
++var ThemeManager = class DashToDock_ThemeManager {
++
++    constructor(settings, dock) {
++        this._settings = settings;
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++        this._bindSettingsChanges();
++        this._actor = dock.actor;
++        this._dash = dock.dash;
++
++        // initialize colors with generic values
++        this._customizedBackground = {red: 0, green: 0, blue: 0, alpha: 0};
++        this._customizedBorder = {red: 0, green: 0, blue: 0, alpha: 0};
++        this._transparency = new Transparency(this._settings, dock);
++
++        this._signalsHandler.add([
++            // When theme changes re-obtain default background color
++            St.ThemeContext.get_for_stage (global.stage),
++            'changed',
++            this.updateCustomTheme.bind(this)
++        ], [
++            // update :overview pseudoclass
++            Main.overview,
++            'showing',
++            this._onOverviewShowing.bind(this)
++        ], [
++            Main.overview,
++            'hiding',
++            this._onOverviewHiding.bind(this)
++        ]);
++
++        this._updateCustomStyleClasses();
++
++        // destroy themeManager when the managed actor is destroyed (e.g. extension unload)
++        // in order to disconnect signals
++        this._actor.connect('destroy', this.destroy.bind(this));
++
++    }
++
++    destroy() {
++        this._signalsHandler.destroy();
++        this._transparency.destroy();
++    }
++
++    _onOverviewShowing() {
++        this._actor.add_style_pseudo_class('overview');
++    }
++
++    _onOverviewHiding() {
++        this._actor.remove_style_pseudo_class('overview');
++    }
++
++    _updateDashOpacity() {
++        let newAlpha = this._settings.get_double('background-opacity');
++
++        let [backgroundColor, borderColor] = this._getDefaultColors();
++
++        if (backgroundColor==null)
++            return;
++
++        // Get the background and border alphas. We check the background alpha
++        // for a minimum of .001 to prevent division by 0 errors
++        let backgroundAlpha = Math.max(Math.round(backgroundColor.alpha/2.55)/100, .001);
++        let borderAlpha = Math.round(borderColor.alpha/2.55)/100;
++
++        // The border and background alphas should remain in sync
++        // We also limit the borderAlpha to a maximum of 1 (full opacity)
++        borderAlpha = Math.min((borderAlpha/backgroundAlpha)*newAlpha, 1);
++
++        this._customizedBackground = 'rgba(' +
++            backgroundColor.red + ',' +
++            backgroundColor.green + ',' +
++            backgroundColor.blue + ',' +
++            newAlpha + ')';
++
++        this._customizedBorder = 'rgba(' +
++            borderColor.red + ',' +
++            borderColor.green + ',' +
++            borderColor.blue + ',' +
++            borderAlpha + ')';
++
++    }
++
++    _getDefaultColors() {
++        // Prevent shell crash if the actor is not on the stage.
++        // It happens enabling/disabling repeatedly the extension
++        if (!this._dash._container.get_stage())
++            return [null, null];
++
++        // Remove custom style
++        let oldStyle = this._dash._container.get_style();
++        this._dash._container.set_style(null);
++
++        let themeNode = this._dash._container.get_theme_node();
++        this._dash._container.set_style(oldStyle);
++
++        let backgroundColor = themeNode.get_background_color();
++
++        // Just in case the theme has different border colors ..
++        // We want to find the inside border-color of the dock because it is
++        // the side most visible to the user. We do this by finding the side
++        // opposite the position
++        let position = Utils.getPosition(this._settings);
++        let side = position + 2;
++        if (side > 3)
++            side = Math.abs(side - 4);
++
++        let borderColor = themeNode.get_border_color(side);
++
++        return [backgroundColor, borderColor];
++    }
++
++    _updateDashColor() {
++        // Retrieve the color. If needed we will adjust it before passing it to
++        // this._transparency.
++        let [backgroundColor, borderColor] = this._getDefaultColors();
++
++        if (backgroundColor==null)
++            return;
++
++        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 '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)
++                newAlpha = this._settings.get_double('background-opacity');
++
++            backgroundColor = Clutter.color_from_string(this._settings.get_string('background-color'))[1];
++            this._customizedBackground = 'rgba(' +
++                backgroundColor.red + ',' +
++                backgroundColor.green + ',' +
++                backgroundColor.blue + ',' +
++                newAlpha + ')';
++
++            this._customizedBorder = this._customizedBackground;
++        }
++        this._transparency.setColor(backgroundColor);
++    }
++
++    _updateCustomStyleClasses() {
++        if (this._settings.get_boolean('apply-custom-theme'))
++            this._actor.add_style_class_name('dashtodock');
++        else
++            this._actor.remove_style_class_name('dashtodock');
++
++        if (this._settings.get_boolean('custom-theme-shrink'))
++            this._actor.add_style_class_name('shrink');
++        else
++            this._actor.remove_style_class_name('shrink');
++
++        if (this._settings.get_enum('running-indicator-style') !== 0)
++            this._actor.add_style_class_name('running-dots');
++        else
++            this._actor.remove_style_class_name('running-dots');
++
++        // If not the built-in theme option is not selected
++        if (!this._settings.get_boolean('apply-custom-theme')) {
++            if (this._settings.get_boolean('force-straight-corner'))
++                this._actor.add_style_class_name('straight-corner');
++            else
++                this._actor.remove_style_class_name('straight-corner');
++        } else {
++            this._actor.remove_style_class_name('straight-corner');
++        }
++    }
++
++    updateCustomTheme() {
++        this._updateCustomStyleClasses();
++        this._updateDashOpacity();
++        this._updateDashColor();
++        this._adjustTheme();
++        this._dash._redisplay();
++    }
++
++    /**
++     * Reimported back and adapted from atomdock
++     */
++    _adjustTheme() {
++        // Prevent shell crash if the actor is not on the stage.
++        // It happens enabling/disabling repeatedly the extension
++        if (!this._dash._container.get_stage())
++            return;
++
++        // Remove prior style edits
++        this._dash._container.set_style(null);
++        this._transparency.disable();
++
++        // If built-in theme is enabled do nothing else
++        if (this._settings.get_boolean('apply-custom-theme'))
++            return;
++
++        let newStyle = '';
++        let position = Utils.getPosition(this._settings);
++
++        if (!this._settings.get_boolean('custom-theme-shrink')) {
++            // obtain theme border settings
++            let themeNode = this._dash._container.get_theme_node();
++            let borderColor = themeNode.get_border_color(St.Side.TOP);
++            let borderWidth = themeNode.get_border_width(St.Side.TOP);
++            let borderRadius = themeNode.get_border_radius(St.Corner.TOPRIGHT);
++
++            // We're copying border and corner styles to left border and top-left
++            // corner, also removing bottom border and bottom-right corner styles
++            let borderInner = '';
++            let borderRadiusValue = '';
++            let borderMissingStyle = '';
++
++            if (this._rtl && (position != St.Side.RIGHT))
++                borderMissingStyle = 'border-right: ' + borderWidth + 'px solid ' +
++                       borderColor.to_string() + ';';
++            else if (!this._rtl && (position != St.Side.LEFT))
++                borderMissingStyle = 'border-left: ' + borderWidth + 'px solid ' +
++                       borderColor.to_string() + ';';
++
++            switch (position) {
++            case St.Side.LEFT:
++                borderInner = 'border-left';
++                borderRadiusValue = '0 ' + borderRadius + 'px ' + borderRadius + 'px 0;';
++                break;
++            case St.Side.RIGHT:
++                borderInner = 'border-right';
++                borderRadiusValue = borderRadius + 'px 0 0 ' + borderRadius + 'px;';
++                break;
++            case St.Side.TOP:
++                borderInner = 'border-top';
++                borderRadiusValue = '0 0 ' + borderRadius + 'px ' + borderRadius + 'px;';
++                break;
++            case St.Side.BOTTOM:
++                borderInner = 'border-bottom';
++                borderRadiusValue = borderRadius + 'px ' + borderRadius + 'px 0 0;';
++                break;
++            }
++
++            newStyle = borderInner + ': none;' +
++                'border-radius: ' + borderRadiusValue +
++                borderMissingStyle;
++
++            // I do call set_style possibly twice so that only the background gets the transition.
++            // The transition-property css rules seems to be unsupported
++            this._dash._container.set_style(newStyle);
++        }
++
++        // Customize background
++        let fixedTransparency = this._settings.get_enum('transparency-mode') == TransparencyMode.FIXED;
++        let defaultTransparency = this._settings.get_enum('transparency-mode') == TransparencyMode.DEFAULT;
++        if (!defaultTransparency && !fixedTransparency) {
++            this._transparency.enable();
++        }
++        else if (!defaultTransparency || this._settings.get_boolean('custom-background-color')) {
++            newStyle = newStyle + 'background-color:'+ this._customizedBackground + '; ' +
++                       'border-color:'+ this._customizedBorder + '; ' +
++                       'transition-delay: 0s; transition-duration: 0.250s;';
++            this._dash._container.set_style(newStyle);
++        }
++    }
++
++    _bindSettingsChanges() {
++        let keys = ['transparency-mode',
++                    'customize-alphas',
++                    'min-alpha',
++                    'max-alpha',
++                    'background-opacity',
++                    'custom-background-color',
++                    'background-color',
++                    'apply-custom-theme',
++                    'custom-theme-shrink',
++                    'custom-theme-running-dots',
++                    'extend-height',
++                    'force-straight-corner'];
++
++        keys.forEach(function(key) {
++            this._signalsHandler.add([
++                this._settings,
++                'changed::' + key,
++                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
++ */
++var Transparency = class DashToDock_Transparency {
++
++    constructor(settings, dock) {
++        this._settings = settings;
++        this._dash = dock.dash;
++        this._actor = this._dash._container;
++        this._dockActor = dock.actor;
++        this._dock = dock;
++        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';
++        this._transparentAlphaBorder = '0.1';
++        this._opaqueAlphaBorder = '0.5';
++        this._transparentTransition = '0ms';
++        this._opaqueTransition = '0ms';
++        this._base_actor_style = "";
++
++        this._signalsHandler = new Utils.GlobalSignalsHandler();
++        this._injectionsHandler = new Utils.InjectionsHandler();
++        this._trackedWindows = new Map();
++    }
++
++    enable() {
++        // ensure I never double-register/inject
++        // although it should never happen
++        this.disable();
++
++        this._base_actor_style = this._actor.get_style();
++        if (this._base_actor_style == null) {
++            this._base_actor_style = "";
++        }
++
++        this._signalsHandler.addWithLabel('transparency', [
++            global.window_group,
++            'actor-added',
++            this._onWindowActorAdded.bind(this)
++        ], [
++            global.window_group,
++            'actor-removed',
++            this._onWindowActorRemoved.bind(this)
++        ], [
++            global.window_manager,
++            'switch-workspace',
++            this._updateSolidStyle.bind(this)
++        ], [
++            Main.overview,
++            'hiding',
++            this._updateSolidStyle.bind(this)
++        ], [
++            Main.overview,
++            'showing',
++            this._updateSolidStyle.bind(this)
++        ]);
++
++        // Window signals
++        global.window_group.get_children().filter(function(child) {
++            // An irrelevant window actor ('Gnome-shell') produces an error when the signals are
++            // disconnected, therefore do not add signals to it.
++            return child instanceof Meta.WindowActor &&
++                   child.get_meta_window().get_wm_class() !== 'Gnome-shell';
++        }).forEach(function(win) {
++            this._onWindowActorAdded(null, win);
++        }, this);
++
++        if (this._actor.get_stage())
++            this._updateSolidStyle();
++
++        this._updateStyles();
++        this._updateSolidStyle();
++
++        this.emit('transparency-enabled');
++    }
++
++    disable() {
++        // ensure I never double-register/inject
++        // although it should never happen
++        this._signalsHandler.removeWithLabel('transparency');
++
++        for (let key of this._trackedWindows.keys())
++            this._trackedWindows.get(key).forEach(id => {
++                key.disconnect(id);
++            });
++        this._trackedWindows.clear();
++
++        this.emit('transparency-disabled');
++    }
++
++    destroy() {
++        this.disable();
++        this._signalsHandler.destroy();
++        this._injectionsHandler.destroy();
++    }
++
++    _onWindowActorAdded(container, metaWindowActor) {
++        let signalIds = [];
++        ['allocation-changed', 'notify::visible'].forEach(s => {
++            signalIds.push(metaWindowActor.connect(s, this._updateSolidStyle.bind(this)));
++        });
++        this._trackedWindows.set(metaWindowActor, signalIds);
++    }
++
++    _onWindowActorRemoved(container, metaWindowActor) {
++        if (!this._trackedWindows.get(metaWindowActor))
++            return;
++
++        this._trackedWindows.get(metaWindowActor).forEach(id => {
++            metaWindowActor.disconnect(id);
++        });
++        this._trackedWindows.delete(metaWindowActor);
++        this._updateSolidStyle();
++    }
++
++    _updateSolidStyle() {
++        let isNear = this._dockIsNear();
++        if (isNear) {
++            this._actor.set_style(this._opaque_style);
++            this._dockActor.remove_style_class_name('transparent');
++            this._dockActor.add_style_class_name('opaque');
++        }
++        else {
++            this._actor.set_style(this._transparent_style);
++            this._dockActor.remove_style_class_name('opaque');
++            this._dockActor.add_style_class_name('transparent');
++        }
++
++        this.emit('solid-style-updated', isNear);
++    }
++
++    _dockIsNear() {
++        if (this._dockActor.has_style_pseudo_class('overview'))
++            return false;
++        /* Get all the windows in the active workspace that are in the primary monitor and visible */
++        let activeWorkspace = global.workspace_manager.get_active_workspace();
++        let dash = this._dash;
++        let windows = activeWorkspace.list_windows().filter(function(metaWindow) {
++            return metaWindow.get_monitor() === dash._monitorIndex &&
++                   metaWindow.showing_on_its_workspace() &&
++                   metaWindow.get_window_type() != Meta.WindowType.DESKTOP;
++        });
++
++        /* Check if at least one window is near enough to the panel.
++         * If the dock is hidden, we need to account for the space it would take
++         * up when it slides out. This is avoid an ugly transition.
++         * */
++        let factor = 0;
++        if (!this._settings.get_boolean('dock-fixed') &&
++            this._dock.getDockState() == Dock.State.HIDDEN)
++            factor = 1;
++        let [leftCoord, topCoord] = this._actor.get_transformed_position();
++        let threshold;
++        if (this._position === St.Side.LEFT)
++            threshold = leftCoord + this._actor.get_width() * (factor + 1);
++        else if (this._position === St.Side.RIGHT)
++            threshold = leftCoord - this._actor.get_width() * factor;
++        else if (this._position === St.Side.TOP)
++            threshold = topCoord + this._actor.get_height() * (factor + 1);
++        else
++            threshold = topCoord - this._actor.get_height() * factor;
++
++        let scale = St.ThemeContext.get_for_stage(global.stage).scale_factor;
++        let isNearEnough = windows.some((metaWindow) => {
++            let coord;
++            if (this._position === St.Side.LEFT) {
++                coord = metaWindow.get_frame_rect().x;
++                return coord < threshold + 5 * scale;
++            }
++            else if (this._position === St.Side.RIGHT) {
++                coord = metaWindow.get_frame_rect().x + metaWindow.get_frame_rect().width;
++                return coord > threshold - 5 * scale;
++            }
++            else if (this._position === St.Side.TOP) {
++                coord = metaWindow.get_frame_rect().y;
++                return coord < threshold + 5 * scale;
++            }
++            else {
++                coord = metaWindow.get_frame_rect().y + metaWindow.get_frame_rect().height;
++                return coord > threshold - 5 * scale;
++            }
++        });
++
++        return isNearEnough;
++    }
++
++    _updateStyles() {
++        this._getAlphas();
++
++        this._transparent_style = this._base_actor_style +
++            'background-color: rgba(' +
++            this._backgroundColor + ', ' + this._transparentAlpha + ');' +
++            'border-color: rgba(' +
++            this._backgroundColor + ', ' + this._transparentAlphaBorder + ');' +
++            'transition-duration: ' + this._transparentTransition + 'ms;';
++
++        this._opaque_style = this._base_actor_style +
++            'background-color: rgba(' +
++            this._backgroundColor + ', ' + this._opaqueAlpha + ');' +
++            'border-color: rgba(' +
++            this._backgroundColor + ',' + this._opaqueAlphaBorder + ');' +
++            'transition-duration: ' + this._opaqueTransition + 'ms;';
++
++        this.emit('styles-updated');
++    }
++
++    setColor(color) {
++        this._backgroundColor = color.red + ',' + color.green + ',' + color.blue;
++        this._updateStyles();
++    }
++
++    _getAlphas() {
++        // Create dummy object and add to the uiGroup to get it to the stage
++        let dummyObject = new St.Bin({
++            name: 'dashtodockContainer',
++        });
++        Main.uiGroup.add_child(dummyObject);
++
++        dummyObject.add_style_class_name('dummy-opaque');
++        let themeNode = dummyObject.get_theme_node();
++        this._opaqueAlpha = themeNode.get_background_color().alpha / 255;
++        this._opaqueAlphaBorder = themeNode.get_border_color(0).alpha / 255;
++        this._opaqueTransition = themeNode.get_transition_duration();
++
++        dummyObject.add_style_class_name('dummy-transparent');
++        themeNode = dummyObject.get_theme_node();
++        this._transparentAlpha = themeNode.get_background_color().alpha / 255;
++        this._transparentAlphaBorder = themeNode.get_border_color(0).alpha / 255;
++        this._transparentTransition = themeNode.get_transition_duration();
++
++        Main.uiGroup.remove_child(dummyObject);
++
++        if (this._settings.get_boolean('customize-alphas')) {
++            this._opaqueAlpha = this._settings.get_double('max-alpha');
++            this._opaqueAlphaBorder = this._opaqueAlpha / 2;
++            this._transparentAlpha = this._settings.get_double('min-alpha');
++            this._transparentAlphaBorder = this._transparentAlpha / 2;
++        }
++    }
++};
++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..d315bd9
+--- /dev/null
++++ b/extensions/dash-to-dock/utils.js
+@@ -0,0 +1,258 @@
++const Clutter = imports.gi.Clutter;
++const Meta = imports.gi.Meta;
++const St = imports.gi.St;
++
++/**
++ * Simplify global signals and function injections handling
++ * abstract class
++ */
++const BasicHandler = class DashToDock_BasicHandler {
++
++    constructor() {
++        this._storage = new Object();
++    }
++
++    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() {
++        for( let label in this._storage )
++            this.removeWithLabel(label);
++    }
++
++    addWithLabel(label /* plus unlimited 3-long array arguments*/) {
++        if (this._storage[label] == undefined)
++            this._storage[label] = new Array();
++
++        // Skip first element of the arguments
++        for (let i = 1; i < arguments.length; i++) {
++            let item = this._storage[label];
++            item.push(this._create(arguments[i]));
++        }
++    }
++
++    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(item) {
++        throw new Error('no implementation of _create in ' + this);
++    }
++
++    /**
++     * Correctly delete single element
++     */
++    _remove(item) {
++        throw new Error('no implementation of _remove in ' + this);
++    }
++};
++
++/**
++ * Manage global signals
++ */
++var GlobalSignalsHandler = class DashToDock_GlobalSignalHandler extends BasicHandler {
++
++    _create(item) {
++        let object = item[0];
++        let event = item[1];
++        let callback = item[2]
++        let id = object.connect(event, callback);
++
++        return [object, id];
++    }
++
++    _remove(item) {
++         item[0].disconnect(item[1]);
++    }
++};
++
++/**
++ * Color manipulation utilities
++  */
++var ColorUtils = class DashToDock_ColorUtils {
++
++    // Darken or brigthen color by a fraction dlum
++    // Each rgb value is modified by the same fraction.
++    // Return "#rrggbb" string
++    static ColorLuminance(r, g, b, dlum) {
++        let rgbString = '#';
++
++        rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(r*(1+dlum), 0), 255)), 2);
++        rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(g*(1+dlum), 0), 255)), 2);
++        rgbString += ColorUtils._decimalToHex(Math.round(Math.min(Math.max(b*(1+dlum), 0), 255)), 2);
++
++        return rgbString;
++    }
++
++    // Convert decimal to an hexadecimal string adding the desired padding
++    static _decimalToHex(d, padding) {
++        let hex = d.toString(16);
++        while (hex.length < padding)
++            hex = '0'+ hex;
++        return hex;
++    }
++
++    // Convert hsv ([0-1, 0-1, 0-1]) to rgb ([0-255, 0-255, 0-255]).
++    // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV
++    // here with h = [0,1] instead of [0, 360]
++    // Accept either (h,s,v) independently or  {h:h, s:s, v:v} object.
++    // Return {r:r, g:g, b:b} object.
++    static HSVtoRGB(h, s, v) {
++        if (arguments.length === 1) {
++            s = h.s;
++            v = h.v;
++            h = h.h;
++        }
++
++        let r,g,b;
++        let c = v*s;
++        let h1 = h*6;
++        let x = c*(1 - Math.abs(h1 % 2 - 1));
++        let m = v - c;
++
++        if (h1 <=1)
++            r = c + m, g = x + m, b = m;
++        else if (h1 <=2)
++            r = x + m, g = c + m, b = m;
++        else if (h1 <=3)
++            r = m, g = c + m, b = x + m;
++        else if (h1 <=4)
++            r = m, g = x + m, b = c + m;
++        else if (h1 <=5)
++            r = x + m, g = m, b = c + m;
++        else
++            r = c + m, g = m, b = x + m;
++
++        return {
++            r: Math.round(r * 255),
++            g: Math.round(g * 255),
++            b: Math.round(b * 255)
++        };
++    }
++
++    // Convert rgb ([0-255, 0-255, 0-255]) to hsv ([0-1, 0-1, 0-1]).
++    // Following algorithm in https://en.wikipedia.org/wiki/HSL_and_HSV
++    // here with h = [0,1] instead of [0, 360]
++    // Accept either (r,g,b) independently or {r:r, g:g, b:b} object.
++    // Return {h:h, s:s, v:v} object.
++    static RGBtoHSV(r, g, b) {
++        if (arguments.length === 1) {
++            r = r.r;
++            g = r.g;
++            b = r.b;
++        }
++
++        let h,s,v;
++
++        let M = Math.max(r, g, b);
++        let m = Math.min(r, g, b);
++        let c = M - m;
++
++        if (c == 0)
++            h = 0;
++        else if (M == r)
++            h = ((g-b)/c) % 6;
++        else if (M == g)
++            h = (b-r)/c + 2;
++        else
++            h = (r-g)/c + 4;
++
++        h = h/6;
++        v = M/255;
++        if (M !== 0)
++            s = c/M;
++        else
++            s = 0;
++
++        return {
++            h: h,
++            s: s,
++            v: v
++        };
++    }
++};
++
++/**
++ * Manage function injection: both instances and prototype can be overridden
++ * and restored
++ */
++var InjectionsHandler = class DashToDock_InjectionsHandler extends BasicHandler {
++
++    _create(item) {
++        let object = item[0];
++        let name = item[1];
++        let injectedFunction = item[2];
++        let original = object[name];
++
++        object[name] = injectedFunction;
++        return [object, name, injectedFunction, original];
++    }
++
++    _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
++ */
++function getPosition(settings) {
++    let position = settings.get_enum('dock-position');
++    if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
++        if (position == St.Side.LEFT)
++            position = St.Side.RIGHT;
++        else if (position == St.Side.RIGHT)
++            position = St.Side.LEFT;
++    }
++    return position;
++}
++
++function drawRoundedLine(cr, x, y, width, height, isRoundLeft, isRoundRight, stroke, fill) {
++    if (height > width) {
++        y += Math.floor((height - width) / 2.0);
++        height = width;
++    }
++    
++    height = 2.0 * Math.floor(height / 2.0);
++    
++    var leftRadius = isRoundLeft ? height / 2.0 : 0.0;
++    var rightRadius = isRoundRight ? height / 2.0 : 0.0;
++    
++    cr.moveTo(x + width - rightRadius, y);
++    cr.lineTo(x + leftRadius, y);
++    if (isRoundLeft)
++        cr.arcNegative(x + leftRadius, y + leftRadius, leftRadius, -Math.PI/2, Math.PI/2);
++    else
++        cr.lineTo(x, y + height);
++    cr.lineTo(x + width - rightRadius, y + height);
++    if (isRoundRight)
++        cr.arcNegative(x + width - rightRadius, y + rightRadius, rightRadius, Math.PI/2, -Math.PI/2);
++    else
++        cr.lineTo(x + width, y);
++    cr.closePath();
++    
++    if (fill != null) {
++        cr.setSource(fill);
++        cr.fillPreserve();
++    }
++    if (stroke != null)
++        cr.setSource(stroke);
++    cr.stroke();
++}
+diff --git a/extensions/dash-to-dock/windowPreview.js b/extensions/dash-to-dock/windowPreview.js
+new file mode 100644
+index 0000000..ea98f27
+--- /dev/null
++++ b/extensions/dash-to-dock/windowPreview.js
+@@ -0,0 +1,578 @@
++/*
++ * Credits:
++ * This file is based on code from the Dash to Panel extension by Jason DeRose
++ * and code from the Taskbar extension by Zorin OS
++ * Some code was also adapted from the upstream Gnome Shell source code.
++ */
++const Clutter = imports.gi.Clutter;
++const GLib = imports.gi.GLib;
++const St = imports.gi.St;
++const Mainloop = imports.mainloop;
++const Main = imports.ui.main;
++const Gtk = imports.gi.Gtk;
++
++const Params = imports.misc.params;
++const PopupMenu = imports.ui.popupMenu;
++const Tweener = imports.ui.tweener;
++const Workspace = imports.ui.workspace;
++
++const Me = imports.misc.extensionUtils.getCurrentExtension();
++const Utils = Me.imports.utils;
++
++const PREVIEW_MAX_WIDTH = 250;
++const PREVIEW_MAX_HEIGHT = 150;
++
++var WindowPreviewMenu = class DashToDock_WindowPreviewMenu extends PopupMenu.PopupMenu {
++
++    constructor(source, settings) {
++        let side = Utils.getPosition(settings);
++        super(source.actor, 0.5, side);
++
++        this._dtdSettings = settings;
++
++        // We want to keep the item hovered while the menu is up
++        this.blockSourceEvents = true;
++
++        this._source = source;
++        this._app = this._source.app;
++        let monitorIndex = this._source.monitorIndex;
++
++        this.actor.add_style_class_name('app-well-menu');
++        this.actor.set_style('max-width: '  + (Main.layoutManager.monitors[monitorIndex].width  - 22) + 'px; ' +
++                             'max-height: ' + (Main.layoutManager.monitors[monitorIndex].height - 22) + 'px;');
++        this.actor.hide();
++
++        // Chain our visibility and lifecycle to that of the source
++        this._mappedId = this._source.actor.connect('notify::mapped', () => {
++            if (!this._source.actor.mapped)
++                this.close();
++        });
++        this._destroyId = this._source.actor.connect('destroy', this.destroy.bind(this));
++
++        Main.uiGroup.add_actor(this.actor);
++
++        // Change the initialized side where required.
++        this._arrowSide = side;
++        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);
++        this._previewBox._redisplay();
++    }
++
++    popup() {
++        let windows = this._source.getInterestingWindows();
++        if (windows.length > 0) {
++            this._redisplay();
++            this.open();
++            this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
++            this._source.emit('sync-tooltip');
++        }
++    }
++
++    _onDestroy() {
++        if (this._mappedId)
++            this._source.actor.disconnect(this._mappedId);
++
++        if (this._destroyId)
++            this._source.actor.disconnect(this._destroyId);
++    }
++};
++
++var WindowPreviewList = class DashToDock_WindowPreviewList extends PopupMenu.PopupMenuSection {
++
++    constructor(source, settings) {
++        super();
++        this._dtdSettings = settings;
++
++        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', this._onScrollEvent.bind(this));
++
++        let position = Utils.getPosition(this._dtdSettings);
++        this.isHorizontal = position == St.Side.BOTTOM || position == St.Side.TOP;
++        this.box.set_vertical(!this.isHorizontal);
++        this.box.set_name('dashtodockWindowList');
++        this.actor.add_actor(this.box);
++        this.actor._delegate = this;
++
++        this._shownInitially = false;
++
++        this._source = source;
++        this.app = source.app;
++
++        this._redisplayId = Main.initializeDeferredWork(this.actor, this._redisplay.bind(this));
++
++        this.actor.connect('destroy', this._onDestroy.bind(this));
++        this._stateChangedId = this.app.connect('windows-changed',
++                                                this._queueRedisplay.bind(this));
++    }
++
++    _queueRedisplay () {
++        Main.queueDeferredWork(this._redisplayId);
++    }
++
++    _onScrollEvent(actor, event) {
++        // Event coordinates are relative to the stage but can be transformed
++        // as the actor will only receive events within his bounds.
++        let stage_x, stage_y, ok, event_x, event_y, actor_w, actor_h;
++        [stage_x, stage_y] = event.get_coords();
++        [ok, event_x, event_y] = actor.transform_stage_point(stage_x, stage_y);
++        [actor_w, actor_h] = actor.get_size();
++
++        // If the scroll event is within a 1px margin from
++        // the relevant edge of the actor, let the event propagate.
++        if (event_y >= actor_h - 2)
++            return Clutter.EVENT_PROPAGATE;
++
++        // Skip to avoid double events mouse
++        if (event.is_pointer_emulated())
++            return Clutter.EVENT_STOP;
++
++        let adjustment, delta;
++
++        if (this.isHorizontal)
++            adjustment = this.actor.get_hscroll_bar().get_adjustment();
++        else
++            adjustment = this.actor.get_vscroll_bar().get_adjustment();
++
++        let increment = adjustment.step_increment;
++
++        switch ( event.get_scroll_direction() ) {
++        case Clutter.ScrollDirection.UP:
++            delta = -increment;
++            break;
++        case Clutter.ScrollDirection.DOWN:
++            delta = +increment;
++            break;
++        case Clutter.ScrollDirection.SMOOTH:
++            let [dx, dy] = event.get_scroll_delta();
++            delta = dy*increment;
++            delta += dx*increment;
++            break;
++
++        }
++
++        adjustment.set_value(adjustment.get_value() + delta);
++
++        return Clutter.EVENT_STOP;
++    }
++
++    _onDestroy() {
++        this.app.disconnect(this._stateChangedId);
++        this._stateChangedId = 0;
++    }
++
++    _createPreviewItem(window) {
++        let preview = new WindowPreviewMenuItem(window);
++        return preview;
++    }
++
++    _redisplay () {
++        let children = this._getMenuItems().filter(function(actor) {
++                return actor._window;
++            });
++
++        // Windows currently on the menu
++        let oldWin = children.map(function(actor) {
++                return actor._window;
++            });
++
++        // All app windows with a static order
++        let newWin = this._source.getInterestingWindows().sort(function(a, b) {
++            return a.get_stable_sequence() > b.get_stable_sequence();
++        });
++
++        let addedItems = [];
++        let removedActors = [];
++
++        let newIndex = 0;
++        let oldIndex = 0;
++
++        while (newIndex < newWin.length || oldIndex < oldWin.length) {
++            // No change at oldIndex/newIndex
++            if (oldWin[oldIndex] &&
++                oldWin[oldIndex] == newWin[newIndex]) {
++                oldIndex++;
++                newIndex++;
++                continue;
++            }
++
++            // Window removed at oldIndex
++            if (oldWin[oldIndex] &&
++                newWin.indexOf(oldWin[oldIndex]) == -1) {
++                removedActors.push(children[oldIndex]);
++                oldIndex++;
++                continue;
++            }
++
++            // Window added at newIndex
++            if (newWin[newIndex] &&
++                oldWin.indexOf(newWin[newIndex]) == -1) {
++                addedItems.push({ item: this._createPreviewItem(newWin[newIndex]),
++                                  pos: newIndex });
++                newIndex++;
++                continue;
++            }
++
++            // Window moved
++            let insertHere = newWin[newIndex + 1] &&
++                             newWin[newIndex + 1] == oldWin[oldIndex];
++            let alreadyRemoved = removedActors.reduce(function(result, actor) {
++                let removedWin = actor._window;
++                return result || removedWin == newWin[newIndex];
++            }, false);
++
++            if (insertHere || alreadyRemoved) {
++                addedItems.push({ item: this._createPreviewItem(newWin[newIndex]),
++                                  pos: newIndex + removedActors.length });
++                newIndex++;
++            } else {
++                removedActors.push(children[oldIndex]);
++                oldIndex++;
++            }
++        }
++
++        for (let i = 0; i < addedItems.length; i++)
++            this.addMenuItem(addedItems[i].item,
++                             addedItems[i].pos);
++
++        for (let i = 0; i < removedActors.length; i++) {
++            let item = removedActors[i];
++            if (this._shownInitially)
++                item._animateOutAndDestroy();
++            else
++                item.actor.destroy();
++        }
++
++        // Skip animations on first run when adding the initial set
++        // of items, to avoid all items zooming in at once
++        let animate = this._shownInitially;
++
++        if (!this._shownInitially)
++            this._shownInitially = true;
++
++        for (let i = 0; i < addedItems.length; i++)
++            addedItems[i].item.show(animate);
++
++        // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744
++        // Without it, StBoxLayout may use a stale size cache
++        this.box.queue_relayout();
++
++        if (newWin.length < 1)
++            this._getTopMenu().close(~0);
++
++        // As for upstream:
++        // St.ScrollView always requests space horizontally for a possible vertical
++        // scrollbar if in AUTOMATIC mode. Doing better would require implementation
++        // of width-for-height in St.BoxLayout and St.ScrollView. This looks bad
++        // when we *don't* need it, so turn off the scrollbar when that's true.
++        // Dynamic changes in whether we need it aren't handled properly.
++        let needsScrollbar = this._needsScrollbar();
++        let scrollbar_policy =  needsScrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
++        if (this.isHorizontal)
++            this.actor.hscrollbar_policy =  scrollbar_policy;
++        else
++            this.actor.vscrollbar_policy =  scrollbar_policy;
++
++        if (needsScrollbar)
++            this.actor.add_style_pseudo_class('scrolled');
++        else
++            this.actor.remove_style_pseudo_class('scrolled');
++    }
++
++    _needsScrollbar() {
++        let topMenu = this._getTopMenu();
++        let topThemeNode = topMenu.actor.get_theme_node();
++        if (this.isHorizontal) {
++            let [topMinWidth, topNaturalWidth] = topMenu.actor.get_preferred_width(-1);
++            let topMaxWidth = topThemeNode.get_max_width();
++            return topMaxWidth >= 0 && topNaturalWidth >= topMaxWidth;
++        } else {
++            let [topMinHeight, topNaturalHeight] = topMenu.actor.get_preferred_height(-1);
++            let topMaxHeight = topThemeNode.get_max_height();
++            return topMaxHeight >= 0 && topNaturalHeight >= topMaxHeight;
++        }
++
++    }
++
++    isAnimatingOut() {
++        return this.actor.get_children().reduce(function(result, actor) {
++                   return result || actor.animatingOut;
++               }, false);
++    }
++};
++
++var WindowPreviewMenuItem = class DashToDock_WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem {
++
++    constructor(window, params) {
++        super(params);
++
++        this._window = window;
++        this._destroyId = 0;
++        this._windowAddedId = 0;
++
++        // We don't want this: it adds spacing on the left of the item.
++        this.actor.remove_child(this._ornamentLabel);
++        this.actor.add_style_class_name('dashtodock-app-well-preview-menu-item');
++
++        this._cloneBin = new St.Bin();
++        this._cloneBin.set_size(PREVIEW_MAX_WIDTH, PREVIEW_MAX_HEIGHT);
++
++        // TODO: improve the way the closebutton is layout. Just use some padding
++        // for the moment.
++        this._cloneBin.set_style('padding-bottom: 0.5em');
++
++        this.closeButton = new St.Button({ style_class: 'window-close',
++                                          x_expand: true,
++                                          y_expand: true});
++        this.closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' }));
++        this.closeButton.set_x_align(Clutter.ActorAlign.END);
++        this.closeButton.set_y_align(Clutter.ActorAlign.START);
++
++
++        this.closeButton.opacity = 0;
++        this.closeButton.connect('clicked', this._closeWindow.bind(this));
++
++        let overlayGroup = new Clutter.Actor({layout_manager: new Clutter.BinLayout() });
++
++        overlayGroup.add_actor(this._cloneBin);
++        overlayGroup.add_actor(this.closeButton);
++
++        let label = new St.Label({ text: window.get_title()});
++        label.set_style('max-width: '+PREVIEW_MAX_WIDTH +'px');
++        let labelBin = new St.Bin({ child: label,
++                                    x_align: St.Align.MIDDLE});
++
++        this._windowTitleId = this._window.connect('notify::title', () => {
++                                  label.set_text(this._window.get_title());
++                              });
++
++        let box = new St.BoxLayout({ vertical: true,
++                                     reactive:true,
++                                     x_expand:true });
++        box.add(overlayGroup);
++        box.add(labelBin);
++        this.actor.add_actor(box);
++
++        this.actor.connect('enter-event',
++                                  this._onEnter.bind(this));
++        this.actor.connect('leave-event',
++                                  this._onLeave.bind(this));
++        this.actor.connect('key-focus-in',
++                                  this._onEnter.bind(this));
++        this.actor.connect('key-focus-out',
++                                  this._onLeave.bind(this));
++
++        this._cloneTexture(window);
++
++    }
++
++    _cloneTexture(metaWin){
++
++        let mutterWindow = metaWin.get_compositor_private();
++
++        // Newly-created windows are added to a workspace before
++        // the compositor finds out about them...
++        // Moreover sometimes they return an empty texture, thus as a workarounf also check for it size
++        if (!mutterWindow || !mutterWindow.get_texture() || !mutterWindow.get_texture().get_size()[0]) {
++            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;
++        }
++
++        let windowTexture = mutterWindow.get_texture();
++        let [width, height] = windowTexture.get_size();
++
++        let scale = Math.min(1.0, PREVIEW_MAX_WIDTH/width, PREVIEW_MAX_HEIGHT/height);
++
++        let clone = new Clutter.Clone ({ source: windowTexture,
++                                         reactive: true,
++                                         width: width * scale,
++                                         height: height * scale });
++
++        // when the source actor is destroyed, i.e. the window closed, first destroy the clone
++        // and then destroy the menu item (do this animating out)
++        this._destroyId = mutterWindow.connect('destroy', () => {
++            clone.destroy();
++            this._destroyId = 0; // avoid to try to disconnect this signal from mutterWindow in _onDestroy(),
++                                 // as the object was just destroyed
++            this._animateOutAndDestroy();
++        });
++
++        this._clone = clone;
++        this._mutterWindow = mutterWindow;
++        this._cloneBin.set_child(this._clone);
++    }
++
++    _windowCanClose() {
++        return this._window.can_close() &&
++               !this._hasAttachedDialogs();
++    }
++
++    _closeWindow(actor) {
++        this._workspace = this._window.get_workspace();
++
++        // This mechanism is copied from the workspace.js upstream code
++        // It forces window activation if the windows don't get closed,
++        // for instance because asking user confirmation, by monitoring the opening of
++        // such additional confirmation window
++        this._windowAddedId = this._workspace.connect('window-added',
++                                                      this._onWindowAdded.bind(this));
++
++        this.deleteAllWindows();
++    }
++
++    deleteAllWindows() {
++        // Delete all windows, starting from the bottom-most (most-modal) one
++        //let windows = this._window.get_compositor_private().get_children();
++        let windows = this._clone.get_children();
++        for (let i = windows.length - 1; i >= 1; i--) {
++            let realWindow = windows[i].source;
++            let metaWindow = realWindow.meta_window;
++
++            metaWindow.delete(global.get_current_time());
++        }
++
++        this._window.delete(global.get_current_time());
++    }
++
++    _onWindowAdded(workspace, win) {
++        let metaWindow = this._window;
++
++        if (win.get_transient_for() == metaWindow) {
++            workspace.disconnect(this._windowAddedId);
++            this._windowAddedId = 0;
++
++            // use an idle handler to avoid mapping problems -
++            // see comment in Workspace._windowAdded
++            let id = Mainloop.idle_add(() => {
++                this.emit('activate');
++                return GLib.SOURCE_REMOVE;
++            });
++            GLib.Source.set_name_by_id(id, '[dash-to-dock] this.emit');
++        }
++    }
++
++    _hasAttachedDialogs() {
++        // count trasient windows
++        let n=0;
++        this._window.foreach_transient(function(){n++;});
++        return n>0;
++    }
++
++    _onEnter() {
++        this._showCloseButton();
++        return Clutter.EVENT_PROPAGATE;
++    }
++
++    _onLeave() {
++        if (!this._cloneBin.has_pointer &&
++            !this.closeButton.has_pointer)
++            this._hideCloseButton();
++
++        return Clutter.EVENT_PROPAGATE;
++    }
++
++    _idleToggleCloseButton() {
++        this._idleToggleCloseId = 0;
++
++        if (!this._cloneBin.has_pointer &&
++            !this.closeButton.has_pointer)
++            this._hideCloseButton();
++
++        return GLib.SOURCE_REMOVE;
++    }
++
++    _showCloseButton() {
++
++        if (this._windowCanClose()) {
++            this.closeButton.show();
++            Tweener.addTween(this.closeButton,
++                             { opacity: 255,
++                               time: Workspace.CLOSE_BUTTON_FADE_TIME,
++                               transition: 'easeOutQuad' });
++        }
++    }
++
++    _hideCloseButton() {
++        Tweener.addTween(this.closeButton,
++                         { opacity: 0,
++                           time: Workspace.CLOSE_BUTTON_FADE_TIME,
++                           transition: 'easeInQuad' });
++    }
++
++    show(animate) {
++        let fullWidth = this.actor.get_width();
++
++        this.actor.opacity = 0;
++        this.actor.set_width(0);
++
++        let time = animate ? 0.25 : 0;
++        Tweener.addTween(this.actor,
++                         { opacity: 255,
++                           width: fullWidth,
++                           time: time,
++                           transition: 'easeInOutQuad'
++                         });
++    }
++
++    _animateOutAndDestroy() {
++        Tweener.addTween(this.actor,
++                         { opacity: 0,
++                           time: 0.25,
++                         });
++
++        Tweener.addTween(this.actor,
++                         { height: 0,
++                           width: 0,
++                           time: 0.25,
++                           delay: 0.25,
++                           onCompleteScope: this,
++                           onComplete() {
++                              this.actor.destroy();
++                           }
++                         });
++    }
++
++    activate() {
++        this._getTopMenu().close();
++        Main.activateWindow(this._window);
++    }
++
++    _onDestroy() {
++        super._onDestroy();
++
++        if (this._windowAddedId > 0) {
++            this._workspace.disconnect(this._windowAddedId);
++            this._windowAddedId = 0;
++        }
++
++        if (this._destroyId > 0) {
++            this._mutterWindow.disconnect(this._destroyId);
++            this._destroyId = 0;
++        }
++
++        if (this._windowTitleId > 0) {
++            this._window.disconnect(this._windowTitleId);
++            this._windowTitleId = 0;
++        }
++    }
++};
++
+diff --git a/meson.build b/meson.build
+index 6050c32..2909135 100644
+--- a/meson.build
++++ b/meson.build
+@@ -49,6 +49,7 @@ default_extensions += [
+ all_extensions = default_extensions
+ all_extensions += [
+   'auto-move-windows',
++  'dash-to-dock',
+   'native-window-placement',
+   'top-icons',
+   'user-theme'
+-- 
+2.21.1
+
+
+From 9ffe67c4d25f34fa6c3af5ee4ddbd0be3018ef14 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Wed, 20 May 2015 18:55:47 +0200
+Subject: [PATCH 3/8] Add panel-favorites extension
+
+---
+ extensions/panel-favorites/extension.js     | 267 ++++++++++++++++++++
+ extensions/panel-favorites/meson.build      |   5 +
+ extensions/panel-favorites/metadata.json.in |  10 +
+ extensions/panel-favorites/stylesheet.css   |  14 +
+ meson.build                                 |   1 +
+ 5 files changed, 297 insertions(+)
+ create mode 100644 extensions/panel-favorites/extension.js
+ create mode 100644 extensions/panel-favorites/meson.build
+ create mode 100644 extensions/panel-favorites/metadata.json.in
+ create mode 100644 extensions/panel-favorites/stylesheet.css
+
+diff --git a/extensions/panel-favorites/extension.js b/extensions/panel-favorites/extension.js
+new file mode 100644
+index 0000000..b817dbb
+--- /dev/null
++++ b/extensions/panel-favorites/extension.js
+@@ -0,0 +1,267 @@
++// Copyright (C) 2011-2013 R M Yorston
++// Licence: GPLv2+
++
++const Clutter = imports.gi.Clutter;
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++const Lang = imports.lang;
++const Shell = imports.gi.Shell;
++const Signals = imports.signals;
++const St = imports.gi.St;
++const Mainloop = imports.mainloop;
++
++const AppFavorites = imports.ui.appFavorites;
++const Main = imports.ui.main;
++const Panel = imports.ui.panel;
++const Tweener = imports.ui.tweener;
++
++const PANEL_LAUNCHER_LABEL_SHOW_TIME = 0.15;
++const PANEL_LAUNCHER_LABEL_HIDE_TIME = 0.1;
++const PANEL_LAUNCHER_HOVER_TIMEOUT = 300;
++
++const PanelLauncher = new Lang.Class({
++    Name: 'PanelLauncher',
++
++    _init: function(app) {
++        this.actor = new St.Button({ style_class: 'panel-button',
++                                     reactive: true });
++        this.iconSize = 24;
++        let icon = app.create_icon_texture(this.iconSize);
++        this.actor.set_child(icon);
++        this.actor._delegate = this;
++        let text = app.get_name();
++        if ( app.get_description() ) {
++            text += '\n' + app.get_description();
++        }
++
++        this.label = new St.Label({ style_class: 'panel-launcher-label'});
++        this.label.set_text(text);
++        Main.layoutManager.addChrome(this.label);
++        this.label.hide();
++        this.actor.label_actor = this.label;
++
++        this._app = app;
++        this.actor.connect('clicked', Lang.bind(this, function() {
++            this._app.open_new_window(-1);
++        }));
++        this.actor.connect('notify::hover',
++                Lang.bind(this, this._onHoverChanged));
++        this.actor.opacity = 207;
++
++        this.actor.connect('notify::allocation', Lang.bind(this, this._alloc));
++    },
++
++    _onHoverChanged: function(actor) {
++        actor.opacity = actor.hover ? 255 : 207;
++    },
++
++    _alloc: function() {
++        let size = this.actor.allocation.y2 - this.actor.allocation.y1 - 3;
++        if ( size >= 24 && size != this.iconSize ) {
++            this.actor.get_child().destroy();
++            this.iconSize = size;
++            let icon = this._app.create_icon_texture(this.iconSize);
++            this.actor.set_child(icon);
++        }
++    },
++
++    showLabel: function() {
++        this.label.opacity = 0;
++        this.label.show();
++
++        let [stageX, stageY] = this.actor.get_transformed_position();
++
++        let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
++        let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
++        let labelWidth = this.label.get_width();
++
++        let node = this.label.get_theme_node();
++        let yOffset = node.get_length('-y-offset');
++
++        let y = stageY + itemHeight + yOffset;
++        let x = Math.floor(stageX + itemWidth/2 - labelWidth/2);
++
++        let parent = this.label.get_parent();
++        let parentWidth = parent.allocation.x2 - parent.allocation.x1;
++
++        if ( Clutter.get_default_text_direction() == Clutter.TextDirection.LTR ) {
++            // stop long tooltips falling off the right of the screen
++            x = Math.min(x, parentWidth-labelWidth-6);
++            // but whatever happens don't let them fall of the left
++            x = Math.max(x, 6);
++        }
++        else {
++            x = Math.max(x, 6);
++            x = Math.min(x, parentWidth-labelWidth-6);
++        }
++
++        this.label.set_position(x, y);
++        Tweener.addTween(this.label,
++                         { opacity: 255,
++                           time: PANEL_LAUNCHER_LABEL_SHOW_TIME,
++                           transition: 'easeOutQuad',
++                         });
++    },
++
++    hideLabel: function() {
++        this.label.opacity = 255;
++        Tweener.addTween(this.label,
++                         { opacity: 0,
++                           time: PANEL_LAUNCHER_LABEL_HIDE_TIME,
++                           transition: 'easeOutQuad',
++                           onComplete: Lang.bind(this, function() {
++                               this.label.hide();
++                           })
++                         });
++    },
++
++    destroy: function() {
++        this.label.destroy();
++        this.actor.destroy();
++    }
++});
++
++const PanelFavorites = new Lang.Class({
++    Name: 'PanelFavorites',
++
++    _init: function() {
++        this._showLabelTimeoutId = 0;
++        this._resetHoverTimeoutId = 0;
++        this._labelShowing = false;
++
++        this.actor = new St.BoxLayout({ name: 'panelFavorites',
++                                        x_expand: true, y_expand: true,
++                                        style_class: 'panel-favorites' });
++        this._display();
++
++        this.container = new St.Bin({ y_fill: true,
++                                      x_fill: true,
++                                      child: this.actor });
++
++        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
++        this._installChangedId = Shell.AppSystem.get_default().connect('installed-changed', Lang.bind(this, this._redisplay));
++        this._changedId = AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._redisplay));
++    },
++
++    _redisplay: function() {
++        for ( let i=0; i<this._buttons.length; ++i ) {
++            this._buttons[i].destroy();
++        }
++
++        this._display();
++    },
++
++    _display: function() {
++        let launchers = global.settings.get_strv(AppFavorites.getAppFavorites().FAVORITE_APPS_KEY);
++
++        this._buttons = [];
++        let j = 0;
++        for ( let i=0; i<launchers.length; ++i ) {
++            let app = Shell.AppSystem.get_default().lookup_app(launchers[i]);
++
++            if ( app == null ) {
++                continue;
++            }
++
++            let launcher = new PanelLauncher(app);
++            this.actor.add(launcher.actor);
++            launcher.actor.connect('notify::hover',
++                        Lang.bind(this, function() {
++                            this._onHover(launcher);
++                        }));
++            this._buttons[j] = launcher;
++            ++j;
++        }
++    },
++
++    // this routine stolen from dash.js
++    _onHover: function(launcher) {
++        if ( launcher.actor.hover ) {
++            if (this._showLabelTimeoutId == 0) {
++                let timeout = this._labelShowing ?
++                                0 : PANEL_LAUNCHER_HOVER_TIMEOUT;
++                this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
++                    Lang.bind(this, function() {
++                        this._labelShowing = true;
++                        launcher.showLabel();
++                        this._showLabelTimeoutId = 0;
++                        return GLib.SOURCE_REMOVE;
++                    }));
++                if (this._resetHoverTimeoutId > 0) {
++                    Mainloop.source_remove(this._resetHoverTimeoutId);
++                    this._resetHoverTimeoutId = 0;
++                }
++            }
++        } else {
++            if (this._showLabelTimeoutId > 0) {
++                Mainloop.source_remove(this._showLabelTimeoutId);
++                this._showLabelTimeoutId = 0;
++            }
++            launcher.hideLabel();
++            if (this._labelShowing) {
++                this._resetHoverTimeoutId = Mainloop.timeout_add(
++                    PANEL_LAUNCHER_HOVER_TIMEOUT,
++                    Lang.bind(this, function() {
++                        this._labelShowing = false;
++                        this._resetHoverTimeoutId = 0;
++                        return GLib.SOURCE_REMOVE;
++                    }));
++            }
++        }
++    },
++
++    _onDestroy: function() {
++        if ( this._installChangedId != 0 ) {
++            Shell.AppSystem.get_default().disconnect(this._installChangedId);
++            this._installChangedId = 0;
++        }
++
++        if ( this._changedId != 0 ) {
++            AppFavorites.getAppFavorites().disconnect(this._changedId);
++            this._changedId = 0;
++        }
++    }
++});
++Signals.addSignalMethods(PanelFavorites.prototype);
++
++let myAddToStatusArea;
++let panelFavorites;
++
++function enable() {
++    Panel.Panel.prototype.myAddToStatusArea = myAddToStatusArea;
++
++    // place panel to left of app menu, or failing that at right end of box
++    let siblings = Main.panel._leftBox.get_children();
++    let appMenu = Main.panel.statusArea['appMenu'];
++    let pos = appMenu ? siblings.indexOf(appMenu.container) : siblings.length;
++
++    panelFavorites = new PanelFavorites();
++    Main.panel.myAddToStatusArea('panel-favorites', panelFavorites,
++                                pos, 'left');
++}
++
++function disable() {
++    delete Panel.Panel.prototype.myAddToStatusArea;
++
++    panelFavorites.actor.destroy();
++    panelFavorites.emit('destroy');
++    panelFavorites = null;
++}
++
++function init() {
++    myAddToStatusArea = function(role, indicator, position, box) {
++        if (this.statusArea[role])
++            throw new Error('Extension point conflict: there is already a status indicator for role ' + role);
++
++        position = position || 0;
++        let boxes = {
++            left: this._leftBox,
++            center: this._centerBox,
++            right: this._rightBox
++        };
++        let boxContainer = boxes[box] || this._rightBox;
++        this.statusArea[role] = indicator;
++        this._addToPanelBox(role, indicator, position, boxContainer);
++        return indicator;
++    };
++}
+diff --git a/extensions/panel-favorites/meson.build b/extensions/panel-favorites/meson.build
+new file mode 100644
+index 0000000..48504f6
+--- /dev/null
++++ b/extensions/panel-favorites/meson.build
+@@ -0,0 +1,5 @@
++extension_data += configure_file(
++  input: metadata_name + '.in',
++  output: metadata_name,
++  configuration: metadata_conf
++)
+diff --git a/extensions/panel-favorites/metadata.json.in b/extensions/panel-favorites/metadata.json.in
+new file mode 100644
+index 0000000..037f281
+--- /dev/null
++++ b/extensions/panel-favorites/metadata.json.in
+@@ -0,0 +1,10 @@
++{
++"extension-id": "@extension_id@",
++"uuid": "@uuid@",
++"settings-schema": "@gschemaname@",
++"gettext-domain": "@gettext_domain@",
++"name": "Frippery Panel Favorites",
++"description": "Add launchers for Favorites to the panel",
++"shell-version": [ "@shell_current@" ],
++"url": "http://intgat.tigress.co.uk/rmy/extensions/index.html"
++}
+diff --git a/extensions/panel-favorites/stylesheet.css b/extensions/panel-favorites/stylesheet.css
+new file mode 100644
+index 0000000..120adac
+--- /dev/null
++++ b/extensions/panel-favorites/stylesheet.css
+@@ -0,0 +1,14 @@
++.panel-favorites {
++    spacing: 6px;
++}
++
++.panel-launcher-label {
++    border-radius: 7px;
++    padding: 4px 12px;
++    background-color: rgba(0,0,0,0.9);
++    color: white;
++    text-align: center;
++    font-size: 9pt;
++    font-weight: bold;
++    -y-offset: 6px;
++}
+diff --git a/meson.build b/meson.build
+index 2909135..e8e00dc 100644
+--- a/meson.build
++++ b/meson.build
+@@ -51,6 +51,7 @@ all_extensions += [
+   'auto-move-windows',
+   'dash-to-dock',
+   'native-window-placement',
++  'panel-favorites',
+   'top-icons',
+   'user-theme'
+ ]
+-- 
+2.21.1
+
+
+From 4bd1716e559af83795eec5b02025798b02c09fa4 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Fri, 4 Mar 2016 17:07:21 +0100
+Subject: [PATCH 4/8] Add updates-dialog extension
+
+---
+ 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, 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
+ create mode 100644 extensions/updates-dialog/org.gnome.shell.extensions.updates-dialog.gschema.xml
+ create mode 100644 extensions/updates-dialog/stylesheet.css
+
+diff --git a/extensions/updates-dialog/extension.js b/extensions/updates-dialog/extension.js
+new file mode 100644
+index 0000000..59f6dcf
+--- /dev/null
++++ b/extensions/updates-dialog/extension.js
+@@ -0,0 +1,503 @@
++/*
++ * Copyright (c) 2015 Red Hat, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of the
++ * License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful, but
++ * WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ * General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, see <http://www.gnu.org/licenses/>.
++ */
++
++/* exported enable disable */
++
++const { Clutter, Gio, GLib, PackageKitGlib: PkgKit, Pango, Polkit, St } = imports.gi;
++const Signals = imports.signals;
++
++const EndSessionDialog = imports.ui.endSessionDialog;
++const ModalDialog = imports.ui.modalDialog;
++
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++
++const PkIface = '<node> \
++<interface name="org.freedesktop.PackageKit"> \
++    <method name="CreateTransaction"> \
++        <arg type="o" name="object_path" direction="out"/> \
++    </method> \
++    <signal name="UpdatesChanged"/> \
++</interface> \
++</node>';
++
++const PkOfflineIface = '<node> \
++<interface name="org.freedesktop.PackageKit.Offline"> \
++    <property name="UpdatePrepared" type="b" access="read"/> \
++    <property name="TriggerAction" type="s" access="read"/> \
++    <method name="Trigger"> \
++        <arg type="s" name="action" direction="in"/> \
++    </method> \
++    <method name="Cancel"/> \
++</interface> \
++</node>';
++
++const PkTransactionIface = '<node> \
++<interface name="org.freedesktop.PackageKit.Transaction"> \
++    <method name="SetHints"> \
++        <arg type="as" name="hints" direction="in"/> \
++    </method> \
++    <method name="GetUpdates"> \
++        <arg type="t" name="filter" direction="in"/> \
++    </method> \
++    <method name="UpdatePackages"> \
++        <arg type="t" name="transaction_flags" direction="in"/> \
++        <arg type="as" name="package_ids" direction="in"/> \
++    </method> \
++    <signal name="Package"> \
++        <arg type="u" name="info" direction="out"/> \
++        <arg type="s" name="package_id" direction="out"/> \
++        <arg type="s" name="summary" direction="out"/> \
++    </signal> \
++    <signal name="Finished"> \
++        <arg type="u" name="exit" direction="out"/> \
++        <arg type="u" name="runtime" direction="out"/> \
++    </signal> \
++</interface> \
++</node>';
++
++const LoginManagerIface = '<node> \
++<interface name="org.freedesktop.login1.Manager"> \
++<method name="Reboot"> \
++    <arg type="b" direction="in"/> \
++</method> \
++<method name="CanReboot"> \
++    <arg type="s" direction="out"/> \
++</method> \
++</interface> \
++</node>';
++
++const PkProxy = Gio.DBusProxy.makeProxyWrapper(PkIface);
++const PkOfflineProxy = Gio.DBusProxy.makeProxyWrapper(PkOfflineIface);
++const PkTransactionProxy = Gio.DBusProxy.makeProxyWrapper(PkTransactionIface);
++const LoginManagerProxy = Gio.DBusProxy.makeProxyWrapper(LoginManagerIface);
++
++let pkProxy = null;
++let pkOfflineProxy = null;
++let loginManagerProxy = null;
++let updatesDialog = null;
++let extensionSettings = null;
++let cancellable = null;
++
++let updatesCheckInProgress = false;
++let updatesCheckRequested = false;
++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));
++    }
++    return text;
++}
++
++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._lastWarningPeriod = settings.get_uint('last-warning-period');
++        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._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
++        });
++
++        let buttons = [{
++            action: this.close.bind(this),
++            label: _('Close'),
++            key: Clutter.Escape
++        }, {
++            action: this._done.bind(this),
++            label: _('Restart &amp; Install')
++        }];
++
++        this.setButtons(buttons);
++
++        this._openTimeoutId = 0;
++        this.connect('destroy', this._clearOpenTimeout.bind(this));
++
++        this._startTimer();
++    }
++
++    _clearOpenTimeout() {
++        if (this._openTimeoutId > 0) {
++            GLib.source_remove(this._openTimeoutId);
++            this._openTimeoutId = 0;
++        }
++    }
++
++    tryOpen() {
++        if (this._openTimeoutId > 0 || this.open())
++            return;
++
++        this._openTimeoutId = GLib.timeout_add_seconds(
++            GLib.PRIORITY_DEFAULT, 1, () => {
++                if (!this.open())
++                    return GLib.SOURCE_CONTINUE;
++
++                this._clearOpenTimeout();
++                return GLib.SOURCE_REMOVE;
++            });
++    }
++
++    _startTimer() {
++        this._secondsLeft = this._gracePeriod * 60;
++
++        this._timerId = GLib.timeout_add_seconds(
++            GLib.PRIORITY_DEFAULT, 1, () => {
++                this._secondsLeft -= 1;
++                let minutesLeft = this._secondsLeft / 60;
++                let periodLeft = Math.floor(minutesLeft);
++
++                if (this._secondsLeft == 60 ||
++                    (periodLeft > 0 && periodLeft <= this._lastWarningPeriod * this._lastWarnings &&
++                     minutesLeft % this._lastWarningPeriod == 0)) {
++                    this.tryOpen();
++                    this._detailLabel.text = getDetailText(periodLeft);
++                }
++
++                if (this._secondsLeft > 0) {
++                    if (this._secondsLeft < 60) {
++                        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);
++                    }
++                    return GLib.SOURCE_CONTINUE;
++                }
++
++                this._done();
++                return GLib.SOURCE_REMOVE;
++            });
++        this.connect('destroy', () => {
++            if (this._timerId > 0) {
++                GLib.source_remove(this._timerId);
++                this._timerId = 0;
++            }
++        });
++    }
++
++    _done() {
++        this.emit('done');
++        this.destroy();
++    }
++
++    getState() {
++        return [this._gracePeriod, this._lastWarningPeriod, this._lastWarnings, this._secondsLeft];
++    }
++
++    setState(state) {
++        [this._gracePeriod, this._lastWarningPeriod, this._lastWarnings, this._secondsLeft] = state;
++    }
++};
++Signals.addSignalMethods(UpdatesDialog.prototype);
++
++function showDialog() {
++    if (updatesDialog)
++        return;
++
++    updatesDialog = new UpdatesDialog(extensionSettings);
++    updatesDialog.tryOpen();
++    updatesDialog.connect('destroy', () => updatesDialog = null);
++    updatesDialog.connect('done', () => {
++        if (pkOfflineProxy.TriggerAction == 'power-off' ||
++            pkOfflineProxy.TriggerAction == 'reboot') {
++            loginManagerProxy.RebootRemote(false);
++        } else {
++            pkOfflineProxy.TriggerRemote('reboot', (result, error) => {
++                if (!error)
++                    loginManagerProxy.RebootRemote(false);
++                else
++                    log('Failed to trigger offline update: %s'.format(error.message));
++            });
++        }
++    });
++}
++
++function cancelDialog(save) {
++    if (!updatesDialog)
++        return;
++
++    if (save) {
++        let state = GLib.Variant.new('(uuuu)', updatesDialog.getState());
++        global.set_runtime_state(Me.uuid, state);
++    }
++    updatesDialog.destroy();
++}
++
++function restoreExistingState() {
++    let state = global.get_runtime_state('(uuuu)', Me.uuid);
++    if (state === null)
++        return false;
++
++    global.set_runtime_state(Me.uuid, null);
++    showDialog();
++    updatesDialog.setState(state.deep_unpack());
++    return true;
++}
++
++function syncState() {
++    if (!pkOfflineProxy || !loginManagerProxy)
++        return;
++
++    if (restoreExistingState())
++        return;
++
++    if (!updatesCheckInProgress &&
++        securityUpdates.length > 0 &&
++        pkOfflineProxy.UpdatePrepared)
++        showDialog();
++    else
++        cancelDialog();
++}
++
++function doPkTransaction(callback) {
++    if (!pkProxy)
++        return;
++
++    pkProxy.CreateTransactionRemote((result, error) => {
++        if (error) {
++            log('Error creating PackageKit transaction: %s'.format(error.message));
++            checkUpdatesDone();
++            return;
++        }
++
++        new PkTransactionProxy(Gio.DBus.system,
++            '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', (p, e, params) => {
++        let [exit, runtime_] = params;
++
++        if (exit == PkgKit.ExitEnum.CANCELLED_PRIORITY) {
++            // try again
++            checkUpdates();
++        } else if (exit != PkgKit.ExitEnum.SUCCESS) {
++            log('UpdatePackages failed: %s'.format(PkgKit.ExitEnum.to_string(exit)));
++        }
++
++        checkUpdatesDone();
++    });
++    proxy.UpdatePackagesRemote(1 << PkgKit.TransactionFlagEnum.ONLY_DOWNLOAD, securityUpdates);
++}
++
++function pkGetUpdates(proxy) {
++    proxy.connectSignal('Package', (p, e, params) => {
++        let [info, packageId, summary_] = params;
++
++        if (info == PkgKit.InfoEnum.SECURITY)
++            securityUpdates.push(packageId);
++    });
++    proxy.connectSignal('Finished', (p, e, params) => {
++        let [exit, runtime_] = params;
++
++        if (exit == PkgKit.ExitEnum.SUCCESS) {
++            if (securityUpdates.length > 0) {
++                doPkTransaction(pkUpdatePackages);
++                return;
++            }
++        } else if (exit == PkgKit.ExitEnum.CANCELLED_PRIORITY) {
++            // try again
++            checkUpdates();
++        } else {
++            log('GetUpdates failed: %s'.format(PkgKit.ExitEnum.to_string(exit)));
++        }
++
++        checkUpdatesDone();
++    });
++    proxy.GetUpdatesRemote(0);
++}
++
++function checkUpdatesDone() {
++    updatesCheckInProgress = false;
++    if (updatesCheckRequested) {
++        updatesCheckRequested = false;
++        checkUpdates();
++    } else {
++        syncState();
++    }
++}
++
++function checkUpdates() {
++    if (updatesCheckInProgress) {
++        updatesCheckRequested = true;
++        return;
++    }
++    updatesCheckInProgress = true;
++    securityUpdates = [];
++    doPkTransaction(pkGetUpdates);
++}
++
++function initSystemProxies() {
++    new PkProxy(Gio.DBus.system,
++        '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',
++        (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',
++        (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 = 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() {
++    cancelDialog(true);
++    cancellable.cancel();
++    cancellable = null;
++    extensionSettings = null;
++    updatesDialog = null;
++    loginManagerProxy = null;
++    if (pkOfflineProxy) {
++        pkOfflineProxy.disconnect(pkOfflineProxy._signalId);
++        pkOfflineProxy = null;
++    }
++    if (pkProxy) {
++        pkProxy.disconnectSignal(pkProxy._signalId);
++        pkProxy = null;
++    }
++}
+diff --git a/extensions/updates-dialog/meson.build b/extensions/updates-dialog/meson.build
+new file mode 100644
+index 0000000..585c02d
+--- /dev/null
++++ b/extensions/updates-dialog/meson.build
+@@ -0,0 +1,7 @@
++extension_data += configure_file(
++  input: metadata_name + '.in',
++  output: metadata_name,
++  configuration: metadata_conf
++)
++
++extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
+diff --git a/extensions/updates-dialog/metadata.json.in b/extensions/updates-dialog/metadata.json.in
+new file mode 100644
+index 0000000..9946abb
+--- /dev/null
++++ b/extensions/updates-dialog/metadata.json.in
+@@ -0,0 +1,10 @@
++{
++"extension-id": "@extension_id@",
++"uuid": "@uuid@",
++"settings-schema": "@gschemaname@",
++"gettext-domain": "@gettext_domain@",
++"name": "Updates Dialog",
++"description": "Shows a modal dialog when there are software updates.",
++"shell-version": [ "@shell_current@" ],
++"url": "http://rtcm.fedorapeople.org/updates-dialog"
++}
+diff --git a/extensions/updates-dialog/org.gnome.shell.extensions.updates-dialog.gschema.xml b/extensions/updates-dialog/org.gnome.shell.extensions.updates-dialog.gschema.xml
+new file mode 100644
+index 0000000..c08d33c
+--- /dev/null
++++ b/extensions/updates-dialog/org.gnome.shell.extensions.updates-dialog.gschema.xml
+@@ -0,0 +1,30 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<schemalist>
++  <schema path="/org/gnome/shell/extensions/updates-dialog/"
++          id="org.gnome.shell.extensions.updates-dialog">
++    <key name="grace-period" type="u">
++      <default>300</default>
++      <summary>Grace period in minutes</summary>
++      <description>
++        When the grace period is over, the computer will automatically
++        reboot and install security updates.
++      </description>
++    </key>
++    <key name="last-warning-period" type="u">
++      <default>10</default>
++      <summary>Last warning dialog period</summary>
++      <description>
++        A last warning dialog is displayed this many minutes before
++        the automatic reboot.
++      </description>
++    </key>
++    <key name="last-warnings" type="u">
++      <default>1</default>
++      <summary>Number of last warning dialogs</summary>
++      <description>
++        How many warning dialogs are displayed. Each is displayed at
++        'last-warning-period' minute intervals.
++      </description>
++    </key>
++  </schema>
++</schemalist>
+diff --git a/extensions/updates-dialog/stylesheet.css b/extensions/updates-dialog/stylesheet.css
+new file mode 100644
+index 0000000..25134b6
+--- /dev/null
++++ b/extensions/updates-dialog/stylesheet.css
+@@ -0,0 +1 @@
++/* This extensions requires no special styling */
+diff --git a/meson.build b/meson.build
+index e8e00dc..d129e6c 100644
+--- a/meson.build
++++ b/meson.build
+@@ -53,6 +53,7 @@ all_extensions += [
+   'native-window-placement',
+   'panel-favorites',
+   'top-icons',
++  'updates-dialog',
+   'user-theme'
+ ]
+ 
+diff --git a/po/POTFILES.in b/po/POTFILES.in
+index 9c1438a..55f0e9a 100644
+--- a/po/POTFILES.in
++++ b/po/POTFILES.in
+@@ -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
++extensions/updates-dialog/extension.js
++extensions/updates-dialog/org.gnome.shell.extensions.updates-dialog.gschema.xml
+ extensions/user-theme/extension.js
+ extensions/user-theme/org.gnome.shell.extensions.user-theme.gschema.xml
+ extensions/window-list/extension.js
+-- 
+2.21.1
+
+
+From 0ba4b86fa5f73bccd3ab1984d9deef0d39f656c6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Thu, 1 Jun 2017 23:57:14 +0200
+Subject: [PATCH 5/8] Add no-hot-corner extension
+
+---
+ extensions/no-hot-corner/extension.js     | 31 +++++++++++++++++++++++
+ extensions/no-hot-corner/meson.build      |  5 ++++
+ extensions/no-hot-corner/metadata.json.in |  9 +++++++
+ extensions/no-hot-corner/stylesheet.css   |  1 +
+ meson.build                               |  1 +
+ 5 files changed, 47 insertions(+)
+ create mode 100644 extensions/no-hot-corner/extension.js
+ create mode 100644 extensions/no-hot-corner/meson.build
+ create mode 100644 extensions/no-hot-corner/metadata.json.in
+ create mode 100644 extensions/no-hot-corner/stylesheet.css
+
+diff --git a/extensions/no-hot-corner/extension.js b/extensions/no-hot-corner/extension.js
+new file mode 100644
+index 0000000..e7a0d63
+--- /dev/null
++++ b/extensions/no-hot-corner/extension.js
+@@ -0,0 +1,31 @@
++const Main = imports.ui.main;
++
++let _id;
++
++function _disableHotCorners() {
++  // Disables all hot corners
++  Main.layoutManager.hotCorners.forEach(function(hotCorner) {
++    if (!hotCorner) {
++      return;
++    }
++
++    hotCorner._toggleOverview = function() {};
++    hotCorner._pressureBarrier._trigger = function() {};
++  });
++}
++
++function init() {
++}
++
++function enable() {
++  _disableHotCorners();
++  // Hot corners may be re-created afterwards (for example, If there's a monitor change).
++  // So we catch all changes.
++  _id = Main.layoutManager.connect('hot-corners-changed', _disableHotCorners);
++}
++
++function disable() {
++  // Disconnects the callback and re-creates the hot corners
++  Main.layoutManager.disconnect(_id);
++  Main.layoutManager._updateHotCorners();
++}
+diff --git a/extensions/no-hot-corner/meson.build b/extensions/no-hot-corner/meson.build
+new file mode 100644
+index 0000000..48504f6
+--- /dev/null
++++ b/extensions/no-hot-corner/meson.build
+@@ -0,0 +1,5 @@
++extension_data += configure_file(
++  input: metadata_name + '.in',
++  output: metadata_name,
++  configuration: metadata_conf
++)
+diff --git a/extensions/no-hot-corner/metadata.json.in b/extensions/no-hot-corner/metadata.json.in
+new file mode 100644
+index 0000000..406d83b
+--- /dev/null
++++ b/extensions/no-hot-corner/metadata.json.in
+@@ -0,0 +1,9 @@
++{
++"extension-id": "@extension_id@",
++"uuid": "@uuid@",
++"name": "No Topleft Hot Corner",
++"description": "Disable the hot corner in the top left; you can still reach the overview by clicking the Activities button or pressing the dedicated key.",
++"shell-version": [ "@shell_current@" ],
++"url": "https://github.com/HROMANO/nohotcorner/",
++"version": 15
++}
+diff --git a/extensions/no-hot-corner/stylesheet.css b/extensions/no-hot-corner/stylesheet.css
+new file mode 100644
+index 0000000..25134b6
+--- /dev/null
++++ b/extensions/no-hot-corner/stylesheet.css
+@@ -0,0 +1 @@
++/* This extensions requires no special styling */
+diff --git a/meson.build b/meson.build
+index d129e6c..6f27f46 100644
+--- a/meson.build
++++ b/meson.build
+@@ -51,6 +51,7 @@ all_extensions += [
+   'auto-move-windows',
+   'dash-to-dock',
+   'native-window-placement',
++  'no-hot-corner',
+   'panel-favorites',
+   'top-icons',
+   'updates-dialog',
+-- 
+2.21.1
+
+
+From f56b4374904cdfd8e1790dc3cf5080b60f30ebea Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+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 @@
++<schemalist gettext-domain="gnome-shell-extensions">
++  <schema id="org.gnome.shell.extensions.window-grouper" path="/org/gnome/shell/extensions/window-grouper/">
++    <key name="application-list" type="as">
++      <default>[ ]</default>
++      <summary>Application that should be grouped</summary>
++      <description>A list of application ids</description>
++    </key>
++  </schema>
++</schemalist>
+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.1
+
+
+From 25c4999ff6adf19a32bab2a4d6cccae42520563b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+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.1
+
+
+From 59604979f6ba48b7ff8d1616ab9df739dcf46a20 Mon Sep 17 00:00:00 2001
+From: Carlos Soriano <csoriano@gnome.org>
+Date: Mon, 13 Aug 2018 17:28:41 +0200
+Subject: [PATCH 8/8] Add desktop icons extension
+
+---
+ .../desktop-icons/createFolderDialog.js       | 164 ++++
+ extensions/desktop-icons/createThumbnail.js   |  35 +
+ extensions/desktop-icons/dbusUtils.js         | 103 +++
+ extensions/desktop-icons/desktopGrid.js       | 692 +++++++++++++++
+ extensions/desktop-icons/desktopIconsUtil.js  | 123 +++
+ extensions/desktop-icons/desktopManager.js    | 754 ++++++++++++++++
+ extensions/desktop-icons/extension.js         |  71 ++
+ extensions/desktop-icons/fileItem.js          | 830 ++++++++++++++++++
+ extensions/desktop-icons/meson.build          |  19 +
+ extensions/desktop-icons/metadata.json.in     |  11 +
+ extensions/desktop-icons/po/LINGUAS           |  19 +
+ extensions/desktop-icons/po/POTFILES.in       |   4 +
+ 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/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/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       |  38 +
+ meson.build                                   |   1 +
+ po/ca.po                                      | 194 ++++
+ po/cs.po                                      | 198 +++++
+ po/da.po                                      | 194 ++++
+ po/de.po                                      | 195 ++++
+ po/en_GB.po                                   | 204 ++++-
+ po/es.po                                      | 243 ++++-
+ po/fi.po                                      | 209 ++++-
+ po/fr.po                                      | 167 ++++
+ po/fur.po                                     | 198 ++++-
+ po/hr.po                                      | 195 ++++
+ po/hu.po                                      | 195 ++++
+ po/id.po                                      | 197 +++++
+ po/it.po                                      | 192 ++++
+ po/ja.po                                      | 210 ++++-
+ po/nl.po                                      | 191 ++++
+ po/pl.po                                      | 196 +++++
+ po/pt_BR.po                                   | 216 ++++-
+ po/ru.po                                      | 156 ++++
+ po/sv.po                                      | 204 +++++
+ po/tr.po                                      | 194 ++++
+ po/zh_TW.po                                   | 149 +++-
+ 58 files changed, 10608 insertions(+), 48 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
+ create mode 100644 extensions/desktop-icons/desktopIconsUtil.js
+ create mode 100644 extensions/desktop-icons/desktopManager.js
+ create mode 100644 extensions/desktop-icons/extension.js
+ create mode 100644 extensions/desktop-icons/fileItem.js
+ create mode 100644 extensions/desktop-icons/meson.build
+ create mode 100644 extensions/desktop-icons/metadata.json.in
+ create mode 100644 extensions/desktop-icons/po/LINGUAS
+ create mode 100644 extensions/desktop-icons/po/POTFILES.in
+ create mode 100644 extensions/desktop-icons/po/cs.po
+ create mode 100644 extensions/desktop-icons/po/da.po
+ create mode 100644 extensions/desktop-icons/po/de.po
+ 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/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 <andrea.azzarone@canonical.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++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
+@@ -0,0 +1,35 @@
++#!/usr/bin/gjs
++
++/* Desktop Icons GNOME Shell extension
++ *
++ * Copyright (C) 2018 Sergio Costas <rastersoft@gmail.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++const GnomeDesktop = imports.gi.GnomeDesktop;
++const Gio = imports.gi.Gio;
++
++let thumbnailFactory = GnomeDesktop.DesktopThumbnailFactory.new(GnomeDesktop.DesktopThumbnailSize.LARGE);
++
++let file = Gio.File.new_for_path(ARGV[0]);
++let fileUri = file.get_uri();
++
++let fileInfo = file.query_info('standard::content-type,time::modified', Gio.FileQueryInfoFlags.NONE, null);
++let modifiedTime = fileInfo.get_attribute_uint64('time::modified');
++let thumbnailPixbuf = thumbnailFactory.generate_thumbnail(fileUri, fileInfo.get_content_type());
++if (thumbnailPixbuf == null)
++    thumbnailFactory.create_failed_thumbnail(fileUri, modifiedTime);
++else
++    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..19fe987
+--- /dev/null
++++ b/extensions/desktop-icons/dbusUtils.js
+@@ -0,0 +1,103 @@
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++var NautilusFileOperationsProxy;
++var FreeDesktopFileManagerProxy;
++
++const NautilusFileOperationsInterface = `<node>
++<interface name='org.gnome.Nautilus.FileOperations'>
++    <method name='CopyURIs'>
++        <arg name='URIs' type='as' direction='in'/>
++        <arg name='Destination' type='s' direction='in'/>
++    </method>
++    <method name='MoveURIs'>
++        <arg name='URIs' type='as' direction='in'/>
++        <arg name='Destination' type='s' direction='in'/>
++    </method>
++    <method name='EmptyTrash'>
++    </method>
++    <method name='TrashFiles'>
++        <arg name='URIs' type='as' direction='in'/>
++    </method>
++    <method name='CreateFolder'>
++        <arg name='URI' type='s' direction='in'/>
++    </method>
++    <method name='RenameFile'>
++        <arg name='URI' type='s' direction='in'/>
++        <arg name='NewName' type='s' direction='in'/>
++    </method>
++    <method name='Undo'>
++    </method>
++    <method name='Redo'>
++    </method>
++    <property name='UndoStatus' type='i' access='read'/>
++</interface>
++</node>`;
++
++const NautilusFileOperationsProxyInterface = Gio.DBusProxy.makeProxyWrapper(NautilusFileOperationsInterface);
++
++const FreeDesktopFileManagerInterface = `<node>
++<interface name='org.freedesktop.FileManager1'>
++    <method name='ShowItems'>
++        <arg name='URIs' type='as' direction='in'/>
++        <arg name='StartupId' type='s' direction='in'/>
++    </method>
++    <method name='ShowItemProperties'>
++        <arg name='URIs' type='as' direction='in'/>
++        <arg name='StartupId' type='s' direction='in'/>
++    </method>
++</interface>
++</node>`;
++
++const FreeDesktopFileManagerProxyInterface = Gio.DBusProxy.makeProxyWrapper(FreeDesktopFileManagerInterface);
++
++function init() {
++    NautilusFileOperationsProxy = new NautilusFileOperationsProxyInterface(
++        Gio.DBus.session,
++        'org.gnome.Nautilus',
++        '/org/gnome/Nautilus',
++        (proxy, error) => {
++            if (error) {
++                log('Error connecting to Nautilus');
++            }
++        }
++    );
++
++    FreeDesktopFileManagerProxy = new FreeDesktopFileManagerProxyInterface(
++        Gio.DBus.session,
++        'org.freedesktop.FileManager1',
++        '/org/freedesktop/FileManager1',
++        (proxy, error) => {
++            if (error) {
++                log('Error connecting to Nautilus');
++            }
++        }
++    );
++}
++
++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..a2d1f12
+--- /dev/null
++++ b/extensions/desktop-icons/desktopGrid.js
+@@ -0,0 +1,692 @@
++/* Desktop Icons GNOME Shell extension
++ *
++ * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++const Gtk = imports.gi.Gtk;
++const Clutter = imports.gi.Clutter;
++const St = imports.gi.St;
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++const Shell = imports.gi.Shell;
++
++const Signals = imports.signals;
++
++const Layout = imports.ui.layout;
++const Main = imports.ui.main;
++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;
++const DBusUtils = Me.imports.dbusUtils;
++const DesktopIconsUtil = Me.imports.desktopIconsUtil;
++const Util = imports.misc.util;
++
++const Clipboard = St.Clipboard.get_default();
++const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD;
++const Gettext = imports.gettext.domain('desktop-icons');
++
++const _ = Gettext.gettext;
++
++
++/* From NautilusFileUndoManagerState */
++var UndoStatus = {
++    NONE: 0,
++    UNDO: 1,
++    REDO: 2,
++};
++
++var StoredCoordinates = {
++    PRESERVE: 0,
++    OVERWRITE:1,
++    ASSIGN:2,
++};
++
++class Placeholder extends St.Bin {
++    constructor() {
++        super();
++    }
++}
++
++var DesktopGrid = class {
++
++    constructor(bgManager) {
++        this._bgManager = bgManager;
++
++        this._fileItemHandlers = new Map();
++        this._fileItems = [];
++
++        this.layout = new Clutter.GridLayout({
++            orientation: Clutter.Orientation.VERTICAL,
++            column_homogeneous: true,
++            row_homogeneous: true
++        });
++
++        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({
++            name: 'DesktopGrid',
++            layout_manager: this.layout,
++            reactive: true,
++            x_expand: true,
++            y_expand: true,
++            can_focus: true,
++            opacity: 255
++        });
++        this.actor.add_child(this._grid);
++
++        this._renamePopup = new RenamePopup(this);
++        this.actor.add_child(this._renamePopup.actor);
++
++        this._bgManager._container.add_child(this.actor);
++
++        this.actor.connect('destroy', () => this._onDestroy());
++
++        let monitorIndex = bgManager._monitorIndex;
++        this._monitorConstraint = new Layout.MonitorConstraint({
++            index: monitorIndex,
++            work_area: true
++        });
++        this.actor.add_constraint(this._monitorConstraint);
++
++        this._addDesktopBackgroundMenu();
++
++        this._bgDestroyedId = bgManager.backgroundActor.connect('destroy',
++            () => this._backgroundDestroyed());
++
++        this._grid.connect('button-press-event', (actor, event) => this._onPressButton(actor, event));
++
++        this._grid.connect('key-press-event', this._onKeyPress.bind(this));
++
++        this._grid.connect('allocation-changed', () => Extension.desktopManager.scheduleReLayoutChildren());
++    }
++
++    _onKeyPress(actor, event) {
++        if (global.stage.get_key_focus() != actor)
++            return Clutter.EVENT_PROPAGATE;
++
++        let symbol = event.get_key_symbol();
++        let isCtrl = (event.get_state() & Clutter.ModifierType.CONTROL_MASK) != 0;
++        let isShift = (event.get_state() & Clutter.ModifierType.SHIFT_MASK) != 0;
++        if (isCtrl && isShift && [Clutter.Z, Clutter.z].indexOf(symbol) > -1) {
++            this._doRedo();
++            return Clutter.EVENT_STOP;
++        }
++        else if (isCtrl && [Clutter.Z, Clutter.z].indexOf(symbol) > -1) {
++            this._doUndo();
++            return Clutter.EVENT_STOP;
++        }
++        else if (isCtrl && [Clutter.C, Clutter.c].indexOf(symbol) > -1) {
++            Extension.desktopManager.doCopy();
++            return Clutter.EVENT_STOP;
++        }
++        else if (isCtrl && [Clutter.X, Clutter.x].indexOf(symbol) > -1) {
++            Extension.desktopManager.doCut();
++            return Clutter.EVENT_STOP;
++        }
++        else if (isCtrl && [Clutter.V, Clutter.v].indexOf(symbol) > -1) {
++            this._doPaste();
++            return Clutter.EVENT_STOP;
++        }
++        else if (symbol == Clutter.Return) {
++            Extension.desktopManager.doOpen();
++            return Clutter.EVENT_STOP;
++        }
++        else if (symbol == Clutter.Delete) {
++            Extension.desktopManager.doTrash();
++            return Clutter.EVENT_STOP;
++        } else if (symbol == Clutter.F2) {
++            // Support renaming other grids file items.
++            Extension.desktopManager.doRename();
++            return Clutter.EVENT_STOP;
++        }
++
++        return Clutter.EVENT_PROPAGATE;
++    }
++
++    _backgroundDestroyed() {
++        this._bgDestroyedId = 0;
++        if (this._bgManager == null)
++            return;
++
++        if (this._bgManager._backgroundSource) {
++            this._bgDestroyedId = this._bgManager.backgroundActor.connect('destroy',
++                () => this._backgroundDestroyed());
++        } else {
++            this.actor.destroy();
++        }
++    }
++
++    _onDestroy() {
++        if (this._bgDestroyedId && this._bgManager.backgroundActor != null)
++            this._bgManager.backgroundActor.disconnect(this._bgDestroyedId);
++        this._bgDestroyedId = 0;
++        this._bgManager = null;
++    }
++
++    _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;
++
++        if (mime != 'x-special/nautilus-clipboard')
++            return [false, false, null];
++
++        if (!(['copy', 'cut'].includes(action)))
++            return [false, false, null];
++        let isCut = action == 'cut';
++
++        /* Last line is empty due to the split */
++        if (files.length <= 1)
++            return [false, false, null];
++        /* Remove last line */
++        files.pop();
++
++        return [true, isCut, files];
++    }
++
++    _doPaste() {
++        Clipboard.get_text(CLIPBOARD_TYPE,
++            (clipboard, text) => {
++                let [valid, is_cut, files] = this._parseClipboardText(text);
++                if (!valid)
++                    return;
++
++                let desktopDir = `${DesktopIconsUtil.getDesktopDir().get_uri()}`;
++                if (is_cut) {
++                    DBusUtils.NautilusFileOperationsProxy.MoveURIsRemote(files, desktopDir,
++                        (result, error) => {
++                            if (error)
++                                throw new Error('Error moving files: ' + error.message);
++                        }
++                    );
++                } else {
++                    DBusUtils.NautilusFileOperationsProxy.CopyURIsRemote(files, desktopDir,
++                        (result, error) => {
++                            if (error)
++                                throw new Error('Error copying files: ' + error.message);
++                        }
++                    );
++                }
++            }
++        );
++    }
++
++    _onPasteClicked() {
++        this._doPaste();
++    }
++
++    _doUndo() {
++        DBusUtils.NautilusFileOperationsProxy.UndoRemote(
++            (result, error) => {
++                if (error)
++                    throw new Error('Error performing undo: ' + error.message);
++            }
++        );
++    }
++
++    _onUndoClicked() {
++        this._doUndo();
++    }
++
++    _doRedo() {
++        DBusUtils.NautilusFileOperationsProxy.RedoRemote(
++            (result, error) => {
++                if (error)
++                    throw new Error('Error performing redo: ' + error.message);
++            }
++        );
++    }
++
++    _onRedoClicked() {
++        this._doRedo();
++    }
++
++    _onOpenDesktopInFilesClicked() {
++        Gio.AppInfo.launch_default_for_uri_async(DesktopIconsUtil.getDesktopDir().get_uri(),
++            null, null,
++            (source, result) => {
++                try {
++                    Gio.AppInfo.launch_default_for_uri_finish(result);
++                } catch (e) {
++                   log('Error opening Desktop in Files: ' + e.message);
++                }
++            }
++        );
++    }
++
++    _onOpenTerminalClicked() {
++        let desktopPath = DesktopIconsUtil.getDesktopDir().get_path();
++        DesktopIconsUtil.launchTerminal(desktopPath);
++    }
++
++    _syncUndoRedo() {
++        this._undoMenuItem.actor.visible = DBusUtils.NautilusFileOperationsProxy.UndoStatus == UndoStatus.UNDO;
++        this._redoMenuItem.actor.visible = DBusUtils.NautilusFileOperationsProxy.UndoStatus == UndoStatus.REDO;
++    }
++
++    _undoStatusChanged(proxy, properties, test) {
++        if ('UndoStatus' in properties.deep_unpack())
++            this._syncUndoRedo();
++    }
++
++    _createDesktopBackgroundMenu() {
++        let menu = new PopupMenu.PopupMenu(Main.layoutManager.dummyCursor,
++                                           0, St.Side.TOP);
++        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());
++        this._redoMenuItem = menu.addAction(_("Redo"), () => this._onRedoClicked());
++        menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++        menu.addAction(_("Show Desktop in Files"), () => this._onOpenDesktopInFilesClicked());
++        menu.addAction(_("Open in Terminal"), () => this._onOpenTerminalClicked());
++        menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++        menu.addSettingsAction(_("Change Background…"), 'gnome-background-panel.desktop');
++        menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++        menu.addSettingsAction(_("Display Settings"), 'gnome-display-panel.desktop');
++        menu.addSettingsAction(_("Settings"), 'gnome-control-center.desktop');
++
++        menu.actor.add_style_class_name('background-menu');
++
++        Main.layoutManager.uiGroup.add_child(menu.actor);
++        menu.actor.hide();
++
++        menu._propertiesChangedId = DBusUtils.NautilusFileOperationsProxy.connect('g-properties-changed',
++            this._undoStatusChanged.bind(this));
++        this._syncUndoRedo();
++
++        menu.connect('destroy',
++            () => DBusUtils.NautilusFileOperationsProxy.disconnect(menu._propertiesChangedId));
++        menu.connect('open-state-changed',
++            (popupm, isOpen) => {
++                if (isOpen) {
++                    Clipboard.get_text(CLIPBOARD_TYPE,
++                        (clipBoard, text) => {
++                            let [valid, is_cut, files] = this._parseClipboardText(text);
++                            this._pasteMenuItem.setSensitive(valid);
++                        }
++                    );
++                }
++            }
++        );
++        this._pasteMenuItem.setSensitive(false);
++
++        return menu;
++    }
++
++    _openMenu(x, y) {
++        Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
++        this.actor._desktopBackgroundMenu.open(BoxPointer.PopupAnimation.NONE);
++        /* Since the handler is in the press event it needs to ignore the release event
++         * to not immediately close the menu on release
++         */
++        this.actor._desktopBackgroundManager.ignoreRelease();
++    }
++
++    _addFileItemTo(fileItem, column, row, coordinatesAction) {
++        let placeholder = this.layout.get_child_at(column, row);
++        placeholder.child = fileItem.actor;
++        this._fileItems.push(fileItem);
++        let selectedId = fileItem.connect('selected', this._onFileItemSelected.bind(this));
++        let renameId = fileItem.connect('rename-clicked', this.doRename.bind(this));
++        this._fileItemHandlers.set(fileItem, [selectedId, renameId]);
++
++        /* If this file is new in the Desktop and hasn't yet
++         * fixed coordinates, store the new possition to ensure
++         * that the next time it will be shown in the same possition.
++         * Also store the new possition if it has been moved by the user,
++         * and not triggered by a screen change.
++         */
++        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, coordinatesAction) {
++        let [column, row] = this._getEmptyPlaceClosestTo(x, y, coordinatesAction);
++        this._addFileItemTo(fileItem, column, row, coordinatesAction);
++    }
++
++    _getEmptyPlaceClosestTo(x, y, coordinatesAction) {
++        let maxColumns = this._getMaxColumns();
++        let maxRows = this._getMaxRows();
++
++        let [actorX, actorY] = this._grid.get_transformed_position();
++        let actorWidth = this._grid.allocation.x2 - this._grid.allocation.x1;
++        let actorHeight = this._grid.allocation.y2 - this._grid.allocation.y1;
++        let placeX = Math.round((x - actorX) * maxColumns / actorWidth);
++        let placeY = Math.round((y - actorY) * maxRows / actorHeight);
++
++        placeX = DesktopIconsUtil.clamp(placeX, 0, maxColumns - 1);
++        placeY = DesktopIconsUtil.clamp(placeY, 0, maxRows - 1);
++        if (this.layout.get_child_at(placeX, placeY).child == null)
++            return [placeX, placeY];
++        let found = false;
++        let resColumn = null;
++        let resRow = null;
++        let minDistance = Infinity;
++        for (let column = 0; column < maxColumns; column++) {
++            for (let row = 0; row < maxRows; row++) {
++                let placeholder = this.layout.get_child_at(column, row);
++                if (placeholder.child != null)
++                    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;
++                    minDistance = distance;
++                    resColumn = column;
++                    resRow = row;
++                }
++            }
++        }
++
++        if (!found)
++            throw new Error(`Not enough place at monitor ${this._bgManager._monitorIndex}`);
++
++        return [resColumn, resRow];
++    }
++
++    removeFileItem(fileItem) {
++        let index = this._fileItems.indexOf(fileItem);
++        if (index > -1)
++            this._fileItems.splice(index, 1);
++        else
++            throw new Error('Error removing children from container');
++
++        let [column, row] = this._getPosOfFileItem(fileItem);
++        let placeholder = this.layout.get_child_at(column, row);
++        placeholder.child = null;
++        let [selectedId, renameId] = this._fileItemHandlers.get(fileItem);
++        fileItem.disconnect(selectedId);
++        fileItem.disconnect(renameId);
++        this._fileItemHandlers.delete(fileItem);
++    }
++
++    _fillPlaceholders() {
++        for (let column = 0; column < this._getMaxColumns(); column++) {
++            for (let row = 0; row < this._getMaxRows(); row++) {
++                this.layout.attach(new Placeholder(), column, row, 1, 1);
++            }
++        }
++    }
++
++    reset() {
++        let tmpFileItemsCopy = this._fileItems.slice();
++        for (let fileItem of tmpFileItemsCopy)
++            this.removeFileItem(fileItem);
++        this._grid.remove_all_children();
++
++        this._fillPlaceholders();
++    }
++
++    _onStageMotion(actor, event) {
++        if (this._drawingRubberBand) {
++            let [x, y] = event.get_coords();
++            this._updateRubberBand(x, y);
++            this._selectFromRubberband(x, y);
++        }
++        return Clutter.EVENT_PROPAGATE;
++    }
++
++    _onPressButton(actor, event) {
++        let button = event.get_button();
++        let [x, y] = event.get_coords();
++
++        this._grid.grab_key_focus();
++
++        if (button == 1) {
++            let shiftPressed = !!(event.get_state() & Clutter.ModifierType.SHIFT_MASK);
++            let controlPressed = !!(event.get_state() & Clutter.ModifierType.CONTROL_MASK);
++            if (!shiftPressed && !controlPressed)
++                Extension.desktopManager.clearSelection();
++            let [gridX, gridY] = this._grid.get_transformed_position();
++            Extension.desktopManager.startRubberBand(x, y, gridX, gridY);
++            return Clutter.EVENT_STOP;
++        }
++
++        if (button == 3) {
++            this._openMenu(x, y);
++
++            return Clutter.EVENT_STOP;
++        }
++
++        return Clutter.EVENT_PROPAGATE;
++    }
++
++    _addDesktopBackgroundMenu() {
++        this.actor._desktopBackgroundMenu = this._createDesktopBackgroundMenu();
++        this.actor._desktopBackgroundManager = new PopupMenu.PopupMenuManager({ actor: this.actor });
++        this.actor._desktopBackgroundManager.addMenu(this.actor._desktopBackgroundMenu);
++
++        this.actor.connect('destroy', () => {
++            this.actor._desktopBackgroundMenu.destroy();
++            this.actor._desktopBackgroundMenu = null;
++            this.actor._desktopBackgroundManager = null;
++        });
++    }
++
++    _getMaxColumns() {
++        let gridWidth = this._grid.allocation.x2 - this._grid.allocation.x1;
++        return Math.floor(gridWidth / Prefs.get_desired_width(St.ThemeContext.get_for_stage(global.stage).scale_factor));
++    }
++
++    _getMaxRows() {
++        let gridHeight = this._grid.allocation.y2 - this._grid.allocation.y1;
++        return Math.floor(gridHeight / Prefs.get_desired_height(St.ThemeContext.get_for_stage(global.stage).scale_factor));
++    }
++
++    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.actor.get_transformed_position();
++        let [absoluteX, absoluteY] = [x + gridX, y + gridY];
++        return Extension.desktopManager.acceptDrop(absoluteX, absoluteY);
++    }
++
++    _getPosOfFileItem(itemToFind) {
++        if (itemToFind == null)
++            throw new Error('Error at _getPosOfFileItem: child cannot be null');
++
++        let found = false;
++        let maxColumns = this._getMaxColumns();
++        let maxRows = this._getMaxRows();
++        let column = 0;
++        let row = 0;
++        for (column = 0; column < maxColumns; column++) {
++            for (row = 0; row < maxRows; row++) {
++                let item = this.layout.get_child_at(column, row);
++                if (item.child && item.child._delegate.file.equal(itemToFind.file)) {
++                    found = true;
++                    break;
++                }
++            }
++
++            if (found)
++                break;
++        }
++
++        if (!found)
++            throw new Error('Position of file item was not found');
++
++        return [column, row];
++    }
++
++    _onFileItemSelected(fileItem, keepCurrentSelection, addToSelection) {
++        this._grid.grab_key_focus();
++    }
++
++    doRename(fileItem) {
++        this._renamePopup.onFileItemRenameClicked(fileItem);
++    }
++};
++
++var RenamePopup = class {
++
++    constructor(grid) {
++        this._source = null;
++        this._isOpen = false;
++
++        this._renameEntry = new St.Entry({ hint_text: _("Enter file name…"),
++                                           can_focus: true,
++                                           x_expand: true });
++        this._renameEntry.clutter_text.connect('activate', this._onRenameAccepted.bind(this));
++        this._renameOkButton= new St.Button({ label: _("OK"),
++                                              style_class: 'app-view-control button',
++                                              button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
++                                              reactive: true,
++                                              can_focus: true,
++                                              x_expand: true });
++        this._renameCancelButton = new St.Button({ label: _("Cancel"),
++                                                   style_class: 'app-view-control button',
++                                                   button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
++                                                   reactive: true,
++                                                   can_focus: true,
++                                                   x_expand: true });
++        this._renameCancelButton.connect('clicked', () => { this._onRenameCanceled(); });
++        this._renameOkButton.connect('clicked', () => { this._onRenameAccepted(); });
++        let renameButtonsBoxLayout = new Clutter.BoxLayout({ homogeneous: true });
++        let renameButtonsBox = new St.Widget({ layout_manager: renameButtonsBoxLayout,
++                                               x_expand: true });
++        renameButtonsBox.add_child(this._renameCancelButton);
++        renameButtonsBox.add_child(this._renameOkButton);
++
++        let renameContentLayout = new Clutter.BoxLayout({ spacing: 6,
++                                                          orientation: Clutter.Orientation.VERTICAL });
++        let renameContent = new St.Widget({ style_class: 'rename-popup',
++                                            layout_manager: renameContentLayout,
++                                            x_expand: true });
++        renameContent.add_child(this._renameEntry);
++        renameContent.add_child(renameButtonsBox);
++
++        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');
++        this.actor.visible = false;
++        this._boxPointer.bin.set_child(renameContent);
++
++        this._grabHelper = new GrabHelper.GrabHelper(grid.actor, { actionMode: Shell.ActionMode.POPUP });
++        this._grabHelper.addActor(this.actor);
++    }
++
++    _popup() {
++        if (this._isOpen)
++            return;
++
++        this._isOpen = this._grabHelper.grab({ actor: this.actor,
++                                               onUngrab: this._popdown.bind(this) });
++
++        if (!this._isOpen) {
++            this._grabHelper.ungrab({ actor: this.actor });
++            return;
++        }
++
++        this._boxPointer.setPosition(this._source.actor, 0.5);
++        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);
++    }
++
++    _popdown() {
++        if (!this._isOpen)
++            return;
++
++        this._grabHelper.ungrab({ actor: this.actor });
++
++        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);
++    }
++
++    onFileItemRenameClicked(fileItem) {
++        this._source = fileItem;
++
++        this._renameEntry.text = fileItem.displayName;
++
++        this._popup();
++        this._renameEntry.grab_key_focus();
++        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() {
++        this._popdown();
++        DBusUtils.NautilusFileOperationsProxy.RenameFileRemote(this._source.file.get_uri(),
++                                                               this._renameEntry.get_text(),
++            (result, error) => {
++                if (error)
++                    throw new Error('Error renaming file: ' + error.message);
++            }
++        );
++    }
++
++    _onRenameCanceled() {
++        this._popdown();
++    }
++};
++Signals.addSignalMethods(RenamePopup.prototype);
+diff --git a/extensions/desktop-icons/desktopIconsUtil.js b/extensions/desktop-icons/desktopIconsUtil.js
+new file mode 100644
+index 0000000..0aea654
+--- /dev/null
++++ b/extensions/desktop-icons/desktopIconsUtil.js
+@@ -0,0 +1,123 @@
++/* Desktop Icons GNOME Shell extension
++ *
++ * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++const Gtk = imports.gi.Gtk;
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++const Prefs = Me.imports.prefs;
++
++const TERMINAL_SCHEMA = 'org.gnome.desktop.default-applications.terminal';
++const EXEC_KEY = 'exec';
++
++var DEFAULT_ATTRIBUTES = 'metadata::*,standard::*,access::*,time::modified,unix::mode';
++
++function getDesktopDir() {
++    let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
++    return Gio.File.new_for_commandline_arg(desktopPath);
++}
++
++function clamp(value, min, max) {
++    return Math.max(Math.min(value, max), min);
++};
++
++function launchTerminal(workdir) {
++    let terminalSettings = new Gio.Settings({ schema_id: TERMINAL_SCHEMA });
++    let exec = terminalSettings.get_string(EXEC_KEY);
++    let argv = [exec, `--working-directory=${workdir}`];
++
++    /* 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) {
++    return (Math.pow(x - x2, 2) + Math.pow(y - y2, 2));
++}
++
++function getExtraFolders() {
++    let extraFolders = new Array();
++    if (Prefs.settings.get_boolean('show-home')) {
++        extraFolders.push([Gio.File.new_for_commandline_arg(GLib.get_home_dir()), Prefs.FileType.USER_DIRECTORY_HOME]);
++    }
++    if (Prefs.settings.get_boolean('show-trash')) {
++        extraFolders.push([Gio.File.new_for_uri('trash:///'), Prefs.FileType.USER_DIRECTORY_TRASH]);
++    }
++    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..399aee0
+--- /dev/null
++++ b/extensions/desktop-icons/desktopManager.js
+@@ -0,0 +1,754 @@
++/* Desktop Icons GNOME Shell extension
++ *
++ * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++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 St = imports.gi.St;
++const Mainloop = imports.mainloop;
++const Meta = imports.gi.Meta;
++
++const Animation = imports.ui.animation;
++const Background = imports.ui.background;
++const DND = imports.ui.dnd;
++const Main = imports.ui.main;
++const GrabHelper = imports.ui.grabHelper;
++
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++const Extension = Me.imports.extension;
++const DesktopGrid = Me.imports.desktopGrid;
++const FileItem = Me.imports.fileItem;
++const Prefs = Me.imports.prefs;
++const DBusUtils = Me.imports.dbusUtils;
++const DesktopIconsUtil = Me.imports.desktopIconsUtil;
++
++const Clipboard = St.Clipboard.get_default();
++const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD;
++
++var S_IWOTH = 0x00002;
++
++function getDpy() {
++    return global.screen || global.display;
++}
++
++function findMonitorIndexForPos(x, y) {
++    return getDpy().get_monitor_index_for_rect(new Meta.Rectangle({x, y}));
++}
++
++
++var DesktopManager = GObject.registerClass({
++    Properties: {
++        'writable-by-others': GObject.ParamSpec.boolean(
++            'writable-by-others',
++            'WritableByOthers',
++            'Whether the desktop\'s directory can be written by others (o+w unix permission)',
++            GObject.ParamFlags.READABLE,
++            false
++        )
++    }
++}, class DesktopManager extends GObject.Object {
++    _init(params) {
++        super._init(params);
++
++        this._layoutChildrenId = 0;
++        this._deleteChildrenId = 0;
++        this._monitorDesktopDir = null;
++        this._desktopMonitorCancellable = null;
++        this._desktopGrids = {};
++        this._fileItemHandlers = new Map();
++        this._fileItems = new Map();
++        this._dragCancelled = false;
++        this._queryFileInfoCancellable = null;
++        this._unixMode = null;
++        this._writableByOthers = null;
++
++        this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._recreateDesktopIcons());
++        this._rubberBand = new St.Widget({ style_class: 'rubber-band' });
++        this._rubberBand.hide();
++        Main.layoutManager._backgroundGroup.add_child(this._rubberBand);
++        this._grabHelper = new GrabHelper.GrabHelper(global.stage);
++
++        this._addDesktopIcons();
++        this._monitorDesktopFolder();
++
++        this.settingsId = Prefs.settings.connect('changed', () => this._recreateDesktopIcons());
++        this.gtkSettingsId = Prefs.gtkSettings.connect('changed', (obj, key) => {
++            if (key == 'show-hidden')
++                this._recreateDesktopIcons();
++        });
++
++        this._selection = new Set();
++        this._currentSelection = new Set();
++        this._inDrag = false;
++        this._dragXStart = Number.POSITIVE_INFINITY;
++        this._dragYStart = Number.POSITIVE_INFINITY;
++    }
++
++    startRubberBand(x, y) {
++        this._rubberBandInitialX = x;
++        this._rubberBandInitialY = y;
++        this._initRubberBandColor();
++        this._updateRubberBand(x, y);
++        this._rubberBand.show();
++        this._grabHelper.grab({ actor: global.stage });
++        Extension.lockActivitiesButton = true;
++        this._stageReleaseEventId = global.stage.connect('button-release-event', (actor, event) => {
++            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;
++            if (x >= this._rubberBandInitialX) {
++                x0 = this._rubberBandInitialX;
++                x1 = x;
++            } else {
++                x1 = this._rubberBandInitialX;
++                x0 = x;
++            }
++            if (y >= this._rubberBandInitialY) {
++                y0 = this._rubberBandInitialY;
++                y1 = y;
++            } else {
++                y1 = this._rubberBandInitialY;
++                y0 = y;
++            }
++            for (let [fileUri, fileItem] of this._fileItems) {
++                fileItem.emit('selected', true, true,
++                              fileItem.intersectsWith(x0, y0, x1 - x0, y1 - y0));
++            }
++        });
++    }
++
++    endRubberBand() {
++        this._rubberBand.hide();
++        Extension.lockActivitiesButton = false;
++        this._grabHelper.ungrab();
++        global.stage.disconnect(this._rubberBandId);
++        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) {
++        let x = this._rubberBandInitialX < currentX ? this._rubberBandInitialX
++                                                    : currentX;
++        let y = this._rubberBandInitialY < currentY ? this._rubberBandInitialY
++                                                    : currentY;
++        let width = Math.abs(this._rubberBandInitialX - currentX);
++        let height = Math.abs(this._rubberBandInitialY - currentY);
++        /* TODO: Convert to gobject.set for 3.30 */
++        this._rubberBand.set_position(x, y);
++        this._rubberBand.set_size(width, height);
++    }
++
++    _recreateDesktopIcons() {
++        this._destroyDesktopIcons();
++        this._addDesktopIcons();
++    }
++
++    _addDesktopIcons() {
++        forEachBackgroundManager(bgManager => {
++            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)
++                    if (this._desktopGrids[grid].actor == actor) {
++                        delete this._desktopGrids[grid];
++                        break;
++                    }
++            });
++            this._desktopGrids[bgManager._monitorIndex] = newGrid;
++        });
++
++        this._scanFiles();
++    }
++
++    _destroyDesktopIcons() {
++        Object.values(this._desktopGrids).forEach(grid => grid.actor.destroy());
++        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();
++
++        if (!this._unixMode) {
++            let desktopDir = DesktopIconsUtil.getDesktopDir();
++            let fileInfo = desktopDir.query_info(Gio.FILE_ATTRIBUTE_UNIX_MODE,
++                                                 Gio.FileQueryInfoFlags.NONE,
++                                                 null);
++            this._unixMode = fileInfo.get_attribute_uint32(Gio.FILE_ATTRIBUTE_UNIX_MODE);
++            this._setWritableByOthers((this._unixMode & S_IWOTH) != 0);
++        }
++
++        try {
++            let tmpFileItems = new Map();
++            for (let [file, info, extra] of await this._enumerateDesktop()) {
++                let fileItem = new FileItem.FileItem(file, info, extra);
++                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}`);
++            return;
++        }
++
++        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)
++                this._desktopEnumerateCancellable.cancel();
++
++            this._desktopEnumerateCancellable = new Gio.Cancellable();
++
++            let desktopDir = DesktopIconsUtil.getDesktopDir();
++            desktopDir.enumerate_children_async(DesktopIconsUtil.DEFAULT_ATTRIBUTES,
++                Gio.FileQueryInfoFlags.NONE,
++                GLib.PRIORITY_DEFAULT,
++                this._desktopEnumerateCancellable,
++                (source, result) => {
++                    try {
++                        let fileEnum = source.enumerate_children_finish(result);
++                        let resultGenerator = function *() {
++                            let info;
++                            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) {
++                        reject(e);
++                    }
++                });
++        });
++    }
++
++    _monitorDesktopFolder() {
++        if (this._monitorDesktopDir) {
++            this._monitorDesktopDir.cancel();
++            this._monitorDesktopDir = null;
++        }
++
++        let desktopDir = DesktopIconsUtil.getDesktopDir();
++        this._monitorDesktopDir = desktopDir.monitor_directory(Gio.FileMonitorFlags.WATCH_MOVES, null);
++        this._monitorDesktopDir.set_rate_limit(1000);
++        this._monitorDesktopDir.connect('changed', (obj, file, otherFile, eventType) => this._updateDesktopIfChanged(file, otherFile, eventType));
++    }
++
++    checkIfSpecialFilesAreSelected() {
++        for (let fileItem of this._selection) {
++            if (fileItem.isSpecial)
++                return true;
++        }
++        return false;
++    }
++
++    getNumberOfSelectedItems() {
++        return this._selection.size;
++    }
++
++    get writableByOthers() {
++        return this._writableByOthers;
++    }
++
++    _setWritableByOthers(value) {
++        if (value == this._writableByOthers)
++            return;
++
++        this._writableByOthers = value
++        this.notify('writable-by-others');
++    }
++
++    _updateDesktopIfChanged (file, otherFile, eventType) {
++        let {
++            DELETED, MOVED_IN, MOVED_OUT, CREATED, RENAMED, CHANGES_DONE_HINT, ATTRIBUTE_CHANGED
++        } = Gio.FileMonitorEvent;
++
++        let fileUri = file.get_uri();
++        let fileItem = null;
++        if (this._fileItems.has(fileUri))
++            fileItem = this._fileItems.get(fileUri);
++        switch(eventType) {
++            case RENAMED:
++                this._fileItems.delete(fileUri);
++                this._fileItems.set(otherFile.get_uri(), fileItem);
++                fileItem.onFileRenamed(otherFile);
++                return;
++            case CHANGES_DONE_HINT:
++            case ATTRIBUTE_CHANGED:
++                /* a file changed, rather than the desktop itself */
++                let desktopDir = DesktopIconsUtil.getDesktopDir();
++                if (file.get_uri() != desktopDir.get_uri()) {
++                    fileItem.onAttributeChanged();
++                    return;
++                }
++
++                if (this._queryFileInfoCancellable)
++                    this._queryFileInfoCancellable.cancel();
++
++                file.query_info_async(Gio.FILE_ATTRIBUTE_UNIX_MODE,
++                                      Gio.FileQueryInfoFlags.NONE,
++                                      GLib.PRIORITY_DEFAULT,
++                                      this._queryFileInfoCancellable,
++                    (source, result) => {
++                        try {
++                            let info = source.query_info_finish(result);
++                            this._queryFileInfoCancellable = null;
++
++                            this._unixMode = info.get_attribute_uint32(Gio.FILE_ATTRIBUTE_UNIX_MODE);
++                            this._setWritableByOthers((this._unixMode & S_IWOTH) != 0);
++
++                            if (this._writableByOthers)
++                                log(`desktop-icons: Desktop is writable by others - will not allow launching any desktop files`);
++                        } catch(error) {
++                            if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
++                                global.log('Error getting desktop unix mode: ' + error);
++                        }
++                    });
++
++                return;
++        }
++
++        // Only get a subset of events we are interested in.
++        // Note that CREATED will emit a CHANGES_DONE_HINT
++        if (![DELETED, MOVED_IN, MOVED_OUT, CREATED].includes(eventType))
++            return;
++
++        this._recreateDesktopIcons();
++    }
++
++    _setupDnD() {
++        this._draggableContainer = new St.Widget({
++            visible: true,
++            width: 1,
++            height: 1,
++            x: 0,
++            y: 0,
++            style_class: 'draggable'
++        });
++        this._draggableContainer._delegate = this;
++        this._draggable = DND.makeDraggable(this._draggableContainer,
++            {
++                manualMode: true,
++                dragActorOpacity: 100
++            });
++
++        this._draggable.connect('drag-cancelled', () => this._onDragCancelled());
++        this._draggable.connect('drag-end', () => this._onDragEnd());
++
++        this._draggable._dragActorDropped = event => this._dragActorDropped(event);
++    }
++
++    dragStart() {
++        if (this._inDrag) {
++            return;
++        }
++
++        this._setupDnD();
++        let event = Clutter.get_current_event();
++        let [x, y] = event.get_coords();
++        [this._dragXStart, this._dragYStart] = event.get_coords();
++        this._inDrag = true;
++
++        for (let fileItem of this._selection) {
++            let clone = new Clutter.Clone({
++                source: fileItem.actor,
++                reactive: false
++            });
++            clone.x = fileItem.actor.get_transformed_position()[0];
++            clone.y = fileItem.actor.get_transformed_position()[1];
++            this._draggableContainer.add_child(clone);
++        }
++
++        Main.layoutManager.uiGroup.add_child(this._draggableContainer);
++        this._draggable.startDrag(x, y, global.get_current_time(), event.get_event_sequence());
++    }
++
++    _onDragCancelled() {
++        let event = Clutter.get_current_event();
++        let [x, y] = event.get_coords();
++        this._dragCancelled = true;
++    }
++
++    _onDragEnd() {
++        this._inDrag = false;
++        Main.layoutManager.uiGroup.remove_child(this._draggableContainer);
++    }
++
++    _dragActorDropped(event) {
++        let [dropX, dropY] = event.get_coords();
++        let target = this._draggable._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
++                                                                             dropX, dropY);
++
++        // We call observers only once per motion with the innermost
++        // target actor. If necessary, the observer can walk the
++        // parent itself.
++        let dropEvent = {
++            dropActor: this._draggable._dragActor,
++            targetActor: target,
++            clutterEvent: event
++        };
++        for (let dragMonitor of DND.dragMonitors) {
++            let dropFunc = dragMonitor.dragDrop;
++            if (dropFunc)
++                switch (dropFunc(dropEvent)) {
++                    case DragDropResult.FAILURE:
++                    case DragDropResult.SUCCESS:
++                        return true;
++                    case DragDropResult.CONTINUE:
++                        continue;
++                }
++        }
++
++        // At this point it is too late to cancel a drag by destroying
++        // the actor, the fate of which is decided by acceptDrop and its
++        // side-effects
++        this._draggable._dragCancellable = false;
++
++        let destroyActor = false;
++        while (target) {
++            if (target._delegate && target._delegate.acceptDrop) {
++                let [r, targX, targY] = target.transform_stage_point(dropX, dropY);
++                if (target._delegate.acceptDrop(this._draggable.actor._delegate,
++                    this._draggable._dragActor,
++                    targX,
++                    targY,
++                    event.get_time())) {
++                    // If it accepted the drop without taking the actor,
++                    // handle it ourselves.
++                    if (this._draggable._dragActor.get_parent() == Main.uiGroup) {
++                        if (this._draggable._restoreOnSuccess) {
++                            this._draggable._restoreDragActor(event.get_time());
++                            return true;
++                        }
++                        else {
++                            // We need this in order to make sure drag-end is fired
++                            destroyActor = true;
++                        }
++                    }
++
++                    this._draggable._dragInProgress = false;
++                    getDpy().set_cursor(Meta.Cursor.DEFAULT);
++                    this._draggable.emit('drag-end', event.get_time(), true);
++                    if (destroyActor) {
++                        this._draggable._dragActor.destroy();
++                    }
++                    this._draggable._dragComplete();
++
++                    return true;
++                }
++            }
++            target = target.get_parent();
++        }
++
++        this._draggable._cancelDrag(event.get_time());
++
++        return true;
++    }
++
++    acceptDrop(xEnd, yEnd) {
++        let savedCoordinates = new Map();
++        let [xDiff, yDiff] = [xEnd - this._dragXStart, yEnd - this._dragYStart];
++        /* Remove all items before dropping new ones, so we can freely reposition
++         * them.
++         */
++        for (let item of this._selection) {
++            let [itemX, itemY] = item.actor.get_transformed_position();
++            let monitorIndex = findMonitorIndexForPos(itemX, itemY);
++            savedCoordinates.set(item, [itemX, itemY]);
++            this._desktopGrids[monitorIndex].removeFileItem(item);
++        }
++
++        for (let item of this._selection) {
++            let [itemX, itemY] = savedCoordinates.get(item);
++            /* Set the new ideal position where the item drop should happen */
++            let newFileX = Math.round(xDiff + itemX);
++            let newFileY = Math.round(yDiff + itemY);
++            let monitorIndex = findMonitorIndexForPos(newFileX, newFileY);
++            this._desktopGrids[monitorIndex].addFileItemCloseTo(item, newFileX, newFileY, DesktopGrid.StoredCoordinates.OVERWRITE);
++        }
++
++        return true;
++    }
++
++    selectionDropOnFileItem (fileItemDestination) {
++        if (!fileItemDestination.isDirectory)
++            return false;
++
++        let droppedUris = [];
++        for (let fileItem of this._selection) {
++            if (fileItem.isSpecial)
++                return false;
++            if (fileItemDestination.file.get_uri() == fileItem.file.get_uri())
++                return false;
++            droppedUris.push(fileItem.file.get_uri());
++        }
++
++        if (droppedUris.length == 0)
++            return true;
++
++        DBusUtils.NautilusFileOperationsProxy.MoveURIsRemote(droppedUris,
++                                                             fileItemDestination.file.get_uri(),
++            (result, error) => {
++                if (error)
++                    throw new Error('Error moving files: ' + error.message);
++            }
++        );
++        for (let fileItem of this._selection) {
++            fileItem.state = FileItem.State.GONE;
++        }
++
++        this._recreateDesktopIcons();
++
++        return true;
++    }
++
++    _resetGridsAndScheduleLayout() {
++        this._deleteChildrenId = 0;
++
++        Object.values(this._desktopGrids).forEach((grid) => grid.reset());
++
++        this._layoutChildrenId = GLib.idle_add(GLib.PRIORITY_LOW, () => this._layoutChildren());
++
++        return GLib.SOURCE_REMOVE;
++    }
++
++    scheduleReLayoutChildren() {
++        if (this._deleteChildrenId != 0)
++            return;
++
++        if (this._layoutChildrenId != 0) {
++            GLib.source_remove(this._layoutChildrenId);
++            this._layoutChildrenId = 0;
++        }
++
++
++        this._deleteChildrenId = GLib.idle_add(GLib.PRIORITY_LOW, () => this._resetGridsAndScheduleLayout());
++    }
++
++    _addFileItemCloseTo(item) {
++        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, coordinatesAction);
++        } catch (e) {
++            log(`Error adding children to desktop: ${e.message}`);
++        }
++    }
++
++    _layoutChildren() {
++        let showHidden = Prefs.gtkSettings.get_boolean('show-hidden');
++        /*
++         * Paint the icons in two passes:
++         * * first pass paints those that have their coordinates defined in the metadata
++         * * second pass paints those new files that still don't have their definitive coordinates
++         */
++        for (let [fileUri, fileItem] of this._fileItems) {
++            if (fileItem.savedCoordinates == null)
++                continue;
++            if (fileItem.state != FileItem.State.NORMAL)
++                continue;
++            if (!showHidden && fileItem.isHidden)
++                continue;
++            this._addFileItemCloseTo(fileItem);
++        }
++
++        for (let [fileUri, fileItem] of this._fileItems) {
++            if (fileItem.savedCoordinates !== null)
++                continue;
++            if (fileItem.state != FileItem.State.NORMAL)
++                continue;
++            if (!showHidden && fileItem.isHidden)
++                continue;
++            this._addFileItemCloseTo(fileItem);
++        }
++
++        this._layoutChildrenId = 0;
++        return GLib.SOURCE_REMOVE;
++    }
++
++    doRename() {
++        if (this._selection.size != 1)
++            return;
++
++        let item = [...this._selection][0];
++        if (item.canRename())
++            item.doRename();
++    }
++
++    doOpen() {
++        for (let fileItem of this._selection)
++            fileItem.doOpen();
++    }
++
++    doTrash() {
++        DBusUtils.NautilusFileOperationsProxy.TrashFilesRemote([...this._selection].map((x) => { return x.file.get_uri(); }),
++            (source, error) => {
++                if (error)
++                    throw new Error('Error trashing files on the desktop: ' + error.message);
++            }
++        );
++    }
++
++    doEmptyTrash() {
++        DBusUtils.NautilusFileOperationsProxy.EmptyTrashRemote( (source, error) => {
++            if (error)
++                throw new Error('Error trashing files on the desktop: ' + error.message);
++        });
++    }
++
++    _onFileItemSelected(fileItem, keepCurrentSelection, rubberBandSelection, addToSelection) {
++
++        if (!keepCurrentSelection && !this._inDrag)
++            this.clearSelection();
++
++        let selection = keepCurrentSelection && rubberBandSelection ? this._currentSelection : this._selection;
++        if (addToSelection)
++            selection.add(fileItem);
++        else
++            selection.delete(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) {
++        let action = isCopy ? 'copy' : 'cut';
++        let text = `x-special/nautilus-clipboard\n${action}\n${
++            [...this._selection].map(s => s.file.get_uri()).join('\n')
++        }\n`;
++
++        return text;
++    }
++
++    doCopy() {
++        Clipboard.set_text(CLIPBOARD_TYPE, this._getClipboardText(true));
++    }
++
++    doCut() {
++        Clipboard.set_text(CLIPBOARD_TYPE, this._getClipboardText(false));
++    }
++
++    destroy() {
++        if (this._monitorDesktopDir)
++            this._monitorDesktopDir.cancel();
++        this._monitorDesktopDir = null;
++
++        if (this.settingsId)
++            Prefs.settings.disconnect(this.settingsId);
++        this.settingsId = 0;
++        if (this.gtkSettingsId)
++            Prefs.gtkSettings.disconnect(this.gtkSettingsId);
++        this.gtkSettingsId = 0;
++
++        if (this._layoutChildrenId)
++            GLib.source_remove(this._layoutChildrenId);
++        this._layoutChildrenId = 0;
++
++        if (this._deleteChildrenId)
++            GLib.source_remove(this._deleteChildrenId);
++        this._deleteChildrenId = 0;
++
++        if (this._monitorsChangedId)
++            Main.layoutManager.disconnect(this._monitorsChangedId);
++        this._monitorsChangedId = 0;
++        if (this._stageReleaseEventId)
++            global.stage.disconnect(this._stageReleaseEventId);
++        this._stageReleaseEventId = 0;
++
++        if (this._rubberBandId)
++            global.stage.disconnect(this._rubberBandId);
++        this._rubberBandId = 0;
++
++        this._rubberBand.destroy();
++
++        if (this._queryFileInfoCancellable)
++            this._queryFileInfoCancellable.cancel();
++
++        Object.values(this._desktopGrids).forEach(grid => grid.actor.destroy());
++        this._desktopGrids = {}
++    }
++});
++
++function forEachBackgroundManager(func) {
++    Main.layoutManager._bgManagers.forEach(func);
++}
+diff --git a/extensions/desktop-icons/extension.js b/extensions/desktop-icons/extension.js
+new file mode 100644
+index 0000000..4b960ab
+--- /dev/null
++++ b/extensions/desktop-icons/extension.js
+@@ -0,0 +1,71 @@
++/* Desktop Icons GNOME Shell extension
++ *
++ * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++const Main = imports.ui.main;
++
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++const Prefs = Me.imports.prefs;
++const { DesktopManager } = Me.imports.desktopManager;
++const DBusUtils = Me.imports.dbusUtils;
++
++var desktopManager = null;
++var addBackgroundMenuOrig = null;
++var _startupPreparedId;
++var lockActivitiesButton = false;
++
++var oldShouldToggleByCornerOrButtonFunction = null;
++
++function init() {
++    addBackgroundMenuOrig = Main.layoutManager._addBackgroundMenu;
++
++    Prefs.initTranslations();
++}
++
++function newShouldToggleByCornerOrButton() {
++    if (lockActivitiesButton)
++        return false;
++    else
++        return oldShouldToggleByCornerOrButtonFunction.bind(Main.overview);
++}
++
++function enable() {
++    // register a new function to allow to lock the Activities button when doing a rubberband selection
++    oldShouldToggleByCornerOrButtonFunction = Main.overview.shouldToggleByCornerOrButton;
++    Main.overview.shouldToggleByCornerOrButton = newShouldToggleByCornerOrButton;
++    // wait until the startup process has ended
++    if (Main.layoutManager._startingUp)
++        _startupPreparedId = Main.layoutManager.connect('startup-complete', () => innerEnable(true));
++    else
++        innerEnable(false);
++}
++
++function innerEnable(disconnectSignal) {
++    if (disconnectSignal)
++        Main.layoutManager.disconnect(_startupPreparedId);
++    DBusUtils.init();
++    Prefs.init();
++    Main.layoutManager._addBackgroundMenu = function() {};
++    desktopManager = new DesktopManager();
++}
++
++function disable() {
++    desktopManager.destroy();
++    Main.layoutManager._addBackgroundMenu = addBackgroundMenuOrig;
++    Main.overview.shouldToggleByCornerOrButton = oldShouldToggleByCornerOrButtonFunction;
++}
+diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
+new file mode 100644
+index 0000000..0c6a54d
+--- /dev/null
++++ b/extensions/desktop-icons/fileItem.js
+@@ -0,0 +1,830 @@
++/* Desktop Icons GNOME Shell extension
++ *
++ * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++const Gtk = imports.gi.Gtk;
++const Clutter = imports.gi.Clutter;
++const Gio = imports.gi.Gio;
++const GLib = imports.gi.GLib;
++const St = imports.gi.St;
++const Pango = imports.gi.Pango;
++const Meta = imports.gi.Meta;
++const GdkPixbuf = imports.gi.GdkPixbuf;
++const Cogl = imports.gi.Cogl;
++const GnomeDesktop = imports.gi.GnomeDesktop;
++
++const Mainloop = imports.mainloop;
++const Signals = imports.signals;
++
++const Background = imports.ui.background;
++const Main = imports.ui.main;
++const PopupMenu = imports.ui.popupMenu;
++const Util = imports.misc.util;
++
++const ExtensionUtils = imports.misc.extensionUtils;
++const Me = ExtensionUtils.getCurrentExtension();
++const Extension = Me.imports.extension;
++const Prefs = Me.imports.prefs;
++const DBusUtils = Me.imports.dbusUtils;
++const DesktopIconsUtil = Me.imports.desktopIconsUtil;
++
++const Gettext = imports.gettext.domain('desktop-icons');
++
++const _ = Gettext.gettext;
++
++const DRAG_TRESHOLD = 8;
++
++var S_IXUSR = 0o00100;
++var S_IWOTH = 0o00002;
++
++var State = {
++    NORMAL: 0,
++    GONE: 1,
++};
++
++var FileItem = class {
++
++    constructor(file, fileInfo, fileExtra) {
++        this._fileExtra = fileExtra;
++        this._loadThumbnailDataCancellable = null;
++        this._thumbnailScriptWatch = 0;
++        this._setMetadataCancellable = null;
++        this._queryFileInfoCancellable = null;
++        this._isSpecial = this._fileExtra != Prefs.FileType.NONE;
++
++        this._file = file;
++
++        this._savedCoordinates = null;
++        let savedCoordinates = fileInfo.get_attribute_as_string('metadata::nautilus-icon-position');
++        if (savedCoordinates != null)
++            this._savedCoordinates = savedCoordinates.split(',').map(x => Number(x));
++
++        this._state = State.NORMAL;
++
++        this.actor = new St.Bin({ visible: true });
++        this.actor.set_fill(true, true);
++        let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
++        this.actor.set_height(Prefs.get_desired_height(scaleFactor));
++        this.actor.set_width(Prefs.get_desired_width(scaleFactor));
++        this.actor._delegate = this;
++        this.actor.connect('destroy', () => this._onDestroy());
++
++        this._container = new St.BoxLayout({ reactive: true,
++                                             track_hover: true,
++                                             can_focus: true,
++                                             style_class: 'file-item',
++                                             x_expand: true,
++                                             y_expand: true,
++                                             x_align: Clutter.ActorAlign.FILL,
++                                             vertical: true });
++        this.actor.set_child(this._container);
++        this._icon = new St.Bin();
++        this._icon.set_height(Prefs.get_icon_size() * scaleFactor);
++
++        this._iconContainer = new St.Bin({ visible: true });
++        this._iconContainer.child = this._icon;
++        this._container.add_child(this._iconContainer);
++
++        this._label = new St.Label({
++            style_class: 'name-label'
++        });
++
++        this._container.add_child(this._label);
++        let clutterText = this._label.get_clutter_text();
++        /* TODO: Convert to gobject.set for 3.30 */
++        clutterText.set_line_wrap(true);
++        clutterText.set_line_wrap_mode(Pango.WrapMode.WORD_CHAR);
++        clutterText.set_ellipsize(Pango.EllipsizeMode.END);
++
++        this._container.connect('button-press-event', (actor, event) => this._onPressButton(actor, event));
++        this._container.connect('motion-event', (actor, event) => this._onMotion(actor, event));
++        this._container.connect('leave-event', (actor, event) => this._onLeave(actor, event));
++        this._container.connect('button-release-event', (actor, event) => this._onReleaseButton(actor, event));
++
++        /* Set the metadata and update relevant UI */
++        this._updateMetadataFromFileInfo(fileInfo);
++
++        this._menuManager = null;
++        this._menu = null;
++        this._updateIcon();
++
++        this._isSelected = false;
++        this._primaryButtonPressed = false;
++        if (this._attributeCanExecute && !this._isValidDesktopFile)
++            this._execLine = this.file.get_path();
++        if (fileExtra == Prefs.FileType.USER_DIRECTORY_TRASH) {
++            // if this icon is the trash, monitor the state of the directory to update the icon
++            this._trashChanged = false;
++            this._queryTrashInfoCancellable = null;
++            this._scheduleTrashRefreshId = 0;
++            this._monitorTrashDir = this._file.monitor_directory(Gio.FileMonitorFlags.WATCH_MOVES, null);
++            this._monitorTrashId = this._monitorTrashDir.connect('changed', (obj, file, otherFile, eventType) => {
++                switch(eventType) {
++                    case Gio.FileMonitorEvent.DELETED:
++                    case Gio.FileMonitorEvent.MOVED_OUT:
++                    case Gio.FileMonitorEvent.CREATED:
++                    case Gio.FileMonitorEvent.MOVED_IN:
++                        if (this._queryTrashInfoCancellable || this._scheduleTrashRefreshId) {
++                            if (this._scheduleTrashRefreshId)
++                                GLib.source_remove(this._scheduleTrashRefreshId);
++                            this._scheduleTrashRefreshId = Mainloop.timeout_add(200, () => this._refreshTrashIcon());
++                        } else {
++                            this._refreshTrashIcon();
++                        }
++                    break;
++                }
++            });
++        }
++
++        this._writebleByOthersId = Extension.desktopManager.connect('notify::writable-by-others', () => {
++            if (!this._isValidDesktopFile)
++                return;
++            this._refreshMetadataAsync(true);
++        });
++    }
++
++    onAttributeChanged() {
++        if (this._isDesktopFile) {
++            this._refreshMetadataAsync(true);
++        }
++    }
++
++    _onDestroy() {
++        /* Regular file data */
++        if (this._setMetadataCancellable)
++            this._setMetadataCancellable.cancel();
++        if (this._queryFileInfoCancellable)
++            this._queryFileInfoCancellable.cancel();
++
++        Extension.desktopManager.disconnect(this._writebleByOthersId);
++
++        /* Thumbnailing */
++        if (this._thumbnailScriptWatch)
++            GLib.source_remove(this._thumbnailScriptWatch);
++        if (this._loadThumbnailDataCancellable)
++            this._loadThumbnailDataCancellable.cancel();
++
++        /* Desktop file */
++        if (this._monitorDesktopFileId) {
++            this._monitorDesktopFile.disconnect(this._monitorDesktopFileId);
++            this._monitorDesktopFile.cancel();
++        }
++
++        /* Trash */
++        if (this._monitorTrashDir) {
++            this._monitorTrashDir.disconnect(this._monitorTrashId);
++            this._monitorTrashDir.cancel();
++        }
++        if (this._queryTrashInfoCancellable)
++            this._queryTrashInfoCancellable.cancel();
++        if (this._scheduleTrashRefreshId)
++            GLib.source_remove(this._scheduleTrashRefreshId);
++
++        /* Menu */
++        this._removeMenu();
++    }
++
++    _refreshMetadataAsync(rebuild) {
++        if (this._queryFileInfoCancellable)
++            this._queryFileInfoCancellable.cancel();
++        this._queryFileInfoCancellable = new Gio.Cancellable();
++        this._file.query_info_async(DesktopIconsUtil.DEFAULT_ATTRIBUTES,
++                                    Gio.FileQueryInfoFlags.NONE,
++                                    GLib.PRIORITY_DEFAULT,
++                                    this._queryFileInfoCancellable,
++            (source, result) => {
++                try {
++                    let newFileInfo = source.query_info_finish(result);
++                    this._queryFileInfoCancellable = null;
++                    this._updateMetadataFromFileInfo(newFileInfo);
++                    if (rebuild) {
++                        this._recreateMenu();
++                        this._updateIcon();
++                    }
++                } catch(error) {
++                    if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
++                        global.log("Error getting the file info: " + error);
++                }
++            });
++    }
++
++    _updateMetadataFromFileInfo(fileInfo) {
++        this._fileInfo = fileInfo;
++
++        let oldLabelText = this._label.text;
++
++        this._displayName = fileInfo.get_attribute_as_string('standard::display-name');
++        this._attributeCanExecute = fileInfo.get_attribute_boolean('access::can-execute');
++        this._unixmode = fileInfo.get_attribute_uint32('unix::mode')
++        this._writableByOthers = (this._unixmode & S_IWOTH) != 0;
++        this._trusted = fileInfo.get_attribute_as_string('metadata::trusted') == 'true';
++        this._attributeContentType = fileInfo.get_content_type();
++        this._isDesktopFile = this._attributeContentType == 'application/x-desktop';
++
++        if (this._isDesktopFile && this._writableByOthers)
++            log(`desktop-icons: File ${this._displayName} is writable by others - will not allow launching`);
++
++        if (this._isDesktopFile) {
++            this._desktopFile = Gio.DesktopAppInfo.new_from_filename(this._file.get_path());
++            if (!this._desktopFile) {
++                log(`Couldn’t parse ${this._displayName} as a desktop file, will treat it as a regular file.`);
++                this._isValidDesktopFile = false;
++            } else {
++                this._isValidDesktopFile = true;
++            }
++        } else {
++            this._isValidDesktopFile = false;
++        }
++
++        if (this.displayName != oldLabelText) {
++            this._label.text = this.displayName;
++        }
++
++        this._fileType = fileInfo.get_file_type();
++        this._isDirectory = this._fileType == Gio.FileType.DIRECTORY;
++        this._isSpecial = this._fileExtra != Prefs.FileType.NONE;
++        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");
++        /*
++         * This is a glib trick to detect broken symlinks. If a file is a symlink, the filetype
++         * points to the final file, unless it is broken; thus if the file type is SYMBOLIC_LINK,
++         * it must be a broken link.
++         * https://developer.gnome.org/gio/stable/GFile.html#g-file-query-info
++         */
++        this._isBrokenSymlink = this._isSymlink && this._fileType == Gio.FileType.SYMBOLIC_LINK
++    }
++
++    onFileRenamed(file) {
++        this._file = file;
++        this._refreshMetadataAsync(false);
++    }
++
++    _updateIcon() {
++        if (this._fileExtra == Prefs.FileType.USER_DIRECTORY_TRASH) {
++            this._icon.child = this._createEmblemedStIcon(this._fileInfo.get_icon(), null);
++            return;
++        }
++
++        let thumbnailFactory = GnomeDesktop.DesktopThumbnailFactory.new(GnomeDesktop.DesktopThumbnailSize.LARGE);
++        if (thumbnailFactory.can_thumbnail(this._file.get_uri(),
++                                           this._attributeContentType,
++                                           this._modifiedTime)) {
++            let thumbnail = thumbnailFactory.lookup(this._file.get_uri(), this._modifiedTime);
++            if (thumbnail == null) {
++                if (!thumbnailFactory.has_valid_failed_thumbnail(this._file.get_uri(),
++                                                                 this._modifiedTime)) {
++                    let argv = [];
++                    argv.push(GLib.build_filenamev([ExtensionUtils.getCurrentExtension().path,
++                                                   'createThumbnail.js']));
++                    argv.push(this._file.get_path());
++                    let [success, pid] = GLib.spawn_async(null, argv, null,
++                                                          GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, null);
++                    if (this._thumbnailScriptWatch)
++                        GLib.source_remove(this._thumbnailScriptWatch);
++                    this._thumbnailScriptWatch = GLib.child_watch_add(GLib.PRIORITY_DEFAULT,
++                                                                      pid,
++                        (pid, exitCode) => {
++                            this._thumbnailScriptWatch = 0;
++                            if (exitCode == 0)
++                                this._updateIcon();
++                            else
++                                global.log('Failed to generate thumbnail for ' + this._filePath);
++                            GLib.spawn_close_pid(pid);
++                            return false;
++                        }
++                    );
++                }
++            } else {
++                if (this._loadThumbnailDataCancellable)
++                    this._loadThumbnailDataCancellable.cancel();
++                this._loadThumbnailDataCancellable = new Gio.Cancellable();
++                let thumbnailFile = Gio.File.new_for_path(thumbnail);
++                thumbnailFile.load_bytes_async(this._loadThumbnailDataCancellable,
++                    (source, result) => {
++                        try {
++                            this._loadThumbnailDataCancellable = null;
++                            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);
++
++                            if (thumbnailPixbuf != null) {
++                                let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
++                                let thumbnailImage = new Clutter.Image();
++                                thumbnailImage.set_data(thumbnailPixbuf.get_pixels(),
++                                                        thumbnailPixbuf.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888,
++                                                        thumbnailPixbuf.width,
++                                                        thumbnailPixbuf.height,
++                                                        thumbnailPixbuf.rowstride
++                                );
++                                let icon = new Clutter.Actor();
++                                icon.set_content(thumbnailImage);
++                                let width = Prefs.get_desired_width(scaleFactor);
++                                let height = Prefs.get_icon_size() * scaleFactor;
++                                let aspectRatio = thumbnailPixbuf.width / thumbnailPixbuf.height;
++                                if ((width / height) > aspectRatio)
++                                    icon.set_size(height * aspectRatio, height);
++                                else
++                                    icon.set_size(width, width / aspectRatio);
++                                this._icon.child = icon;
++                            }
++                        } catch (error) {
++                            if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
++                                global.log('Error while loading thumbnail: ' + error);
++                                this._icon.child = this._createEmblemedStIcon(this._fileInfo.get_icon(), null);
++                            }
++                        }
++                    }
++                );
++            }
++        }
++
++        if (this._isBrokenSymlink) {
++            this._icon.child = this._createEmblemedStIcon(null, 'text-x-generic');
++        } else {
++            if (this.trustedDesktopFile && this._desktopFile.has_key('Icon'))
++                this._icon.child = this._createEmblemedStIcon(null, this._desktopFile.get_string('Icon'));
++            else
++                this._icon.child = this._createEmblemedStIcon(this._fileInfo.get_icon(), null);
++        }
++    }
++
++    _refreshTrashIcon() {
++        if (this._queryTrashInfoCancellable)
++            this._queryTrashInfoCancellable.cancel();
++        this._queryTrashInfoCancellable = new Gio.Cancellable();
++
++        this._file.query_info_async(DesktopIconsUtil.DEFAULT_ATTRIBUTES,
++                                    Gio.FileQueryInfoFlags.NONE,
++                                    GLib.PRIORITY_DEFAULT,
++                                    this._queryTrashInfoCancellable,
++            (source, result) => {
++                try {
++                    this._fileInfo = source.query_info_finish(result);
++                    this._queryTrashInfoCancellable = null;
++                    this._updateIcon();
++                } catch(error) {
++                    if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
++                        global.log('Error getting the number of files in the trash: ' + error);
++                }
++            });
++
++        this._scheduleTrashRefreshId = 0;
++        return false;
++    }
++
++    get file() {
++        return this._file;
++    }
++
++    get isHidden() {
++        return this._isHidden;
++    }
++
++    _createEmblemedStIcon(icon, iconName) {
++        if (icon == null) {
++            if (GLib.path_is_absolute(iconName)) {
++                let iconFile = Gio.File.new_for_commandline_arg(iconName);
++                icon = new Gio.FileIcon({ file: iconFile });
++            } else {
++                icon = Gio.ThemedIcon.new_with_default_fallbacks(iconName);
++            }
++        }
++        let itemIcon = Gio.EmblemedIcon.new(icon, null);
++
++        if (this._isSymlink) {
++            if (this._isBrokenSymlink)
++                itemIcon.add_emblem(Gio.Emblem.new(Gio.ThemedIcon.new('emblem-unreadable')));
++            else
++                itemIcon.add_emblem(Gio.Emblem.new(Gio.ThemedIcon.new('emblem-symbolic-link')));
++        } else if (this.trustedDesktopFile) {
++            itemIcon.add_emblem(Gio.Emblem.new(Gio.ThemedIcon.new('emblem-symbolic-link')));
++        }
++
++        return new St.Icon({ gicon: itemIcon,
++                             icon_size: Prefs.get_icon_size()
++        });
++    }
++
++    doRename() {
++        if (!this.canRename()) {
++            log (`Error: ${this.file.get_uri()} cannot be renamed`);
++            return;
++        }
++
++        this.emit('rename-clicked');
++    }
++
++    doOpen() {
++        if (this._isBrokenSymlink) {
++            log(`Error: Can’t open ${this.file.get_uri()} because it is a broken symlink.`);
++            return;
++        }
++
++        if (this.trustedDesktopFile) {
++            this._desktopFile.launch_uris_as_manager([], null, GLib.SpawnFlags.SEARCH_PATH, null, null);
++            return;
++        }
++
++        if (this._attributeCanExecute && !this._isDirectory && !this._isValidDesktopFile) {
++            if (this._execLine)
++                Util.spawnCommandLine(this._execLine);
++            return;
++        }
++
++        Gio.AppInfo.launch_default_for_uri_async(this.file.get_uri(),
++            null, null,
++            (source, result) => {
++                try {
++                    Gio.AppInfo.launch_default_for_uri_finish(result);
++                } catch (e) {
++                    log('Error opening file ' + this.file.get_uri() + ': ' + e.message);
++                }
++            }
++        );
++    }
++
++    _onCopyClicked() {
++        Extension.desktopManager.doCopy();
++    }
++
++    _onCutClicked() {
++        Extension.desktopManager.doCut();
++    }
++
++    _onShowInFilesClicked() {
++
++        DBusUtils.FreeDesktopFileManagerProxy.ShowItemsRemote([this.file.get_uri()], '',
++            (result, error) => {
++                if (error)
++                    log('Error showing file on desktop: ' + error.message);
++            }
++        );
++    }
++
++    _onPropertiesClicked() {
++
++        DBusUtils.FreeDesktopFileManagerProxy.ShowItemPropertiesRemote([this.file.get_uri()], '',
++            (result, error) => {
++                if (error)
++                    log('Error showing properties: ' + error.message);
++            }
++        );
++    }
++
++    _onMoveToTrashClicked() {
++        Extension.desktopManager.doTrash();
++    }
++
++    _onEmptyTrashClicked() {
++        Extension.desktopManager.doEmptyTrash();
++    }
++
++    get _allowLaunchingText() {
++        if (this.trustedDesktopFile)
++            return _("Don’t Allow Launching");
++
++        return _("Allow Launching");
++    }
++
++    get metadataTrusted() {
++        return this._trusted;
++    }
++
++    set metadataTrusted(value) {
++        this._trusted = value;
++
++        let info = new Gio.FileInfo();
++        info.set_attribute_string('metadata::trusted',
++                                  value ? 'true' : 'false');
++        this._file.set_attributes_async(info,
++                                        Gio.FileQueryInfoFlags.NONE,
++                                        GLib.PRIORITY_LOW,
++                                        null,
++            (source, result) => {
++                try {
++                    source.set_attributes_finish(result);
++                    this._refreshMetadataAsync(true);
++                } catch(e) {
++                    log(`Failed to set metadata::trusted: ${e.message}`);
++                }
++        });
++    }
++
++    _onAllowDisallowLaunchingClicked() {
++        this.metadataTrusted = !this.trustedDesktopFile;
++
++        /*
++         * we're marking as trusted, make the file executable too. note that we
++         * do not ever remove the executable bit, since we don't know who set
++         * it.
++         */
++        if (this.metadataTrusted && !this._attributeCanExecute) {
++            let info = new Gio.FileInfo();
++            let newUnixMode = this._unixmode | S_IXUSR;
++            info.set_attribute_uint32(Gio.FILE_ATTRIBUTE_UNIX_MODE, newUnixMode);
++            this._file.set_attributes_async(info,
++                                            Gio.FileQueryInfoFlags.NONE,
++                                            GLib.PRIORITY_LOW,
++                                            null,
++                (source, result) => {
++                    try {
++                        source.set_attributes_finish (result);
++                    } catch(e) {
++                        log(`Failed to set unix mode: ${e.message}`);
++                    }
++            });
++        }
++    }
++
++    canRename() {
++        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 + ';'
++    }
++
++    _removeMenu() {
++        if (this._menu != null) {
++            if (this._menuManager != null)
++                this._menuManager.removeMenu(this._menu);
++
++            Main.layoutManager.uiGroup.remove_child(this._menu.actor);
++            this._menu.destroy();
++            this._menu = null;
++        }
++
++        this._menuManager = null;
++    }
++
++    _recreateMenu() {
++        this._removeMenu();
++
++        this._menuManager = new PopupMenu.PopupMenuManager({ actor: this.actor });
++        let side = St.Side.LEFT;
++        if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
++            side = St.Side.RIGHT;
++        this._menu = new PopupMenu.PopupMenu(this.actor, 0.5, side);
++        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())
++                this._menu.addAction(_('Rename…'), () => this.doRename());
++            this._actionTrash = this._menu.addAction(_('Move to Trash'), () => this._onMoveToTrashClicked());
++            if (this._isValidDesktopFile && !Extension.desktopManager.writableByOthers && !this._writableByOthers) {
++                this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++                this._allowLaunchingMenuItem = this._menu.addAction(this._allowLaunchingText,
++                                                                    () => this._onAllowDisallowLaunchingClicked());
++
++            }
++            break;
++        case Prefs.FileType.USER_DIRECTORY_TRASH:
++            this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++            this._menu.addAction(_('Empty Trash'), () => this._onEmptyTrashClicked());
++            break;
++        default:
++            break;
++        }
++        this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++        this._menu.addAction(_('Properties'), () => this._onPropertiesClicked());
++        this._menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
++        this._menu.addAction(_('Show in Files'), () => this._onShowInFilesClicked());
++        if (this._isDirectory && this.file.get_path() != null)
++            this._actionOpenInTerminal = this._menu.addAction(_('Open in Terminal'), () => this._onOpenTerminalClicked());
++
++        this._menuManager.addMenu(this._menu);
++
++        Main.layoutManager.uiGroup.add_child(this._menu.actor);
++        this._menu.actor.hide();
++    }
++
++    _ensureMenu() {
++        if (this._menu == null)
++            this._recreateMenu();
++
++        return this._menu;
++    }
++
++    _onOpenTerminalClicked () {
++        DesktopIconsUtil.launchTerminal(this.file.get_path());
++    }
++
++    _onPressButton(actor, event) {
++        let button = event.get_button();
++        if (button == 3) {
++            if (!this.isSelected)
++                this.emit('selected', false, false, true);
++            this._ensureMenu().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);
++            if (this._actionCopy)
++                this._actionCopy.setSensitive(!specialFilesSelected);
++            if (this._actionTrash)
++                this._actionTrash.setSensitive(!specialFilesSelected);
++            return Clutter.EVENT_STOP;
++        } else if (button == 1) {
++            if (event.get_click_count() == 1) {
++                let [x, y] = event.get_coords();
++                this._primaryButtonPressed = true;
++                this._buttonPressInitialX = x;
++                this._buttonPressInitialY = y;
++                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, false, true);
++                }
++            }
++            return Clutter.EVENT_STOP;
++        }
++
++        return Clutter.EVENT_PROPAGATE;
++    }
++
++    _onLeave(actor, event) {
++        this._primaryButtonPressed = false;
++    }
++
++    _onMotion(actor, event) {
++        let [x, y] = event.get_coords();
++        if (this._primaryButtonPressed) {
++            let xDiff = x - this._buttonPressInitialX;
++            let yDiff = y - this._buttonPressInitialY;
++            let distance = Math.sqrt(Math.pow(xDiff, 2) + Math.pow(yDiff, 2));
++            if (distance > DRAG_TRESHOLD) {
++                // Don't need to track anymore this if we start drag, and also
++                // avoids reentrance here
++                this._primaryButtonPressed = false;
++                let event = Clutter.get_current_event();
++                let [x, y] = event.get_coords();
++                Extension.desktopManager.dragStart();
++            }
++        }
++
++        return Clutter.EVENT_PROPAGATE;
++    }
++
++    _onReleaseButton(actor, event) {
++        let button = event.get_button();
++        if (button == 1) {
++            // primaryButtonPressed is TRUE only if the user has pressed the button
++            // over an icon, and if (s)he has not started a drag&drop operation
++            if (this._primaryButtonPressed) {
++                this._primaryButtonPressed = false;
++                let shiftPressed = !!(event.get_state() & Clutter.ModifierType.SHIFT_MASK);
++                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, false, true);
++                return Clutter.EVENT_STOP;
++            }
++            if ((event.get_click_count() == 2) && (!Prefs.CLICK_POLICY_SINGLE))
++                this.doOpen();
++        }
++        return Clutter.EVENT_PROPAGATE;
++    }
++
++    get savedCoordinates() {
++        return this._savedCoordinates;
++    }
++
++    _onSetMetadataFileFinished(source, result) {
++        try {
++            let [success, info] = source.set_attributes_finish(result);
++        } catch (error) {
++            if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
++                log('Error setting metadata to desktop files ', error);
++        }
++    }
++
++    set savedCoordinates(pos) {
++        if (this._setMetadataCancellable)
++            this._setMetadataCancellable.cancel();
++
++        this._setMetadataCancellable = new Gio.Cancellable();
++        this._savedCoordinates = [pos[0], pos[1]];
++        let info = new Gio.FileInfo();
++        info.set_attribute_string('metadata::nautilus-icon-position',
++                                  `${pos[0]},${pos[1]}`);
++        this.file.set_attributes_async(info,
++                                       Gio.FileQueryInfoFlags.NONE,
++                                       GLib.PRIORITY_DEFAULT,
++                                       this._setMetadataCancellable,
++            (source, result) => {
++                this._setMetadataCancellable = null;
++                this._onSetMetadataFileFinished(source, result);
++            }
++        );
++    }
++
++    intersectsWith(argX, argY, argWidth, argHeight) {
++        let rect = new Meta.Rectangle({ x: argX, y: argY, width: argWidth, height: argHeight });
++        let [containerX, containerY] = this._container.get_transformed_position();
++        let boundingBox = new Meta.Rectangle({ x: containerX,
++                                               y: containerY,
++                                               width: this._container.allocation.x2 - this._container.allocation.x1,
++                                               height: this._container.allocation.y2 - this._container.allocation.y1 });
++        let [intersects, _] = rect.intersect(boundingBox);
++
++        return intersects;
++    }
++
++    set isSelected(isSelected) {
++        isSelected = !!isSelected;
++        if (isSelected == this._isSelected)
++            return;
++
++        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;
++    }
++
++    get isSelected() {
++        return this._isSelected;
++    }
++
++    get isSpecial() {
++        return this._isSpecial;
++    }
++
++    get state() {
++        return this._state;
++    }
++
++    set state(state) {
++        if (state == this._state)
++            return;
++
++        this._state = state;
++    }
++
++    get isDirectory() {
++        return this._isDirectory;
++    }
++
++    get trustedDesktopFile() {
++        return this._isValidDesktopFile &&
++               this._attributeCanExecute &&
++               this.metadataTrusted &&
++               !Extension.desktopManager.writableByOthers &&
++               !this._writableByOthers;
++    }
++
++    get fileName() {
++        return this._fileInfo.get_name();
++    }
++
++    get displayName() {
++        if (this.trustedDesktopFile)
++            return this._desktopFile.get_name();
++
++        return this._displayName || null;
++    }
++
++    acceptDrop() {
++        return Extension.desktopManager.selectionDropOnFileItem(this);
++    }
++};
++Signals.addSignalMethods(FileItem.prototype);
+diff --git a/extensions/desktop-icons/meson.build b/extensions/desktop-icons/meson.build
+new file mode 100644
+index 0000000..8431af6
+--- /dev/null
++++ b/extensions/desktop-icons/meson.build
+@@ -0,0 +1,19 @@
++extension_data += configure_file(
++  input: metadata_name + '.in',
++  output: metadata_name,
++  configuration: metadata_conf
++)
++
++extension_schemas += files(join_paths('schemas', metadata_conf.get('gschemaname') + '.gschema.xml'))
++
++extension_sources += files(
++  'createFolderDialog.js',
++  'createThumbnail.js',
++  'dbusUtils.js',
++  'desktopGrid.js',
++  'desktopIconsUtil.js',
++  'desktopManager.js',
++  'extension.js',
++  'fileItem.js',
++  'prefs.js'
++)
+diff --git a/extensions/desktop-icons/metadata.json.in b/extensions/desktop-icons/metadata.json.in
+new file mode 100644
+index 0000000..78cabf0
+--- /dev/null
++++ b/extensions/desktop-icons/metadata.json.in
+@@ -0,0 +1,11 @@
++{
++"extension-id": "@extension_id@",
++"uuid": "@uuid@",
++"settings-schema": "@gschemaname@",
++"gettext-domain": "@gettext_domain@",
++"name": "Desktop Icons",
++"description": "Provide desktop icons support for classic mode",
++"original-authors": [  "csoriano@redhat.com" ],
++"shell-version": [ "@shell_current@" ],
++"url": "@url@"
++}
+diff --git a/extensions/desktop-icons/po/LINGUAS b/extensions/desktop-icons/po/LINGUAS
+new file mode 100644
+index 0000000..65b7521
+--- /dev/null
++++ b/extensions/desktop-icons/po/LINGUAS
+@@ -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
+index 0000000..7c2ebd3
+--- /dev/null
++++ b/extensions/desktop-icons/po/POTFILES.in
+@@ -0,0 +1,4 @@
++prefs.js
++desktopGrid.js
++fileItem.js
++schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml
+\ 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..f5f9db4
+--- /dev/null
++++ b/extensions/desktop-icons/po/cs.po
+@@ -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ý <marek@manet.cz>, 2018.
++# Milan Zink <zeten30@gmail.com>, 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: 2019-03-01 12:49+0000\n"
++"PO-Revision-Date: 2019-03-02 18:02+0100\n"
++"Last-Translator: Daniel Rusek <mail@asciiwolf.com>\n"
++"Language-Team: Czech <zeten30@gmail.com>\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: Poedit 2.2.1\n"
++
++#: 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:102
++msgid "Small"
++msgstr "malé"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "standardní"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "velké"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Zobrazovat osobní složku na pracovní ploše"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Zobrazovat ikonu koše na pracovní ploše"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Nová složka"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Vložit"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Zpět"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Znovu"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Zobrazit plochu v Souborech"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Otevřít v terminálu"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Změnit pozadí…"
++
++#: desktopGrid.js:331
++msgid "Display Settings"
++msgstr "Zobrazit nastavení"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Nastavení"
++
++#: 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:578
++msgid "Open With Other Application"
++msgstr "Otevřít pomocí jiné aplikace"
++
++#: fileItem.js:582
++msgid "Cut"
++msgstr "Vyjmout"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "Kopírovat"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "Přejmenovat…"
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "Přesunout do koše"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "Vyprázdnit koš"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "Vlastnosti"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "Zobrazit v Souborech"
++
++#: 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: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:16
++msgid "Show personal folder"
++msgstr "Zobrazovat osobní složku"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Zobrazovat koš"
++
++#: 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..d3f51f0
+--- /dev/null
++++ b/extensions/desktop-icons/po/da.po
+@@ -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.
++# Alan Mortensen <alanmortensen.am@gmail.com>, 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: 2019-01-15 10:59+0000\n"
++"PO-Revision-Date: 2019-02-09 11:35+0100\n"
++"Last-Translator: Alan Mortensen <alanmortensen.am@gmail.com>\n"
++"Language-Team: Danish <dansk@dansk-gruppen.dk>\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"
++"X-Generator: Poedit 2.0.6\n"
++
++#: prefs.js:102
++msgid "Size for the desktop icons"
++msgstr "Størrelsen på skrivebordsikoner"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Små"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standard"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Store"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Vis den personlige mappe på skrivebordet"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Vis papirkurvsikonet på skrivebordet"
++
++#: desktopGrid.js:187 desktopGrid.js:306
++msgid "New Folder"
++msgstr "Ny mappe"
++
++#: desktopGrid.js:308
++msgid "Paste"
++msgstr "Indsæt"
++
++#: desktopGrid.js:309
++msgid "Undo"
++msgstr "Fortryd"
++
++#: desktopGrid.js:310
++msgid "Redo"
++msgstr "Omgør"
++
++#: desktopGrid.js:312
++msgid "Show Desktop in Files"
++msgstr "Vis skrivebordet i Filer"
++
++#: desktopGrid.js:313 fileItem.js:586
++msgid "Open in Terminal"
++msgstr "Åbn i terminal"
++
++#: desktopGrid.js:315
++msgid "Change Background…"
++msgstr "Skift baggrund …"
++
++#: desktopGrid.js:317
++msgid "Display Settings"
++msgstr "Skærmindstillinger"
++
++#: desktopGrid.js:318
++msgid "Settings"
++msgstr "Indstillinger"
++
++#: 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:562
++msgid "Cut"
++msgstr "Klip"
++
++#: fileItem.js:563
++msgid "Copy"
++msgstr "Kopiér"
++
++#: fileItem.js:565
++msgid "Rename…"
++msgstr "Omdøb …"
++
++#: fileItem.js:566
++msgid "Move to Trash"
++msgstr "Flyt til papirkurven"
++
++#: fileItem.js:576
++msgid "Empty Trash"
++msgstr "Tøm papirkurven"
++
++#: fileItem.js:582
++msgid "Properties"
++msgstr "Egenskaber"
++
++#: fileItem.js:584
++msgid "Show in Files"
++msgstr "Vis i Filer"
++
++#: 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:12
++msgid "Set the size for the desktop icons."
++msgstr "Angiv størrelsen på skrivebordsikoner."
++
++#: 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: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:21
++msgid "Show trash icon"
++msgstr "Vis papirkurvsikon"
++
++#: 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..ed5a257
+--- /dev/null
++++ b/extensions/desktop-icons/po/de.po
+@@ -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 <mario.blaettermann@gmail.com>, 2018.
++# rugk <rugk+i18n@posteo.de>, 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-07 22:46+0000\n"
++"PO-Revision-Date: 2019-03-09 15:42+0100\n"
++"Last-Translator: Tim Sabsch <tim@sabsch.com>\n"
++"Language-Team: German <gnome-de@gnome.org>\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.2.1\n"
++
++#: 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:102
++msgid "Small"
++msgstr "Klein"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standard"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Groß"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Den persönlichen Ordner auf der Arbeitsfläche anzeigen"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Papierkorb-Symbol auf der Arbeitsfläche anzeigen"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Neuer Ordner"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Einfügen"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Rückgängig"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Wiederholen"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Schreibtisch in Dateien anzeigen"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Im Terminal öffnen"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Hintergrund ändern …"
++
++#: desktopGrid.js:331
++msgid "Display Settings"
++msgstr "Anzeigeeinstellungen"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Einstellungen"
++
++#: 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:578
++msgid "Open With Other Application"
++msgstr "Mit anderer Anwendung öffnen"
++
++#: fileItem.js:582
++msgid "Cut"
++msgstr "Ausschneiden"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "Kopieren"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "Umbenennen …"
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "In den Papierkorb verschieben"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "Papierkorb leeren"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "Eigenschaften"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "In Dateiverwaltung anzeigen"
++
++#: 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: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:16
++msgid "Show personal folder"
++msgstr "Persönlichen Ordner anzeigen"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Papierkorb-Symbol anzeigen"
++
++#: 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..8cc87da
+--- /dev/null
++++ b/extensions/desktop-icons/po/es.po
+@@ -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 <EMAIL@ADDRESS>, YEAR.
++# Sergio Costas <rastersoft@gmail.com>, 2018.
++# Daniel Mustieles <daniel.mustieles@gmail.com>, 2018-2019.
++#
++msgid ""
++msgstr ""
++"Project-Id-Version: 1.0\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 10:37+0100\n"
++"Last-Translator: Daniel Mustieles <daniel.mustieles@gmail.com>\n"
++"Language-Team: es <gnome-es-list@gnome.org>\n"
++"Language: es\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: 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"
++msgstr "Tamaño de los iconos del escritorio"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Pequeño"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Estándar"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Grande"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Mostrar la carpeta personal en el escritorio"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Mostrar la papelera en el escritorio"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Nueva carpeta"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Pegar"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Deshacer"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Rehacer"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Mostrar el escritorio en Archivos"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Abrir en una terminal"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Cambiar el fondo..."
++
++#: desktopGrid.js:331
++msgid "Display Settings"
++msgstr "Configuración de pantalla"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Configuración"
++
++#: desktopGrid.js:576
++msgid "Enter file name…"
++msgstr "Introduzca el nombre del archivo…"
++
++#: desktopGrid.js:580
++msgid "OK"
++msgstr "Aceptar"
++
++#: fileItem.js:490
++msgid "Don’t Allow Launching"
++msgstr "No permitir lanzar"
++
++#: fileItem.js:492
++msgid "Allow Launching"
++msgstr "Permitir lanzar"
++
++#: fileItem.js:574
++msgid "Open"
++msgstr "Abrir"
++
++#: fileItem.js:578
++msgid "Open With Other Application"
++msgstr "Abrir con otra aplicación"
++
++#: fileItem.js:582
++msgid "Cut"
++msgstr "Cortar"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "Copiar"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "Renombrar…"
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "Mover a la papelera"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "Vaciar la papelera"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "Propiedades"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "Mostrar en Files"
++
++#: 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: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:16
++msgid "Show personal folder"
++msgstr "Mostrar la carpeta personal"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Mostrar la papelera"
++
++#: 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"
++
++#~ msgid "huge"
++#~ msgstr "inmenso"
++
++#~ msgid "Maximum width for the icons and filename."
++#~ msgstr "Ancho máximo de los iconos y el nombre de fichero."
++
++#~ msgid "Shows the Documents folder in the desktop."
++#~ msgstr "Muestra la carpeta Documentos en el escritorio."
++
++#~ msgid "Shows the Downloads folder in the desktop."
++#~ msgstr "Muestra la carpeta Descargas en el escritorio."
++
++#~ msgid "Shows the Music folder in the desktop."
++#~ msgstr "Muestra la carpeta Música en el escritorio."
++
++#~ msgid "Shows the Pictures folder in the desktop."
++#~ msgstr "Muestra la carpeta Imágenes en el escritorio."
++
++#~ msgid "Shows the Videos folder in the desktop."
++#~ 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..71ac40d
+--- /dev/null
++++ b/extensions/desktop-icons/po/fi.po
+@@ -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.
++# Jiri Grönroos <jiri.gronroos@iki.fi>, 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: 2019-03-01 12:11+0000\n"
++"PO-Revision-Date: 2019-03-02 11:29+0200\n"
++"Last-Translator: Jiri Grönroos <jiri.gronroos+l10n@iki.fi>\n"
++"Language-Team: Finnish <lokalisointi-lista@googlegroups.com>\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"
++"X-Generator: Poedit 2.0.6\n"
++
++#: 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:102
++msgid "Small"
++msgstr "Pieni"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Normaali"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Suuri"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Näytä kotikansio työpöydällä"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Näytä roskakorin kuvake työpöydällä"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Uusi kansio"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Liitä"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Kumoa"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Tee uudeleen"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Näytä työpöytä tiedostonhallinnassa"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Avaa päätteessä"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Vaihda taustakuvaa…"
++
++#: desktopGrid.js:331
++msgid "Display Settings"
++msgstr "Näytön asetukset"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Asetukset"
++
++#: 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:578
++msgid "Open With Other Application"
++msgstr "Avaa toisella sovelluksella"
++
++#: fileItem.js:582
++msgid "Cut"
++msgstr "Leikkaa"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "Kopioi"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "Nimeä uudelleen…"
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "Siirrä roskakoriin"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "Tyhjennä roskakori"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "Ominaisuudet"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "Näytä tiedostonhallinnassa"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++msgid "Icon size"
++msgstr "Kuvakekoko"
++
++#: 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:16
++msgid "Show personal folder"
++msgstr "Näytä kotikansio"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Näytä roskakorin kuvake"
++
++#: 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
+--- /dev/null
++++ b/extensions/desktop-icons/po/fr.po
+@@ -0,0 +1,164 @@
++# French 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.
++# ghentdebian <ghent.debian@gmail.com>, 2018.
++# Charles Monzat <charles.monzat@numericable.fr>, 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-12-14 09:12+0000\n"
++"PO-Revision-Date: 2018-12-16 17:47+0100\n"
++"Last-Translator: Charles Monzat <charles.monzat@numericable.fr>\n"
++"Language-Team: GNOME French Team <gnomefr@traduc.org>\n"
++"Language: fr\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: Gtranslator 3.30.0\n"
++
++#: prefs.js:102
++msgid "Size for the desktop icons"
++msgstr "Taille des icônes du bureau"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Petite"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Normale"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Grande"
++
++#: prefs.js:102
++msgid "Huge"
++msgstr "Immense"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Montrer le dossier personnel sur le bureau"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Montrer la corbeille sur le bureau"
++
++#: desktopGrid.js:182 desktopGrid.js:301
++msgid "New Folder"
++msgstr "Nouveau dossier"
++
++#: desktopGrid.js:303
++msgid "Paste"
++msgstr "Coller"
++
++#: desktopGrid.js:304
++msgid "Undo"
++msgstr "Annuler"
++
++#: desktopGrid.js:305
++msgid "Redo"
++msgstr "Refaire"
++
++#: desktopGrid.js:307
++msgid "Open Desktop in Files"
++msgstr "Ouvrir le bureau dans Fichiers"
++
++#: desktopGrid.js:308
++msgid "Open Terminal"
++msgstr "Ouvrir un terminal"
++
++#: desktopGrid.js:310
++msgid "Change Background…"
++msgstr "Changer l’arrière-plan…"
++
++#: desktopGrid.js:311
++msgid "Display Settings"
++msgstr "Configuration d’affichage"
++
++#: desktopGrid.js:312
++msgid "Settings"
++msgstr "Paramètres"
++
++#: desktopGrid.js:568
++msgid "Enter file name…"
++msgstr "Saisir un nom de fichier…"
++
++#: desktopGrid.js:572
++msgid "OK"
++msgstr "Valider"
++
++#: desktopGrid.js:578
++msgid "Cancel"
++msgstr "Annuler"
++
++#: fileItem.js:485
++msgid "Don’t Allow Launching"
++msgstr "Ne pas autoriser le lancement"
++
++#: fileItem.js:487
++msgid "Allow Launching"
++msgstr "Autoriser le lancement"
++
++#: fileItem.js:550
++msgid "Open"
++msgstr "Ouvrir"
++
++#: fileItem.js:553
++msgid "Cut"
++msgstr "Couper"
++
++#: fileItem.js:554
++msgid "Copy"
++msgstr "Copier"
++
++#: fileItem.js:556
++msgid "Rename"
++msgstr "Renommer"
++
++#: fileItem.js:557
++msgid "Move to Trash"
++msgstr "Mettre à la corbeille"
++
++#: fileItem.js:567
++msgid "Empty Trash"
++msgstr "Vider la corbeille"
++
++#: fileItem.js:573
++msgid "Properties"
++msgstr "Propriétés"
++
++#: fileItem.js:575
++msgid "Show in Files"
++msgstr "Montrer dans Fichiers"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Icon size"
++msgstr "Taille d’icônes"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13
++msgid "Set the size for the desktop icons."
++msgstr "Définir la taille des icônes du bureau."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show personal folder"
++msgstr "Montrer le dossier personnel"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18
++msgid "Show the personal folder in the desktop."
++msgstr "Montrer le dossier personnel sur le bureau."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show trash icon"
++msgstr "Montrer l’icône de la corbeille"
++
++#: 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 "Ok"
++#~ msgstr "Valider"
+diff --git a/extensions/desktop-icons/po/fur.po b/extensions/desktop-icons/po/fur.po
+new file mode 100644
+index 0000000..3ab6129
+--- /dev/null
++++ 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.
++# Fabio Tomat <f.t.public@gmail.com>, 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-05 22:20+0100\n"
++"Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
++"Language-Team: Friulian <fur@li.org>\n"
++"Language: fur\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 "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 "Dimension pes iconis dal scritori"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Piçule"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standard"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Largje"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Mostre la cartele personâl intal scritori"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Mostre la icone de scovacere intal scritori"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Gnove cartele"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Tache"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Anule"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Torne fâ"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Mostre Scritori in File"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Vierç in Terminâl"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Cambie sfont…"
++
++#: desktopGrid.js:331
++msgid "Display Settings"
++msgstr "Impostazions visôr"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Impostazions"
++
++#: 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 "Vierç"
++
++#: fileItem.js:578
++msgid "Open With Other Application"
++msgstr "Vierç cuntune altre aplicazion"
++
++#: fileItem.js:582
++msgid "Cut"
++msgstr "Taie"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "Copie"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "Cambie non..."
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "Sposte te scovacere"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "Disvuede scovacere"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "Propietâts"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "Mostre in File"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++msgid "Icon size"
++msgstr "Dimension icone"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Set the size for the desktop icons."
++msgstr "Stabilìs la dimension pes iconis dal scritori."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16
++msgid "Show personal folder"
++msgstr "Mostre cartele personâl"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show the personal folder in the desktop."
++msgstr "Mostre la cartele personâl intal scritori."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21
++msgid "Show trash icon"
++msgstr "Mostre la icone de scovacere"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show the trash icon in the desktop."
++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..0d26696
+--- /dev/null
++++ 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 <EMAIL@ADDRESS>, 2019.
++#
++msgid ""
++msgstr ""
++"Project-Id-Version: gnome-shell-extension-desktop-icons\n"
++"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
++"POT-Creation-Date: 2019-03-05 11:27+0000\n"
++"PO-Revision-Date: 2019-03-23 16:03+0000\n"
++"Last-Translator: gogo <trebelnik2@gmail.com>\n"
++"Language-Team: Croatian <hr@li.org>\n"
++"MIME-Version: 1.0\n"
++"Content-Type: text/plain; charset=UTF-8\n"
++"Content-Transfer-Encoding: 8bit\n"
++"X-Launchpad-Export-Date: 2019-03-27 09:36+0000\n"
++"X-Generator: Launchpad (build 18910)\n"
++
++#: 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 "Veličina ikona radne površine"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Male"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standardne"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Velike"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Prikaži osobnu mapu na radnoj površini"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Prikaži mapu smeća na radnoj površini"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Nova mapa"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Zalijepi"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Poništi"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Ponovi"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Prikaži radnu površinu u Datotekama"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Otvori u Terminalu"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Promijeni pozadinu…"
++
++#: desktopGrid.js:331
++msgid "Display Settings"
++msgstr "Postavke zaslona"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Postavke"
++
++#: desktopGrid.js:576
++msgid "Enter file name…"
++msgstr "Upiši naziv datoteke…"
++
++#: desktopGrid.js:580
++msgid "OK"
++msgstr "U redu"
++
++#: fileItem.js:490
++msgid "Don’t Allow Launching"
++msgstr "Ne dopuštaj pokretanje"
++
++#: fileItem.js:492
++msgid "Allow Launching"
++msgstr "Dopusti pokretanje"
++
++#: fileItem.js:574
++msgid "Open"
++msgstr "Otvori"
++
++#: 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 <ur.balazs at fsf dot hu>, 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 <ur.balazs at fsf dot hu>\n"
++"Language-Team: Hungarian <gnome-hu-list at gnome dot org>\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 <kukuhsyafaat@gnome.org>, 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 <kukuhsyafaat@gnome.org>\n"
++"Language-Team: Indonesian <gnome-l10n-id@googlegroups.com>\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 <max.bra.gtalk@gmail.com>, 2019.
++# Milo Casagrande <milo@milo.name>, 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 <milo@milo.name>\n"
++"Language-Team: Italian <tp@lists.linux.it>\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 <translation@sicklylife.jp>, 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 <translation@sicklylife.jp>\n"
++"Language-Team: Japanese <gnome-translation@gnome.gr.jp>\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 "切り取り"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "コピー"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "名前の変更…"
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "ゴミ箱へ移動する"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "ゴミ箱を空にする"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "プロパティ"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "“ファイル”で表示する"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++msgid "Icon size"
++msgstr "アイコンサイズ"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Set the size for the desktop icons."
++msgstr "デスクトップのアイコンサイズを設定します。"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16
++msgid "Show personal folder"
++msgstr "ホームフォルダーを表示する"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show the personal folder in the desktop."
++msgstr "デスクトップにホームフォルダーを表示します。"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21
++msgid "Show trash icon"
++msgstr "ゴミ箱アイコンを表示する"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show the trash icon in the desktop."
++msgstr "デスクトップにゴミ箱のアイコンを表示します。"
+diff --git a/extensions/desktop-icons/po/meson.build b/extensions/desktop-icons/po/meson.build
+new file mode 100644
+index 0000000..b2e9e42
+--- /dev/null
++++ 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 <nthn@unseen.is>, 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 <nthn@unseen.is>\n"
++"Language-Team: Dutch <gnome-nl-list@gnome.org>\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..f57b3be
+--- /dev/null
++++ b/extensions/desktop-icons/po/pl.po
+@@ -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.
++# Piotr Drąg <piotrdrag@gmail.com>, 2018-2019.
++# Aviary.pl <community-poland@mozilla.org>, 2018-2019.
++#
++msgid ""
++msgstr ""
++"Project-Id-Version: desktop-icons\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-05-01 13:03+0200\n"
++"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
++"Language-Team: Polish <community-poland@mozilla.org>\n"
++"Language: pl\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%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"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Mały"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standardowy"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Duży"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Katalog domowy na pulpicie"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Kosz na pulpicie"
++
++#: desktopGrid.js:323
++msgid "New Folder"
++msgstr "Nowy katalog"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Wklej"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Cofnij"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Ponów"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Wyświetl pulpit w menedżerze plików"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Otwórz w terminalu"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Zmień tło…"
++
++#: desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Ustawienia ekranu"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Ustawienia"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Nazwa pliku…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "OK"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Nie odnaleziono polecenia"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "Nie zezwalaj na uruchamianie"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Zezwól na uruchamianie"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Otwórz"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Otwórz za pomocą innego programu"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Wytnij"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Skopiuj"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Zmień nazwę…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Przenieś do kosza"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Opróżnij kosz"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Właściwości"
++
++#: fileItem.js:608
++msgid "Show in Files"
++msgstr "Wyświetl w menedżerze plików"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++msgid "Icon size"
++msgstr "Rozmiar ikon"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Set the size for the desktop icons."
++msgstr "Ustawia rozmiar ikon na pulpicie."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16
++msgid "Show personal folder"
++msgstr "Katalog domowy"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show the personal folder in the desktop."
++msgstr "Wyświetla katalog domowy na pulpicie."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21
++msgid "Show trash icon"
++msgstr "Kosz"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show the trash icon in the desktop."
++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..8d61c72
+--- /dev/null
++++ b/extensions/desktop-icons/po/pt_BR.po
+@@ -0,0 +1,199 @@
++# Brazilian Portuguese 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.
++# Enrico Nicoletto <liverig@gmail.com>, 2018.
++# Rafael Fontenelle <rafaelff@gnome.org>, 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-04-29 14:11+0000\n"
++"PO-Revision-Date: 2019-04-29 17:35-0300\n"
++"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n"
++"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\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: 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"
++msgstr "Tamanho para os ícones da área de trabalho"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Pequeno"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Padrão"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Grande"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Mostrar a pasta pessoal na área de trabalho"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Mostrar o ícone da lixeira na área de trabalho"
++
++#: desktopGrid.js:323
++msgid "New Folder"
++msgstr "Nova pasta"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Colar"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Desfazer"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Refazer"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Mostrar a área de trabalho no Arquivos"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Abrir no terminal"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Alterar plano de fundo…"
++
++#: desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Configurações de exibição"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Configurações"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Insira um nome de arquivo…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "OK"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Comando não encontrado"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "Não permitir iniciar"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Permitir iniciar"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Abrir"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Abrir com outro aplicativo"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Recortar"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Copiar"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Renomear…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Mover para a lixeira"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Esvaziar lixeira"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Propriedades"
++
++#: fileItem.js:608
++msgid "Show in Files"
++msgstr "Mostrar no Arquivos"
++
++#: 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: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:16
++msgid "Show personal folder"
++msgstr "Mostrar pasta pessoal"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Mostrar ícone da lixeira"
++
++#: 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
+new file mode 100644
+index 0000000..4094f16
+--- /dev/null
++++ b/extensions/desktop-icons/po/ru.po
+@@ -0,0 +1,153 @@
++# SOME DESCRIPTIVE TITLE.
++# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
++# This file is distributed under the same license as the PACKAGE package.
++# Eaglers <eaglersdeveloper@gmail.com>, 2018.
++#
++msgid ""
++msgstr ""
++"Project-Id-Version: \n"
++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-"
++"icons/issues\n"
++"POT-Creation-Date: 2018-11-22 08:42+0000\n"
++"PO-Revision-Date: 2018-11-22 22:02+0300\n"
++"Last-Translator: Stas Solovey <whats_up@tut.by>\n"
++"Language-Team: Russian <gnome-cyr@gnome.org>\n"
++"Language: ru\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%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
++"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
++"X-Generator: Poedit 2.2\n"
++
++#: prefs.js:89
++msgid "Size for the desktop icons"
++msgstr "Размер значков"
++
++#: prefs.js:89
++msgid "Small"
++msgstr "Маленький"
++
++#: prefs.js:89
++msgid "Standard"
++msgstr "Стандартный"
++
++#: prefs.js:89
++msgid "Large"
++msgstr "Большой"
++
++#: prefs.js:89
++msgid "Huge"
++msgstr "Огромный"
++
++#: prefs.js:90
++msgid "Show the personal folder in the desktop"
++msgstr "Показывать домашнюю папку на рабочем столе"
++
++#: prefs.js:91
++msgid "Show the trash icon in the desktop"
++msgstr "Показывать «Корзину» на рабочем столе"
++
++#: desktopGrid.js:185 desktopGrid.js:304
++msgid "New Folder"
++msgstr "Создать папку"
++
++#: desktopGrid.js:306
++msgid "Paste"
++msgstr "Вставить"
++
++#: desktopGrid.js:307
++msgid "Undo"
++msgstr "Отменить"
++
++#: desktopGrid.js:308
++msgid "Redo"
++msgstr "Повторить"
++
++#: desktopGrid.js:310
++msgid "Open Desktop in Files"
++msgstr "Открыть «Рабочий стол» в «Файлах»"
++
++#: desktopGrid.js:311
++msgid "Open Terminal"
++msgstr "Открыть терминал"
++
++#: desktopGrid.js:313
++msgid "Change Background…"
++msgstr "Изменить фон…"
++
++#: desktopGrid.js:314
++msgid "Display Settings"
++msgstr "Настройки дисплея"
++
++#: desktopGrid.js:315
++msgid "Settings"
++msgstr "Параметры"
++
++#: desktopGrid.js:569
++msgid "Enter file name…"
++msgstr "Ввести имя файла…"
++
++#: desktopGrid.js:573
++msgid "Ok"
++msgstr "ОК"
++
++#: desktopGrid.js:579
++msgid "Cancel"
++msgstr "Отмена"
++
++#: fileItem.js:390
++msgid "Open"
++msgstr "Открыть"
++
++#: fileItem.js:393
++msgid "Cut"
++msgstr "Вырезать"
++
++#: fileItem.js:394
++msgid "Copy"
++msgstr "Вставить"
++
++#: fileItem.js:395
++msgid "Rename"
++msgstr "Переименовать"
++
++#: fileItem.js:396
++msgid "Move to Trash"
++msgstr "Переместить в корзину"
++
++#: fileItem.js:400
++msgid "Empty trash"
++msgstr "Очистить корзину"
++
++#: fileItem.js:406
++msgid "Properties"
++msgstr "Свойства"
++
++#: fileItem.js:408
++msgid "Show in Files"
++msgstr "Показать в «Файлах»"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Icon size"
++msgstr "Размер значков"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13
++msgid "Set the size for the desktop icons."
++msgstr "Установить размер значков на рабочем столе."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show personal folder"
++msgstr "Показывать домашнюю папку"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18
++msgid "Show the personal folder in the desktop."
++msgstr "Показывать значок домашней папки на рабочем столе."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show trash icon"
++msgstr "Показывать значок корзины"
++
++#: 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 <anders.jonsson@norsjovallen.se>, 2018, 2019.
++# Josef Andersson <l10nl18nsweja@gmail.com>, 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 <anders.jonsson@norsjovallen.se>\n"
++"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\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 <libreajans@gmail.com>, 2019.
++# Serdar Sağlam <teknomobil@yandex.com>, 2019
++# Emin Tufan Çetin <etcetin@gmail.com>, 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 <etcetin@gmail.com>\n"
++"Language-Team: Türkçe <gnome-turk@gnome.org>\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
+--- /dev/null
++++ b/extensions/desktop-icons/po/zh_TW.po
+@@ -0,0 +1,135 @@
++# Chinese (Taiwan) 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.
++# Yi-Jyun Pan <pan93412@gmail.com>, 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-22 14:12+0000\n"
++"PO-Revision-Date: 2018-10-24 21:31+0800\n"
++"Language-Team: Chinese (Taiwan) <chinese-l10n@googlegroups.com>\n"
++"Language: zh_TW\n"
++"MIME-Version: 1.0\n"
++"Content-Type: text/plain; charset=UTF-8\n"
++"Content-Transfer-Encoding: 8bit\n"
++"Last-Translator: pan93412 <pan93412@gmail.com>\n"
++"X-Generator: Poedit 2.2\n"
++
++#: prefs.js:89
++msgid "Size for the desktop icons"
++msgstr "桌面圖示的大小"
++
++#: prefs.js:89
++msgid "Small"
++msgstr "小圖示"
++
++#: prefs.js:89
++msgid "Standard"
++msgstr "標準大小圖示"
++
++#: prefs.js:89
++msgid "Large"
++msgstr "大圖示"
++
++#: prefs.js:89
++msgid "Huge"
++msgstr "巨大圖示"
++
++#: prefs.js:90
++msgid "Show the personal folder in the desktop"
++msgstr "在桌面顯示個人資料夾"
++
++#: prefs.js:91
++msgid "Show the trash icon in the desktop"
++msgstr "在桌面顯示垃圾桶圖示"
++
++#: desktopGrid.js:178 desktopGrid.js:297
++msgid "New Folder"
++msgstr "新增資料夾"
++
++#: desktopGrid.js:299
++msgid "Paste"
++msgstr "貼上"
++
++#: desktopGrid.js:300
++msgid "Undo"
++msgstr "復原"
++
++#: desktopGrid.js:301
++msgid "Redo"
++msgstr "重做"
++
++#: desktopGrid.js:303
++msgid "Open Desktop in Files"
++msgstr "在《檔案》中開啟桌面"
++
++#: desktopGrid.js:304
++msgid "Open Terminal"
++msgstr "開啟終端器"
++
++#: desktopGrid.js:306
++msgid "Change Background…"
++msgstr "變更背景圖片…"
++
++#: desktopGrid.js:307
++msgid "Display Settings"
++msgstr "顯示設定"
++
++#: desktopGrid.js:308
++msgid "Settings"
++msgstr "設定"
++
++#: fileItem.js:223
++msgid "Open"
++msgstr "開啟"
++
++#: fileItem.js:226
++msgid "Cut"
++msgstr "剪下"
++
++#: fileItem.js:227
++msgid "Copy"
++msgstr "複製"
++
++#: fileItem.js:228
++msgid "Move to Trash"
++msgstr "移動到垃圾桶"
++
++#: fileItem.js:232
++msgid "Empty trash"
++msgstr "清空回收桶"
++
++#: fileItem.js:238
++msgid "Properties"
++msgstr "屬性"
++
++#: fileItem.js:240
++msgid "Show in Files"
++msgstr "在《檔案》中顯示"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Icon size"
++msgstr "圖示大小"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13
++msgid "Set the size for the desktop icons."
++msgstr "設定桌面圖示的大小。"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show personal folder"
++msgstr "顯示個人資料夾"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18
++msgid "Show the personal folder in the desktop."
++msgstr "在桌面顯示個人資料夾。"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show trash icon"
++msgstr "顯示垃圾桶圖示"
++
++#: 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/prefs.js b/extensions/desktop-icons/prefs.js
+new file mode 100644
+index 0000000..4b8d986
+--- /dev/null
++++ b/extensions/desktop-icons/prefs.js
+@@ -0,0 +1,159 @@
++
++/* Desktop Icons GNOME Shell extension
++ *
++ * Copyright (C) 2017 Carlos Soriano <csoriano@redhat.com>
++ *
++ * This program is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
++ */
++
++const Gtk = imports.gi.Gtk;
++const GObject = imports.gi.GObject;
++const Gio = imports.gi.Gio;
++const GioSSS = Gio.SettingsSchemaSource;
++const ExtensionUtils = imports.misc.extensionUtils;
++const Gettext = imports.gettext;
++
++const Config = imports.misc.config;
++
++var _ = Gettext.domain('desktop-icons').gettext;
++
++const SCHEMA_NAUTILUS = 'org.gnome.nautilus.preferences';
++const SCHEMA_GTK = 'org.gtk.Settings.FileChooser';
++const SCHEMA = 'org.gnome.shell.extensions.desktop-icons';
++
++const ICON_SIZE = { 'small': 48, 'standard': 64, 'large': 96 };
++const ICON_WIDTH = { 'small': 120, 'standard': 128, 'large': 128 };
++const ICON_HEIGHT = { 'small': 98, 'standard': 114, 'large': 146 };
++
++var FileType = {
++    NONE: null,
++    USER_DIRECTORY_HOME: 'show-home',
++    USER_DIRECTORY_TRASH: 'show-trash',
++}
++
++var nautilusSettings;
++var gtkSettings;
++var settings;
++// This is already in Nautilus settings, so it should not be made tweakable here
++var CLICK_POLICY_SINGLE = false;
++
++function initTranslations() {
++    let extension = ExtensionUtils.getCurrentExtension();
++
++    let localedir = extension.dir.get_child('locale');
++    if (localedir.query_exists(null))
++        Gettext.bindtextdomain('desktop-icons', localedir.get_path());
++    else
++        Gettext.bindtextdomain('desktop-icons', Config.LOCALEDIR);
++}
++
++function init() {
++    let schemaSource = GioSSS.get_default();
++    let schemaGtk = schemaSource.lookup(SCHEMA_GTK, true);
++    gtkSettings = new Gio.Settings({ settings_schema: schemaGtk });
++    let schemaObj = schemaSource.lookup(SCHEMA_NAUTILUS, true);
++    if (!schemaObj) {
++        nautilusSettings = null;
++    } else {
++        nautilusSettings = new Gio.Settings({ settings_schema: schemaObj });;
++        nautilusSettings.connect('changed', _onNautilusSettingsChanged);
++        _onNautilusSettingsChanged();
++    }
++    settings = get_schema(SCHEMA);
++}
++
++function get_schema(schema) {
++    let extension = ExtensionUtils.getCurrentExtension();
++
++    // 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 });
++}
++
++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") }));
++    frame.add(buildSwitcher('show-home', _("Show the personal folder in the desktop")));
++    frame.add(buildSwitcher('show-trash', _("Show the trash icon in the desktop")));
++    frame.show_all();
++    return frame;
++}
++
++function buildSwitcher(key, labelText) {
++    let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, spacing: 10 });
++    let label = new Gtk.Label({ label: labelText, xalign: 0 });
++    let switcher = new Gtk.Switch({ active: settings.get_boolean(key) });
++    settings.bind(key, switcher, 'active', 3);
++    hbox.pack_start(label, true, true, 0);
++    hbox.add(switcher);
++    return hbox;
++}
++
++function buildSelector(key, labelText, elements) {
++    let listStore = new Gtk.ListStore();
++    listStore.set_column_types ([GObject.TYPE_STRING, GObject.TYPE_STRING]);
++    let schemaKey = settings.settings_schema.get_key(key);
++    let values = schemaKey.get_range().get_child_value(1).get_child_value(0).get_strv();
++    for (let val of values) {
++        let iter = listStore.append();
++        let visibleText = val;
++        if (visibleText in elements)
++            visibleText = elements[visibleText];
++        listStore.set (iter, [0, 1], [visibleText, val]);
++    }
++    let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, spacing: 10 });
++    let label = new Gtk.Label({ label: labelText, xalign: 0 });
++    let combo = new Gtk.ComboBox({model: listStore});
++    let rendererText = new Gtk.CellRendererText();
++    combo.pack_start (rendererText, false);
++    combo.add_attribute (rendererText, 'text', 0);
++    combo.set_id_column(1);
++    settings.bind(key, combo, 'active-id', 3);
++    hbox.pack_start(label, true, true, 0);
++    hbox.add(combo);
++    return hbox;
++}
++
++function _onNautilusSettingsChanged() {
++    CLICK_POLICY_SINGLE = nautilusSettings.get_string('click-policy') == 'single';
++}
++
++function get_icon_size() {
++    // this one doesn't need scaling because Gnome Shell automagically scales the icons
++    return ICON_SIZE[settings.get_string('icon-size')];
++}
++
++function get_desired_width(scale_factor) {
++    return ICON_WIDTH[settings.get_string('icon-size')] * scale_factor;
++}
++
++function get_desired_height(scale_factor) {
++    return ICON_HEIGHT[settings.get_string('icon-size')] * scale_factor;
++}
+diff --git a/extensions/desktop-icons/schemas/meson.build b/extensions/desktop-icons/schemas/meson.build
+new file mode 100644
+index 0000000..2b17916
+--- /dev/null
++++ b/extensions/desktop-icons/schemas/meson.build
+@@ -0,0 +1,6 @@
++gnome.compile_schemas()
++
++install_data(
++  'org.gnome.shell.extensions.desktop-icons.gschema.xml',
++  install_dir : schema_dir
++)
+diff --git a/extensions/desktop-icons/schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml b/extensions/desktop-icons/schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml
+new file mode 100644
+index 0000000..bb4e50f
+--- /dev/null
++++ b/extensions/desktop-icons/schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml
+@@ -0,0 +1,25 @@
++<?xml version="1.0" encoding="UTF-8"?>
++<schemalist gettext-domain="desktop-icons">
++    <enum id="org.gnome.shell.extension.desktop-icons.ZoomLevel">
++        <value value="0" nick="small"/>
++        <value value="1" nick="standard"/>
++        <value value="2" nick="large"/>
++    </enum>
++    <schema path="/org/gnome/shell/extensions/desktop-icons/" id="org.gnome.shell.extensions.desktop-icons">
++    <key name="icon-size" enum="org.gnome.shell.extension.desktop-icons.ZoomLevel">
++        <default>'standard'</default>
++        <summary>Icon size</summary>
++        <description>Set the size for the desktop icons.</description>
++    </key>
++	<key type="b" name="show-home">
++        <default>true</default>
++        <summary>Show personal folder</summary>
++        <description>Show the personal folder in the desktop.</description>
++    </key>
++	<key type="b" name="show-trash">
++        <default>true</default>
++        <summary>Show trash icon</summary>
++        <description>Show the trash icon in the desktop.</description>
++    </key>
++  </schema>
++</schemalist>
+diff --git a/extensions/desktop-icons/stylesheet.css b/extensions/desktop-icons/stylesheet.css
+new file mode 100644
+index 0000000..17d4b32
+--- /dev/null
++++ b/extensions/desktop-icons/stylesheet.css
+@@ -0,0 +1,38 @@
++.file-item {
++    padding: 4px;
++    border: 1px;
++    margin: 1px;
++}
++
++.file-item:hover {
++   background-color: rgba(238, 238, 238, 0.2);
++}
++
++.name-label {
++    text-shadow: 1px 1px black;
++    color: white;
++    text-align: center;
++}
++
++.draggable {
++    background-color: red;
++}
++
++.rename-popup {
++    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 cf855a0..6e8c41f 100644
+--- a/meson.build
++++ b/meson.build
+@@ -33,6 +33,7 @@ uuid_suffix = '@gnome-shell-extensions.gcampax.github.com'
+ 
+ classic_extensions = [
+   'apps-menu',
++  'desktop-icons',
+   'places-menu',
+   'launch-new-instance',
+   'window-list'
+diff --git a/po/ca.po b/po/ca.po
+index f3be74c..53a097f 100644
+--- a/po/ca.po
++++ b/po/ca.po
+@@ -1,11 +1,19 @@
++# #-#-#-#-#  ca.po (gnome-shell-extensions)  #-#-#-#-#
+ # Catalan translation for gnome-shell-extensions.
+ # Copyright (C) 2011 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ # Jordi Mas i Hernandez <jmas@softcatala.org>, 2011.
+ # Gil Forcada <gilforcada@guifi.net>, 2012, 2013, 2014.
+ #
++# #-#-#-#-#  ca.po (1.0)  #-#-#-#-#
++#
++# This file is distributed under the same license as the PACKAGE package.
++# Jordi Mas i Hernandez <jmas@softcatala.org>, 2019
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  ca.po (gnome-shell-extensions)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions\n"
+ "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
+ "shell&keywords=I18N+L10N&component=extensions\n"
+@@ -18,6 +26,20 @@ msgstr ""
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=2; plural=n != 1;\n"
++"#-#-#-#-#  ca.po (1.0)  #-#-#-#-#\n"
++"Project-Id-Version: 1.0\n"
++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-"
++"icons/issues\n"
++"POT-Creation-Date: 2019-07-22 10:24+0200\n"
++"PO-Revision-Date: 2019-07-22 10:24+0200\n"
++"Language: ca\n"
++"Language-Team: Catalan <info@softcatala.org>\n"
++"MIME-Version: 1.0\n"
++"Content-Type: text/plain; charset=UTF-8\n"
++"Content-Transfer-Encoding: 8bit\n"
++"Last-Translator: Jordi Mas <jmas@softcatala.org>\n"
++"Language: ca\n"
++"X-Generator: Poedit 2.2.1\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -362,6 +384,178 @@ msgstr "Nom"
+ msgid "Workspace %d"
+ msgstr "Espai de treball %d"
+ 
++#: ../createFolderDialog.js:48
++msgid "New folder name"
++msgstr "Nom de la carpeta nou"
++
++#: ../createFolderDialog.js:72
++msgid "Create"
++msgstr "Crea"
++
++#: ../createFolderDialog.js:74 ../desktopGrid.js:592
++msgid "Cancel"
++msgstr "Cancel·la"
++
++#: ../createFolderDialog.js:145
++msgid "Folder names cannot contain “/”."
++msgstr "Els noms de carpetes no poden contenir «/»."
++
++#: ../createFolderDialog.js:148
++msgid "A folder cannot be called “.”."
++msgstr "Una carpeta no es pot anomenar «.»."
++
++#: ../createFolderDialog.js:151
++msgid "A folder cannot be called “..”."
++msgstr "Una carpeta no es pot anomenar «..»."
++
++#: ../createFolderDialog.js:153
++msgid "Folders with “.” at the beginning of their name are hidden."
++msgstr "Les carpetes amb un «.» a l'inici del seu nom s'amaguen."
++
++#: ../createFolderDialog.js:155
++msgid "There is already a file or folder with that name."
++msgstr "Ja existeix un fitxer o carpeta amb aquest nom."
++
++#: ../prefs.js:102
++msgid "Size for the desktop icons"
++msgstr "Mida de les icones d'escriptori"
++
++#: ../prefs.js:102
++msgid "Small"
++msgstr "Petita"
++
++#: ../prefs.js:102
++msgid "Standard"
++msgstr "Estàndard"
++
++#: ../prefs.js:102
++msgid "Large"
++msgstr "Gran"
++
++#: ../prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Mostra la carpeta personal a l'escriptori"
++
++#: ../prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Mostra la icona de la paperera a l'escriptori"
++
++#: ../desktopGrid.js:323
++msgid "New Folder"
++msgstr "Carpeta nova"
++
++#: ../desktopGrid.js:325
++msgid "Paste"
++msgstr "Enganxa"
++
++#: ../desktopGrid.js:326
++msgid "Undo"
++msgstr "Desfés"
++
++#: ../desktopGrid.js:327
++msgid "Redo"
++msgstr "Refés"
++
++#: ../desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Mostra l'escriptori al Fitxers"
++
++#: ../desktopGrid.js:330 ../fileItem.js:612
++msgid "Open in Terminal"
++msgstr "Obre al Terminal"
++
++#: ../desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Canvia el fons de l'escriptori…"
++
++#: ../desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Paràmetres de la pantalla"
++
++#: ../desktopGrid.js:335
++msgid "Settings"
++msgstr "Paràmetres"
++
++#: ../desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Introduïu un nom de fitxer…"
++
++#: ../desktopGrid.js:586
++msgid "OK"
++msgstr "D'acord"
++
++#: ../desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "\tNo s'ha trobat l'ordre"
++
++#: ../fileItem.js:500
++msgid "Don’t Allow Launching"
++msgstr "No permetis que s'iniciï"
++
++#: ../fileItem.js:502
++msgid "Allow Launching"
++msgstr "Permet que s'iniciï"
++
++#: ../fileItem.js:580
++msgid "Open"
++msgstr "Obre"
++
++#: ../fileItem.js:584
++msgid "Open With Other Application"
++msgstr "Obre amb una altra aplicació..."
++
++#: ../fileItem.js:588
++msgid "Cut"
++msgstr "Retalla"
++
++#: ../fileItem.js:589
++msgid "Copy"
++msgstr "Copia"
++
++#: ../fileItem.js:591
++msgid "Rename…"
++msgstr "Canvia el nom…"
++
++#: ../fileItem.js:592
++msgid "Move to Trash"
++msgstr "Mou a la paperera"
++
++#: ../fileItem.js:602
++msgid "Empty Trash"
++msgstr "Buida la paperera"
++
++#: ../fileItem.js:608
++msgid "Properties"
++msgstr "Propietats"
++
++#: ../fileItem.js:610
++msgid "Show in Files"
++msgstr "Mostra al Fitxers"
++
++#: ../schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml.h:1
++msgid "Icon size"
++msgstr "Mida d'icona"
++
++#: ../schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml.h:2
++msgid "Set the size for the desktop icons."
++msgstr "Estableix la mida per les icones de l'escriptori."
++
++#: ../schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml.h:3
++msgid "Show personal folder"
++msgstr "Mostra la carpeta personal"
++
++#: ../schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml.h:4
++msgid "Show the personal folder in the desktop."
++msgstr "Mostra la carpeta personal a l'escriptori."
++
++#: ../schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml.h:5
++msgid "Show trash icon"
++msgstr "Mostra la icona de la paperera"
++
++#: ../schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml.h:6
++msgid "Show the trash icon in the desktop."
++msgstr "Mostra la icona de la paperera a l'escriptori."
++
+ #~ msgid "GNOME Shell Classic"
+ #~ msgstr "GNOME Shell clàssic"
+ 
+diff --git a/po/cs.po b/po/cs.po
+index 04bb195..7ce51c9 100644
+--- a/po/cs.po
++++ b/po/cs.po
+@@ -1,11 +1,21 @@
++# #-#-#-#-#  cs.po (gnome-shell-extensions)  #-#-#-#-#
+ # Czech translation for gnome-shell-extensions.
+ # Copyright (C) 2011 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ # Petr Kovar <pknbe@volny.cz>, 2013.
+ # Marek Černocký <marek@manet.cz>, 2011, 2012, 2013, 2014, 2015, 2017.
+ #
++# #-#-#-#-#  cs.po (desktop-icons master)  #-#-#-#-#
++# 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ý <marek@manet.cz>, 2018.
++# Milan Zink <zeten30@gmail.com>, 2018.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  cs.po (gnome-shell-extensions)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions\n"
+ "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
+ "shell&keywords=I18N+L10N&component=extensions\n"
+@@ -19,6 +29,20 @@ msgstr ""
+ "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.6\n"
++"#-#-#-#-#  cs.po (desktop-icons master)  #-#-#-#-#\n"
++"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:49+0000\n"
++"PO-Revision-Date: 2019-03-02 18:02+0100\n"
++"Last-Translator: Daniel Rusek <mail@asciiwolf.com>\n"
++"Language-Team: Czech <zeten30@gmail.com>\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: Poedit 2.2.1\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -350,3 +374,177 @@ msgstr "Název"
+ #, javascript-format
+ msgid "Workspace %d"
+ msgstr "Pracovní plocha %d"
++
++#: 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:102
++msgid "Small"
++msgstr "malé"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "standardní"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "velké"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Zobrazovat osobní složku na pracovní ploše"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Zobrazovat ikonu koše na pracovní ploše"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Nová složka"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Vložit"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Zpět"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Znovu"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Zobrazit plochu v Souborech"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Otevřít v terminálu"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Změnit pozadí…"
++
++#: desktopGrid.js:331
++msgid "Display Settings"
++msgstr "Zobrazit nastavení"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Nastavení"
++
++#: 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:578
++msgid "Open With Other Application"
++msgstr "Otevřít pomocí jiné aplikace"
++
++#: fileItem.js:582
++msgid "Cut"
++msgstr "Vyjmout"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "Kopírovat"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "Přejmenovat…"
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "Přesunout do koše"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "Vyprázdnit koš"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "Vlastnosti"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "Zobrazit v Souborech"
++
++#: 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: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:16
++msgid "Show personal folder"
++msgstr "Zobrazovat osobní složku"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Zobrazovat koš"
++
++#: 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/po/da.po b/po/da.po
+index 5a4c257..4e1f110 100644
+--- a/po/da.po
++++ b/po/da.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  da.po (gnome-shell-extensions master)  #-#-#-#-#
+ # Danish translation for gnome-shell-extensions.
+ # Copyright (C) 2011-2017 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+@@ -6,8 +7,16 @@
+ # Ask Hjorth Larsen <asklarsen@gmail.com>, 2015, 2017.
+ # Joe Hansen <joedalton2@yahoo.dk>, 2017.
+ #
++# #-#-#-#-#  da.po (desktop-icons master)  #-#-#-#-#
++# 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.
++# Alan Mortensen <alanmortensen.am@gmail.com>, 2018.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  da.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"
+@@ -20,6 +29,19 @@ msgstr ""
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
++"#-#-#-#-#  da.po (desktop-icons master)  #-#-#-#-#\n"
++"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 14:55+0200\n"
++"Last-Translator: scootergrisen\n"
++"Language-Team: Danish <dansk@dansk-gruppen.dk>\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"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -359,3 +381,175 @@ msgstr "Navn"
+ #, javascript-format
+ msgid "Workspace %d"
+ msgstr "Arbejdsområde %d"
++
++#: createFolderDialog.js:48
++#| msgid "New Folder"
++msgid "New folder name"
++msgstr "Nyt mappenavn"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "Opret"
++
++#: createFolderDialog.js:74 desktopGrid.js:586
++msgid "Cancel"
++msgstr "Annullér"
++
++#: createFolderDialog.js:145
++msgid "Folder names cannot contain “/”."
++msgstr "Mappenavne må ikke indeholde “/”."
++
++#: createFolderDialog.js:148
++msgid "A folder cannot be called “.”."
++msgstr "En mappe må ikke kaldes “.”."
++
++#: createFolderDialog.js:151
++msgid "A folder cannot be called “..”."
++msgstr "En mappe må ikke kaldes “..”."
++
++#: createFolderDialog.js:153
++msgid "Folders with “.” at the beginning of their name are hidden."
++msgstr "Mapper med “.” i begyndelsen af deres navn er skjulte."
++
++#: createFolderDialog.js:155
++msgid "There is already a file or folder with that name."
++msgstr "Der findes allerede en fil eller mappe med det navn."
++
++#: prefs.js:102
++msgid "Size for the desktop icons"
++msgstr "Størrelsen på skrivebordsikoner"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Små"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standard"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Store"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Vis den personlige mappe på skrivebordet"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Vis papirkurvsikonet på skrivebordet"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Ny mappe"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Indsæt"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Fortryd"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Omgør"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Vis skrivebordet i Filer"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Åbn i terminal"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Skift baggrund …"
++
++#: desktopGrid.js:331
++msgid "Display Settings"
++msgstr "Skærmindstillinger"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Indstillinger"
++
++#: desktopGrid.js:576
++msgid "Enter file name…"
++msgstr "Indtast filnavn …"
++
++#: desktopGrid.js:580
++msgid "OK"
++msgstr "OK"
++
++#: fileItem.js:490
++msgid "Don’t Allow Launching"
++msgstr "Tillad ikke opstart"
++
++#: fileItem.js:492
++msgid "Allow Launching"
++msgstr "Tillad opstart"
++
++#: fileItem.js:574
++msgid "Open"
++msgstr "Åbn"
++
++#: fileItem.js:578
++msgid "Open With Other Application"
++msgstr "Åbn med et andet program"
++
++#: fileItem.js:582
++msgid "Cut"
++msgstr "Klip"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "Kopiér"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "Omdøb …"
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "Flyt til papirkurven"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "Tøm papirkurven"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "Egenskaber"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "Vis i Filer"
++
++#: 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:12
++msgid "Set the size for the desktop icons."
++msgstr "Angiv størrelsen på skrivebordsikoner."
++
++#: 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: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:21
++msgid "Show trash icon"
++msgstr "Vis papirkurvsikon"
++
++#: 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/po/de.po b/po/de.po
+index 01924b8..6bd5c83 100644
+--- a/po/de.po
++++ b/po/de.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  de.po (gnome-shell-extensions master)  #-#-#-#-#
+ # German translation for gnome-shell-extensions.
+ # Copyright (C) 2011 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+@@ -7,8 +8,17 @@
+ # Wolfgang Stöggl <c72578@yahoo.de>, 2014.
+ # Paul Seyfert <pseyfert@mathphys.fsk.uni-heidelberg.de>, 2017.
+ #
++# #-#-#-#-#  de.po (desktop-icons master)  #-#-#-#-#
++# 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 <mario.blaettermann@gmail.com>, 2018.
++# rugk <rugk+i18n@posteo.de>, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  de.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"
+@@ -22,6 +32,20 @@ msgstr ""
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
+ "X-Generator: Poedit 2.0.2\n"
++"#-#-#-#-#  de.po (desktop-icons master)  #-#-#-#-#\n"
++"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-07 22:46+0000\n"
++"PO-Revision-Date: 2019-03-09 15:42+0100\n"
++"Last-Translator: Tim Sabsch <tim@sabsch.com>\n"
++"Language-Team: German <gnome-de@gnome.org>\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.2.1\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -366,3 +390,174 @@ msgstr "Name"
+ #, javascript-format
+ msgid "Workspace %d"
+ msgstr "Arbeitsfläche %d"
++
++#: 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:102
++msgid "Small"
++msgstr "Klein"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standard"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Groß"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Den persönlichen Ordner auf der Arbeitsfläche anzeigen"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Papierkorb-Symbol auf der Arbeitsfläche anzeigen"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Neuer Ordner"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Einfügen"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Rückgängig"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Wiederholen"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Schreibtisch in Dateien anzeigen"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Im Terminal öffnen"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Hintergrund ändern …"
++
++#: desktopGrid.js:331
++msgid "Display Settings"
++msgstr "Anzeigeeinstellungen"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Einstellungen"
++
++#: 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:578
++msgid "Open With Other Application"
++msgstr "Mit anderer Anwendung öffnen"
++
++#: fileItem.js:582
++msgid "Cut"
++msgstr "Ausschneiden"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "Kopieren"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "Umbenennen …"
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "In den Papierkorb verschieben"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "Papierkorb leeren"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "Eigenschaften"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "In Dateiverwaltung anzeigen"
++
++#: 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: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:16
++msgid "Show personal folder"
++msgstr "Persönlichen Ordner anzeigen"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Papierkorb-Symbol anzeigen"
++
++#: 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/po/en_GB.po b/po/en_GB.po
+index 92ae445..60fc687 100644
+--- a/po/en_GB.po
++++ b/po/en_GB.po
+@@ -1,11 +1,20 @@
++# #-#-#-#-#  en_GB.po (gnome-shell-extensions)  #-#-#-#-#
+ # British English translation of gnome-shell-extensions.
+ # Copyright (C) 2011 gnome-shell-extensions'S COPYRIGHT HOLDER.
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ # Bruce Cowan <bruce@bcowan.eu>, 2011, 2018.
+ # Chris Leonard <cjlhomeaddress@gmail.com>, 2012.
+ # Philip Withnall <philip@tecnocode.co.uk>, 2014.
++# #-#-#-#-#  en_GB.po (desktop-icons master)  #-#-#-#-#
++# British English 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.
++# Zander Brown <zbrown@gnome.org>, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  en_GB.po (gnome-shell-extensions)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions\n"
+ "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/"
+ "issues\n"
+@@ -20,6 +29,20 @@ msgstr ""
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
+ "X-Generator: Poedit 2.0.6\n"
+ "X-Project-Style: gnome\n"
++"#-#-#-#-#  en_GB.po (desktop-icons master)  #-#-#-#-#\n"
++"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-08-22 15:53+0000\n"
++"PO-Revision-Date: 2019-08-23 21:48+0100\n"
++"Last-Translator: Zander Brown <zbrown@gnome.org>\n"
++"Language-Team: English - United Kingdom <en_GB@li.org>\n"
++"Language: en_GB\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: Gtranslator 3.32.1\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -367,6 +390,178 @@ msgstr "Name"
+ msgid "Workspace %d"
+ msgstr "Workspace %d"
+ 
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++msgid "Icon size"
++msgstr "Icon size"
++
++#: desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Display Settings"
++
++#: createFolderDialog.js:74 desktopGrid.js:592
++msgid "Cancel"
++msgstr "Cancel"
++
++#: createFolderDialog.js:48
++msgid "New folder name"
++msgstr "New folder name"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "Create"
++
++#: createFolderDialog.js:145
++msgid "Folder names cannot contain “/”."
++msgstr "Folder names cannot contain “/”."
++
++#: createFolderDialog.js:148
++msgid "A folder cannot be called “.”."
++msgstr "A folder cannot be called “.”."
++
++#: createFolderDialog.js:151
++msgid "A folder cannot be called “..”."
++msgstr "A folder cannot be called “..”."
++
++#: createFolderDialog.js:153
++msgid "Folders with “.” at the beginning of their name are hidden."
++msgstr "Folders with “.” at the beginning of their name are hidden."
++
++#: createFolderDialog.js:155
++msgid "There is already a file or folder with that name."
++msgstr "There is already a file or folder with that name."
++
++#: prefs.js:102
++msgid "Size for the desktop icons"
++msgstr "Size for the desktop icons"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Small"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standard"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Large"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Show the personal folder on the desktop"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Show the wastebasket icon on the desktop"
++
++#: desktopGrid.js:323
++msgid "New Folder"
++msgstr "New Folder"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Paste"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Undo"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Redo"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Show Desktop in Files"
++
++#: desktopGrid.js:330 fileItem.js:626
++msgid "Open in Terminal"
++msgstr "Open in Terminal"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Change Background…"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Settings"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Enter file name…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "OK"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Command not found"
++
++#: fileItem.js:499
++msgid "Don’t Allow Launching"
++msgstr "Don’t Allow Launching"
++
++#: fileItem.js:501
++msgid "Allow Launching"
++msgstr "Allow Launching"
++
++#: fileItem.js:594
++msgid "Open"
++msgstr "Open"
++
++#: fileItem.js:598
++msgid "Open With Other Application"
++msgstr "Open With Other Application"
++
++#: fileItem.js:602
++msgid "Cut"
++msgstr "Cut"
++
++#: fileItem.js:603
++msgid "Copy"
++msgstr "Copy"
++
++#: fileItem.js:605
++msgid "Rename…"
++msgstr "Rename…"
++
++#: fileItem.js:606
++msgid "Move to Trash"
++msgstr "Move to Wastebasket"
++
++#: fileItem.js:616
++msgid "Empty Trash"
++msgstr "Empty Wastebasket"
++
++#: fileItem.js:622
++msgid "Properties"
++msgstr "Properties"
++
++#: fileItem.js:624
++msgid "Show in Files"
++msgstr "Show in Files"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Set the size for the desktop icons."
++msgstr "Set the size for the desktop icons."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16
++msgid "Show personal folder"
++msgstr "Show personal folder"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show the personal folder in the desktop."
++msgstr "Show the personal folder on the desktop."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21
++msgid "Show trash icon"
++msgstr "Show wastebasket icon"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show the trash icon in the desktop."
++msgstr "Show the trash icon on the desktop."
++
+ #~ msgid "GNOME Shell Classic"
+ #~ msgstr "GNOME Shell Classic"
+ 
+@@ -434,9 +629,6 @@ msgstr "Workspace %d"
+ #~ "Sets the position of the dock in the screen. Allowed values are 'right' "
+ #~ "or 'left'"
+ 
+-#~ msgid "Icon size"
+-#~ msgstr "Icon size"
+-
+ #~ msgid "Sets icon size of the dock."
+ #~ msgstr "Sets icon size of the dock."
+ 
+@@ -508,9 +700,6 @@ msgstr "Workspace %d"
+ #~ msgid "Display"
+ #~ msgstr "Display"
+ 
+-#~ msgid "Display Settings"
+-#~ msgstr "Display Settings"
+-
+ #~ msgid "Do Not Disturb"
+ #~ msgstr "Do Not Disturb"
+ 
+@@ -582,9 +771,6 @@ msgstr "Workspace %d"
+ #~ msgid "Native"
+ #~ msgstr "Native"
+ 
+-#~ msgid "Cancel"
+-#~ msgstr "Cancel"
+-
+ #~ msgid "Ask the user for a default behaviour if true."
+ #~ msgstr "Ask the user for a default behaviour if true."
+ 
+diff --git a/po/es.po b/po/es.po
+index a3c0703..ee30c8a 100644
+--- a/po/es.po
++++ b/po/es.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  es.po (gnome-shell-extensions master)  #-#-#-#-#
+ # Spanish translation for gnome-shell-extensions.
+ # Copyright (C) 2011 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+@@ -6,8 +7,18 @@
+ # 
+ # Daniel Mustieles <daniel.mustieles@gmail.com>, 2011-2015, 2017.
+ #
++# #-#-#-#-#  es.po (1.0)  #-#-#-#-#
++# SOME DESCRIPTIVE TITLE.
++# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
++# This file is distributed under the same license as the PACKAGE package.
++# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
++# Sergio Costas <rastersoft@gmail.com>, 2018.
++# Daniel Mustieles <daniel.mustieles@gmail.com>, 2018-2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  es.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"
+@@ -21,6 +32,20 @@ msgstr ""
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
+ "X-Generator: Gtranslator 2.91.6\n"
++"#-#-#-#-#  es.po (1.0)  #-#-#-#-#\n"
++"Project-Id-Version: 1.0\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-05-13 15:13+0200\n"
++"Last-Translator: Daniel Mustieles <daniel.mustieles@gmail.com>\n"
++"Language-Team: es <gnome-es-list@gnome.org>\n"
++"Language: es\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: Gtranslator 3.32.0\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -361,6 +386,188 @@ msgstr "Nombre"
+ msgid "Workspace %d"
+ msgstr "Área de trabajo %d"
+ 
++#: desktopGrid.js:334
++#, fuzzy
++msgid "Display Settings"
++msgstr ""
++"#-#-#-#-#  es.po (gnome-shell-extensions master)  #-#-#-#-#\n"
++"Configuración de pantalla\n"
++"#-#-#-#-#  es.po (1.0)  #-#-#-#-#\n"
++"Configuración de pantalla"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++#, fuzzy
++msgid "Icon size"
++msgstr ""
++"#-#-#-#-#  es.po (gnome-shell-extensions master)  #-#-#-#-#\n"
++"Tamaño del icono\n"
++"#-#-#-#-#  es.po (1.0)  #-#-#-#-#\n"
++"Tamaño de los iconos"
++
++#: createFolderDialog.js:74 desktopGrid.js:592
++msgid "Cancel"
++msgstr "Cancelar"
++
++#: createFolderDialog.js:48
++msgid "New folder name"
++msgstr "Nombre de la nueva carpeta"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "Crear"
++
++#: 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"
++msgstr "Tamaño de los iconos del escritorio"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Pequeño"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Estándar"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Grande"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Mostrar la carpeta personal en el escritorio"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Mostrar la papelera en el escritorio"
++
++#: desktopGrid.js:323
++msgid "New Folder"
++msgstr "Nueva carpeta"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Pegar"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Deshacer"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Rehacer"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Mostrar el escritorio en Archivos"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Abrir en una terminal"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Cambiar el fondo..."
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Configuración"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Introduzca el nombre del archivo…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "Aceptar"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Comando no encontrado"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "No permitir lanzar"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Permitir lanzar"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Abrir"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Abrir con otra aplicación"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Cortar"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Copiar"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Renombrar…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Mover a la papelera"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Vaciar la papelera"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Propiedades"
++
++#: fileItem.js:608
++msgid "Show in Files"
++msgstr "Mostrar en Files"
++
++#: 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:16
++msgid "Show personal folder"
++msgstr "Mostrar la carpeta personal"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Mostrar la papelera"
++
++#: 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 "CPU"
+ #~ msgstr "CPU"
+ 
+@@ -409,9 +616,6 @@ msgstr "Área de trabajo %d"
+ #~ msgid "Display"
+ #~ msgstr "Pantalla"
+ 
+-#~ msgid "Display Settings"
+-#~ msgstr "Configuración de pantalla"
+-
+ #~ msgid "File System"
+ #~ msgstr "Sistema de archivos"
+ 
+@@ -459,9 +663,6 @@ msgstr "Área de trabajo %d"
+ #~ "Configura la posición del tablero en la pantalla. Los valores permitidos "
+ #~ "son «right» (derecha) o «left» (izquierda)"
+ 
+-#~ msgid "Icon size"
+-#~ msgstr "Tamaño del icono"
+-
+ #~ msgid "Sets icon size of the dock."
+ #~ msgstr "Configura el tamaño de los íconos del tablero."
+ 
+@@ -632,9 +833,6 @@ msgstr "Área de trabajo %d"
+ #~ msgid "Alt Tab Behaviour"
+ #~ msgstr "Comportamiento de Alt+Tab"
+ 
+-#~ msgid "Cancel"
+-#~ msgstr "Cancelar"
+-
+ #~ msgid "Notifications"
+ #~ msgstr "Notificaciones"
+ 
+@@ -668,3 +866,30 @@ msgstr "Área de trabajo %d"
+ 
+ #~ msgid "Busy"
+ #~ msgstr "Ocupado"
++
++#~ msgid "Huge"
++#~ msgstr "Inmenso"
++
++#~ msgid "Ok"
++#~ msgstr "Aceptar"
++
++#~ msgid "huge"
++#~ msgstr "inmenso"
++
++#~ msgid "Maximum width for the icons and filename."
++#~ msgstr "Ancho máximo de los iconos y el nombre de fichero."
++
++#~ msgid "Shows the Documents folder in the desktop."
++#~ msgstr "Muestra la carpeta Documentos en el escritorio."
++
++#~ msgid "Shows the Downloads folder in the desktop."
++#~ msgstr "Muestra la carpeta Descargas en el escritorio."
++
++#~ msgid "Shows the Music folder in the desktop."
++#~ msgstr "Muestra la carpeta Música en el escritorio."
++
++#~ msgid "Shows the Pictures folder in the desktop."
++#~ msgstr "Muestra la carpeta Imágenes en el escritorio."
++
++#~ msgid "Shows the Videos folder in the desktop."
++#~ msgstr "Muestra la carpeta Vídeos en el escritorio."
+diff --git a/po/fi.po b/po/fi.po
+index e036448..e23c0c8 100644
+--- a/po/fi.po
++++ b/po/fi.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  fi.po (gnome-shell-extensions)  #-#-#-#-#
+ # Finnish translation of gnome-shell-extensions.
+ # Copyright (C) 2011 Ville-Pekka Vainio
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+@@ -7,8 +8,16 @@
+ # Ville-Pekka Vainio <vpvainio@iki.fi>, 2011.
+ # Jiri Grönroos <jiri.gronroos+l10n@iki.fi>, 2012, 2013, 2014, 2015, 2017.
+ #
++# #-#-#-#-#  fi.po (desktop-icons master)  #-#-#-#-#
++# 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.
++# Jiri Grönroos <jiri.gronroos@iki.fi>, 2018.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  fi.po (gnome-shell-extensions)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions\n"
+ "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
+ "shell&keywords=I18N+L10N&component=extensions\n"
+@@ -24,6 +33,20 @@ msgstr ""
+ "X-Generator: Gtranslator 2.91.7\n"
+ "X-Project-Style: gnome\n"
+ "X-POT-Import-Date: 2012-03-05 15:06:12+0000\n"
++"#-#-#-#-#  fi.po (desktop-icons master)  #-#-#-#-#\n"
++"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-04-29 14:11+0000\n"
++"PO-Revision-Date: 2019-06-02 15:23+0300\n"
++"Last-Translator: Jiri Grönroos <jiri.gronroos+l10n@iki.fi>\n"
++"Language-Team: Finnish <lokalisointi-lista@googlegroups.com>\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"
++"X-Generator: Poedit 2.0.6\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -352,6 +375,183 @@ msgstr "Nimi"
+ msgid "Workspace %d"
+ msgstr "Työtila %d"
+ 
++#: desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Näytön asetukset"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++#, fuzzy
++msgid "Icon size"
++msgstr ""
++"#-#-#-#-#  fi.po (gnome-shell-extensions)  #-#-#-#-#\n"
++"Kuvakkeiden koko\n"
++"#-#-#-#-#  fi.po (desktop-icons master)  #-#-#-#-#\n"
++"Kuvakekoko"
++
++#: createFolderDialog.js:48
++msgid "New folder name"
++msgstr "Uusi kansion nimi"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "Luo"
++
++#: createFolderDialog.js:74 desktopGrid.js:592
++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:102
++msgid "Small"
++msgstr "Pieni"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Normaali"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Suuri"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Näytä kotikansio työpöydällä"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Näytä roskakorin kuvake työpöydällä"
++
++#: desktopGrid.js:323
++msgid "New Folder"
++msgstr "Uusi kansio"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Liitä"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Kumoa"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Tee uudeleen"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Näytä työpöytä tiedostonhallinnassa"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Avaa päätteessä"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Vaihda taustakuvaa…"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Asetukset"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Anna tiedostonimi…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "OK"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Komentoa ei löydy"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "Älä salli käynnistämistä"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Salli käynnistäminen"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Avaa"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Avaa toisella sovelluksella"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Leikkaa"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Kopioi"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Nimeä uudelleen…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Siirrä roskakoriin"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Tyhjennä roskakori"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Ominaisuudet"
++
++#: fileItem.js:608
++msgid "Show in Files"
++msgstr "Näytä tiedostonhallinnassa"
++
++#: 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:16
++msgid "Show personal folder"
++msgstr "Näytä kotikansio"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Näytä roskakorin kuvake"
++
++#: 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 "CPU"
+ #~ msgstr "Suoritin"
+ 
+@@ -388,9 +588,6 @@ msgstr "Työtila %d"
+ #~ msgid "Display"
+ #~ msgstr "Näyttö"
+ 
+-#~ msgid "Display Settings"
+-#~ msgstr "Näytön asetukset"
+-
+ #~ msgid "Drag here to add favorites"
+ #~ msgstr "Raahaa tähän lisätäksesi suosikkeihin"
+ 
+@@ -412,9 +609,6 @@ msgstr "Työtila %d"
+ #~ msgstr ""
+ #~ "Asettaa telakan sijainnin näytöllä. Sallitut arvot ovat 'right' tai 'left'"
+ 
+-#~ msgid "Icon size"
+-#~ msgstr "Kuvakkeiden koko"
+-
+ #~ msgid "Sets icon size of the dock."
+ #~ msgstr "Asettaa telakan kuvakkeiden koon."
+ 
+@@ -459,3 +653,6 @@ msgstr "Työtila %d"
+ 
+ #~ msgid "Workspace & Icons"
+ #~ msgstr "Työtila ja kuvakkeet"
++
++#~ msgid "Huge"
++#~ msgstr "Valtava"
+diff --git a/po/fr.po b/po/fr.po
+index 6825d0d..6961fa4 100644
+--- a/po/fr.po
++++ b/po/fr.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  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.
+@@ -5,8 +6,17 @@
+ # Alain Lojewski <allomervan@gmail.com>, 2012-2013.
+ # Charles Monzat <charles.monzat@numericable.fr>, 2018.
+ #
++# #-#-#-#-#  fr.po (desktop-icons master)  #-#-#-#-#
++# French 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.
++# ghentdebian <ghent.debian@gmail.com>, 2018.
++# Charles Monzat <charles.monzat@numericable.fr>, 2018.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  fr.po (gnome-shell-extensions master)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions master\n"
+ "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/"
+ "issues\n"
+@@ -20,6 +30,20 @@ msgstr ""
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=2; plural=(n > 1);\n"
+ "X-Generator: Gtranslator 3.30.0\n"
++"#-#-#-#-#  fr.po (desktop-icons master)  #-#-#-#-#\n"
++"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-16 17:47+0100\n"
++"Last-Translator: Charles Monzat <charles.monzat@numericable.fr>\n"
++"Language-Team: GNOME French Team <gnomefr@traduc.org>\n"
++"Language: fr\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: Gtranslator 3.30.0\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -323,6 +347,146 @@ msgstr "Nom"
+ msgid "Workspace %d"
+ msgstr "Espace de travail %d"
+ 
++#: prefs.js:102
++msgid "Size for the desktop icons"
++msgstr "Taille des icônes du bureau"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Petite"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Normale"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Grande"
++
++#: prefs.js:102
++msgid "Huge"
++msgstr "Immense"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Montrer le dossier personnel sur le bureau"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Montrer la corbeille sur le bureau"
++
++#: desktopGrid.js:182 desktopGrid.js:301
++msgid "New Folder"
++msgstr "Nouveau dossier"
++
++#: desktopGrid.js:303
++msgid "Paste"
++msgstr "Coller"
++
++#: desktopGrid.js:304
++msgid "Undo"
++msgstr "Annuler"
++
++#: desktopGrid.js:305
++msgid "Redo"
++msgstr "Refaire"
++
++#: desktopGrid.js:307
++msgid "Open Desktop in Files"
++msgstr "Ouvrir le bureau dans Fichiers"
++
++#: desktopGrid.js:308
++msgid "Open Terminal"
++msgstr "Ouvrir un terminal"
++
++#: desktopGrid.js:310
++msgid "Change Background…"
++msgstr "Changer l’arrière-plan…"
++
++#: desktopGrid.js:311
++msgid "Display Settings"
++msgstr "Configuration d’affichage"
++
++#: desktopGrid.js:312
++msgid "Settings"
++msgstr "Paramètres"
++
++#: desktopGrid.js:568
++msgid "Enter file name…"
++msgstr "Saisir un nom de fichier…"
++
++#: desktopGrid.js:572
++msgid "OK"
++msgstr "Valider"
++
++#: desktopGrid.js:578
++msgid "Cancel"
++msgstr "Annuler"
++
++#: fileItem.js:485
++msgid "Don’t Allow Launching"
++msgstr "Ne pas autoriser le lancement"
++
++#: fileItem.js:487
++msgid "Allow Launching"
++msgstr "Autoriser le lancement"
++
++#: fileItem.js:550
++msgid "Open"
++msgstr "Ouvrir"
++
++#: fileItem.js:553
++msgid "Cut"
++msgstr "Couper"
++
++#: fileItem.js:554
++msgid "Copy"
++msgstr "Copier"
++
++#: fileItem.js:556
++msgid "Rename"
++msgstr "Renommer"
++
++#: fileItem.js:557
++msgid "Move to Trash"
++msgstr "Mettre à la corbeille"
++
++#: fileItem.js:567
++msgid "Empty Trash"
++msgstr "Vider la corbeille"
++
++#: fileItem.js:573
++msgid "Properties"
++msgstr "Propriétés"
++
++#: fileItem.js:575
++msgid "Show in Files"
++msgstr "Montrer dans Fichiers"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Icon size"
++msgstr "Taille d’icônes"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13
++msgid "Set the size for the desktop icons."
++msgstr "Définir la taille des icônes du bureau."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show personal folder"
++msgstr "Montrer le dossier personnel"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18
++msgid "Show the personal folder in the desktop."
++msgstr "Montrer le dossier personnel sur le bureau."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show trash icon"
++msgstr "Montrer l’icône de la corbeille"
++
++#: 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 "Attach modal dialog to the parent window"
+ #~ msgstr "Attacher les boîtes de dialogue modales à leur fenêtre parente"
+ 
+@@ -360,3 +524,6 @@ msgstr "Espace de travail %d"
+ 
+ #~ msgid "Memory"
+ #~ msgstr "Mémoire"
++
++#~ msgid "Ok"
++#~ msgstr "Valider"
+diff --git a/po/fur.po b/po/fur.po
+index 0fb3f70..a2793c9 100644
+--- a/po/fur.po
++++ b/po/fur.po
+@@ -1,10 +1,19 @@
++# #-#-#-#-#  fur.po (gnome-shell-extensions master)  #-#-#-#-#
+ # Friulian translation for gnome-shell-extensions.
+ # Copyright (C) 2013 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ # Fabio Tomat <f.t.public@gmail.com>, 2013.
+ #
++# #-#-#-#-#  fur.po (desktop-icons master)  #-#-#-#-#
++# 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.
++# Fabio Tomat <f.t.public@gmail.com>, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  fur.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"
+@@ -17,6 +26,19 @@ msgstr ""
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "X-Generator: Poedit 1.8.12\n"
++"#-#-#-#-#  fur.po (desktop-icons master)  #-#-#-#-#\n"
++"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-05 22:20+0100\n"
++"Last-Translator: Fabio Tomat <f.t.public@gmail.com>\n"
++"Language-Team: Friulian <fur@li.org>\n"
++"Language: fur\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"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -355,6 +377,179 @@ msgstr "Non"
+ msgid "Workspace %d"
+ msgstr "Spazi di lavôr %d"
+ 
++#: desktopGrid.js:331
++#, fuzzy
++msgid "Display Settings"
++msgstr ""
++"#-#-#-#-#  fur.po (gnome-shell-extensions master)  #-#-#-#-#\n"
++"Impostazions Visôr\n"
++"#-#-#-#-#  fur.po (desktop-icons master)  #-#-#-#-#\n"
++"Impostazions visôr"
++
++#: 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 "Dimension pes iconis dal scritori"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Piçule"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standard"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Largje"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Mostre la cartele personâl intal scritori"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Mostre la icone de scovacere intal scritori"
++
++#: desktopGrid.js:320
++msgid "New Folder"
++msgstr "Gnove cartele"
++
++#: desktopGrid.js:322
++msgid "Paste"
++msgstr "Tache"
++
++#: desktopGrid.js:323
++msgid "Undo"
++msgstr "Anule"
++
++#: desktopGrid.js:324
++msgid "Redo"
++msgstr "Torne fâ"
++
++#: desktopGrid.js:326
++msgid "Show Desktop in Files"
++msgstr "Mostre Scritori in File"
++
++#: desktopGrid.js:327 fileItem.js:606
++msgid "Open in Terminal"
++msgstr "Vierç in Terminâl"
++
++#: desktopGrid.js:329
++msgid "Change Background…"
++msgstr "Cambie sfont…"
++
++#: desktopGrid.js:332
++msgid "Settings"
++msgstr "Impostazions"
++
++#: 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 "Vierç"
++
++#: fileItem.js:578
++msgid "Open With Other Application"
++msgstr "Vierç cuntune altre aplicazion"
++
++#: fileItem.js:582
++msgid "Cut"
++msgstr "Taie"
++
++#: fileItem.js:583
++msgid "Copy"
++msgstr "Copie"
++
++#: fileItem.js:585
++msgid "Rename…"
++msgstr "Cambie non..."
++
++#: fileItem.js:586
++msgid "Move to Trash"
++msgstr "Sposte te scovacere"
++
++#: fileItem.js:596
++msgid "Empty Trash"
++msgstr "Disvuede scovacere"
++
++#: fileItem.js:602
++msgid "Properties"
++msgstr "Propietâts"
++
++#: fileItem.js:604
++msgid "Show in Files"
++msgstr "Mostre in File"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++msgid "Icon size"
++msgstr "Dimension icone"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Set the size for the desktop icons."
++msgstr "Stabilìs la dimension pes iconis dal scritori."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16
++msgid "Show personal folder"
++msgstr "Mostre cartele personâl"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show the personal folder in the desktop."
++msgstr "Mostre la cartele personâl intal scritori."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21
++msgid "Show trash icon"
++msgstr "Mostre la icone de scovacere"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show the trash icon in the desktop."
++msgstr "Mostre la icone de scovacere intal scritori."
++
+ #~ msgid "CPU"
+ #~ msgstr "CPU"
+ 
+@@ -381,6 +576,3 @@ msgstr "Spazi di lavôr %d"
+ 
+ #~ msgid "Display"
+ #~ msgstr "Visôr"
+-
+-#~ msgid "Display Settings"
+-#~ msgstr "Impostazions Visôr"
+diff --git a/po/hr.po b/po/hr.po
+index deee76e..a4d39d1 100644
+--- a/po/hr.po
++++ b/po/hr.po
+@@ -1,10 +1,19 @@
++# #-#-#-#-#  hr.po (gnome-shell-extensions master)  #-#-#-#-#
+ # Croatian translation for gnome-shell-extensions.
+ # Copyright (C) 2017 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+ #
++# #-#-#-#-#  hr.po (gnome-shell-extension-desktop-icons)  #-#-#-#-#
++# 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 <EMAIL@ADDRESS>, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  hr.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"
+@@ -19,6 +28,20 @@ msgstr ""
+ "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+ "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+ "X-Generator: Poedit 2.0.2\n"
++"#-#-#-#-#  hr.po (gnome-shell-extension-desktop-icons)  #-#-#-#-#\n"
++"Project-Id-Version: gnome-shell-extension-desktop-icons\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-06-22 18:52+0200\n"
++"Last-Translator: gogo <trebelnik2@gmail.com>\n"
++"Language-Team: Croatian <hr@li.org>\n"
++"Language: hr\n"
++"MIME-Version: 1.0\n"
++"Content-Type: text/plain; charset=UTF-8\n"
++"Content-Transfer-Encoding: 8bit\n"
++"X-Launchpad-Export-Date: 2019-03-27 09:36+0000\n"
++"X-Generator: Poedit 2.2.1\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -353,3 +376,175 @@ msgstr "Naziv"
+ #, javascript-format
+ msgid "Workspace %d"
+ msgstr "Radni prostor %d"
++
++#: createFolderDialog.js:48
++msgid "New folder name"
++msgstr "Novi naziv mape"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "Stvori"
++
++#: createFolderDialog.js:74 desktopGrid.js:592
++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 "Veličina ikona radne površine"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Male"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standardne"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Velike"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Prikaži osobnu mapu na radnoj površini"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Prikaži mapu smeća na radnoj površini"
++
++#: desktopGrid.js:323
++msgid "New Folder"
++msgstr "Nova mapa"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Zalijepi"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Poništi"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Ponovi"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Prikaži radnu površinu u Datotekama"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Otvori u Terminalu"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Promijeni pozadinu…"
++
++#: desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Postavke zaslona"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Postavke"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Upiši naziv datoteke…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "U redu"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Naredba nije pronađena"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "Ne dopuštaj pokretanje"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Dopusti pokretanje"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Otvori"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Otvori s drugom aplikacijom"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Izreži"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Kopiraj"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Preimenuj…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Premjesti u smeće"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Isprazni smeće"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Svojstva"
++
++#: fileItem.js:608
++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/po/hu.po b/po/hu.po
+index 7c2c406..0635270 100644
+--- a/po/hu.po
++++ b/po/hu.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  hu.po (gnome-shell-extensions master)  #-#-#-#-#
+ # Hungarian translation of
+ # Copyright (C) 2011, 2012, 2013, 2014, 2017 Free Software Foundation, Inc.
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+@@ -5,8 +6,16 @@
+ # Biró Balázs <arch.scar at gmail dot com>, 2011.
+ # Gabor Kelemen <kelemeng at gnome dot hu>, 2011, 2012, 2013.
+ # Balázs Úr <urbalazs at gmail dot com>, 2013, 2014, 2017.
++# #-#-#-#-#  hu.po (desktop-icons master)  #-#-#-#-#
++# 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 <ur.balazs at fsf dot hu>, 2019.
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  hu.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"
+@@ -20,6 +29,20 @@ msgstr ""
+ "Content-Transfer-Encoding: 8bit\n"
+ "X-Generator: Poedit 2.0.2\n"
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
++"#-#-#-#-#  hu.po (desktop-icons master)  #-#-#-#-#\n"
++"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-04-29 14:11+0000\n"
++"PO-Revision-Date: 2019-06-01 18:50+0200\n"
++"Last-Translator: Balázs Úr <ur.balazs at fsf dot hu>\n"
++"Language-Team: Hungarian <gnome-hu-list at gnome dot org>\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 18.12.3\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -356,3 +379,175 @@ msgstr "Név"
+ #, javascript-format
+ msgid "Workspace %d"
+ msgstr "%d. munkaterület"
++
++#: createFolderDialog.js:48
++msgid "New folder name"
++msgstr "Új mappa neve"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "Létrehozás"
++
++#: createFolderDialog.js:74 desktopGrid.js:592
++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:323
++msgid "New Folder"
++msgstr "Új mappa"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Beillesztés"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Visszavonás"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Újra"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Asztal megjelenítése a Fájlokban"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Megnyitás terminálban"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Háttér megváltoztatása…"
++
++#: desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Megjelenítés beállításai"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Beállítások"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Adjon meg egy fájlnevet…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "Rendben"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "A parancs nem található"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "Ne engedélyezzen indítást"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Indítás engedélyezése"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Megnyitás"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Megnyitás egyéb alkalmazással"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Kivágás"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Másolás"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Átnevezés…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Áthelyezés a Kukába"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Kuka ürítése"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Tulajdonságok"
++
++#: fileItem.js:608
++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/po/id.po b/po/id.po
+index 8986a5e..29f27b6 100644
+--- a/po/id.po
++++ b/po/id.po
+@@ -1,11 +1,20 @@
++# #-#-#-#-#  id.po (gnome-shell-extensions master)  #-#-#-#-#
+ # Indonesian translation for gnome-shell-extensions.
+ # Copyright (C) 2012 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ #
+ # Andika Triwidada <andika@gmail.com>, 2012, 2013.
+ # Dirgita <dirgitadevina@yahoo.co.id>, 2012.
++# #-#-#-#-#  id.po (desktop-icons master)  #-#-#-#-#
++# 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 <kukuhsyafaat@gnome.org>, 2018, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  id.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"
+@@ -20,6 +29,19 @@ msgstr ""
+ "Plural-Forms: nplurals=1; plural=0;\n"
+ "X-Poedit-SourceCharset: UTF-8\n"
+ "X-Generator: Poedit 2.0.2\n"
++"#-#-#-#-#  id.po (desktop-icons master)  #-#-#-#-#\n"
++"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-04-29 14:11+0000\n"
++"PO-Revision-Date: 2019-07-11 13:57+0700\n"
++"Last-Translator: Kukuh Syafaat <kukuhsyafaat@gnome.org>\n"
++"Language-Team: Indonesian <gnome-l10n-id@googlegroups.com>\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.3\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -358,8 +380,183 @@ msgstr "Nama"
+ msgid "Workspace %d"
+ msgstr "Ruang Kerja %d"
+ 
++#: createFolderDialog.js:48
++msgid "New folder name"
++msgstr "Nama folder baru"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "Buat"
++
++#: createFolderDialog.js:74 desktopGrid.js:592
++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:323
++msgid "New Folder"
++msgstr "Folder Baru"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Tempel"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Tak Jadi"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Jadi Lagi"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Tampilkan Destop pada Berkas"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Buka dalam Terminal"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Ubah Latar Belakang…"
++
++#: desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Pengaturan Tampilan"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Pengaturan"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Masukkan nama berkas…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "OK"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Perintah tidak ditemukan"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "Jangan Izinkan Peluncuran"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Izinkan Peluncuran"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Buka"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Buka Dengan Aplikasi Lain"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Potong"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Salin"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Ganti Nama…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Pindahkan ke Tong Sampah"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Kosongkan Tong Sampah"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Properti"
++
++#: fileItem.js:608
++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 "CPU"
+ #~ msgstr "CPU"
+ 
+ #~ msgid "Memory"
+ #~ msgstr "Memori"
++
++#~ msgid "Huge"
++#~ msgstr "Sangat besar"
+diff --git a/po/it.po b/po/it.po
+index 4e3a59c..2d215b1 100644
+--- a/po/it.po
++++ b/po/it.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  it.po (gnome-shell-extensions)  #-#-#-#-#
+ # Italian translations for GNOME Shell extensions
+ # Copyright (C) 2011 Giovanni Campagna et al.
+ # Copyright (C) 2012, 2013, 2014, 2015, 2017 The Free Software Foundation, Inc.
+@@ -6,8 +7,17 @@
+ # Milo Casagrande <milo@milo.name>, 2013, 2014, 2015, 2017.
+ # Gianvito Cavasoli <gianvito@gmx.it>, 2017.
+ #
++# #-#-#-#-#  it.po (desktop-icons master)  #-#-#-#-#
++# 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 <max.bra.gtalk@gmail.com>, 2019.
++# Milo Casagrande <milo@milo.name>, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  it.po (gnome-shell-extensions)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions\n"
+ "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
+ "shell&keywords=I18N+L10N&component=extensions\n"
+@@ -21,6 +31,20 @@ msgstr ""
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
+ "X-Generator: Poedit 1.8.12\n"
++"#-#-#-#-#  it.po (desktop-icons master)  #-#-#-#-#\n"
++"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 <milo@milo.name>\n"
++"Language-Team: Italian <tp@lists.linux.it>\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"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -362,3 +386,171 @@ msgstr "Nome"
+ #, javascript-format
+ msgid "Workspace %d"
+ msgstr "Spazio di lavoro %d"
++
++#: 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/po/ja.po b/po/ja.po
+index a2201ef..df5646d 100644
+--- a/po/ja.po
++++ b/po/ja.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  ja.po (gnome-shell-extensions master)  #-#-#-#-#
+ # gnome-shell-extensions ja.po
+ # Copyright (C) 2011-2013 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+@@ -7,8 +8,16 @@
+ # Ikuya Awashiro <ikuya@fruitsbasket.info>, 2014.
+ # Hajime Taira <htaira@redhat.com>, 2014, 2015.
+ #
++# #-#-#-#-#  ja.po (desktop-icons master)  #-#-#-#-#
++# 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 <translation@sicklylife.jp>, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  ja.po (gnome-shell-extensions master)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions master\n"
+ "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/"
+ "issues\n"
+@@ -21,6 +30,19 @@ msgstr ""
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=1; plural=0;\n"
++"#-#-#-#-#  ja.po (desktop-icons master)  #-#-#-#-#\n"
++"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-04-29 14:11+0000\n"
++"PO-Revision-Date: 2019-08-29 21:30+0900\n"
++"Last-Translator: sicklylife <translation@sicklylife.jp>\n"
++"Language-Team: Japanese <gnome-translation@gnome.gr.jp>\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"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -270,6 +292,188 @@ msgstr "名前"
+ msgid "Workspace %d"
+ msgstr "ワークスペース %d"
+ 
++#: desktopGrid.js:334
++#, fuzzy
++msgid "Display Settings"
++msgstr ""
++"#-#-#-#-#  ja.po (gnome-shell-extensions master)  #-#-#-#-#\n"
++"ディスプレイ設定\n"
++"#-#-#-#-#  ja.po (desktop-icons master)  #-#-#-#-#\n"
++"ディスプレイの設定"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++#, fuzzy
++msgid "Icon size"
++msgstr ""
++"#-#-#-#-#  ja.po (gnome-shell-extensions master)  #-#-#-#-#\n"
++"アイコンのサイズ\n"
++"#-#-#-#-#  ja.po (desktop-icons master)  #-#-#-#-#\n"
++"アイコンサイズ"
++
++#: createFolderDialog.js:48
++msgid "New folder name"
++msgstr "新しいフォルダー名"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "作成"
++
++#: createFolderDialog.js:74 desktopGrid.js:592
++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:323
++msgid "New Folder"
++msgstr "新しいフォルダー"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "貼り付け"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "元に戻す"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "やり直す"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "“ファイル”でデスクトップを表示"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "端末を開く"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "背景の変更…"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "設定"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "ファイル名を入力してください…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "OK"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "コマンドが見つかりません"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "起動を許可しない"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "起動を許可する"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "開く"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "別のアプリケーションで開く"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "切り取り"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "コピー"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "名前の変更…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "ゴミ箱へ移動する"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "ゴミ箱を空にする"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "プロパティ"
++
++#: fileItem.js:608
++msgid "Show in Files"
++msgstr "“ファイル”で表示"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Set the size for the desktop icons."
++msgstr "デスクトップのアイコンサイズを設定します。"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16
++msgid "Show personal folder"
++msgstr "ホームフォルダーを表示する"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show the personal folder in the desktop."
++msgstr "デスクトップにホームフォルダーを表示します。"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21
++msgid "Show trash icon"
++msgstr "ゴミ箱アイコンを表示する"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show the trash icon in the desktop."
++msgstr "デスクトップにゴミ箱のアイコンを表示します。"
++
+ #~ msgid "Attach modal dialog to the parent window"
+ #~ msgstr "モーダルダイアログを親ウィンドウに結び付ける"
+ 
+@@ -365,9 +569,6 @@ msgstr "ワークスペース %d"
+ #~ msgid "Display"
+ #~ msgstr "ディスプレイ"
+ 
+-#~ msgid "Display Settings"
+-#~ msgstr "ディスプレイ設定"
+-
+ #~ msgid "Suspend"
+ #~ msgstr "サスペンド"
+ 
+@@ -413,9 +614,6 @@ msgstr "ワークスペース %d"
+ #~ msgid "Remove from Favorites"
+ #~ msgstr "お気に入りから削除"
+ 
+-#~ msgid "Icon size"
+-#~ msgstr "アイコンのサイズ"
+-
+ #~ msgid "Position of the dock"
+ #~ msgstr "ドックの位置"
+ 
+diff --git a/po/nl.po b/po/nl.po
+index a7998d3..bbf7b1f 100644
+--- a/po/nl.po
++++ b/po/nl.po
+@@ -1,11 +1,20 @@
++# #-#-#-#-#  nl.po (gnome-shell-extensions master)  #-#-#-#-#
+ # Dutch translation for gnome-shell-extensions.
+ # Copyright (C) 2013 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ # Reinout van Schouwen <reinouts@gnome.org>, 2013, 2014.
+ # Nathan Follens <nthn@unseen.is>, 2015-2017.
+ # Hannie Dumoleyn <hannie@ubuntu-nl.org>, 2015.
++# #-#-#-#-#  nl.po (desktop-icons master)  #-#-#-#-#
++# 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 <nthn@unseen.is>, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  nl.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"
+@@ -20,6 +29,20 @@ msgstr ""
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
+ "X-Generator: Poedit 2.0.2\n"
+ "X-Project-Style: gnome\n"
++"#-#-#-#-#  nl.po (desktop-icons master)  #-#-#-#-#\n"
++"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 <nthn@unseen.is>\n"
++"Language-Team: Dutch <gnome-nl-list@gnome.org>\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"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -360,6 +383,174 @@ msgstr "Naam"
+ msgid "Workspace %d"
+ msgstr "Werkblad %d"
+ 
++#: 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."
++
+ #~ msgid "GNOME Shell Classic"
+ #~ msgstr "Gnome Shell klassiek"
+ 
+diff --git a/po/pl.po b/po/pl.po
+index 35799ee..a779932 100644
+--- a/po/pl.po
++++ b/po/pl.po
+@@ -1,11 +1,21 @@
++# #-#-#-#-#  pl.po (gnome-shell-extensions)  #-#-#-#-#
+ # Polish translation for gnome-shell-extensions.
+ # Copyright © 2011-2017 the gnome-shell-extensions authors.
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ # Piotr Drąg <piotrdrag@gmail.com>, 2011-2017.
+ # Aviary.pl <community-poland@mozilla.org>, 2011-2017.
+ #
++# #-#-#-#-#  pl.po (desktop-icons)  #-#-#-#-#
++# 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.
++# Piotr Drąg <piotrdrag@gmail.com>, 2018-2019.
++# Aviary.pl <community-poland@mozilla.org>, 2018-2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  pl.po (gnome-shell-extensions)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions\n"
+ "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
+ "shell&keywords=I18N+L10N&component=extensions\n"
+@@ -19,6 +29,20 @@ msgstr ""
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
+ "|| n%100>=20) ? 1 : 2);\n"
++"#-#-#-#-#  pl.po (desktop-icons)  #-#-#-#-#\n"
++"Project-Id-Version: desktop-icons\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-05-01 13:03+0200\n"
++"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
++"Language-Team: Polish <community-poland@mozilla.org>\n"
++"Language: pl\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%10>=2 && n%10<=4 && (n%100<10 "
++"|| n%100>=20) ? 1 : 2);\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -358,3 +382,175 @@ msgstr "Nazwa"
+ #, javascript-format
+ msgid "Workspace %d"
+ msgstr "%d. obszar roboczy"
++
++#: 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"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Mały"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Standardowy"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Duży"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Katalog domowy na pulpicie"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Kosz na pulpicie"
++
++#: desktopGrid.js:323
++msgid "New Folder"
++msgstr "Nowy katalog"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Wklej"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Cofnij"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Ponów"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Wyświetl pulpit w menedżerze plików"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Otwórz w terminalu"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Zmień tło…"
++
++#: desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Ustawienia ekranu"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Ustawienia"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Nazwa pliku…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "OK"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Nie odnaleziono polecenia"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "Nie zezwalaj na uruchamianie"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Zezwól na uruchamianie"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Otwórz"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Otwórz za pomocą innego programu"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Wytnij"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Skopiuj"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Zmień nazwę…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Przenieś do kosza"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Opróżnij kosz"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Właściwości"
++
++#: fileItem.js:608
++msgid "Show in Files"
++msgstr "Wyświetl w menedżerze plików"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++msgid "Icon size"
++msgstr "Rozmiar ikon"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Set the size for the desktop icons."
++msgstr "Ustawia rozmiar ikon na pulpicie."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:16
++msgid "Show personal folder"
++msgstr "Katalog domowy"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show the personal folder in the desktop."
++msgstr "Wyświetla katalog domowy na pulpicie."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:21
++msgid "Show trash icon"
++msgstr "Kosz"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show the trash icon in the desktop."
++msgstr "Wyświetla kosz na pulpicie."
+diff --git a/po/pt_BR.po b/po/pt_BR.po
+index d029648..f1e17f7 100644
+--- a/po/pt_BR.po
++++ b/po/pt_BR.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  pt_BR.po (gnome-shell-extensions master)  #-#-#-#-#
+ # Brazilian Portuguese translation for gnome-shell-extensions.
+ # Copyright (C) 2017 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+@@ -9,8 +10,17 @@
+ # Og Maciel <ogmaciel@gnome.org>, 2012.
+ # Enrico Nicoletto <liverig@gmail.com>, 2013, 2014.
+ # Rafael Fontenelle <rafaelff@gnome.org>, 2013, 2017.
++# #-#-#-#-#  pt_BR.po (desktop-icons master)  #-#-#-#-#
++# Brazilian Portuguese 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.
++# Enrico Nicoletto <liverig@gmail.com>, 2018.
++# Rafael Fontenelle <rafaelff@gnome.org>, 2018-2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  pt_BR.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"
+@@ -25,6 +35,20 @@ msgstr ""
+ "Plural-Forms: nplurals=2; plural=(n > 1);\n"
+ "X-Generator: Virtaal 1.0.0-beta1\n"
+ "X-Project-Style: gnome\n"
++"#-#-#-#-#  pt_BR.po (desktop-icons master)  #-#-#-#-#\n"
++"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-04-29 14:11+0000\n"
++"PO-Revision-Date: 2019-04-29 17:35-0300\n"
++"Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n"
++"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\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: Gtranslator 3.32.0\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -366,6 +390,183 @@ msgstr "Nome"
+ msgid "Workspace %d"
+ msgstr "Espaço de trabalho %d"
+ 
++#: desktopGrid.js:334
++#, fuzzy
++msgid "Display Settings"
++msgstr ""
++"#-#-#-#-#  pt_BR.po (gnome-shell-extensions master)  #-#-#-#-#\n"
++"Configurações de tela\n"
++"#-#-#-#-#  pt_BR.po (desktop-icons master)  #-#-#-#-#\n"
++"Configurações de exibição"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:11
++msgid "Icon size"
++msgstr "Tamanho do ícone"
++
++#: createFolderDialog.js:74 desktopGrid.js:592
++msgid "Cancel"
++msgstr "Cancelar"
++
++#: createFolderDialog.js:48
++msgid "New folder name"
++msgstr "Nome da nova pasta"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "Criar"
++
++#: 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"
++msgstr "Tamanho para os ícones da área de trabalho"
++
++#: prefs.js:102
++msgid "Small"
++msgstr "Pequeno"
++
++#: prefs.js:102
++msgid "Standard"
++msgstr "Padrão"
++
++#: prefs.js:102
++msgid "Large"
++msgstr "Grande"
++
++#: prefs.js:103
++msgid "Show the personal folder in the desktop"
++msgstr "Mostrar a pasta pessoal na área de trabalho"
++
++#: prefs.js:104
++msgid "Show the trash icon in the desktop"
++msgstr "Mostrar o ícone da lixeira na área de trabalho"
++
++#: desktopGrid.js:323
++msgid "New Folder"
++msgstr "Nova pasta"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Colar"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Desfazer"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Refazer"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Mostrar a área de trabalho no Arquivos"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Abrir no terminal"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Alterar plano de fundo…"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Configurações"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Insira um nome de arquivo…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "OK"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Comando não encontrado"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "Não permitir iniciar"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Permitir iniciar"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Abrir"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Abrir com outro aplicativo"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Recortar"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Copiar"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Renomear…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Mover para a lixeira"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Esvaziar lixeira"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Propriedades"
++
++#: fileItem.js:608
++msgid "Show in Files"
++msgstr "Mostrar no Arquivos"
++
++#: 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:16
++msgid "Show personal folder"
++msgstr "Mostrar pasta pessoal"
++
++#: 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:21
++msgid "Show trash icon"
++msgstr "Mostrar ícone da lixeira"
++
++#: 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 "CPU"
+ #~ msgstr "CPU"
+ 
+@@ -414,9 +615,6 @@ msgstr "Espaço de trabalho %d"
+ #~ msgid "Display"
+ #~ msgstr "Tela"
+ 
+-#~ msgid "Display Settings"
+-#~ msgstr "Configurações de tela"
+-
+ #~ msgid "The application icon mode."
+ #~ msgstr "O modo de ícone do aplicativo."
+ 
+@@ -451,9 +649,6 @@ msgstr "Espaço de trabalho %d"
+ #~ "Define a posição do dock na tela. Os valores permitidos são \"right\" ou "
+ #~ "\"left\""
+ 
+-#~ msgid "Icon size"
+-#~ msgstr "Tamanho do ícone"
+-
+ #~ msgid "Sets icon size of the dock."
+ #~ msgstr "Define o tamanho do ícone do dock."
+ 
+@@ -613,9 +808,6 @@ msgstr "Espaço de trabalho %d"
+ #~ msgid "Alt Tab Behaviour"
+ #~ msgstr "Comportamento do Alt Tab"
+ 
+-#~ msgid "Cancel"
+-#~ msgstr "Cancelar"
+-
+ #~ msgid "Ask the user for a default behaviour if true."
+ #~ msgstr "Pergunte ao usuário por um comportamento padrão se marcado."
+ 
+@@ -639,3 +831,9 @@ msgstr "Espaço de trabalho %d"
+ 
+ #~ msgid "Log Out..."
+ #~ msgstr "Encerrar sessão..."
++
++#~ msgid "Huge"
++#~ msgstr "Enorme"
++
++#~ msgid "Ok"
++#~ msgstr "Ok"
+diff --git a/po/ru.po b/po/ru.po
+index c18c0ba..9320c3c 100644
+--- a/po/ru.po
++++ b/po/ru.po
+@@ -1,11 +1,20 @@
++# #-#-#-#-#  ru.po (gnome-shell-extensions gnome-3-0)  #-#-#-#-#
+ # Russian translation for gnome-shell-extensions.
+ # Copyright (C) 2011 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ # Yuri Myasoedov <omerta13@yandex.ru>, 2011, 2012, 2013.
+ # Stas Solovey <whats_up@tut.by>, 2011, 2012, 2013, 2015, 2017.
+ #
++# #-#-#-#-#  ru.po  #-#-#-#-#
++# SOME DESCRIPTIVE TITLE.
++# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
++# This file is distributed under the same license as the PACKAGE package.
++# Eaglers <eaglersdeveloper@gmail.com>, 2018.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  ru.po (gnome-shell-extensions gnome-3-0)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions gnome-3-0\n"
+ "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
+ "shell&keywords=I18N+L10N&component=extensions\n"
+@@ -20,6 +29,21 @@ msgstr ""
+ "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+ "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+ "X-Generator: Poedit 2.0.3\n"
++"#-#-#-#-#  ru.po  #-#-#-#-#\n"
++"Project-Id-Version: \n"
++"Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/ShellExtensions/desktop-"
++"icons/issues\n"
++"POT-Creation-Date: 2018-11-22 08:42+0000\n"
++"PO-Revision-Date: 2018-11-22 22:02+0300\n"
++"Last-Translator: Stas Solovey <whats_up@tut.by>\n"
++"Language-Team: Russian <gnome-cyr@gnome.org>\n"
++"Language: ru\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%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
++"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
++"X-Generator: Poedit 2.2\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -360,6 +384,138 @@ msgstr "Название"
+ msgid "Workspace %d"
+ msgstr "Рабочая область %d"
+ 
++#: prefs.js:89
++msgid "Size for the desktop icons"
++msgstr "Размер значков"
++
++#: prefs.js:89
++msgid "Small"
++msgstr "Маленький"
++
++#: prefs.js:89
++msgid "Standard"
++msgstr "Стандартный"
++
++#: prefs.js:89
++msgid "Large"
++msgstr "Большой"
++
++#: prefs.js:89
++msgid "Huge"
++msgstr "Огромный"
++
++#: prefs.js:90
++msgid "Show the personal folder in the desktop"
++msgstr "Показывать домашнюю папку на рабочем столе"
++
++#: prefs.js:91
++msgid "Show the trash icon in the desktop"
++msgstr "Показывать «Корзину» на рабочем столе"
++
++#: desktopGrid.js:185 desktopGrid.js:304
++msgid "New Folder"
++msgstr "Создать папку"
++
++#: desktopGrid.js:306
++msgid "Paste"
++msgstr "Вставить"
++
++#: desktopGrid.js:307
++msgid "Undo"
++msgstr "Отменить"
++
++#: desktopGrid.js:308
++msgid "Redo"
++msgstr "Повторить"
++
++#: desktopGrid.js:310
++msgid "Open Desktop in Files"
++msgstr "Открыть «Рабочий стол» в «Файлах»"
++
++#: desktopGrid.js:311
++msgid "Open Terminal"
++msgstr "Открыть терминал"
++
++#: desktopGrid.js:313
++msgid "Change Background…"
++msgstr "Изменить фон…"
++
++#: desktopGrid.js:314
++msgid "Display Settings"
++msgstr "Настройки дисплея"
++
++#: desktopGrid.js:315
++msgid "Settings"
++msgstr "Параметры"
++
++#: desktopGrid.js:569
++msgid "Enter file name…"
++msgstr "Ввести имя файла…"
++
++#: desktopGrid.js:573
++msgid "Ok"
++msgstr "ОК"
++
++#: desktopGrid.js:579
++msgid "Cancel"
++msgstr "Отмена"
++
++#: fileItem.js:390
++msgid "Open"
++msgstr "Открыть"
++
++#: fileItem.js:393
++msgid "Cut"
++msgstr "Вырезать"
++
++#: fileItem.js:394
++msgid "Copy"
++msgstr "Вставить"
++
++#: fileItem.js:395
++msgid "Rename"
++msgstr "Переименовать"
++
++#: fileItem.js:396
++msgid "Move to Trash"
++msgstr "Переместить в корзину"
++
++#: fileItem.js:400
++msgid "Empty trash"
++msgstr "Очистить корзину"
++
++#: fileItem.js:406
++msgid "Properties"
++msgstr "Свойства"
++
++#: fileItem.js:408
++msgid "Show in Files"
++msgstr "Показать в «Файлах»"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Icon size"
++msgstr "Размер значков"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13
++msgid "Set the size for the desktop icons."
++msgstr "Установить размер значков на рабочем столе."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show personal folder"
++msgstr "Показывать домашнюю папку"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18
++msgid "Show the personal folder in the desktop."
++msgstr "Показывать значок домашней папки на рабочем столе."
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show trash icon"
++msgstr "Показывать значок корзины"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23
++msgid "Show the trash icon in the desktop."
++msgstr "Показывать значок корзины на рабочем столе."
++
+ #~ msgid "CPU"
+ #~ msgstr "ЦП"
+ 
+diff --git a/po/sv.po b/po/sv.po
+index 3aeafac..33eba9f 100644
+--- a/po/sv.po
++++ b/po/sv.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  sv.po (gnome-shell-extensions)  #-#-#-#-#
+ # Swedish translation for gnome-shell-extensions.
+ # Copyright © 2011, 2012, 2014, 2015, 2017 Free Software Foundation, Inc.
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+@@ -5,8 +6,17 @@
+ # Mattias Eriksson <snaggen@gmail.com>, 2014.
+ # Anders Jonsson <anders.jonsson@norsjovallen.se>, 2015, 2017.
+ #
++# #-#-#-#-#  sv.po (desktop-icons master)  #-#-#-#-#
++# 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 <anders.jonsson@norsjovallen.se>, 2018, 2019.
++# Josef Andersson <l10nl18nsweja@gmail.com>, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  sv.po (gnome-shell-extensions)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions\n"
+ "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
+ "shell&keywords=I18N+L10N&component=extensions\n"
+@@ -19,6 +29,20 @@ msgstr ""
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "X-Generator: Poedit 2.0.4\n"
++"#-#-#-#-#  sv.po (desktop-icons master)  #-#-#-#-#\n"
++"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-04-29 14:11+0000\n"
++"PO-Revision-Date: 2019-08-22 17:52+0200\n"
++"Last-Translator: Anders Jonsson <anders.jonsson@norsjovallen.se>\n"
++"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\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.3\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -355,8 +379,188 @@ msgstr "Namn"
+ msgid "Workspace %d"
+ msgstr "Arbetsyta %d"
+ 
++#: createFolderDialog.js:48
++msgid "New folder name"
++msgstr "Nytt mappnamn"
++
++#: createFolderDialog.js:72
++msgid "Create"
++msgstr "Skapa"
++
++#: createFolderDialog.js:74 desktopGrid.js:592
++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:323
++msgid "New Folder"
++msgstr "Ny mapp"
++
++#: desktopGrid.js:325
++msgid "Paste"
++msgstr "Klistra in"
++
++#: desktopGrid.js:326
++msgid "Undo"
++msgstr "Ångra"
++
++#: desktopGrid.js:327
++msgid "Redo"
++msgstr "Gör om"
++
++#: desktopGrid.js:329
++msgid "Show Desktop in Files"
++msgstr "Visa skrivbord i Filer"
++
++#: desktopGrid.js:330 fileItem.js:610
++msgid "Open in Terminal"
++msgstr "Öppna i terminal"
++
++#: desktopGrid.js:332
++msgid "Change Background…"
++msgstr "Ändra bakgrund…"
++
++#: desktopGrid.js:334
++msgid "Display Settings"
++msgstr "Visningsinställningar"
++
++#: desktopGrid.js:335
++msgid "Settings"
++msgstr "Inställningar"
++
++#: desktopGrid.js:582
++msgid "Enter file name…"
++msgstr "Ange filnamn…"
++
++#: desktopGrid.js:586
++msgid "OK"
++msgstr "OK"
++
++#: desktopIconsUtil.js:61
++msgid "Command not found"
++msgstr "Kommandot hittades inte"
++
++#: fileItem.js:494
++msgid "Don’t Allow Launching"
++msgstr "Tillåt ej programstart"
++
++#: fileItem.js:496
++msgid "Allow Launching"
++msgstr "Tillåt programstart"
++
++#: fileItem.js:578
++msgid "Open"
++msgstr "Öppna"
++
++#: fileItem.js:582
++msgid "Open With Other Application"
++msgstr "Öppna med annat program"
++
++#: fileItem.js:586
++msgid "Cut"
++msgstr "Klipp ut"
++
++#: fileItem.js:587
++msgid "Copy"
++msgstr "Kopiera"
++
++#: fileItem.js:589
++msgid "Rename…"
++msgstr "Byt namn…"
++
++#: fileItem.js:590
++msgid "Move to Trash"
++msgstr "Flytta till papperskorgen"
++
++#: fileItem.js:600
++msgid "Empty Trash"
++msgstr "Töm papperskorgen"
++
++#: fileItem.js:606
++msgid "Properties"
++msgstr "Egenskaper"
++
++#: fileItem.js:608
++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 "CPU"
+ #~ msgstr "CPU"
+ 
+ #~ msgid "Memory"
+ #~ msgstr "Minne"
++
++#~ msgid "Huge"
++#~ msgstr "Enorm"
+diff --git a/po/tr.po b/po/tr.po
+index 6243374..30ceafa 100644
+--- a/po/tr.po
++++ b/po/tr.po
+@@ -1,3 +1,4 @@
++# #-#-#-#-#  tr.po (gnome-shell-extensions master)  #-#-#-#-#
+ # Turkish translation for gnome-shell-extensions.
+ # Copyright (C) 2012 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+@@ -7,8 +8,19 @@
+ # Muhammet Kara <muhammetk@gmail.com>, 2013, 2014, 2015.
+ # Furkan Tokaç <developmentft@gmail.com>, 2017.
+ #
++# #-#-#-#-#  tr.po  #-#-#-#-#
++# 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 <libreajans@gmail.com>, 2019.
++# Serdar Sağlam <teknomobil@yandex.com>, 2019
++# Emin Tufan Çetin <etcetin@gmail.com>, 2019.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  tr.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"
+@@ -22,6 +34,20 @@ msgstr ""
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=1; plural=0;\n"
+ "X-Generator: Gtranslator 2.91.7\n"
++"#-#-#-#-#  tr.po  #-#-#-#-#\n"
++"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 <etcetin@gmail.com>\n"
++"Language-Team: Türkçe <gnome-turk@gnome.org>\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"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -362,6 +388,174 @@ msgstr "İsim"
+ msgid "Workspace %d"
+ msgstr "Çalışma Alanı %d"
+ 
++#: 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."
++
+ #~ msgid "CPU"
+ #~ msgstr "İşlemci"
+ 
+diff --git a/po/zh_TW.po b/po/zh_TW.po
+index 74a95f8..fa5ba9b 100644
+--- a/po/zh_TW.po
++++ b/po/zh_TW.po
+@@ -1,10 +1,19 @@
++# #-#-#-#-#  zh_TW.po (gnome-shell-extensions gnome-3-0)  #-#-#-#-#
+ # Chinese (Taiwan) translation for gnome-shell-extensions.
+ # Copyright (C) 2011 gnome-shell-extensions's COPYRIGHT HOLDER
+ # This file is distributed under the same license as the gnome-shell-extensions package.
+ # Cheng-Chia Tseng <pswo10680@gmail.com>, 2011.
+ #
++# #-#-#-#-#  zh_TW.po (desktop-icons master)  #-#-#-#-#
++# Chinese (Taiwan) 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.
++# Yi-Jyun Pan <pan93412@gmail.com>, 2018.
++#
++#, fuzzy
+ msgid ""
+ msgstr ""
++"#-#-#-#-#  zh_TW.po (gnome-shell-extensions gnome-3-0)  #-#-#-#-#\n"
+ "Project-Id-Version: gnome-shell-extensions gnome-3-0\n"
+ "Report-Msgid-Bugs-To: https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
+ "shell&keywords=I18N+L10N&component=extensions\n"
+@@ -17,6 +26,19 @@ msgstr ""
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "X-Generator: Poedit 2.0.3\n"
++"#-#-#-#-#  zh_TW.po (desktop-icons master)  #-#-#-#-#\n"
++"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-22 14:12+0000\n"
++"PO-Revision-Date: 2018-10-24 21:31+0800\n"
++"Language-Team: Chinese (Taiwan) <chinese-l10n@googlegroups.com>\n"
++"Language: zh_TW\n"
++"MIME-Version: 1.0\n"
++"Content-Type: text/plain; charset=UTF-8\n"
++"Content-Transfer-Encoding: 8bit\n"
++"Last-Translator: pan93412 <pan93412@gmail.com>\n"
++"X-Generator: Poedit 2.2\n"
+ 
+ #: data/gnome-classic.desktop.in:3 data/gnome-classic.session.desktop.in:3
+ msgid "GNOME Classic"
+@@ -344,6 +366,127 @@ msgstr "名稱"
+ msgid "Workspace %d"
+ msgstr "工作區 %d"
+ 
++#: desktopGrid.js:307
++#, fuzzy
++msgid "Display Settings"
++msgstr ""
++"#-#-#-#-#  zh_TW.po (gnome-shell-extensions gnome-3-0)  #-#-#-#-#\n"
++"顯示設定值\n"
++"#-#-#-#-#  zh_TW.po (desktop-icons master)  #-#-#-#-#\n"
++"顯示設定"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:12
++msgid "Icon size"
++msgstr "圖示大小"
++
++#: prefs.js:89
++msgid "Size for the desktop icons"
++msgstr "桌面圖示的大小"
++
++#: prefs.js:89
++msgid "Small"
++msgstr "小圖示"
++
++#: prefs.js:89
++msgid "Standard"
++msgstr "標準大小圖示"
++
++#: prefs.js:89
++msgid "Large"
++msgstr "大圖示"
++
++#: prefs.js:89
++msgid "Huge"
++msgstr "巨大圖示"
++
++#: prefs.js:90
++msgid "Show the personal folder in the desktop"
++msgstr "在桌面顯示個人資料夾"
++
++#: prefs.js:91
++msgid "Show the trash icon in the desktop"
++msgstr "在桌面顯示垃圾桶圖示"
++
++#: desktopGrid.js:178 desktopGrid.js:297
++msgid "New Folder"
++msgstr "新增資料夾"
++
++#: desktopGrid.js:299
++msgid "Paste"
++msgstr "貼上"
++
++#: desktopGrid.js:300
++msgid "Undo"
++msgstr "復原"
++
++#: desktopGrid.js:301
++msgid "Redo"
++msgstr "重做"
++
++#: desktopGrid.js:303
++msgid "Open Desktop in Files"
++msgstr "在《檔案》中開啟桌面"
++
++#: desktopGrid.js:304
++msgid "Open Terminal"
++msgstr "開啟終端器"
++
++#: desktopGrid.js:306
++msgid "Change Background…"
++msgstr "變更背景圖片…"
++
++#: desktopGrid.js:308
++msgid "Settings"
++msgstr "設定"
++
++#: fileItem.js:223
++msgid "Open"
++msgstr "開啟"
++
++#: fileItem.js:226
++msgid "Cut"
++msgstr "剪下"
++
++#: fileItem.js:227
++msgid "Copy"
++msgstr "複製"
++
++#: fileItem.js:228
++msgid "Move to Trash"
++msgstr "移動到垃圾桶"
++
++#: fileItem.js:232
++msgid "Empty trash"
++msgstr "清空回收桶"
++
++#: fileItem.js:238
++msgid "Properties"
++msgstr "屬性"
++
++#: fileItem.js:240
++msgid "Show in Files"
++msgstr "在《檔案》中顯示"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:13
++msgid "Set the size for the desktop icons."
++msgstr "設定桌面圖示的大小。"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:17
++msgid "Show personal folder"
++msgstr "顯示個人資料夾"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:18
++msgid "Show the personal folder in the desktop."
++msgstr "在桌面顯示個人資料夾。"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:22
++msgid "Show trash icon"
++msgstr "顯示垃圾桶圖示"
++
++#: schemas/org.gnome.shell.extensions.desktop-icons.gschema.xml:23
++msgid "Show the trash icon in the desktop."
++msgstr "在桌面顯示垃圾桶圖示。"
++
+ #~ msgid "CPU"
+ #~ msgstr "CPU"
+ 
+@@ -371,9 +514,6 @@ msgstr "工作區 %d"
+ #~ msgid "Display"
+ #~ msgstr "顯示"
+ 
+-#~ msgid "Display Settings"
+-#~ msgstr "顯示設定值"
+-
+ #~ msgid "Suspend"
+ #~ msgstr "暫停"
+ 
+@@ -481,9 +621,6 @@ msgstr "工作區 %d"
+ #~ msgid "Enable/disable autohide"
+ #~ msgstr "啟用/停用自動隱藏"
+ 
+-#~ msgid "Icon size"
+-#~ msgstr "圖示大小"
+-
+ #~ msgid "Position of the dock"
+ #~ msgstr "Dock 的位置"
+ 
+-- 
+2.21.1
+
diff --git a/SOURCES/gnome-classic-wayland.desktop b/SOURCES/gnome-classic-wayland.desktop
new file mode 100644
index 0000000..bf02a49
--- /dev/null
+++ b/SOURCES/gnome-classic-wayland.desktop
@@ -0,0 +1,27 @@
+[Desktop Entry]
+Name[de]=Klassisch (Wayland Anzeige-Server)
+Name[es]=Clásico (servidor gráfico Wayland)
+Name[fr]=Classic (serveur affichage Wayland)
+Name[it]=Classico (server grafico Wayland)
+Name[ja]=クラシック (Wayland ディスプレイサーバー)
+Name[ko]=클래식 (Wayland 디스플레이 서버)
+Name[pt_BR]=Clássico (servidor de exibição Wayland)
+Name[ru]=Классический (дисплейный сервер Wayland)
+Name[zh_CN]=经典(Wayland 显现服务器)
+Name[zh_TW]=經典(Wayland顯示服務器)
+Name=Classic (Wayland display server)
+Comment[de]=Diese Sitzung meldet Sie in GNOME Classic an
+Comment[es]=Esta sesión inicia GNOME clásico
+Comment[fr]=Cette session vous connnecte à GNOME Classique
+Comment[it]=Questa sessione si avvia con GNOME classico
+Comment[ja]=GNOME クラシックモードでログインします
+Comment[ko]=이 세션을 사용하면 그놈 클래식에 로그인합니다
+Comment[pt_BR]=Essa sessão se inicia como GNOME Clássico
+Comment[ru]=Данный сеанс использует классический рабочий стол GNOME
+Comment[zh_CN]=该会话将登录到“GNOME 经典模式”
+Comment[zh_TW]=這個作業階段讓您登入 GNOME Classic
+Comment=This session logs you into GNOME Classic
+Exec=env GNOME_SHELL_SESSION_MODE=classic gnome-session --session gnome-classic
+TryExec=gnome-session
+Type=Application
+DesktopNames=GNOME-Classic;GNOME;
diff --git a/SOURCES/gnome-classic.desktop b/SOURCES/gnome-classic.desktop
new file mode 100644
index 0000000..b59c0d9
--- /dev/null
+++ b/SOURCES/gnome-classic.desktop
@@ -0,0 +1,27 @@
+[Desktop Entry]
+Name[de]=Klassisch (X11 Anzeige-Server)
+Name[es]=Clásico (servidor gráfico X11)
+Name[fr]=Classic (serveur affichage X11)
+Name[it]=Classico (server grafico X11)
+Name[ja]=クラシック  (X11 ディスプレイサーバー)
+Name[ko]=클래식 (X11 디스플레이 서버)
+Name[pt_BR]=Clássico (servidor de exibição X11)
+Name[ru]=Классический (дисплейный сервер X11)
+Name[zh_CN]=经典(X11 显示服务器)
+Name[zh_TW]=經典(X11顯示服務器)
+Name=Classic (X11 display server)
+Comment[de]=Diese Sitzung meldet Sie in GNOME Classic an
+Comment[es]=Esta sesión inicia GNOME clásico
+Comment[fr]=Cette session vous connnecte à GNOME Classique
+Comment[it]=Questa sessione si avvia con GNOME classico
+Comment[ja]=GNOME クラシックモードでログインします
+Comment[ko]=이 세션을 사용하면 그놈 클래식에 로그인합니다
+Comment[pt_BR]=Essa sessão se inicia como GNOME Clássico
+Comment[ru]=Данный сеанс использует классический рабочий стол GNOME
+Comment[zh_CN]=该会话将登录到“GNOME 经典模式”
+Comment[zh_TW]=這個作業階段讓您登入 GNOME Classic
+Comment=This session logs you into GNOME Classic
+Exec=env GNOME_SHELL_SESSION_MODE=classic gnome-session --session gnome-classic
+TryExec=gnome-session
+Type=Application
+DesktopNames=GNOME-Classic;GNOME;
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 <jimmac@gmail.com>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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 <jimmac@gmail.com>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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?= <fmuellner@gnome.org>
+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
new file mode 100644
index 0000000..9c4daf4
--- /dev/null
+++ b/SOURCES/resurrect-system-monitor.patch
@@ -0,0 +1,1311 @@
+From 7c3b0af4fde0b542089f2b0c84250404eef0ecca Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Wed, 17 May 2017 19:13:50 +0200
+Subject: [PATCH 1/5] extensions: Resurrect systemMonitor extension
+
+The extension was removed upstream because:
+ - it hooks into the message tray that was removed
+ - it was known to have performance issues
+ - there are plenty of alternatives
+
+Those aren't good enough reasons for dropping it downstream
+as well though, so we need to bring it back ...
+
+This reverts commit c9a6421f362cd156cf731289eadc11f44f6970ac.
+---
+ extensions/systemMonitor/extension.js     | 376 ++++++++++++++++++++++
+ extensions/systemMonitor/meson.build      |   5 +
+ extensions/systemMonitor/metadata.json.in |  11 +
+ extensions/systemMonitor/stylesheet.css   |  35 ++
+ meson.build                               |   1 +
+ 5 files changed, 428 insertions(+)
+ create mode 100644 extensions/systemMonitor/extension.js
+ create mode 100644 extensions/systemMonitor/meson.build
+ create mode 100644 extensions/systemMonitor/metadata.json.in
+ create mode 100644 extensions/systemMonitor/stylesheet.css
+
+diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js
+new file mode 100644
+index 0000000..7b09df0
+--- /dev/null
++++ b/extensions/systemMonitor/extension.js
+@@ -0,0 +1,376 @@
++/* -*- 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;
++
++const Main = imports.ui.main;
++const Tweener = imports.ui.tweener;
++
++const Gettext = imports.gettext.domain('gnome-shell-extensions');
++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;
++
++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() {
++        this._initValues();
++        this.drawing_area = new St.DrawingArea({ reactive: true });
++        this.drawing_area.connect('repaint', Lang.bind(this, this._draw));
++        this.drawing_area.connect('button-press-event', function() {
++            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 });
++        this.actor.add_actor(this.drawing_area);
++
++        this._timeout = Mainloop.timeout_add(INDICATOR_UPDATE_INTERVAL, Lang.bind(this, function () {
++            this._updateValues();
++            this.drawing_area.queue_repaint();
++            return true;
++        }));
++    },
++
++    showLabel: function() {
++        if (this.label == null)
++            return;
++
++        this.label.opacity = 0;
++        this.label.show();
++
++        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 labelWidth = this.label.width;
++        let labelHeight = this.label.height;
++        let xOffset = Math.floor((itemWidth - labelWidth) / 2)
++
++        let x = stageX + xOffset;
++
++        let node = this.label.get_theme_node();
++        let yOffset = node.get_length('-y-offset');
++
++        let y = stageY - this.label.get_height() - yOffset;
++
++        this.label.set_position(x, y);
++        Tweener.addTween(this.label,
++                         { opacity: 255,
++                           time: ITEM_LABEL_SHOW_TIME,
++                           transition: 'easeOutQuad',
++                         });
++    },
++
++    setLabelText: function(text) {
++        if (this.label == null)
++            this.label = new St.Label({ style_class: 'extension-systemMonitor-indicator-label'});
++
++        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);
++
++        this.actor.destroy();
++	if (this.label)
++	    this.label.destroy();
++    },
++
++    _initValues: function() {
++    },
++
++    _updateValues: function() {
++    },
++
++    _draw: function(area) {
++        let [width, height] = area.get_surface_size();
++        let themeNode = this.actor.get_theme_node();
++        let cr = area.get_context();
++
++        //draw the background grid
++        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);
++        }
++        Clutter.cairo_set_source_color(cr, color);
++        cr.setLineWidth(1);
++        cr.setDash([4,1], 0);
++        cr.stroke();
++
++        //draw the foreground
++
++        function makePath(values, reverse, nudge) {
++            if (nudge == null) {
++                nudge = 0;
++            }
++            //if we are going in reverse, we are completing the bottom of a chart, so use lineTo
++            if (reverse) {
++                cr.lineTo(values.length - 1, (1 - values[values.length - 1]) * height + nudge);
++                for (let k = values.length - 2; k >= 0; --k) {
++                    cr.lineTo(k, (1 - values[k]) * height + nudge);
++                }
++            } else {
++                cr.moveTo(0, (1 - values[0]) * height + nudge);
++                for (let k = 1; k < values.length; ++k) {
++                    cr.lineTo(k, (1 - values[k]) * height + nudge);
++                }
++
++            }
++        }
++
++        let renderStats = this.renderStats;
++
++        // Make sure we don't have more sample points than pixels
++        renderStats.map(Lang.bind(this, function(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]];
++            // We outline at full opacity and fill with 40% opacity
++            let outlineColor = themeNode.get_color(stat.color);
++            let color = new Clutter.Color(outlineColor);
++            color.alpha = color.alpha * .4;
++
++            // Render the background between us and the next level
++            makePath(stat.values, false);
++            // If there is a process below us, render the cpu between us and it, otherwise,
++            // render to the bottom of the chart
++            if (i == renderStats.length - 1) {
++                cr.lineTo(stat.values.length - 1, height);
++                cr.lineTo(0, height);
++                cr.closePath();
++            } else {
++                let nextStat = this.stats[renderStats[i+1]];
++                makePath(nextStat.values, true);
++            }
++            cr.closePath()
++            Clutter.cairo_set_source_color(cr, color);
++            cr.fill();
++
++            // Render the outline of this level
++            makePath(stat.values, false, .5);
++            Clutter.cairo_set_source_color(cr, outlineColor);
++            cr.setLineWidth(1.0);
++            cr.setDash([], 0);
++            cr.stroke();
++        }
++    }
++});
++
++const CpuIndicator = new Lang.Class({
++    Name: 'SystemMonitor.CpuIndicator',
++    Extends: Indicator,
++
++    _init: function() {
++        this.parent();
++
++        this.gridColor = '-grid-color';
++        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) {
++            return renderStatOrder[a] - renderStatOrder[b];
++        });
++
++	this.setLabelText(_("CPU"));
++    },
++
++    _initValues: function() {
++        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() {
++        let cpu = new GTop.glibtop_cpu;
++        let t = 0.0;
++        GTop.glibtop_get_cpu(cpu);
++        let total = cpu.total - this._prev.total;
++        let user = cpu.user - this._prev.user;
++        let sys = cpu.sys - this._prev.sys;
++        let iowait = cpu.iowait - this._prev.iowait;
++        let idle = cpu.idle - this._prev.idle;
++
++        t += iowait / total;
++        this.stats['cpu-iowait'].values.push(t);
++        t += sys / total;
++        this.stats['cpu-sys'].values.push(t);
++        t += user / total;
++        this.stats['cpu-user'].values.push(t);
++        this.stats['cpu-total'].values.push(1 - idle / total);
++
++        this._prev = cpu;
++    }
++});
++
++const MemoryIndicator = new Lang.Class({
++    Name: 'SystemMonitor.MemoryIndicator',
++    Extends: Indicator,
++
++    _init: function() {
++        this.parent();
++
++        this.gridColor = '-grid-color';
++        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) {
++            return renderStatOrder[a] - renderStatOrder[b];
++        });
++
++	this.setLabelText(_("Memory"));
++    },
++
++    _initValues: function() {
++        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: [] }
++                     };
++    },
++
++    _updateValues: function() {
++        GTop.glibtop_get_mem(this.mem);
++
++        let t = this.mem.user / this.mem.total;
++        this.stats['mem-user'].values.push(t);
++        t += (this.mem.used - this.mem.user - this.mem.cached) / this.mem.total;
++        this.stats['mem-other'].values.push(t);
++        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._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._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: 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) {
++        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;
++                }
++            }
++        } else {
++            if (this._showLabelTimeoutId > 0)
++                Mainloop.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;
++                    }));
++            }
++        }
++    },
++});
++
++function init() {
++    return new Extension();
++}
+diff --git a/extensions/systemMonitor/meson.build b/extensions/systemMonitor/meson.build
+new file mode 100644
+index 0000000..48504f6
+--- /dev/null
++++ b/extensions/systemMonitor/meson.build
+@@ -0,0 +1,5 @@
++extension_data += configure_file(
++  input: metadata_name + '.in',
++  output: metadata_name,
++  configuration: metadata_conf
++)
+diff --git a/extensions/systemMonitor/metadata.json.in b/extensions/systemMonitor/metadata.json.in
+new file mode 100644
+index 0000000..fa75007
+--- /dev/null
++++ b/extensions/systemMonitor/metadata.json.in
+@@ -0,0 +1,11 @@
++{
++    "shell-version": ["@shell_current@" ],
++    "uuid": "@uuid@",
++    "extension-id": "@extension_id@",
++    "settings-schema": "@gschemaname@",
++    "gettext-domain": "@gettext_domain@",
++    "original-author": "zaspire@rambler.ru",
++    "name": "SystemMonitor",
++    "description": "System monitor showing CPU and memory usage in the message tray.",
++    "url": "@url@"
++}
+diff --git a/extensions/systemMonitor/stylesheet.css b/extensions/systemMonitor/stylesheet.css
+new file mode 100644
+index 0000000..13f95ec
+--- /dev/null
++++ b/extensions/systemMonitor/stylesheet.css
+@@ -0,0 +1,35 @@
++.extension-systemMonitor-container {
++    spacing: 5px;
++    padding-left: 5px;
++    padding-right: 5px;
++    padding-bottom: 10px;
++    padding-top: 10px;
++}
++
++.extension-systemMonitor-indicator-area {
++    border: 1px solid #8d8d8d;
++    border-radius: 3px;
++    width: 100px;
++    /* message tray is 72px, so 20px padding of the container,
++       2px of border, makes it 50px */
++    height: 50px;
++    -grid-color: #575757;
++    -cpu-total-color: rgb(0,154,62);
++    -cpu-user-color: rgb(69,154,0);
++    -cpu-sys-color: rgb(255,253,81);
++    -cpu-iowait-color: rgb(210,148,0);
++    -mem-user-color: rgb(210,148,0);
++    -mem-cached-color: rgb(90,90,90);
++    -mem-other-color: rgb(205,203,41);
++    background-color: #1e1e1e;
++}
++
++.extension-systemMonitor-indicator-label {
++    border-radius: 7px;
++    padding: 4px 12px;
++    background-color: rgba(0,0,0,0.9);
++    text-align: center;
++    -y-offset: 8px;
++    font-size: 9pt;
++    font-weight: bold;
++}
+diff --git a/meson.build b/meson.build
+index 6e8c41f..6764f9a 100644
+--- a/meson.build
++++ b/meson.build
+@@ -55,6 +55,7 @@ all_extensions += [
+   'native-window-placement',
+   'no-hot-corner',
+   'panel-favorites',
++  'systemMonitor',
+   'top-icons',
+   'updates-dialog',
+   'user-theme',
+-- 
+2.21.0
+
+
+From ddf4d70df56321366a2cb8b89689d59be4dbb718 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Fri, 17 May 2019 22:55:48 +0000
+Subject: [PATCH 2/5] systemMonitor: Modernise code
+
+ - port to ES6 classes
+ - replace Lang.bind()
+ - destructure imports
+ - fix style issues (stray/missing spaces/semi-colons, indent, ...)
+---
+ 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..89f8916 100644
+--- a/extensions/systemMonitor/extension.js
++++ b/extensions/systemMonitor/extension.js
+@@ -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 Tweener = imports.ui.tweener;
+ 
+ const Gettext = imports.gettext.domain('gnome-shell-extensions');
+ 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;
+ 
+@@ -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.connect('repaint', Lang.bind(this, this._draw));
+-        this.drawing_area.connect('button-press-event', 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;
+         });
+ 
+-        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);
++        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();
+-            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);
+-        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'
++            });
+ 
+         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()
++        });
++    }
++
++    destroy() {
+         this.actor.destroy();
+-	if (this.label)
+-	    this.label.destroy();
+-    },
++    }
++
++    _onDestroy() {
++        GLib.source_remove(this._timeout);
++
++        if (this.label)
++            this.label.destroy();
++    }
+ 
+-    _initValues: function() {
+-    },
++    _initValues() {
++    }
+ 
+-    _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();
+         }
+     }
+-});
+-
+-const CpuIndicator = new Lang.Class({
+-    Name: 'SystemMonitor.CpuIndicator',
+-    Extends: Indicator,
++};
+ 
+-    _init: function() {
+-        this.parent();
++const CpuIndicator = class extends Indicator {
++    constructor() {
++        super();
+ 
+         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._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._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: 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?= <fmuellner@gnome.org>
+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(item) {
+diff --git a/extensions/systemMonitor/stylesheet.css b/extensions/systemMonitor/stylesheet.css
+index 13f95ec..978ac12 100644
+--- a/extensions/systemMonitor/stylesheet.css
++++ b/extensions/systemMonitor/stylesheet.css
+@@ -1,17 +1,4 @@
+-.extension-systemMonitor-container {
+-    spacing: 5px;
+-    padding-left: 5px;
+-    padding-right: 5px;
+-    padding-bottom: 10px;
+-    padding-top: 10px;
+-}
+-
+ .extension-systemMonitor-indicator-area {
+-    border: 1px solid #8d8d8d;
+-    border-radius: 3px;
+-    width: 100px;
+-    /* message tray is 72px, so 20px padding of the container,
+-       2px of border, makes it 50px */
+     height: 50px;
+     -grid-color: #575757;
+     -cpu-total-color: rgb(0,154,62);
+@@ -21,7 +8,6 @@
+     -mem-user-color: rgb(210,148,0);
+     -mem-cached-color: rgb(90,90,90);
+     -mem-other-color: rgb(205,203,41);
+-    background-color: #1e1e1e;
+ }
+ 
+ .extension-systemMonitor-indicator-label {
+-- 
+2.21.0
+
+
+From f73fe9cfb5f9dbd6647e4eb30a9af0fb7ff79219 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Thu, 18 May 2017 16:20:07 +0200
+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: https://gitlab.gnome.org/GNOME/gnome-shell-extensions3
+---
+ 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 0188960..b4d5a9d 100644
+--- a/extensions/systemMonitor/extension.js
++++ b/extensions/systemMonitor/extension.js
+@@ -303,6 +303,21 @@ const MemoryIndicator = class extends Indicator {
+     }
+ };
+ 
++class SystemMonitorSection extends MessageList.MessageListSection {
++    constructor() {
++        super(_('System Monitor'));
++    }
++
++    _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];
+ 
+ class Extension {
+@@ -315,7 +330,7 @@ class Extension {
+     }
+ 
+     enable() {
+-        this._section = new MessageList.MessageListSection(_('System Monitor'));
++        this._section = new SystemMonitorSection();
+         this._indicators = [];
+ 
+         for (let i = 0; i < INDICATORS.length; i++) {
+-- 
+2.21.0
+
+
+From df76e98d6bbac7dccc86f66e82eac2977fb5ed87 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
+Date: Thu, 18 May 2017 18:00:17 +0200
+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
+style.
+
+Fixes: #4
+---
+ extensions/systemMonitor/classic.css | 6 ++++++
+ extensions/systemMonitor/meson.build | 4 ++++
+ 2 files changed, 10 insertions(+)
+ create mode 100644 extensions/systemMonitor/classic.css
+
+diff --git a/extensions/systemMonitor/classic.css b/extensions/systemMonitor/classic.css
+new file mode 100644
+index 0000000..946863d
+--- /dev/null
++++ b/extensions/systemMonitor/classic.css
+@@ -0,0 +1,6 @@
++@import url("stylesheet.css");
++
++.extension-systemMonitor-indicator-label {
++    background-color: rgba(237,237,237,0.9);
++    border: 1px solid #a1a1a1;
++}
+diff --git a/extensions/systemMonitor/meson.build b/extensions/systemMonitor/meson.build
+index 48504f6..b6548b1 100644
+--- a/extensions/systemMonitor/meson.build
++++ b/extensions/systemMonitor/meson.build
+@@ -3,3 +3,7 @@ extension_data += configure_file(
+   output: metadata_name,
+   configuration: metadata_conf
+ )
++
++if classic_mode_enabled
++  extension_data += files('classic.css')
++endif
+-- 
+2.21.0
+
diff --git a/SPECS/gnome-shell-extensions.spec b/SPECS/gnome-shell-extensions.spec
new file mode 100644
index 0000000..5ae872b
--- /dev/null
+++ b/SPECS/gnome-shell-extensions.spec
@@ -0,0 +1,1025 @@
+%global major_version %%(cut -d "." -f 1-2 <<<%{version})
+# Minimum GNOME Shell version supported
+%global min_gs_version %%(cut -d "." -f 1-3 <<<%{version})
+
+%global pkg_prefix gnome-shell-extension
+
+Name:           gnome-shell-extensions
+Version:        3.32.1
+Release:        13%{?dist}
+Summary:        Modify and extend GNOME Shell functionality and behavior
+
+Group:          User Interface/Desktops
+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
+Source2:        gnome-classic-wayland.desktop
+
+# BuildRequires:  gnome-common
+BuildRequires:  meson
+BuildRequires:  sassc
+BuildRequires:  git
+BuildRequires:  gettext >= 0.19.6
+BuildRequires:  pkgconfig(gnome-desktop-3.0)
+BuildRequires:  pkgconfig(libgtop-2.0)
+Requires:       gnome-shell >= %{min_gs_version}
+BuildArch:      noarch
+
+Patch0001:         0001-Update-style.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
+Patch0009:         0001-dashToDock-Handle-no-overview-case.patch
+Patch0010:         0001-window-list-Invalid-current-mode-selected-in-Prefere.patch
+Patch0011:         0001-Update-desktop-icons-gettext-domain.patch
+Patch0012:         0001-desktop-icons-Update-Japanese-translation.patch
+
+%description
+GNOME Shell Extensions is a collection of extensions providing additional and
+optional functionality to GNOME Shell.
+
+Enabled extensions:
+  * apps-menu
+  * auto-move-windows
+  * dash-to-dock
+  * disable-screenshield
+  * desktop-icons
+  * horizontal-workspaces
+  * drive-menu
+  * launch-new-instance
+  * native-window-placement
+  * no-hot-corner
+  * panel-favorites
+  * places-menu
+  * screenshot-window-sizer
+  * top-icons
+  * updates-dialog
+  * user-theme
+  * window-list
+  * windowsNavigator
+  * workspace-indicator
+
+
+%package -n %{pkg_prefix}-common
+Summary:        Files common to GNOME Shell Extensions
+Group:          User Interface/Desktops
+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
+Obsoletes:      %{pkg_prefix}-xrandr-indicator < 3.9.90
+# Obsolete extensions dropped in favor of schema overrides by upstream
+Obsoletes:       %{pkg_prefix}-default-min-max < 3.9.3-1
+Obsoletes:       %{pkg_prefix}-static-workspaces < 3.9.3-1
+Obsoletes:       %{pkg_prefix}-systemMonitor < 3.15.91
+
+%description -n %{pkg_prefix}-common
+GNOME Shell Extensions is a collection of extensions providing additional and
+optional functionality to GNOME Shell.
+
+This package provides common data files shared by various extensions.
+
+
+%package -n gnome-classic-session
+Summary:        GNOME "classic" mode session
+Group:          User Interface/Desktops
+License:        GPLv2+
+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}
+Requires:       nautilus
+# Obsolete fallback mode components
+Obsoletes:      gnome-applets < 1:3.5.92-5
+%global gnome_applet_sensors_obsolete_ver 3.0.0-6
+Obsoletes:      gnome-applet-sensors < %{gnome_applet_sensors_obsolete_ver}
+Obsoletes:      gnome-applet-sensors-devel < %{gnome_applet_sensors_obsolete_ver}
+%global gnome_panel_obsolete_ver 3.6.2-7
+Obsoletes:      gnome-panel < %{gnome_panel_obsolete_ver}
+Obsoletes:      gnome-panel-devel < %{gnome_panel_obsolete_ver}
+Obsoletes:      gnome-panel-libs < %{gnome_panel_obsolete_ver}
+
+%description -n gnome-classic-session
+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}-apps-menu
+Summary:        Application menu for GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+Requires:       gnome-menus
+
+%description  -n %{pkg_prefix}-apps-menu
+This GNOME Shell extension adds a GNOME 2.x style menu for applications.
+
+
+%package -n %{pkg_prefix}-auto-move-windows
+Summary:        Assign specific workspaces to applications in GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-auto-move-windows
+This GNOME Shell extension enables easy workspace management. A specific
+workspace can be assigned to each application as soon as it creates a window, in
+a manner configurable with a GSettings key.
+
+
+%package -n %{pkg_prefix}-dash-to-dock
+Summary:        Show the dash outside the activities overview
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-dash-to-dock
+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
+License:        GPLv3+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-desktop-icons
+This GNOME Shell extension adds desktop icons support as seen in GNOME 2
+
+
+%package -n %{pkg_prefix}-drive-menu
+Summary:        Drive status menu for GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-drive-menu
+This GNOME Shell extension provides a panel status menu for accessing and
+unmounting removable devices.
+
+
+%package -n %{pkg_prefix}-launch-new-instance
+Summary:        Always launch a new application instance for GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description  -n %{pkg_prefix}-launch-new-instance
+This GNOME Shell extension modifies the behavior of clicking in the dash and app
+launcher to always launch a new application instance.
+
+
+%package -n %{pkg_prefix}-native-window-placement
+Summary:        Native window placement for GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description  -n %{pkg_prefix}-native-window-placement
+This GNOME Shell extension provides additional configurability for the window
+layout in the overview, including a mechanism similar to KDE4.
+
+
+%package -n %{pkg_prefix}-no-hot-corner
+Summary:        Disable the hot corner in GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description  -n %{pkg_prefix}-no-hot-corner
+This GNOME Shell extension disables the hot corner in the top bar.
+
+
+%package -n %{pkg_prefix}-panel-favorites
+Summary:        Favorite launchers in GNOME Shell's top bar
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-panel-favorites
+This GNOME Shell extension adds favorite launchers to the top bar.
+
+
+%package -n %{pkg_prefix}-places-menu
+Summary:        Places status menu for GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-places-menu
+This GNOME Shell extension add a system status menu for quickly navigating
+places in the system.
+
+
+%package -n %{pkg_prefix}-screenshot-window-sizer
+Summary:        Screenshot window sizer for GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-screenshot-window-sizer
+This GNOME Shell extension allows to easily resize windows for GNOME Software
+screenshots.
+
+
+%package -n %{pkg_prefix}-systemMonitor
+Summary:        System Monitor for GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+# Should be pulled in by control-center, but in case someone tries for a
+# minimalist gnome-shell installation
+Requires:       libgtop2
+
+%description -n %{pkg_prefix}-systemMonitor
+This GNOME Shell extension is a message tray indicator for CPU and memory usage
+
+
+%package -n %{pkg_prefix}-top-icons
+Summary:        Show legacy icons on top
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-top-icons
+This GNOME Shell extension moves legacy tray icons into the top bar.
+
+
+%package -n %{pkg_prefix}-updates-dialog
+Summary:        Show a modal dialog when there are software updates
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-updates-dialog
+This GNOME Shell extension shows a modal dialog when there are software updates
+
+
+%package -n %{pkg_prefix}-user-theme
+Summary:        Support for custom themes in GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-user-theme
+This GNOME Shell extension enables loading a GNOME Shell theme from
+~/.themes/<name>/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
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-window-list
+This GNOME Shell extension displays a window list at the bottom of the screen.
+
+
+%package -n %{pkg_prefix}-windowsNavigator
+Summary:        Support for keyboard selection of windows and workspaces in GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-windowsNavigator
+This GNOME Shell extension enables keyboard selection of windows and workspaces
+in overlay mode, by pressing the Alt and Ctrl key respectively.
+
+
+%package -n %{pkg_prefix}-workspace-indicator
+Summary:        Workspace indicator for GNOME Shell
+Group:          User Interface/Desktops
+License:        GPLv2+
+Requires:       %{pkg_prefix}-common = %{version}-%{release}
+
+%description -n %{pkg_prefix}-workspace-indicator
+This GNOME Shell extension add a system status menu for quickly changing
+workspaces.
+
+
+%prep
+%autosetup -S git
+
+
+%build
+%meson -Dextension_set="all" -Dclassic_mode=true
+%meson_build
+
+
+%install
+%meson_install
+
+# rename GNOME Classic to Classic and provide a wayland variant
+mkdir -p $RPM_BUILD_ROOT%{_datadir}/wayland-sessions
+cp $RPM_BUILD_ROOT%{_datadir}/xsessions/gnome-classic.desktop \
+   $RPM_BUILD_ROOT%{_datadir}/wayland-sessions/gnome-classic-wayland.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
+
+%find_lang %{name}
+
+
+%files -n %{pkg_prefix}-common -f %{name}.lang
+%doc NEWS README.md
+%license COPYING
+
+
+%files -n gnome-classic-session
+%{_datadir}/gnome-session/sessions/gnome-classic.session
+%{_datadir}/gnome-shell/modes/classic.json
+%{_datadir}/gnome-shell/theme/*.svg
+%{_datadir}/gnome-shell/theme/gnome-classic-high-contrast.css
+%{_datadir}/gnome-shell/theme/gnome-classic.css
+%{_datadir}/xsessions/gnome-classic.desktop
+%{_datadir}/wayland-sessions/gnome-classic-wayland.desktop
+%{_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*/
+
+
+%files -n %{pkg_prefix}-auto-move-windows
+%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.auto-move-windows.gschema.xml
+%{_datadir}/gnome-shell/extensions/auto-move-windows*/
+
+
+%files -n %{pkg_prefix}-dash-to-dock
+%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.dash-to-dock.gschema.xml
+%{_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*/
+
+
+%files -n %{pkg_prefix}-drive-menu
+%{_datadir}/gnome-shell/extensions/drive-menu*/
+
+
+%files -n %{pkg_prefix}-launch-new-instance
+%{_datadir}/gnome-shell/extensions/launch-new-instance*/
+
+
+%files -n %{pkg_prefix}-native-window-placement
+%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.native-window-placement.gschema.xml
+%{_datadir}/gnome-shell/extensions/native-window-placement*/
+
+
+%files -n %{pkg_prefix}-no-hot-corner
+%{_datadir}/gnome-shell/extensions/no-hot-corner*/
+
+
+%files -n %{pkg_prefix}-panel-favorites
+%{_datadir}/gnome-shell/extensions/panel-favorites*/
+
+
+%files -n %{pkg_prefix}-places-menu
+%{_datadir}/gnome-shell/extensions/places-menu*/
+
+
+%files -n %{pkg_prefix}-screenshot-window-sizer
+%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.screenshot-window-sizer.gschema.xml
+%{_datadir}/gnome-shell/extensions/screenshot-window-sizer*/
+
+
+%files -n %{pkg_prefix}-systemMonitor
+%{_datadir}/gnome-shell/extensions/systemMonitor*/
+
+
+%files -n %{pkg_prefix}-top-icons
+%{_datadir}/gnome-shell/extensions/top-icons*/
+
+
+%files -n %{pkg_prefix}-updates-dialog
+%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.updates-dialog.gschema.xml
+%{_datadir}/gnome-shell/extensions/updates-dialog*/
+
+
+%files -n %{pkg_prefix}-user-theme
+%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.user-theme.gschema.xml
+%{_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
+
+
+%files -n %{pkg_prefix}-windowsNavigator
+%{_datadir}/gnome-shell/extensions/windowsNavigator*/
+
+
+%files -n %{pkg_prefix}-workspace-indicator
+%{_datadir}/gnome-shell/extensions/workspace-indicator*/
+
+
+%changelog
+* Wed Jan 27 2021 Florian Müllner <fmuellner@redhat.com> - 3.32.1-13
+- Update Japanese translation
+  Related: #1865718
+
+* Sat Oct 24 2020 Florian Müllner <fmuellner@redhat.com> - 3.32.1-12
+- Adjust gettext locale in desktop-icons extension
+  Resolves: #1865718
+
+* Thu Apr 30 2020 Florian Müllner <fmuellner@redhat.com> - 3.32.1-11
+- Adjust dash-to-dock for classic backports
+  Resolves: #1805929
+- Fix inconsistent state in window-list prefs dialog
+  Resolves: #1824362
+
+* Wed Jul 24 2019 Florian Müllner <fmuellner@redhat.com> - 3.32.1-10
+- Drop obsolete downstream style patch
+- Keep classic notification styling
+  Related: #1731372
+
+* Thu Jul 18 2019 Florian Müllner <fmuellner@redhat.com> - 3.32.1-9
+- Backport classic style improvements
+  Resolves: #1726093
+
+* Thu Jul 04 2019 Florian Müllner <fmuellner@redhat.com> - 3.32.1-8
+- Allow closing window picker with Escape
+  Resolves: #1725854
+
+* Sat Jun 29 2019 Florian Müllner <fmuellner@redhat.com> - 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 <fmuellner@redhat.com> - 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 <fmuellner@redhat.com> - 3.32.1-5
+- Small refinements after design feedback:
+  - use default icon size in picker button to avoid blurriness
+  - use <super> shortcut to open window picker
+  Resolves: #1721195
+
+* Tue Jun 18 2019 Florian Müllner <fmuellner@redhat.com> - 3.32.1-4
+- Don't add apps-menu logo when activities button is present
+  Resolves: #1721195
+
+* Wed Jun 12 2019 Florian Müllner <fmuellner@redhat.com> - 3.32.1-3
+- Make classic mode more classic
+  Resolves: #1704360
+
+* Fri May 31 2019 Florian Müllner <fmuellner@redhat.com> - 3.32.1-2
+- Fix top-icons sizing issue
+  Resolves: #1715765
+
+* Thu May 23 2019 Florian Müllner <fmuellner@redhat.com> - 3.32.1-1
+- Update to 3.32.1
+  Resolves: #1713453
+
+* Mon Feb 11 2019 Florian Müllner <fmuellner@redhat.com> - 3.28.1-8
+- Update desktop-icons extension to 19.01
+  Resolves: #1666739
+
+* Fri Feb 08 2019 Florian Müllner <fmuellner@redhat.com> - 3.28.1-7
+- Re-add dropped downstream patches
+  Resolves: #1668885
+
+* Mon Jan 14 2019 Ray Strode <rstrode@redhat.com> - 3.28.1-6
+- Update desktop file names
+  Related: #1647713
+
+* Thu Dec 06 2018 Ray Strode <rstrode@redhat.com> - 3.28.1-5
+- Add requires on desktop-icons extension for classic session
+  Resolves: #1648863
+
+* Tue Sep 04 2018 Ray Strode <rstrode@redhat.com> - 3.28.1-4
+- Add back corporate logo on the left of Activities
+- Remove shadow remnants of app logo to the right of Activities
+  Resolves: #1620241
+
+* Wed Aug 22 2018 Ray Strode <rstrode@redhat.com> - 3.28.1-3
+- Add a wayland variant of gnome-classic
+  Also change up the names to Standard and Classic to match UX design
+
+  Related: #1612915 1595825
+
+* Tue Aug 21 2018 Carlos Soriano <csoriano@redhat.com> - 3.28.1-2
+- Add desktop icons extension
+
+* Fri Apr 13 2018 Florian Müllner <fmuellner@redhat.com> - 3.28.1-1
+- Update to 3.28.1
+
+* Mon Mar 12 2018 Florian Müllner <fmuellner@redhat.com> - 3.28.0-1
+- Update to 3.28.0
+
+* Mon Mar 05 2018 Florian Müllner <fmuellner@redhat.com> - 3.27.92-1
+- Update to 3.27.92
+
+* Thu Feb 22 2018 Florian Müllner <fmuellner@redhat.com> - 3.27.91-1
+- Update to 3.27.91
+
+* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 3.27.1-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
+
+* Sat Jan 06 2018 Igor Gnatenko <ignatenkobrain@fedoraproject.org> - 3.27.1-2
+- Remove obsolete scriptlets
+
+* Tue Oct 17 2017 Florian Müllner <fmuellner@redhat.com> - 3.27.1-1
+- Update to 3.27.1
+
+* Wed Oct 04 2017 Florian Müllner <fmuellner@redhat.com> - 3.26.1-1
+- Update to 3.26.1
+
+* Tue Sep 12 2017 Florian Müllner <fmuellner@redhat.com> - 3.26.0-1
+- Update to 3.26.0
+
+* Tue Aug 22 2017 Florian Müllner <fmuellner@redhat.com> - 3.25.91-1
+- Update to 3.25.91
+
+* Fri Aug 11 2017 Kevin Fenzi <kevin@scrye.com> - 3.25.90-2
+- Rebuild with older working rpm
+
+* Thu Aug 10 2017 Florian Müllner <fmuellner@redhat.com> - 3.25.90-1
+- Update to 3.25.90
+
+* Wed Jul 26 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3.25.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Thu Jul 20 2017 Florian Müllner <fmuellner@redhat.com> - 3.25.4-1
+- Update to 3.25.4
+
+* Wed Jun 21 2017 Florian Müllner <fmuellner@redhat.com> - 3.25.3-1
+- Update to 3.25.3
+
+* Thu May 25 2017 Florian Müllner <fmuellner@redhat.com> - 3.25.2-1
+- Update to 3.25.2
+
+* Thu Apr 27 2017 Florian Müllner <fmuellner@redhat.com> - 3.25.1-1
+- Update to 3.25.1
+
+* Tue Apr 11 2017 Florian Müllner <fmuellner@redhat.com> - 3.24.1-1
+- Update to 3.24.1
+
+* Mon Mar 20 2017 Florian Müllner <fmuellner@redhat.com> - 3.24.0-1
+- Update to 3.24.0
+
+* Tue Mar 14 2017 Florian Müllner <fmuellner@redhat.com> - 3.23.92-1
+- Update to 3.23.92
+
+* Wed Mar 01 2017 Florian Müllner <fmuellner@redhat.com> - 3.23.91-1
+- Update to 3.23.91
+
+* Thu Feb 16 2017 Florian Müllner <fmuellner@redhat.com> - 3.23.90-1
+- Update to 3.23.90
+
+* Fri Feb 10 2017 Fedora Release Engineering <releng@fedoraproject.org> - 3.23.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Wed Nov 23 2016 Florian Müllner <fmuellner@redhat.com> - 3.23.2-1
+- Update to 3.23.2
+
+* Tue Oct 11 2016 Florian Müllner <fmuellner@redhat.com> - 3.22.1-1
+- Update to 3.22.1
+
+* Mon Sep 19 2016 Florian Müllner <fmuellner@redhat.com> - 3.22.0-1
+- Update to 3.22.0
+
+* Tue Sep 13 2016 Florian Müllner <fmuellner@redhat.com> - 3.21.92-1
+- Update to 3.21.92
+
+* Tue Aug 30 2016 Florian Müllner <fmuellner@redhat.com> - 3.21.91-1
+- Update to 3.21.91
+
+* Fri Aug 19 2016 Florian Müllner <fmuellner@redhat.com> - 3.21.90-1
+- Update to 3.21.90
+
+* Wed Jul 20 2016 Florian Müllner <fmuellner@redhat.com> - 3.21.4-1
+- Update to 3.21.4
+
+* Tue Jun 21 2016 Florian Müllner <fmuellner@redhat.com> - 3.21.3-1
+- Update to 3.21.3
+
+* Fri May 27 2016 Florian Müllner <fmuellner@redhat.com> - 3.21.2-1
+- Update to 3.21.2
+
+* Tue May 10 2016 Florian Müllner <fmuellner@redhat.com> - 3.20.1-1
+- Update to 3.20.1
+
+* Tue Mar 22 2016 Florian Müllner <fmuellner@redhat.com> - 3.20.0-1
+- Update to 3.20.0
+
+* Wed Mar 16 2016 Florian Müllner <fmuellner@redhat.com> - 3.19.92-1
+- Update to 3.19.92
+
+* Thu Mar 03 2016 Florian Müllner <fmuellner@redhat.com> - 3.19.91-1
+- Update to 3.19.91
+
+* Fri Feb 19 2016 Florian Müllner <fmuellner@redhat.com> - 3.19.90-1
+- Update to 3.19.90
+
+* Wed Feb 03 2016 Fedora Release Engineering <releng@fedoraproject.org> - 3.19.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_24_Mass_Rebuild
+
+* Thu Jan 21 2016 Florian Müllner <fmuellner@redhat.com> - 3.19.4-1
+- Update to 3.19.4
+
+* Thu Dec 17 2015 Florian Müllner <fmuellner@redhat.com> - 3.19.3-1
+- Update to 3.19.3
+
+* Wed Nov 25 2015 Florian Müllner <fmuellner@redhat.com> - 3.19.2-1
+- Update to 3.19.2
+
+* Thu Oct 29 2015 Florian Müllner <fmuellner@redhat.com> - 3.19.1-1
+- Update to 3.19.1
+
+* Thu Oct 15 2015 Florian Müllner <fmuellner@redhat.com> - 3.18.1-1
+- Update to 3.18.1
+
+* Mon Sep 21 2015 Florian Müllner <fmuellner@redhat.com> - 3.18.0-1
+- Update to 3.18.0
+
+* Wed Sep 16 2015 Florian Müllner <fmuellner@redhat.com> - 3.17.92-1
+- Update to 3.17.92
+
+* Thu Sep 03 2015 Florian Müllner <fmuellner@redhat.com> - 3.17.91-1
+- Update to 3.17.91
+
+* Thu Aug 20 2015 Florian Müllner <fmuellner@redhat.com> - 3.17.90-1
+- Update to 3.17.90
+
+* Wed Aug 19 2015 Kalev Lember <klember@redhat.com> - 3.17.4-2
+- Don't own /usr/share/gnome-shell/extensions directory: now part of
+  gnome-shell package
+
+* Thu Jul 23 2015 Florian Müllner <fmuellner@redhat.com> - 3.17.4-1
+- Update to 3.17.4
+
+* Thu Jul 02 2015 Florian Müllner <fmuellner@redhat.com> - 3.17.3-1
+- Update to 3.17.3
+
+* Wed Jun 17 2015 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.17.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Wed May 27 2015 Florian Müllner <fmuellner@redhat.com> - 3.17.2-1
+- Update to 3.17.2
+
+* Fri May 01 2015 Kalev Lember <kalevlember@gmail.com> - 3.17.1-2
+- Add glib-compile-schemas rpm scripts for screenshot-window-sizer
+
+* Thu Apr 30 2015 Florian Müllner <fmuellner@redhat.com> - 3.17.1-1
+- Update to 3.17.1
+
+* Tue Apr 14 2015 Florian Müllner <fmuellner@redhat.com> - 3.16.1-1
+- Update to 3.16.1
+
+* Mon Mar 23 2015 Florian Müllner <fmuellner@redhat.com> - 3.16.0-1
+- Update to 3.16.0
+
+* Tue Mar 17 2015 Florian Müllner <fmuellner@redhat.com> - 3.15.92-1
+- Update to 3.15.92
+
+* Thu Mar 05 2015 Kalev Lember <kalevlember@gmail.com> - 3.15.91-2
+- Obsolete the systemMonitor extension that was dropped in 3.15.91
+
+* Thu Mar 05 2015 Florian Müllner <fmuellner@redhat.com> - 3.15.91-1
+- Update to 3.15.91
+
+* Fri Feb 20 2015 Florian Müllner <fmuellner@redhat.com> - 3.15.90-1
+- Update to 3.15.90
+
+* Wed Jan 21 2015 Florian Müllner <fmuellner@redhat.com> - 3.15.4-1
+- Update to 3.15.4
+
+* Fri Dec 19 2014 Florian Müllner <fmuellner@redhat.com> - 3.15.3.1-1
+- Update to 3.15.3.1
+
+* Fri Dec 19 2014 Florian Müllner <fmuellner@redhat.com> - 3.15.3-1
+- Update to 3.15.3
+
+* Thu Nov 27 2014 Florian Müllner <fmuellner@redhat.com> - 3.15.2-1
+- Update to 3.15.2
+
+* Thu Oct 30 2014 Florian Müllner <fmuellner@redhat.com> - 3.15.1-1
+- Update to 3.15.1
+
+* Tue Oct 14 2014 Florian Müllner <fmuellner@redhat.com> - 3.14.1-1
+- Update to 3.14.1
+
+* Mon Sep 22 2014 Florian Müllner <fmuellner@redhat.com> - 3.14.0-1
+- Update to 3.14.0
+
+* Wed Sep 17 2014 Florian Müllner <fmuellner@redhat.com> - 3.13.92-1
+- Update to 3.13.92
+
+* Wed Sep 03 2014 Florian Müllner <fmuellner@redhat.com> - 3.13.91-1
+- Update to 3.13.91
+
+* Wed Aug 20 2014 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.13.90-1
+- Update to 3.13.90
+
+* Thu Jul 24 2014 Kalev Lember <kalevlember@gmail.com> - 3.13.4-1
+- Update to 3.13.4
+
+* Thu Jun 26 2014 Richard Hughes <rhughes@redhat.com> - 3.13.3-1
+- Update to 3.13.3
+
+* Sat Jun 07 2014 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.13.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Wed May 28 2014 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.13.2-1
+- Update to 3.13.2
+
+* Fri May 02 2014 Kalev Lember <kalevlember@gmail.com> - 3.13.1-1
+- Update to 3.13.1
+
+* Tue Mar 25 2014 Richard Hughes <rhughes@redhat.com> - 3.12.0-1
+- Update to 3.12.0
+
+* Thu Mar 20 2014 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.11.92-1
+- Update to 3.11.92
+
+* Thu Mar 06 2014 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.11.91-1
+- Update to 3.11.91
+
+* Thu Feb 20 2014 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.11.90-1
+- Update to 3.11.90
+
+* Wed Feb 05 2014 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.11.5-1
+- Update to 3.11.5
+
+* Mon Feb 03 2014 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.11.4-1
+- Update to 3.11.4
+
+* Sun Dec 22 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.11.3-1
+- Update to 3.11.3
+
+* Wed Nov 13 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.11.2-1
+- Update to 3.11.2
+
+* Wed Oct 16 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.10.1-1
+- Update to 3.10.1
+
+* Tue Sep 24 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.10.0-1
+- Update to 3.10.0
+
+* Tue Sep 17 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.9.92-1
+- Update to 3.9.92
+
+* Tue Sep 03 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.9.91-1
+- Update to 3.9.91
+
+* Thu Aug 22 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.9.90-1
+- Update to 3.9.90
+- Drop xrand-indicator subpackage, no longer provided upstream
+
+* Mon Aug 12 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.9.5-3
+- Fix alternative-status-menu subpackage obsoleting
+
+* Mon Aug 12 2013 Nils Philippsen <nils@redhat.com> - 3.9.5-2
+- obsolete alternative-status-menu subpackage to allow smooth upgrades
+
+* Sun Aug 04 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.9.5-1
+- Update to 3.9.5
+- Drop alternative-status-menu subpackage, no longer provided upstream
+
+* Sat Aug 03 2013 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.9.3-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Thu Jun 20 2013 Rahul Sundaram <sundaram@fedoraproject.org> - 3.9.3-1
+- Update to 3.9.3
+- Obsolete default-min-max and static workspaces extensions
+- Use make_install macro
+- Fix bogus dates in spec changelog
+
+* Tue May 28 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.9.2-1
+- Update to 3.9.2
+
+* Fri May 10 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.9.1-1
+- Update to 3.9.1
+
+* Fri May 10 2013 Kalev Lember <kalevlember@gmail.com> - 3.8.1-3
+- Obsolete gnome-applet-sensors
+
+* Wed May 01 2013 Kalev Lember <kalevlember@gmail.com> - 3.8.1-2
+- Obsolete a few more fallback mode packages
+- Remove gnome-panel provides
+
+* Tue Apr 16 2013 Matthias Clasen <mclasen@redhat.com> - 3.8.1-1
+- Update to 3.8.1
+
+* Tue Mar 26 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.8.0-1
+- Update to 3.8.0
+
+* Tue Mar 19 2013 Ray Strode <rstrode@redhat.com> 3.7.92-1
+- Update to 3.7.92
+
+* Tue Mar 05 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.7.91-1
+- Update to 3.7.91
+
+* Sat Mar 02 2013 Adel Gadllah <adel.gadllah@gmail.com> - 3.7.90-2
+- Obsolete gnome-panel
+
+* Fri Feb 22 2013 Kalev Lember <kalevlember@gmail.com> - 3.7.90-1
+- Update to 3.7.90
+
+* Thu Feb 07 2013 Kalev Lember <kalevlember@gmail.com> - 3.7.5.1-2
+- Depend on gnome-shell 3.7.5, there's no 3.7.5.1
+
+* Thu Feb 07 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.7.5.1-1
+- Update to 3.7.5
+- Enable new launch-new-instance and window-list extensions, and add them in the
+  classic-mode extension set
+- Re-add places-menu in the classic-mode extension set
+
+* Wed Jan 16 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.7.4-1
+- Update to 3.7.4
+- places-menu extension no longer part of the classic-mode extension set
+
+* Tue Jan 01 2013 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.7.3-1
+- Update to 3.7.3
+- Enable new default-min-max and static-workspaces extensions
+- Provide new subpackage gnome-classic-session
+- Revamp summaries and descriptions
+
+* Tue Oct 30 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.7.1-1
+- Update to 3.7.1
+- Drop dock and gajim extensions, no longer provided
+
+* Tue Oct 30 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.6.1-1
+- Update to 3.6.1
+
+* Tue Oct 02 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.6.0-1
+- Update to 3.6.0
+
+* Thu Sep 06 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.5.91-1
+- Update to 3.5.91
+
+* Wed Aug 29 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.5.90-1
+- Update to 3.5.90
+
+* Sat Aug 11 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.5.5-1
+- Update to 3.5.5
+
+* Sun Jul 22 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.5.4-1
+- Update to 3.5.4
+
+* Wed Jul 18 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.5.2-1
+- Update to 3.5.2
+- Drop useless Provides/Obsoletes
+
+* Sat Mar 24 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.4.0-1
+- Update to 3.4.0
+- Minor spec fixes
+
+* Sat Mar 24 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.3.92-1
+- Update to 3.3.92
+
+* Tue Feb 28 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.3.90-1
+- Update to 3.3.90
+
+* Thu Feb 16 2012 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.3.5-1
+- Update to 3.3.5
+- Spec cleanup
+
+* Fri Jan 13 2012 Fedora Release Engineering <rel-eng@lists.fedoraproject.org> - 3.3.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Wed Nov 30 2011 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.3.2-1
+- Update to 3.3.2
+
+* Wed Nov 30 2011 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.2.1-1
+- Update to 3.2.1
+- Fix alternative-status-menu extension crash when login
+
+* Wed Nov 09 2011 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.2.0-2
+- Fix dock and alternate-tab extensions
+- Fix GNOME Shell version to work with GS 3.2.1
+
+* Mon Oct 03 2011 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.2.0-1
+- Update to 3.2.0
+
+* Mon Sep 26 2011 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.1.91-3.20111001gite102c0c6
+- Update to a newer git snapshot
+- Fix GNOME Shell version to work with GS 3.2.0
+- Add Requires on GS 3.2.0 or above to gnome-shell-common
+
+* Wed Sep 14 2011 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.1.91-2
+- Enable xrandr-indicator and workspace-indicator extensions
+
+* Mon Sep 12 2011 Michel Salim <salimma@fedoraproject.org> - 3.1.91-1
+- Update to 3.1.91
+- add more documentation
+
+* Thu Sep  1 2011 Michel Salim <salimma@fedoraproject.org> - 3.1.4-3.20110830git6b5e3a3e
+- Update to git snapshot, for gnome-shell 3.1.90
+
+* Sun Aug 21 2011 Michel Salim <salimma@fedoraproject.org> - 3.1.4-2
+- Enable apps-menu extension
+- Spec cleanup
+
+* Sun Aug 21 2011 Michel Salim <salimma@fedoraproject.org> - 3.1.4-1
+- Update to 3.1.4
+- Enable systemMonitor extension
+- Prepare xrandr-indicator, commenting out since it does not seem to work yet
+- Rename subpackages in line with new guidelines (# 715367)
+- Sort subpackages in alphabetical order
+
+* Sat May 28 2011 Timur Kristóf <venemo@fedoraproject.org> - 3.0.2-1.g63dd27cgit
+- Update to a newer git snapshot
+- Fix RHBZ bug #708230
+- Enabled systemMonitor extension, but commented out since the requirements are not available
+
+* Fri May 13 2011 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.0.1-3.03660fgit
+- Update to a newer git snapshot
+- Enable native-window-placement extension
+
+* Fri May 06 2011 Rahul Sundaram <sundaram@fedoraproject.org> - 3.0.1-2b20cbagit
+- Fix description 
+
+* Thu May 5 2011 Elad Alfassa <elad@fedoraproject.org> - 3.0.1-1.b20cbagit
+- Update to a newer git snapshot
+- Enabled the places-menu extension
+
+* Tue Apr 26 2011 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.0.1-1.f016b9git
+- Update to a newer git snapshot (post-3.0.1 release)
+- Enable drive-menu extension
+
+* Mon Apr 11 2011 Mohamed El Morabity <melmorabity@fedoraproject.org> - 3.0.0-5.6d56cfgit
+- Enable auto-move-windows extension
+
+* Mon Apr 11 2011 Rahul Sundaram <sundaram@fedoraproject.org>  - 3.0.0-4.6d56cfgit
+- Add glib2-devel as build requires
+
+* Mon Apr 11 2011 Rahul Sundaram <sundaram@fedoraproject.org>  - 3.0.0-3.6d56cfgit
+- Tweak description
+- Fix typo in configure
+
+* Mon Apr 11 2011 Rahul Sundaram <sundaram@fedoraproject.org>  - 3.0.0-2.6d56cfgit
+- Added the user-theme extension
+- Patch from Timur Kristóf <venemo@msn.com>
+
+* Fri Apr 08 2011 Rahul Sundaram <sundaram@fedoraproject.org> - 3.0.0-1.6d56cfgit
+- Make sure configure doesn't get called twice
+
+* Fri Apr 08 2011 Rahul Sundaram <sundaram@fedoraproject.org> - 3.0.0-0.6d56cfgit
+- Initial build