From 228bd3bed4b9d8aef427210d58fbf73baa4f39a1 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 12 May 2019 23:03:48 -0400 Subject: [PATCH] Use single preview container per taskbar --- appIcons.js | 55 ++++++++++---------- taskbar.js | 34 +++---------- windowPreview.js | 128 +++++++++++++++++++++++++++-------------------- 3 files changed, 108 insertions(+), 109 deletions(-) diff --git a/appIcons.js b/appIcons.js index a0b1957..181d56b 100644 --- a/appIcons.js +++ b/appIcons.js @@ -47,7 +47,6 @@ const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Utils = Me.imports.utils; -const WindowPreview = Me.imports.windowPreview; const Taskbar = Me.imports.taskbar; const _ = imports.gettext.domain(Utils.TRANSLATION_DOMAIN).gettext; @@ -99,7 +98,7 @@ var taskbarAppIcon = Utils.defineClass({ Extends: AppDisplay.AppIcon, ParentConstrParams: [[1, 'app'], [3]], - _init: function(settings, appInfo, panelWrapper, iconParams) { + _init: function(settings, appInfo, panelWrapper, iconParams, previewMenu) { // a prefix is required to avoid conflicting with the parent class variable this._dtpSettings = settings; @@ -107,6 +106,7 @@ var taskbarAppIcon = Utils.defineClass({ this._nWindows = 0; this.window = appInfo.window; this.isLauncher = appInfo.isLauncher; + this._previewMenu = previewMenu; // Fix touchscreen issues before the listener is added by the parent constructor. this._onTouchEvent = function(actor, event) { @@ -202,6 +202,8 @@ var taskbarAppIcon = Utils.defineClass({ this._switchWorkspaceId = global.window_manager.connect('switch-workspace', Lang.bind(this, this._onSwitchWorkspace)); + + this._hoverChangeId = this.actor.connect('notify::hover', () => this._onAppIconHoverChanged()); this._dtpSettingsSignalIds = [ this._dtpSettings.connect('changed::dot-position', Lang.bind(this, this._settingsChangeRefresh)), @@ -234,23 +236,6 @@ var taskbarAppIcon = Utils.defineClass({ this.forcedOverview = false; this._numberOverlay(); - - this._signalsHandler = new Utils.GlobalSignalsHandler(); - }, - - enableWindowPreview: function() { - if (!this.windowPreview) { - this.windowPreview = new WindowPreview.PreviewMenu(this); - this.windowPreview.enable(); - this._updateWindows(); - } - }, - - disableWindowPreview: function() { - if (this.windowPreview) { - this.windowPreview.disable(); - this.windowPreview = null; - } }, shouldShowTooltip: function() { @@ -261,7 +246,20 @@ var taskbarAppIcon = Utils.defineClass({ } else { return this.actor.hover && !this.window && (!this._menu || !this._menu.isOpen) && - (!this.windowPreview || !this.windowPreview.isOpen); + (this._previewMenu.getCurrentAppIcon() !== this); + } + }, + + _onAppIconHoverChanged: function() { + if (!this._dtpSettings.get_boolean('show-window-previews') || + (!this.window && !this._nWindows)) { + return; + } + + if (this.actor.hover) { + this._previewMenu.requestOpen(this); + } else { + this._previewMenu.requestClose(); } }, @@ -292,6 +290,10 @@ var taskbarAppIcon = Utils.defineClass({ if(this._scaleFactorChangedId) St.ThemeContext.get_for_stage(global.stage).disconnect(this._scaleFactorChangedId); + if (this._hoverChangeId) { + this.actor.disconnect(this._hoverChangeId); + } + for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) { this._dtpSettings.disconnect(this._dtpSettingsSignalIds[i]); } @@ -516,8 +518,7 @@ var taskbarAppIcon = Utils.defineClass({ this.emit('menu-state-changed', true); - if (this.windowPreview) - this.windowPreview.close(); + this._previewMenu.close(true); this.actor.set_hover(true); this._menu.actor.add_style_class_name('dashtopanelSecondaryMenu'); @@ -702,8 +703,8 @@ var taskbarAppIcon = Utils.defineClass({ } let appCount = this.getAppIconInterestingWindows().length; - if (this.windowPreview && (!(buttonAction == "TOGGLE-SHOWPREVIEW") || (appCount <= 1))) - this.windowPreview.close(); + if (!(buttonAction == "TOGGLE-SHOWPREVIEW") || (appCount <= 1)) + this._previewMenu.close(true); // We check if the app is running, and that the # of windows is > 0 in // case we use workspace isolation, @@ -863,9 +864,7 @@ var taskbarAppIcon = Utils.defineClass({ this.actor.add_style_class_name(className); } - if (this.windowPreview) { - this.windowPreview.updateWindows(windows); - } + this._previewMenu.updateWindows(this, windows); }, _getRunningIndicatorCount: function() { @@ -1083,7 +1082,7 @@ var taskbarAppIcon = Utils.defineClass({ handleDragOver: function(source, actor, x, y, time) { if (source == Main.xdndHandler) { - this.windowPreview.close(); + this._previewMenu.close(true); } return DND.DragMotionResult.CONTINUE; diff --git a/taskbar.js b/taskbar.js index 76547ea..8ce1495 100644 --- a/taskbar.js +++ b/taskbar.js @@ -238,6 +238,9 @@ var taskbar = Utils.defineClass({ coordinate: Clutter.BindCoordinate.HEIGHT })); + this.previewMenu = new WindowPreview.PreviewMenu(settings, panelWrapper); + this.previewMenu.enable(); + if (!this._dtpSettings.get_boolean('show-show-apps-button')) this.hideShowAppsButton(); @@ -325,11 +328,6 @@ var taskbar = Utils.defineClass({ 'notify::checked', Lang.bind(this, this._syncShowAppsButtonToggled) ], - [ - this._dtpSettings, - 'changed::show-window-previews', - Lang.bind(this, this._toggleWindowPreview) - ], [ this._dtpSettings, 'changed::show-show-apps-button', @@ -379,6 +377,7 @@ var taskbar = Utils.defineClass({ this._showAppsIconWrapper.destroy(); this._container.destroy(); + this.previewMenu.disable(); this._disconnectWorkspaceSignals(); }, @@ -552,7 +551,8 @@ var taskbar = Utils.defineClass({ setSizeManually: true, showLabel: false, isDraggable: !this._dtpSettings.get_boolean('taskbar-locked'), - } + }, + this.previewMenu ); if (appIcon._draggable) { @@ -622,27 +622,12 @@ var taskbar = Utils.defineClass({ return item; }, - _toggleWindowPreview: function() { - if (this._dtpSettings.get_boolean('show-window-previews')) - this._enableWindowPreview(); - else - this._disableWindowPreview(); - }, - _enableWindowPreview: function() { - let appIcons = this._getAppIcons(); - - appIcons.filter(appIcon => !appIcon.isLauncher) - .forEach(function (appIcon) { - appIcon.enableWindowPreview(); - }); + this.previewMenu.enable(); }, _disableWindowPreview: function() { - let appIcons = this._getAppIcons(); - appIcons.forEach(function (appIcon) { - appIcon.disableWindowPreview(); - }); + this.previewMenu.disable(); }, // Return an array with the "proper" appIcons currently in the taskbar @@ -871,9 +856,6 @@ var taskbar = Utils.defineClass({ this._updateNumberOverlay(); } - // Connect windows previews to hover events - this._toggleWindowPreview(); - this._shownInitially = true; }, diff --git a/windowPreview.js b/windowPreview.js index 74f8ad1..2843c17 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -26,6 +26,7 @@ const Taskbar = Me.imports.taskbar; const Utils = Me.imports.utils; const TRANSLATION_OFFSET = 50; +const MONITOR_PADDING = 10; //timeout intervals @@ -37,14 +38,16 @@ var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel.PreviewMenu', Extends: St.Widget, - _init: function(appIcon) { + _init: function(dtpSettings, panelWrapper) { this.callParent('_init', { name: 'preview-menu', reactive: true }); - this.isOpen = false; + this._dtpSettings = dtpSettings; + this._panelWrapper = panelWrapper; - this._appIcon = appIcon; - this._app = appIcon.app; - this._dtpSettings = appIcon._dtpSettings; + this._currentAppIcon = null; + this._position = Taskbar.getPosition(); + this._translationProp = 'translation_' + (this._position == St.Side.LEFT || this._position == St.Side.RIGHT ? 'x' : 'y'); + this[this._translationProp] = TRANSLATION_OFFSET; @@ -65,47 +68,63 @@ var PreviewMenu = Utils.defineClass({ this.visible = false; this.opacity = 0; - Main.uiGroup.insert_child_below(this, this._appIcon.panelWrapper.panelBox); + Main.uiGroup.insert_child_below(this, this._panelWrapper.panelBox); - this._signalsHandler.add( - [ - this._appIcon.actor, - 'notify::hover', - () => this._onAppIconHoverChanged() - ], - ); + // this._signalsHandler.add( + // [ + + // ], + // ); }, disable: function() { this._signalsHandler.destroy(); this._timeoutsHandler.destroy(); - this.close(); + this.close(true); Main.uiGroup.remove_child(this); }, - open: function() { - if (!this.isOpen) { - this.isOpen = true; + requestOpen: function(appIcon) { + this._endOpenCloseTimeouts(); - this._updatePosition(); - this.show(); - this._animateOpenOrClose(true); + if (this._currentAppIcon) { + return this.open(appIcon); } + + this._timeoutsHandler.add([T1, this._dtpSettings.get_int('show-window-previews-timeout'), () => this.open(appIcon)]); }, - close: function() { - if (this.isOpen) { - this.isOpen = false; + requestClose: function() { + this._endOpenCloseTimeouts(); + this._timeoutsHandler.add([T2, this._dtpSettings.get_int('leave-timeout'), () => this.close()]); + }, - this._animateOpenOrClose(false, () => { + open: function(appIcon) { + this._currentAppIcon = appIcon; + this._updatePosition(); + this.show(); + this._animateOpenOrClose(true); + }, + + close: function(immediate) { + this._currentAppIcon = null; + + if (this.visible) { + this._animateOpenOrClose(false, immediate, () => { this.hide(); }); } }, - updateWindows: function(windows) { + updateWindows: function(appIcon, windows) { + if (this._currentAppIcon == appIcon) { + } + }, + + getCurrentAppIcon: function() { + return this._currentAppIcon; }, vfunc_allocate: function(box, flags) { @@ -120,63 +139,62 @@ var PreviewMenu = Utils.defineClass({ return [0, 200]; }, - _onAppIconHoverChanged: function() { - if (this._appIcon.actor.hover) { - this._timeoutsHandler.remove(T2); - this._timeoutsHandler.add([T1, this._dtpSettings.get_int('show-window-previews-timeout'), () => this.open()]); - } else { - this._timeoutsHandler.remove(T1); - this._timeoutsHandler.add([T2, this._dtpSettings.get_int('leave-timeout'), () => this.close()]); - } + _endOpenCloseTimeouts: function() { + this._timeoutsHandler.remove(T1); + this._timeoutsHandler.remove(T2); }, _updatePosition: function() { - let sourceNode = this._appIcon.actor.get_theme_node(); - let sourceContentBox = sourceNode.get_content_box(this._appIcon.actor.get_allocation_box()); - let sourceAllocation = Shell.util_get_transformed_allocation(this._appIcon.actor); + let sourceNode = this._currentAppIcon.actor.get_theme_node(); + let sourceContentBox = sourceNode.get_content_box(this._currentAppIcon.actor.get_allocation_box()); + let sourceAllocation = Shell.util_get_transformed_allocation(this._currentAppIcon.actor); let [minWidth, minHeight, natWidth, natHeight] = this.get_preferred_size(); - let position = Taskbar.getPosition(); - let isLeftOrRight = position == St.Side.LEFT || position == St.Side.RIGHT; let x, y; - if (position == St.Side.TOP || position == St.Side.BOTTOM) { + if (this._position == St.Side.TOP || this._position == St.Side.BOTTOM) { x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * .5 - natWidth * .5; - } else if (position == St.Side.LEFT) { + } else if (this._position == St.Side.LEFT) { x = sourceAllocation.x2; } else { //St.Side.RIGHT x = sourceAllocation.x1 - natWidth; } - if (isLeftOrRight) { + if (this._position == St.Side.LEFT || this._position == St.Side.RIGHT) { y = sourceAllocation.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * .5 - natHeight * .5; - } else if (position == St.Side.TOP) { + } else if (this._position == St.Side.TOP) { y = sourceAllocation.y2; } else { //St.Side.BOTTOM y = sourceAllocation.y1 - natHeight; } - x = Math.max(x, this._appIcon.panelWrapper.monitor.x); - y = Math.max(y, this._appIcon.panelWrapper.monitor.y); + x = Math.max(x, this._panelWrapper.monitor.x + MONITOR_PADDING); + y = Math.max(y, this._panelWrapper.monitor.y + MONITOR_PADDING); - this.set_position(x, y); - this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y'); - this[this._translationProp] = TRANSLATION_OFFSET; + if (this[this._translationProp] > 0) { + this.set_position(x, y); + this[this._translationProp] = TRANSLATION_OFFSET; + } else { + Tweener.addTween(this, { + x: x, y: y, + time: Taskbar.DASH_ANIMATION_TIME, + transition: 'easeInOutQuad' + }); + } }, - _animateOpenOrClose: function(show, onComplete) { - Tweener.removeTweens(this); - + _animateOpenOrClose: function(show, immediate, onComplete) { let tweenOpts = { opacity: show ? 255 : 0, - time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: () => { - (onComplete || (() => {}))(); - } + time: immediate ? 0 : Taskbar.DASH_ANIMATION_TIME, + transition: show ? 'easeInOutQuad' : 'easeInCubic' }; tweenOpts[this._translationProp] = show ? 0 : TRANSLATION_OFFSET; + if (onComplete) { + tweenOpts.onComplete = onComplete; + } + Tweener.addTween(this, tweenOpts); }, }); \ No newline at end of file