From 018af512baec0b6028df9cf2b6a008b0f452564d Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sat, 11 May 2019 21:40:48 -0400 Subject: [PATCH 01/61] Add initial custom preview container --- appIcons.js | 110 +--- taskbar.js | 3 +- windowPreview.js | 1314 +++++----------------------------------------- 3 files changed, 159 insertions(+), 1268 deletions(-) diff --git a/appIcons.js b/appIcons.js index a973fbf..a0b1957 100644 --- a/appIcons.js +++ b/appIcons.js @@ -238,89 +238,19 @@ var taskbarAppIcon = Utils.defineClass({ this._signalsHandler = new Utils.GlobalSignalsHandler(); }, - _createWindowPreview: function() { - // Abort if already activated - if (this.menuManagerWindowPreview) - return; - - // Creating a new menu manager for window previews as adding it to the - // using the secondary menu's menu manager (which uses the "ignoreRelease" - // function) caused the extension to crash. - this.menuManagerWindowPreview = new PopupMenu.PopupMenuManager(this); - - this.windowPreview = new WindowPreview.thumbnailPreviewMenu(this, this._dtpSettings, this.menuManagerWindowPreview); - - this.windowPreview.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) { - if (!isPoppedUp) - this._onMenuPoppedDown(); - })); - this.menuManagerWindowPreview.addMenu(this.windowPreview); - - // grabHelper.grab() is usually called when the menu is opened. However, there seems to be a bug in the - // underlying gnome-shell that causes all window contents to freeze if the grab and ungrab occur - // in quick succession in timeouts from the Mainloop (for example, clicking the icon as the preview window is opening) - // So, instead wait until the mouse is leaving the icon (and might be moving toward the open window) to trigger the grab - // in windowPreview.js - let windowPreviewMenuData = this.menuManagerWindowPreview._menus[this.menuManagerWindowPreview._findMenu(this.windowPreview)]; - this.windowPreview.disconnect(windowPreviewMenuData.openStateChangeId); - windowPreviewMenuData.openStateChangeId = this.windowPreview.connect('open-state-changed', Lang.bind(this.menuManagerWindowPreview, function(menu, open) { - if (open) { - if (this.activeMenu) - this.activeMenu.close(BoxPointer.PopupAnimation.FADE); - - // don't grab here, we are grabbing in onLeave in windowPreview.js - //this._grabHelper.grab({ actor: menu.actor, focus: menu.sourceActor, onUngrab: Lang.bind(this, this._closeMenu, menu) }); - } else { - this._grabHelper.ungrab({ actor: menu.actor }); - } - })); - }, - - enableWindowPreview: function(appIcons) { - this._createWindowPreview(); - - // We first remove to ensure there are no duplicates - this._signalsHandler.removeWithLabel('window-preview'); - this._signalsHandler.addWithLabel('window-preview', [ - this.windowPreview, - 'menu-closed', - // enter-event doesn't fire on an app icon when the popup menu from a previously - // hovered app icon is still open, so when a preview menu closes we need to - // see if a new app icon is hovered and open its preview menu now. - // also, for some reason actor doesn't report being hovered by get_hover() - // if the hover started when a popup was opened. So, look for the actor by mouse position. - menu => this.syncWindowPreview(appIcons, menu) - ]); - - this.windowPreview.enableWindowPreview(); - }, - - syncWindowPreview: function(appIcons, menu) { - let [x, y,] = global.get_pointer(); - let hoveredActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y); - let appIconToOpen; - - appIcons.forEach(function (appIcon) { - if(appIcon.actor == hoveredActor) { - appIconToOpen = appIcon; - } else if(appIcon.windowPreview && appIcon.windowPreview.isOpen) { - appIcon.windowPreview.close(); - } - }); - - if(appIconToOpen) { - appIconToOpen.actor.sync_hover(); - if(appIconToOpen.windowPreview && appIconToOpen.windowPreview != menu) - appIconToOpen.windowPreview._onEnter(); + enableWindowPreview: function() { + if (!this.windowPreview) { + this.windowPreview = new WindowPreview.PreviewMenu(this); + this.windowPreview.enable(); + this._updateWindows(); } - - return GLib.SOURCE_REMOVE; }, disableWindowPreview: function() { - this._signalsHandler.removeWithLabel('window-preview'); - if (this.windowPreview) - this.windowPreview.disableWindowPreview(); + if (this.windowPreview) { + this.windowPreview.disable(); + this.windowPreview = null; + } }, shouldShowTooltip: function() { @@ -368,13 +298,13 @@ var taskbarAppIcon = Utils.defineClass({ }, onWindowsChanged: function() { - this._updateCounterClass(); + this._updateWindows(); this.updateIcon(); }, onWindowEnteredOrLeft: function() { if (this._checkIfFocusedApp()) { - this._updateCounterClass(); + this._updateWindows(); this._displayProperIndicator(); } }, @@ -403,7 +333,7 @@ var taskbarAppIcon = Utils.defineClass({ _showDots: function() { // Just update style if dots already exist if (this._focusedDots && this._unfocusedDots) { - this._updateCounterClass(); + this._updateWindows(); return; } @@ -447,7 +377,7 @@ var taskbarAppIcon = Utils.defineClass({ this._dotsContainer.add_child(this._unfocusedDots); - this._updateCounterClass(); + this._updateWindows(); } this._dotsContainer.add_child(this._focusedDots); @@ -463,7 +393,7 @@ var taskbarAppIcon = Utils.defineClass({ _settingsChangeRefresh: function() { if (this._isGroupApps) { - this._updateCounterClass(); + this._updateWindows(); this._focusedDots.queue_repaint(); this._unfocusedDots.queue_repaint(); } @@ -773,7 +703,7 @@ var taskbarAppIcon = Utils.defineClass({ let appCount = this.getAppIconInterestingWindows().length; if (this.windowPreview && (!(buttonAction == "TOGGLE-SHOWPREVIEW") || (appCount <= 1))) - this.windowPreview.requestCloseMenu(); + this.windowPreview.close(); // We check if the app is running, and that the # of windows is > 0 in // case we use workspace isolation, @@ -920,8 +850,10 @@ var taskbarAppIcon = Utils.defineClass({ } }, - _updateCounterClass: function() { - this._nWindows = this.getAppIconInterestingWindows().length; + _updateWindows: function() { + let windows = this.getAppIconInterestingWindows(); + + this._nWindows = windows.length; for (let i = 1; i <= MAX_INDICATORS; i++){ let className = 'running'+i; @@ -930,6 +862,10 @@ var taskbarAppIcon = Utils.defineClass({ else this.actor.add_style_class_name(className); } + + if (this.windowPreview) { + this.windowPreview.updateWindows(windows); + } }, _getRunningIndicatorCount: function() { diff --git a/taskbar.js b/taskbar.js index 19d3ca0..76547ea 100644 --- a/taskbar.js +++ b/taskbar.js @@ -565,7 +565,6 @@ var taskbar = Utils.defineClass({ Lang.bind(this, function() { appIcon.actor.opacity = 255; this._enableWindowPreview(); - appIcon.syncWindowPreview(this._getAppIcons()); })); } @@ -635,7 +634,7 @@ var taskbar = Utils.defineClass({ appIcons.filter(appIcon => !appIcon.isLauncher) .forEach(function (appIcon) { - appIcon.enableWindowPreview(appIcons); + appIcon.enableWindowPreview(); }); }, diff --git a/windowPreview.js b/windowPreview.js index 8b2376c..74f8ad1 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -12,1215 +12,171 @@ * 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 . - * - * - * Credits: - * This file is based on code from the Dash to Dock extension by micheleg - * and code from the Taskbar extension by Zorin OS - * Some code was also adapted from the upstream Gnome Shell source code. + * along with this program. If not, see . */ - -const BoxPointer = imports.ui.boxpointer; -const Clutter = imports.gi.Clutter; -const Config = imports.misc.config; -const GLib = imports.gi.GLib; -const Gtk = imports.gi.Gtk; -const Lang = imports.lang; const Main = imports.ui.main; -const Mainloop = imports.mainloop; -const Meta = imports.gi.Meta; -const PopupMenu = imports.ui.popupMenu; const Signals = imports.signals; const Shell = imports.gi.Shell; const St = imports.gi.St; const Tweener = imports.ui.tweener; -const WindowMenu = imports.ui.windowMenu; -const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Taskbar = Me.imports.taskbar; -const AppIcons = Me.imports.appIcons; const Utils = Me.imports.utils; -let HOVER_APP_BLACKLIST = [ - "Oracle VM VirtualBox", - "Virtual Machine Manager", - "Remmina" - ] +const TRANSLATION_OFFSET = 50; -var thumbnailPreviewMenu = Utils.defineClass({ - Name: 'DashToPanel.ThumbnailPreviewMenu', - Extends: PopupMenu.PopupMenu, - ParentConstrParams: [[0, 'actor'], 0.5, Taskbar.getPosition()], +//timeout intervals - _init: function(source, settings) { - this._dtpSettings = settings; +//timeout names +const T1 = 'openMenuTimeout'; +const T2 = 'closeMenuTimeout'; - let side = Taskbar.getPosition(); +var PreviewMenu = Utils.defineClass({ + Name: 'DashToPanel.PreviewMenu', + Extends: St.Widget, - this.callParent('_init', source.actor, 0.5, side); - - // We want to keep the item hovered while the menu is up - this.blockSourceEvents = false; - - this._source = source; - this._app = this._source.app; - - this.actor.add_style_class_name('app-well-menu'); - this.actor.set_style("max-width: " + (this._source.panelWrapper.monitor.width - 22) + "px;"); - this.actor.hide(); - - // Chain our visibility and lifecycle to that of the source - this._mappedId = this._source.actor.connect('notify::mapped', Lang.bind(this, function () { - if (!this._source.actor.mapped) - this.close(); - })); - this._destroyId = this._source.actor.connect('destroy', Lang.bind(this, this.destroy)); - - Main.uiGroup.add_actor(this.actor); - - // Change the initialized side where required. - this._arrowSide = side; - this._boxPointer._arrowSide = side; - this._boxPointer._userArrowSide = side; - - this._previewBox = new thumbnailPreviewList(this._app, source, this._dtpSettings); - this.addMenuItem(this._previewBox); - - this._peekMode = false; - this._peekModeEnterTimeoutId = 0; - this._peekModeDisableTimeoutId = 0; - this._DISABLE_PEEK_MODE_TIMEOUT = 50; - this._peekedWindow = null; - this._peekModeSavedWorkspaces = null; - this._peekModeSavedOrder = null; - this._trackOpenWindowsId = null; - this._trackClosedWindowsIds = null; - this._peekModeOriginalWorkspace = null; - this._peekModeCurrentWorkspace = null; - }, - - enableWindowPreview: function() { - // Show window previews on mouse hover - this._enterSourceId = this._source.actor.connect('enter-event', Lang.bind(this, this._onEnter)); - this._leaveSourceId = this._source.actor.connect('leave-event', Lang.bind(this, this._onLeave)); - - this._enterMenuId = this.actor.connect('enter-event', Lang.bind(this, this._onMenuEnter)); - this._leaveMenuId = this.actor.connect('leave-event', Lang.bind(this, this._onMenuLeave)); - }, - - disableWindowPreview: function() { - if (this._enterSourceId) { - this._source.actor.disconnect(this._enterSourceId); - this._enterSourceId = 0; - } - if (this._leaveSourceId) { - this._source.actor.disconnect(this._leaveSourceId); - this._leaveSourceId = 0; - } - - if (this._enterMenuId) { - this.actor.disconnect(this._enterMenuId); - this._enterMenuId = 0; - } - if (this._leaveMenuId) { - this.actor.disconnect(this._leaveMenuId); - this._leaveMenuId = 0; - } - - this.close(); - }, - - requestCloseMenu: function() { - // The "~0" argument makes the animation display. - this.close(~0); - }, - - _redisplay: function() { - this._previewBox._shownInitially = false; - this._previewBox._redisplay(); - }, - - popup: function() { - let windows = AppIcons.getInterestingWindows(this._app, this._dtpSettings, this._source.panelWrapper.monitor); - if (windows.length > 0) { - this._redisplay(); - this.open(); - this._source.emit('sync-tooltip'); - } - }, - - _onMenuEnter: function () { - this.cancelClose(); - - this.hoverOpen(); - }, - - _onMenuLeave: function () { - this.cancelOpen(); - this.cancelClose(); - - this._hoverCloseTimeoutId = Mainloop.timeout_add(Taskbar.DASH_ITEM_HOVER_TIMEOUT, Lang.bind(this, this.hoverClose)); - }, - - _onEnter: function () { - this.cancelOpen(); - this.cancelClose(); - - this._hoverOpenTimeoutId = Mainloop.timeout_add(this._dtpSettings.get_int('show-window-previews-timeout'), Lang.bind(this, this.hoverOpen)); - }, - - _onLeave: function () { - this.cancelOpen(); - this.cancelClose(); - - // grabHelper.grab() is usually called when the menu is opened. However, there seems to be a bug in the - // underlying gnome-shell that causes all window contents to freeze if the grab and ungrab occur - // in quick succession in timeouts from the Mainloop (for example, clicking the icon as the preview window is opening) - // So, instead wait until the mouse is leaving the icon (and might be moving toward the open window) to trigger the grab - if(this.isOpen) - this._source.menuManagerWindowPreview._grabHelper.grab({ actor: this.actor, focus: this.sourceActor, - onUngrab: Lang.bind(this, this.requestCloseMenu) }); - - this._hoverCloseTimeoutId = Mainloop.timeout_add(this._dtpSettings.get_int('leave-timeout'), Lang.bind(this, this.hoverClose)); - }, - - cancelOpen: function () { - if(this._hoverOpenTimeoutId) { - Mainloop.source_remove(this._hoverOpenTimeoutId); - this._hoverOpenTimeoutId = null; - } - }, - - cancelClose: function () { - if(this._hoverCloseTimeoutId) { - Mainloop.source_remove(this._hoverCloseTimeoutId); - this._hoverCloseTimeoutId = null; - } - }, - - _appInHoverBlacklist: function (appName) { - for (let i = 0; i < HOVER_APP_BLACKLIST.length; i++) { - if (appName === HOVER_APP_BLACKLIST[i]) - return true; - } - - return false; - }, - - hoverOpen: function () { - this._hoverOpenTimeoutId = null; - if (!this.isOpen && this._dtpSettings.get_boolean("show-window-previews")) { - this.popup(); - let focusedApp = Shell.WindowTracker.get_default().focus_app; - if (focusedApp && this._appInHoverBlacklist(focusedApp.get_name())) { - this.actor.grab_key_focus(); - } - } - }, - - hoverClose: function () { - this._hoverCloseTimeoutId = null; - this.close(~0); - }, - - destroy: function () { - this.cancelClose(); - this.cancelOpen(); - - if (this._mappedId) - this._source.actor.disconnect(this._mappedId); - - if (this._destroyId) - this._source.actor.disconnect(this._destroyId); - - if (this._enterSourceId) - this._source.actor.disconnect(this._enterSourceId); - if (this._leaveSourceId) - this._source.actor.disconnect(this._leaveSourceId); - - if (this._enterMenuId) - this.actor.disconnect(this._enterMenuId); - if (this._leaveMenuId) - this.actor.disconnect(this._leaveMenuId); - - this.callParent('destroy'); - }, - - close: function(animate) { - this.cancelOpen(); - - if (this.isOpen) - this.emit('open-state-changed', false); - if (this._activeMenuItem) - this._activeMenuItem.setActive(false); - - if (this._boxPointer.actor.visible) { - (this._boxPointer.close || this._boxPointer.hide).call(this._boxPointer, animate, Lang.bind(this, function() { - this.emit('menu-closed', this); - })); - } - - if(this._peekMode) - this._disablePeekMode(); + _init: function(appIcon) { + this.callParent('_init', { name: 'preview-menu', reactive: true }); this.isOpen = false; - }, - _emulateSwitchingWorkspaces: function(oldWorkspace, newWorkspace) { - if(oldWorkspace == newWorkspace) - return; + this._appIcon = appIcon; + this._app = appIcon.app; + this._dtpSettings = appIcon._dtpSettings; - oldWorkspace.list_windows().forEach(Lang.bind(this, function(window) { - if(!window.is_on_all_workspaces() && !window.minimized) { - let windowActor = window.get_compositor_private(); - Tweener.addTween(windowActor, { - opacity: 0, - time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, function(windowActor) { - windowActor.hide(); - windowActor.opacity = this._dtpSettings.get_int('peek-mode-opacity'); - }), - onCompleteParams: [windowActor] - }); - } - })); - newWorkspace.list_windows().forEach(Lang.bind(this, function(window) { - if(!window.is_on_all_workspaces() && !window.minimized) { - let windowActor = window.get_compositor_private(); - windowActor.show(); - windowActor.opacity = 0; - Tweener.addTween(windowActor, { - opacity: this._dtpSettings.get_int('peek-mode-opacity'), - time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeOutQuad' - }); - } - })); - this._peekModeCurrentWorkspace = newWorkspace; - }, - _disablePeekMode: function() { - if(this._peekModeDisableTimeoutId) { - Mainloop.source_remove(this._peekModeDisableTimeoutId); - this._peekModeDisableTimeoutId = null; - } - //Restore windows' old state - if(this._peekedWindow) { - let peekedWindowActor = this._peekedWindow.get_compositor_private(); - let originalIndex = this._peekModeSavedOrder.indexOf(peekedWindowActor); - - let locatedOnOriginalWorkspace = this._peekModeCurrentWorkspace == this._peekModeOriginalWorkspace; - if(!locatedOnOriginalWorkspace) - this._emulateSwitchingWorkspaces(this._peekModeCurrentWorkspace, this._peekModeOriginalWorkspace); - - if(peekedWindowActor) - global.window_group.set_child_at_index(peekedWindowActor, originalIndex); - } - - this._peekModeSavedWorkspaces.forEach(Lang.bind(this, function(workspace) { - workspace.forEach(Lang.bind(this, function(pairWindowOpacity) { - let window = pairWindowOpacity[0]; - let initialOpacity = pairWindowOpacity[1]; - let windowActor = window.get_compositor_private(); - if(window && windowActor) { - if(window.minimized || !window.located_on_workspace(this._peekModeOriginalWorkspace)) - Tweener.addTween(windowActor, { - opacity: 0, - time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: Lang.bind(windowActor, function() { - windowActor.hide(); - windowActor.opacity = initialOpacity; - }) - }); - else - Tweener.addTween(windowActor, { - opacity: initialOpacity, - time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeOutQuad' - }); - } - })); - })); - this._peekModeSavedWorkspaces = null; - this._peekedWindow = null; - this._peekModeSavedOrder = null; - this._peekModeCurrentWorkspace = null; - this._peekModeOriginalWorkspace = null; - - this._trackClosedWindowsIds.forEach(function(pairWindowSignalId) { - if(pairWindowSignalId) - pairWindowSignalId[0].disconnect(pairWindowSignalId[1]); - }); - this._trackClosedWindowsIds = null; - - if(this._trackOpenWindowsId) { - global.display.disconnect(this._trackOpenWindowsId); - this._trackOpenWindowsId = null; - } - - this._peekMode = false; - }, - - _setPeekedWindow: function(newPeekedWindow) { - if(this._peekedWindow == newPeekedWindow) - return; + //testing + this.set_style('background: #ff0000;') - //We don't need to bother with animating the workspace out and then in if the old peeked workspace is the same as the new one - let needToChangeWorkspace = !newPeekedWindow.located_on_workspace(this._peekModeCurrentWorkspace) || (newPeekedWindow.is_on_all_workspaces() && this._peekModeCurrentWorkspace != this._peekModeOriginalWorkspace); - if(needToChangeWorkspace) { - //If the new peeked window is on every workspace, we get the original one - //Otherwise, we get the workspace the window is exclusive to - let newWorkspace = newPeekedWindow.get_workspace(); - this._emulateSwitchingWorkspaces(this._peekModeCurrentWorkspace, newWorkspace); + //TODO + //'open-state-changed' + //'menu-closed' + //'sync-tooltip' + //this.add_style_class_name('app-well-menu'); + }, + + enable: function() { + this._signalsHandler = new Utils.GlobalSignalsHandler(); + this._timeoutsHandler = new Utils.TimeoutsHandler(); + + this.visible = false; + this.opacity = 0; + + Main.uiGroup.insert_child_below(this, this._appIcon.panelWrapper.panelBox); + + this._signalsHandler.add( + [ + this._appIcon.actor, + 'notify::hover', + () => this._onAppIconHoverChanged() + ], + ); + }, + + disable: function() { + this._signalsHandler.destroy(); + this._timeoutsHandler.destroy(); + + this.close(); + Main.uiGroup.remove_child(this); + }, + + open: function() { + if (!this.isOpen) { + this.isOpen = true; + + this._updatePosition(); + this.show(); + this._animateOpenOrClose(true); + } + }, + + close: function() { + if (this.isOpen) { + this.isOpen = false; + + this._animateOpenOrClose(false, () => { + this.hide(); + }); + } + }, + + updateWindows: function(windows) { + + }, + + vfunc_allocate: function(box, flags) { + this.set_allocation(box, flags); + }, + + vfunc_get_preferred_width: function(forHeight) { + return [0, 300]; + }, + + vfunc_get_preferred_height: function(forWidth) { + 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()]); + } + }, + + _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 [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) { + x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * .5 - natWidth * .5; + } else if (position == St.Side.LEFT) { + x = sourceAllocation.x2; + } else { //St.Side.RIGHT + x = sourceAllocation.x1 - natWidth; } - //Hide currently peeked window and show the new one - if(this._peekedWindow) { - let peekedWindowActor = this._peekedWindow.get_compositor_private(); - let originalIndex = this._peekModeSavedOrder.indexOf(peekedWindowActor); - - global.window_group.set_child_at_index(peekedWindowActor, originalIndex); - if(this._peekedWindow.minimized || (needToChangeWorkspace && !this._peekedWindow.is_on_all_workspaces())) - Tweener.addTween(peekedWindowActor, { - opacity: 0, - time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, function(peekedWindowActor) { - peekedWindowActor.hide(); - peekedWindowActor.opacity = this._dtpSettings.get_int('peek-mode-opacity'); - }), - onCompleteParams: [peekedWindowActor] - }); - else - Tweener.addTween(peekedWindowActor, { - opacity: this._dtpSettings.get_int('peek-mode-opacity'), - time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeOutQuad' - }); + if (isLeftOrRight) { + y = sourceAllocation.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * .5 - natHeight * .5; + } else if (position == St.Side.TOP) { + y = sourceAllocation.y2; + } else { //St.Side.BOTTOM + y = sourceAllocation.y1 - natHeight; } - this._peekedWindow = newPeekedWindow; - let peekedWindowActor = this._peekedWindow.get_compositor_private(); + x = Math.max(x, this._appIcon.panelWrapper.monitor.x); + y = Math.max(y, this._appIcon.panelWrapper.monitor.y); - if(this._peekedWindow.minimized) { - peekedWindowActor.opacity = 0; - peekedWindowActor.show(); - } + this.set_position(x, y); + this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y'); + this[this._translationProp] = TRANSLATION_OFFSET; + }, - global.window_group.set_child_above_sibling(peekedWindowActor, null); - Tweener.addTween(peekedWindowActor, { - opacity: 255, + _animateOpenOrClose: function(show, onComplete) { + Tweener.removeTweens(this); + + let tweenOpts = { + opacity: show ? 255 : 0, time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeOutQuad' - }); - }, - - _enterPeekMode: function(thumbnail) { - let workspaceManager = Utils.DisplayWrapper.getWorkspaceManager(); - - this._peekMode = true; - //Remove the enter peek mode timeout - if(this._peekModeEnterTimeoutId) { - Mainloop.source_remove(this._peekModeEnterTimeoutId); - this._peekModeEnterTimeoutId = null; - } - - //Save the visible windows in each workspace and lower their opacity - this._peekModeSavedWorkspaces = []; - this._peekModeOriginalWorkspace = workspaceManager.get_active_workspace(); - this._peekModeCurrentWorkspace = this._peekModeOriginalWorkspace; - - for ( let wks=0; wks, - //there might appear St.Widget of type "tile preview" that is on top of the stack - this._peekModeSavedOrder = global.window_group.get_children().slice(); - - //Track closed windows - pairs (window, signal Id), null for backgrounds - this._trackClosedWindowsIds = this._peekModeSavedOrder.map(Lang.bind(this, function(windowActor) { - if(!(windowActor instanceof Meta.BackgroundGroup) && !(windowActor instanceof St.Widget)) - return [windowActor.meta_window, - windowActor.meta_window.connect('unmanaged', Lang.bind(this, this._peekModeWindowClosed))]; - else - return null; - })); - - //Track newly opened windows - if(this._trackOpenWindowsId) - global.display.disconnect(this._trackOpenWindowsId); - this._trackOpenWindowsId = global.display.connect('window-created', Lang.bind(this, this._peekModeWindowOpened)); - - //Having lowered opacity of all the windows, show the peeked window - this._setPeekedWindow(thumbnail.window); - }, - - _peekModeWindowClosed: function(window) { - if(this._peekMode && window == this._peekedWindow) - this._disablePeekMode(); - }, - - _windowOnTop: function(window) { - //There can be St.Widgets "tile-preview" on top of the window stack. - //The window is on top if there are no other window actors above it (Except for St.Widgets) - let windowStack = global.window_group.get_children(); - let newWindowIndex = windowStack.indexOf(window.get_compositor_private()); - - for(let index = newWindowIndex + 1; index < windowStack.length; ++index) { - if(windowStack[index] instanceof Meta.WindowActor || windowStack[index] instanceof Meta.BackgroundGroup) - return false; - } - return true; - }, - - _peekModeWindowOpened: function(display, window) { - this._disablePeekMode(); - //If this new window is placed on the top then close the preview - if(this._windowOnTop(window)) - this.requestCloseMenu(); - } -}); - -var thumbnailPreview = Utils.defineClass({ - Name: 'DashToPanel.ThumbnailPreview', - Extends: PopupMenu.PopupBaseMenuItem, - ParentConstrParams: [{ reactive: true }], - - _init: function(window, settings) { - this._dtpSettings = settings; - this.window = window; - - let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - if(!scaleFactor) - scaleFactor = 1; - - this._thumbnailWidth = this._dtpSettings.get_int('window-preview-width')*scaleFactor; - this._thumbnailHeight = this._dtpSettings.get_int('window-preview-height')*scaleFactor; - - this.callParent('_init', {reactive: true}); - - this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._onResize)); - - this.preview = this.getThumbnail(); - - this.actor.remove_child(this._ornamentLabel); - this.actor._delegate = this; - - this.actor.set_style('padding: ' + this._dtpSettings.get_int('window-preview-padding') + 'px;'); - - this.animatingOut = false; - - this._windowBox = new St.BoxLayout({ style_class: 'window-box', - x_expand: true, - vertical: true }); - - this._closeButton = new St.Button({ style_class: 'window-close', accessible_name: "Close window" }); - - if (Config.PACKAGE_VERSION >= '3.31.9') { - this._closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); - } - - this._closeButton.opacity = 0; - this._closeButton.connect('clicked', Lang.bind(this, this._closeWindow)); - this._closeButton.connect('style-changed', () => this._isLeftButtons = null); - - this._previewBin = new Clutter.Actor({ width: this._thumbnailWidth, height: this._thumbnailHeight }); - - if (this.preview) - this._previewBin.add_actor(this.preview); - - this._previewBin.add_actor(this._closeButton); - - this.overlayGroup = new Clutter.Actor({ layout_manager: new Clutter.BinLayout()}); - this.overlayGroup.add_actor(this._previewBin); - - this._titleNotifyId = 0; - - this._windowBin = new St.Bin({ - child: this.overlayGroup, - x_align: St.Align.MIDDLE, - width: this._thumbnailWidth, - height: this._thumbnailHeight - }); - - this._windowBox.add_child(this._windowBin); - - if (this._dtpSettings.get_boolean('window-preview-show-title')) { - this._title = new St.Label({ text: window.title }); - this._titleBin = new St.Bin({ child: this._title, - x_align: St.Align.MIDDLE, - width: this._thumbnailWidth - }); - this._titleBin.add_style_class_name("preview-window-title"); - - this._windowBox.add_child(this._titleBin); - - this._titleNotifyId = this.window.connect('notify::title', Lang.bind(this, function() { - this._title.set_text(this.window.title); - })); - } - - this.actor.add_child(this._windowBox); - - this.actor.connect('enter-event', - Lang.bind(this, this._onEnter)); - this.actor.connect('leave-event', - Lang.bind(this, this._onLeave)); - this.actor.connect('key-focus-in', - Lang.bind(this, this._onEnter)); - this.actor.connect('key-focus-out', - Lang.bind(this, this._onLeave)); - this.actor.connect('motion-event', - Lang.bind(this, this._onMotionEvent)); - - this._previewMenuPopupManager = new previewMenuPopupManager(window, this.actor); - }, - - _onEnter: function(actor, event) { - this._repositionCloseButton(); - this._showCloseButton(); - - let topMenu = this._getTopMenu(); - if(topMenu._dtpSettings.get_boolean('peek-mode')) { - if(topMenu._peekMode) { - if(topMenu._peekModeDisableTimeoutId) { - Mainloop.source_remove(topMenu._peekModeDisableTimeoutId); - topMenu._peekModeDisableTimeoutId = null; - } - //Hide the old peeked window and show the window in preview - topMenu._setPeekedWindow(this.window); - } else if(!this.animatingOut) { - //Remove old timeout and set a new one - if(topMenu._peekModeEnterTimeoutId) - Mainloop.source_remove(topMenu._peekModeEnterTimeoutId); - topMenu._peekModeEnterTimeoutId = Mainloop.timeout_add(topMenu._dtpSettings.get_int('enter-peek-mode-timeout'), Lang.bind(this, function() { - topMenu._enterPeekMode(this); - })); + transition: 'easeOutQuad', + onComplete: () => { + (onComplete || (() => {}))(); } - } + }; - return Clutter.EVENT_PROPAGATE; + tweenOpts[this._translationProp] = show ? 0 : TRANSLATION_OFFSET; + + Tweener.addTween(this, tweenOpts); }, - - _onLeave: function(actor, event) { - if (!this._previewBin.has_pointer && - !this._closeButton.has_pointer) - this._hideCloseButton(); - - let topMenu = this._getTopMenu(); - if(topMenu._peekMode) { - if(topMenu._peekModeDisableTimeoutId){ - Mainloop.source_remove(topMenu._peekModeDisableTimeoutId); - topMenu._peekModeDisableTimeoutId = null; - } - topMenu._peekModeDisableTimeoutId = Mainloop.timeout_add(topMenu._DISABLE_PEEK_MODE_TIMEOUT, function() { - topMenu._disablePeekMode() - }); - } - if(topMenu._peekModeEnterTimeoutId) { - Mainloop.source_remove(topMenu._peekModeEnterTimeoutId); - topMenu._peekModeEnterTimeoutId = null; - } - - return Clutter.EVENT_PROPAGATE; - }, - - _idleToggleCloseButton: function() { - this._idleToggleCloseId = 0; - - if (!this._previewBin.has_pointer && - !this._closeButton.has_pointer) - this._hideCloseButton(); - - return GLib.SOURCE_REMOVE; - }, - - _showCloseButton: function() { - if (this._windowCanClose()) { - this._closeButton.show(); - Tweener.addTween(this._closeButton, - { opacity: 255, - time: Workspace.CLOSE_BUTTON_FADE_TIME, - transition: 'easeOutQuad' }); - } - }, - - _windowCanClose: function() { - return this.window.can_close() && - !this._hasAttachedDialogs(); - }, - - _hasAttachedDialogs: function() { - // count trasient windows - let n = 0; - this.window.foreach_transient(function() {n++;}); - return n > 0; - }, - - _hideCloseButton: function() { - Tweener.addTween(this._closeButton, - { opacity: 0, - time: Workspace.CLOSE_BUTTON_FADE_TIME, - transition: 'easeInQuad' }); - }, - - getThumbnail: function() { - let thumbnail = null; - let mutterWindow = this.window.get_compositor_private(); - if (mutterWindow) { - thumbnail = new Clutter.Clone ({ source: mutterWindow.get_texture(), reactive: true }); - this._resizePreview(thumbnail); - - this._resizeId = mutterWindow.meta_window.connect('size-changed', - Lang.bind(this, this._queueResize)); - - this._destroyId = mutterWindow.connect('destroy', () => this.animateOutAndDestroy()); - } - - return thumbnail; - }, - - _queueResize: function () { - Main.queueDeferredWork(this._workId); - }, - - _resizePreview: function(preview) { - let [width, height] = preview.get_source().get_size(); - let scale = Math.min(this._thumbnailWidth / width, this._thumbnailHeight / height); - - preview.set_size(width * scale, height * scale); - preview.set_position((this._thumbnailWidth - preview.width) * .5, (this._thumbnailHeight - preview.height) * .5); - }, - - _onResize: function() { - if (!this.preview) { - return; - } - - this._resizePreview(this.preview); - }, - - _repositionCloseButton: function() { - let isLeftButtons = Meta.prefs_get_button_layout().left_buttons.indexOf(Meta.ButtonFunction.CLOSE) >= 0; - - if (this._isLeftButtons !== isLeftButtons) { - let padding = this._dtpSettings.get_int('window-preview-padding'); - let halfButton = this._closeButton.width * .5; //button is a square - let xInset = 4; - let buttonX; - - if (isLeftButtons) { - buttonX = Math.max(this.preview.x - halfButton + xInset, -padding); - } else { - buttonX = this.preview.x + this.preview.width - halfButton - Math.max(xInset, halfButton - this.preview.x - padding); - } - - this._closeButton.set_position(buttonX, Math.max(this.preview.y - halfButton, -padding)); - this._isLeftButtons = isLeftButtons; - } - }, - - _closeWindow: function() { - let topMenu = this._getTopMenu(); - if(topMenu._peekModeEnterTimeoutId) { - Mainloop.source_remove(topMenu._peekModeEnterTimeoutId); - topMenu._peekModeEnterTimeoutId = null; - } - - this.window.delete(global.get_current_time()); - }, - - show: function(animate) { - let fullWidth = this.actor.get_width(); - - this.actor.opacity = 0; - this.actor.set_width(0); - - let time = animate ? Taskbar.DASH_ANIMATION_TIME : 0; - Tweener.addTween(this.actor, - { opacity: 255, - width: fullWidth, - time: time, - transition: 'easeInOutQuad' - }); - }, - - animateOutAndDestroy: function() { - if (!this.animatingOut) { - this.animatingOut = true; - this._hideCloseButton(); - Tweener.addTween(this.actor, - { width: 0, - opacity: 0, - time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: Lang.bind(this, function() { - this.destroy(); - }) - }); - } - }, - - activate: function() { - let topMenu = this._getTopMenu(); - - if(topMenu._dtpSettings.get_boolean('peek-mode')) { - if(topMenu._peekMode) { - topMenu._disablePeekMode(); - } - else if(topMenu._peekModeEnterTimeoutId) { - Mainloop.source_remove(topMenu._peekModeEnterTimeoutId); - topMenu._peekModeEnterTimeoutId = null; - } - } - - topMenu.close(~0); - - Main.activateWindow(this.window); - }, - - _onMotionEvent: function() { - //If in normal mode, then set new timeout for entering peek mode after removing the old one - let topMenu = this._getTopMenu(); - if(topMenu._dtpSettings.get_boolean('peek-mode')) { - if(!topMenu._peekMode && !this.animatingOut) { - if(topMenu._peekModeEnterTimeoutId) - Mainloop.source_remove(topMenu._peekModeEnterTimeoutId); - topMenu._peekModeEnterTimeoutId = Mainloop.timeout_add(topMenu._dtpSettings.get_int('enter-peek-mode-timeout'), Lang.bind(this, function() { - topMenu._enterPeekMode(this); - })); - } - } - }, - - _onButtonReleaseEvent: function(actor, event) { - this.actor.remove_style_pseudo_class ('active'); - switch (event.get_button()) { - case 1: - // Left click - this.activate(event); - break; - case 2: - // Middle click - if (this._dtpSettings.get_boolean('preview-middle-click-close')) { - this._closeWindow(); - } - break; - case 3: - // Right click - this.showContextMenu(event); - break; - } - return Clutter.EVENT_STOP; - }, - - showContextMenu: function(event) { - let coords = event.get_coords(); - this._previewMenuPopupManager.showWindowMenuForWindow({ - x: coords[0], - y: coords[1], - width: 0, - height: 0 - }); - }, - - destroy: function() { - if (this._titleNotifyId) { - this.window.disconnect(this._titleNotifyId); - this._titleNotifyId = 0; - } - - let mutterWindow = this.window.get_compositor_private(); - - if (mutterWindow) { - if(this._resizeId) { - mutterWindow.meta_window.disconnect(this._resizeId); - } - - if(this._destroyId) { - mutterWindow.disconnect(this._destroyId); - } - } - - this.callParent('destroy'); - } -}); - -var thumbnailPreviewList = Utils.defineClass({ - Name: 'DashToPanel.ThumbnailPreviewList', - Extends: PopupMenu.PopupMenuSection, - - _init: function(app, source, settings) { - this._dtpSettings = settings; - - this.callParent('_init'); - - this._ensurePreviewVisibilityTimeoutId = 0; - - this.actor = new St.ScrollView({ name: 'dashtopanelThumbnailScrollview', - hscrollbar_policy: Gtk.PolicyType.NEVER, - vscrollbar_policy: Gtk.PolicyType.NEVER, - enable_mouse_scrolling: true }); - - this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent )); - - this.box.set_vertical(false); - this.box.set_name("dashtopanelThumbnailList"); - this.actor.add_actor(this.box); - this.actor._delegate = this; - - this._shownInitially = false; - - this.app = app; - this._source = source; - - this._redisplayId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay)); - this._scrollbarId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._showHideScrollbar)); - - this.actor.connect('destroy', Lang.bind(this, this._onDestroy)); - - this._dtpSettingsSignalIds = [ - this._dtpSettings.connect('changed::window-preview-width', () => this._resetPreviews()), - this._dtpSettings.connect('changed::window-preview-height', () => this._resetPreviews()), - this._dtpSettings.connect('changed::window-preview-show-title', () => this._resetPreviews()), - this._dtpSettings.connect('changed::window-preview-padding', () => this._resetPreviews()) - ]; - - this._stateChangedId = this._source.window ? 0 : - this.app.connect('windows-changed', Lang.bind(this, this._queueRedisplay)); - }, - - _needsScrollbar: function() { - let topMenu = this._getTopMenu(); - let [topMinWidth, topNaturalWidth] = topMenu.actor.get_preferred_width(-1); - let topThemeNode = topMenu.actor.get_theme_node(); - - let topMaxWidth = topThemeNode.get_max_width(); - return topMaxWidth >= 0 && topNaturalWidth >= topMaxWidth; - }, - - _showHideScrollbar: function() { - let needsScrollbar = this._needsScrollbar(); - - // St.ScrollView always requests space vertically for a possible horizontal - // scrollbar if in AUTOMATIC mode. 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. - - this.actor.hscrollbar_policy = - needsScrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER; - - if (needsScrollbar) - this.actor.add_style_pseudo_class('scrolled'); - else - this.actor.remove_style_pseudo_class('scrolled'); - }, - - _queueScrollbar: function () { - Main.queueDeferredWork(this._scrollbarId); - }, - - _queueRedisplay: function () { - Main.queueDeferredWork(this._redisplayId); - }, - - _onScrollEvent: function(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; - - // reset timeout to avid conflicts with the mousehover event - if (this._ensurePreviewVisibilityTimeoutId>0) { - Mainloop.source_remove(this._ensurePreviewVisibilityTimeoutId); - this._ensurePreviewVisibilityTimeoutId = 0; - } - - // Skip to avoid double events mouse - if (event.is_pointer_emulated()) - return Clutter.EVENT_STOP; - - let adjustment, delta; - - adjustment = this.actor.get_hscroll_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: function() { - for (let i = 0; i < this._dtpSettingsSignalIds.length; ++i) { - this._dtpSettings.disconnect(this._dtpSettingsSignalIds[i]); - } - - if (this._stateChangedId) { - this.app.disconnect(this._stateChangedId); - this._stateChangedId = 0; - } - }, - - _createPreviewItem: function(window) { - let preview = new thumbnailPreview(window, this._dtpSettings); - - preview.actor.connect('notify::hover', Lang.bind(this, function() { - if (preview.actor.hover){ - this._ensurePreviewVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function(){ - Taskbar.ensureActorVisibleInScrollView(this.actor, preview.actor); - this._ensurePreviewVisibilityTimeoutId = 0; - return GLib.SOURCE_REMOVE; - })); - } else { - if (this._ensurePreviewVisibilityTimeoutId>0) { - Mainloop.source_remove(this._ensurePreviewVisibilityTimeoutId); - this._ensurePreviewVisibilityTimeoutId = 0; - } - } - })); - - preview.actor.connect('key-focus-in', - Lang.bind(this, function(actor) { - - let [x_shift, y_shift] = Taskbar.ensureActorVisibleInScrollView(this.actor, actor); - })); - - return preview; - }, - - _resetPreviews: function() { - let previews = this._getPreviews(); - let l = previews.length; - - if (l > 0) { - for (let i = 0; i < l; ++i) { - previews[i]._delegate.animateOutAndDestroy(); - } - - this._queueRedisplay(); - } - }, - - _getPreviews: function() { - return this.box.get_children().filter(function(actor) { - return actor._delegate.window && - actor._delegate.preview && - !actor._delegate.animatingOut; - }); - }, - - _redisplay: function () { - let windows = this._source.window ? [this._source.window] : - AppIcons.getInterestingWindows(this.app, this._dtpSettings, this._source.panelWrapper.monitor).sort(this.sortWindowsCompareFunction); - let children = this._getPreviews(); - // Apps currently in the taskbar - let oldWin = children.map(function(actor) { - return actor._delegate.window; - }); - // Apps supposed to be in the taskbar - let newWin = windows; - - let addedItems = []; - let removedActors = []; - - let newIndex = 0; - let oldIndex = 0; - - while (newIndex < newWin.length || oldIndex < oldWin.length) { - // 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; - } - - // No change at oldIndex/newIndex - if (oldWin[oldIndex] == newWin[newIndex]) { - oldIndex++; - 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]; - item._delegate.animateOutAndDestroy(); - } - - // 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); - } - - this._queueScrollbar(); - - // 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 (windows.length < 1) { - this._getTopMenu().close(~0); - } - }, - - isAnimatingOut: function() { - return this.actor.get_children().reduce(function(result, actor) { - return result || actor.animatingOut; - }, false); - }, - - sortWindowsCompareFunction: function(windowA, windowB) { - return windowA.get_stable_sequence() > windowB.get_stable_sequence(); - } -}); - -var previewMenuPopup = Utils.defineClass({ - Name: 'previewMenuPopup', - Extends: WindowMenu.WindowMenu, - ParentConstrParams: [[0], [1]], - - _init: function(window, sourceActor) { - this.callParent('_init', window, sourceActor); - - let side = Taskbar.getPosition(); - this._arrowSide = side; - this._boxPointer._arrowSide = side; - this._boxPointer._userArrowSide = side; - } - - // Otherwise, just let the parent do its thing? -}); - -var previewMenuPopupManager = Utils.defineClass({ - Name: 'previewMenuPopupManagerTest', - - _init: function(window, source) { - this._manager = new PopupMenu.PopupMenuManager({ actor: Main.layoutManager.dummyCursor }); - - this._sourceActor = new St.Widget({ reactive: true, visible: false }); - this._sourceActor.connect('button-press-event', Lang.bind(this, - function() { - this._manager.activeMenu.toggle(); - })); - Main.uiGroup.add_actor(this._sourceActor); - - this.window = window; - }, - - showWindowMenuForWindow: function(rect) { - let menu = new previewMenuPopup(this.window, this._sourceActor); - let window = this.window; - - this._manager.addMenu(menu); - - menu.connect('activate', function() { - window.check_alive(global.get_current_time()); - }); - let destroyId = window.connect('unmanaged', - function() { - menu.close(); - }); - - this._sourceActor.set_size(Math.max(1, rect.width), Math.max(1, rect.height)); - this._sourceActor.set_position(rect.x, rect.y); - - this._sourceActor.show(); - - menu.open(BoxPointer.PopupAnimation.NONE); - menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false); - menu.connect('open-state-changed', Lang.bind(this, function(menu_, isOpen) { - if (isOpen) - return; - - this._sourceActor.hide(); - menu.destroy(); - window.disconnect(destroyId); - })); - } -}); +}); \ No newline at end of file From 228bd3bed4b9d8aef427210d58fbf73baa4f39a1 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 12 May 2019 23:03:48 -0400 Subject: [PATCH 02/61] 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 From 207cc5777207a76a97b4da7fa5b064f43d37c5ce Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 14 May 2019 17:08:08 -0400 Subject: [PATCH 03/61] Add initial window clones --- stylesheet.css | 3 +- windowPreview.js | 217 +++++++++++++++++++++++++++++++++++++---------- 2 files changed, 176 insertions(+), 44 deletions(-) diff --git a/stylesheet.css b/stylesheet.css index 05cb091..94981b7 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -41,8 +41,9 @@ padding-right: 8px; } -#dashtopanelThumbnailScrollview { +#dashtopanelPreviewScrollview { -st-hfade-offset: 48px; + -st-vfade-offset: 48px; } #dashtopanelScrollview .app-well-app:hover .overview-icon, diff --git a/windowPreview.js b/windowPreview.js index 2843c17..e08b6d0 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -15,6 +15,8 @@ * along with this program. If not, see . */ +const Clutter = imports.gi.Clutter; +const Gtk = imports.gi.Gtk; const Main = imports.ui.main; const Signals = imports.signals; const Shell = imports.gi.Shell; @@ -25,7 +27,6 @@ const Me = imports.misc.extensionUtils.getCurrentExtension(); const Taskbar = Me.imports.taskbar; const Utils = Me.imports.utils; -const TRANSLATION_OFFSET = 50; const MONITOR_PADDING = 10; //timeout intervals @@ -39,87 +40,140 @@ var PreviewMenu = Utils.defineClass({ Extends: St.Widget, _init: function(dtpSettings, panelWrapper) { - this.callParent('_init', { name: 'preview-menu', reactive: true }); + this.callParent('_init', { name: 'preview-menu', layout_manager: new Clutter.BinLayout(), reactive: true, track_hover: true }); this._dtpSettings = dtpSettings; this._panelWrapper = panelWrapper; 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; + let isLeftOrRight = this._position == St.Side.LEFT || this._position == St.Side.RIGHT; + this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y'); + this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), 40); + + this._box = new St.BoxLayout({ + vertical: isLeftOrRight, + clip_to_allocation: false, + x_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign.START + }); + + this._scrollView = new St.ScrollView({ + name: 'dashtopanelPreviewScrollview', + hscrollbar_policy: Gtk.PolicyType.NEVER, + vscrollbar_policy: Gtk.PolicyType.NEVER, + enable_mouse_scrolling: true + }); + + this._scrollView.add_actor(this._box); + this.add_child(this._scrollView); + //testing - this.set_style('background: #ff0000;') + //this._scrollView.set_style('padding: 10px;'); //TODO //'open-state-changed' //'menu-closed' //'sync-tooltip' //this.add_style_class_name('app-well-menu'); + + // this._titleWindowChangeId = this.window.connect('notify::title', + // Lang.bind(this, this._updateWindowTitle)); }, enable: function() { - this._signalsHandler = new Utils.GlobalSignalsHandler(); this._timeoutsHandler = new Utils.TimeoutsHandler(); - - this.visible = false; - this.opacity = 0; + this._signalsHandler = new Utils.GlobalSignalsHandler(); Main.uiGroup.insert_child_below(this, this._panelWrapper.panelBox); - - // this._signalsHandler.add( - // [ - - // ], - // ); + Main.layoutManager._trackActor(this, { affectsStruts: false, trackFullscreen: true }); + this._resetHiddenState(); + + this._signalsHandler.add( + [ + this, + 'notify::hover', + () => this._onHoverChanged() + ], + ); }, disable: function() { - this._signalsHandler.destroy(); this._timeoutsHandler.destroy(); + this._signalsHandler.destroy(); this.close(true); + + Main.layoutManager._untrackActor(this); Main.uiGroup.remove_child(this); }, requestOpen: function(appIcon) { this._endOpenCloseTimeouts(); - - if (this._currentAppIcon) { - return this.open(appIcon); - } - this._timeoutsHandler.add([T1, this._dtpSettings.get_int('show-window-previews-timeout'), () => this.open(appIcon)]); }, requestClose: function() { this._endOpenCloseTimeouts(); - this._timeoutsHandler.add([T2, this._dtpSettings.get_int('leave-timeout'), () => this.close()]); + this._addCloseTimeout(); }, open: function(appIcon) { this._currentAppIcon = appIcon; + this.updateWindows(appIcon); this._updatePosition(); - this.show(); + this.visible = true; this._animateOpenOrClose(true); }, close: function(immediate) { this._currentAppIcon = null; - if (this.visible) { - this._animateOpenOrClose(false, immediate, () => { - this.hide(); - }); + if (immediate) { + this._resetHiddenState(); + } else { + this._animateOpenOrClose(false, () => this._resetHiddenState()); } }, updateWindows: function(appIcon, windows) { if (this._currentAppIcon == appIcon) { + windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); + let currentPreviews = this._box.get_children(); + + for (let i = 0, l = currentPreviews.length; i < l; ++i) { + if (Taskbar.findIndex(windows, w => w == currentPreviews[i].window) < 0) { + this._box.remove_child(currentPreviews[i]); + // currentPreviews[i]._animatingOut = 1; + // Tweener.addTween(currentPreviews[i], { + // width: 0, + // opacity: 0, + // time: Taskbar.DASH_ANIMATION_TIME, + // transition: 'easeInOutQuad', + // onComplete: () => this._box.remove_child(currentPreviews[i]) + // }) + } + } + + for (let i = 0, l = windows.length; i < l; ++i) { + let currentPosition = Taskbar.findIndex(currentPreviews, cp => cp.window == windows[i]); + let preview; + + if (currentPosition == i) { + continue; + } else if (currentPosition < 0) { + preview = new Preview(windows[i]); + preview.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor + 'padding: 10px;'); + } else { + preview = currentPreviews[currentPosition]; + } + + this._box.insert_child_at_index(preview, i); + } } }, @@ -127,16 +181,35 @@ var PreviewMenu = Utils.defineClass({ return this._currentAppIcon; }, - vfunc_allocate: function(box, flags) { - this.set_allocation(box, flags); - }, + // vfunc_allocate: function(box, flags) { + // this.callParent('vfunc_allocate', box, flags); + // this._scrollView.set_clip(0, 0, box.x2 - box.x1, box.y2 - box.y1 - this.translation_y); + // }, vfunc_get_preferred_width: function(forHeight) { - return [0, 300]; + let [, width] = St.Widget.prototype.vfunc_get_preferred_width.call(this, forHeight); + let maxWidth = this._panelWrapper.monitor.width - MONITOR_PADDING * 2; + + return [0, Math.min(width, maxWidth)]; }, vfunc_get_preferred_height: function(forWidth) { - return [0, 200]; + let [, height] = St.Widget.prototype.vfunc_get_preferred_height.call(this, forWidth); + let maxHeight = this._panelWrapper.monitor.height - MONITOR_PADDING * 2; + + return [0, Math.min(height, maxHeight)]; + }, + + _addCloseTimeout: function() { + this._timeoutsHandler.add([T2, this._dtpSettings.get_int('leave-timeout'), () => this.close()]); + }, + + _onHoverChanged: function() { + this._endOpenCloseTimeouts(); + + if (!this.hover) { + this._addCloseTimeout(); + } }, _endOpenCloseTimeouts: function() { @@ -144,15 +217,26 @@ var PreviewMenu = Utils.defineClass({ this._timeoutsHandler.remove(T2); }, + _resetHiddenState: function() { + this.visible = false; + this.opacity = 0; + this[this._translationProp] = this._translationOffset; + //this._box.remove_all_children(); + }, + _updatePosition: function() { 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 removedChildren = this._box.get_children().filter(c => c._animatingOut); + //let excessWidth = 0; let x, y; + + //removedChildren.forEach(rc => excessWidth += rc.width); if (this._position == St.Side.TOP || this._position == St.Side.BOTTOM) { - x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * .5 - natWidth * .5; + x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * .5 - natWidth * .5 /*+ excessWidth * .5*/; } else if (this._position == St.Side.LEFT) { x = sourceAllocation.x2; } else { //St.Side.RIGHT @@ -170,9 +254,9 @@ var PreviewMenu = Utils.defineClass({ x = Math.max(x, this._panelWrapper.monitor.x + MONITOR_PADDING); y = Math.max(y, this._panelWrapper.monitor.y + MONITOR_PADDING); - if (this[this._translationProp] > 0) { + if (this[this._translationProp] != 0) { this.set_position(x, y); - this[this._translationProp] = TRANSLATION_OFFSET; + this[this._translationProp] = this._translationOffset; } else { Tweener.addTween(this, { x: x, y: y, @@ -182,19 +266,66 @@ var PreviewMenu = Utils.defineClass({ } }, - _animateOpenOrClose: function(show, immediate, onComplete) { + _animateOpenOrClose: function(show, onComplete) { + let isTranslationAnimation = this[this._translationProp] !=0; let tweenOpts = { opacity: show ? 255 : 0, - time: immediate ? 0 : Taskbar.DASH_ANIMATION_TIME, - transition: show ? 'easeInOutQuad' : 'easeInCubic' + time: Taskbar.DASH_ANIMATION_TIME, + transition: show ? 'easeInOutQuad' : 'easeInCubic', + onComplete: () => { + if (isTranslationAnimation) { + Main.layoutManager._queueUpdateRegions(); + } + + (onComplete || (() => {}))(); + } }; - tweenOpts[this._translationProp] = show ? 0 : TRANSLATION_OFFSET; - - if (onComplete) { - tweenOpts.onComplete = onComplete; - } + tweenOpts[this._translationProp] = show ? 0 : this._translationOffset; Tweener.addTween(this, tweenOpts); }, +}); + +var Preview = Utils.defineClass({ + Name: 'DashToPanel.Preview', + Extends: St.Widget, + + _init: function(window) { + this.callParent('_init', { name: 'preview-menu', reactive: true }); + + this.window = window; + this.add_actor(this.getThumbnail()); + + // this._windowTitle = new St.Label({ + // y_align: Clutter.ActorAlign.CENTER, + // x_align: Clutter.ActorAlign.START, + // style_class: 'overview-label' + // }); + }, + + getThumbnail: function() { + let clone = null; + let mutterWindow = this.window.get_compositor_private(); + + if (mutterWindow) { + clone = new Clutter.Clone ({ source: mutterWindow.get_texture(), reactive: true }); + this._resize(clone); + + // this._resizeId = mutterWindow.meta_window.connect('size-changed', + // Lang.bind(this, this._queueResize)); + + // this._destroyId = mutterWindow.connect('destroy', () => this.animateOutAndDestroy()); + } + + return clone; + }, + + _resize: function(clone) { + let [width, height] = clone.get_source().get_size(); + //let scale = Math.min(this._thumbnailWidth / width, this._thumbnailHeight / height); + + clone.set_size(200, 150); + clone.set_position(10, 10); + }, }); \ No newline at end of file From b2bbf7b55e24a37aab5b954fb226deda58567fbc Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 14 May 2019 20:13:01 -0400 Subject: [PATCH 04/61] Add initial preview animations --- utils.js | 10 ++++ windowPreview.js | 137 ++++++++++++++++++++++++++++------------------- 2 files changed, 92 insertions(+), 55 deletions(-) diff --git a/utils.js b/utils.js index 14a6163..da67fcd 100644 --- a/utils.js +++ b/utils.js @@ -270,6 +270,16 @@ var DisplayWrapper = { } }; +var mergeObjects = function(main, bck) { + for (var prop in bck) { + if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { + main[prop] = bck[prop]; + } + } + + return main; +}; + var hookVfunc = function(proto, symbol, func) { if (Gi.hook_up_vfunc_symbol) { //gjs > 1.53.3 diff --git a/windowPreview.js b/windowPreview.js index e08b6d0..800e1d6 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -122,9 +122,11 @@ var PreviewMenu = Utils.defineClass({ }, open: function(appIcon) { + let isHidden = this[this._translationProp] != 0; + this._currentAppIcon = appIcon; - this.updateWindows(appIcon); - this._updatePosition(); + this.updateWindows(appIcon, null, isHidden); + this._updatePosition(isHidden); this.visible = true; this._animateOpenOrClose(true); }, @@ -139,40 +141,23 @@ var PreviewMenu = Utils.defineClass({ } }, - updateWindows: function(appIcon, windows) { - if (this._currentAppIcon == appIcon) { - windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); + updateWindows: function(appIcon, windows, immediate) { + if (this._currentAppIcon != appIcon) { + return; + } - let currentPreviews = this._box.get_children(); + windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); + + let currentPreviews = this._box.get_children(); + let l = Math.max(windows.length, currentPreviews.length); - for (let i = 0, l = currentPreviews.length; i < l; ++i) { - if (Taskbar.findIndex(windows, w => w == currentPreviews[i].window) < 0) { - this._box.remove_child(currentPreviews[i]); - // currentPreviews[i]._animatingOut = 1; - // Tweener.addTween(currentPreviews[i], { - // width: 0, - // opacity: 0, - // time: Taskbar.DASH_ANIMATION_TIME, - // transition: 'easeInOutQuad', - // onComplete: () => this._box.remove_child(currentPreviews[i]) - // }) - } - } - - for (let i = 0, l = windows.length; i < l; ++i) { - let currentPosition = Taskbar.findIndex(currentPreviews, cp => cp.window == windows[i]); - let preview; - - if (currentPosition == i) { - continue; - } else if (currentPosition < 0) { - preview = new Preview(windows[i]); - preview.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor + 'padding: 10px;'); - } else { - preview = currentPreviews[currentPosition]; - } - - this._box.insert_child_at_index(preview, i); + for (let i = 0; i < l; ++i) { + if (currentPreviews[i] && windows[i] && windows[i] != currentPreviews[i].window) { + currentPreviews[i].assignWindow(windows[i]); + } else if (!currentPreviews[i]) { + this._box.add_child(new Preview(this._panelWrapper, this, windows[i])); + } else if (!windows[i]) { + currentPreviews[i][immediate ? 'destroy' : 'animateOut'](); } } }, @@ -221,22 +206,22 @@ var PreviewMenu = Utils.defineClass({ this.visible = false; this.opacity = 0; this[this._translationProp] = this._translationOffset; - //this._box.remove_all_children(); + this._box.get_children().forEach(c => c.destroy()); }, - _updatePosition: function() { + _updatePosition: function(immediate) { 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 removedChildren = this._box.get_children().filter(c => c._animatingOut); - //let excessWidth = 0; + let removedChildren = this._box.get_children().filter(c => c.animatingOut); + let excessWidth = 0; let x, y; - //removedChildren.forEach(rc => excessWidth += rc.width); + removedChildren.forEach(rc => excessWidth += rc.width); if (this._position == St.Side.TOP || this._position == St.Side.BOTTOM) { - x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * .5 - natWidth * .5 /*+ excessWidth * .5*/; + x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * .5 - natWidth * .5 + excessWidth * .5; } else if (this._position == St.Side.LEFT) { x = sourceAllocation.x2; } else { //St.Side.RIGHT @@ -254,15 +239,11 @@ var PreviewMenu = Utils.defineClass({ x = Math.max(x, this._panelWrapper.monitor.x + MONITOR_PADDING); y = Math.max(y, this._panelWrapper.monitor.y + MONITOR_PADDING); - if (this[this._translationProp] != 0) { + if (immediate) { this.set_position(x, y); this[this._translationProp] = this._translationOffset; } else { - Tweener.addTween(this, { - x: x, y: y, - time: Taskbar.DASH_ANIMATION_TIME, - transition: 'easeInOutQuad' - }); + Tweener.addTween(this, getTweenOpts({ x: x, y: y })); } }, @@ -270,7 +251,6 @@ var PreviewMenu = Utils.defineClass({ let isTranslationAnimation = this[this._translationProp] !=0; let tweenOpts = { opacity: show ? 255 : 0, - time: Taskbar.DASH_ANIMATION_TIME, transition: show ? 'easeInOutQuad' : 'easeInCubic', onComplete: () => { if (isTranslationAnimation) { @@ -283,7 +263,7 @@ var PreviewMenu = Utils.defineClass({ tweenOpts[this._translationProp] = show ? 0 : this._translationOffset; - Tweener.addTween(this, tweenOpts); + Tweener.addTween(this, getTweenOpts(tweenOpts)); }, }); @@ -291,11 +271,21 @@ var Preview = Utils.defineClass({ Name: 'DashToPanel.Preview', Extends: St.Widget, - _init: function(window) { + _init: function(panelWrapper, previewMenu, window) { this.callParent('_init', { name: 'preview-menu', reactive: true }); - this.window = window; - this.add_actor(this.getThumbnail()); + this._panelWrapper = panelWrapper; + this._previewMenu = previewMenu; + this.animatingOut = false; + + this.titleBox = new St.BoxLayout({ }); + this.add_actor(this.titleBox) + + this.previewBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this.add_actor(this.previewBin); + + this.assignWindow(window); + this.set_style('background: ' + panelWrapper.dynamicTransparency.currentBackgroundColor + 'padding: 10px;'); // this._windowTitle = new St.Label({ // y_align: Clutter.ActorAlign.CENTER, @@ -304,12 +294,40 @@ var Preview = Utils.defineClass({ // }); }, - getThumbnail: function() { + assignWindow: function(window) { + this.window = window; + + let clone = this._getWindowClone(); + + this.previewBin.get_children().forEach(c => Tweener.addTween(c, getTweenOpts({ scale_x: .9, scale_y: .9 }))); + this.previewBin.add_child(clone); + + Tweener.addTween( + clone, + getTweenOpts({ + opacity: 255, + onComplete: () => this.previewBin.get_children().filter(c => c != clone).forEach(c => c.destroy()) + }) + ); + }, + + animateOut: function() { + let isLeftOrRight = this._previewMenu._position == St.Side.LEFT || this._previewMenu._position == St.Side.RIGHT; + let tweenOpts = getTweenOpts({ onComplete: () => this.destroy() }); + + tweenOpts[isLeftOrRight ? 'height' : 'width'] = 0; + this.animatingOut = true; + + Tweener.addTween(this, tweenOpts); + }, + + _getWindowClone: function() { let clone = null; let mutterWindow = this.window.get_compositor_private(); if (mutterWindow) { - clone = new Clutter.Clone ({ source: mutterWindow.get_texture(), reactive: true }); + clone = new Clutter.Clone({ source: mutterWindow, reactive: true, opacity: 0 }); + clone.set_pivot_point(0.5, 0.5); this._resize(clone); // this._resizeId = mutterWindow.meta_window.connect('size-changed', @@ -325,7 +343,16 @@ var Preview = Utils.defineClass({ let [width, height] = clone.get_source().get_size(); //let scale = Math.min(this._thumbnailWidth / width, this._thumbnailHeight / height); - clone.set_size(200, 150); + clone.set_size(200, 160); clone.set_position(10, 10); }, -}); \ No newline at end of file +}); + +function getTweenOpts(opts) { + let defaults = { + time: Taskbar.DASH_ANIMATION_TIME, + transition: 'easeInOutQuad' + }; + + return Utils.mergeObjects(opts || {}, defaults); +} \ No newline at end of file From 4e2f757e2fadf2931cc23afa3d2113de25d21702 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Wed, 15 May 2019 17:02:18 -0400 Subject: [PATCH 05/61] Add window clones scaling --- ...shell.extensions.dash-to-panel.gschema.xml | 5 + stylesheet.css | 4 +- windowPreview.js | 290 +++++++++++------- 3 files changed, 194 insertions(+), 105 deletions(-) diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index ddeaf68..cc5afac 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -410,6 +410,11 @@ Display title in preview Display window title in preview + + false + Use previews fixed size + Previews always have the same size or they scale to the aspect ratio of their window clone + 350 Window previews width diff --git a/stylesheet.css b/stylesheet.css index 94981b7..de04d88 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -42,8 +42,8 @@ } #dashtopanelPreviewScrollview { - -st-hfade-offset: 48px; - -st-vfade-offset: 48px; + -st-hfade-offset: 24px; + -st-vfade-offset: 24px; } #dashtopanelScrollview .app-well-app:hover .overview-icon, diff --git a/windowPreview.js b/windowPreview.js index 800e1d6..957f639 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -27,8 +27,6 @@ const Me = imports.misc.extensionUtils.getCurrentExtension(); const Taskbar = Me.imports.taskbar; const Utils = Me.imports.utils; -const MONITOR_PADDING = 10; - //timeout intervals //timeout names @@ -49,14 +47,9 @@ var PreviewMenu = Utils.defineClass({ this._position = Taskbar.getPosition(); let isLeftOrRight = this._position == St.Side.LEFT || this._position == St.Side.RIGHT; this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y'); - this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), 40); + this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), 40) * (this._position == St.Side.TOP || this._position == St.Side.LEFT ? -1 : 1); - this._box = new St.BoxLayout({ - vertical: isLeftOrRight, - clip_to_allocation: false, - x_align: Clutter.ActorAlign.START, - y_align: Clutter.ActorAlign.START - }); + this._box = new St.BoxLayout({ vertical: isLeftOrRight, clip_to_allocation: false }); this._scrollView = new St.ScrollView({ name: 'dashtopanelPreviewScrollview', @@ -71,17 +64,12 @@ var PreviewMenu = Utils.defineClass({ - //testing - //this._scrollView.set_style('padding: 10px;'); //TODO //'open-state-changed' //'menu-closed' //'sync-tooltip' //this.add_style_class_name('app-well-menu'); - - // this._titleWindowChangeId = this.window.connect('notify::title', - // Lang.bind(this, this._updateWindowTitle)); }, enable: function() { @@ -91,6 +79,8 @@ var PreviewMenu = Utils.defineClass({ Main.uiGroup.insert_child_below(this, this._panelWrapper.panelBox); Main.layoutManager._trackActor(this, { affectsStruts: false, trackFullscreen: true }); this._resetHiddenState(); + + this.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor ); this._signalsHandler.add( [ @@ -98,6 +88,11 @@ var PreviewMenu = Utils.defineClass({ 'notify::hover', () => this._onHoverChanged() ], + [ + this._scrollView, + 'scroll-event', + this._onScrollEvent.bind(this) + ] ); }, @@ -122,13 +117,15 @@ var PreviewMenu = Utils.defineClass({ }, open: function(appIcon) { - let isHidden = this[this._translationProp] != 0; + if (this._currentAppIcon != appIcon) { + let isHidden = this[this._translationProp] != 0; - this._currentAppIcon = appIcon; - this.updateWindows(appIcon, null, isHidden); - this._updatePosition(isHidden); - this.visible = true; - this._animateOpenOrClose(true); + this._currentAppIcon = appIcon; + this.updateWindows(appIcon, null, isHidden); + this._updatePosition(isHidden); + this.visible = true; + this._animateOpenOrClose(true); + } }, close: function(immediate) { @@ -142,22 +139,21 @@ var PreviewMenu = Utils.defineClass({ }, updateWindows: function(appIcon, windows, immediate) { - if (this._currentAppIcon != appIcon) { - return; - } - - windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); + if (this._currentAppIcon == appIcon) { + windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); - let currentPreviews = this._box.get_children(); - let l = Math.max(windows.length, currentPreviews.length); + let currentPreviews = this._box.get_children(); + let l = Math.max(windows.length, currentPreviews.length); + let ii = 0; - for (let i = 0; i < l; ++i) { - if (currentPreviews[i] && windows[i] && windows[i] != currentPreviews[i].window) { - currentPreviews[i].assignWindow(windows[i]); - } else if (!currentPreviews[i]) { - this._box.add_child(new Preview(this._panelWrapper, this, windows[i])); - } else if (!windows[i]) { - currentPreviews[i][immediate ? 'destroy' : 'animateOut'](); + for (let i = 0; i < l; ++i) { + if (currentPreviews[i] && windows[i] && windows[i] != currentPreviews[i].window) { + currentPreviews[i].assignWindow(windows[i]); + } else if (!currentPreviews[i]) { + this._box.add_child(new Preview(this._panelWrapper, this, windows[i])); + } else if (!windows[i]) { + currentPreviews[i][++ii > 3 || immediate ? 'destroy' : 'animateOut'](); + } } } }, @@ -166,23 +162,16 @@ var PreviewMenu = Utils.defineClass({ return this._currentAppIcon; }, - // vfunc_allocate: function(box, flags) { - // this.callParent('vfunc_allocate', box, flags); - // this._scrollView.set_clip(0, 0, box.x2 - box.x1, box.y2 - box.y1 - this.translation_y); - // }, - vfunc_get_preferred_width: function(forHeight) { let [, width] = St.Widget.prototype.vfunc_get_preferred_width.call(this, forHeight); - let maxWidth = this._panelWrapper.monitor.width - MONITOR_PADDING * 2; - return [0, Math.min(width, maxWidth)]; + return [0, Math.min(width, this._panelWrapper.monitor.width)]; }, vfunc_get_preferred_height: function(forWidth) { let [, height] = St.Widget.prototype.vfunc_get_preferred_height.call(this, forWidth); - let maxHeight = this._panelWrapper.monitor.height - MONITOR_PADDING * 2; - return [0, Math.min(height, maxHeight)]; + return [0, Math.min(height, this._panelWrapper.monitor.height)]; }, _addCloseTimeout: function() { @@ -197,6 +186,33 @@ var PreviewMenu = Utils.defineClass({ } }, + _onScrollEvent: function(actor, event) { + if (!event.is_pointer_emulated()) { + let adjustment = this._scrollView.get_hscroll_bar().get_adjustment(); + let increment = adjustment.step_increment; + let delta; + + 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; + }, + _endOpenCloseTimeouts: function() { this._timeoutsHandler.remove(T1); this._timeoutsHandler.remove(T2); @@ -210,43 +226,68 @@ var PreviewMenu = Utils.defineClass({ }, _updatePosition: function(immediate) { + let monitorArea = Main.layoutManager.getWorkAreaForMonitor(this._panelWrapper.monitor.index); 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 removedChildren = this._box.get_children().filter(c => c.animatingOut); - let excessWidth = 0; + let [ , , natWidth, natHeight] = this.get_preferred_size(); + let isLeftOrRight = this._position == St.Side.LEFT || this._position == St.Side.RIGHT; + let [previewsWidth, previewsHeight] = this._getPreviewsSize(isLeftOrRight); let x, y; - - removedChildren.forEach(rc => excessWidth += rc.width); + previewsWidth = Math.min(previewsWidth, monitorArea.width); + previewsHeight = Math.min(previewsHeight, monitorArea.height); + if (this._position == St.Side.TOP || this._position == St.Side.BOTTOM) { - x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * .5 - natWidth * .5 + excessWidth * .5; + x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * .5 - previewsWidth * .5 ; + x = Math.max(x, monitorArea.x); + x = Math.min(x, monitorArea.x + monitorArea.width - previewsWidth); } else if (this._position == St.Side.LEFT) { x = sourceAllocation.x2; } else { //St.Side.RIGHT - x = sourceAllocation.x1 - natWidth; + x = sourceAllocation.x1 - previewsWidth; } - if (this._position == St.Side.LEFT || this._position == St.Side.RIGHT) { - y = sourceAllocation.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * .5 - natHeight * .5; + if (isLeftOrRight) { + y = sourceAllocation.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * .5 - previewsHeight * .5; + y = Math.max(y, monitorArea.y); + y = Math.min(y, monitorArea.y + monitorArea.height - previewsHeight); } else if (this._position == St.Side.TOP) { y = sourceAllocation.y2; } else { //St.Side.BOTTOM - y = sourceAllocation.y1 - natHeight; + y = sourceAllocation.y1 - previewsHeight; } - x = Math.max(x, this._panelWrapper.monitor.x + MONITOR_PADDING); - y = Math.max(y, this._panelWrapper.monitor.y + MONITOR_PADDING); - - if (immediate) { + if (immediate || Math.abs(this.x - x) > 320 || + (!isLeftOrRight && this.x + natWidth > monitorArea.x + monitorArea.width) || + (isLeftOrRight && this.y + natHeight > monitorArea.y + monitorArea.height)) { this.set_position(x, y); - this[this._translationProp] = this._translationOffset; } else { Tweener.addTween(this, getTweenOpts({ x: x, y: y })); } }, + _getPreviewsSize: function(isLeftOrRight) { + let previewsWidth = 0; + let previewsHeight = 0; + + this._box.get_children().forEach(c => { + if (!c.animatingOut) { + let [width, height] = c.getSize(); + + if (isLeftOrRight) { + previewsWidth = width; + previewsHeight += height; + } else { + previewsWidth += width; + previewsHeight = height; + } + } + }); + + return [previewsWidth, previewsHeight]; + }, + _animateOpenOrClose: function(show, onComplete) { let isTranslationAnimation = this[this._translationProp] !=0; let tweenOpts = { @@ -272,85 +313,128 @@ var Preview = Utils.defineClass({ Extends: St.Widget, _init: function(panelWrapper, previewMenu, window) { - this.callParent('_init', { name: 'preview-menu', reactive: true }); + this.callParent('_init', { style_class: 'preview-menu', reactive: true }); this._panelWrapper = panelWrapper; this._previewMenu = previewMenu; + this._padding = previewMenu._dtpSettings.get_int('window-preview-padding'); this.animatingOut = false; - this.titleBox = new St.BoxLayout({ }); - this.add_actor(this.titleBox) + this._titleBox = new St.BoxLayout({ }); - this.previewBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); - this.add_actor(this.previewBin); + this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, style_class: 'preview-label' }); + + this._titleBox.add_child(this._windowTitle); + + this.add_actor(this._titleBox) + + this._previewBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + + this._previewBin.set_style('padding: ' + this._padding + 'px'); + this._resizeBin(); + this.add_actor(this._previewBin); this.assignWindow(window); - this.set_style('background: ' + panelWrapper.dynamicTransparency.currentBackgroundColor + 'padding: 10px;'); - - // this._windowTitle = new St.Label({ - // y_align: Clutter.ActorAlign.CENTER, - // x_align: Clutter.ActorAlign.START, - // style_class: 'overview-label' - // }); }, assignWindow: function(window) { - this.window = window; + let clone = this._getWindowClone(window); - let clone = this._getWindowClone(); - - this.previewBin.get_children().forEach(c => Tweener.addTween(c, getTweenOpts({ scale_x: .9, scale_y: .9 }))); - this.previewBin.add_child(clone); - - Tweener.addTween( - clone, - getTweenOpts({ - opacity: 255, - onComplete: () => this.previewBin.get_children().filter(c => c != clone).forEach(c => c.destroy()) - }) - ); + this._resizeClone(clone); + this._removeCurrentClone(clone); + this._previewBin.add_child(clone); + + Tweener.addTween(clone, getTweenOpts({ opacity: 255 })); }, animateOut: function() { - let isLeftOrRight = this._previewMenu._position == St.Side.LEFT || this._previewMenu._position == St.Side.RIGHT; - let tweenOpts = getTweenOpts({ onComplete: () => this.destroy() }); + let tweenOpts = getTweenOpts({ opacity: 0, onComplete: () => this.destroy() }); - tweenOpts[isLeftOrRight ? 'height' : 'width'] = 0; + tweenOpts[this._checkIfLeftOrRight() ? 'height' : 'width'] = 0; this.animatingOut = true; Tweener.addTween(this, tweenOpts); }, + + getSize: function() { + let [binWidth, binHeight] = this._getBinSize(); + let currentClone = this._previewBin.get_last_child(); + + binWidth = Math.max(binWidth, currentClone.width + this._padding * 2); + binHeight = Math.max(binHeight, currentClone.height + this._padding * 2); + + return [binWidth, binHeight]; + }, + + _removeCurrentClone: function(newClone) { + this._previewBin.get_children().forEach(c =>{ + Tweener.addTween(c, getTweenOpts({ + opacity: 0, + width: newClone.width, + height: newClone.height, + onComplete: () => c.destroy() + })); + }); + }, - _getWindowClone: function() { - let clone = null; - let mutterWindow = this.window.get_compositor_private(); + _getWindowClone: function(window) { + return new Clutter.Clone({ + source: window.get_compositor_private(), + reactive: true, + opacity: 60, + y_align: Clutter.ActorAlign.CENTER, + x_align: Clutter.ActorAlign.CENTER + }); + }, - if (mutterWindow) { - clone = new Clutter.Clone({ source: mutterWindow, reactive: true, opacity: 0 }); - clone.set_pivot_point(0.5, 0.5); - this._resize(clone); + _resizeBin: function() { + let [width, height] = this._getBinSize(); - // this._resizeId = mutterWindow.meta_window.connect('size-changed', - // Lang.bind(this, this._queueResize)); - - // this._destroyId = mutterWindow.connect('destroy', () => this.animateOutAndDestroy()); + this._previewBin.set_size(width, height); + }, + + _getBinSize: function() { + let [width, height] = this._getPreviewDimensions(); + + width += this._padding * 2; + height += this._padding * 2; + + if (!this._previewMenu._dtpSettings.get_boolean('window-preview-fixed-size')) { + if (this._checkIfLeftOrRight()) { + height = -1; + } else { + width = -1; + } } - return clone; + return [width, height]; }, - _resize: function(clone) { + _resizeClone: function(clone) { let [width, height] = clone.get_source().get_size(); - //let scale = Math.min(this._thumbnailWidth / width, this._thumbnailHeight / height); + let [maxWidth, maxHeight] = this._getPreviewDimensions(); + let ratio = Math.min(maxWidth / width, maxHeight / height); + + ratio = ratio < 1 ? ratio : 1; - clone.set_size(200, 160); - clone.set_position(10, 10); + clone.set_size(Math.floor(width * ratio), Math.floor(height * ratio)); }, + + _getPreviewDimensions: function() { + return [ + this._previewMenu._dtpSettings.get_int('window-preview-width'), + this._previewMenu._dtpSettings.get_int('window-preview-height') + ]; + }, + + _checkIfLeftOrRight: function() { + return this._previewMenu._position == St.Side.LEFT || this._previewMenu._position == St.Side.RIGHT; + } }); function getTweenOpts(opts) { let defaults = { - time: Taskbar.DASH_ANIMATION_TIME, + time: Taskbar.DASH_ANIMATION_TIME * 2, transition: 'easeInOutQuad' }; From 15d1bf44647be1b18db2e778a3e1e75c7945f484 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 17 May 2019 01:25:39 -0400 Subject: [PATCH 06/61] Work on preview animations --- stylesheet.css | 4 +- windowPreview.js | 99 +++++++++++++++++++++++++++++++----------------- 2 files changed, 67 insertions(+), 36 deletions(-) diff --git a/stylesheet.css b/stylesheet.css index de04d88..6df8fa6 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -41,10 +41,10 @@ padding-right: 8px; } -#dashtopanelPreviewScrollview { +/* #dashtopanelPreviewScrollview { -st-hfade-offset: 24px; -st-vfade-offset: 24px; -} +} */ #dashtopanelScrollview .app-well-app:hover .overview-icon, #dashtopanelScrollview .app-well-app:focus .overview-icon { diff --git a/windowPreview.js b/windowPreview.js index 957f639..cba1be3 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -80,8 +80,6 @@ var PreviewMenu = Utils.defineClass({ Main.layoutManager._trackActor(this, { affectsStruts: false, trackFullscreen: true }); this._resetHiddenState(); - this.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor ); - this._signalsHandler.add( [ this, @@ -118,6 +116,7 @@ var PreviewMenu = Utils.defineClass({ open: function(appIcon) { if (this._currentAppIcon != appIcon) { + this.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor); let isHidden = this[this._translationProp] != 0; this._currentAppIcon = appIcon; @@ -150,7 +149,10 @@ var PreviewMenu = Utils.defineClass({ if (currentPreviews[i] && windows[i] && windows[i] != currentPreviews[i].window) { currentPreviews[i].assignWindow(windows[i]); } else if (!currentPreviews[i]) { - this._box.add_child(new Preview(this._panelWrapper, this, windows[i])); + let preview = new Preview(this._panelWrapper, this); + + this._box.add_child(preview); + preview.assignWindow(windows[i], immediate); } else if (!windows[i]) { currentPreviews[i][++ii > 3 || immediate ? 'destroy' : 'animateOut'](); } @@ -194,16 +196,15 @@ var PreviewMenu = Utils.defineClass({ switch (event.get_scroll_direction()) { case Clutter.ScrollDirection.UP: - delta = -increment; + delta = -increment; break; case Clutter.ScrollDirection.DOWN: - delta = +increment; + delta = +increment; break; case Clutter.ScrollDirection.SMOOTH: - let [dx, dy] = event.get_scroll_delta(); - - delta = dy*increment; - delta += dx*increment; + let [dx, dy] = event.get_scroll_delta(); + delta = dy * increment; + delta += dx * increment; break; } @@ -276,11 +277,11 @@ var PreviewMenu = Utils.defineClass({ let [width, height] = c.getSize(); if (isLeftOrRight) { - previewsWidth = width; + previewsWidth = Math.max(width, previewsWidth); previewsHeight += height; } else { previewsWidth += width; - previewsHeight = height; + previewsHeight = Math.max(height, previewsHeight); } } }); @@ -312,8 +313,13 @@ var Preview = Utils.defineClass({ Name: 'DashToPanel.Preview', Extends: St.Widget, - _init: function(panelWrapper, previewMenu, window) { - this.callParent('_init', { style_class: 'preview-menu', reactive: true }); + _init: function(panelWrapper, previewMenu) { + this.callParent('_init', { + style_class: 'preview-menu', + reactive: true, + y_align: Clutter.ActorAlign.CENTER, + x_align: Clutter.ActorAlign.CENTER + }); this._panelWrapper = panelWrapper; this._previewMenu = previewMenu; @@ -333,18 +339,13 @@ var Preview = Utils.defineClass({ this._previewBin.set_style('padding: ' + this._padding + 'px'); this._resizeBin(); this.add_actor(this._previewBin); - - this.assignWindow(window); }, - assignWindow: function(window) { + assignWindow: function(window, immediate) { let clone = this._getWindowClone(window); this._resizeClone(clone); - this._removeCurrentClone(clone); - this._previewBin.add_child(clone); - - Tweener.addTween(clone, getTweenOpts({ opacity: 255 })); + this._addClone(clone, immediate); }, animateOut: function() { @@ -358,30 +359,57 @@ var Preview = Utils.defineClass({ getSize: function() { let [binWidth, binHeight] = this._getBinSize(); - let currentClone = this._previewBin.get_last_child(); - binWidth = Math.max(binWidth, currentClone.width + this._padding * 2); - binHeight = Math.max(binHeight, currentClone.height + this._padding * 2); + binWidth = Math.max(binWidth, this.cloneWidth + this._padding * 2); + binHeight = Math.max(binHeight, this.cloneHeight + this._padding * 2); return [binWidth, binHeight]; }, - _removeCurrentClone: function(newClone) { - this._previewBin.get_children().forEach(c =>{ - Tweener.addTween(c, getTweenOpts({ - opacity: 0, - width: newClone.width, - height: newClone.height, - onComplete: () => c.destroy() - })); - }); + _addClone: function(newClone, immediate) { + let currentClones = this._previewBin.get_children(); + let newCloneOpts = getTweenOpts({ opacity: 255 }); + + if (currentClones.length) { + let currentClone = currentClones.pop(); + let currentCloneOpts = getTweenOpts({ opacity: 0, onComplete: () => currentClone.destroy() }); + + if (newClone.width > currentClone.width) { + newCloneOpts.width = newClone.width; + newClone.width = currentClone.width; + } else { + currentCloneOpts.width = newClone.width; + } + + if (newClone.height > currentClone.height) { + newCloneOpts.height = newClone.height; + newClone.height = currentClone.height; + } else { + currentCloneOpts.height = newClone.height; + } + + currentClones.forEach(c => c.destroy()); + Tweener.addTween(currentClone, currentCloneOpts); + } else if (!immediate) { + if (this._checkIfLeftOrRight()) { + newClone.height = 0; + newCloneOpts.height = this.cloneHeight; + } else { + newClone.width = 0; + newCloneOpts.width = this.cloneWidth; + } + } + + this._previewBin.add_child(newClone); + + Tweener.addTween(newClone, newCloneOpts); }, _getWindowClone: function(window) { return new Clutter.Clone({ source: window.get_compositor_private(), reactive: true, - opacity: 60, + opacity: 0, y_align: Clutter.ActorAlign.CENTER, x_align: Clutter.ActorAlign.CENTER }); @@ -417,7 +445,10 @@ var Preview = Utils.defineClass({ ratio = ratio < 1 ? ratio : 1; - clone.set_size(Math.floor(width * ratio), Math.floor(height * ratio)); + this.cloneWidth = Math.floor(width * ratio); + this.cloneHeight = Math.floor(height * ratio); + + clone.set_size(this.cloneWidth, this.cloneHeight); }, _getPreviewDimensions: function() { From 998f74b0089dbc6d4e3d0f48c6f17495121ef4df Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 17 May 2019 15:02:11 -0400 Subject: [PATCH 07/61] Use custom indicator to keep track of the preview menu opened state --- windowPreview.js | 65 +++++++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index cba1be3..677e877 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -33,6 +33,8 @@ const Utils = Me.imports.utils; const T1 = 'openMenuTimeout'; const T2 = 'closeMenuTimeout'; +const MAX_TRANSITION_WINDOWS = 2; + var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel.PreviewMenu', Extends: St.Widget, @@ -44,6 +46,7 @@ var PreviewMenu = Utils.defineClass({ this._panelWrapper = panelWrapper; this._currentAppIcon = null; + this.opened = false; this._position = Taskbar.getPosition(); let isLeftOrRight = this._position == St.Side.LEFT || this._position == St.Side.RIGHT; this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y'); @@ -70,6 +73,15 @@ var PreviewMenu = Utils.defineClass({ //'menu-closed' //'sync-tooltip' //this.add_style_class_name('app-well-menu'); + + // add fixed size limitations + + // adjust intellihide depending on grabs + + // move closing delay setting from "advanced" + + // this._titleWindowChangeId = this.window.connect('notify::title', + // Lang.bind(this, this._updateWindowTitle)); }, enable: function() { @@ -116,13 +128,17 @@ var PreviewMenu = Utils.defineClass({ open: function(appIcon) { if (this._currentAppIcon != appIcon) { - this.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor); - let isHidden = this[this._translationProp] != 0; - this._currentAppIcon = appIcon; - this.updateWindows(appIcon, null, isHidden); - this._updatePosition(isHidden); - this.visible = true; + + this.updateWindows(appIcon); + this._updatePosition(); + + if (!this.opened) { + this.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor); + this.show(); + this.opened = true; + } + this._animateOpenOrClose(true); } }, @@ -137,13 +153,14 @@ var PreviewMenu = Utils.defineClass({ } }, - updateWindows: function(appIcon, windows, immediate) { + updateWindows: function(appIcon, windows) { if (this._currentAppIcon == appIcon) { windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); let currentPreviews = this._box.get_children(); let l = Math.max(windows.length, currentPreviews.length); - let ii = 0; + let added = 0; + let deleted = 0; for (let i = 0; i < l; ++i) { if (currentPreviews[i] && windows[i] && windows[i] != currentPreviews[i].window) { @@ -152,9 +169,9 @@ var PreviewMenu = Utils.defineClass({ let preview = new Preview(this._panelWrapper, this); this._box.add_child(preview); - preview.assignWindow(windows[i], immediate); + preview.assignWindow(windows[i], this.opened, added++ > MAX_TRANSITION_WINDOWS); } else if (!windows[i]) { - currentPreviews[i][++ii > 3 || immediate ? 'destroy' : 'animateOut'](); + currentPreviews[i][deleted++ > MAX_TRANSITION_WINDOWS || !this.opened ? 'destroy' : 'animateOut'](); } } } @@ -220,18 +237,18 @@ var PreviewMenu = Utils.defineClass({ }, _resetHiddenState: function() { - this.visible = false; + this.hide(); + this.opened = false; this.opacity = 0; this[this._translationProp] = this._translationOffset; this._box.get_children().forEach(c => c.destroy()); }, - _updatePosition: function(immediate) { + _updatePosition: function() { let monitorArea = Main.layoutManager.getWorkAreaForMonitor(this._panelWrapper.monitor.index); 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 [ , , natWidth, natHeight] = this.get_preferred_size(); let isLeftOrRight = this._position == St.Side.LEFT || this._position == St.Side.RIGHT; let [previewsWidth, previewsHeight] = this._getPreviewsSize(isLeftOrRight); let x, y; @@ -240,7 +257,7 @@ var PreviewMenu = Utils.defineClass({ previewsHeight = Math.min(previewsHeight, monitorArea.height); if (this._position == St.Side.TOP || this._position == St.Side.BOTTOM) { - x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * .5 - previewsWidth * .5 ; + x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * .5 ; x = Math.max(x, monitorArea.x); x = Math.min(x, monitorArea.x + monitorArea.width - previewsWidth); } else if (this._position == St.Side.LEFT) { @@ -250,7 +267,7 @@ var PreviewMenu = Utils.defineClass({ } if (isLeftOrRight) { - y = sourceAllocation.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * .5 - previewsHeight * .5; + y = sourceAllocation.y1 + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; y = Math.max(y, monitorArea.y); y = Math.min(y, monitorArea.y + monitorArea.height - previewsHeight); } else if (this._position == St.Side.TOP) { @@ -259,9 +276,7 @@ var PreviewMenu = Utils.defineClass({ y = sourceAllocation.y1 - previewsHeight; } - if (immediate || Math.abs(this.x - x) > 320 || - (!isLeftOrRight && this.x + natWidth > monitorArea.x + monitorArea.width) || - (isLeftOrRight && this.y + natHeight > monitorArea.y + monitorArea.height)) { + if (!this.opened) { this.set_position(x, y); } else { Tweener.addTween(this, getTweenOpts({ x: x, y: y })); @@ -290,7 +305,7 @@ var PreviewMenu = Utils.defineClass({ }, _animateOpenOrClose: function(show, onComplete) { - let isTranslationAnimation = this[this._translationProp] !=0; + let isTranslationAnimation = this[this._translationProp] != 0; let tweenOpts = { opacity: show ? 255 : 0, transition: show ? 'easeInOutQuad' : 'easeInCubic', @@ -341,11 +356,11 @@ var Preview = Utils.defineClass({ this.add_actor(this._previewBin); }, - assignWindow: function(window, immediate) { + assignWindow: function(window, animateSize, delay) { let clone = this._getWindowClone(window); this._resizeClone(clone); - this._addClone(clone, immediate); + this._addClone(clone, animateSize, delay); }, animateOut: function() { @@ -366,7 +381,7 @@ var Preview = Utils.defineClass({ return [binWidth, binHeight]; }, - _addClone: function(newClone, immediate) { + _addClone: function(newClone, animateSize, delay) { let currentClones = this._previewBin.get_children(); let newCloneOpts = getTweenOpts({ opacity: 255 }); @@ -390,7 +405,7 @@ var Preview = Utils.defineClass({ currentClones.forEach(c => c.destroy()); Tweener.addTween(currentClone, currentCloneOpts); - } else if (!immediate) { + } else if (animateSize) { if (this._checkIfLeftOrRight()) { newClone.height = 0; newCloneOpts.height = this.cloneHeight; @@ -398,6 +413,10 @@ var Preview = Utils.defineClass({ newClone.width = 0; newCloneOpts.width = this.cloneWidth; } + + if (delay) { + newCloneOpts.delay = newCloneOpts.time * .5; + } } this._previewBin.add_child(newClone); From a3c8da82d418265ba255db1c3a217fb26303bb91 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 17 May 2019 15:40:00 -0400 Subject: [PATCH 08/61] Adjust intellihide for custom previews --- intellihide.js | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/intellihide.js b/intellihide.js index 4690500..233819d 100644 --- a/intellihide.js +++ b/intellihide.js @@ -20,7 +20,6 @@ const Clutter = imports.gi.Clutter; const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; -const GrabHelper = imports.ui.grabHelper; const Layout = imports.ui.layout; const Main = imports.ui.main; const OverviewControls = imports.ui.overviewControls; @@ -33,12 +32,10 @@ const Utils = Me.imports.utils; //timeout intervals const CHECK_POINTER_MS = 200; -const CHECK_GRAB_MS = 400; const POST_ANIMATE_MS = 50; const MIN_UPDATE_MS = 250; //timeout names -const T1 = 'checkGrabTimeout'; const T2 = 'limitUpdateTimeout'; const T3 = 'postAnimateTimeout'; @@ -187,10 +184,12 @@ var Intellihide = Utils.defineClass({ [ this._panelBox, 'notify::hover', - () => { - this._hoveredOut = !this._panelBox.hover; - this._queueUpdatePanelPosition(); - } + () => this._onHoverChanged() + ], + [ + this._dtpPanel.taskbar.previewMenu, + 'notify::hover', + () => this._onHoverChanged() ], [ Main.overview, @@ -203,6 +202,11 @@ var Intellihide = Utils.defineClass({ ); }, + _onHoverChanged: function() { + this._hoveredOut = !this._panelBox.hover && !this._dtpPanel.taskbar.previewMenu.hover; + this._queueUpdatePanelPosition(); + }, + _setTrackPanel: function(reset, enable) { if (!reset) { Main.layoutManager._untrackActor(this._panelBox); @@ -291,7 +295,7 @@ var Intellihide = Utils.defineClass({ }, _checkIfShouldBeVisible: function(fromRevealMechanism) { - if (Main.overview.visibleTarget || this._checkIfGrab() || this._panelBox.get_hover()) { + if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.get_hover() || this._panelBox.get_hover()) { return true; } @@ -313,17 +317,6 @@ var Intellihide = Utils.defineClass({ return !this._windowOverlap; }, - _checkIfGrab: function() { - if (GrabHelper._grabHelperStack.some(gh => this._panelBox.contains(gh._owner))) { - //there currently is a grab on a child of the panel, check again soon to catch its release - this._timeoutsHandler.add([T1, CHECK_GRAB_MS, () => this._queueUpdatePanelPosition()]); - - return true; - } - - return false; - }, - _revealPanel: function(immediate) { this._animatePanel(0, immediate); }, From 8e6c196f4446593ced8948114f3fcc630c2c90d7 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 17 May 2019 22:44:52 -0400 Subject: [PATCH 09/61] Use clipping container to prevent alpha addition --- intellihide.js | 6 +- ...shell.extensions.dash-to-panel.gschema.xml | 8 +- stylesheet.css | 4 +- windowPreview.js | 191 ++++++++++-------- 4 files changed, 120 insertions(+), 89 deletions(-) diff --git a/intellihide.js b/intellihide.js index 233819d..639eb19 100644 --- a/intellihide.js +++ b/intellihide.js @@ -187,7 +187,7 @@ var Intellihide = Utils.defineClass({ () => this._onHoverChanged() ], [ - this._dtpPanel.taskbar.previewMenu, + this._dtpPanel.taskbar.previewMenu.menu, 'notify::hover', () => this._onHoverChanged() ], @@ -203,7 +203,7 @@ var Intellihide = Utils.defineClass({ }, _onHoverChanged: function() { - this._hoveredOut = !this._panelBox.hover && !this._dtpPanel.taskbar.previewMenu.hover; + this._hoveredOut = !this._panelBox.hover && !this._dtpPanel.taskbar.previewMenu.menu.hover; this._queueUpdatePanelPosition(); }, @@ -295,7 +295,7 @@ var Intellihide = Utils.defineClass({ }, _checkIfShouldBeVisible: function(fromRevealMechanism) { - if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.get_hover() || this._panelBox.get_hover()) { + if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.menu.get_hover() || this._panelBox.get_hover()) { return true; } diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index cc5afac..b49e2d5 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -410,10 +410,10 @@ Display title in preview Display window title in preview - - false - Use previews fixed size - Previews always have the same size or they scale to the aspect ratio of their window clone + + 200 + Window previews size + Preferred window previews size 350 diff --git a/stylesheet.css b/stylesheet.css index 6df8fa6..de04d88 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -41,10 +41,10 @@ padding-right: 8px; } -/* #dashtopanelPreviewScrollview { +#dashtopanelPreviewScrollview { -st-hfade-offset: 24px; -st-vfade-offset: 24px; -} */ +} #dashtopanelScrollview .app-well-app:hover .overview-icon, #dashtopanelScrollview .app-well-app:focus .overview-icon { diff --git a/windowPreview.js b/windowPreview.js index 677e877..41ce85b 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -33,27 +33,27 @@ const Utils = Me.imports.utils; const T1 = 'openMenuTimeout'; const T2 = 'closeMenuTimeout'; -const MAX_TRANSITION_WINDOWS = 2; +const HEADER_HEIGHT = 0; var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel.PreviewMenu', Extends: St.Widget, _init: function(dtpSettings, panelWrapper) { - this.callParent('_init', { name: 'preview-menu', layout_manager: new Clutter.BinLayout(), reactive: true, track_hover: true }); + this.callParent('_init', { layout_manager: new Clutter.BinLayout() }); this._dtpSettings = dtpSettings; this._panelWrapper = panelWrapper; - this._currentAppIcon = null; this.opened = false; this._position = Taskbar.getPosition(); - let isLeftOrRight = this._position == St.Side.LEFT || this._position == St.Side.RIGHT; + let isLeftOrRight = this._checkIfLeftOrRight(); this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y'); - this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), 40) * (this._position == St.Side.TOP || this._position == St.Side.LEFT ? -1 : 1); - - this._box = new St.BoxLayout({ vertical: isLeftOrRight, clip_to_allocation: false }); + this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), 40) * + (this._position == St.Side.TOP || this._position == St.Side.LEFT ? -1 : 1); + this.menu = new St.Widget({ name: 'preview-menu', layout_manager: new Clutter.BinLayout(), reactive: true, track_hover: true }); + this._box = new St.BoxLayout({ vertical: isLeftOrRight }); this._scrollView = new St.ScrollView({ name: 'dashtopanelPreviewScrollview', hscrollbar_policy: Gtk.PolicyType.NEVER, @@ -62,7 +62,8 @@ var PreviewMenu = Utils.defineClass({ }); this._scrollView.add_actor(this._box); - this.add_child(this._scrollView); + this.menu.add_child(this._scrollView); + this.add_child(this.menu); @@ -76,8 +77,6 @@ var PreviewMenu = Utils.defineClass({ // add fixed size limitations - // adjust intellihide depending on grabs - // move closing delay setting from "advanced" // this._titleWindowChangeId = this.window.connect('notify::title', @@ -89,12 +88,15 @@ var PreviewMenu = Utils.defineClass({ this._signalsHandler = new Utils.GlobalSignalsHandler(); Main.uiGroup.insert_child_below(this, this._panelWrapper.panelBox); - Main.layoutManager._trackActor(this, { affectsStruts: false, trackFullscreen: true }); + Main.layoutManager._trackActor(this, { trackFullscreen: true, affectsInputRegion: false }); + Main.layoutManager.trackChrome(this.menu, { affectsInputRegion: true }); + this._resetHiddenState(); + this._updateClip(); this._signalsHandler.add( [ - this, + this.menu, 'notify::hover', () => this._onHoverChanged() ], @@ -102,6 +104,15 @@ var PreviewMenu = Utils.defineClass({ this._scrollView, 'scroll-event', this._onScrollEvent.bind(this) + ], + [ + this._dtpSettings, + [ + 'changed::panel-size', + 'changed::window-preview-size', + 'changed::window-preview-padding' + ], + () => this._updateClip() ] ); }, @@ -114,6 +125,8 @@ var PreviewMenu = Utils.defineClass({ Main.layoutManager._untrackActor(this); Main.uiGroup.remove_child(this); + + this.destroy(); }, requestOpen: function(appIcon) { @@ -134,8 +147,8 @@ var PreviewMenu = Utils.defineClass({ this._updatePosition(); if (!this.opened) { - this.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor); - this.show(); + this.menu.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor); + this.menu.show(); this.opened = true; } @@ -159,19 +172,17 @@ var PreviewMenu = Utils.defineClass({ let currentPreviews = this._box.get_children(); let l = Math.max(windows.length, currentPreviews.length); - let added = 0; - let deleted = 0; for (let i = 0; i < l; ++i) { if (currentPreviews[i] && windows[i] && windows[i] != currentPreviews[i].window) { - currentPreviews[i].assignWindow(windows[i]); + currentPreviews[i].assignWindow(windows[i], this.opened); } else if (!currentPreviews[i]) { let preview = new Preview(this._panelWrapper, this); this._box.add_child(preview); - preview.assignWindow(windows[i], this.opened, added++ > MAX_TRANSITION_WINDOWS); + preview.assignWindow(windows[i], this.opened); } else if (!windows[i]) { - currentPreviews[i][deleted++ > MAX_TRANSITION_WINDOWS || !this.opened ? 'destroy' : 'animateOut'](); + currentPreviews[i][!this.opened ? 'destroy' : 'animateOut'](); } } } @@ -200,24 +211,22 @@ var PreviewMenu = Utils.defineClass({ _onHoverChanged: function() { this._endOpenCloseTimeouts(); - if (!this.hover) { + if (!this.menu.hover) { this._addCloseTimeout(); } }, _onScrollEvent: function(actor, event) { if (!event.is_pointer_emulated()) { - let adjustment = this._scrollView.get_hscroll_bar().get_adjustment(); + let vOrh = this._checkIfLeftOrRight() ? 'v' : 'h'; + let adjustment = this._scrollView['get_' + vOrh + 'scroll_bar']().get_adjustment(); let increment = adjustment.step_increment; - let delta; + let delta = 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; @@ -237,53 +246,73 @@ var PreviewMenu = Utils.defineClass({ }, _resetHiddenState: function() { - this.hide(); + this.menu.hide(); this.opened = false; - this.opacity = 0; - this[this._translationProp] = this._translationOffset; + this.menu.opacity = 0; + this.menu[this._translationProp] = this._translationOffset; this._box.get_children().forEach(c => c.destroy()); }, + _updateClip: function() { + let x, y, w, h; + let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; + let panelSize = this._dtpSettings.get_int('panel-size'); + let previewSize = this._dtpSettings.get_int('window-preview-size') + + this._dtpSettings.get_int('window-preview-padding') * 2; + + if (this._checkIfLeftOrRight()) { + w = previewSize * scaleFactor; + h = this._panelWrapper.monitor.height; + y = this._panelWrapper.monitor.y; + } else { + w = this._panelWrapper.monitor.width; + h = (previewSize + HEADER_HEIGHT) * scaleFactor; + x = this._panelWrapper.monitor.x; + } + + if (this._position == St.Side.LEFT) { + x = this._panelWrapper.monitor.x + panelSize * scaleFactor; + } else if (this._position == St.Side.RIGHT) { + x = this._panelWrapper.monitor.x + this._panelWrapper.monitor.width - (panelSize + previewSize) * scaleFactor; + } else if (this._position == St.Side.TOP) { + y = this._panelWrapper.monitor.y + panelSize * scaleFactor; + } else { //St.Side.BOTTOM + y = this._panelWrapper.monitor.y + this._panelWrapper.monitor.height - (panelSize + previewSize + HEADER_HEIGHT) * scaleFactor; + } + + this.set_clip(0, 0, w, h); + this.set_position(x, y); + this.set_size(w, h); + }, + _updatePosition: function() { - let monitorArea = Main.layoutManager.getWorkAreaForMonitor(this._panelWrapper.monitor.index); 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 isLeftOrRight = this._position == St.Side.LEFT || this._position == St.Side.RIGHT; - let [previewsWidth, previewsHeight] = this._getPreviewsSize(isLeftOrRight); - let x, y; + let [previewsWidth, previewsHeight] = this._getPreviewsSize(); + let x = 0, y = 0; - previewsWidth = Math.min(previewsWidth, monitorArea.width); - previewsHeight = Math.min(previewsHeight, monitorArea.height); + previewsWidth = Math.min(previewsWidth, this._panelWrapper.monitor.width); + previewsHeight = Math.min(previewsHeight, this._panelWrapper.monitor.height); - if (this._position == St.Side.TOP || this._position == St.Side.BOTTOM) { - x = sourceAllocation.x1 + (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * .5 ; - x = Math.max(x, monitorArea.x); - x = Math.min(x, monitorArea.x + monitorArea.width - previewsWidth); - } else if (this._position == St.Side.LEFT) { - x = sourceAllocation.x2; - } else { //St.Side.RIGHT - x = sourceAllocation.x1 - previewsWidth; - } - - if (isLeftOrRight) { - y = sourceAllocation.y1 + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; - y = Math.max(y, monitorArea.y); - y = Math.min(y, monitorArea.y + monitorArea.height - previewsHeight); - } else if (this._position == St.Side.TOP) { - y = sourceAllocation.y2; - } else { //St.Side.BOTTOM - y = sourceAllocation.y1 - previewsHeight; + if (this._checkIfLeftOrRight()) { + y = sourceAllocation.y1 - this._panelWrapper.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; + y = Math.max(y, 0); + y = Math.min(y, this._panelWrapper.monitor.height - previewsHeight); + } else { + x = sourceAllocation.x1 - this._panelWrapper.monitor.x + (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * .5; + x = Math.max(x, 0); + x = Math.min(x, this._panelWrapper.monitor.width - previewsWidth); } if (!this.opened) { - this.set_position(x, y); + this.menu.set_position(x, y); } else { - Tweener.addTween(this, getTweenOpts({ x: x, y: y })); + Tweener.addTween(this.menu, getTweenOpts({ x: x, y: y })); } }, - _getPreviewsSize: function(isLeftOrRight) { + _getPreviewsSize: function() { let previewsWidth = 0; let previewsHeight = 0; @@ -291,7 +320,7 @@ var PreviewMenu = Utils.defineClass({ if (!c.animatingOut) { let [width, height] = c.getSize(); - if (isLeftOrRight) { + if (this._checkIfLeftOrRight()) { previewsWidth = Math.max(width, previewsWidth); previewsHeight += height; } else { @@ -305,7 +334,7 @@ var PreviewMenu = Utils.defineClass({ }, _animateOpenOrClose: function(show, onComplete) { - let isTranslationAnimation = this[this._translationProp] != 0; + let isTranslationAnimation = this.menu[this._translationProp] != 0; let tweenOpts = { opacity: show ? 255 : 0, transition: show ? 'easeInOutQuad' : 'easeInCubic', @@ -320,8 +349,12 @@ var PreviewMenu = Utils.defineClass({ tweenOpts[this._translationProp] = show ? 0 : this._translationOffset; - Tweener.addTween(this, getTweenOpts(tweenOpts)); + Tweener.addTween(this.menu, getTweenOpts(tweenOpts)); }, + + _checkIfLeftOrRight: function() { + return this._position == St.Side.LEFT || this._position == St.Side.RIGHT; + } }); var Preview = Utils.defineClass({ @@ -330,10 +363,11 @@ var Preview = Utils.defineClass({ _init: function(panelWrapper, previewMenu) { this.callParent('_init', { - style_class: 'preview-menu', + style_class: 'preview-container', reactive: true, y_align: Clutter.ActorAlign.CENTER, - x_align: Clutter.ActorAlign.CENTER + x_align: Clutter.ActorAlign.CENTER, + layout_manager: new Clutter.BoxLayout({ vertical: false }) }); this._panelWrapper = panelWrapper; @@ -341,7 +375,7 @@ var Preview = Utils.defineClass({ this._padding = previewMenu._dtpSettings.get_int('window-preview-padding'); this.animatingOut = false; - this._titleBox = new St.BoxLayout({ }); + this._titleBox = new St.BoxLayout({ height: HEADER_HEIGHT }); this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, style_class: 'preview-label' }); @@ -356,17 +390,17 @@ var Preview = Utils.defineClass({ this.add_actor(this._previewBin); }, - assignWindow: function(window, animateSize, delay) { + assignWindow: function(window, animateSize) { let clone = this._getWindowClone(window); this._resizeClone(clone); - this._addClone(clone, animateSize, delay); + this._addClone(clone, animateSize); }, animateOut: function() { let tweenOpts = getTweenOpts({ opacity: 0, onComplete: () => this.destroy() }); - tweenOpts[this._checkIfLeftOrRight() ? 'height' : 'width'] = 0; + tweenOpts[this._previewMenu._checkIfLeftOrRight() ? 'height' : 'width'] = 0; this.animatingOut = true; Tweener.addTween(this, tweenOpts); @@ -381,7 +415,7 @@ var Preview = Utils.defineClass({ return [binWidth, binHeight]; }, - _addClone: function(newClone, animateSize, delay) { + _addClone: function(newClone, animateSize) { let currentClones = this._previewBin.get_children(); let newCloneOpts = getTweenOpts({ opacity: 255 }); @@ -406,17 +440,13 @@ var Preview = Utils.defineClass({ currentClones.forEach(c => c.destroy()); Tweener.addTween(currentClone, currentCloneOpts); } else if (animateSize) { - if (this._checkIfLeftOrRight()) { + if (this._previewMenu._checkIfLeftOrRight()) { newClone.height = 0; newCloneOpts.height = this.cloneHeight; } else { newClone.width = 0; newCloneOpts.width = this.cloneWidth; } - - if (delay) { - newCloneOpts.delay = newCloneOpts.time * .5; - } } this._previewBin.add_child(newClone); @@ -446,12 +476,10 @@ var Preview = Utils.defineClass({ width += this._padding * 2; height += this._padding * 2; - if (!this._previewMenu._dtpSettings.get_boolean('window-preview-fixed-size')) { - if (this._checkIfLeftOrRight()) { - height = -1; - } else { - width = -1; - } + if (this._previewMenu._checkIfLeftOrRight()) { + height = -1; + } else { + width = -1; } return [width, height]; @@ -471,14 +499,17 @@ var Preview = Utils.defineClass({ }, _getPreviewDimensions: function() { + let size = this._previewMenu._dtpSettings.get_int('window-preview-size'); + let w, h; + + if (this._previewMenu._checkIfLeftOrRight()) { + + } + return [ this._previewMenu._dtpSettings.get_int('window-preview-width'), this._previewMenu._dtpSettings.get_int('window-preview-height') ]; - }, - - _checkIfLeftOrRight: function() { - return this._previewMenu._position == St.Side.LEFT || this._previewMenu._position == St.Side.RIGHT; } }); From 2033f1b00c9cd8b00035ae2c7ea02153d2b6a0e8 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sat, 18 May 2019 09:17:34 -0400 Subject: [PATCH 10/61] Use aspect ratio only for preview sizing --- ...shell.extensions.dash-to-panel.gschema.xml | 2 +- windowPreview.js | 49 +++++++------------ 2 files changed, 20 insertions(+), 31 deletions(-) diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index b49e2d5..21b3dc1 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -411,7 +411,7 @@ Display window title in preview - 200 + 240 Window previews size Preferred window previews size diff --git a/windowPreview.js b/windowPreview.js index 41ce85b..7766a2b 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -33,7 +33,9 @@ const Utils = Me.imports.utils; const T1 = 'openMenuTimeout'; const T2 = 'closeMenuTimeout'; +const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 0; +const DEFAULT_RATIO = { w: 160, h: 90 }; var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel.PreviewMenu', @@ -49,7 +51,7 @@ var PreviewMenu = Utils.defineClass({ this._position = Taskbar.getPosition(); let isLeftOrRight = this._checkIfLeftOrRight(); this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y'); - this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), 40) * + this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), MAX_TRANSLATION) * (this._position == St.Side.TOP || this._position == St.Side.LEFT ? -1 : 1); this.menu = new St.Widget({ name: 'preview-menu', layout_manager: new Clutter.BinLayout(), reactive: true, track_hover: true }); @@ -75,12 +77,14 @@ var PreviewMenu = Utils.defineClass({ //'sync-tooltip' //this.add_style_class_name('app-well-menu'); - // add fixed size limitations + // add middle click // move closing delay setting from "advanced" // this._titleWindowChangeId = this.window.connect('notify::title', // Lang.bind(this, this._updateWindowTitle)); + + // hook settings }, enable: function() { @@ -192,18 +196,6 @@ var PreviewMenu = Utils.defineClass({ return this._currentAppIcon; }, - vfunc_get_preferred_width: function(forHeight) { - let [, width] = St.Widget.prototype.vfunc_get_preferred_width.call(this, forHeight); - - return [0, Math.min(width, this._panelWrapper.monitor.width)]; - }, - - vfunc_get_preferred_height: function(forWidth) { - let [, height] = St.Widget.prototype.vfunc_get_preferred_height.call(this, forWidth); - - return [0, Math.min(height, this._panelWrapper.monitor.height)]; - }, - _addCloseTimeout: function() { this._timeoutsHandler.add([T2, this._dtpSettings.get_int('leave-timeout'), () => this.close()]); }, @@ -372,7 +364,8 @@ var Preview = Utils.defineClass({ this._panelWrapper = panelWrapper; this._previewMenu = previewMenu; - this._padding = previewMenu._dtpSettings.get_int('window-preview-padding'); + this._padding = previewMenu._dtpSettings.get_int('window-preview-padding') * St.ThemeContext.get_for_stage(global.stage).scale_factor; + this._previewDimensions = this._getPreviewDimensions(); this.animatingOut = false; this._titleBox = new St.BoxLayout({ height: HEADER_HEIGHT }); @@ -386,7 +379,8 @@ var Preview = Utils.defineClass({ this._previewBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); this._previewBin.set_style('padding: ' + this._padding + 'px'); - this._resizeBin(); + this._previewBin.set_size.apply(this._previewBin, this._getBinSize()); + this.add_actor(this._previewBin); }, @@ -464,14 +458,8 @@ var Preview = Utils.defineClass({ }); }, - _resizeBin: function() { - let [width, height] = this._getBinSize(); - - this._previewBin.set_size(width, height); - }, - _getBinSize: function() { - let [width, height] = this._getPreviewDimensions(); + let [width, height] = this._previewDimensions; width += this._padding * 2; height += this._padding * 2; @@ -487,7 +475,7 @@ var Preview = Utils.defineClass({ _resizeClone: function(clone) { let [width, height] = clone.get_source().get_size(); - let [maxWidth, maxHeight] = this._getPreviewDimensions(); + let [maxWidth, maxHeight] = this._previewDimensions; let ratio = Math.min(maxWidth / width, maxHeight / height); ratio = ratio < 1 ? ratio : 1; @@ -499,17 +487,18 @@ var Preview = Utils.defineClass({ }, _getPreviewDimensions: function() { - let size = this._previewMenu._dtpSettings.get_int('window-preview-size'); + let size = this._previewMenu._dtpSettings.get_int('window-preview-size') * St.ThemeContext.get_for_stage(global.stage).scale_factor; let w, h; if (this._previewMenu._checkIfLeftOrRight()) { - + w = Math.max(DEFAULT_RATIO.w, size); + h = w * DEFAULT_RATIO.h / DEFAULT_RATIO.w; + } else { + h = Math.max(DEFAULT_RATIO.h, size); + w = h * DEFAULT_RATIO.w / DEFAULT_RATIO.h; } - return [ - this._previewMenu._dtpSettings.get_int('window-preview-width'), - this._previewMenu._dtpSettings.get_int('window-preview-height') - ]; + return [w, h]; } }); From aa87cb800d25a6aa41410890c2b878c84191385b Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 19 May 2019 10:42:22 -0400 Subject: [PATCH 11/61] Add close button --- appIcons.js | 2 +- panelManager.js | 2 +- taskbar.js | 39 ++++-------- utils.js | 14 +++++ windowPreview.js | 153 +++++++++++++++++++++++++++++++++++------------ 5 files changed, 143 insertions(+), 67 deletions(-) diff --git a/appIcons.js b/appIcons.js index 181d56b..dc4d066 100644 --- a/appIcons.js +++ b/appIcons.js @@ -864,7 +864,7 @@ var taskbarAppIcon = Utils.defineClass({ this.actor.add_style_class_name(className); } - this._previewMenu.updateWindows(this, windows); + this._previewMenu.update(this, windows); }, _getRunningIndicatorCount: function() { diff --git a/panelManager.js b/panelManager.js index 1eea9e2..06c8f87 100755 --- a/panelManager.js +++ b/panelManager.js @@ -385,7 +385,7 @@ var dtpPanelManager = Utils.defineClass({ }, _newGetShowAppsButton: function() { - let focusedMonitorIndex = Taskbar.findIndex(this.allPanels, p => this.checkIfFocusedMonitor(p.monitor)); + let focusedMonitorIndex = Utils.findIndex(this.allPanels, p => this.checkIfFocusedMonitor(p.monitor)); return this.allPanels[focusedMonitorIndex].taskbar.showAppsButton; }, diff --git a/taskbar.js b/taskbar.js index 8ce1495..a41fdce 100644 --- a/taskbar.js +++ b/taskbar.js @@ -84,21 +84,6 @@ function extendDashItemContainer(dashItemContainer) { * - modified chldBox calculations for when 'show-apps-at-top' option is checked * - handle horizontal dash */ - -function findIndex(array, predicate) { - if (Array.prototype.findIndex) { - return array.findIndex(predicate); - } - - for (let i = 0, l = array.length; i < l; ++i) { - if (predicate(array[i])) { - return i; - } - } - - return -1; -}; - var taskbarActor = Utils.defineClass({ Name: 'DashToPanel-TaskbarActor', Extends: St.Widget, @@ -766,10 +751,6 @@ var taskbar = Utils.defineClass({ getAppStableSequence(appB, this._dtpSettings, this.panelWrapper.monitor); }, - sortWindowsCompareFunction: function(windowA, windowB) { - return getWindowStableSequence(windowA) - getWindowStableSequence(windowB); - }, - _redisplay: function () { if (!this._signalsHandler) { return; @@ -798,8 +779,8 @@ var taskbar = Utils.defineClass({ //remove the appIcons which are not in the expected apps list for (let i = currentAppIcons.length - 1; i > -1; --i) { let appIcon = currentAppIcons[i].child._delegate; - let appIndex = findIndex(expectedAppInfos, appInfo => appInfo.app == appIcon.app && - appInfo.isLauncher == appIcon.isLauncher); + let appIndex = Utils.findIndex(expectedAppInfos, appInfo => appInfo.app == appIcon.app && + appInfo.isLauncher == appIcon.isLauncher); if (appIndex < 0 || (appIcon.window && (this.isGroupApps || expectedAppInfos[appIndex].windows.indexOf(appIcon.window) < 0)) || @@ -819,8 +800,8 @@ var taskbar = Utils.defineClass({ for (let j = 0, ll = neededAppIcons.length; j < ll; ++j) { //check if the icon already exists - let matchingAppIconIndex = findIndex(currentAppIcons, appIcon => appIcon.child._delegate.app == neededAppIcons[j].app && - appIcon.child._delegate.window == neededAppIcons[j].window); + let matchingAppIconIndex = Utils.findIndex(currentAppIcons, appIcon => appIcon.child._delegate.app == neededAppIcons[j].app && + appIcon.child._delegate.window == neededAppIcons[j].window); if (matchingAppIconIndex > 0 && matchingAppIconIndex != currentPosition) { //moved icon, reposition it @@ -885,7 +866,7 @@ var taskbar = Utils.defineClass({ app: app, isLauncher: defaultIsLauncher || false, windows: defaultWindows || AppIcons.getInterestingWindows(app, this._dtpSettings, this.panelWrapper.monitor) - .sort(this.sortWindowsCompareFunction) + .sort(sortWindowsCompareFunction) })); }, @@ -964,9 +945,9 @@ var taskbar = Utils.defineClass({ let currentAppIcons = this._getAppIcons(); let sourceIndex = currentAppIcons.indexOf(source); - let hoveredIndex = findIndex(currentAppIcons, - appIcon => x >= appIcon._dashItemContainer.x && - x <= (appIcon._dashItemContainer.x + appIcon._dashItemContainer.width)); + let hoveredIndex = Utils.findIndex(currentAppIcons, + appIcon => x >= appIcon._dashItemContainer.x && + x <= (appIcon._dashItemContainer.x + appIcon._dashItemContainer.width)); if (!this._dragInfo) { this._dragInfo = [sourceIndex, source]; @@ -1239,6 +1220,10 @@ function getAppStableSequence(app, settings, monitor) { }, Infinity); } +function sortWindowsCompareFunction(windowA, windowB) { + return getWindowStableSequence(windowA) - getWindowStableSequence(windowB); +} + function getWindowStableSequence(window) { return ('_dtpPosition' in window ? window._dtpPosition : window.get_stable_sequence()); } diff --git a/utils.js b/utils.js index da67fcd..1af139d 100644 --- a/utils.js +++ b/utils.js @@ -270,6 +270,20 @@ var DisplayWrapper = { } }; +var findIndex = function(array, predicate) { + if (Array.prototype.findIndex) { + return array.findIndex(predicate); + } + + for (let i = 0, l = array.length; i < l; ++i) { + if (predicate(array[i])) { + return i; + } + } + + return -1; +}; + var mergeObjects = function(main, bck) { for (var prop in bck) { if (!main.hasOwnProperty(prop) && bck.hasOwnProperty(prop)) { diff --git a/windowPreview.js b/windowPreview.js index 7766a2b..3cc4e94 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -16,12 +16,15 @@ */ const Clutter = imports.gi.Clutter; +const Config = imports.misc.config; const Gtk = imports.gi.Gtk; const Main = imports.ui.main; +const Meta = imports.gi.Meta; const Signals = imports.signals; const Shell = imports.gi.Shell; const St = imports.gi.St; const Tweener = imports.ui.tweener; +const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); const Taskbar = Me.imports.taskbar; @@ -34,9 +37,12 @@ const T1 = 'openMenuTimeout'; const T2 = 'closeMenuTimeout'; const MAX_TRANSLATION = 40; -const HEADER_HEIGHT = 0; +const HEADER_HEIGHT = 40; const DEFAULT_RATIO = { w: 160, h: 90 }; +var headerHeight = 0; +var isLeftButtons = false; + var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel.PreviewMenu', Extends: St.Widget, @@ -96,6 +102,7 @@ var PreviewMenu = Utils.defineClass({ Main.layoutManager.trackChrome(this.menu, { affectsInputRegion: true }); this._resetHiddenState(); + this._refreshGlobals(); this._updateClip(); this._signalsHandler.add( @@ -147,16 +154,18 @@ var PreviewMenu = Utils.defineClass({ if (this._currentAppIcon != appIcon) { this._currentAppIcon = appIcon; - this.updateWindows(appIcon); - this._updatePosition(); - if (!this.opened) { this.menu.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor); this.menu.show(); - this.opened = true; + + this._refreshGlobals(); } - + + this._mergeWindows(appIcon); + this._updatePosition(); this._animateOpenOrClose(true); + + this.opened = true; } }, @@ -170,28 +179,60 @@ var PreviewMenu = Utils.defineClass({ } }, - updateWindows: function(appIcon, windows) { + update: function(appIcon, windows) { if (this._currentAppIcon == appIcon) { - windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); - - let currentPreviews = this._box.get_children(); - let l = Math.max(windows.length, currentPreviews.length); - - for (let i = 0; i < l; ++i) { - if (currentPreviews[i] && windows[i] && windows[i] != currentPreviews[i].window) { - currentPreviews[i].assignWindow(windows[i], this.opened); - } else if (!currentPreviews[i]) { - let preview = new Preview(this._panelWrapper, this); - - this._box.add_child(preview); - preview.assignWindow(windows[i], this.opened); - } else if (!windows[i]) { - currentPreviews[i][!this.opened ? 'destroy' : 'animateOut'](); - } + if (windows && !windows.length) { + this.close(); + } else { + this._addAndRemoveWindows(windows); + this._updatePosition(); } } }, + _mergeWindows: function(appIcon, windows) { + windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); + windows.sort(Taskbar.sortWindowsCompareFunction); + + let currentPreviews = this._box.get_children(); + let l = Math.max(windows.length, currentPreviews.length); + + for (let i = 0; i < l; ++i) { + if (currentPreviews[i] && windows[i] && windows[i] != currentPreviews[i].window) { + currentPreviews[i].assignWindow(windows[i], this.opened); + } else if (!currentPreviews[i]) { + this._addNewPreview(windows[i]); + } else if (!windows[i]) { + currentPreviews[i][!this.opened ? 'destroy' : 'animateOut'](); + } + } + }, + + _addAndRemoveWindows: function(windows) { + let currentPreviews = this._box.get_children(); + + windows.sort(Taskbar.sortWindowsCompareFunction); + + for (let i = 0, l = windows.length; i < l; ++i) { + let currentIndex = Utils.findIndex(currentPreviews, c => c.window == windows[i]); + + if (currentIndex < 0) { + this._addNewPreview(windows[i]); + } else { + currentPreviews.splice(currentIndex, 1); + } + } + + currentPreviews.forEach(c => c.animateOut()); + }, + + _addNewPreview: function(window) { + let preview = new Preview(this._panelWrapper, this); + + this._box.add_child(preview); + preview.assignWindow(window, this.opened); + }, + getCurrentAppIcon: function() { return this._currentAppIcon; }, @@ -237,6 +278,11 @@ var PreviewMenu = Utils.defineClass({ this._timeoutsHandler.remove(T2); }, + _refreshGlobals: function() { + headerHeight = this._dtpSettings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT : 0; + isLeftButtons = Meta.prefs_get_button_layout().left_buttons.indexOf(Meta.ButtonFunction.CLOSE) >= 0; + }, + _resetHiddenState: function() { this.menu.hide(); this.opened = false; @@ -258,7 +304,7 @@ var PreviewMenu = Utils.defineClass({ y = this._panelWrapper.monitor.y; } else { w = this._panelWrapper.monitor.width; - h = (previewSize + HEADER_HEIGHT) * scaleFactor; + h = (previewSize + headerHeight) * scaleFactor; x = this._panelWrapper.monitor.x; } @@ -269,7 +315,7 @@ var PreviewMenu = Utils.defineClass({ } else if (this._position == St.Side.TOP) { y = this._panelWrapper.monitor.y + panelSize * scaleFactor; } else { //St.Side.BOTTOM - y = this._panelWrapper.monitor.y + this._panelWrapper.monitor.height - (panelSize + previewSize + HEADER_HEIGHT) * scaleFactor; + y = this._panelWrapper.monitor.y + this._panelWrapper.monitor.height - (panelSize + previewSize + headerHeight) * scaleFactor; } this.set_clip(0, 0, w, h); @@ -357,9 +403,8 @@ var Preview = Utils.defineClass({ this.callParent('_init', { style_class: 'preview-container', reactive: true, - y_align: Clutter.ActorAlign.CENTER, - x_align: Clutter.ActorAlign.CENTER, - layout_manager: new Clutter.BoxLayout({ vertical: false }) + track_hover: true, + layout_manager: new Clutter.BinLayout() }); this._panelWrapper = panelWrapper; @@ -368,25 +413,49 @@ var Preview = Utils.defineClass({ this._previewDimensions = this._getPreviewDimensions(); this.animatingOut = false; - this._titleBox = new St.BoxLayout({ height: HEADER_HEIGHT }); - - this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, style_class: 'preview-label' }); - - this._titleBox.add_child(this._windowTitle); - - this.add_actor(this._titleBox) - this._previewBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); - - this._previewBin.set_style('padding: ' + this._padding + 'px'); + this._previewBin.set_style('padding: ' + this._padding + 'px;'); this._previewBin.set_size.apply(this._previewBin, this._getBinSize()); + let closeButton = new St.Button({ style_class: 'window-close', accessible_name: 'Close window' }); + this._closeButtonBin = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + opacity: 0, + x_expand: true, y_expand: true, + x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'], + y_align: Clutter.ActorAlign.START, + style: 'padding: 4px; border-radius: 0 0 4px 4px;' + + 'background-color:' + panelWrapper.dynamicTransparency.currentBackgroundColor + }) + + this._closeButtonBin.add_child(closeButton); + + if (Config.PACKAGE_VERSION >= '3.31.9') { + closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); + } + + // if (headerHeight) { + // this._titleBox = new St.BoxLayout({ height: headerHeight }); + + // this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, style_class: 'preview-label' }); + + // this._titleBox.add_child(this._windowTitle); + // this.add_actor(this._titleBox); + // } + + //this.set_size + + closeButton.connect('clicked', () => this._onCloseBtnClick()); + this.connect('notify::hover', () => this._onHoverChanged()); + this.add_actor(this._previewBin); + this.add_child(this._closeButtonBin); }, assignWindow: function(window, animateSize) { let clone = this._getWindowClone(window); + this.window = window; this._resizeClone(clone); this._addClone(clone, animateSize); }, @@ -409,6 +478,14 @@ var Preview = Utils.defineClass({ return [binWidth, binHeight]; }, + _onHoverChanged: function() { + Tweener.addTween(this._closeButtonBin, getTweenOpts({ opacity: this.hover ? 255 : 0 })); + }, + + _onCloseBtnClick: function() { + this.window.delete(global.get_current_time()); + }, + _addClone: function(newClone, animateSize) { let currentClones = this._previewBin.get_children(); let newCloneOpts = getTweenOpts({ opacity: 255 }); From b4ad83147453b1825c2c70550299797bbb9cab24 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 19 May 2019 11:39:15 -0400 Subject: [PATCH 12/61] Add click actions --- taskbar.js | 10 ---------- windowPreview.js | 25 +++++++++++++++++++++---- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/taskbar.js b/taskbar.js index a41fdce..0cd6431 100644 --- a/taskbar.js +++ b/taskbar.js @@ -544,12 +544,10 @@ var taskbar = Utils.defineClass({ appIcon._draggable.connect('drag-begin', Lang.bind(this, function() { appIcon.actor.opacity = 50; - this._disableWindowPreview(); })); appIcon._draggable.connect('drag-end', Lang.bind(this, function() { appIcon.actor.opacity = 255; - this._enableWindowPreview(); })); } @@ -607,14 +605,6 @@ var taskbar = Utils.defineClass({ return item; }, - _enableWindowPreview: function() { - this.previewMenu.enable(); - }, - - _disableWindowPreview: function() { - this.previewMenu.disable(); - }, - // Return an array with the "proper" appIcons currently in the taskbar _getAppIcons: function() { // Only consider children which are "proper" icons and which are not diff --git a/windowPreview.js b/windowPreview.js index 3cc4e94..956d8c3 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -258,12 +258,12 @@ var PreviewMenu = Utils.defineClass({ switch (event.get_scroll_direction()) { case Clutter.ScrollDirection.UP: - delta = -increment; + delta = -increment; break; case Clutter.ScrollDirection.SMOOTH: - let [dx, dy] = event.get_scroll_delta(); - delta = dy * increment; - delta += dx * increment; + let [dx, dy] = event.get_scroll_delta(); + delta = dy * increment; + delta += dx * increment; break; } @@ -447,6 +447,7 @@ var Preview = Utils.defineClass({ closeButton.connect('clicked', () => this._onCloseBtnClick()); this.connect('notify::hover', () => this._onHoverChanged()); + this.connect('button-release-event', (actor, e) => this._onButtonReleaseEvent(e)); this.add_actor(this._previewBin); this.add_child(this._closeButtonBin); @@ -486,6 +487,22 @@ var Preview = Utils.defineClass({ this.window.delete(global.get_current_time()); }, + _onButtonReleaseEvent: function(e) { + switch (e.get_button()) { + case 1: // Left click + Main.activateWindow(this.window); + this._previewMenu.close(); + break; + case 2: // Middle click + if (this._previewMenu._dtpSettings.get_boolean('preview-middle-click-close')) { + this._onCloseBtnClick(); + } + break; + } + + return Clutter.EVENT_STOP; + }, + _addClone: function(newClone, animateSize) { let currentClones = this._previewBin.get_children(); let newCloneOpts = getTweenOpts({ opacity: 255 }); From 91c2a0a071b886fd8cb7d0558e15988377098171 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 19 May 2019 17:51:07 -0400 Subject: [PATCH 13/61] Add preview hover effect --- transparency.js | 38 +++++++++++++------------------------- utils.js | 23 +++++++++++++++++++++++ windowPreview.js | 41 +++++++++++++++++++++++++++++++++++------ 3 files changed, 71 insertions(+), 31 deletions(-) diff --git a/transparency.js b/transparency.js index 4c1a92f..8f72c67 100644 --- a/transparency.js +++ b/transparency.js @@ -136,7 +136,7 @@ var DynamicTransparency = Utils.defineClass({ }, _updateAnimationDuration: function() { - this._animationDuration = (this._dtpSettings.get_int('trans-dynamic-anim-time') * 0.001) + 's;'; + this.animationDuration = (this._dtpSettings.get_int('trans-dynamic-anim-time') * 0.001) + 's;'; }, _updateAllAndSet: function() { @@ -165,18 +165,18 @@ var DynamicTransparency = Utils.defineClass({ }, _updateColor: function(themeBackground) { - this._backgroundColor = this._dtpSettings.get_boolean('trans-use-custom-bg') ? - this._dtpSettings.get_string('trans-bg-color') : - (themeBackground || this._getThemeBackground()); + this.backgroundColorRgb = this._dtpSettings.get_boolean('trans-use-custom-bg') ? + this._dtpSettings.get_string('trans-bg-color') : + (themeBackground || this._getThemeBackground()); }, _updateAlpha: function(themeBackground) { if (this._windowOverlap && !Main.overview.visibleTarget && this._dtpSettings.get_boolean('trans-use-dynamic-opacity')) { - this._alpha = this._dtpSettings.get_double('trans-dynamic-anim-target'); + this.alpha = this._dtpSettings.get_double('trans-dynamic-anim-target'); } else { - this._alpha = this._dtpSettings.get_boolean('trans-use-custom-opacity') ? - this._dtpSettings.get_double('trans-panel-opacity') : - (themeBackground || this._getThemeBackground()).alpha * 0.003921569; // 1 / 255 = 0.003921569 + this.alpha = this._dtpSettings.get_boolean('trans-use-custom-opacity') ? + this._dtpSettings.get_double('trans-panel-opacity') : + (themeBackground || this._getThemeBackground()).alpha * 0.003921569; // 1 / 255 = 0.003921569 } }, @@ -185,17 +185,17 @@ var DynamicTransparency = Utils.defineClass({ if (this._dtpSettings.get_boolean('trans-use-custom-gradient')) { this._gradientStyle += 'background-gradient-direction: vertical; ' + - 'background-gradient-start: ' + this._getrgbaColor(this._dtpSettings.get_string('trans-gradient-top-color'), + 'background-gradient-start: ' + Utils.getrgbaColor(this._dtpSettings.get_string('trans-gradient-top-color'), this._dtpSettings.get_double('trans-gradient-top-opacity')) + - 'background-gradient-end: ' + this._getrgbaColor(this._dtpSettings.get_string('trans-gradient-bottom-color'), + 'background-gradient-end: ' + Utils.getrgbaColor(this._dtpSettings.get_string('trans-gradient-bottom-color'), this._dtpSettings.get_double('trans-gradient-bottom-opacity')); } }, _setBackground: function() { - this.currentBackgroundColor = this._getrgbaColor(this._backgroundColor, this._alpha); + this.currentBackgroundColor = Utils.getrgbaColor(this.backgroundColorRgb, this.alpha); - let transition = 'transition-duration:' + this._animationDuration; + let transition = 'transition-duration:' + this.animationDuration; let cornerStyle = '-panel-corner-background-color: ' + this.currentBackgroundColor + transition; this._dtpPanel.panelBg.set_style('background-color: ' + this.currentBackgroundColor + transition + this._dtpPanel.panelBg.styles); @@ -209,22 +209,10 @@ var DynamicTransparency = Utils.defineClass({ 'border-image: none; ' + 'background-image: none; ' + this._gradientStyle + - 'transition-duration:' + this._animationDuration + 'transition-duration:' + this.animationDuration ); }, - _getrgbaColor: function(color, alpha) { - if (alpha <= 0) { - return 'transparent; '; - } - - if (typeof color === 'string') { - color = Clutter.color_from_string(color)[1]; - } - - return 'rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + (Math.floor(alpha * 100) * 0.01) + '); ' ; - }, - _getThemeBackground: function(reload) { if (reload || !this._themeBackground) { let fakePanel = new St.Bin({ name: 'panel' }); diff --git a/utils.js b/utils.js index 1af139d..aabf69f 100644 --- a/utils.js +++ b/utils.js @@ -21,6 +21,7 @@ * Some code was also adapted from the upstream Gnome Shell source code. */ +const Clutter = imports.gi.Clutter; const GdkPixbuf = imports.gi.GdkPixbuf const Gi = imports._gi; const Gio = imports.gi.Gio; @@ -320,6 +321,28 @@ var removeKeybinding = function(key) { Main.wm.removeKeybinding(key); } }; + +var getrgbaColor = function(color, alpha, offset) { + if (alpha <= 0) { + return 'transparent; '; + } + + color = typeof color === 'string' ? Clutter.color_from_string(color)[1] : color; + + let rgb = { red: color.red, green: color.green, blue: color.blue }; + + if (offset) { + ['red', 'green', 'blue'].forEach(k => { + rgb[k] = Math.min(255, Math.max(0, rgb[k] + offset)); + + if (rgb[k] == color[k]) { + rgb[k] = Math.min(255, Math.max(0, rgb[k] - offset)); + } + }); + } + + return 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ',' + (Math.floor(alpha * 100) * 0.01) + '); ' ; +}; /** * ColorUtils is adapted from https://github.com/micheleg/dash-to-dock diff --git a/windowPreview.js b/windowPreview.js index 956d8c3..207e8ef 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -39,6 +39,7 @@ const T2 = 'closeMenuTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 40; const DEFAULT_RATIO = { w: 160, h: 90 }; +const HOVER_COLOR_OFFSET = 16; var headerHeight = 0; var isLeftButtons = false; @@ -90,7 +91,7 @@ var PreviewMenu = Utils.defineClass({ // this._titleWindowChangeId = this.window.connect('notify::title', // Lang.bind(this, this._updateWindowTitle)); - // hook settings + // hook settings (animation time, size) }, enable: function() { @@ -171,6 +172,7 @@ var PreviewMenu = Utils.defineClass({ close: function(immediate) { this._currentAppIcon = null; + this._endOpenCloseTimeouts(); if (immediate) { this._resetHiddenState(); @@ -244,7 +246,7 @@ var PreviewMenu = Utils.defineClass({ _onHoverChanged: function() { this._endOpenCloseTimeouts(); - if (!this.menu.hover) { + if (this._currentAppIcon && !this.menu.hover) { this._addCloseTimeout(); } }, @@ -424,8 +426,7 @@ var Preview = Utils.defineClass({ x_expand: true, y_expand: true, x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'], y_align: Clutter.ActorAlign.START, - style: 'padding: 4px; border-radius: 0 0 4px 4px;' + - 'background-color:' + panelWrapper.dynamicTransparency.currentBackgroundColor + style: 'padding: 4px; border-radius: ' + (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;') + this._getBackgroundColor(true) }) this._closeButtonBin.add_child(closeButton); @@ -449,6 +450,9 @@ var Preview = Utils.defineClass({ this.connect('notify::hover', () => this._onHoverChanged()); this.connect('button-release-event', (actor, e) => this._onButtonReleaseEvent(e)); + this.connect('key-focus-in', () => this._onKeyFocusChanged()); + this.connect('key-focus-out', () => this._onKeyFocusChanged()); + this.add_actor(this._previewBin); this.add_child(this._closeButtonBin); }, @@ -480,17 +484,23 @@ var Preview = Utils.defineClass({ }, _onHoverChanged: function() { - Tweener.addTween(this._closeButtonBin, getTweenOpts({ opacity: this.hover ? 255 : 0 })); + this._setFocus(this.hover); + }, + + _onKeyFocusChanged: function() { + this._setFocus(this.has_key_focus()); }, _onCloseBtnClick: function() { this.window.delete(global.get_current_time()); + this._hideOrShowCloseButton(true); }, _onButtonReleaseEvent: function(e) { switch (e.get_button()) { case 1: // Left click Main.activateWindow(this.window); + this._hideOrShowCloseButton(true); this._previewMenu.close(); break; case 2: // Middle click @@ -503,6 +513,25 @@ var Preview = Utils.defineClass({ return Clutter.EVENT_STOP; }, + _setFocus: function(focused) { + this._hideOrShowCloseButton(!focused); + this.set_style(this._getBackgroundColor(focused)); + }, + + _hideOrShowCloseButton: function(hide) { + Tweener.addTween(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 })); + }, + + _getBackgroundColor: function(focused) { + return 'background-color: ' + + Utils.getrgbaColor( + this._panelWrapper.dynamicTransparency.backgroundColorRgb, + focused ? this._panelWrapper.dynamicTransparency.alpha : 0, + HOVER_COLOR_OFFSET + ) + + 'transition-duration:' + this._panelWrapper.dynamicTransparency.animationDuration; + }, + _addClone: function(newClone, animateSize) { let currentClones = this._previewBin.get_children(); let newCloneOpts = getTweenOpts({ opacity: 255 }); @@ -598,7 +627,7 @@ var Preview = Utils.defineClass({ function getTweenOpts(opts) { let defaults = { - time: Taskbar.DASH_ANIMATION_TIME * 2, + time: Taskbar.DASH_ANIMATION_TIME * 1.5, transition: 'easeInOutQuad' }; From 8c4012e2c95996761108db4c2c81bbe09b3efd18 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 20 May 2019 00:25:22 -0400 Subject: [PATCH 14/61] Add preview header bar --- appIcons.js | 2 + windowPreview.js | 161 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 121 insertions(+), 42 deletions(-) diff --git a/appIcons.js b/appIcons.js index dc4d066..7d3470b 100644 --- a/appIcons.js +++ b/appIcons.js @@ -541,6 +541,8 @@ var taskbarAppIcon = Utils.defineClass({ }, _onSwitchWorkspace: function(windowTracker) { + this._previewMenu.close(); + Mainloop.timeout_add(0, Lang.bind(this, function () { this._displayProperIndicator(); return GLib.SOURCE_REMOVE; diff --git a/windowPreview.js b/windowPreview.js index 207e8ef..f7030ed 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -37,9 +37,10 @@ const T1 = 'openMenuTimeout'; const T2 = 'closeMenuTimeout'; const MAX_TRANSLATION = 40; -const HEADER_HEIGHT = 40; +const HEADER_HEIGHT = 38; const DEFAULT_RATIO = { w: 160, h: 90 }; -const HOVER_COLOR_OFFSET = 16; +const FOCUSED_COLOR_OFFSET = 24; +const HEADER_COLOR_OFFSET = -12; var headerHeight = 0; var isLeftButtons = false; @@ -53,7 +54,7 @@ var PreviewMenu = Utils.defineClass({ this._dtpSettings = dtpSettings; this._panelWrapper = panelWrapper; - this._currentAppIcon = null; + this.currentAppIcon = null; this.opened = false; this._position = Taskbar.getPosition(); let isLeftOrRight = this._checkIfLeftOrRight(); @@ -84,14 +85,11 @@ var PreviewMenu = Utils.defineClass({ //'sync-tooltip' //this.add_style_class_name('app-well-menu'); - // add middle click + //peek // move closing delay setting from "advanced" - // this._titleWindowChangeId = this.window.connect('notify::title', - // Lang.bind(this, this._updateWindowTitle)); - - // hook settings (animation time, size) + // hook settings (animation time, size, label color) }, enable: function() { @@ -122,9 +120,13 @@ var PreviewMenu = Utils.defineClass({ [ 'changed::panel-size', 'changed::window-preview-size', - 'changed::window-preview-padding' + 'changed::window-preview-padding', + 'changed::window-preview-show-title' ], - () => this._updateClip() + () => { + this._refreshGlobals(); + this._updateClip(); + } ] ); }, @@ -152,8 +154,8 @@ var PreviewMenu = Utils.defineClass({ }, open: function(appIcon) { - if (this._currentAppIcon != appIcon) { - this._currentAppIcon = appIcon; + if (this.currentAppIcon != appIcon) { + this.currentAppIcon = appIcon; if (!this.opened) { this.menu.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor); @@ -171,7 +173,7 @@ var PreviewMenu = Utils.defineClass({ }, close: function(immediate) { - this._currentAppIcon = null; + this.currentAppIcon = null; this._endOpenCloseTimeouts(); if (immediate) { @@ -182,7 +184,7 @@ var PreviewMenu = Utils.defineClass({ }, update: function(appIcon, windows) { - if (this._currentAppIcon == appIcon) { + if (this.currentAppIcon == appIcon) { if (windows && !windows.length) { this.close(); } else { @@ -232,11 +234,12 @@ var PreviewMenu = Utils.defineClass({ let preview = new Preview(this._panelWrapper, this); this._box.add_child(preview); + preview.adjustOnStage(); preview.assignWindow(window, this.opened); }, getCurrentAppIcon: function() { - return this._currentAppIcon; + return this.currentAppIcon; }, _addCloseTimeout: function() { @@ -246,7 +249,7 @@ var PreviewMenu = Utils.defineClass({ _onHoverChanged: function() { this._endOpenCloseTimeouts(); - if (this._currentAppIcon && !this.menu.hover) { + if (this.currentAppIcon && !this.menu.hover) { this._addCloseTimeout(); } }, @@ -326,9 +329,9 @@ var PreviewMenu = Utils.defineClass({ }, _updatePosition: function() { - 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 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 [previewsWidth, previewsHeight] = this._getPreviewsSize(); let x = 0, y = 0; @@ -415,36 +418,47 @@ var Preview = Utils.defineClass({ this._previewDimensions = this._getPreviewDimensions(); this.animatingOut = false; + let [previewBinWidth, previewBinHeight] = this._getBinSize(); this._previewBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); this._previewBin.set_style('padding: ' + this._padding + 'px;'); - this._previewBin.set_size.apply(this._previewBin, this._getBinSize()); + this._previewBin.set_size(previewBinWidth, previewBinHeight); let closeButton = new St.Button({ style_class: 'window-close', accessible_name: 'Close window' }); - this._closeButtonBin = new St.Widget({ - layout_manager: new Clutter.BinLayout(), - opacity: 0, - x_expand: true, y_expand: true, - x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'], - y_align: Clutter.ActorAlign.START, - style: 'padding: 4px; border-radius: ' + (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;') + this._getBackgroundColor(true) - }) - - this._closeButtonBin.add_child(closeButton); if (Config.PACKAGE_VERSION >= '3.31.9') { closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); } - // if (headerHeight) { - // this._titleBox = new St.BoxLayout({ height: headerHeight }); + this._closeButtonBin = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + opacity: 0, + x_expand: true, y_expand: true, + x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'], + y_align: Clutter.ActorAlign.START + }) - // this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, style_class: 'preview-label' }); + this._closeButtonBin.add_child(closeButton); + + if (headerHeight) { + let headerBox = new St.Widget({ + layout_manager: new Clutter.BoxLayout(), + y_align: Clutter.ActorAlign.START, + y_expand: true, + style: this._getBackgroundColor(HEADER_COLOR_OFFSET, 255) + }); + + this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, x_expand: true }); + + this._iconBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); + this._iconBin.set_size(headerHeight, headerHeight); - // this._titleBox.add_child(this._windowTitle); - // this.add_actor(this._titleBox); - // } + headerBox.add_child(this._iconBin); + headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 0 : 1); - //this.set_size + this.add_child(headerBox); + + this._previewBin.set_position(0, headerHeight); + } closeButton.connect('clicked', () => this._onCloseBtnClick()); this.connect('notify::hover', () => this._onHoverChanged()); @@ -453,14 +467,31 @@ var Preview = Utils.defineClass({ this.connect('key-focus-in', () => this._onKeyFocusChanged()); this.connect('key-focus-out', () => this._onKeyFocusChanged()); - this.add_actor(this._previewBin); + this.connect('destroy', () => this._onDestroy()); + + this.add_child(this._previewBin); this.add_child(this._closeButtonBin); + + this.set_size(-1, previewBinHeight + headerHeight); + }, + + adjustOnStage: function() { + let closeButtonPadding = headerHeight ? Math.round((headerHeight - this._closeButtonBin.height) * .5) : 4; + + this._closeButtonBin.set_style( + 'padding: ' + closeButtonPadding + 'px; ' + + this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 255 : '-') + + 'border-radius: ' + (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;') + ); }, assignWindow: function(window, animateSize) { let clone = this._getWindowClone(window); + this._removeWindowSignals(); this.window = window; + + this._updateHeader(); this._resizeClone(clone); this._addClone(clone, animateSize); }, @@ -483,6 +514,10 @@ var Preview = Utils.defineClass({ return [binWidth, binHeight]; }, + _onDestroy: function() { + this._removeWindowSignals(); + }, + _onHoverChanged: function() { this._setFocus(this.hover); }, @@ -494,6 +529,10 @@ var Preview = Utils.defineClass({ _onCloseBtnClick: function() { this.window.delete(global.get_current_time()); this._hideOrShowCloseButton(true); + + if (!this._previewMenu._dtpSettings.get_boolean('group-apps')) { + this._previewMenu.close(); + } }, _onButtonReleaseEvent: function(e) { @@ -513,21 +552,59 @@ var Preview = Utils.defineClass({ return Clutter.EVENT_STOP; }, + _removeWindowSignals: function() { + if (this._titleWindowChangeId) { + this.window.disconnect(this._titleWindowChangeId); + this._titleWindowChangeId = 0; + } + }, + + _updateHeader: function() { + if (headerHeight) { + let icon = this._previewMenu.getCurrentAppIcon().app.create_icon_texture(headerHeight * .6); + let windowTitleStyle = 'max-width: 0px;'; + + this._iconBin.destroy_all_children(); + this._iconBin.add_child(icon); + + if (isLeftButtons) { + windowTitleStyle += 'padding-left:' + (headerHeight - icon.width) * .5 + 'px;'; + } + + this._titleWindowChangeId = this.window.connect('notify::title', () => this._updateWindowTitle()); + + this._windowTitle.set_style(windowTitleStyle); + this._updateWindowTitle(); + } + }, + + _updateWindowTitle: function() { + this._windowTitle.text = (!this._previewMenu._dtpSettings.get_boolean('isolate-workspaces') ? + '[' + this.window.get_workspace().index() + '] ' : '') + + this.window.title; + }, + _setFocus: function(focused) { this._hideOrShowCloseButton(!focused); - this.set_style(this._getBackgroundColor(focused)); + this.set_style(this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0)); }, _hideOrShowCloseButton: function(hide) { Tweener.addTween(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 })); }, - _getBackgroundColor: function(focused) { + _getBackgroundColor: function(offset, alpha) { + alpha = Math.abs(alpha); + + if (isNaN(alpha)) { + alpha = this._panelWrapper.dynamicTransparency.alpha; + } + return 'background-color: ' + Utils.getrgbaColor( this._panelWrapper.dynamicTransparency.backgroundColorRgb, - focused ? this._panelWrapper.dynamicTransparency.alpha : 0, - HOVER_COLOR_OFFSET + alpha, + offset ) + 'transition-duration:' + this._panelWrapper.dynamicTransparency.animationDuration; }, From 8c65333e3601daae65f563a7d1a68c95a8ee6fe4 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 20 May 2019 10:56:22 -0400 Subject: [PATCH 15/61] Adjust show preview on hotkey --- overview.js | 68 ++++++++++++++----------------------------- windowPreview.js | 75 ++++++++++++++++++++++++++++++++++-------------- 2 files changed, 75 insertions(+), 68 deletions(-) diff --git a/overview.js b/overview.js index 5255acc..9547023 100644 --- a/overview.js +++ b/overview.js @@ -42,6 +42,7 @@ var dtpOverview = Utils.defineClass({ _init: function(settings) { this._numHotkeys = 10; + this._currentHotkeyFocusIndex = -1; this._dtpSettings = settings; }, @@ -179,56 +180,31 @@ var dtpOverview = Utils.defineClass({ if (appIndex < apps.length) { let appIcon = apps[appIndex]; - let windowCount = !appIcon.window ? appIcon._nWindows : seenApps[appIcon.app]; + let seenAppCount = seenApps[appIcon.app]; + let windowCount = appIcon.window || appIcon._hotkeysCycle ? seenAppCount : appIcon._nWindows; if (this._dtpSettings.get_boolean('shortcut-previews') && windowCount > 1) { - let windowIndex = 0; - let currentWindow = appIcon.window; - let hotkeyPrefix = this._dtpSettings.get_string('hotkey-prefix-text'); - let shortcutKeys = (hotkeyPrefix == 'Super' ? [Clutter.Super_L] : [Clutter.Super_L, Clutter.Alt_L]).concat([Clutter['KEY_' + (appIndex + 1)]]); - let currentKeys = shortcutKeys.slice(); - let setFocus = windowIndex => global.stage.set_key_focus(appIcon.windowPreview._previewBox.box.get_children()[windowIndex]); - let capturedEventId = global.stage.connect('captured-event', (actor, event) => { - if (event.type() == Clutter.EventType.KEY_PRESS) { - let pressedKey = event.get_key_symbol(); - - if (shortcutKeys.indexOf(pressedKey) >= 0 && currentKeys.indexOf(pressedKey) < 0) { - currentKeys.push(pressedKey); - - if (shortcutKeys.length === currentKeys.length) { - windowIndex = windowIndex < windowCount - 1 ? windowIndex + 1 : 0; - setFocus(windowIndex); - } - } - } else if (event.type() == Clutter.EventType.KEY_RELEASE) { - let releasedKey = event.get_key_symbol(); - let keyIndex = currentKeys.indexOf(releasedKey); - - if (releasedKey == Clutter.Super_L) { - let thumbnails = appIcon.windowPreview._previewBox.box.get_children(); - let focusedThumbnail = thumbnails.filter(c => c.has_key_focus())[0]; - - focusedThumbnail._delegate.activate(); - } else if (keyIndex >= 0) { - currentKeys.splice(keyIndex, 1); + if (this._currentHotkeyFocusIndex < 0) { + let currentWindow = appIcon.window; + let capturedEventId = global.stage.connect('captured-event', (actor, e) => { + if (e.type() == Clutter.EventType.KEY_RELEASE && e.get_key_symbol() == Clutter.Super_L) { + global.stage.disconnect(capturedEventId); + appIcon._previewMenu.activateFocused(); + appIcon.window = currentWindow; + delete appIcon._hotkeysCycle; + this._currentHotkeyFocusIndex = -1; } - } + + return Clutter.EVENT_PROPAGATE; + }); - return Clutter.EVENT_PROPAGATE; - }); - let hotkeyOpenStateChangedId = appIcon.windowPreview.connect('open-state-changed', (menu, isOpen) => { - if (!isOpen) { - global.stage.disconnect(capturedEventId); - appIcon.windowPreview.disconnect(hotkeyOpenStateChangedId); - appIcon.windowPreview._previewBox._resetPreviews(); - appIcon.window = currentWindow; - } - }); - - appIcon.window = null; - appIcon.windowPreview.popup(); - appIcon.menuManagerWindowPreview._onMenuOpenState(appIcon.windowPreview, true); - setFocus(windowIndex); + appIcon._hotkeysCycle = appIcon.window; + appIcon.window = null; + appIcon._previewMenu.open(appIcon); + global.stage.set_key_focus(appIcon.actor); + } + + this._currentHotkeyFocusIndex = appIcon._previewMenu.focusNext(); } else { // Activate with button = 1, i.e. same as left click let button = 1; diff --git a/windowPreview.js b/windowPreview.js index f7030ed..2011b76 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -55,6 +55,7 @@ var PreviewMenu = Utils.defineClass({ this._dtpSettings = dtpSettings; this._panelWrapper = panelWrapper; this.currentAppIcon = null; + this._focusedPreview = null; this.opened = false; this._position = Taskbar.getPosition(); let isLeftOrRight = this._checkIfLeftOrRight(); @@ -96,13 +97,13 @@ var PreviewMenu = Utils.defineClass({ this._timeoutsHandler = new Utils.TimeoutsHandler(); this._signalsHandler = new Utils.GlobalSignalsHandler(); - Main.uiGroup.insert_child_below(this, this._panelWrapper.panelBox); - Main.layoutManager._trackActor(this, { trackFullscreen: true, affectsInputRegion: false }); + Main.layoutManager.addChrome(this, { trackFullscreen: true, affectsInputRegion: false }); Main.layoutManager.trackChrome(this.menu, { affectsInputRegion: true }); this._resetHiddenState(); this._refreshGlobals(); this._updateClip(); + this.menu.set_position(1, 1); this._signalsHandler.add( [ @@ -174,6 +175,7 @@ var PreviewMenu = Utils.defineClass({ close: function(immediate) { this.currentAppIcon = null; + this.removeFocus(); this._endOpenCloseTimeouts(); if (immediate) { @@ -194,6 +196,33 @@ var PreviewMenu = Utils.defineClass({ } }, + focusNext: function() { + let previews = this._box.get_children(); + let currentIndex = this._focusedPreview ? previews.indexOf(this._focusedPreview) : -1; + let nextIndex = currentIndex + 1; + + nextIndex = previews[nextIndex] ? nextIndex : 0; + + this.removeFocus(); + previews[nextIndex].setFocus(true); + this._focusedPreview = previews[nextIndex]; + + return nextIndex; + }, + + activateFocused: function() { + if (this.opened && this._focusedPreview) { + this._focusedPreview.activate(); + } + }, + + removeFocus: function() { + if (this._focusedPreview) { + this._focusedPreview.setFocus(false); + this._focusedPreview = null; + } + }, + _mergeWindows: function(appIcon, windows) { windows = windows || (appIcon.window ? [appIcon.window] : appIcon.getAppIconInterestingWindows()); windows.sort(Taskbar.sortWindowsCompareFunction); @@ -444,7 +473,7 @@ var Preview = Utils.defineClass({ layout_manager: new Clutter.BoxLayout(), y_align: Clutter.ActorAlign.START, y_expand: true, - style: this._getBackgroundColor(HEADER_COLOR_OFFSET, 255) + style: this._getBackgroundColor(HEADER_COLOR_OFFSET, .8) }); this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, x_expand: true }); @@ -464,9 +493,6 @@ var Preview = Utils.defineClass({ this.connect('notify::hover', () => this._onHoverChanged()); this.connect('button-release-event', (actor, e) => this._onButtonReleaseEvent(e)); - this.connect('key-focus-in', () => this._onKeyFocusChanged()); - this.connect('key-focus-out', () => this._onKeyFocusChanged()); - this.connect('destroy', () => this._onDestroy()); this.add_child(this._previewBin); @@ -477,11 +503,16 @@ var Preview = Utils.defineClass({ adjustOnStage: function() { let closeButtonPadding = headerHeight ? Math.round((headerHeight - this._closeButtonBin.height) * .5) : 4; - + let closeButtonBorderRadius = ''; + + if (!headerHeight) { + closeButtonBorderRadius = 'border-radius: ' + (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;'); + } + this._closeButtonBin.set_style( 'padding: ' + closeButtonPadding + 'px; ' + - this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 255 : '-') + - 'border-radius: ' + (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;') + this._getBackgroundColor(HEADER_COLOR_OFFSET, .8) + + closeButtonBorderRadius ); }, @@ -514,16 +545,23 @@ var Preview = Utils.defineClass({ return [binWidth, binHeight]; }, + setFocus: function(focused) { + this._hideOrShowCloseButton(!focused); + this.set_style(this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0)); + }, + + activate: function() { + Main.activateWindow(this.window); + this._hideOrShowCloseButton(true); + this._previewMenu.close(); + }, + _onDestroy: function() { this._removeWindowSignals(); }, _onHoverChanged: function() { - this._setFocus(this.hover); - }, - - _onKeyFocusChanged: function() { - this._setFocus(this.has_key_focus()); + this.setFocus(this.hover); }, _onCloseBtnClick: function() { @@ -538,9 +576,7 @@ var Preview = Utils.defineClass({ _onButtonReleaseEvent: function(e) { switch (e.get_button()) { case 1: // Left click - Main.activateWindow(this.window); - this._hideOrShowCloseButton(true); - this._previewMenu.close(); + this.activate(); break; case 2: // Middle click if (this._previewMenu._dtpSettings.get_boolean('preview-middle-click-close')) { @@ -584,11 +620,6 @@ var Preview = Utils.defineClass({ this.window.title; }, - _setFocus: function(focused) { - this._hideOrShowCloseButton(!focused); - this.set_style(this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0)); - }, - _hideOrShowCloseButton: function(hide) { Tweener.addTween(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 })); }, From ea29926ea744bad14222de6f2299d8b3331b26ea Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 20 May 2019 15:10:11 -0400 Subject: [PATCH 16/61] Add dedicated label for the workspace index --- windowPreview.js | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 2011b76..346e800 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -476,13 +476,15 @@ var Preview = Utils.defineClass({ style: this._getBackgroundColor(HEADER_COLOR_OFFSET, .8) }); + this._workspaceIndicator = new St.Label({ y_align: Clutter.ActorAlign.CENTER }); this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, x_expand: true }); this._iconBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); this._iconBin.set_size(headerHeight, headerHeight); headerBox.add_child(this._iconBin); - headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 0 : 1); + headerBox.insert_child_at_index(this._workspaceIndicator, isLeftButtons ? 0 : 1); + headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 1 : 2); this.add_child(headerBox); @@ -600,6 +602,7 @@ var Preview = Utils.defineClass({ let icon = this._previewMenu.getCurrentAppIcon().app.create_icon_texture(headerHeight * .6); let windowTitleStyle = 'max-width: 0px;'; + icon.y_align = Clutter.ActorAlign.CENTER; this._iconBin.destroy_all_children(); this._iconBin.add_child(icon); @@ -615,9 +618,19 @@ var Preview = Utils.defineClass({ }, _updateWindowTitle: function() { - this._windowTitle.text = (!this._previewMenu._dtpSettings.get_boolean('isolate-workspaces') ? - '[' + this.window.get_workspace().index() + '] ' : '') + - this.window.title; + let workspaceIndex = ''; + let workspaceStyle = null; + + if (!this._previewMenu._dtpSettings.get_boolean('isolate-workspaces')) { + workspaceIndex = this.window.get_workspace().index().toString(); + workspaceStyle = 'padding: 0 4px; border: 2px solid ' + this._getRgbaColor(FOCUSED_COLOR_OFFSET, .8) + + 'border-radius: 2px; margin-right: 4px;'; + } + + this._workspaceIndicator.text = workspaceIndex; + this._workspaceIndicator.set_style(workspaceStyle); + + this._windowTitle.text = this.window.title; }, _hideOrShowCloseButton: function(hide) { @@ -625,19 +638,18 @@ var Preview = Utils.defineClass({ }, _getBackgroundColor: function(offset, alpha) { + return 'background-color: ' + this._getRgbaColor(offset, alpha) + + 'transition-duration:' + this._panelWrapper.dynamicTransparency.animationDuration; + }, + + _getRgbaColor: function(offset, alpha) { alpha = Math.abs(alpha); if (isNaN(alpha)) { alpha = this._panelWrapper.dynamicTransparency.alpha; } - return 'background-color: ' + - Utils.getrgbaColor( - this._panelWrapper.dynamicTransparency.backgroundColorRgb, - alpha, - offset - ) + - 'transition-duration:' + this._panelWrapper.dynamicTransparency.animationDuration; + return Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, alpha, offset); }, _addClone: function(newClone, animateSize) { From 29b3459a765e0cbb8dc135d91f44b7c96cc6ac89 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 20 May 2019 19:32:18 -0400 Subject: [PATCH 17/61] Adjust preview header dimensions with scale factor --- windowPreview.js | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 346e800..d5dc8a4 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -44,6 +44,7 @@ const HEADER_COLOR_OFFSET = -12; var headerHeight = 0; var isLeftButtons = false; +var scaleFactor = 1; var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel.PreviewMenu', @@ -313,8 +314,9 @@ var PreviewMenu = Utils.defineClass({ }, _refreshGlobals: function() { - headerHeight = this._dtpSettings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT : 0; isLeftButtons = Meta.prefs_get_button_layout().left_buttons.indexOf(Meta.ButtonFunction.CLOSE) >= 0; + scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; + headerHeight = this._dtpSettings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT * scaleFactor : 0; }, _resetHiddenState: function() { @@ -327,29 +329,28 @@ var PreviewMenu = Utils.defineClass({ _updateClip: function() { let x, y, w, h; - let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - let panelSize = this._dtpSettings.get_int('panel-size'); - let previewSize = this._dtpSettings.get_int('window-preview-size') + - this._dtpSettings.get_int('window-preview-padding') * 2; + let panelSize = this._dtpSettings.get_int('panel-size') * scaleFactor; + let previewSize = (this._dtpSettings.get_int('window-preview-size') + + this._dtpSettings.get_int('window-preview-padding') * 2) * scaleFactor; if (this._checkIfLeftOrRight()) { - w = previewSize * scaleFactor; + w = previewSize; h = this._panelWrapper.monitor.height; y = this._panelWrapper.monitor.y; } else { w = this._panelWrapper.monitor.width; - h = (previewSize + headerHeight) * scaleFactor; + h = (previewSize + headerHeight); x = this._panelWrapper.monitor.x; } if (this._position == St.Side.LEFT) { - x = this._panelWrapper.monitor.x + panelSize * scaleFactor; + x = this._panelWrapper.monitor.x + panelSize; } else if (this._position == St.Side.RIGHT) { - x = this._panelWrapper.monitor.x + this._panelWrapper.monitor.width - (panelSize + previewSize) * scaleFactor; + x = this._panelWrapper.monitor.x + this._panelWrapper.monitor.width - (panelSize + previewSize) ; } else if (this._position == St.Side.TOP) { - y = this._panelWrapper.monitor.y + panelSize * scaleFactor; + y = this._panelWrapper.monitor.y + panelSize; } else { //St.Side.BOTTOM - y = this._panelWrapper.monitor.y + this._panelWrapper.monitor.height - (panelSize + previewSize + headerHeight) * scaleFactor; + y = this._panelWrapper.monitor.y + this._panelWrapper.monitor.height - (panelSize + previewSize + headerHeight); } this.set_clip(0, 0, w, h); @@ -443,7 +444,7 @@ var Preview = Utils.defineClass({ this._panelWrapper = panelWrapper; this._previewMenu = previewMenu; - this._padding = previewMenu._dtpSettings.get_int('window-preview-padding') * St.ThemeContext.get_for_stage(global.stage).scale_factor; + this._padding = previewMenu._dtpSettings.get_int('window-preview-padding') * scaleFactor; this._previewDimensions = this._getPreviewDimensions(); this.animatingOut = false; @@ -464,7 +465,7 @@ var Preview = Utils.defineClass({ x_expand: true, y_expand: true, x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'], y_align: Clutter.ActorAlign.START - }) + }); this._closeButtonBin.add_child(closeButton); @@ -504,7 +505,7 @@ var Preview = Utils.defineClass({ }, adjustOnStage: function() { - let closeButtonPadding = headerHeight ? Math.round((headerHeight - this._closeButtonBin.height) * .5) : 4; + let closeButtonPadding = headerHeight ? Math.round((headerHeight - this._closeButtonBin.height) * .5 / scaleFactor) : 4; let closeButtonBorderRadius = ''; if (!headerHeight) { @@ -599,10 +600,10 @@ var Preview = Utils.defineClass({ _updateHeader: function() { if (headerHeight) { - let icon = this._previewMenu.getCurrentAppIcon().app.create_icon_texture(headerHeight * .6); + let iconTextureSize = headerHeight / scaleFactor * .6; + let icon = this._previewMenu.getCurrentAppIcon().app.create_icon_texture(iconTextureSize); let windowTitleStyle = 'max-width: 0px;'; - icon.y_align = Clutter.ActorAlign.CENTER; this._iconBin.destroy_all_children(); this._iconBin.add_child(icon); @@ -730,7 +731,7 @@ var Preview = Utils.defineClass({ }, _getPreviewDimensions: function() { - let size = this._previewMenu._dtpSettings.get_int('window-preview-size') * St.ThemeContext.get_for_stage(global.stage).scale_factor; + let size = this._previewMenu._dtpSettings.get_int('window-preview-size') * scaleFactor; let w, h; if (this._previewMenu._checkIfLeftOrRight()) { From 1d1a5ce85acd1f39833dc2fca188b046602a3633 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 21 May 2019 14:31:55 -0400 Subject: [PATCH 18/61] Add window peek --- appIcons.js | 7 +-- overview.js | 5 ++- windowPreview.js | 113 ++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 107 insertions(+), 18 deletions(-) diff --git a/appIcons.js b/appIcons.js index 7d3470b..638e4b3 100644 --- a/appIcons.js +++ b/appIcons.js @@ -541,12 +541,7 @@ var taskbarAppIcon = Utils.defineClass({ }, _onSwitchWorkspace: function(windowTracker) { - this._previewMenu.close(); - - Mainloop.timeout_add(0, Lang.bind(this, function () { - this._displayProperIndicator(); - return GLib.SOURCE_REMOVE; - })); + this._displayProperIndicator(); }, _displayProperIndicator: function (force) { diff --git a/overview.js b/overview.js index 9547023..384fc25 100644 --- a/overview.js +++ b/overview.js @@ -186,9 +186,12 @@ var dtpOverview = Utils.defineClass({ if (this._dtpSettings.get_boolean('shortcut-previews') && windowCount > 1) { if (this._currentHotkeyFocusIndex < 0) { let currentWindow = appIcon.window; + let keyFocusOutId = appIcon.actor.connect('key-focus-out', () => appIcon.actor.grab_key_focus()); let capturedEventId = global.stage.connect('captured-event', (actor, e) => { if (e.type() == Clutter.EventType.KEY_RELEASE && e.get_key_symbol() == Clutter.Super_L) { global.stage.disconnect(capturedEventId); + appIcon.actor.disconnect(keyFocusOutId); + appIcon._previewMenu.activateFocused(); appIcon.window = currentWindow; delete appIcon._hotkeysCycle; @@ -201,7 +204,7 @@ var dtpOverview = Utils.defineClass({ appIcon._hotkeysCycle = appIcon.window; appIcon.window = null; appIcon._previewMenu.open(appIcon); - global.stage.set_key_focus(appIcon.actor); + appIcon.actor.grab_key_focus(); } this._currentHotkeyFocusIndex = appIcon._previewMenu.focusNext(); diff --git a/windowPreview.js b/windowPreview.js index d5dc8a4..f70900e 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -30,17 +30,17 @@ const Me = imports.misc.extensionUtils.getCurrentExtension(); const Taskbar = Me.imports.taskbar; const Utils = Me.imports.utils; -//timeout intervals - //timeout names const T1 = 'openMenuTimeout'; const T2 = 'closeMenuTimeout'; +const T3 = 'enterPeekTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; const DEFAULT_RATIO = { w: 160, h: 90 }; const FOCUSED_COLOR_OFFSET = 24; const HEADER_COLOR_OFFSET = -12; +const WORKSPACE_SWITCH_TIME = 120; var headerHeight = 0; var isLeftButtons = false; @@ -57,6 +57,8 @@ var PreviewMenu = Utils.defineClass({ this._panelWrapper = panelWrapper; this.currentAppIcon = null; this._focusedPreview = null; + this._peekedWorkspace = null; + this._peekInitialWorkspace = null; this.opened = false; this._position = Taskbar.getPosition(); let isLeftOrRight = this._checkIfLeftOrRight(); @@ -91,7 +93,7 @@ var PreviewMenu = Utils.defineClass({ // move closing delay setting from "advanced" - // hook settings (animation time, size, label color) + // hook settings (animation time, size, label color, header location) }, enable: function() { @@ -175,15 +177,17 @@ var PreviewMenu = Utils.defineClass({ }, close: function(immediate) { - this.currentAppIcon = null; - this.removeFocus(); this._endOpenCloseTimeouts(); + this._removeFocus(); + this._endPeek(); if (immediate) { this._resetHiddenState(); } else { this._animateOpenOrClose(false, () => this._resetHiddenState()); } + + this.currentAppIcon = null; }, update: function(appIcon, windows) { @@ -204,9 +208,11 @@ var PreviewMenu = Utils.defineClass({ nextIndex = previews[nextIndex] ? nextIndex : 0; - this.removeFocus(); - previews[nextIndex].setFocus(true); - this._focusedPreview = previews[nextIndex]; + if (previews[nextIndex]) { + this._removeFocus(); + previews[nextIndex].setFocus(true); + this._focusedPreview = previews[nextIndex]; + } return nextIndex; }, @@ -217,7 +223,23 @@ var PreviewMenu = Utils.defineClass({ } }, - removeFocus: function() { + requestPeek(window) { + this._timeoutsHandler.remove(T3); + + if (this._dtpSettings.get_boolean('peek-mode')) { + if (!this._peekInitialWorkspace) { + this._timeoutsHandler.add([T3, this._dtpSettings.get_int('enter-peek-mode-timeout'), () => this._peek(window)]); + } else { + this._peek(window); + } + } + }, + + endPeekHere: function() { + this._endPeek(true); + }, + + _removeFocus: function() { if (this._focusedPreview) { this._focusedPreview.setFocus(false); this._focusedPreview = null; @@ -427,7 +449,71 @@ var PreviewMenu = Utils.defineClass({ _checkIfLeftOrRight: function() { return this._position == St.Side.LEFT || this._position == St.Side.RIGHT; - } + }, + + _peek: function(window) { + let currentWorkspace = this._getCurrentWorkspace(); + let windowWorkspace = window.get_workspace(); + let needsWorspaceChange = currentWorkspace != windowWorkspace; + + this._timeoutsHandler.remove(T3); + + if (this._peekedWorkspace) { + if (needsWorspaceChange) { + this._timeoutsHandler.add([T3, WORKSPACE_SWITCH_TIME, () => this._changeWorkspaceWindows(currentWorkspace, 255, true)]); + } else { + this._changeWorkspaceWindows(this._peekedWorkspace, 255, false); + } + } + + this._changeWorkspaceWindows(windowWorkspace, 0, needsWorspaceChange, window); + this._peekedWorkspace = windowWorkspace; + + if (needsWorspaceChange) { + this._switchToWorkspace(windowWorkspace); + } + + if (!this._peekInitialWorkspace) { + this._peekInitialWorkspace = currentWorkspace; + } + }, + + _endPeek: function(stayHere) { + this._timeoutsHandler.remove(T3); + + if (this._peekedWorkspace) { + this._changeWorkspaceWindows(this._peekedWorkspace, 255, this._peekedWorkspace != this._peekInitialWorkspace); + + if (!stayHere) { + this._switchToWorkspace(this._peekInitialWorkspace); + } + } + + this._peekedWorkspace = null; + this._peekInitialWorkspace = null; + }, + + _changeWorkspaceWindows: function(workspace, opacity, immediate, ignoredWindow) { + workspace.list_windows() + .filter(mw => !mw.minimized && !mw.is_on_all_workspaces() && mw != ignoredWindow) + .forEach(mw => { + let windowActor = mw.get_compositor_private(); + + if (immediate) { + windowActor.opacity = opacity; + } else { + Tweener.addTween(windowActor, getTweenOpts({ opacity: opacity })); + } + }); + }, + + _getCurrentWorkspace: function() { + return Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); + }, + + _switchToWorkspace: function(workspace) { + workspace.activate(1); + }, }); var Preview = Utils.defineClass({ @@ -551,11 +637,16 @@ var Preview = Utils.defineClass({ setFocus: function(focused) { this._hideOrShowCloseButton(!focused); this.set_style(this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0)); + + if (focused) { + this._previewMenu.requestPeek(this.window); + } }, activate: function() { Main.activateWindow(this.window); this._hideOrShowCloseButton(true); + this._previewMenu.endPeekHere(); this._previewMenu.close(); }, @@ -623,7 +714,7 @@ var Preview = Utils.defineClass({ let workspaceStyle = null; if (!this._previewMenu._dtpSettings.get_boolean('isolate-workspaces')) { - workspaceIndex = this.window.get_workspace().index().toString(); + workspaceIndex = (this.window.get_workspace().index() + 1).toString(); workspaceStyle = 'padding: 0 4px; border: 2px solid ' + this._getRgbaColor(FOCUSED_COLOR_OFFSET, .8) + 'border-radius: 2px; margin-right: 4px;'; } From 448c9baae4f54db5e0afca1b7388cc62023e3a5b Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Wed, 22 May 2019 21:37:53 -0400 Subject: [PATCH 19/61] Dim other windows during peek --- windowPreview.js | 86 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 28 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index f70900e..6de8e35 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -24,6 +24,7 @@ const Signals = imports.signals; const Shell = imports.gi.Shell; const St = imports.gi.St; const Tweener = imports.ui.tweener; +const WindowManager = imports.ui.windowManager; const Workspace = imports.ui.workspace; const Me = imports.misc.extensionUtils.getCurrentExtension(); @@ -34,17 +35,19 @@ const Utils = Me.imports.utils; const T1 = 'openMenuTimeout'; const T2 = 'closeMenuTimeout'; const T3 = 'enterPeekTimeout'; +const T4 = 'switchWorkspaceTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; const DEFAULT_RATIO = { w: 160, h: 90 }; const FOCUSED_COLOR_OFFSET = 24; const HEADER_COLOR_OFFSET = -12; -const WORKSPACE_SWITCH_TIME = 120; +const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; var headerHeight = 0; var isLeftButtons = false; var scaleFactor = 1; +var workspaceSwitchTime = WindowManager.WINDOW_ANIMATION_TIME * 1020; var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel.PreviewMenu', @@ -59,6 +62,7 @@ var PreviewMenu = Utils.defineClass({ this._focusedPreview = null; this._peekedWorkspace = null; this._peekInitialWorkspace = null; + this._onWorkspaceSwitchComplete = null; this.opened = false; this._position = Taskbar.getPosition(); let isLeftOrRight = this._checkIfLeftOrRight(); @@ -454,25 +458,29 @@ var PreviewMenu = Utils.defineClass({ _peek: function(window) { let currentWorkspace = this._getCurrentWorkspace(); let windowWorkspace = window.get_workspace(); - let needsWorspaceChange = currentWorkspace != windowWorkspace; - - this._timeoutsHandler.remove(T3); - - if (this._peekedWorkspace) { - if (needsWorspaceChange) { - this._timeoutsHandler.add([T3, WORKSPACE_SWITCH_TIME, () => this._changeWorkspaceWindows(currentWorkspace, 255, true)]); - } else { - this._changeWorkspaceWindows(this._peekedWorkspace, 255, false); + let targetOpacity = this._dtpSettings.get_int('peek-mode-opacity'); + let wasPeeked = !!this._peekedWorkspace; + this._onWorkspaceSwitchComplete = () => { + if (wasPeeked) { + this._changeWorkspaceWindows(currentWorkspace, 255, true); } + + this._changeWorkspaceWindows(windowWorkspace, targetOpacity, false, window); + }; + + if (currentWorkspace != windowWorkspace) { + this._changeWorkspaceWindows(windowWorkspace, targetOpacity, true, null, true); + windowWorkspace.activate(1); + this._timeoutsHandler.add([T4, workspaceSwitchTime, () => this._onWorkspaceSwitchComplete()]); + } else if (this._timeoutsHandler.getId(T4)) { + //the window opacity animation doesn't work while the workspace is switching, do it when it completes instead + return this._onWorkspaceSwitchComplete = () => this._peek(window); + } else { + this._changeWorkspaceWindows(windowWorkspace, targetOpacity, false, window); } - this._changeWorkspaceWindows(windowWorkspace, 0, needsWorspaceChange, window); this._peekedWorkspace = windowWorkspace; - if (needsWorspaceChange) { - this._switchToWorkspace(windowWorkspace); - } - if (!this._peekInitialWorkspace) { this._peekInitialWorkspace = currentWorkspace; } @@ -480,29 +488,54 @@ var PreviewMenu = Utils.defineClass({ _endPeek: function(stayHere) { this._timeoutsHandler.remove(T3); + this._timeoutsHandler.remove(T4); if (this._peekedWorkspace) { this._changeWorkspaceWindows(this._peekedWorkspace, 255, this._peekedWorkspace != this._peekInitialWorkspace); if (!stayHere) { - this._switchToWorkspace(this._peekInitialWorkspace); - } + this._peekInitialWorkspace.activate(1); + } } this._peekedWorkspace = null; this._peekInitialWorkspace = null; + this._onWorkspaceSwitchComplete = null; }, - _changeWorkspaceWindows: function(workspace, opacity, immediate, ignoredWindow) { - workspace.list_windows() - .filter(mw => !mw.minimized && !mw.is_on_all_workspaces() && mw != ignoredWindow) - .forEach(mw => { + _changeWorkspaceWindows: function(workspace, opacity, immediate, focusedWindow, ignoreRestack) { + if (Main.overview.visibleTarget) { + return; + } + + workspace.list_windows().filter(mw => !mw.is_on_all_workspaces()).forEach(mw => { let windowActor = mw.get_compositor_private(); + let isFocusedWindow = mw == focusedWindow; + let targetOpacity = isFocusedWindow ? 255 : opacity; + + if (!ignoreRestack && (isFocusedWindow || mw.hasOwnProperty(PEEK_INDEX_PROP))) { + let windowActorIndex = global.window_group.get_children().indexOf(windowActor); + + if (windowActorIndex >= 0) { + if (isFocusedWindow) { + mw[PEEK_INDEX_PROP] = windowActorIndex; + global.window_group.set_child_above_sibling(windowActor, null); + } else { + global.window_group.set_child_at_index(windowActor, mw[PEEK_INDEX_PROP]); + delete mw[PEEK_INDEX_PROP]; + } + } + } + + if (isFocusedWindow && mw.minimized) { + windowActor.opacity = 0; + windowActor.show(); + } if (immediate) { - windowActor.opacity = opacity; + windowActor.opacity = targetOpacity; } else { - Tweener.addTween(windowActor, getTweenOpts({ opacity: opacity })); + Tweener.addTween(windowActor, getTweenOpts({ opacity: targetOpacity })); } }); }, @@ -510,10 +543,6 @@ var PreviewMenu = Utils.defineClass({ _getCurrentWorkspace: function() { return Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); }, - - _switchToWorkspace: function(workspace) { - workspace.activate(1); - }, }); var Preview = Utils.defineClass({ @@ -644,10 +673,10 @@ var Preview = Utils.defineClass({ }, activate: function() { - Main.activateWindow(this.window); this._hideOrShowCloseButton(true); this._previewMenu.endPeekHere(); this._previewMenu.close(); + Main.activateWindow(this.window); }, _onDestroy: function() { @@ -661,6 +690,7 @@ var Preview = Utils.defineClass({ _onCloseBtnClick: function() { this.window.delete(global.get_current_time()); this._hideOrShowCloseButton(true); + this.reactive = false; if (!this._previewMenu._dtpSettings.get_boolean('group-apps')) { this._previewMenu.close(); From d7c59efbf6351f4e9408c1e712d796952c90328d Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 23 May 2019 17:59:50 -0400 Subject: [PATCH 20/61] Remove workspace switch animation during peek --- windowPreview.js | 112 +++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 58 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 6de8e35..7c349f8 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -34,8 +34,7 @@ const Utils = Me.imports.utils; //timeout names const T1 = 'openMenuTimeout'; const T2 = 'closeMenuTimeout'; -const T3 = 'enterPeekTimeout'; -const T4 = 'switchWorkspaceTimeout'; +const T3 = 'peekTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; @@ -60,9 +59,8 @@ var PreviewMenu = Utils.defineClass({ this._panelWrapper = panelWrapper; this.currentAppIcon = null; this._focusedPreview = null; - this._peekedWorkspace = null; + this._peekedWindow = null; this._peekInitialWorkspace = null; - this._onWorkspaceSwitchComplete = null; this.opened = false; this._position = Taskbar.getPosition(); let isLeftOrRight = this._checkIfLeftOrRight(); @@ -176,6 +174,7 @@ var PreviewMenu = Utils.defineClass({ this._updatePosition(); this._animateOpenOrClose(true); + this.menu.reactive = true; this.opened = true; } }, @@ -184,13 +183,15 @@ var PreviewMenu = Utils.defineClass({ this._endOpenCloseTimeouts(); this._removeFocus(); this._endPeek(); - + if (immediate) { this._resetHiddenState(); } else { this._animateOpenOrClose(false, () => this._resetHiddenState()); } + this._box.get_children().forEach(c => c.reactive = false); + this.menu.reactive = false; this.currentAppIcon = null; }, @@ -458,29 +459,17 @@ var PreviewMenu = Utils.defineClass({ _peek: function(window) { let currentWorkspace = this._getCurrentWorkspace(); let windowWorkspace = window.get_workspace(); - let targetOpacity = this._dtpSettings.get_int('peek-mode-opacity'); - let wasPeeked = !!this._peekedWorkspace; - this._onWorkspaceSwitchComplete = () => { - if (wasPeeked) { - this._changeWorkspaceWindows(currentWorkspace, 255, true); - } - - this._changeWorkspaceWindows(windowWorkspace, targetOpacity, false, window); - }; + let focusWindow = () => this._focusMetaWindow(this._dtpSettings.get_int('peek-mode-opacity'), window); + + this._restorePeekedWindowStack(); if (currentWorkspace != windowWorkspace) { - this._changeWorkspaceWindows(windowWorkspace, targetOpacity, true, null, true); - windowWorkspace.activate(1); - this._timeoutsHandler.add([T4, workspaceSwitchTime, () => this._onWorkspaceSwitchComplete()]); - } else if (this._timeoutsHandler.getId(T4)) { - //the window opacity animation doesn't work while the workspace is switching, do it when it completes instead - return this._onWorkspaceSwitchComplete = () => this._peek(window); + this._switchToWorkspaceImmediate(windowWorkspace); + this._timeoutsHandler.add([T3, 100, focusWindow]); } else { - this._changeWorkspaceWindows(windowWorkspace, targetOpacity, false, window); + focusWindow(); } - this._peekedWorkspace = windowWorkspace; - if (!this._peekInitialWorkspace) { this._peekInitialWorkspace = currentWorkspace; } @@ -488,58 +477,67 @@ var PreviewMenu = Utils.defineClass({ _endPeek: function(stayHere) { this._timeoutsHandler.remove(T3); - this._timeoutsHandler.remove(T4); - if (this._peekedWorkspace) { - this._changeWorkspaceWindows(this._peekedWorkspace, 255, this._peekedWorkspace != this._peekInitialWorkspace); + if (this._peekedWindow) { + this._restorePeekedWindowStack(); if (!stayHere) { - this._peekInitialWorkspace.activate(1); + this._switchToWorkspaceImmediate(this._peekInitialWorkspace); } - } - this._peekedWorkspace = null; - this._peekInitialWorkspace = null; - this._onWorkspaceSwitchComplete = null; + this._focusMetaWindow(255); + this._peekedWindow = null; + this._peekInitialWorkspace = null; + } }, - _changeWorkspaceWindows: function(workspace, opacity, immediate, focusedWindow, ignoreRestack) { + _switchToWorkspaceImmediate: function(workspace) { + Main.wm._blockAnimations = true; + workspace.activate(1); + Main.wm._blockAnimations = false; + }, + + _focusMetaWindow: function(dimOpacity, metaWindow) { if (Main.overview.visibleTarget) { return; } - workspace.list_windows().filter(mw => !mw.is_on_all_workspaces()).forEach(mw => { - let windowActor = mw.get_compositor_private(); - let isFocusedWindow = mw == focusedWindow; - let targetOpacity = isFocusedWindow ? 255 : opacity; + this._peekedWindow = metaWindow; - if (!ignoreRestack && (isFocusedWindow || mw.hasOwnProperty(PEEK_INDEX_PROP))) { - let windowActorIndex = global.window_group.get_children().indexOf(windowActor); + global.get_window_actors().forEach(wa => { + let mw = wa.meta_window; + let isFocused = mw == metaWindow; - if (windowActorIndex >= 0) { - if (isFocusedWindow) { - mw[PEEK_INDEX_PROP] = windowActorIndex; - global.window_group.set_child_above_sibling(windowActor, null); - } else { - global.window_group.set_child_at_index(windowActor, mw[PEEK_INDEX_PROP]); - delete mw[PEEK_INDEX_PROP]; - } + if (mw) { + if (isFocused) { + mw[PEEK_INDEX_PROP] = wa.get_parent().get_children().indexOf(wa); + wa.get_parent().set_child_above_sibling(wa, null); } - } - if (isFocusedWindow && mw.minimized) { - windowActor.opacity = 0; - windowActor.show(); - } - - if (immediate) { - windowActor.opacity = targetOpacity; - } else { - Tweener.addTween(windowActor, getTweenOpts({ opacity: targetOpacity })); + if (isFocused && mw.minimized) { + wa.show(); + } + + Tweener.addTween(wa, getTweenOpts({ opacity: isFocused ? 255 : dimOpacity })); } }); }, + _restorePeekedWindowStack: function() { + let windowActor = this._peekedWindow ? this._peekedWindow.get_compositor_private() : null; + + if (windowActor) { + if (this._peekedWindow.hasOwnProperty(PEEK_INDEX_PROP)) { + windowActor.get_parent().set_child_at_index(windowActor, this._peekedWindow[PEEK_INDEX_PROP]); + delete this._peekedWindow[PEEK_INDEX_PROP]; + } + + if(this._peekedWindow.minimized) { + windowActor.hide(); + } + } + }, + _getCurrentWorkspace: function() { return Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); }, @@ -673,7 +671,6 @@ var Preview = Utils.defineClass({ }, activate: function() { - this._hideOrShowCloseButton(true); this._previewMenu.endPeekHere(); this._previewMenu.close(); Main.activateWindow(this.window); @@ -816,7 +813,6 @@ var Preview = Utils.defineClass({ _getWindowClone: function(window) { return new Clutter.Clone({ source: window.get_compositor_private(), - reactive: true, opacity: 0, y_align: Clutter.ActorAlign.CENTER, x_align: Clutter.ActorAlign.CENTER From 64cd3404c6270107d467a48d5aa9a328c8aa3aca Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 23 May 2019 20:08:49 -0400 Subject: [PATCH 21/61] Add and adjust preview settings --- Settings.ui | 1124 +++++++++-------- prefs.js | 117 +- ...shell.extensions.dash-to-panel.gschema.xml | 27 +- windowPreview.js | 30 +- 4 files changed, 704 insertions(+), 594 deletions(-) diff --git a/Settings.ui b/Settings.ui index b2bdcb7..4fa4f91 100644 --- a/Settings.ui +++ b/Settings.ui @@ -14,6 +14,48 @@ 0.01 0.10000000000000001 + + True + False + vertical + + + True + False + 0 + in + + + True + False + none + + + 100 + 80 + True + True + + + True + False + True + Nothing yet! + True + + + + + + + + + False + True + 0 + + + True False @@ -575,182 +617,6 @@ - - True - False - vertical - - - True - False - none - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Show Desktop button width (px) - 0 - - - 0 - 0 - - - - - True - True - 4 - 1 - show_showdesktop_width_adjustment - True - 1 - - - 1 - 0 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Reveal the desktop when hovering the Show Desktop button - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - True - False - 4 - - - True - False - True - Delay before revealing the desktop (ms) - True - 0 - - - 0 - 0 - - - - - True - True - 4 - 1 - show_showdesktop_delay_adjustment - True - 1 - - - 1 - 0 - - - - - True - False - True - Fade duration (ms) - True - 0 - - - 0 - 1 - - - - - True - True - 4 - 1 - show_showdesktop_time_adjustment - True - 1 - - - 1 - 1 - - - - - 0 - 1 - 2 - - - - - - - - - False - True - 2 - - - 10 1 @@ -2269,96 +2135,6 @@ 25 100 - - True - False - vertical - - - True - False - 0 - in - - - True - False - none - - - 100 - 80 - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Preview timeout on icon leave (ms) - 0 - - - 0 - 0 - - - - - True - False - True - If set too low, the window preview of running applications may seem to close too quickly when trying to enter the popup. If set too high, the preview may linger too long when moving to an adjacent icon. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - True - True - 4 - 0 - leave_timeout_adjustment - True - - - 1 - 0 - - - - - - - - - - - False - True - 0 - - - 0.33000000000000002 1 @@ -2393,16 +2169,22 @@ 1 5 + + 100 + 800 + 10 + 50 + 9999 25 100 - - 50 - 500 - 10 - 50 + + 6 + 24 + 1 + 100 True @@ -2465,13 +2247,11 @@ - - 100 - 80 + True True - + True False 12 @@ -2480,12 +2260,11 @@ 12 32 - + True False True - Enable window peeking - True + Time (ms) before hiding (100 is default) 0 @@ -2494,157 +2273,12 @@ - - True - True - end - center - - - 1 - 0 - - - - - True - False - True - When hovering over a window preview for some time, the window gets distinguished. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - - - - - 100 - 80 - True - True - - - True - False - 24 - 12 - 12 - 12 - 32 - - - True - False - True - Enter window peeking mode timeout (ms) - 0 - - - 0 - 0 - - - - - True - False - True - Time of inactivity while hovering over a window preview needed to enter the window peeking mode. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - + True True 4 - enter_peek_mode_timeout_adjustment - True - - - 1 - 0 - - - - - - - - - 100 - 80 - True - True - - - True - False - 24 - 12 - 12 - 12 - 32 - - - True - False - True - Window peeking mode opacity - 0 - - - 0 - 0 - - - - - True - False - True - All windows except for the peeked one have their opacity set to the same value. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - True - True - 4 - peek_mode_opacity_adjustment + 0 + leave_timeout_adjustment True @@ -2658,8 +2292,6 @@ - 100 - 80 True True @@ -2721,12 +2353,11 @@ - - 100 + True True - + True False 12 @@ -2735,56 +2366,12 @@ 12 32 - - True - False - True - Display window title in previews - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - - - - - 100 - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - + True True 4 0 - preview_width_adjustment + preview_size_adjustment True @@ -2793,57 +2380,11 @@ - + True False True - Width of the window previews (px) - True - 0 - - - 0 - 0 - - - - - - - - - 100 - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - True - 4 - 0 - preview_height_adjustment - True - - - 1 - 0 - - - - - True - False - True - Height of the window previews (px) + Window previews size (px) True 0 @@ -2858,7 +2399,6 @@ - 100 True True @@ -2890,7 +2430,7 @@ True False True - Padding of the window previews (px) + Window previews padding (px) True 0 @@ -2903,6 +2443,360 @@ + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Display window preview headers + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + True + False + 20 + 12 + 32 + + + True + True + 4 + 6 + preview_title_font_size_adjustment + True + 6 + + + 1 + 0 + + + + + True + False + True + Font size (px) of the preview titles + True + 0 + + + 0 + 0 + + + + + 0 + 1 + 2 + + + + + True + False + 20 + 12 + 32 + + + True + False + True + Font weight of the preview titles + 0 + + + 0 + 0 + + + + + True + False + center + + inherit from theme + normal + lighter + bold + bolder + + + + 1 + 0 + + + + + 0 + 2 + 2 + + + + + True + False + 20 + 12 + 32 + + + True + False + True + Font color of the preview titles + True + 0 + + + 0 + 0 + + + + + True + True + True + end + + + 1 + 0 + + + + + 0 + 3 + 2 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Enable window peeking + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + True + False + True + When hovering over a window preview for some time, the window gets distinguished. + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + True + False + 20 + 12 + 32 + + + True + False + True + Enter window peeking mode timeout (ms) + 0 + + + 0 + 0 + + + + + True + True + 4 + 50 + enter_peek_mode_timeout_adjustment + True + 50 + + + 1 + 0 + + + + + True + False + True + Time of inactivity while hovering over a window preview needed to enter the window peeking mode. + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + 0 + 2 + 2 + + + + + True + False + 20 + 12 + 32 + + + True + False + True + Window peeking mode opacity + 0 + + + 0 + 0 + + + + + True + True + 4 + 0 + peek_mode_opacity_adjustment + True + + + 1 + 0 + + + + + True + False + True + All windows except for the peeked one have their opacity set to the same value. + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + 0 + 3 + 2 + + + + + + @@ -3399,6 +3293,182 @@ 1 10 + + True + False + vertical + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Show Desktop button width (px) + 0 + + + 0 + 0 + + + + + True + True + 4 + 1 + show_showdesktop_width_adjustment + True + 1 + + + 1 + 0 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Reveal the desktop when hovering the Show Desktop button + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + True + False + 4 + + + True + False + True + Delay before revealing the desktop (ms) + True + 0 + + + 0 + 0 + + + + + True + True + 4 + 1 + show_showdesktop_delay_adjustment + True + 1 + + + 1 + 0 + + + + + True + False + True + Fade duration (ms) + True + 0 + + + 0 + 1 + + + + + True + True + 4 + 1 + show_showdesktop_time_adjustment + True + 1 + + + 1 + 1 + + + + + 0 + 1 + 2 + + + + + + + + + False + True + 2 + + + 0.33000000000000002 1 diff --git a/prefs.js b/prefs.js index 3260aae..937ff94 100644 --- a/prefs.js +++ b/prefs.js @@ -990,6 +990,13 @@ const Settings = new Lang.Class({ 'active', Gio.SettingsBindFlags.DEFAULT); + this._builder.get_object('grid_preview_title_font_color_colorbutton').connect('notify::color', Lang.bind(this, function (button) { + let rgba = button.get_rgba(); + let css = rgba.to_string(); + let hexString = cssHexString(css); + this._settings.set_string('window-preview-title-font-color', hexString); + })); + this._builder.get_object('show_window_previews_button').connect('clicked', Lang.bind(this, function() { let dialog = new Gtk.Dialog({ title: _('Window preview options'), @@ -1009,47 +1016,59 @@ const Settings = new Lang.Class({ this._settings.set_int('show-window-previews-timeout', widget.get_value()); })); - this._settings.bind('peek-mode', - this._builder.get_object('peek_mode_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('window-preview-show-title', - this._builder.get_object('preview_show_title_switch'), - 'active', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('peek-mode', - this._builder.get_object('listboxrow_enter_peek_mode_timeout'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('peek-mode', - this._builder.get_object('listboxrow_peek_mode_opacity'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT); this._settings.bind('preview-middle-click-close', this._builder.get_object('preview_middle_click_close_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); - this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout')); + this._settings.bind('peek-mode', + this._builder.get_object('peek_mode_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('peek-mode', + this._builder.get_object('grid_enter_peek_mode_timeout'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('peek-mode', + this._builder.get_object('grid_peek_mode_opacity'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-show-title', + this._builder.get_object('preview_show_title_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_size'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_weight'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-show-title', + this._builder.get_object('grid_preview_title_font_color'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._builder.get_object('enter_peek_mode_timeout_spinbutton').set_value(this._settings.get_int('enter-peek-mode-timeout')); this._builder.get_object('enter_peek_mode_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { this._settings.set_int('enter-peek-mode-timeout', widget.get_value()); })); - this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); + this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + this._builder.get_object('leave_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('leave-timeout', widget.get_value()); + })); + this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); this._builder.get_object('peek_mode_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { this._settings.set_int('peek-mode-opacity', widget.get_value()); })); - this._builder.get_object('preview_width_spinbutton').set_value(this._settings.get_int('window-preview-width')); - this._builder.get_object('preview_width_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { - this._settings.set_int('window-preview-width', widget.get_value()); - })); - - this._builder.get_object('preview_height_spinbutton').set_value(this._settings.get_int('window-preview-height')); - this._builder.get_object('preview_height_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { - this._settings.set_int('window-preview-height', widget.get_value()); + this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size')); + this._builder.get_object('preview_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-size', widget.get_value()); })); this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); @@ -1057,12 +1076,31 @@ const Settings = new Lang.Class({ this._settings.set_int('window-preview-padding', widget.get_value()); })); + this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); + this._builder.get_object('preview_title_size_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-title-font-size', widget.get_value()); + })); + + this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight')); + this._builder.get_object('grid_preview_title_weight_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_string('window-preview-title-font-weight', widget.get_active_id()); + })); + + (function() { + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('window-preview-title-font-color')); + this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba); + }).apply(this); + dialog.connect('response', Lang.bind(this, function(dialog, id) { if (id == 1) { // restore default settings this._settings.set_value('show-window-previews-timeout', this._settings.get_default_value('show-window-previews-timeout')); this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout')); + this._settings.set_value('leave-timeout', this._settings.get_default_value('leave-timeout')); + this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + this._settings.set_value('peek-mode', this._settings.get_default_value('peek-mode')); this._settings.set_value('window-preview-show-title', this._settings.get_default_value('window-preview-show-title')); this._settings.set_value('enter-peek-mode-timeout', this._settings.get_default_value('enter-peek-mode-timeout')); @@ -1070,17 +1108,25 @@ const Settings = new Lang.Class({ this._settings.set_value('peek-mode-opacity', this._settings.get_default_value('peek-mode-opacity')); this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); - this._settings.set_value('window-preview-width', this._settings.get_default_value('window-preview-width')); - this._builder.get_object('preview_width_spinbutton').set_value(this._settings.get_int('window-preview-width')); + this._settings.set_value('window-preview-size', this._settings.get_default_value('window-preview-size')); + this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size')); - this._settings.set_value('window-preview-height', this._settings.get_default_value('window-preview-height')); - this._builder.get_object('preview_height_spinbutton').set_value(this._settings.get_int('window-preview-height')); - this._settings.set_value('window-preview-padding', this._settings.get_default_value('window-preview-padding')); this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); this._settings.set_value('preview-middle-click-close', this._settings.get_default_value('preview-middle-click-close')); + this._settings.set_value('window-preview-title-font-size', this._settings.get_default_value('window-preview-title-font-size')); + this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); + + this._settings.set_value('window-preview-title-font-weight', this._settings.get_default_value('window-preview-title-font-weight')); + this._builder.get_object('grid_preview_title_weight_combo').set_active_id(this._settings.get_string('window-preview-title-font-weight')); + + this._settings.set_value('window-preview-title-font-color', this._settings.get_default_value('window-preview-title-font-color')); + let rgba = new Gdk.RGBA(); + rgba.parse(this._settings.get_string('window-preview-title-font-color')); + this._builder.get_object('grid_preview_title_font_color_colorbutton').set_rgba(rgba); + } else { // remove the settings box so it doesn't get destroyed; dialog.get_content_area().remove(box); @@ -1414,17 +1460,10 @@ const Settings = new Lang.Class({ let box = this._builder.get_object('box_advanced_options'); dialog.get_content_area().add(box); - this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); - - this._builder.get_object('leave_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { - this._settings.set_int('leave-timeout', widget.get_value()); - })); - dialog.connect('response', Lang.bind(this, function(dialog, id) { if (id == 1) { // restore default settings - this._settings.set_value('leave-timeout', this._settings.get_default_value('leave-timeout')); - this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + } else { // remove the settings box so it doesn't get destroyed; dialog.get_content_area().remove(box); diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index 21b3dc1..fdcf2dd 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -410,23 +410,28 @@ Display title in preview Display window title in preview + + "#dddddd" + Window previews title font color + This defines the Window previews titles font color. + + + 14 + Window previews title font size + This defines the Window previews titles font size. + + + 'inherit' + Font weight of window preview titles + This defines the font weight of window preview titles. Supported values: inherit (from theme), normal, lighter, bold and bolder. + 240 Window previews size Preferred window previews size - - 350 - Window previews width - The width of the window previews - - - 200 - Window previews height - The height of the window previews - - 20 + 8 Window previews padding The padding of the window previews diff --git a/windowPreview.js b/windowPreview.js index 7c349f8..d4b17f6 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -720,35 +720,31 @@ var Preview = Utils.defineClass({ if (headerHeight) { let iconTextureSize = headerHeight / scaleFactor * .6; let icon = this._previewMenu.getCurrentAppIcon().app.create_icon_texture(iconTextureSize); - let windowTitleStyle = 'max-width: 0px;'; + let workspaceIndex = ''; + let workspaceStyle = null; + let commonTitleStyles = 'color: ' + this._previewMenu._dtpSettings.get_string('window-preview-title-font-color') + ';' + + 'font-size: ' + this._previewMenu._dtpSettings.get_int('window-preview-title-font-size') + 'px;' + + 'font-weight: ' + this._previewMenu._dtpSettings.get_string('window-preview-title-font-weight') + ';'; this._iconBin.destroy_all_children(); this._iconBin.add_child(icon); - if (isLeftButtons) { - windowTitleStyle += 'padding-left:' + (headerHeight - icon.width) * .5 + 'px;'; + if (!this._previewMenu._dtpSettings.get_boolean('isolate-workspaces')) { + workspaceIndex = (this.window.get_workspace().index() + 1).toString(); + workspaceStyle = 'margin: 0 4px 0 ' + (isLeftButtons ? Math.round((headerHeight - icon.width) * .5) + 'px' : '0') + '; padding: 0 4px;' + + 'border: 2px solid ' + this._getRgbaColor(FOCUSED_COLOR_OFFSET, .8) + 'border-radius: 2px;' + commonTitleStyles; } + + this._workspaceIndicator.text = workspaceIndex; + this._workspaceIndicator.set_style(workspaceStyle); this._titleWindowChangeId = this.window.connect('notify::title', () => this._updateWindowTitle()); - - this._windowTitle.set_style(windowTitleStyle); + this._windowTitle.set_style('max-width: 0px; padding-right: 4px;' + commonTitleStyles); this._updateWindowTitle(); } }, _updateWindowTitle: function() { - let workspaceIndex = ''; - let workspaceStyle = null; - - if (!this._previewMenu._dtpSettings.get_boolean('isolate-workspaces')) { - workspaceIndex = (this.window.get_workspace().index() + 1).toString(); - workspaceStyle = 'padding: 0 4px; border: 2px solid ' + this._getRgbaColor(FOCUSED_COLOR_OFFSET, .8) + - 'border-radius: 2px; margin-right: 4px;'; - } - - this._workspaceIndicator.text = workspaceIndex; - this._workspaceIndicator.set_style(workspaceStyle); - this._windowTitle.text = this.window.title; }, From 6dc88321072deb595190e09a848b2f42db6f8e1f Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 23 May 2019 23:16:27 -0400 Subject: [PATCH 22/61] Remove todo list --- windowPreview.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index d4b17f6..43b5c49 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -80,22 +80,6 @@ var PreviewMenu = Utils.defineClass({ this._scrollView.add_actor(this._box); this.menu.add_child(this._scrollView); this.add_child(this.menu); - - - - - - //TODO - //'open-state-changed' - //'menu-closed' - //'sync-tooltip' - //this.add_style_class_name('app-well-menu'); - - //peek - - // move closing delay setting from "advanced" - - // hook settings (animation time, size, label color, header location) }, enable: function() { From 5873ec0677eba6f76f552a2200e9c4120b2e6ff7 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 24 May 2019 08:55:11 -0400 Subject: [PATCH 23/61] Fix GObject names on older gnome-shell versions --- windowPreview.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 43b5c49..2725afe 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -49,7 +49,7 @@ var scaleFactor = 1; var workspaceSwitchTime = WindowManager.WINDOW_ANIMATION_TIME * 1020; var PreviewMenu = Utils.defineClass({ - Name: 'DashToPanel.PreviewMenu', + Name: 'DashToPanel-PreviewMenu', Extends: St.Widget, _init: function(dtpSettings, panelWrapper) { @@ -528,7 +528,7 @@ var PreviewMenu = Utils.defineClass({ }); var Preview = Utils.defineClass({ - Name: 'DashToPanel.Preview', + Name: 'DashToPanel-Preview', Extends: St.Widget, _init: function(panelWrapper, previewMenu) { From 9a941b0cea4a2b759e7b56dbc8f69ea332036dd3 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 24 May 2019 09:17:04 -0400 Subject: [PATCH 24/61] Fix ES6 syntax for older gnome-shell versions --- windowPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windowPreview.js b/windowPreview.js index 2725afe..2e2ef46 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -212,7 +212,7 @@ var PreviewMenu = Utils.defineClass({ } }, - requestPeek(window) { + requestPeek: function(window) { this._timeoutsHandler.remove(T3); if (this._dtpSettings.get_boolean('peek-mode')) { From 78760e2bf6790fe137f56c564b0a8fca349e2741 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 24 May 2019 17:22:04 -0400 Subject: [PATCH 25/61] Fix missing window compositor on clone creation --- windowPreview.js | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 2e2ef46..f241280 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -17,8 +17,10 @@ const Clutter = imports.gi.Clutter; const Config = imports.misc.config; +const GLib = imports.gi.GLib; const Gtk = imports.gi.Gtk; const Main = imports.ui.main; +const Mainloop = imports.mainloop; const Meta = imports.gi.Meta; const Signals = imports.signals; const Shell = imports.gi.Shell; @@ -46,7 +48,6 @@ const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; var headerHeight = 0; var isLeftButtons = false; var scaleFactor = 1; -var workspaceSwitchTime = WindowManager.WINDOW_ANIMATION_TIME * 1020; var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel-PreviewMenu', @@ -190,6 +191,10 @@ var PreviewMenu = Utils.defineClass({ } }, + updatePosition: function() { + this._updatePosition(); + }, + focusNext: function() { let previews = this._box.get_children(); let currentIndex = this._focusedPreview ? previews.indexOf(this._focusedPreview) : -1; @@ -476,9 +481,11 @@ var PreviewMenu = Utils.defineClass({ }, _switchToWorkspaceImmediate: function(workspace) { - Main.wm._blockAnimations = true; - workspace.activate(1); - Main.wm._blockAnimations = false; + if (workspace) { + Main.wm._blockAnimations = true; + workspace.activate(1); + Main.wm._blockAnimations = false; + } }, _focusMetaWindow: function(dimOpacity, metaWindow) { @@ -539,6 +546,7 @@ var Preview = Utils.defineClass({ layout_manager: new Clutter.BinLayout() }); + this.cloneWidth = this.cloneHeight = 0; this._panelWrapper = panelWrapper; this._previewMenu = previewMenu; this._padding = previewMenu._dtpSettings.get_int('window-preview-padding') * scaleFactor; @@ -617,14 +625,23 @@ var Preview = Utils.defineClass({ }, assignWindow: function(window, animateSize) { - let clone = this._getWindowClone(window); + let _assignWindow = () => { + if (window.get_compositor_private()) { + let clone = this._getWindowClone(window); + + this._updateHeader(); + this._resizeClone(clone); + this._addClone(clone, animateSize); + this._previewMenu.updatePosition(); + } else { + Mainloop.idle_add(() => _assignWindow()); + } + }; this._removeWindowSignals(); this.window = window; - - this._updateHeader(); - this._resizeClone(clone); - this._addClone(clone, animateSize); + + _assignWindow(); }, animateOut: function() { From d2b969d15722462244e2f32eff19e2e507b40f14 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 24 May 2019 18:17:13 -0400 Subject: [PATCH 26/61] Add setting to define previews animation time --- Settings.ui | 49 +++++++++++++++++++ prefs.js | 10 +++- ...shell.extensions.dash-to-panel.gschema.xml | 9 +++- windowPreview.js | 5 +- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/Settings.ui b/Settings.ui index 4fa4f91..add7730 100644 --- a/Settings.ui +++ b/Settings.ui @@ -2158,6 +2158,11 @@ 10 25 + + 1000 + 10 + 50 + 50 500 @@ -2290,6 +2295,50 @@ + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Animation time (ms) + 0 + + + 0 + 0 + + + + + True + True + 4 + 0 + preview_animation_time_adjustment + True + + + 1 + 0 + + + + + + True diff --git a/prefs.js b/prefs.js index 937ff94..37ad7ec 100644 --- a/prefs.js +++ b/prefs.js @@ -1061,6 +1061,11 @@ const Settings = new Lang.Class({ this._settings.set_int('leave-timeout', widget.get_value()); })); + this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time')); + this._builder.get_object('animation_time_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-animation-time', widget.get_value()); + })); + this._builder.get_object('peek_mode_opacity_spinbutton').set_value(this._settings.get_int('peek-mode-opacity')); this._builder.get_object('peek_mode_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { this._settings.set_int('peek-mode-opacity', widget.get_value()); @@ -1099,7 +1104,10 @@ const Settings = new Lang.Class({ this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout')); this._settings.set_value('leave-timeout', this._settings.get_default_value('leave-timeout')); - this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); + + this._settings.set_value('window-preview-animation-time', this._settings.get_default_value('window-preview-animation-time')); + this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time')); this._settings.set_value('peek-mode', this._settings.get_default_value('peek-mode')); this._settings.set_value('window-preview-show-title', this._settings.get_default_value('window-preview-show-title')); diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index fdcf2dd..f44ada9 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -413,12 +413,17 @@ "#dddddd" Window previews title font color - This defines the Window previews titles font color. + This defines the window preview titles font color. 14 Window previews title font size - This defines the Window previews titles font size. + This defines the window preview titles font size. + + + 300 + Window previews animation time + This defines the window previews animation time. 'inherit' diff --git a/windowPreview.js b/windowPreview.js index f241280..d2fc89f 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -17,7 +17,6 @@ const Clutter = imports.gi.Clutter; const Config = imports.misc.config; -const GLib = imports.gi.GLib; const Gtk = imports.gi.Gtk; const Main = imports.ui.main; const Mainloop = imports.mainloop; @@ -48,6 +47,7 @@ const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; var headerHeight = 0; var isLeftButtons = false; var scaleFactor = 1; +var animationTime = 0; var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel-PreviewMenu', @@ -333,6 +333,7 @@ var PreviewMenu = Utils.defineClass({ isLeftButtons = Meta.prefs_get_button_layout().left_buttons.indexOf(Meta.ButtonFunction.CLOSE) >= 0; scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; headerHeight = this._dtpSettings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT * scaleFactor : 0; + animationTime = this._dtpSettings.get_int('window-preview-animation-time') * .001; }, _resetHiddenState: function() { @@ -862,7 +863,7 @@ var Preview = Utils.defineClass({ function getTweenOpts(opts) { let defaults = { - time: Taskbar.DASH_ANIMATION_TIME * 1.5, + time: animationTime, transition: 'easeInOutQuad' }; From c28bfb46e4c920085f4188c274a73ef51148ba2b Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 24 May 2019 20:41:55 -0400 Subject: [PATCH 27/61] Add setting to specify close button and header position --- Settings.ui | 101 ++++++++++++++---- prefs.js | 19 ++++ ...shell.extensions.dash-to-panel.gschema.xml | 15 +-- windowPreview.js | 28 +++-- 4 files changed, 127 insertions(+), 36 deletions(-) diff --git a/Settings.ui b/Settings.ui index add7730..542239d 100644 --- a/Settings.ui +++ b/Settings.ui @@ -2357,7 +2357,7 @@ True False True - Middle click to close window + Middle click on the preview to close the window True 0 @@ -2378,25 +2378,6 @@ 0 - - - True - False - True - Middle click on the preview to close the window. - True - 40 - 0 - - - - 0 - 1 - 2 - - @@ -2492,6 +2473,86 @@ + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Close button and header position + 0 + + + False + True + 0 + + + + + True + False + 32 + + + Bottom + True + True + False + center + center + True + True + + + + False + True + 1 + + + + + Top + True + True + False + center + center + bottom + True + preview_title_position_bottom_button + + + + False + True + 2 + + + + + False + True + 1 + + + + + + True diff --git a/prefs.js b/prefs.js index 37ad7ec..4bc8bd1 100644 --- a/prefs.js +++ b/prefs.js @@ -990,6 +990,15 @@ const Settings = new Lang.Class({ 'active', Gio.SettingsBindFlags.DEFAULT); + switch (this._settings.get_string('window-preview-title-position')) { + case 'BOTTOM': + this._builder.get_object('preview_title_position_bottom_button').set_active(true); + break; + case 'TOP': + this._builder.get_object('preview_title_position_top_button').set_active(true); + break; + } + this._builder.get_object('grid_preview_title_font_color_colorbutton').connect('notify::color', Lang.bind(this, function (button) { let rgba = button.get_rgba(); let css = rgba.to_string(); @@ -1632,6 +1641,16 @@ const Settings = new Lang.Class({ this._settings.set_string('dot-position', "TOP"); }, + preview_title_position_bottom_button_toggled_cb: function(button) { + if (button.get_active()) + this._settings.set_string('window-preview-title-position', 'BOTTOM'); + }, + + preview_title_position_top_button_toggled_cb: function(button) { + if (button.get_active()) + this._settings.set_string('window-preview-title-position', 'TOP'); + }, + panel_size_scale_format_value_cb: function(scale, value) { return value+ ' px'; }, diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index f44ada9..8b0730e 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -44,11 +44,7 @@ - - - - - + @@ -65,7 +61,7 @@ - + 'BOTTOM' Panel position Panel is shown on the Bottom or Top of the screen. @@ -75,7 +71,7 @@ Panel size Set the size of the panel. - + 'BOTTOM' Dot position Running indicators are shown on the Bottom or Top of the screen. @@ -410,6 +406,11 @@ Display title in preview Display window title in preview + + 'TOP' + Title position + Position of the window title, close button and icon in preview. + "#dddddd" Window previews title font color diff --git a/windowPreview.js b/windowPreview.js index d2fc89f..1a9cab7 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -46,6 +46,7 @@ const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; var headerHeight = 0; var isLeftButtons = false; +var isTopHeader = true; var scaleFactor = 1; var animationTime = 0; @@ -331,6 +332,7 @@ var PreviewMenu = Utils.defineClass({ _refreshGlobals: function() { isLeftButtons = Meta.prefs_get_button_layout().left_buttons.indexOf(Meta.ButtonFunction.CLOSE) >= 0; + isTopHeader = this._dtpSettings.get_string('window-preview-title-position') == 'TOP'; scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; headerHeight = this._dtpSettings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT * scaleFactor : 0; animationTime = this._dtpSettings.get_int('window-preview-animation-time') * .001; @@ -555,12 +557,16 @@ var Preview = Utils.defineClass({ this.animatingOut = false; let [previewBinWidth, previewBinHeight] = this._getBinSize(); - this._previewBin = new St.Widget({ layout_manager: new Clutter.BinLayout() }); - this._previewBin.set_style('padding: ' + this._padding + 'px;'); - this._previewBin.set_size(previewBinWidth, previewBinHeight); - let closeButton = new St.Button({ style_class: 'window-close', accessible_name: 'Close window' }); + this._previewBin = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + y_align: Clutter.ActorAlign[!isTopHeader ? 'START' : 'END'], + y_expand: true, + style: 'padding: ' + this._padding + 'px;' + }); + this._previewBin.set_size(previewBinWidth, previewBinHeight); + if (Config.PACKAGE_VERSION >= '3.31.9') { closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); } @@ -570,7 +576,7 @@ var Preview = Utils.defineClass({ opacity: 0, x_expand: true, y_expand: true, x_align: Clutter.ActorAlign[isLeftButtons ? 'START' : 'END'], - y_align: Clutter.ActorAlign.START + y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'] }); this._closeButtonBin.add_child(closeButton); @@ -578,7 +584,7 @@ var Preview = Utils.defineClass({ if (headerHeight) { let headerBox = new St.Widget({ layout_manager: new Clutter.BoxLayout(), - y_align: Clutter.ActorAlign.START, + y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'], y_expand: true, style: this._getBackgroundColor(HEADER_COLOR_OFFSET, .8) }); @@ -594,8 +600,6 @@ var Preview = Utils.defineClass({ headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 1 : 2); this.add_child(headerBox); - - this._previewBin.set_position(0, headerHeight); } closeButton.connect('clicked', () => this._onCloseBtnClick()); @@ -615,7 +619,13 @@ var Preview = Utils.defineClass({ let closeButtonBorderRadius = ''; if (!headerHeight) { - closeButtonBorderRadius = 'border-radius: ' + (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;'); + closeButtonBorderRadius = 'border-radius: '; + + if (isTopHeader) { + closeButtonBorderRadius += (isLeftButtons ? '0 0 4px 0;' : '0 0 0 4px;'); + } else { + closeButtonBorderRadius += (isLeftButtons ? '0 4px 0 0;' : '4px 0 0 0;'); + } } this._closeButtonBin.set_style( From 2369dea8209884ab078f80e9d5ea77e01cd6f668 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 24 May 2019 21:47:42 -0400 Subject: [PATCH 28/61] Brighten preview close button background --- windowPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windowPreview.js b/windowPreview.js index 1a9cab7..cb59a46 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -630,7 +630,7 @@ var Preview = Utils.defineClass({ this._closeButtonBin.set_style( 'padding: ' + closeButtonPadding + 'px; ' + - this._getBackgroundColor(HEADER_COLOR_OFFSET, .8) + + this._getBackgroundColor(Math.abs(HEADER_COLOR_OFFSET), .8) + closeButtonBorderRadius ); }, From fca4b6920a637f9efa76e6b2e169a4bd38552691 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sat, 25 May 2019 11:08:46 -0400 Subject: [PATCH 29/61] Add window preview context menu --- appIcons.js | 30 ++++++----- utils.js | 12 +++++ windowPreview.js | 131 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 122 insertions(+), 51 deletions(-) diff --git a/appIcons.js b/appIcons.js index 638e4b3..d72de18 100644 --- a/appIcons.js +++ b/appIcons.js @@ -181,10 +181,10 @@ var taskbarAppIcon = Utils.defineClass({ Lang.bind(this, this._onFocusAppChanged)); this._windowEnteredMonitorId = this._windowLeftMonitorId = 0; - + this._stateChangedId = this.app.connect('windows-changed', + Lang.bind(this, this.onWindowsChanged)); if (!this.window) { - this._stateChangedId = this.app.connect('windows-changed', - Lang.bind(this, this.onWindowsChanged)); + if (this._dtpSettings.get_boolean('isolate-monitors')) { this._windowEnteredMonitorId = Utils.DisplayWrapper.getScreen().connect('window-entered-monitor', this.onWindowEnteredOrLeft.bind(this)); @@ -267,6 +267,8 @@ var taskbarAppIcon = Utils.defineClass({ this.callParent('_onDestroy'); this._destroyed = true; + this._previewMenu.close(true); + // Disconect global signals // stateChangedId is already handled by parent) @@ -849,16 +851,20 @@ var taskbarAppIcon = Utils.defineClass({ }, _updateWindows: function() { - let windows = this.getAppIconInterestingWindows(); + let windows = [this.window]; - this._nWindows = windows.length; - - for (let i = 1; i <= MAX_INDICATORS; i++){ - let className = 'running'+i; - if(i != this._nWindows) - this.actor.remove_style_class_name(className); - else - this.actor.add_style_class_name(className); + if (!this.window) { + windows = this.getAppIconInterestingWindows(); + + this._nWindows = windows.length; + + for (let i = 1; i <= MAX_INDICATORS; i++){ + let className = 'running'+i; + if(i != this._nWindows) + this.actor.remove_style_class_name(className); + else + this.actor.add_style_class_name(className); + } } this._previewMenu.update(this, windows); diff --git a/utils.js b/utils.js index aabf69f..3eb4158 100644 --- a/utils.js +++ b/utils.js @@ -271,6 +271,18 @@ var DisplayWrapper = { } }; +var getCurrentWorkspace = function() { + return DisplayWrapper.getWorkspaceManager().get_active_workspace(); +}; + +var getWorkspaceByIndex = function(index) { + return DisplayWrapper.getWorkspaceManager().get_workspace_by_index(index); +}; + +var getWorkspaceCount = function() { + return DisplayWrapper.getWorkspaceManager().n_workspaces; +}; + var findIndex = function(array, predicate) { if (Array.prototype.findIndex) { return array.findIndex(predicate); diff --git a/windowPreview.js b/windowPreview.js index cb59a46..2bfd58a 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -21,6 +21,7 @@ const Gtk = imports.gi.Gtk; const Main = imports.ui.main; const Mainloop = imports.mainloop; const Meta = imports.gi.Meta; +const PopupMenu = imports.ui.popupMenu; const Signals = imports.signals; const Shell = imports.gi.Shell; const St = imports.gi.St; @@ -62,7 +63,7 @@ var PreviewMenu = Utils.defineClass({ this.currentAppIcon = null; this._focusedPreview = null; this._peekedWindow = null; - this._peekInitialWorkspace = null; + this.peekInitialWorkspaceIndex = -1; this.opened = false; this._position = Taskbar.getPosition(); let isLeftOrRight = this._checkIfLeftOrRight(); @@ -222,7 +223,7 @@ var PreviewMenu = Utils.defineClass({ this._timeoutsHandler.remove(T3); if (this._dtpSettings.get_boolean('peek-mode')) { - if (!this._peekInitialWorkspace) { + if (this.peekInitialWorkspaceIndex < 0) { this._timeoutsHandler.add([T3, this._dtpSettings.get_int('enter-peek-mode-timeout'), () => this._peek(window)]); } else { this._peek(window); @@ -270,7 +271,13 @@ var PreviewMenu = Utils.defineClass({ if (currentIndex < 0) { this._addNewPreview(windows[i]); } else { + currentPreviews[currentIndex].cancelAnimateOut(); + currentPreviews[currentIndex].assignWindow(windows[i]); currentPreviews.splice(currentIndex, 1); + + if (this._peekedWindow && this._peekedWindow == windows[i]) { + this.requestPeek(windows[i]); + } } } @@ -449,21 +456,22 @@ var PreviewMenu = Utils.defineClass({ }, _peek: function(window) { - let currentWorkspace = this._getCurrentWorkspace(); + let currentWorkspace = Utils.getCurrentWorkspace(); let windowWorkspace = window.get_workspace(); let focusWindow = () => this._focusMetaWindow(this._dtpSettings.get_int('peek-mode-opacity'), window); this._restorePeekedWindowStack(); + this._peekedWindow = window; if (currentWorkspace != windowWorkspace) { - this._switchToWorkspaceImmediate(windowWorkspace); + this._switchToWorkspaceImmediate(windowWorkspace.index()); this._timeoutsHandler.add([T3, 100, focusWindow]); } else { focusWindow(); } - if (!this._peekInitialWorkspace) { - this._peekInitialWorkspace = currentWorkspace; + if (this.peekInitialWorkspaceIndex < 0) { + this.peekInitialWorkspaceIndex = currentWorkspace.index(); } }, @@ -474,33 +482,36 @@ var PreviewMenu = Utils.defineClass({ this._restorePeekedWindowStack(); if (!stayHere) { - this._switchToWorkspaceImmediate(this._peekInitialWorkspace); + this._switchToWorkspaceImmediate(this.peekInitialWorkspaceIndex); } this._focusMetaWindow(255); this._peekedWindow = null; - this._peekInitialWorkspace = null; + this.peekInitialWorkspaceIndex = -1; } }, - _switchToWorkspaceImmediate: function(workspace) { - if (workspace) { - Main.wm._blockAnimations = true; - workspace.activate(1); - Main.wm._blockAnimations = false; + _switchToWorkspaceImmediate: function(workspaceIndex) { + let workspace = Utils.getWorkspaceByIndex(workspaceIndex); + + if (!workspace || (!workspace.list_windows().length && + workspaceIndex < Utils.getWorkspaceCount() -1)) { + workspace = Utils.getCurrentWorkspace(); } + + Main.wm._blockAnimations = true; + workspace.activate(1); + Main.wm._blockAnimations = false; }, - _focusMetaWindow: function(dimOpacity, metaWindow) { + _focusMetaWindow: function(dimOpacity, window) { if (Main.overview.visibleTarget) { return; } - this._peekedWindow = metaWindow; - global.get_window_actors().forEach(wa => { let mw = wa.meta_window; - let isFocused = mw == metaWindow; + let isFocused = mw == window; if (mw) { if (isFocused) { @@ -531,10 +542,6 @@ var PreviewMenu = Utils.defineClass({ } } }, - - _getCurrentWorkspace: function() { - return Utils.DisplayWrapper.getWorkspaceManager().get_active_workspace(); - }, }); var Preview = Utils.defineClass({ @@ -549,6 +556,7 @@ var Preview = Utils.defineClass({ layout_manager: new Clutter.BinLayout() }); + this.window = null; this.cloneWidth = this.cloneHeight = 0; this._panelWrapper = panelWrapper; this._previewMenu = previewMenu; @@ -636,32 +644,46 @@ var Preview = Utils.defineClass({ }, assignWindow: function(window, animateSize) { - let _assignWindow = () => { - if (window.get_compositor_private()) { - let clone = this._getWindowClone(window); - - this._updateHeader(); - this._resizeClone(clone); - this._addClone(clone, animateSize); - this._previewMenu.updatePosition(); - } else { - Mainloop.idle_add(() => _assignWindow()); - } - }; + if (this.window != window) { + let _assignWindowClone = () => { + if (window.get_compositor_private()) { + let clone = this._getWindowClone(window); + + this._resizeClone(clone); + this._addClone(clone, animateSize); + this._previewMenu.updatePosition(); + } else { + Mainloop.idle_add(() => _assignWindowClone()); + } + }; + + _assignWindowClone(); + } this._removeWindowSignals(); this.window = window; - - _assignWindow(); + this._updateHeader(); }, animateOut: function() { - let tweenOpts = getTweenOpts({ opacity: 0, onComplete: () => this.destroy() }); + if (!this.animatingOut) { + let tweenOpts = getTweenOpts({ opacity: 0, onComplete: () => this.destroy() }); - tweenOpts[this._previewMenu._checkIfLeftOrRight() ? 'height' : 'width'] = 0; - this.animatingOut = true; + tweenOpts[this._previewMenu._checkIfLeftOrRight() ? 'height' : 'width'] = 0; + this.animatingOut = true; - Tweener.addTween(this, tweenOpts); + Tweener.removeTweens(this); + Tweener.addTween(this, tweenOpts); + } + }, + + cancelAnimateOut: function() { + if (this.animatingOut) { + this.animatingOut = false; + + Tweener.removeTweens(this); + Tweener.addTween(this, getTweenOpts({ opacity: 255 })); + } }, getSize: function() { @@ -716,11 +738,42 @@ var Preview = Utils.defineClass({ this._onCloseBtnClick(); } break; + case 3: // Right click + this._showContextMenu(e); + break; } return Clutter.EVENT_STOP; }, + _showContextMenu: function(e) { + let coords = e.get_coords(); + let currentWorkspace = this._previewMenu.peekInitialWorkspaceIndex < 0 ? + Utils.getCurrentWorkspace() : + Utils.getWorkspaceByIndex(this._previewMenu.peekInitialWorkspaceIndex); + + Main.wm._showWindowMenu(null, this.window, Meta.WindowMenuType.WM, { + x: coords[0], + y: coords[1], + width: 0, + height: 0 + }); + + let ctxMenuData = Main.wm._windowMenuManager._manager._menus[0]; + + ctxMenuData.menu.connect('open-state-changed', () => this._previewMenu.menu.sync_hover()); + + if (this.window.get_workspace() != currentWorkspace) { + let menuItem = new PopupMenu.PopupMenuItem(_('Move to current Workspace') + ' [' + (currentWorkspace.index() + 1) + ']'); + let menuItems = ctxMenuData.menu.box.get_children(); + let insertIndex = Utils.findIndex(menuItems, c => c._delegate instanceof PopupMenu.PopupSeparatorMenuItem); + + insertIndex = insertIndex >= 0 ? insertIndex : menuItems.length - 1; + ctxMenuData.menu.addMenuItem(menuItem, insertIndex); + menuItem.connect('activate', () => this.window.change_workspace(currentWorkspace)); + } + }, + _removeWindowSignals: function() { if (this._titleWindowChangeId) { this.window.disconnect(this._titleWindowChangeId); From d767c3946e0be938ba5fc4c8f7eba7b5eb8fe4e2 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sat, 25 May 2019 23:38:09 -0400 Subject: [PATCH 30/61] Fix double peek on workspace restore --- windowPreview.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 2bfd58a..9b52bdf 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -481,13 +481,13 @@ var PreviewMenu = Utils.defineClass({ if (this._peekedWindow) { this._restorePeekedWindowStack(); - if (!stayHere) { - this._switchToWorkspaceImmediate(this.peekInitialWorkspaceIndex); - } - this._focusMetaWindow(255); this._peekedWindow = null; this.peekInitialWorkspaceIndex = -1; + + if (!stayHere) { + this._switchToWorkspaceImmediate(this.peekInitialWorkspaceIndex); + } } }, From 198c786266748e8aa67aeffe6a5313e8432f5729 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 26 May 2019 00:01:22 -0400 Subject: [PATCH 31/61] Fix workspace restore on peek exit --- windowPreview.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/windowPreview.js b/windowPreview.js index 9b52bdf..336a7bc 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -483,11 +483,12 @@ var PreviewMenu = Utils.defineClass({ this._focusMetaWindow(255); this._peekedWindow = null; - this.peekInitialWorkspaceIndex = -1; if (!stayHere) { this._switchToWorkspaceImmediate(this.peekInitialWorkspaceIndex); } + + this.peekInitialWorkspaceIndex = -1; } }, From c74fa64a66acebafe24a6cf66acd62105d8844f3 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 26 May 2019 07:57:00 -0400 Subject: [PATCH 32/61] Remove focus from window while previews are up --- windowPreview.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/windowPreview.js b/windowPreview.js index 336a7bc..5d3a6e8 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -155,6 +155,7 @@ var PreviewMenu = Utils.defineClass({ this.menu.show(); this._refreshGlobals(); + this.grab_key_focus(); } this._mergeWindows(appIcon); @@ -177,6 +178,7 @@ var PreviewMenu = Utils.defineClass({ this._animateOpenOrClose(false, () => this._resetHiddenState()); } + global.display.focus_default_window(1); this._box.get_children().forEach(c => c.reactive = false); this.menu.reactive = false; this.currentAppIcon = null; @@ -503,6 +505,8 @@ var PreviewMenu = Utils.defineClass({ Main.wm._blockAnimations = true; workspace.activate(1); Main.wm._blockAnimations = false; + + this.grab_key_focus(); }, _focusMetaWindow: function(dimOpacity, window) { From 9c262facdc9e4376209ddc2cb4a9f93e524b0b9c Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 26 May 2019 08:41:45 -0400 Subject: [PATCH 33/61] Use preview opened state instead of hover for intellihide --- intellihide.js | 10 +++++----- utils.js | 2 +- windowPreview.js | 10 ++++++++-- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/intellihide.js b/intellihide.js index 639eb19..7ab838a 100644 --- a/intellihide.js +++ b/intellihide.js @@ -187,9 +187,9 @@ var Intellihide = Utils.defineClass({ () => this._onHoverChanged() ], [ - this._dtpPanel.taskbar.previewMenu.menu, - 'notify::hover', - () => this._onHoverChanged() + this._dtpPanel.taskbar.previewMenu, + 'open-state-changed', + () => this._queueUpdatePanelPosition() ], [ Main.overview, @@ -203,7 +203,7 @@ var Intellihide = Utils.defineClass({ }, _onHoverChanged: function() { - this._hoveredOut = !this._panelBox.hover && !this._dtpPanel.taskbar.previewMenu.menu.hover; + this._hoveredOut = !this._panelBox.hover; this._queueUpdatePanelPosition(); }, @@ -295,7 +295,7 @@ var Intellihide = Utils.defineClass({ }, _checkIfShouldBeVisible: function(fromRevealMechanism) { - if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.menu.get_hover() || this._panelBox.get_hover()) { + if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.opened || this._panelBox.get_hover()) { return true; } diff --git a/utils.js b/utils.js index 3eb4158..4807251 100644 --- a/utils.js +++ b/utils.js @@ -94,7 +94,7 @@ var defineClass = function (classDef) { .forEach(k => C.prototype[k] = classDef[k]); if (isGObject) { - C = GObject.registerClass(C); + C = GObject.registerClass({ Signals: classDef.Signals || {} }, C); } return C; diff --git a/windowPreview.js b/windowPreview.js index 5d3a6e8..0613597 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -54,6 +54,7 @@ var animationTime = 0; var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel-PreviewMenu', Extends: St.Widget, + Signals: { 'open-state-changed': {} }, _init: function(dtpSettings, panelWrapper) { this.callParent('_init', { layout_manager: new Clutter.BinLayout() }); @@ -163,7 +164,7 @@ var PreviewMenu = Utils.defineClass({ this._animateOpenOrClose(true); this.menu.reactive = true; - this.opened = true; + this._setOpenedState(true); } }, @@ -237,6 +238,11 @@ var PreviewMenu = Utils.defineClass({ this._endPeek(true); }, + _setOpenedState: function(opened) { + this.opened = opened; + this.emit('open-state-changed'); + }, + _removeFocus: function() { if (this._focusedPreview) { this._focusedPreview.setFocus(false); @@ -349,7 +355,7 @@ var PreviewMenu = Utils.defineClass({ _resetHiddenState: function() { this.menu.hide(); - this.opened = false; + this._setOpenedState(false); this.menu.opacity = 0; this.menu[this._translationProp] = this._translationOffset; this._box.get_children().forEach(c => c.destroy()); From 17a448603f4ac2ed61474dcdd610c3ab4402eba4 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 26 May 2019 09:47:20 -0400 Subject: [PATCH 34/61] Use MetaScreen for the focus on older gnome-shell versions --- windowPreview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windowPreview.js b/windowPreview.js index 0613597..578298d 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -179,7 +179,7 @@ var PreviewMenu = Utils.defineClass({ this._animateOpenOrClose(false, () => this._resetHiddenState()); } - global.display.focus_default_window(1); + Utils.DisplayWrapper.getScreen().focus_default_window(1); this._box.get_children().forEach(c => c.reactive = false); this.menu.reactive = false; this.currentAppIcon = null; From 0a5ce634e43c4a60fbaced8304fa0c677f40fc08 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 26 May 2019 13:43:42 -0400 Subject: [PATCH 35/61] Add previews dynamic size option --- Settings.ui | 43 +++++++++ prefs.js | 7 ++ ...shell.extensions.dash-to-panel.gschema.xml | 5 ++ stylesheet.css | 2 +- windowPreview.js | 88 ++++++++++--------- 5 files changed, 104 insertions(+), 41 deletions(-) diff --git a/Settings.ui b/Settings.ui index 542239d..2cd7e60 100644 --- a/Settings.ui +++ b/Settings.ui @@ -2427,6 +2427,49 @@ + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use a fixed size for the window previews + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + + True diff --git a/prefs.js b/prefs.js index 4bc8bd1..ddf5b4f 100644 --- a/prefs.js +++ b/prefs.js @@ -1030,6 +1030,11 @@ const Settings = new Lang.Class({ 'active', Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('window-preview-fixed-size', + this._builder.get_object('preview_fixed_size_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('peek-mode', this._builder.get_object('peek_mode_switch'), 'active', @@ -1133,6 +1138,8 @@ const Settings = new Lang.Class({ this._settings.set_value('preview-middle-click-close', this._settings.get_default_value('preview-middle-click-close')); + this._settings.set_value('window-preview-fixed-size', this._settings.get_default_value('window-preview-fixed-size')); + this._settings.set_value('window-preview-title-font-size', this._settings.get_default_value('window-preview-title-font-size')); this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index 8b0730e..1647af8 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -436,6 +436,11 @@ Window previews size Preferred window previews size + + true + Window previews fixed size + This defines if the window previews use a fixed or dynamic size. + 8 Window previews padding diff --git a/stylesheet.css b/stylesheet.css index de04d88..cec49e6 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -43,7 +43,7 @@ #dashtopanelPreviewScrollview { -st-hfade-offset: 24px; - -st-vfade-offset: 24px; + /* -st-vfade-offset: 24px; */ } #dashtopanelScrollview .app-well-app:hover .overview-icon, diff --git a/windowPreview.js b/windowPreview.js index 578298d..934a549 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -69,16 +69,25 @@ var PreviewMenu = Utils.defineClass({ this._position = Taskbar.getPosition(); let isLeftOrRight = this._checkIfLeftOrRight(); this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y'); - this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), MAX_TRANSLATION) * - (this._position == St.Side.TOP || this._position == St.Side.LEFT ? -1 : 1); + this._translationDirection = (this._position == St.Side.TOP || this._position == St.Side.LEFT ? -1 : 1); + this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), MAX_TRANSLATION) * this._translationDirection; - this.menu = new St.Widget({ name: 'preview-menu', layout_manager: new Clutter.BinLayout(), reactive: true, track_hover: true }); + this.menu = new St.Widget({ + name: 'preview-menu', + layout_manager: new Clutter.BinLayout(), + reactive: true, + track_hover: true, + y_expand: true, + y_align: Clutter.ActorAlign.END + }); this._box = new St.BoxLayout({ vertical: isLeftOrRight }); this._scrollView = new St.ScrollView({ name: 'dashtopanelPreviewScrollview', hscrollbar_policy: Gtk.PolicyType.NEVER, vscrollbar_policy: Gtk.PolicyType.NEVER, - enable_mouse_scrolling: true + enable_mouse_scrolling: true, + y_expand: !isLeftOrRight, + x_expand: isLeftOrRight }); this._scrollView.add_actor(this._box); @@ -400,7 +409,7 @@ var PreviewMenu = Utils.defineClass({ let x = 0, y = 0; previewsWidth = Math.min(previewsWidth, this._panelWrapper.monitor.width); - previewsHeight = Math.min(previewsHeight, this._panelWrapper.monitor.height); + previewsHeight = Math.min(previewsHeight, this._panelWrapper.monitor.height) + headerHeight; if (this._checkIfLeftOrRight()) { y = sourceAllocation.y1 - this._panelWrapper.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; @@ -414,8 +423,9 @@ var PreviewMenu = Utils.defineClass({ if (!this.opened) { this.menu.set_position(x, y); + this.menu.set_size(previewsWidth, previewsHeight); } else { - Tweener.addTween(this.menu, getTweenOpts({ x: x, y: y })); + Tweener.addTween(this.menu, getTweenOpts({ x: x, y: y, width: previewsWidth, height: previewsHeight })); } }, @@ -454,7 +464,7 @@ var PreviewMenu = Utils.defineClass({ } }; - tweenOpts[this._translationProp] = show ? 0 : this._translationOffset; + tweenOpts[this._translationProp] = show ? 1 * this._translationDirection : this._translationOffset; Tweener.addTween(this.menu, getTweenOpts(tweenOpts)); }, @@ -575,17 +585,10 @@ var Preview = Utils.defineClass({ this._previewDimensions = this._getPreviewDimensions(); this.animatingOut = false; + let box = new St.Widget({ layout_manager: new Clutter.BoxLayout({ vertical: true }), y_expand: true }); let [previewBinWidth, previewBinHeight] = this._getBinSize(); let closeButton = new St.Button({ style_class: 'window-close', accessible_name: 'Close window' }); - this._previewBin = new St.Widget({ - layout_manager: new Clutter.BinLayout(), - y_align: Clutter.ActorAlign[!isTopHeader ? 'START' : 'END'], - y_expand: true, - style: 'padding: ' + this._padding + 'px;' - }); - this._previewBin.set_size(previewBinWidth, previewBinHeight); - if (Config.PACKAGE_VERSION >= '3.31.9') { closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); } @@ -600,11 +603,21 @@ var Preview = Utils.defineClass({ this._closeButtonBin.add_child(closeButton); + this._previewBin = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + x_expand: true, y_expand: true, + style: 'padding: ' + this._padding + 'px;' + }); + + this._previewBin.set_size(previewBinWidth, previewBinHeight); + + box.add_child(this._previewBin); + if (headerHeight) { let headerBox = new St.Widget({ layout_manager: new Clutter.BoxLayout(), - y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'], - y_expand: true, + x_expand: true, + y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'], style: this._getBackgroundColor(HEADER_COLOR_OFFSET, .8) }); @@ -618,19 +631,16 @@ var Preview = Utils.defineClass({ headerBox.insert_child_at_index(this._workspaceIndicator, isLeftButtons ? 0 : 1); headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 1 : 2); - this.add_child(headerBox); + box.insert_child_at_index(headerBox, isTopHeader ? 0 : 1); } + this.add_child(box); + this.add_child(this._closeButtonBin); + closeButton.connect('clicked', () => this._onCloseBtnClick()); this.connect('notify::hover', () => this._onHoverChanged()); this.connect('button-release-event', (actor, e) => this._onButtonReleaseEvent(e)); - this.connect('destroy', () => this._onDestroy()); - - this.add_child(this._previewBin); - this.add_child(this._closeButtonBin); - - this.set_size(-1, previewBinHeight + headerHeight); }, adjustOnStage: function() { @@ -678,9 +688,8 @@ var Preview = Utils.defineClass({ animateOut: function() { if (!this.animatingOut) { - let tweenOpts = getTweenOpts({ opacity: 0, onComplete: () => this.destroy() }); + let tweenOpts = getTweenOpts({ opacity: 0, width: 0, height: 0, onComplete: () => this.destroy() }); - tweenOpts[this._previewMenu._checkIfLeftOrRight() ? 'height' : 'width'] = 0; this.animatingOut = true; Tweener.removeTweens(this); @@ -868,13 +877,10 @@ var Preview = Utils.defineClass({ currentClones.forEach(c => c.destroy()); Tweener.addTween(currentClone, currentCloneOpts); } else if (animateSize) { - if (this._previewMenu._checkIfLeftOrRight()) { - newClone.height = 0; - newCloneOpts.height = this.cloneHeight; - } else { - newClone.width = 0; - newCloneOpts.width = this.cloneWidth; - } + newClone.width = 0; + newClone.height = 0; + newCloneOpts.width = this.cloneWidth; + newCloneOpts.height = this.cloneHeight; } this._previewBin.add_child(newClone); @@ -892,15 +898,17 @@ var Preview = Utils.defineClass({ }, _getBinSize: function() { - let [width, height] = this._previewDimensions; + let width = -1; + let height = -1; - width += this._padding * 2; - height += this._padding * 2; + if (this._previewMenu._dtpSettings.get_boolean('window-preview-fixed-size')) { + let [fixedWidth, fixedHeight] = this._previewDimensions; - if (this._previewMenu._checkIfLeftOrRight()) { - height = -1; - } else { - width = -1; + if (this._previewMenu._checkIfLeftOrRight()) { + width = fixedWidth + this._padding * 2; + } else { + height = fixedHeight + this._padding * 2; + } } return [width, height]; From 0692d344b3cd37d989b2b7fa79ab2b41f9553768 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 26 May 2019 21:19:41 -0400 Subject: [PATCH 36/61] Tweak preview menu opacity --- panel.js | 1 + windowPreview.js | 13 ++++++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/panel.js b/panel.js index 45d06a5..afdf0b3 100644 --- a/panel.js +++ b/panel.js @@ -158,6 +158,7 @@ var dtpPanelWrapper = Utils.defineClass({ //the timeout makes sure the theme's styles are computed before initially applying the transparency this.startDynamicTransparencyId = Mainloop.timeout_add(0, () => { + this.startDynamicTransparencyId = 0; this.dynamicTransparency = new Transparency.DynamicTransparency(this); }); diff --git a/windowPreview.js b/windowPreview.js index 934a549..be77894 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -41,6 +41,7 @@ const T3 = 'peekTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; const DEFAULT_RATIO = { w: 160, h: 90 }; +const MIN_MENU_ALPHA = .5; const FOCUSED_COLOR_OFFSET = 24; const HEADER_COLOR_OFFSET = -12; const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; @@ -78,7 +79,7 @@ var PreviewMenu = Utils.defineClass({ reactive: true, track_hover: true, y_expand: true, - y_align: Clutter.ActorAlign.END + y_align: Clutter.ActorAlign[this._translationDirection > 0 ? 'END' : 'START'] }); this._box = new St.BoxLayout({ vertical: isLeftOrRight }); this._scrollView = new St.ScrollView({ @@ -161,7 +162,9 @@ var PreviewMenu = Utils.defineClass({ this.currentAppIcon = appIcon; if (!this.opened) { - this.menu.set_style('background: ' + this._panelWrapper.dynamicTransparency.currentBackgroundColor); + let alpha = Math.max(MIN_MENU_ALPHA, this._panelWrapper.dynamicTransparency.alpha); + + this.menu.set_style('background: ' + Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, alpha)); this.menu.show(); this._refreshGlobals(); @@ -618,7 +621,7 @@ var Preview = Utils.defineClass({ layout_manager: new Clutter.BoxLayout(), x_expand: true, y_align: Clutter.ActorAlign[isTopHeader ? 'START' : 'END'], - style: this._getBackgroundColor(HEADER_COLOR_OFFSET, .8) + style: this._getBackgroundColor(HEADER_COLOR_OFFSET, 1) }); this._workspaceIndicator = new St.Label({ y_align: Clutter.ActorAlign.CENTER }); @@ -659,7 +662,7 @@ var Preview = Utils.defineClass({ this._closeButtonBin.set_style( 'padding: ' + closeButtonPadding + 'px; ' + - this._getBackgroundColor(Math.abs(HEADER_COLOR_OFFSET), .8) + + this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : MIN_MENU_ALPHA) + closeButtonBorderRadius ); }, @@ -846,7 +849,7 @@ var Preview = Utils.defineClass({ alpha = Math.abs(alpha); if (isNaN(alpha)) { - alpha = this._panelWrapper.dynamicTransparency.alpha; + alpha = Math.max(MIN_MENU_ALPHA, this._panelWrapper.dynamicTransparency.alpha); } return Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, alpha, offset); From 3649424b7e96ed60e4a2aa2d0e14cf81b79d3095 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 27 May 2019 23:57:25 -0400 Subject: [PATCH 37/61] Add minimum size to previews --- windowPreview.js | 74 +++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index be77894..16bdd06 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -41,6 +41,7 @@ const T3 = 'peekTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; const DEFAULT_RATIO = { w: 160, h: 90 }; +const MIN_DIMENSION = 100; const MIN_MENU_ALPHA = .5; const FOCUSED_COLOR_OFFSET = 24; const HEADER_COLOR_OFFSET = -12; @@ -609,7 +610,7 @@ var Preview = Utils.defineClass({ this._previewBin = new St.Widget({ layout_manager: new Clutter.BinLayout(), x_expand: true, y_expand: true, - style: 'padding: ' + this._padding + 'px;' + style: 'padding: ' + this._padding / scaleFactor + 'px;' }); this._previewBin.set_size(previewBinWidth, previewBinHeight); @@ -671,10 +672,10 @@ var Preview = Utils.defineClass({ if (this.window != window) { let _assignWindowClone = () => { if (window.get_compositor_private()) { - let clone = this._getWindowClone(window); + let cloneBin = this._getWindowCloneBin(window); - this._resizeClone(clone); - this._addClone(clone, animateSize); + this._resizeClone(cloneBin); + this._addClone(cloneBin, animateSize); this._previewMenu.updatePosition(); } else { Mainloop.idle_add(() => _assignWindowClone()); @@ -855,48 +856,48 @@ var Preview = Utils.defineClass({ return Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, alpha, offset); }, - _addClone: function(newClone, animateSize) { + _addClone: function(newCloneBin, animateSize) { let currentClones = this._previewBin.get_children(); let newCloneOpts = getTweenOpts({ opacity: 255 }); - if (currentClones.length) { - let currentClone = currentClones.pop(); - let currentCloneOpts = getTweenOpts({ opacity: 0, onComplete: () => currentClone.destroy() }); + this._previewBin.add_child(newCloneBin); - if (newClone.width > currentClone.width) { - newCloneOpts.width = newClone.width; - newClone.width = currentClone.width; + if (currentClones.length) { + let currentCloneBin = currentClones.pop(); + let currentCloneOpts = getTweenOpts({ opacity: 0, onComplete: () => currentCloneBin.destroy() }); + + if (newCloneBin.width > currentCloneBin.width) { + newCloneOpts.width = newCloneBin.width; + newCloneBin.width = currentCloneBin.width; } else { - currentCloneOpts.width = newClone.width; + currentCloneOpts.width = newCloneBin.width; } - if (newClone.height > currentClone.height) { - newCloneOpts.height = newClone.height; - newClone.height = currentClone.height; + if (newCloneBin.height > currentCloneBin.height) { + newCloneOpts.height = newCloneBin.height; + newCloneBin.height = currentCloneBin.height; } else { - currentCloneOpts.height = newClone.height; + currentCloneOpts.height = newCloneBin.height; } currentClones.forEach(c => c.destroy()); - Tweener.addTween(currentClone, currentCloneOpts); + Tweener.addTween(currentCloneBin, currentCloneOpts); } else if (animateSize) { - newClone.width = 0; - newClone.height = 0; + newCloneBin.width = 0; + newCloneBin.height = 0; newCloneOpts.width = this.cloneWidth; newCloneOpts.height = this.cloneHeight; } - this._previewBin.add_child(newClone); - - Tweener.addTween(newClone, newCloneOpts); + Tweener.addTween(newCloneBin, newCloneOpts); }, - _getWindowClone: function(window) { - return new Clutter.Clone({ - source: window.get_compositor_private(), - opacity: 0, + _getWindowCloneBin: function(window) { + return new St.Bin({ + child: new Clutter.Clone({ source: window.get_compositor_private() }), y_align: Clutter.ActorAlign.CENTER, - x_align: Clutter.ActorAlign.CENTER + x_align: Clutter.ActorAlign.CENTER, + opacity: 0, }); }, @@ -917,17 +918,20 @@ var Preview = Utils.defineClass({ return [width, height]; }, - _resizeClone: function(clone) { - let [width, height] = clone.get_source().get_size(); + _resizeClone: function(cloneBin) { + let [width, height] = cloneBin.child.get_source().get_size(); let [maxWidth, maxHeight] = this._previewDimensions; - let ratio = Math.min(maxWidth / width, maxHeight / height); + let ratio = Math.min(maxWidth / width, maxHeight / height, 1); + let cloneWidth = Math.floor(width * ratio); + let cloneHeight = Math.floor(height * ratio); + let clonePaddingTB = cloneHeight < MIN_DIMENSION ? MIN_DIMENSION - cloneHeight : 0; + let clonePaddingLR = cloneWidth < MIN_DIMENSION ? MIN_DIMENSION - cloneWidth : 0; - ratio = ratio < 1 ? ratio : 1; + this.cloneWidth = cloneWidth + clonePaddingLR * scaleFactor; + this.cloneHeight = cloneHeight + clonePaddingTB * scaleFactor; - this.cloneWidth = Math.floor(width * ratio); - this.cloneHeight = Math.floor(height * ratio); - - clone.set_size(this.cloneWidth, this.cloneHeight); + cloneBin.set_style('padding: ' + Math.floor(clonePaddingTB * .5) + 'px ' + Math.floor(clonePaddingLR * .5) + 'px;'); + cloneBin.child.set_size(cloneWidth, cloneHeight); }, _getPreviewDimensions: function() { From 6ea159ac286e4cfadeb27c71f80348c30aa9bc9c Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 28 May 2019 17:51:07 -0400 Subject: [PATCH 38/61] Use primary monitor as preview reference aspect ratio --- windowPreview.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 16bdd06..a355c6a 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -40,7 +40,6 @@ const T3 = 'peekTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; -const DEFAULT_RATIO = { w: 160, h: 90 }; const MIN_DIMENSION = 100; const MIN_MENU_ALPHA = .5; const FOCUSED_COLOR_OFFSET = 24; @@ -920,8 +919,8 @@ var Preview = Utils.defineClass({ _resizeClone: function(cloneBin) { let [width, height] = cloneBin.child.get_source().get_size(); - let [maxWidth, maxHeight] = this._previewDimensions; - let ratio = Math.min(maxWidth / width, maxHeight / height, 1); + let [fixedWidth, fixedHeight] = this._previewDimensions; + let ratio = Math.min(fixedWidth / width, fixedHeight / height, 1); let cloneWidth = Math.floor(width * ratio); let cloneHeight = Math.floor(height * ratio); let clonePaddingTB = cloneHeight < MIN_DIMENSION ? MIN_DIMENSION - cloneHeight : 0; @@ -935,15 +934,16 @@ var Preview = Utils.defineClass({ }, _getPreviewDimensions: function() { + let primaryMonitor = Main.layoutManager.primaryMonitor; let size = this._previewMenu._dtpSettings.get_int('window-preview-size') * scaleFactor; let w, h; if (this._previewMenu._checkIfLeftOrRight()) { - w = Math.max(DEFAULT_RATIO.w, size); - h = w * DEFAULT_RATIO.h / DEFAULT_RATIO.w; + w = size; + h = w * primaryMonitor.height / primaryMonitor.width; } else { - h = Math.max(DEFAULT_RATIO.h, size); - w = h * DEFAULT_RATIO.w / DEFAULT_RATIO.h; + h = size; + w = h * primaryMonitor.width / primaryMonitor.height; } return [w, h]; From 7bb92dbfa341e1950277a7f08ecac65d10ffa979 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 28 May 2019 17:59:14 -0400 Subject: [PATCH 39/61] Include appicon margin in preview centering --- windowPreview.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index a355c6a..f0059ce 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -409,17 +409,18 @@ var PreviewMenu = Utils.defineClass({ let sourceContentBox = sourceNode.get_content_box(this.currentAppIcon.actor.get_allocation_box()); let sourceAllocation = Shell.util_get_transformed_allocation(this.currentAppIcon.actor); let [previewsWidth, previewsHeight] = this._getPreviewsSize(); + let appIconMargin = this._dtpSettings.get_int('appicon-margin') / scaleFactor; let x = 0, y = 0; previewsWidth = Math.min(previewsWidth, this._panelWrapper.monitor.width); previewsHeight = Math.min(previewsHeight, this._panelWrapper.monitor.height) + headerHeight; if (this._checkIfLeftOrRight()) { - y = sourceAllocation.y1 - this._panelWrapper.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; + y = sourceAllocation.y1 + appIconMargin - this._panelWrapper.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; y = Math.max(y, 0); y = Math.min(y, this._panelWrapper.monitor.height - previewsHeight); } else { - x = sourceAllocation.x1 - this._panelWrapper.monitor.x + (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * .5; + x = sourceAllocation.x1 + appIconMargin - this._panelWrapper.monitor.x + (sourceContentBox.x2 - sourceContentBox.x1 - previewsWidth) * .5; x = Math.max(x, 0); x = Math.min(x, this._panelWrapper.monitor.width - previewsWidth); } From e448d5862d884e724443a0d4cfa287412b25b42c Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 28 May 2019 18:17:28 -0400 Subject: [PATCH 40/61] Tweak animation time without impatience enabled --- schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index 1647af8..31889c0 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -422,7 +422,7 @@ This defines the window preview titles font size. - 300 + 260 Window previews animation time This defines the window previews animation time. From 42ecac85e1da85be3302b566a081e73c7d7f547b Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Wed, 29 May 2019 00:10:07 -0400 Subject: [PATCH 41/61] Restore intellihide grabs check for PanelMenuButton --- intellihide.js | 17 ++++++++++++++++- panel.js | 3 ++- panelManager.js | 2 +- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/intellihide.js b/intellihide.js index 7ab838a..e725715 100644 --- a/intellihide.js +++ b/intellihide.js @@ -20,6 +20,7 @@ const Clutter = imports.gi.Clutter; const Meta = imports.gi.Meta; const Shell = imports.gi.Shell; +const GrabHelper = imports.ui.grabHelper; const Layout = imports.ui.layout; const Main = imports.ui.main; const OverviewControls = imports.ui.overviewControls; @@ -32,10 +33,12 @@ const Utils = Me.imports.utils; //timeout intervals const CHECK_POINTER_MS = 200; +const CHECK_GRAB_MS = 400; const POST_ANIMATE_MS = 50; const MIN_UPDATE_MS = 250; //timeout names +const T1 = 'checkGrabTimeout'; const T2 = 'limitUpdateTimeout'; const T3 = 'postAnimateTimeout'; @@ -295,7 +298,8 @@ var Intellihide = Utils.defineClass({ }, _checkIfShouldBeVisible: function(fromRevealMechanism) { - if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.opened || this._panelBox.get_hover()) { + if (Main.overview.visibleTarget || this._dtpPanel.taskbar.previewMenu.opened || + this._panelBox.get_hover() || this._checkIfGrab()) { return true; } @@ -317,6 +321,17 @@ var Intellihide = Utils.defineClass({ return !this._windowOverlap; }, + _checkIfGrab: function() { + if (GrabHelper._grabHelperStack.some(gh => this._panelBox.contains(gh._owner))) { + //there currently is a grab on a child of the panel, check again soon to catch its release + this._timeoutsHandler.add([T1, CHECK_GRAB_MS, () => this._queueUpdatePanelPosition()]); + + return true; + } + + return false; + }, + _revealPanel: function(immediate) { this._animatePanel(0, immediate); }, diff --git a/panel.js b/panel.js index afdf0b3..ae9c8fc 100644 --- a/panel.js +++ b/panel.js @@ -267,7 +267,6 @@ var dtpPanelWrapper = Utils.defineClass({ this._setAppmenuVisible(false); if(this.appMenu) this.panel._leftBox.add_child(this.appMenu.container); - this.taskbar.destroy(); if (this.startIntellihideId) { Mainloop.source_remove(this.startIntellihideId); @@ -288,6 +287,8 @@ var dtpPanelWrapper = Utils.defineClass({ this.dynamicTransparency.destroy(); } + this.taskbar.destroy(); + // reset stored icon size to the default dash Main.overview.dashIconSize = Main.overview._controls.dash.iconSize; diff --git a/panelManager.js b/panelManager.js index 06c8f87..146af74 100755 --- a/panelManager.js +++ b/panelManager.js @@ -282,7 +282,7 @@ var dtpPanelManager = Utils.defineClass({ }, _getBoxPointerPreferredHeight: function(boxPointer, alloc, monitor) { - if (boxPointer._dtpInPanel && this._dtpSettings.get_boolean('intellihide')) { + if (boxPointer._dtpInPanel && boxPointer.sourceActor && this._dtpSettings.get_boolean('intellihide')) { monitor = monitor || Main.layoutManager.findMonitorForActor(boxPointer.sourceActor); let excess = alloc.natural_size + this._dtpSettings.get_int('panel-size') + 10 - monitor.height; // 10 is arbitrary From 045350db8207b5fe023b082c6acdc2c2f9b80eba Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Wed, 29 May 2019 21:24:25 -0400 Subject: [PATCH 42/61] Add more preview sizing options --- Settings.ui | 307 +++++++++++------- prefs.js | 30 +- ...shell.extensions.dash-to-panel.gschema.xml | 21 +- windowPreview.js | 42 +-- 4 files changed, 250 insertions(+), 150 deletions(-) diff --git a/Settings.ui b/Settings.ui index 2cd7e60..7bf6ce2 100644 --- a/Settings.ui +++ b/Settings.ui @@ -2207,17 +2207,18 @@ False none - + True True - + True False 12 12 12 12 + 12 32 @@ -2247,23 +2248,6 @@ 0 - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 True @@ -2274,7 +2258,7 @@ 0 - 0 + 1 @@ -2282,32 +2266,16 @@ True True 4 - 0 + 25 leave_timeout_adjustment True + 25 1 - 0 + 1 - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 True @@ -2318,7 +2286,7 @@ 0 - 0 + 2 @@ -2332,7 +2300,7 @@ 1 - 0 + 2 @@ -2383,32 +2351,19 @@ - + True True - + True False 12 12 12 12 + 12 32 - - - True - True - 4 - 0 - preview_size_adjustment - True - - - 1 - 0 - - True @@ -2421,81 +2376,36 @@ 0 0 + 3 - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - + + True + True + 4 + 0 + preview_size_adjustment + True + + + 2 + 0 + + + + True False True - Use a fixed size for the window previews + Window aspect ratio Y (height) True 0 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - True - 4 - 50 - preview_padding_adjustment - True - 50 - - - 1 - 0 + 2 + 2 @@ -2509,7 +2419,160 @@ 0 - 0 + 3 + 2 + + + + + True + True + 4 + 50 + preview_padding_adjustment + True + 50 + + + 2 + 3 + + + + + True + False + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + False + True + 1 + + + + + Fixed + True + True + True + + + False + True + 2 + + + + + 2 + 1 + + + + + True + False + True + Window aspect ratio X (width) + True + 0 + + + 0 + 1 + 2 + + + + + True + False + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + False + True + 0 + + + + + Fixed + True + True + True + + + False + True + 1 + + + + + 2 + 2 diff --git a/prefs.js b/prefs.js index ddf5b4f..6d82f4c 100644 --- a/prefs.js +++ b/prefs.js @@ -1030,8 +1030,13 @@ const Settings = new Lang.Class({ 'active', Gio.SettingsBindFlags.DEFAULT); - this._settings.bind('window-preview-fixed-size', - this._builder.get_object('preview_fixed_size_switch'), + this._settings.bind('window-preview-fixed-x', + this._builder.get_object('preview_aspect_ratio_x_fixed_togglebutton'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('window-preview-fixed-y', + this._builder.get_object('preview_aspect_ratio_y_fixed_togglebutton'), 'active', Gio.SettingsBindFlags.DEFAULT); @@ -1090,6 +1095,16 @@ const Settings = new Lang.Class({ this._settings.set_int('window-preview-size', widget.get_value()); })); + this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString()); + this._builder.get_object('preview_aspect_ratio_x_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-aspect-ratio-x', parseInt(widget.get_active_id(), 10)); + })); + + this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString()); + this._builder.get_object('preview_aspect_ratio_y_combo').connect('changed', Lang.bind (this, function(widget) { + this._settings.set_int('window-preview-aspect-ratio-y', parseInt(widget.get_active_id(), 10)); + })); + this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); this._builder.get_object('preview_padding_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { this._settings.set_int('window-preview-padding', widget.get_value()); @@ -1132,14 +1147,21 @@ const Settings = new Lang.Class({ this._settings.set_value('window-preview-size', this._settings.get_default_value('window-preview-size')); this._builder.get_object('preview_size_spinbutton').set_value(this._settings.get_int('window-preview-size')); + + this._settings.set_value('window-preview-fixed-x', this._settings.get_default_value('window-preview-fixed-x')); + this._settings.set_value('window-preview-fixed-y', this._settings.get_default_value('window-preview-fixed-y')); + + this._settings.set_value('window-preview-aspect-ratio-x', this._settings.get_default_value('window-preview-aspect-ratio-x')); + this._builder.get_object('preview_aspect_ratio_x_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-x').toString()); + + this._settings.set_value('window-preview-aspect-ratio-y', this._settings.get_default_value('window-preview-aspect-ratio-y')); + this._builder.get_object('preview_aspect_ratio_y_combo').set_active_id(this._settings.get_int('window-preview-aspect-ratio-y').toString()); this._settings.set_value('window-preview-padding', this._settings.get_default_value('window-preview-padding')); this._builder.get_object('preview_padding_spinbutton').set_value(this._settings.get_int('window-preview-padding')); this._settings.set_value('preview-middle-click-close', this._settings.get_default_value('preview-middle-click-close')); - this._settings.set_value('window-preview-fixed-size', this._settings.get_default_value('window-preview-fixed-size')); - this._settings.set_value('window-preview-title-font-size', this._settings.get_default_value('window-preview-title-font-size')); this._builder.get_object('preview_title_size_spinbutton').set_value(this._settings.get_int('window-preview-title-font-size')); diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index 31889c0..744a500 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -436,16 +436,31 @@ Window previews size Preferred window previews size - + + false + Fixed aspect ratio X + This defines if the window previews use a fixed aspect ratio X. + + true - Window previews fixed size - This defines if the window previews use a fixed or dynamic size. + Fixed aspect ratio Y + This defines if the window previews use a fixed aspect ratio Y. 8 Window previews padding The padding of the window previews + + 16 + Aspect ratio X + The window previews respected aspect ratio X. + + + 9 + Aspect ratio Y + The window previews respected aspect ratio Y. + false Provide workspace isolation diff --git a/windowPreview.js b/windowPreview.js index f0059ce..7db979c 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -46,11 +46,12 @@ const FOCUSED_COLOR_OFFSET = 24; const HEADER_COLOR_OFFSET = -12; const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; -var headerHeight = 0; -var isLeftButtons = false; -var isTopHeader = true; -var scaleFactor = 1; -var animationTime = 0; +let headerHeight = 0; +let isLeftButtons = false; +let isTopHeader = true; +let scaleFactor = 1; +let animationTime = 0; +let aspectRatio = {}; var PreviewMenu = Utils.defineClass({ Name: 'DashToPanel-PreviewMenu', @@ -363,6 +364,14 @@ var PreviewMenu = Utils.defineClass({ scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; headerHeight = this._dtpSettings.get_boolean('window-preview-show-title') ? HEADER_HEIGHT * scaleFactor : 0; animationTime = this._dtpSettings.get_int('window-preview-animation-time') * .001; + aspectRatio.x = { + size: this._dtpSettings.get_int('window-preview-aspect-ratio-x'), + fixed: this._dtpSettings.get_boolean('window-preview-fixed-x') + }; + aspectRatio.y = { + size: this._dtpSettings.get_int('window-preview-aspect-ratio-y'), + fixed: this._dtpSettings.get_boolean('window-preview-fixed-y') + }; }, _resetHiddenState: function() { @@ -902,20 +911,12 @@ var Preview = Utils.defineClass({ }, _getBinSize: function() { - let width = -1; - let height = -1; + let [fixedWidth, fixedHeight] = this._previewDimensions; - if (this._previewMenu._dtpSettings.get_boolean('window-preview-fixed-size')) { - let [fixedWidth, fixedHeight] = this._previewDimensions; - - if (this._previewMenu._checkIfLeftOrRight()) { - width = fixedWidth + this._padding * 2; - } else { - height = fixedHeight + this._padding * 2; - } - } - - return [width, height]; + return [ + aspectRatio.x.fixed ? fixedWidth + this._padding * 2 : -1, + aspectRatio.y.fixed ? fixedHeight + this._padding * 2 : -1 + ]; }, _resizeClone: function(cloneBin) { @@ -935,16 +936,15 @@ var Preview = Utils.defineClass({ }, _getPreviewDimensions: function() { - let primaryMonitor = Main.layoutManager.primaryMonitor; let size = this._previewMenu._dtpSettings.get_int('window-preview-size') * scaleFactor; let w, h; if (this._previewMenu._checkIfLeftOrRight()) { w = size; - h = w * primaryMonitor.height / primaryMonitor.width; + h = w * aspectRatio.y.size / aspectRatio.x.size; } else { h = size; - w = h * primaryMonitor.width / primaryMonitor.height; + w = h * aspectRatio.x.size / aspectRatio.y.size; } return [w, h]; From 3f6361a110ec3c92570ecfc7bf368ea18d81ae82 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 30 May 2019 19:09:02 -0400 Subject: [PATCH 43/61] Remove clipping container when previews are hidden --- Settings.ui | 2 ++ windowPreview.js | 6 +++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Settings.ui b/Settings.ui index 7bf6ce2..27cc1bc 100644 --- a/Settings.ui +++ b/Settings.ui @@ -2383,6 +2383,7 @@ True True + end 4 0 preview_size_adjustment @@ -2427,6 +2428,7 @@ True True + end 4 50 preview_padding_adjustment diff --git a/windowPreview.js b/windowPreview.js index 7db979c..91500c8 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -101,7 +101,7 @@ var PreviewMenu = Utils.defineClass({ this._timeoutsHandler = new Utils.TimeoutsHandler(); this._signalsHandler = new Utils.GlobalSignalsHandler(); - Main.layoutManager.addChrome(this, { trackFullscreen: true, affectsInputRegion: false }); + Main.layoutManager.addChrome(this, { affectsInputRegion: false }); Main.layoutManager.trackChrome(this.menu, { affectsInputRegion: true }); this._resetHiddenState(); @@ -166,7 +166,7 @@ var PreviewMenu = Utils.defineClass({ let alpha = Math.max(MIN_MENU_ALPHA, this._panelWrapper.dynamicTransparency.alpha); this.menu.set_style('background: ' + Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, alpha)); - this.menu.show(); + this.show(); this._refreshGlobals(); this.grab_key_focus(); @@ -375,7 +375,7 @@ var PreviewMenu = Utils.defineClass({ }, _resetHiddenState: function() { - this.menu.hide(); + this.hide(); this._setOpenedState(false); this.menu.opacity = 0; this.menu[this._translationProp] = this._translationOffset; From f63b39b2e828d03cbe16f561e9c409764dff6635 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 31 May 2019 17:10:53 -0400 Subject: [PATCH 44/61] Add panelBox padding to clipping container position --- windowPreview.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 91500c8..c0e0cd6 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -120,6 +120,11 @@ var PreviewMenu = Utils.defineClass({ 'scroll-event', this._onScrollEvent.bind(this) ], + [ + this._panelWrapper.panelBox, + 'style-changed', + () => this._updateClip() + ], [ this._dtpSettings, [ @@ -384,6 +389,7 @@ var PreviewMenu = Utils.defineClass({ _updateClip: function() { let x, y, w, h; + let panelBoxTheme = this._panelWrapper.panelBox.get_theme_node(); let panelSize = this._dtpSettings.get_int('panel-size') * scaleFactor; let previewSize = (this._dtpSettings.get_int('window-preview-size') + this._dtpSettings.get_int('window-preview-padding') * 2) * scaleFactor; @@ -399,13 +405,13 @@ var PreviewMenu = Utils.defineClass({ } if (this._position == St.Side.LEFT) { - x = this._panelWrapper.monitor.x + panelSize; + x = this._panelWrapper.monitor.x + panelSize + panelBoxTheme.get_padding(St.Side.LEFT); } else if (this._position == St.Side.RIGHT) { - x = this._panelWrapper.monitor.x + this._panelWrapper.monitor.width - (panelSize + previewSize) ; + x = this._panelWrapper.monitor.x + this._panelWrapper.monitor.width - (panelSize + previewSize) - panelBoxTheme.get_padding(St.Side.RIGHT); } else if (this._position == St.Side.TOP) { - y = this._panelWrapper.monitor.y + panelSize; + y = this._panelWrapper.monitor.y + panelSize + panelBoxTheme.get_padding(St.Side.TOP); } else { //St.Side.BOTTOM - y = this._panelWrapper.monitor.y + this._panelWrapper.monitor.height - (panelSize + previewSize + headerHeight); + y = this._panelWrapper.monitor.y + this._panelWrapper.monitor.height - (panelSize + panelBoxTheme.get_padding(St.Side.BOTTOM) + previewSize + headerHeight); } this.set_clip(0, 0, w, h); From 9b299ff4def8bd1eade7a4aca961ee14176c84bf Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 31 May 2019 17:27:06 -0400 Subject: [PATCH 45/61] Do not grab key focus when showing previews --- appIcons.js | 6 ++---- windowPreview.js | 6 +----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/appIcons.js b/appIcons.js index d72de18..04ff659 100644 --- a/appIcons.js +++ b/appIcons.js @@ -181,11 +181,9 @@ var taskbarAppIcon = Utils.defineClass({ Lang.bind(this, this._onFocusAppChanged)); this._windowEnteredMonitorId = this._windowLeftMonitorId = 0; - this._stateChangedId = this.app.connect('windows-changed', - Lang.bind(this, this.onWindowsChanged)); - if (!this.window) { - + this._stateChangedId = this.app.connect('windows-changed', Lang.bind(this, this.onWindowsChanged)); + if (!this.window) { if (this._dtpSettings.get_boolean('isolate-monitors')) { this._windowEnteredMonitorId = Utils.DisplayWrapper.getScreen().connect('window-entered-monitor', this.onWindowEnteredOrLeft.bind(this)); this._windowLeftMonitorId = Utils.DisplayWrapper.getScreen().connect('window-left-monitor', this.onWindowEnteredOrLeft.bind(this)); diff --git a/windowPreview.js b/windowPreview.js index c0e0cd6..45a1a2f 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -174,7 +174,6 @@ var PreviewMenu = Utils.defineClass({ this.show(); this._refreshGlobals(); - this.grab_key_focus(); } this._mergeWindows(appIcon); @@ -197,7 +196,6 @@ var PreviewMenu = Utils.defineClass({ this._animateOpenOrClose(false, () => this._resetHiddenState()); } - Utils.DisplayWrapper.getScreen().focus_default_window(1); this._box.get_children().forEach(c => c.reactive = false); this.menu.reactive = false; this.currentAppIcon = null; @@ -538,10 +536,8 @@ var PreviewMenu = Utils.defineClass({ } Main.wm._blockAnimations = true; - workspace.activate(1); + workspace.activate(global.display.get_current_time_roundtrip()); Main.wm._blockAnimations = false; - - this.grab_key_focus(); }, _focusMetaWindow: function(dimOpacity, window) { From 3f57dad99ede99206ead5c1bc1647b5740a88046 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 31 May 2019 20:24:50 -0400 Subject: [PATCH 46/61] Try to clarify preview sizing options --- Settings.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Settings.ui b/Settings.ui index 27cc1bc..e68efdf 100644 --- a/Settings.ui +++ b/Settings.ui @@ -2369,7 +2369,7 @@ True False True - Window previews size (px) + Window previews preferred size (px) True 0 @@ -2399,7 +2399,7 @@ True False True - Window aspect ratio Y (height) + Window previews aspect ratio Y (height) True 0 @@ -2506,7 +2506,7 @@ True False True - Window aspect ratio X (width) + Window previews aspect ratio X (width) True 0 From becde70098083ab2ad21e7b1cf4019b406def583 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 31 May 2019 23:16:16 -0400 Subject: [PATCH 47/61] Add scrollbar to preview options dialog --- Settings.ui | 1356 ++++++++++++++++++++++++++------------------------- 1 file changed, 683 insertions(+), 673 deletions(-) diff --git a/Settings.ui b/Settings.ui index e68efdf..4b8b8cc 100644 --- a/Settings.ui +++ b/Settings.ui @@ -2196,361 +2196,424 @@ False vertical - + True - False - 0 + True in + 480 + True + True - + True False - none + natural + natural - + True - True + False + none - + True - False - 12 - 12 - 12 - 12 - 12 - 32 + True - - True - True - 4 - 0 - preview_timeout_adjustment - True - - - 1 - 0 - - - - + True False - True - Time (ms) before showing (100 is default) - True - 0 - - - 0 - 0 - - - - - True - False - True - Time (ms) before hiding (100 is default) - 0 - - - 0 - 1 - - - - - True - True - 4 - 25 - leave_timeout_adjustment - True - 25 - - - 1 - 1 - - - - - True - False - True - Animation time (ms) - 0 - - - 0 - 2 - - - - - True - True - 4 - 0 - preview_animation_time_adjustment - True - - - 1 - 2 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Middle click on the preview to close the window - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Window previews preferred size (px) - True - 0 - - - 0 - 0 - 3 - - - - - True - True - end - 4 - 0 - preview_size_adjustment - True - - - 2 - 0 - - - - - True - False - True - Window previews aspect ratio Y (height) - True - 0 - - - 0 - 2 - 2 - - - - - True - False - True - Window previews padding (px) - True - 0 - - - 0 - 3 - 2 - - - - - True - True - end - 4 - 50 - preview_padding_adjustment - True - 50 - - - 2 - 3 - - - - - True - False - 2 - True + 12 + 12 + 12 + 12 + 12 + 32 - - True - False - end - center - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - - - - False - True - 1 - - - - - Fixed + True True - True + 4 + 0 + preview_timeout_adjustment + True - False - True - 2 + 1 + 0 + + + + + True + False + True + Time (ms) before showing (100 is default) + True + 0 + + + 0 + 0 + + + + + True + False + True + Time (ms) before hiding (100 is default) + 0 + + + 0 + 1 + + + + + True + True + 4 + 25 + leave_timeout_adjustment + True + 25 + + + 1 + 1 + + + + + True + False + True + Animation time (ms) + 0 + + + 0 + 2 + + + + + True + True + 4 + 0 + preview_animation_time_adjustment + True + + + 1 + 2 - - 2 - 1 - + + + + + True + True - + True False - True - Window previews aspect ratio X (width) - True - 0 - - - 0 - 1 - 2 - - - - - True - False - 2 - True + 12 + 12 + 12 + 12 + 32 - + + True + False + True + Middle click on the preview to close the window + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Window previews preferred size (px) + True + 0 + + + 0 + 0 + 3 + + + + + True + True + end + 4 + 100 + preview_size_adjustment + True + 100 + + + 2 + 0 + + + + + True + False + True + Window previews aspect ratio Y (height) + True + 0 + + + 0 + 2 + 2 + + + + + True + False + True + Window previews padding (px) + True + 0 + + + 0 + 3 + 2 + + + + + True + True + end + 4 + 50 + preview_padding_adjustment + True + 50 + + + 2 + 3 + + + + True False end - center - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + False + True + 1 + + + + + Fixed + True + True + True + end + + + False + True + 2 + + + + + 2 + 1 + + + + + True + False + True + Window previews aspect ratio X (width) + True + 0 + + + 0 + 1 + 2 + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + False + True + 0 + + + + + Fixed + True + True + True + end + + + False + True + 1 + + + + + 2 + 2 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Close button and header position + 0 False @@ -2559,11 +2622,47 @@ - - Fixed + True - True - True + False + 32 + + + Bottom + True + True + False + center + center + True + True + + + + False + True + 1 + + + + + Top + True + True + False + center + center + bottom + True + preview_title_position_bottom_button + + + + False + True + 2 + + False @@ -2572,235 +2671,28 @@ - - 2 - 2 - - - - - - True - True - + True - False - 12 - 12 - 12 - 12 - 32 + True - + True False - True - Close button and header position - 0 - - - False - True - 0 - - - - - True - False - 32 - - - Bottom - True - True - False - center - center - True - True - - - - False - True - 1 - - - - - Top - True - True - False - center - center - bottom - True - preview_title_position_bottom_button - - - - False - True - 2 - - - - - False - True - 1 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Display window preview headers - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - True - False - 20 + 12 + 12 12 + 12 32 - - True - True - 4 - 6 - preview_title_font_size_adjustment - True - 6 - - - 1 - 0 - - - - + True False True - Font size (px) of the preview titles - True - 0 - - - 0 - 0 - - - - - 0 - 1 - 2 - - - - - True - False - 20 - 12 - 32 - - - True - False - True - Font weight of the preview titles - 0 - - - 0 - 0 - - - - - True - False - center - - inherit from theme - normal - lighter - bold - bolder - - - - 1 - 0 - - - - - 0 - 2 - 2 - - - - - True - False - 20 - 12 - 32 - - - True - False - True - Font color of the preview titles + Display window preview headers True 0 @@ -2810,99 +2702,166 @@ - + True True - True end + center 1 0 + + + True + False + 12 + 32 + + + True + True + 4 + 6 + preview_title_font_size_adjustment + True + 6 + + + 1 + 0 + + + + + True + False + True + Font size (px) of the preview titles + True + 0 + + + 0 + 0 + + + + + 0 + 1 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Font weight of the preview titles + 0 + + + 0 + 0 + + + + + True + False + center + + inherit from theme + normal + lighter + bold + bolder + + + + 1 + 0 + + + + + 0 + 2 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Font color of the preview titles + True + 0 + + + 0 + 0 + + + + + True + True + True + end + + + 1 + 0 + + + + + 0 + 3 + 2 + + - - 0 - 3 - 2 - - - - - - True - True - + True - False - 12 - 12 - 12 - 12 - 32 + True - + True False - True - Enable window peeking - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - True - False - True - When hovering over a window preview for some time, the window gets distinguished. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - True - False - 20 + 12 + 12 12 + 12 32 - + True False True - Enter window peeking mode timeout (ms) + Enable window peeking + True 0 @@ -2911,14 +2870,11 @@ - + True True - 4 - 50 - enter_peek_mode_timeout_adjustment - True - 50 + end + center 1 @@ -2926,11 +2882,11 @@ - + True False True - Time of inactivity while hovering over a window preview needed to enter the window peeking mode. + When hovering over a window preview for some time, the window gets distinguished. True 40 0 @@ -2944,72 +2900,126 @@ 2 - - - 0 - 2 - 2 - - - - - True - False - 20 - 12 - 32 - + True False - True - Window peeking mode opacity - 0 + 12 + 32 + + + True + False + True + Enter window peeking mode timeout (ms) + 0 + + + 0 + 0 + + + + + True + True + 4 + 50 + enter_peek_mode_timeout_adjustment + True + 50 + + + 1 + 0 + + + + + True + False + True + Time of inactivity while hovering over a window preview needed to enter the window peeking mode. + True + 40 + 0 + + + + 0 + 1 + 2 + + 0 - 0 + 2 + 2 - - True - True - 4 - 0 - peek_mode_opacity_adjustment - True - - - 1 - 0 - - - - + True False - True - All windows except for the peeked one have their opacity set to the same value. - True - 40 - 0 - + 12 + 32 + + + True + False + True + Window peeking mode opacity + 0 + + + 0 + 0 + + + + + True + True + 4 + 0 + peek_mode_opacity_adjustment + True + + + 1 + 0 + + + + + True + False + True + All windows except for the peeked one have their opacity set to the same value. + True + 40 + 0 + + + + 0 + 1 + 2 + + 0 - 1 + 3 2 - - 0 - 3 - 2 - @@ -3020,8 +3030,8 @@ False - True - 0 + False + 1 From e3853f966b4612fc6c35ab92eadda20fddde6cbd Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sat, 1 Jun 2019 09:30:28 -0400 Subject: [PATCH 48/61] Fix hover when reopening before close complete --- windowPreview.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 45a1a2f..c6d0610 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -180,7 +180,7 @@ var PreviewMenu = Utils.defineClass({ this._updatePosition(); this._animateOpenOrClose(true); - this.menu.reactive = true; + this._setReactive(true); this._setOpenedState(true); } }, @@ -196,8 +196,7 @@ var PreviewMenu = Utils.defineClass({ this._animateOpenOrClose(false, () => this._resetHiddenState()); } - this._box.get_children().forEach(c => c.reactive = false); - this.menu.reactive = false; + this._setReactive(false); this.currentAppIcon = null; }, @@ -254,6 +253,11 @@ var PreviewMenu = Utils.defineClass({ this._endPeek(true); }, + _setReactive: function(reactive) {  + this._box.get_children().forEach(c => c.reactive = reactive); + this.menu.reactive = reactive; + }, + _setOpenedState: function(opened) { this.opened = opened; this.emit('open-state-changed'); From fe55850a55c115eef19cceea47c04fd179ac4b26 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 2 Jun 2019 21:34:02 -0400 Subject: [PATCH 49/61] Remove prefs property propagate_natural_width for GTK < 3.22 --- Settings.ui | 1678 +++++++++++++++++++++++++-------------------------- prefs.js | 21 +- 2 files changed, 848 insertions(+), 851 deletions(-) diff --git a/Settings.ui b/Settings.ui index 4b8b8cc..b280cbe 100644 --- a/Settings.ui +++ b/Settings.ui @@ -617,6 +617,840 @@ + + True + True + in + 460 + 480 + + + True + False + True + True + natural + natural + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + True + 4 + 0 + preview_timeout_adjustment + True + + + 1 + 0 + + + + + True + False + True + Time (ms) before showing (100 is default) + True + 0 + + + 0 + 0 + + + + + True + False + True + Time (ms) before hiding (100 is default) + 0 + + + 0 + 1 + + + + + True + True + 4 + 25 + leave_timeout_adjustment + True + 25 + + + 1 + 1 + + + + + True + False + True + Animation time (ms) + 0 + + + 0 + 2 + + + + + True + True + 4 + 0 + preview_animation_time_adjustment + True + + + 1 + 2 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Middle click on the preview to close the window + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Window previews preferred size (px) + True + 0 + + + 0 + 0 + 3 + + + + + True + True + end + 4 + 100 + preview_size_adjustment + True + 100 + + + 2 + 0 + + + + + True + False + True + Window previews aspect ratio Y (height) + True + 0 + + + 0 + 2 + 2 + + + + + True + False + True + Window previews padding (px) + True + 0 + + + 0 + 3 + 2 + + + + + True + True + end + 4 + 50 + preview_padding_adjustment + True + 50 + + + 2 + 3 + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + False + True + 1 + + + + + Fixed + True + True + True + end + + + False + True + 2 + + + + + 2 + 1 + + + + + True + False + True + Window previews aspect ratio X (width) + True + 0 + + + 0 + 1 + 2 + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + False + True + 0 + + + + + Fixed + True + True + True + end + + + False + True + 1 + + + + + 2 + 2 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Close button and header position + 0 + + + False + True + 0 + + + + + True + False + 32 + + + Bottom + True + True + False + center + center + True + True + + + + False + True + 1 + + + + + Top + True + True + False + center + center + bottom + True + preview_title_position_bottom_button + + + + False + True + 2 + + + + + False + True + 1 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Display window preview headers + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + True + False + 12 + 32 + + + True + True + 4 + 6 + preview_title_font_size_adjustment + True + 6 + + + 1 + 0 + + + + + True + False + True + Font size (px) of the preview titles + True + 0 + + + 0 + 0 + + + + + 0 + 1 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Font weight of the preview titles + 0 + + + 0 + 0 + + + + + True + False + center + + inherit from theme + normal + lighter + bold + bolder + + + + 1 + 0 + + + + + 0 + 2 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Font color of the preview titles + True + 0 + + + 0 + 0 + + + + + True + True + True + end + + + 1 + 0 + + + + + 0 + 3 + 2 + + + + + + + + + True + True + 6 + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Enable window peeking + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + True + False + True + When hovering over a window preview for some time, the window gets distinguished. + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Enter window peeking mode timeout (ms) + 0 + + + 0 + 0 + + + + + True + True + 4 + 50 + enter_peek_mode_timeout_adjustment + True + 50 + + + 1 + 0 + + + + + True + False + True + Time of inactivity while hovering over a window preview needed to enter the window peeking mode. + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + 0 + 2 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Window peeking mode opacity + 0 + + + 0 + 0 + + + + + True + True + 4 + 0 + peek_mode_opacity_adjustment + True + + + 1 + 0 + + + + + True + False + True + All windows except for the peeked one have their opacity set to the same value. + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + 0 + 3 + 2 + + + + + + + + + + + 10 1 @@ -2191,850 +3025,6 @@ 1 100 - - True - False - vertical - - - True - True - in - 480 - True - True - - - True - False - natural - natural - - - True - False - none - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 12 - 32 - - - True - True - 4 - 0 - preview_timeout_adjustment - True - - - 1 - 0 - - - - - True - False - True - Time (ms) before showing (100 is default) - True - 0 - - - 0 - 0 - - - - - True - False - True - Time (ms) before hiding (100 is default) - 0 - - - 0 - 1 - - - - - True - True - 4 - 25 - leave_timeout_adjustment - True - 25 - - - 1 - 1 - - - - - True - False - True - Animation time (ms) - 0 - - - 0 - 2 - - - - - True - True - 4 - 0 - preview_animation_time_adjustment - True - - - 1 - 2 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Middle click on the preview to close the window - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Window previews preferred size (px) - True - 0 - - - 0 - 0 - 3 - - - - - True - True - end - 4 - 100 - preview_size_adjustment - True - 100 - - - 2 - 0 - - - - - True - False - True - Window previews aspect ratio Y (height) - True - 0 - - - 0 - 2 - 2 - - - - - True - False - True - Window previews padding (px) - True - 0 - - - 0 - 3 - 2 - - - - - True - True - end - 4 - 50 - preview_padding_adjustment - True - 50 - - - 2 - 3 - - - - - True - False - end - 2 - True - - - True - False - end - center - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - - - - False - True - 1 - - - - - Fixed - True - True - True - end - - - False - True - 2 - - - - - 2 - 1 - - - - - True - False - True - Window previews aspect ratio X (width) - True - 0 - - - 0 - 1 - 2 - - - - - True - False - end - 2 - True - - - True - False - end - center - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - - - - False - True - 0 - - - - - Fixed - True - True - True - end - - - False - True - 1 - - - - - 2 - 2 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Close button and header position - 0 - - - False - True - 0 - - - - - True - False - 32 - - - Bottom - True - True - False - center - center - True - True - - - - False - True - 1 - - - - - Top - True - True - False - center - center - bottom - True - preview_title_position_bottom_button - - - - False - True - 2 - - - - - False - True - 1 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Display window preview headers - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - True - False - 12 - 32 - - - True - True - 4 - 6 - preview_title_font_size_adjustment - True - 6 - - - 1 - 0 - - - - - True - False - True - Font size (px) of the preview titles - True - 0 - - - 0 - 0 - - - - - 0 - 1 - 2 - - - - - True - False - 12 - 32 - - - True - False - True - Font weight of the preview titles - 0 - - - 0 - 0 - - - - - True - False - center - - inherit from theme - normal - lighter - bold - bolder - - - - 1 - 0 - - - - - 0 - 2 - 2 - - - - - True - False - 12 - 32 - - - True - False - True - Font color of the preview titles - True - 0 - - - 0 - 0 - - - - - True - True - True - end - - - 1 - 0 - - - - - 0 - 3 - 2 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Enable window peeking - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - True - False - True - When hovering over a window preview for some time, the window gets distinguished. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - True - False - 12 - 32 - - - True - False - True - Enter window peeking mode timeout (ms) - 0 - - - 0 - 0 - - - - - True - True - 4 - 50 - enter_peek_mode_timeout_adjustment - True - 50 - - - 1 - 0 - - - - - True - False - True - Time of inactivity while hovering over a window preview needed to enter the window peeking mode. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - 0 - 2 - 2 - - - - - True - False - 12 - 32 - - - True - False - True - Window peeking mode opacity - 0 - - - 0 - 0 - - - - - True - True - 4 - 0 - peek_mode_opacity_adjustment - True - - - 1 - 0 - - - - - True - False - True - All windows except for the peeked one have their opacity set to the same value. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - 0 - 3 - 2 - - - - - - - - - - - - - False - False - 1 - - - 10000 250 diff --git a/prefs.js b/prefs.js index 6d82f4c..7b7aab1 100644 --- a/prefs.js +++ b/prefs.js @@ -1017,8 +1017,11 @@ const Settings = new Lang.Class({ // Use +1 for the reset action dialog.add_button(_('Reset to defaults'), 1); - let box = this._builder.get_object('box_window_preview_options'); - dialog.get_content_area().add(box); + let scrolledWindow = this._builder.get_object('box_window_preview_options'); + + adjustScrollableHeight(this._builder.get_object('viewport_window_preview_options'), scrolledWindow); + + dialog.get_content_area().add(scrolledWindow); this._builder.get_object('preview_timeout_spinbutton').set_value(this._settings.get_int('show-window-previews-timeout')); this._builder.get_object('preview_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { @@ -1175,7 +1178,7 @@ const Settings = new Lang.Class({ } else { // remove the settings box so it doesn't get destroyed; - dialog.get_content_area().remove(box); + dialog.get_content_area().remove(scrolledWindow); dialog.destroy(); } return; @@ -1821,10 +1824,14 @@ function buildPrefsWidget() { // I'd like the scrolled window to default to a size large enough to show all without scrolling, if it fits on the screen // But, it doesn't seem possible, so I'm setting a minimum size if there seems to be enough screen real estate widget.show_all(); - let viewportSize = settings.viewport.size_request(); - let screenHeight = widget.get_screen().get_height() - 120; - - widget.set_size_request(viewportSize.width, viewportSize.height > screenHeight ? screenHeight : viewportSize.height); + adjustScrollableHeight(settings.viewport, widget); return widget; } + +function adjustScrollableHeight(viewport, scrollableWindow) { + let viewportSize = viewport.size_request(); + let screenHeight = scrollableWindow.get_screen().get_height() - 120; + + scrollableWindow.set_size_request(viewportSize.width, viewportSize.height > screenHeight ? screenHeight : viewportSize.height); +} \ No newline at end of file From 68ef3683bff30e19c63f42b7c53d7e03086e0ad1 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 4 Jun 2019 14:11:04 -0400 Subject: [PATCH 50/61] Adjust settings spinbutton alignments --- Settings.ui | 1688 ++++++++++++++++++++++++++------------------------- 1 file changed, 854 insertions(+), 834 deletions(-) diff --git a/Settings.ui b/Settings.ui index b280cbe..dce178d 100644 --- a/Settings.ui +++ b/Settings.ui @@ -617,840 +617,6 @@ - - True - True - in - 460 - 480 - - - True - False - True - True - natural - natural - - - True - False - none - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 12 - 32 - - - True - True - 4 - 0 - preview_timeout_adjustment - True - - - 1 - 0 - - - - - True - False - True - Time (ms) before showing (100 is default) - True - 0 - - - 0 - 0 - - - - - True - False - True - Time (ms) before hiding (100 is default) - 0 - - - 0 - 1 - - - - - True - True - 4 - 25 - leave_timeout_adjustment - True - 25 - - - 1 - 1 - - - - - True - False - True - Animation time (ms) - 0 - - - 0 - 2 - - - - - True - True - 4 - 0 - preview_animation_time_adjustment - True - - - 1 - 2 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Middle click on the preview to close the window - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Window previews preferred size (px) - True - 0 - - - 0 - 0 - 3 - - - - - True - True - end - 4 - 100 - preview_size_adjustment - True - 100 - - - 2 - 0 - - - - - True - False - True - Window previews aspect ratio Y (height) - True - 0 - - - 0 - 2 - 2 - - - - - True - False - True - Window previews padding (px) - True - 0 - - - 0 - 3 - 2 - - - - - True - True - end - 4 - 50 - preview_padding_adjustment - True - 50 - - - 2 - 3 - - - - - True - False - end - 2 - True - - - True - False - end - center - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - - - - False - True - 1 - - - - - Fixed - True - True - True - end - - - False - True - 2 - - - - - 2 - 1 - - - - - True - False - True - Window previews aspect ratio X (width) - True - 0 - - - 0 - 1 - 2 - - - - - True - False - end - 2 - True - - - True - False - end - center - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 - 20 - 21 - - - - False - True - 0 - - - - - Fixed - True - True - True - end - - - False - True - 1 - - - - - 2 - 2 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Close button and header position - 0 - - - False - True - 0 - - - - - True - False - 32 - - - Bottom - True - True - False - center - center - True - True - - - - False - True - 1 - - - - - Top - True - True - False - center - center - bottom - True - preview_title_position_bottom_button - - - - False - True - 2 - - - - - False - True - 1 - - - - - - - - - True - True - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Display window preview headers - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - True - False - 12 - 32 - - - True - True - 4 - 6 - preview_title_font_size_adjustment - True - 6 - - - 1 - 0 - - - - - True - False - True - Font size (px) of the preview titles - True - 0 - - - 0 - 0 - - - - - 0 - 1 - 2 - - - - - True - False - 12 - 32 - - - True - False - True - Font weight of the preview titles - 0 - - - 0 - 0 - - - - - True - False - center - - inherit from theme - normal - lighter - bold - bolder - - - - 1 - 0 - - - - - 0 - 2 - 2 - - - - - True - False - 12 - 32 - - - True - False - True - Font color of the preview titles - True - 0 - - - 0 - 0 - - - - - True - True - True - end - - - 1 - 0 - - - - - 0 - 3 - 2 - - - - - - - - - True - True - 6 - - - True - False - 12 - 12 - 12 - 12 - 32 - - - True - False - True - Enable window peeking - True - 0 - - - 0 - 0 - - - - - True - True - end - center - - - 1 - 0 - - - - - True - False - True - When hovering over a window preview for some time, the window gets distinguished. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - True - False - 12 - 32 - - - True - False - True - Enter window peeking mode timeout (ms) - 0 - - - 0 - 0 - - - - - True - True - 4 - 50 - enter_peek_mode_timeout_adjustment - True - 50 - - - 1 - 0 - - - - - True - False - True - Time of inactivity while hovering over a window preview needed to enter the window peeking mode. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - 0 - 2 - 2 - - - - - True - False - 12 - 32 - - - True - False - True - Window peeking mode opacity - 0 - - - 0 - 0 - - - - - True - True - 4 - 0 - peek_mode_opacity_adjustment - True - - - 1 - 0 - - - - - True - False - True - All windows except for the peeked one have their opacity set to the same value. - True - 40 - 0 - - - - 0 - 1 - 2 - - - - - 0 - 3 - 2 - - - - - - - - - - - 10 1 @@ -2158,6 +1324,7 @@ True True + end 4 0 group_apps_label_font_size_adjustment @@ -2307,6 +1474,7 @@ True True + end 4 0 group_apps_label_max_width_adjustment @@ -2666,6 +1834,7 @@ True True + end 4 0 intellihide_pressure_threshold_adjustment @@ -2694,6 +1863,7 @@ True True + end 4 0 intellihide_pressure_time_adjustment @@ -2894,6 +2064,7 @@ True True + end 4 0 intellihide_animation_time_adjustment @@ -2939,6 +2110,7 @@ True True + end 4 10 intellihide_close_delay_adjustment @@ -3025,6 +2197,848 @@ 1 100 + + True + True + in + 460 + 480 + + + True + False + True + True + natural + natural + + + True + False + none + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + True + end + 4 + 0 + preview_timeout_adjustment + True + + + 1 + 0 + + + + + True + False + True + Time (ms) before showing (100 is default) + True + 0 + + + 0 + 0 + + + + + True + False + True + Time (ms) before hiding (100 is default) + 0 + + + 0 + 1 + + + + + True + True + end + 4 + 25 + leave_timeout_adjustment + True + 25 + + + 1 + 1 + + + + + True + False + True + Animation time (ms) + 0 + + + 0 + 2 + + + + + True + True + end + 4 + 0 + preview_animation_time_adjustment + True + + + 1 + 2 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Middle click on the preview to close the window + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Window previews preferred size (px) + True + 0 + + + 0 + 0 + 3 + + + + + True + True + end + 4 + 100 + preview_size_adjustment + True + 100 + + + 2 + 0 + + + + + True + False + True + Window previews aspect ratio Y (height) + True + 0 + + + 0 + 2 + 2 + + + + + True + False + True + Window previews padding (px) + True + 0 + + + 0 + 3 + 2 + + + + + True + True + end + 4 + 50 + preview_padding_adjustment + True + 50 + + + 2 + 3 + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + False + True + 1 + + + + + Fixed + True + True + True + end + + + False + True + 2 + + + + + 2 + 1 + + + + + True + False + True + Window previews aspect ratio X (width) + True + 0 + + + 0 + 1 + 2 + + + + + True + False + end + 2 + True + + + True + False + end + center + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + + + + False + True + 0 + + + + + Fixed + True + True + True + end + + + False + True + 1 + + + + + 2 + 2 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Close button and header position + 0 + + + False + True + 0 + + + + + True + False + end + 32 + + + Bottom + True + True + False + center + center + True + True + + + + False + True + 1 + + + + + Top + True + True + False + center + center + bottom + True + preview_title_position_bottom_button + + + + False + True + 2 + + + + + False + True + 1 + + + + + + + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Display window preview headers + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + True + False + 12 + 32 + + + True + True + end + 4 + 6 + preview_title_font_size_adjustment + True + 6 + + + 1 + 0 + + + + + True + False + True + Font size (px) of the preview titles + True + 0 + + + 0 + 0 + + + + + 0 + 1 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Font weight of the preview titles + 0 + + + 0 + 0 + + + + + True + False + end + center + + inherit from theme + normal + lighter + bold + bolder + + + + 1 + 0 + + + + + 0 + 2 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Font color of the preview titles + True + 0 + + + 0 + 0 + + + + + True + True + True + end + + + 1 + 0 + + + + + 0 + 3 + 2 + + + + + + + + + True + True + 6 + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Enable window peeking + True + 0 + + + 0 + 0 + + + + + True + True + end + center + + + 1 + 0 + + + + + True + False + True + When hovering over a window preview for some time, the window gets distinguished. + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Enter window peeking mode timeout (ms) + 0 + + + 0 + 0 + + + + + True + True + end + 4 + 50 + enter_peek_mode_timeout_adjustment + True + 50 + + + 1 + 0 + + + + + True + False + True + Time of inactivity while hovering over a window preview needed to enter the window peeking mode. + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + 0 + 2 + 2 + + + + + True + False + 12 + 32 + + + True + False + True + Window peeking mode opacity + 0 + + + 0 + 0 + + + + + True + True + end + 4 + 0 + peek_mode_opacity_adjustment + True + + + 1 + 0 + + + + + True + False + True + All windows except for the peeked one have their opacity set to the same value. + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + 0 + 3 + 2 + + + + + + + + + + + 10000 250 @@ -3550,6 +3564,7 @@ True True + end 4 1 show_showdesktop_width_adjustment @@ -3628,6 +3643,7 @@ True True + end 4 1 show_showdesktop_delay_adjustment @@ -3657,6 +3673,7 @@ True True + end 4 1 show_showdesktop_time_adjustment @@ -3795,6 +3812,7 @@ True True + end 4 50 trans_distance_adjustment @@ -3855,6 +3873,7 @@ True True + end 0 trans_opacity_min_adjustment @@ -3886,6 +3905,7 @@ True True + end 4 50 trans_anim_time_adjustment From 89c33ef844dd19620ae51473de6fee20ccc35923 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 4 Jun 2019 14:12:18 -0400 Subject: [PATCH 51/61] Remove close button from previews having transient --- utils.js | 8 ++++++++ windowPreview.js | 6 +++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/utils.js b/utils.js index 8ef7945..41a458a 100644 --- a/utils.js +++ b/utils.js @@ -283,6 +283,14 @@ var getWorkspaceCount = function() { return DisplayWrapper.getWorkspaceManager().n_workspaces; }; +var checkIfWindowHasTransient = function(window) { + let hasTransient; + + window.foreach_transient(t => !(hasTransient = true)); + + return hasTransient; +}; + var findIndex = function(array, predicate) { if (Array.prototype.findIndex) { return array.findIndex(predicate); diff --git a/windowPreview.js b/windowPreview.js index c6d0610..d20a002 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -597,6 +597,7 @@ var Preview = Utils.defineClass({ }); this.window = null; + this._needsCloseButton = true; this.cloneWidth = this.cloneHeight = 0; this._panelWrapper = panelWrapper; this._previewMenu = previewMenu; @@ -702,6 +703,7 @@ var Preview = Utils.defineClass({ this._removeWindowSignals(); this.window = window; + this._needsCloseButton = window.can_close() && !Utils.checkIfWindowHasTransient(window); this._updateHeader(); }, @@ -853,7 +855,9 @@ var Preview = Utils.defineClass({ }, _hideOrShowCloseButton: function(hide) { - Tweener.addTween(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 })); + if (this._needsCloseButton) { + Tweener.addTween(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 })); + } }, _getBackgroundColor: function(offset, alpha) { From de72de122739e097acdb197501d279c8f6524bf6 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 6 Jun 2019 18:11:38 -0400 Subject: [PATCH 52/61] Exit peek mode when moving the mouse back to the taskbar --- windowPreview.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index d20a002..df308b5 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -41,7 +41,7 @@ const T3 = 'peekTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; const MIN_DIMENSION = 100; -const MIN_MENU_ALPHA = .5; +const MIN_MENU_ALPHA = .6; const FOCUSED_COLOR_OFFSET = 24; const HEADER_COLOR_OFFSET = -12; const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; @@ -333,6 +333,7 @@ var PreviewMenu = Utils.defineClass({ if (this.currentAppIcon && !this.menu.hover) { this._addCloseTimeout(); + this._endPeek(); } }, @@ -485,7 +486,7 @@ var PreviewMenu = Utils.defineClass({ } }; - tweenOpts[this._translationProp] = show ? 1 * this._translationDirection : this._translationOffset; + tweenOpts[this._translationProp] = show ? this._translationDirection : this._translationOffset; Tweener.addTween(this.menu, getTweenOpts(tweenOpts)); }, From db309b3540c88b25b5ce0a2f74a826b2bb93fe91 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 6 Jun 2019 23:02:01 -0400 Subject: [PATCH 53/61] Add setting to define previews background opacity --- Settings.ui | 95 +++++++++++++++++++ prefs.js | 19 ++++ ...shell.extensions.dash-to-panel.gschema.xml | 10 ++ windowPreview.js | 20 ++-- 4 files changed, 136 insertions(+), 8 deletions(-) diff --git a/Settings.ui b/Settings.ui index dce178d..3c21cb2 100644 --- a/Settings.ui +++ b/Settings.ui @@ -2175,6 +2175,11 @@ 10 50 + + 100 + 5 + 10 + 50 1 @@ -2599,6 +2604,96 @@ + + + True + True + + + True + False + 12 + 12 + 12 + 12 + 32 + + + True + False + True + Use custom opacity for the previews background + True + 0 + + + 0 + 0 + + + + + True + False + True + If disabled, the previews background have the same opacity as the panel + True + 40 + 0 + + + + 0 + 1 + 2 + + + + + True + False + 8 + + + True + True + end + center + + + False + True + 1 + + + + + True + True + end + center + 5 + preview_opacity_adjustment + 5 + + + False + True + 2 + + + + + 1 + 0 + + + + + + True diff --git a/prefs.js b/prefs.js index 7b7aab1..b7db252 100644 --- a/prefs.js +++ b/prefs.js @@ -1042,6 +1042,20 @@ const Settings = new Lang.Class({ this._builder.get_object('preview_aspect_ratio_y_fixed_togglebutton'), 'active', Gio.SettingsBindFlags.DEFAULT); + + this._settings.bind('preview-use-custom-opacity', + this._builder.get_object('preview_custom_opacity_switch'), + 'active', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('preview-use-custom-opacity', + this._builder.get_object('preview_custom_opacity_spinbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity')); + this._builder.get_object('preview_custom_opacity_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { + this._settings.set_int('preview-custom-opacity', widget.get_value()); + })); this._settings.bind('peek-mode', this._builder.get_object('peek_mode_switch'), @@ -1141,6 +1155,11 @@ const Settings = new Lang.Class({ this._settings.set_value('window-preview-animation-time', this._settings.get_default_value('window-preview-animation-time')); this._builder.get_object('animation_time_spinbutton').set_value(this._settings.get_int('window-preview-animation-time')); + this._settings.set_value('preview-use-custom-opacity', this._settings.get_default_value('preview-use-custom-opacity')); + + this._settings.set_value('preview-custom-opacity', this._settings.get_default_value('preview-custom-opacity')); + this._builder.get_object('preview_custom_opacity_spinbutton').set_value(this._settings.get_int('preview-custom-opacity')); + this._settings.set_value('peek-mode', this._settings.get_default_value('peek-mode')); this._settings.set_value('window-preview-show-title', this._settings.get_default_value('window-preview-show-title')); this._settings.set_value('enter-peek-mode-timeout', this._settings.get_default_value('enter-peek-mode-timeout')); diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index 744a500..1fa144f 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -589,6 +589,16 @@ Middle click preview to close window Middle click on the window preview to close that window + + true + Window previews use custom opacity + Window previews background use a different opacity from the panel + + + 60 + Window previews background opacity + Window previews use this custom background opacity. + 0 Tray font size diff --git a/windowPreview.js b/windowPreview.js index df308b5..e0b4dd5 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -41,12 +41,12 @@ const T3 = 'peekTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; const MIN_DIMENSION = 100; -const MIN_MENU_ALPHA = .6; const FOCUSED_COLOR_OFFSET = 24; const HEADER_COLOR_OFFSET = -12; const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; let headerHeight = 0; +let alphaBg = 0; let isLeftButtons = false; let isTopHeader = true; let scaleFactor = 1; @@ -168,12 +168,10 @@ var PreviewMenu = Utils.defineClass({ this.currentAppIcon = appIcon; if (!this.opened) { - let alpha = Math.max(MIN_MENU_ALPHA, this._panelWrapper.dynamicTransparency.alpha); - - this.menu.set_style('background: ' + Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, alpha)); - this.show(); - this._refreshGlobals(); + this.menu.set_style('background: ' + Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, alphaBg)); + + this.show(); } this._mergeWindows(appIcon); @@ -380,6 +378,12 @@ var PreviewMenu = Utils.defineClass({ size: this._dtpSettings.get_int('window-preview-aspect-ratio-y'), fixed: this._dtpSettings.get_boolean('window-preview-fixed-y') }; + + if (this._panelWrapper.dynamicTransparency) { + alphaBg = this._dtpSettings.get_boolean('preview-use-custom-opacity') ? + this._dtpSettings.get_int('preview-custom-opacity') * .01 : + this._panelWrapper.dynamicTransparency.alpha; + } }, _resetHiddenState: function() { @@ -680,7 +684,7 @@ var Preview = Utils.defineClass({ this._closeButtonBin.set_style( 'padding: ' + closeButtonPadding + 'px; ' + - this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : MIN_MENU_ALPHA) + + this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : .6) + closeButtonBorderRadius ); }, @@ -870,7 +874,7 @@ var Preview = Utils.defineClass({ alpha = Math.abs(alpha); if (isNaN(alpha)) { - alpha = Math.max(MIN_MENU_ALPHA, this._panelWrapper.dynamicTransparency.alpha); + alpha = alphaBg; } return Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, alpha, offset); From 3606cdff45185830dea679ee61bf1ee0b5280645 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 7 Jun 2019 20:02:51 -0400 Subject: [PATCH 54/61] Scroll previews using mouse pointer --- taskbar.js | 77 ++++-------------------------------------------- utils.js | 62 ++++++++++++++++++++++++++++++++++++++ windowPreview.js | 42 ++++++++++++++++---------- 3 files changed, 95 insertions(+), 86 deletions(-) diff --git a/taskbar.js b/taskbar.js index 79d25fd..de99965 100644 --- a/taskbar.js +++ b/taskbar.js @@ -41,7 +41,6 @@ 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(); @@ -567,7 +566,7 @@ var taskbar = Utils.defineClass({ appIcon.actor.connect('notify::hover', Lang.bind(this, function() { if (appIcon.actor.hover){ this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function(){ - ensureActorVisibleInScrollView(this._scrollView, appIcon.actor); + Utils.ensureActorVisibleInScrollView(this._scrollView, appIcon.actor, this._scrollView._dtpFadeSize); this._ensureAppIconVisibilityTimeoutId = 0; return GLib.SOURCE_REMOVE; })); @@ -581,11 +580,11 @@ var taskbar = Utils.defineClass({ appIcon.actor.connect('clicked', Lang.bind(this, function(actor) { - ensureActorVisibleInScrollView(this._scrollView, actor); + Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize); })); appIcon.actor.connect('key-focus-in', Lang.bind(this, function(actor) { - let [x_shift, y_shift] = ensureActorVisibleInScrollView(this._scrollView, actor); + let [x_shift, y_shift] = Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize); // 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. @@ -960,9 +959,9 @@ var taskbar = Utils.defineClass({ // Ensure the next and previous icon are visible when moving the icon // (I assume there's room for both of them) if (hoveredIndex > 1) - ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex-1]); + ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex-1], this._scrollView._dtpFadeSize); if (hoveredIndex < this._box.get_children().length-1) - ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex+1]); + ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex+1], this._scrollView._dtpFadeSize); } } @@ -1217,68 +1216,4 @@ function sortWindowsCompareFunction(windowA, windowB) { function getWindowStableSequence(window) { return ('_dtpPosition' in window ? window._dtpPosition : window.get_stable_sequence()); -} - -/* - * 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 = scrollView._dtpFadeSize; - - 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]; -} +} \ No newline at end of file diff --git a/utils.js b/utils.js index 41a458a..32f85f9 100644 --- a/utils.js +++ b/utils.js @@ -32,6 +32,8 @@ const Shell = imports.gi.Shell; const St = imports.gi.St; const Mainloop = imports.mainloop; const Main = imports.ui.main; +const Tweener = imports.ui.tweener; +const Util = imports.misc.util; var TRANSLATION_DOMAIN = imports.misc.extensionUtils.getCurrentExtension().metadata['gettext-domain']; @@ -371,6 +373,66 @@ var getrgbaColor = function(color, alpha, offset) { return 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ',' + (Math.floor(alpha * 100) * 0.01) + '); ' ; }; + +/* + * 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 +*/ +var ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize) { + 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 = fadeSize; + let hoffset = fadeSize; + + 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]; +} /** * ColorUtils is adapted from https://github.com/micheleg/dash-to-dock diff --git a/windowPreview.js b/windowPreview.js index e0b4dd5..1467d1c 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -33,10 +33,14 @@ const Me = imports.misc.extensionUtils.getCurrentExtension(); const Taskbar = Me.imports.taskbar; const Utils = Me.imports.utils; +//timeout intervals +const ENSURE_VISIBLE_MS = 200; + //timeout names const T1 = 'openMenuTimeout'; const T2 = 'closeMenuTimeout'; const T3 = 'peekTimeout'; +const T4 = 'ensureVisibleTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; @@ -69,8 +73,8 @@ var PreviewMenu = Utils.defineClass({ this.peekInitialWorkspaceIndex = -1; this.opened = false; this._position = Taskbar.getPosition(); - let isLeftOrRight = this._checkIfLeftOrRight(); - this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y'); + this.isLeftOrRight = this._position == St.Side.LEFT || this._position == St.Side.RIGHT; + this._translationProp = 'translation_' + (this.isLeftOrRight ? 'x' : 'y'); this._translationDirection = (this._position == St.Side.TOP || this._position == St.Side.LEFT ? -1 : 1); this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), MAX_TRANSLATION) * this._translationDirection; @@ -82,14 +86,12 @@ var PreviewMenu = Utils.defineClass({ y_expand: true, y_align: Clutter.ActorAlign[this._translationDirection > 0 ? 'END' : 'START'] }); - this._box = new St.BoxLayout({ vertical: isLeftOrRight }); + this._box = new St.BoxLayout({ vertical: this.isLeftOrRight }); this._scrollView = new St.ScrollView({ name: 'dashtopanelPreviewScrollview', hscrollbar_policy: Gtk.PolicyType.NEVER, vscrollbar_policy: Gtk.PolicyType.NEVER, - enable_mouse_scrolling: true, - y_expand: !isLeftOrRight, - x_expand: isLeftOrRight + enable_mouse_scrolling: true }); this._scrollView.add_actor(this._box); @@ -251,6 +253,18 @@ var PreviewMenu = Utils.defineClass({ this._endPeek(true); }, + ensureVisible: function(preview) { + let [ , , upper, , , pageSize] = this._scrollView[this.isLeftOrRight ? 'v' : 'h' + 'scroll'].adjustment.get_values(); + + if (upper > pageSize) { + this._timeoutsHandler.add([ + T4, + ENSURE_VISIBLE_MS, + () => Utils.ensureActorVisibleInScrollView(this._scrollView, preview, MIN_DIMENSION) + ]); + } + }, + _setReactive: function(reactive) {  this._box.get_children().forEach(c => c.reactive = reactive); this.menu.reactive = reactive; @@ -337,7 +351,7 @@ var PreviewMenu = Utils.defineClass({ _onScrollEvent: function(actor, event) { if (!event.is_pointer_emulated()) { - let vOrh = this._checkIfLeftOrRight() ? 'v' : 'h'; + let vOrh = this.isLeftOrRight ? 'v' : 'h'; let adjustment = this._scrollView['get_' + vOrh + 'scroll_bar']().get_adjustment(); let increment = adjustment.step_increment; let delta = increment; @@ -362,6 +376,7 @@ var PreviewMenu = Utils.defineClass({ _endOpenCloseTimeouts: function() { this._timeoutsHandler.remove(T1); this._timeoutsHandler.remove(T2); + this._timeoutsHandler.remove(T4); }, _refreshGlobals: function() { @@ -401,7 +416,7 @@ var PreviewMenu = Utils.defineClass({ let previewSize = (this._dtpSettings.get_int('window-preview-size') + this._dtpSettings.get_int('window-preview-padding') * 2) * scaleFactor; - if (this._checkIfLeftOrRight()) { + if (this.isLeftOrRight) { w = previewSize; h = this._panelWrapper.monitor.height; y = this._panelWrapper.monitor.y; @@ -437,7 +452,7 @@ var PreviewMenu = Utils.defineClass({ previewsWidth = Math.min(previewsWidth, this._panelWrapper.monitor.width); previewsHeight = Math.min(previewsHeight, this._panelWrapper.monitor.height) + headerHeight; - if (this._checkIfLeftOrRight()) { + if (this.isLeftOrRight) { y = sourceAllocation.y1 + appIconMargin - this._panelWrapper.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; y = Math.max(y, 0); y = Math.min(y, this._panelWrapper.monitor.height - previewsHeight); @@ -463,7 +478,7 @@ var PreviewMenu = Utils.defineClass({ if (!c.animatingOut) { let [width, height] = c.getSize(); - if (this._checkIfLeftOrRight()) { + if (this.isLeftOrRight) { previewsWidth = Math.max(width, previewsWidth); previewsHeight += height; } else { @@ -495,10 +510,6 @@ var PreviewMenu = Utils.defineClass({ Tweener.addTween(this.menu, getTweenOpts(tweenOpts)); }, - _checkIfLeftOrRight: function() { - return this._position == St.Side.LEFT || this._position == St.Side.RIGHT; - }, - _peek: function(window) { let currentWorkspace = Utils.getCurrentWorkspace(); let windowWorkspace = window.get_workspace(); @@ -746,6 +757,7 @@ var Preview = Utils.defineClass({ this.set_style(this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0)); if (focused) { + this._previewMenu.ensureVisible(this); this._previewMenu.requestPeek(this.window); } }, @@ -954,7 +966,7 @@ var Preview = Utils.defineClass({ let size = this._previewMenu._dtpSettings.get_int('window-preview-size') * scaleFactor; let w, h; - if (this._previewMenu._checkIfLeftOrRight()) { + if (this._previewMenu.isLeftOrRight) { w = size; h = w * aspectRatio.y.size / aspectRatio.x.size; } else { From 19d2bc95cbf9a7e23e5df58074a25352fbf234df Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sat, 8 Jun 2019 21:37:37 -0400 Subject: [PATCH 55/61] Remove CSD transparent padding around GTK windows --- windowPreview.js | 74 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index 1467d1c..411a651 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -91,7 +91,9 @@ var PreviewMenu = Utils.defineClass({ name: 'dashtopanelPreviewScrollview', hscrollbar_policy: Gtk.PolicyType.NEVER, vscrollbar_policy: Gtk.PolicyType.NEVER, - enable_mouse_scrolling: true + enable_mouse_scrolling: true, + y_expand: !this.isLeftOrRight, + x_expand: this.isLeftOrRight }); this._scrollView.add_actor(this._box); @@ -325,7 +327,7 @@ var PreviewMenu = Utils.defineClass({ }, _addNewPreview: function(window) { - let preview = new Preview(this._panelWrapper, this); + let preview = new Preview(this); this._box.add_child(preview); preview.adjustOnStage(); @@ -604,7 +606,7 @@ var Preview = Utils.defineClass({ Name: 'DashToPanel-Preview', Extends: St.Widget, - _init: function(panelWrapper, previewMenu) { + _init: function(previewMenu) { this.callParent('_init', { style_class: 'preview-container', reactive: true, @@ -615,7 +617,7 @@ var Preview = Utils.defineClass({ this.window = null; this._needsCloseButton = true; this.cloneWidth = this.cloneHeight = 0; - this._panelWrapper = panelWrapper; + this._panelWrapper = previewMenu._panelWrapper; this._previewMenu = previewMenu; this._padding = previewMenu._dtpSettings.get_int('window-preview-padding') * scaleFactor; this._previewDimensions = this._getPreviewDimensions(); @@ -706,7 +708,7 @@ var Preview = Utils.defineClass({ if (window.get_compositor_private()) { let cloneBin = this._getWindowCloneBin(window); - this._resizeClone(cloneBin); + this._resizeClone(cloneBin, window); this._addClone(cloneBin, animateSize); this._previewMenu.updatePosition(); } else { @@ -929,12 +931,17 @@ var Preview = Utils.defineClass({ }, _getWindowCloneBin: function(window) { - return new St.Bin({ - child: new Clutter.Clone({ source: window.get_compositor_private() }), - y_align: Clutter.ActorAlign.CENTER, - x_align: Clutter.ActorAlign.CENTER, + let clone = new Clutter.Clone({ source: window.get_compositor_private() }); + let cloneBin = new St.Widget({ opacity: 0, + layout_manager: window.is_client_decorated() ? + new WindowCloneLayout(window) : + new Clutter.BinLayout() }); + + cloneBin.add_child(clone); + + return cloneBin; }, _getBinSize: function() { @@ -946,20 +953,27 @@ var Preview = Utils.defineClass({ ]; }, - _resizeClone: function(cloneBin) { - let [width, height] = cloneBin.child.get_source().get_size(); + _resizeClone: function(cloneBin, window) { + let frameRect = window.get_frame_rect(); let [fixedWidth, fixedHeight] = this._previewDimensions; - let ratio = Math.min(fixedWidth / width, fixedHeight / height, 1); - let cloneWidth = Math.floor(width * ratio); - let cloneHeight = Math.floor(height * ratio); + let ratio = Math.min(fixedWidth / frameRect.width, fixedHeight / frameRect.height, 1); + let cloneWidth = frameRect.width * ratio; + let cloneHeight = frameRect.height * ratio; + let clonePaddingTB = cloneHeight < MIN_DIMENSION ? MIN_DIMENSION - cloneHeight : 0; let clonePaddingLR = cloneWidth < MIN_DIMENSION ? MIN_DIMENSION - cloneWidth : 0; + let clonePaddingTop = clonePaddingTB * .5; + let clonePaddingLeft = clonePaddingLR * .5; this.cloneWidth = cloneWidth + clonePaddingLR * scaleFactor; this.cloneHeight = cloneHeight + clonePaddingTB * scaleFactor; - cloneBin.set_style('padding: ' + Math.floor(clonePaddingTB * .5) + 'px ' + Math.floor(clonePaddingLR * .5) + 'px;'); - cloneBin.child.set_size(cloneWidth, cloneHeight); + cloneBin.set_style('padding: ' + clonePaddingTop + 'px ' + clonePaddingLeft + 'px;'); + cloneBin.layout_manager.ratio = ratio; + cloneBin.layout_manager.padding = [clonePaddingLeft * scaleFactor, clonePaddingTop * scaleFactor]; + cloneBin.layout_manager.frameRect = frameRect; + + cloneBin.get_first_child().set_size(cloneWidth, cloneHeight); }, _getPreviewDimensions: function() { @@ -978,6 +992,34 @@ var Preview = Utils.defineClass({ } }); +var WindowCloneLayout = Utils.defineClass({ + Name: 'DashToPanel-WindowCloneLayout', + Extends: Clutter.BinLayout, + + _init: function(window) { + this.callParent('_init'); + + //the buffer_rect contains the CSD transparent padding that must be removed + this.bufferRect = window.get_buffer_rect(); + }, + + vfunc_allocate: function(actor, box, flags) { + let [width, height] = box.get_size(); + + box.set_origin( + (this.bufferRect.x - this.frameRect.x) * this.ratio + this.padding[0], + (this.bufferRect.y - this.frameRect.y) * this.ratio + this.padding[1] + ); + + box.set_size( + width + (this.bufferRect.width - this.frameRect.width) * this.ratio, + height + (this.bufferRect.height - this.frameRect.height) * this.ratio + ); + + actor.get_first_child().allocate(box, flags); + } +}); + function getTweenOpts(opts) { let defaults = { time: animationTime, From f26e092d047be400b143285557ba0ab490b5cac2 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sun, 9 Jun 2019 21:54:30 -0400 Subject: [PATCH 56/61] Add custom scrollview fade for previews --- stylesheet.css | 5 ---- utils.js | 18 ++++++------- windowPreview.js | 70 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 75 insertions(+), 18 deletions(-) diff --git a/stylesheet.css b/stylesheet.css index cec49e6..6cbbf6a 100644 --- a/stylesheet.css +++ b/stylesheet.css @@ -41,11 +41,6 @@ padding-right: 8px; } -#dashtopanelPreviewScrollview { - -st-hfade-offset: 24px; - /* -st-vfade-offset: 24px; */ -} - #dashtopanelScrollview .app-well-app:hover .overview-icon, #dashtopanelScrollview .app-well-app:focus .overview-icon { background: none; diff --git a/utils.js b/utils.js index 32f85f9..6441d17 100644 --- a/utils.js +++ b/utils.js @@ -380,7 +380,7 @@ var getrgbaColor = function(color, alpha, offset) { * it would be clamp to the current one in any case. * Return the amount of shift applied */ -var ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize) { +var ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize, onComplete) { let vadjustment = scrollView.vscroll.adjustment; let hadjustment = scrollView.hscroll.adjustment; let [vvalue, vlower, vupper, vstepIncrement, vpageIncrement, vpageSize] = vadjustment.get_values(); @@ -417,18 +417,18 @@ var ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize) { else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset) hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize); + let tweenOpts = { + time: Util.SCROLL_TIME, + onComplete: onComplete || (() => {}), + transition: 'easeOutQuad' + }; + if (vvalue !== vvalue0) { - Tweener.addTween(vadjustment, - { value: vvalue, - time: Util.SCROLL_TIME, - transition: 'easeOutQuad' }); + Tweener.addTween(vadjustment, mergeObjects(tweenOpts, { value: vvalue })); } if (hvalue !== hvalue0) { - Tweener.addTween(hadjustment, - { value: hvalue, - time: Util.SCROLL_TIME, - transition: 'easeOutQuad' }); + Tweener.addTween(hadjustment, mergeObjects(tweenOpts, { value: hvalue })); } return [hvalue- hvalue0, vvalue - vvalue0]; diff --git a/windowPreview.js b/windowPreview.js index 411a651..f491a99 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -47,6 +47,7 @@ const HEADER_HEIGHT = 38; const MIN_DIMENSION = 100; const FOCUSED_COLOR_OFFSET = 24; const HEADER_COLOR_OFFSET = -12; +const FADE_SIZE = 36; const PEEK_INDEX_PROP = '_dtpPeekInitialIndex'; let headerHeight = 0; @@ -256,13 +257,13 @@ var PreviewMenu = Utils.defineClass({ }, ensureVisible: function(preview) { - let [ , , upper, , , pageSize] = this._scrollView[this.isLeftOrRight ? 'v' : 'h' + 'scroll'].adjustment.get_values(); + let [ , upper, pageSize] = this._getScrollAdjustmentValues(); if (upper > pageSize) { this._timeoutsHandler.add([ T4, ENSURE_VISIBLE_MS, - () => Utils.ensureActorVisibleInScrollView(this._scrollView, preview, MIN_DIMENSION) + () => Utils.ensureActorVisibleInScrollView(this._scrollView, preview, MIN_DIMENSION, () => this._updateScrollFade()) ]); } }, @@ -370,6 +371,7 @@ var PreviewMenu = Utils.defineClass({ } adjustment.set_value(adjustment.get_value() + delta); + this._updateScrollFade(); } return Clutter.EVENT_STOP; @@ -452,7 +454,8 @@ var PreviewMenu = Utils.defineClass({ let x = 0, y = 0; previewsWidth = Math.min(previewsWidth, this._panelWrapper.monitor.width); - previewsHeight = Math.min(previewsHeight, this._panelWrapper.monitor.height) + headerHeight; + previewsHeight = Math.min(previewsHeight, this._panelWrapper.monitor.height); + this._updateScrollFade(previewsWidth < this._panelWrapper.monitor.width && previewsHeight < this._panelWrapper.monitor.height); if (this.isLeftOrRight) { y = sourceAllocation.y1 + appIconMargin - this._panelWrapper.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5; @@ -472,6 +475,65 @@ var PreviewMenu = Utils.defineClass({ } }, + _updateScrollFade: function(remove) { + let [value, upper, pageSize] = this._getScrollAdjustmentValues(); + let needsFade = upper > pageSize; + let fadeWidgets = this.menu.get_children().filter(c => c != this._scrollView); + + if (!remove && needsFade) { + if (!fadeWidgets.length) { + fadeWidgets.push(this._getFadeWidget()); + fadeWidgets.push(this._getFadeWidget(true)); + + this.menu.add_child(fadeWidgets[0]); + this.menu.add_child(fadeWidgets[1]); + } + + fadeWidgets[0].visible = value > 0; + fadeWidgets[1].visible = value + pageSize < upper; + } else if (remove || (!needsFade && fadeWidgets.length)) { + fadeWidgets.forEach(fw => fw.destroy()); + } + }, + + _getScrollAdjustmentValues: function() { + let [value , , upper, , , pageSize] = this._scrollView[this.isLeftOrRight ? 'v' : 'h' + 'scroll'].adjustment.get_values(); + + return [value, upper, pageSize]; + }, + + _getFadeWidget: function(end) { + let rotation = 0; + let size = 0; + let x = 0, y = 0; + let startBg = Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, Math.min(alphaBg + .1, 1)); + let endBg = Utils.getrgbaColor(this._panelWrapper.dynamicTransparency.backgroundColorRgb, 0) + let fadeStyle = 'background-gradient-start:' + startBg + 'background-gradient-end: ' + endBg + ' background-gradient-direction:'; + + if (this.isLeftOrRight) { + fadeStyle += 'vertical;' + rotation = end ? 270 : 90; + y = end ? this._panelWrapper.monitor.height - FADE_SIZE : 0; + size = this.width; + } else { + fadeStyle += 'horizontal;' + rotation = end ? 180 : 0; + x = end ? this._panelWrapper.monitor.width - FADE_SIZE : 0; + size = this.height; + } + + let fadeWidget = new St.Widget({ + reactive: false, + pivot_point: new Clutter.Point({ x: .5, y: .5 }), + rotation_angle_z: rotation, + style: fadeStyle, + x: x, y: y, + width: FADE_SIZE, height: size + }); + + return fadeWidget; + }, + _getPreviewsSize: function() { let previewsWidth = 0; let previewsHeight = 0; @@ -749,7 +811,7 @@ var Preview = Utils.defineClass({ let [binWidth, binHeight] = this._getBinSize(); binWidth = Math.max(binWidth, this.cloneWidth + this._padding * 2); - binHeight = Math.max(binHeight, this.cloneHeight + this._padding * 2); + binHeight = Math.max(binHeight, this.cloneHeight + this._padding * 2) + headerHeight; return [binWidth, binHeight]; }, From 3e3c89ee722a88497718bd4ef29075af3ec1b773 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Mon, 10 Jun 2019 06:40:47 -0400 Subject: [PATCH 57/61] Remove empty space around Qt windows --- windowPreview.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index f491a99..2a4d580 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -993,11 +993,14 @@ var Preview = Utils.defineClass({ }, _getWindowCloneBin: function(window) { + let frameRect = window.get_frame_rect(); + let bufferRect = window.get_buffer_rect(); let clone = new Clutter.Clone({ source: window.get_compositor_private() }); let cloneBin = new St.Widget({ opacity: 0, - layout_manager: window.is_client_decorated() ? - new WindowCloneLayout(window) : + layout_manager: frameRect.width != bufferRect.width || + frameRect.height != bufferRect.height ? + new WindowCloneLayout(frameRect, bufferRect) : new Clutter.BinLayout() }); @@ -1016,7 +1019,7 @@ var Preview = Utils.defineClass({ }, _resizeClone: function(cloneBin, window) { - let frameRect = window.get_frame_rect(); + let frameRect = cloneBin.layout_manager.frameRect || window.get_frame_rect(); let [fixedWidth, fixedHeight] = this._previewDimensions; let ratio = Math.min(fixedWidth / frameRect.width, fixedHeight / frameRect.height, 1); let cloneWidth = frameRect.width * ratio; @@ -1033,7 +1036,6 @@ var Preview = Utils.defineClass({ cloneBin.set_style('padding: ' + clonePaddingTop + 'px ' + clonePaddingLeft + 'px;'); cloneBin.layout_manager.ratio = ratio; cloneBin.layout_manager.padding = [clonePaddingLeft * scaleFactor, clonePaddingTop * scaleFactor]; - cloneBin.layout_manager.frameRect = frameRect; cloneBin.get_first_child().set_size(cloneWidth, cloneHeight); }, @@ -1058,11 +1060,12 @@ var WindowCloneLayout = Utils.defineClass({ Name: 'DashToPanel-WindowCloneLayout', Extends: Clutter.BinLayout, - _init: function(window) { + _init: function(frameRect, bufferRect) { this.callParent('_init'); - //the buffer_rect contains the CSD transparent padding that must be removed - this.bufferRect = window.get_buffer_rect(); + //the buffer_rect contains the transparent padding that must be removed + this.frameRect = frameRect; + this.bufferRect = bufferRect; }, vfunc_allocate: function(actor, box, flags) { From 52006368ea9b3458a6e0abd3658c61768546f122 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 20 Jun 2019 23:20:56 -0400 Subject: [PATCH 58/61] Add maximum size for the preview close button --- windowPreview.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/windowPreview.js b/windowPreview.js index 2a4d580..e842166 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -44,6 +44,7 @@ const T4 = 'ensureVisibleTimeout'; const MAX_TRANSLATION = 40; const HEADER_HEIGHT = 38; +const MAX_CLOSE_BUTTON_SIZE = 30; const MIN_DIMENSION = 100; const FOCUSED_COLOR_OFFSET = 24; const HEADER_COLOR_OFFSET = -12; @@ -744,9 +745,15 @@ var Preview = Utils.defineClass({ }, adjustOnStage: function() { + let closeButton = this._closeButtonBin.get_first_child(); let closeButtonPadding = headerHeight ? Math.round((headerHeight - this._closeButtonBin.height) * .5 / scaleFactor) : 4; let closeButtonBorderRadius = ''; + if (closeButton.height > MAX_CLOSE_BUTTON_SIZE) { + closeButton.set_size(MAX_CLOSE_BUTTON_SIZE, MAX_CLOSE_BUTTON_SIZE); + closeButtonPadding = 4; + } + if (!headerHeight) { closeButtonBorderRadius = 'border-radius: '; @@ -757,8 +764,9 @@ var Preview = Utils.defineClass({ } } + closeButton.set_style('padding: ' + Math.max(closeButtonPadding, 0) + 'px;'); + this._closeButtonBin.set_style( - 'padding: ' + closeButtonPadding + 'px; ' + this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : .6) + closeButtonBorderRadius ); From 22b7e80b8e88e8ada6a4f8199d2633d4a9ee22d6 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Thu, 20 Jun 2019 23:25:03 -0400 Subject: [PATCH 59/61] Tweak default window preview background opacity --- schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml index 1fa144f..fe51f6f 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -595,7 +595,7 @@ Window previews background use a different opacity from the panel - 60 + 80 Window previews background opacity Window previews use this custom background opacity. From f3cf8b39161df147516de258c4ab5d9fae2da189 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Fri, 21 Jun 2019 00:02:11 -0400 Subject: [PATCH 60/61] Remove clickable padding from preview close button --- windowPreview.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index e842166..b2d93f3 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -764,9 +764,8 @@ var Preview = Utils.defineClass({ } } - closeButton.set_style('padding: ' + Math.max(closeButtonPadding, 0) + 'px;'); - this._closeButtonBin.set_style( + 'padding: ' + Math.max(closeButtonPadding, 0) + 'px; ' + this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : .6) + closeButtonBorderRadius ); From 599ce409d18713fa1be6f0ca1882ca11f57c4f4e Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Sat, 22 Jun 2019 17:44:18 -0400 Subject: [PATCH 61/61] Use constant to determine close button padding --- windowPreview.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/windowPreview.js b/windowPreview.js index b2d93f3..ce42944 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -746,12 +746,12 @@ var Preview = Utils.defineClass({ adjustOnStage: function() { let closeButton = this._closeButtonBin.get_first_child(); - let closeButtonPadding = headerHeight ? Math.round((headerHeight - this._closeButtonBin.height) * .5 / scaleFactor) : 4; + let closeButtonHeight = closeButton.height; let closeButtonBorderRadius = ''; if (closeButton.height > MAX_CLOSE_BUTTON_SIZE) { - closeButton.set_size(MAX_CLOSE_BUTTON_SIZE, MAX_CLOSE_BUTTON_SIZE); - closeButtonPadding = 4; + closeButtonHeight = MAX_CLOSE_BUTTON_SIZE; + closeButton.set_size(closeButtonHeight, closeButtonHeight); } if (!headerHeight) { @@ -765,7 +765,7 @@ var Preview = Utils.defineClass({ } this._closeButtonBin.set_style( - 'padding: ' + Math.max(closeButtonPadding, 0) + 'px; ' + + 'padding: ' + (headerHeight ? Math.round((headerHeight - closeButtonHeight) * .5 / scaleFactor) : 4) + 'px;' + this._getBackgroundColor(HEADER_COLOR_OFFSET, headerHeight ? 1 : .6) + closeButtonBorderRadius );