File gse-sle-classic-ext.patch of Package gnome-shell-extensions.3493

diff --git a/data/gnome-classic.css b/sp2-rebasing/gnome-shell-extensions-3.20.0/data/gnome-classic.css
index 7e1b253..80333e2 100644
--- a/data/gnome-classic.css
+++ b/data/gnome-classic.css
@@ -441,7 +441,12 @@ StScrollBar {
       color: rgba(46, 52, 54, 0.5); }
   .popup-menu.panel-menu {
     -boxpointer-gap: 4px;
-    margin-bottom: 1.75em; }
+    /* TODO was 1.75em, no idea of its use  */
+    /* NOTE: the following creates an ugly gap between menu and its source actor
+when the PanelMenu's source actor is at the bottom. Preferrably for bottom menu,
+`margin-top` might be a better choice. However, since we have no idea about its
+use so reset to 0 for now. */
+    margin-bottom: 0em; }
 
 .popup-menu-ornament {
   text-align: right;
 diff -pur a/extensions/window-list/classic.css b/extensions/window-list/classic.css
--- a/extensions/window-list/classic.css	2016-05-23 16:41:51.603370114 +0800
+++ b/extensions/window-list/classic.css	2016-05-23 16:44:37.024370114 +0800
@@ -6,7 +6,7 @@
     height: 2.25em ;
   }
 
-  .bottom-panel .window-button > StWidget {
+ .window-button > StWidget {
     background-gradient-drection: vertical;
     background-color: #fff;
     background-gradient-start: #fff;
@@ -22,29 +22,29 @@
     text-shadow: 0 0 transparent;
   }
 
-  .bottom-panel .window-button:hover > StWidget {
+ .window-button:hover > StWidget {
     background-color: #f9f9f9;
   }
 
-  .bottom-panel .window-button:active > StWidget,
-  .bottom-panel .window-button:focus > StWidget {
+ .window-button:active > StWidget,
+ .window-button:focus > StWidget {
     box-shadow: inset 1px 1px 2px rgba(0,0,0,0.5);
   }
 
-  .bottom-panel .window-button.focused > StWidget {
+ .window-button.focused > StWidget {
     background-color: #ddd;
     box-shadow: inset 1px 1px 1px rgba(0,0,0,0.5);
   }
 
-  .bottom-panel .window-button.focused:hover > StWidget {
+ .window-button.focused:hover > StWidget {
     background-color: #e9e9e9;
   }
 
-  .bottom-panel .window-button.minimized > StWidget {
+ .window-button.minimized > StWidget {
     color: #888;
     box-shadow: inset -1px -1px 1px rgba(0,0,0,0.5);
   }
 
-  .bottom-panel .window-button.minimized > StWidget {
+ .window-button.minimized > StWidget {
     box-shadow: inset 1px 1px 1px rgba(0,0,0,0.5);
   }

diff --git a/extensions/window-list/extension.js b/sp2-rebasing/gnome-shell-extensions-3.20.0/extensions/window-list/extension.js
index bdd4680..2419547 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -22,6 +22,8 @@ const _ = Gettext.gettext;
 const ICON_TEXTURE_SIZE = 24;
 const DND_ACTIVATE_TIMEOUT = 500;
 
+const SLEClassicExt = imports.ui.SLEClassicExt;
+
 const GroupingMode = {
     NEVER: 0,
     AUTO: 1,
@@ -64,6 +66,9 @@ function _getAppStableSequence(app) {
 }
 
 
+// TODO: not critical, but with `gnome-shell -r` there are `St-CRITICAL` errors
+// shown in stdout, 3 warnings for each existing window. Wrong initialization
+// order?
 const WindowContextMenu = new Lang.Class({
     Name: 'WindowContextMenu',
     Extends: PopupMenu.PopupMenu,
@@ -113,6 +118,9 @@ const WindowContextMenu = new Lang.Class({
         }));
         this.addMenuItem(item);
 
+        // NOTE add `-boxpointer-gap` to the menu, to align with `PanelMenu`,
+        // totally optional.
+        this.actor.add_style_class_name('bottom-panel-menu');
         this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
     },
 
@@ -661,6 +669,8 @@ const WorkspaceIndicator = new Lang.Class({
         this.parent(0.0, _("Workspace Indicator"), true);
         this.setMenu(new PopupMenu.PopupMenu(this.actor, 0.0, St.Side.BOTTOM));
         this.actor.add_style_class_name('window-list-workspace-indicator');
+        // NOTE: add `-boxpointer-gap`, totally optional
+        this.menu.actor.add_style_class_name('bottom-panel-menu');
         this.menu.actor.remove_style_class_name('panel-menu');
 
         let container = new St.Widget({ layout_manager: new Clutter.BinLayout(),
@@ -765,199 +775,143 @@ const WorkspaceIndicator = new Lang.Class({
     }
 });
 
-const WindowList = new Lang.Class({
-    Name: 'WindowList',
+// NOTE: call `initializeWindowList` explicitly to finish initialization.
+const PureWinList = new Lang.Class({
+    Name: 'PureWinList',
 
-    _init: function(perMonitor, monitor) {
+    _init: function(perMonitor, monitor, maxWidthFunc) {
+        // NOTE: in SLE Classic `PureWinList` will NOT use any multiple monitor
+        // support, the following is kept for use in GNOME Classic as we try to
+        // unify code for two sides.
         this._perMonitor = perMonitor;
         this._monitor = monitor;
+        // NOTE: callback function given by the employer of this PureWinList.
+        // Since PureWinList can be used various widgets hierarchy, we have to
+        // leave the calculation of max available width to the employer.
+        this._getMaxWindowListWidth = maxWidthFunc;
 
-        this.actor = new St.Widget({ name: 'panel',
-                                     style_class: 'bottom-panel',
+        let layout = new Clutter.BoxLayout({ homogeneous: true });
+        this.actor = new St.Widget({ style_class: 'window-list',
                                      reactive: true,
-                                     track_hover: true,
-                                     layout_manager: new Clutter.BinLayout()});
+                                     layout_manager: layout,
+                                     x_align: Clutter.ActorAlign.START,
+                                     x_expand: true,
+                                     y_expand: true });
+
+        this.actor.connect('style-changed', Lang.bind(this, function() {
+            let node = this.actor.get_theme_node();
+            let spacing = node.get_length('spacing');
+            this.actor.layout_manager.spacing = spacing;
+        }));
+        this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
         this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 
-        let box = new St.BoxLayout({ x_expand: true, y_expand: true });
-        this.actor.add_actor(box);
-
-        let layout = new Clutter.BoxLayout({ homogeneous: true });
-        this._windowList = new St.Widget({ style_class: 'window-list',
-                                           reactive: true,
-                                           layout_manager: layout,
-                                           x_align: Clutter.ActorAlign.START,
-                                           x_expand: true,
-                                           y_expand: true });
-        box.add(this._windowList, { expand: true });
-
-        this._windowList.connect('style-changed', Lang.bind(this,
-            function() {
-                let node = this._windowList.get_theme_node();
-                let spacing = node.get_length('spacing');
-                this._windowList.layout_manager.spacing = spacing;
-            }));
-        this._windowList.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
-
-        let indicatorsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.END });
-        box.add(indicatorsBox);
-
-        this._workspaceIndicator = new WorkspaceIndicator();
-        indicatorsBox.add(this._workspaceIndicator.container, { expand: false, y_fill: true });
-
-        this._workspaceSettings = this._getWorkspaceSettings();
-        this._workspacesOnlyOnPrimaryChangedId =
-            this._workspaceSettings.connect('changed::workspaces-only-on-primary',
-                                            Lang.bind(this, this._updateWorkspaceIndicatorVisibility));
-        this._updateWorkspaceIndicatorVisibility();
-
-        this._menuManager = new PopupMenu.PopupMenuManager(this);
-        this._menuManager.addMenu(this._workspaceIndicator.menu);
-
-        Main.layoutManager.addChrome(this.actor, { affectsStruts: true,
-                                                   trackFullscreen: true });
-        Main.uiGroup.set_child_above_sibling(this.actor, Main.layoutManager.panelBox);
-        Main.ctrlAltTabManager.addGroup(this.actor, _("Window List"), 'start-here-symbolic');
-
-        this.actor.width = this._monitor.width;
-        this.actor.connect('notify::height', Lang.bind(this, this._updatePosition));
-        this._updatePosition();
-
         this._appSystem = Shell.AppSystem.get_default();
         this._appStateChangedId =
             this._appSystem.connect('app-state-changed',
                                     Lang.bind(this, this._onAppStateChanged));
 
-        this._keyboardVisiblechangedId =
-            Main.layoutManager.connect('keyboard-visible-changed',
-                Lang.bind(this, function(o, state) {
-                    Main.layoutManager.keyboardBox.visible = state;
-                    let keyboardBox = Main.layoutManager.keyboardBox;
-                    keyboardBox.visible = state;
-                    if (state)
-                        Main.uiGroup.set_child_above_sibling(this.actor, keyboardBox);
-                    else
-                        Main.uiGroup.set_child_above_sibling(this.actor,
-                                                             Main.layoutManager.panelBox);
-                    this._updateKeyboardAnchor();
-                }));
+        this._settings = Convenience.getSettings();
 
+        // Grouping
+        this._groupingModeChangedId =
+            this._settings.connect('changed::grouping-mode',
+                                   Lang.bind(this, this._groupingModeChanged));
+        this._grouped = undefined;
+        // NOTE: do NOT `_checkGrouping` here
+
+        // workspace related
         this._workspaceSignals = new Map();
         this._nWorkspacesChangedId =
             global.screen.connect('notify::n-workspaces',
                                   Lang.bind(this, this._onWorkspacesChanged));
         this._onWorkspacesChanged();
-
         this._switchWorkspaceId =
             global.window_manager.connect('switch-workspace',
                                           Lang.bind(this, this._checkGrouping));
 
+        // Hide and Show with Overview
         this._overviewShowingId =
             Main.overview.connect('showing', Lang.bind(this, function() {
                 this.actor.hide();
-                this._updateKeyboardAnchor();
             }));
-
         this._overviewHidingId =
             Main.overview.connect('hiding', Lang.bind(this, function() {
-                this.actor.visible = !Main.layoutManager.primaryMonitor.inFullscreen;
-                this._updateKeyboardAnchor();
+                this.actor.show();
             }));
-
-        this._fullscreenChangedId =
-            global.screen.connect('in-fullscreen-changed', Lang.bind(this, function() {
-                this._updateKeyboardAnchor();
-            }));
-
-        this._dragBeginId =
-            Main.xdndHandler.connect('drag-begin',
-                                     Lang.bind(this, this._onDragBegin));
-        this._dragEndId =
-            Main.xdndHandler.connect('drag-end',
-                                     Lang.bind(this, this._onDragEnd));
-        this._dragMonitor = {
-            dragMotion: Lang.bind(this, this._onDragMotion)
-        };
-
-        this._dndTimeoutId = 0;
-        this._dndWindow = null;
-
-        this._settings = Convenience.getSettings();
-        this._groupingModeChangedId =
-            this._settings.connect('changed::grouping-mode',
-                                   Lang.bind(this, this._groupingModeChanged));
-        this._grouped = undefined;
-        this._groupingModeChanged();
     },
 
-    _getWorkspaceSettings: function() {
-        let settings = global.get_overrides_settings();
-        if (settings.list_keys().indexOf('workspaces-only-on-primary') > -1)
-            return settings;
-        return new Gio.Settings({ schema_id: 'org.gnome.mutter' });
+    // NOTE: an API for parent panel to refresh the window list. This is
+    // necessary as window/app buttons require its parents having allocation and
+    // positioning *completed* before being properly allocated and positioned
+    initializeWindowList: function() {
+        this._groupingModeChanged();
     },
 
+    // NOTE: support scrolling in window list s.t. scrolling activate window
+    // buttons sequentially.
+    //
+    // *Code is rewritten*.
     _onScrollEvent: function(actor, event) {
         let direction = event.get_scroll_direction();
         let diff = 0;
-        if (direction == Clutter.ScrollDirection.DOWN)
+        if (direction === Clutter.ScrollDirection.DOWN)
             diff = 1;
-        else if (direction == Clutter.ScrollDirection.UP)
+        else if (direction === Clutter.ScrollDirection.UP)
             diff = -1;
         else
             return;
 
-        let children = this._windowList.get_children().map(function(actor) {
+        let buttons = this.actor.get_children().map(function(actor) {
             return actor._delegate;
         });
-        let active = 0;
-        for (let i = 0; i < children.length; i++) {
-            if (children[i].active) {
-                active = i;
+        let totalBtnNum = buttons.length;
+
+        let activeBtnIdx = 0;
+        for (let i = 0; i < totalBtnNum; i++) {
+            if (buttons[i].active) {
+                activeBtnIdx = i;
                 break;
             }
         }
 
-        active = Math.max(0, Math.min(active + diff, children.length-1));
-        children[active].activate();
-    },
-
-    _updatePosition: function() {
-        this.actor.set_position(this._monitor.x,
-                                this._monitor.y + this._monitor.height - this.actor.height);
-    },
+        // NOTE: bound by `0` and `totalBtnNum - 1`, no wrapping for
+        // scrolling.
+        activeBtnIdx = activeBtnIdx + diff;
+        let noScrollActionNeeded = ( (activeBtnIdx < 0) || (activeBtnIdx >= totalBtnNum) );
+        if (noScrollActionNeeded)
+            return;
 
-    _updateWorkspaceIndicatorVisibility: function() {
-        this._workspaceIndicator.actor.visible =
-            this._monitor == Main.layoutManager.primaryMonitor ||
-            !this._workspaceSettings.get_boolean('workspaces-only-on-primary');
+        // TODO: no need to call `deactivate` for old `active button` ?
+        buttons[activeBtnIdx].activate();
     },
 
-    _getPreferredUngroupedWindowListWidth: function() {
-        if (this._windowList.get_n_children() == 0)
-            return this._windowList.get_preferred_width(-1)[1];
-
-        let children = this._windowList.get_children();
-        let [, childWidth] = children[0].get_preferred_width(-1);
-        let spacing = this._windowList.layout_manager.spacing;
+    _onAppStateChanged: function(appSys, app) {
+        if (!this._grouped)
+            return;
 
-        let workspace = global.screen.get_active_workspace();
-        let windows = global.display.get_tab_list(Meta.TabList.NORMAL, workspace);
-        if (this._perMonitor) {
-            windows = windows.filter(Lang.bind(this, function(window) {
-                return window.get_monitor() == this._monitor.index;
-            }));
-        }
-        let nWindows = windows.length;
-        if (nWindows == 0)
-            return this._windowList.get_preferred_width(-1)[1];
+        if (app.state == Shell.AppState.RUNNING)
+            this._addApp(app);
+        else if (app.state == Shell.AppState.STOPPED)
+            this._removeApp(app);
+    },
 
-        return nWindows * childWidth + (nWindows - 1) * spacing;
+    _addApp: function(app) {
+        let button = new AppButton(app, this._perMonitor, this._monitor.index);
+        this.actor.layout_manager.pack(button.actor,
+                                       true, true, true,
+                                       Clutter.BoxAlignment.START,
+                                       Clutter.BoxAlignment.START);
     },
 
-    _getMaxWindowListWidth: function() {
-        let indicatorsBox = this._workspaceIndicator.actor.get_parent();
-        return this.actor.width - indicatorsBox.get_preferred_width(-1)[1];
+    _removeApp: function(app) {
+        let children = this.actor.get_children();
+        for (let i = 0; i < children.length; i++) {
+            if (children[i]._delegate.app === app) {
+                children[i].destroy();
+                return;
+            }
+        }
     },
 
     _groupingModeChanged: function() {
@@ -966,7 +920,7 @@ const WindowList = new Lang.Class({
         if (this._groupingMode == GroupingMode.AUTO) {
             this._checkGrouping();
         } else {
-            this._grouped = this._groupingMode == GroupingMode.ALWAYS;
+            this._grouped = ( this._groupingMode === GroupingMode.ALWAYS );
             this._populateWindowList();
         }
     },
@@ -975,6 +929,26 @@ const WindowList = new Lang.Class({
         if (this._groupingMode != GroupingMode.AUTO)
             return;
 
+        // TODO `_getMaxWindowListWidth` is known to depend on parent
+        // conditions. However the following call seems to get the right parent
+        // value. So an option to avoid timing issue is to use the following
+        // callback.
+        //
+        // this.actor.connect('allocation-changed', () => {
+        //     log('parent width: ' + this.actor.get_parent().width);
+        // });
+        //
+        // The legitimacy can be explained in the (guessed) algorithm of
+        // allocation: Bubble up then propagate down (like DOM Events?). In
+        // details: changes that would alter the geometric properties of a
+        // widget would trigger a re-allocation to its parent AFTER some initial
+        // allocation calculation of its own (for queries like
+        // `_get_preferred_width` work for its parents). The `re-allocation`
+        // would bubble up the widget hierarchy till one widget stops it (e.g. a
+        // widget that has fixed size and absolute positioning and thus it does
+        // not need to send re-allocation request up.). Then the re-allocation
+        // signal is sent down to its origin. (downward propagation is necessary
+        // as much of the positioning and allocation depends on one's parent)
         let maxWidth = this._getMaxWindowListWidth();
         let natWidth = this._getPreferredUngroupedWindowListWidth();
 
@@ -986,7 +960,7 @@ const WindowList = new Lang.Class({
     },
 
     _populateWindowList: function() {
-        this._windowList.destroy_all_children();
+        this.actor.destroy_all_children();
 
         if (!this._grouped) {
             let windows = global.get_window_actors().sort(
@@ -1007,42 +981,8 @@ const WindowList = new Lang.Class({
         }
     },
 
-    _updateKeyboardAnchor: function() {
-        if (!Main.keyboard.actor)
-            return;
-
-        let anchorY = Main.overview.visible ? 0 : this.actor.height;
-        Main.keyboard.actor.anchor_y = anchorY;
-    },
-
-    _onAppStateChanged: function(appSys, app) {
-        if (!this._grouped)
-            return;
-
-        if (app.state == Shell.AppState.RUNNING)
-            this._addApp(app);
-        else if (app.state == Shell.AppState.STOPPED)
-            this._removeApp(app);
-    },
-
-    _addApp: function(app) {
-        let button = new AppButton(app, this._perMonitor, this._monitor.index);
-        this._windowList.layout_manager.pack(button.actor,
-                                             true, true, true,
-                                             Clutter.BoxAlignment.START,
-                                             Clutter.BoxAlignment.START);
-    },
-
-    _removeApp: function(app) {
-        let children = this._windowList.get_children();
-        for (let i = 0; i < children.length; i++) {
-            if (children[i]._delegate.app == app) {
-                children[i].destroy();
-                return;
-            }
-        }
-    },
-
+    // NOTE the `ws` params in the following two are not used (necessarily be
+    // here as the event handler Interface dictates).
     _onWindowAdded: function(ws, win) {
         if (win.skip_taskbar)
             return;
@@ -1053,30 +993,32 @@ const WindowList = new Lang.Class({
         if (this._grouped)
             return;
 
-        let children = this._windowList.get_children();
+        let children = this.actor.get_children();
         for (let i = 0; i < children.length; i++) {
             if (children[i]._delegate.metaWindow == win)
                 return;
         }
 
         let button = new WindowButton(win, this._perMonitor, this._monitor.index);
-        this._windowList.layout_manager.pack(button.actor,
-                                             true, true, true,
-                                             Clutter.BoxAlignment.START,
-                                             Clutter.BoxAlignment.START);
+        this.actor.layout_manager.pack(button.actor,
+                                       true, true, true,
+                                       Clutter.BoxAlignment.START,
+                                       Clutter.BoxAlignment.START);
     },
 
     _onWindowRemoved: function(ws, win) {
         if (this._grouped)
             this._checkGrouping();
 
+        // NOTE: if it's still grouped after `checking`, do nothing, window
+        // removal is managed by `AppButton` anyway.
         if (this._grouped)
             return;
 
         if (win.get_compositor_private())
             return; // not actually removed, just moved to another workspace
 
-        let children = this._windowList.get_children();
+        let children = this.actor.get_children();
         for (let i = 0; i < children.length; i++) {
             if (children[i]._delegate.metaWindow == win) {
                 children[i].destroy();
@@ -1085,6 +1027,28 @@ const WindowList = new Lang.Class({
         }
     },
 
+    _getPreferredUngroupedWindowListWidth: function() {
+        if (this.actor.get_n_children() == 0)
+            return this.actor.get_preferred_width(-1)[1];
+
+        let children = this.actor.get_children();
+        let [, childWidth] = children[0].get_preferred_width(-1);
+        let spacing = this.actor.layout_manager.spacing;
+
+        let workspace = global.screen.get_active_workspace();
+        let windows = global.display.get_tab_list(Meta.TabList.NORMAL, workspace);
+        if (this._perMonitor) {
+            windows = windows.filter(Lang.bind(this, function(window) {
+                return window.get_monitor() == this._monitor.index;
+            }));
+        }
+        let nWindows = windows.length;
+        if (nWindows == 0)
+            return this.actor.get_preferred_width(-1)[1];
+
+        return nWindows * childWidth + (nWindows - 1) * spacing;
+    },
+
     _onWorkspacesChanged: function() {
         let numWorkspaces = global.screen.n_workspaces;
         for (let i = 0; i < numWorkspaces; i++) {
@@ -1114,6 +1078,157 @@ const WindowList = new Lang.Class({
         }
     },
 
+    _onDestroy: function() {
+        Main.overview.disconnect(this._overviewHidingId);
+        this._overviewHidingId = 0;
+        Main.overview.disconnect(this._overviewShowingId);
+        this._overviewShowingId = 0;
+
+        global.screen.disconnect(this._nWorkspacesChangedId);
+        this._nWorkspacesChangedId = 0;
+        global.window_manager.disconnect(this._switchWorkspaceId);
+        this._switchWorkspaceId = 0;
+        this._disconnectWorkspaceSignals();
+
+        this._settings.disconnect(this._groupingModeChangedId);
+        this._groupingModeChangedId = 0;
+
+        this._appSystem.disconnect(this._appStateChangedId);
+        this._appStateChangedId = 0;
+
+        let windows = global.get_window_actors();
+        for (let i = 0; i < windows.length; i++)
+            windows[i].metaWindow.set_icon_geometry(null);
+    }
+});
+
+// NOTE: the following so-called `WindowList` is actually a bottom panel. The
+// "list of windows" part is going to be factored out into `PureWinList`,
+// specially designed to adapt this extension for use with `SLE-Classic` mode.
+const WindowList = new Lang.Class({
+    Name: 'WindowList',
+
+    _init: function(perMonitor, monitor) {
+        this._perMonitor = perMonitor;
+        this._monitor = monitor;
+
+        this.actor = new St.Widget({ name: 'panel',
+                                     style_class: 'bottom-panel',
+                                     reactive: true,
+                                     track_hover: true,
+                                     layout_manager: new Clutter.BinLayout()});
+        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+
+        let box = new St.BoxLayout({ x_expand: true, y_expand: true });
+        this.actor.add_actor(box);
+
+        let maxWinListWidthFunc = () => {
+            let indicatorsBox = this._workspaceIndicator.actor.get_parent();
+            return this.actor.width - indicatorsBox.get_preferred_width(-1)[1];
+        };
+        this._windowList = new PureWinList(perMonitor, monitor, maxWinListWidthFunc);
+        box.add(this._windowList.actor, { expand: true });
+        let _windowListInitId = this.actor.connect('allocation-changed',
+                                                   () => {
+                                                       this._windowList.initializeWindowList();
+                                                       this.actor.disconnect(_windowListInitId);
+                                                   });
+
+        let indicatorsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.END });
+        box.add(indicatorsBox);
+        this._workspaceIndicator = new WorkspaceIndicator();
+        indicatorsBox.add(this._workspaceIndicator.container, { expand: false, y_fill: true });
+
+        this._workspaceSettings = this._getWorkspaceSettings();
+        this._workspacesOnlyOnPrimaryChangedId =
+            this._workspaceSettings.connect('changed::workspaces-only-on-primary',
+                                            Lang.bind(this, this._updateWorkspaceIndicatorVisibility));
+        this._updateWorkspaceIndicatorVisibility();
+
+        this._menuManager = new PopupMenu.PopupMenuManager(this);
+        this._menuManager.addMenu(this._workspaceIndicator.menu);
+
+        Main.layoutManager.addChrome(this.actor, { affectsStruts: true,
+                                                   trackFullscreen: true });
+        Main.uiGroup.set_child_above_sibling(this.actor, Main.layoutManager.panelBox);
+        Main.ctrlAltTabManager.addGroup(this.actor, _("Window List"), 'start-here-symbolic');
+
+        this.actor.width = this._monitor.width;
+        this.actor.connect('notify::height', Lang.bind(this, this._updatePosition));
+        this._updatePosition();
+
+        this._keyboardVisiblechangedId =
+            Main.layoutManager.connect('keyboard-visible-changed',
+                Lang.bind(this, function(o, state) {
+                    Main.layoutManager.keyboardBox.visible = state;
+                    let keyboardBox = Main.layoutManager.keyboardBox;
+                    keyboardBox.visible = state;
+                    if (state)
+                        Main.uiGroup.set_child_above_sibling(this.actor, keyboardBox);
+                    else
+                        Main.uiGroup.set_child_above_sibling(this.actor,
+                                                             Main.layoutManager.panelBox);
+                    this._updateKeyboardAnchor();
+                }));
+
+        this._overviewShowingId =
+            Main.overview.connect('showing', Lang.bind(this, function() {
+                this.actor.hide();
+                this._updateKeyboardAnchor();
+            }));
+
+        this._overviewHidingId =
+            Main.overview.connect('hiding', Lang.bind(this, function() {
+                this.actor.visible = !Main.layoutManager.primaryMonitor.inFullscreen;
+                this._updateKeyboardAnchor();
+            }));
+
+        this._fullscreenChangedId =
+            global.screen.connect('in-fullscreen-changed', Lang.bind(this, function() {
+                this._updateKeyboardAnchor();
+            }));
+
+        this._dragBeginId =
+            Main.xdndHandler.connect('drag-begin',
+                                     Lang.bind(this, this._onDragBegin));
+        this._dragEndId =
+            Main.xdndHandler.connect('drag-end',
+                                     Lang.bind(this, this._onDragEnd));
+        this._dragMonitor = {
+            dragMotion: Lang.bind(this, this._onDragMotion)
+        };
+
+        this._dndTimeoutId = 0;
+        this._dndWindow = null;
+    },
+
+    _getWorkspaceSettings: function() {
+        let settings = global.get_overrides_settings();
+        if (settings.list_keys().indexOf('workspaces-only-on-primary') > -1)
+            return settings;
+        return new Gio.Settings({ schema_id: 'org.gnome.mutter' });
+    },
+
+    _updatePosition: function() {
+        this.actor.set_position(this._monitor.x,
+                                this._monitor.y + this._monitor.height - this.actor.height);
+    },
+
+    _updateWorkspaceIndicatorVisibility: function() {
+        this._workspaceIndicator.actor.visible =
+            this._monitor == Main.layoutManager.primaryMonitor ||
+            !this._workspaceSettings.get_boolean('workspaces-only-on-primary');
+    },
+
+
+    _updateKeyboardAnchor: function() {
+        if (!Main.keyboard.actor)
+            return;
+
+        let anchorY = Main.overview.visible ? 0 : this.actor.height;
+        Main.keyboard.actor.anchor_y = anchorY;
+    },
+
     _onDragBegin: function() {
         DND.addDragMonitor(this._dragMonitor);
     },
@@ -1174,22 +1289,11 @@ const WindowList = new Lang.Class({
 
         Main.ctrlAltTabManager.removeGroup(this.actor);
 
-        this._appSystem.disconnect(this._appStateChangedId);
-        this._appStateChangedId = 0;
-
         Main.layoutManager.disconnect(this._keyboardVisiblechangedId);
         this._keyboardVisiblechangedId = 0;
 
         Main.layoutManager.hideKeyboard();
 
-        this._disconnectWorkspaceSignals();
-        global.screen.disconnect(this._nWorkspacesChangedId);
-        this._nWorkspacesChangedId = 0;
-
-        global.window_manager.disconnect(this._switchWorkspaceId);
-        this._switchWorkspaceId = 0;
-
-
         Main.overview.disconnect(this._overviewShowingId);
         Main.overview.disconnect(this._overviewHidingId);
 
@@ -1197,12 +1301,6 @@ const WindowList = new Lang.Class({
 
         Main.xdndHandler.disconnect(this._dragBeginId);
         Main.xdndHandler.disconnect(this._dragEndId);
-
-        this._settings.disconnect(this._groupingModeChangedId);
-
-        let windows = global.get_window_actors();
-        for (let i = 0; i < windows.length; i++)
-            windows[i].metaWindow.set_icon_geometry(null);
     }
 });
 
@@ -1211,7 +1309,6 @@ const Extension = new Lang.Class({
 
     _init: function() {
         this._windowLists = null;
-        this._injections = {};
     },
 
     enable: function() {
@@ -1267,6 +1364,63 @@ const Extension = new Lang.Class({
     }
 });
 
+const SCExtension = new Lang.Class({
+    Name: 'SCExtension',
+    _init: function() {
+        this._pureWinList = null;
+    },
+
+    enable: function() {
+        // NOTE For SLE Classic, a window list is shown on Main panel ONLY
+        let showOnAllMonitors = false;
+        // NOTE Use a guessed value passed to `PureWinList` as `checkGrouping`
+        // is run at a time the allocation of the panel boxes might not complete
+        // yet (and thus we get almost random width value). The other options
+        // are to duplicate the centerbox width calculation or change the order
+        // of grouping check code (way more complicated).
+        //
+        // This value is guessed *conservatively*. Further this value is used by
+        // AUTO grouping only.
+        //
+        // NOTE: no Promise is available
+        let panelCenterBoxWidth = Main.panel.actor.width * 0.8;
+
+        this._pureWinList = new PureWinList(showOnAllMonitors,
+                                            Main.layoutManager.primaryMonitor,
+                                            () => panelCenterBoxWidth );
+        Main.panel._centerBox.add(this._pureWinList.actor, {expand: true});
+        let _winListRefreshId = Main.panel._centerBox.connect(
+            'allocation-changed',
+            () => {
+                this._pureWinList.initializeWindowList();
+                Main.panel._centerBox.disconnect(_winListRefreshId);
+            });
+        // NOTE: IMO, no need to rebuild `_pureWinList` when monitors changed.
+        // No need for `showOnAllMonitors` change either even this option
+        // changes.
+    },
+
+    disable: function() {
+        if (!this._pureWinList)
+            return;
+
+        this._pureWinList.actor.hide();
+        this._pureWinList.actor.destroy();
+
+        this._pureWinList = null;
+    },
+
+    // NOTE: this function is used for multiple window list situations, invalid for SCExtension case, let's return false.
+    someWindowListContains: function(actor) {
+        return false;
+    }
+});
+
 function init() {
-    return new Extension();
+    if ( SLEClassicExt.isSLEClassicMode() ){
+        return new SCExtension();
+    }
+    else {
+        return new Extension();
+    }
 }
diff --git a/extensions/window-list/stylesheet.css b/sp2-rebasing/gnome-shell-extensions-3.20.0/extensions/window-list/stylesheet.css
index f5285cb..c207078 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -79,6 +79,10 @@
   border: 1px solid #cccccc;
 }
 
+.bottom-panel-menu {
+  -boxpointer-gap: 4px;
+}
+
 .notification {
   font-weight: normal;
 }
openSUSE Build Service is sponsored by