Index: gnome-shell-extensions-3.26.0/data/gnome-classic.css =================================================================== --- gnome-shell-extensions-3.26.0.orig/data/gnome-classic.css +++ gnome-shell-extensions-3.26.0/data/gnome-classic.css @@ -500,7 +500,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; @@ -691,8 +696,7 @@ StScrollBar { margin-right: 4px; } #panel .panel-button .system-status-icon, #panel .panel-button .app-menu-icon > StIcon, - #panel .panel-button .popup-menu-arrow { - icon-shadow: 0px 0px 2px rgba(0, 0, 0, 0.9); } + #panel .panel-button .popup-menu-arrow {} #panel .panel-button:hover { color: #454f52; text-shadow: 0px 0px 8px black; } @@ -901,6 +905,7 @@ StScrollBar { width: 31.5em; } .message-list-clear-button.button { + color: black; background-color: transparent; margin: 1.5em 1.5em 0; } .message-list-clear-button.button:hover, .message-list-clear-button.button:focus { @@ -924,7 +929,6 @@ StScrollBar { padding: 10px 10px 10px 3px; } .message-icon-bin > StIcon { - color: black; icon-size: 16px; -st-icon-style: symbolic; } @@ -941,11 +945,9 @@ StScrollBar { .message-secondary-bin > StIcon { icon-size: 16px; } -.message-title { - color: #222728; } +.message-title {} .message-content { - color: black; padding: 10px; } .message-media-control { @@ -1882,8 +1884,6 @@ StScrollBar { #panel { font-weight: normal; background-color: #ededed !important; - background-gradient-direction: vertical; - background-gradient-end: #e0e0e0; border-top-color: #666; /* we don't support non-uniform border-colors and use the top border color for any border, so we @@ -1912,8 +1912,6 @@ StScrollBar { icon-shadow: none; } #panel .panel-button:hover { text-shadow: none; } - #panel .panel-button:hover .system-status-icon { - icon-shadow: none; } #panel .panel-button .app-menu-icon { width: 0; height: 0; @@ -1924,12 +1922,10 @@ StScrollBar { #panel .panel-corner:focus { -panel-corner-radius: 0; } #panel.lock-screen, #panel.unlock-screen, #panel.login-screen { - background-color: rgba(46, 52, 54, 0.5); - background-gradient-start: rgba(46, 52, 54, 0.5); - background-gradient-end: rgba(46, 52, 54, 0.5); + background-color: transparent !important; border-bottom: none; } #panel.lock-screen .panel-button, #panel.unlock-screen .panel-button, #panel.login-screen .panel-button { - color: #eeeeec; } + color: #eeeeec !important; } #panel .popup-menu-arrow { width: 0; height: 0; } Index: gnome-shell-extensions-3.26.0/extensions/window-list/classic.css =================================================================== --- gnome-shell-extensions-3.26.0.orig/extensions/window-list/classic.css +++ gnome-shell-extensions-3.26.0/extensions/window-list/classic.css @@ -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,25 +22,25 @@ 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); } Index: gnome-shell-extensions-3.26.0/extensions/window-list/extension.js =================================================================== --- gnome-shell-extensions-3.26.0.orig/extensions/window-list/extension.js +++ gnome-shell-extensions-3.26.0/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(this._closeItem); + // 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)); this.connect('open-state-changed', () => { @@ -678,6 +686,8 @@ const WorkspaceIndicator = new Lang.Clas 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(), @@ -782,88 +792,52 @@ const WorkspaceIndicator = new Lang.Clas } }); -const WindowList = new Lang.Class({ - Name: 'WindowList', - - _init: function(perMonitor, monitor) { +// NOTE: call `initializeWindowList` explicitly to finish initialization. +const PureWinList = new Lang.Class({ + Name: 'PureWinList', + + _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 solid', + 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._mutterSettings = new Gio.Settings({ schema_id: 'org.gnome.mutter' }); - this._workspaceSettings = this._getWorkspaceSettings(); - this._workspacesOnlyOnPrimaryChangedId = - this._workspaceSettings.connect('changed::workspaces-only-on-primary', - Lang.bind(this, this._updateWorkspaceIndicatorVisibility)); - this._dynamicWorkspacesSettings = this._getDynamicWorkspacesSettings(); - this._dynamicWorkspacesChangedId = - this._dynamicWorkspacesSettings.connect('changed::dynamic-workspaces', - 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', @@ -874,42 +848,18 @@ const WindowList = new Lang.Class({ 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._fullscreenChangedId = - global.screen.connect('in-fullscreen-changed', Lang.bind(this, function() { - this._updateKeyboardAnchor(); + this.actor.show(); })); - 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(); + this._groupingMode = this._settings.get_enum('grouping-mode'); }, _getDynamicWorkspacesSettings: function() { @@ -918,77 +868,77 @@ const WindowList = new Lang.Class({ return this._mutterSettings; }, - _getWorkspaceSettings: function() { - let settings = global.get_overrides_settings(); - if (settings.list_keys().indexOf('workspaces-only-on-primary') > -1) - return settings; - return this._mutterSettings; + // 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(); - }, + // NOTE: bound by `0` and `totalBtnNum - 1`, no wrapping for + // scrolling. + activeBtnIdx = activeBtnIdx + diff; + let noScrollActionNeeded = ( (activeBtnIdx < 0) || (activeBtnIdx >= totalBtnNum) ); + if (noScrollActionNeeded) + return; - _updatePosition: function() { - this.actor.set_position(this._monitor.x, - this._monitor.y + this._monitor.height - this.actor.height); + // TODO: no need to call `deactivate` for old `active button` ? + buttons[activeBtnIdx].activate(); }, - _updateWorkspaceIndicatorVisibility: function() { - let hasWorkspaces = this._dynamicWorkspacesSettings.get_boolean('dynamic-workspaces') || - global.screen.n_workspaces > 1; - let workspacesOnMonitor = this._monitor == Main.layoutManager.primaryMonitor || - !this._workspaceSettings.get_boolean('workspaces-only-on-primary'); + _onAppStateChanged: function(appSys, app) { + if (!this._grouped) + return; - this._workspaceIndicator.actor.visible = hasWorkspaces && workspacesOnMonitor; + if (app.state == Shell.AppState.RUNNING) + this._addApp(app); + else if (app.state == Shell.AppState.STOPPED) + this._removeApp(app); }, - _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; - - 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]; - - 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() { @@ -997,7 +947,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(); } }, @@ -1006,6 +956,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(); @@ -1017,7 +987,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( @@ -1038,42 +1008,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; @@ -1084,30 +1020,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(); @@ -1116,6 +1054,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++) { @@ -1132,8 +1092,6 @@ const WindowList = new Lang.Class({ Lang.bind(this, this._onWindowRemoved)); this._workspaceSignals.set(workspace, signals); } - - this._updateWorkspaceIndicatorVisibility(); }, _disconnectWorkspaceSignals: function() { @@ -1147,6 +1105,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); }, @@ -1208,22 +1317,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); @@ -1231,12 +1329,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); } }); @@ -1245,7 +1337,6 @@ const Extension = new Lang.Class({ _init: function() { this._windowLists = null; - this._injections = {}; }, enable: function() { @@ -1301,6 +1392,73 @@ 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', + () => { + if (this._pureWinList == null) + return; + + 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. + + this._heightChangeId = + Main.panel.actor.connect('notify::height', Lang.bind(this, function() { + Main.layoutManager.panelBox.set_position(this._pureWinList._monitor.x, + this._pureWinList._monitor.y + this._pureWinList._monitor.height - Main.panel.actor.height); + })); + }, + + disable: function() { + if (!this._pureWinList) + return; + + Main.panel.actor.disconnect(this._heightChangeId); + 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(); + } } Index: gnome-shell-extensions-3.26.0/extensions/window-list/stylesheet.css =================================================================== --- gnome-shell-extensions-3.26.0.orig/extensions/window-list/stylesheet.css +++ gnome-shell-extensions-3.26.0/extensions/window-list/stylesheet.css @@ -79,6 +79,10 @@ border: 1px solid #cccccc; } +.bottom-panel-menu { + -boxpointer-gap: 4px; +} + .notification { font-weight: normal; }