From e3435275bb20f61ff654da49540474ce4c540c33 Mon Sep 17 00:00:00 2001 From: jderose9 Date: Mon, 6 Feb 2017 18:03:42 -0500 Subject: [PATCH 1/3] Delay window previews on hover for #26 --- Settings.ui | 33 +++++++++++++++++++ prefs.js | 12 ++++++- ...shell.extensions.dash-to-panel.gschema.xml | 5 +++ taskbar.js | 29 ++++++++++++++-- windowPreview.js | 9 ++++- 5 files changed, 83 insertions(+), 5 deletions(-) diff --git a/Settings.ui b/Settings.ui index 1b12929..ca59390 100644 --- a/Settings.ui +++ b/Settings.ui @@ -364,6 +364,11 @@ 0.01 0.10000000000000001 + + 9999 + 25 + 100 + 0.33000000000000002 1 @@ -957,6 +962,34 @@ 0 + + + True + True + 4 + 0 + preview_timeout_adjustment + True + + + 1 + 1 + + + + + True + False + True + Time before showing (ms) + True + 0 + + + 0 + 1 + + diff --git a/prefs.js b/prefs.js index 7986701..a4104a3 100644 --- a/prefs.js +++ b/prefs.js @@ -155,6 +155,16 @@ const Settings = new Lang.Class({ this._builder.get_object('show_window_previews_switch'), 'active', Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('show-window-previews', + this._builder.get_object('preview_timeout_spinbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + + 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) { + this._settings.set_int('show-window-previews-timeout', widget.get_value()); + })); + this._settings.bind('isolate-workspaces', this._builder.get_object('isolate_workspaces_switch'), 'active', @@ -249,7 +259,7 @@ const Settings = new Lang.Class({ this._builder.get_object('leave_timeout_spinbutton').set_value(this._settings.get_int('leave-timeout')); - this._builder.get_object('leave_timeout_spinbutton').connect('changed', Lang.bind (this, function(widget) { + this._builder.get_object('leave_timeout_spinbutton').connect('value-changed', Lang.bind (this, function(widget) { this._settings.set_int('leave-timeout', widget.get_value()); })); 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 bfd42db..800b5e7 100644 --- a/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml +++ b/schemas/org.gnome.shell.extensions.dash-to-panel.gschema.xml @@ -69,6 +69,11 @@ Show window preview Show preview of running window on hover of app icon + + 100 + Icon enter display time + Amount of time after entering icon to wait before displaying window preview if icon is not clicked or mouse has not left. + false Provide workspace isolation diff --git a/taskbar.js b/taskbar.js index cbfc756..7b90164 100644 --- a/taskbar.js +++ b/taskbar.js @@ -1226,14 +1226,37 @@ const taskbarAppIcon = new Lang.Class({ // 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.menuManagerWindowPreview = new PopupMenu.PopupMenuManager(this); + + this.windowPreview = new WindowPreview.thumbnailPreviewMenu(this, this._dtpSettings, this.menuManagerWindowPreview); - this.windowPreview = new WindowPreview.thumbnailPreviewMenu(this, this._dtpSettings); this.windowPreview.connect('open-state-changed', Lang.bind(this, function (menu, isPoppedUp) { if (!isPoppedUp) this._onMenuPoppedDown(); })); - this._menuManagerWindowPreview.addMenu(this.windowPreview); + 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 (for example, clicking the icon as the preview window is opening) + // So, instead I'll issue the grab when the preview menu is actually entered. + // Alternatively, I was able to solve this by waiting a 100ms timeout to ensure the menu was + // still open, but this waiting until the menu is entered seems a bit safer if it doesn't cause other issues + 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); + + // Mainloop.timeout_add(100, Lang.bind(this, function() { + // if(menu.isOpen) + // this._grabHelper.grab({ actor: menu.actor, focus: menu.sourceActor, onUngrab: Lang.bind(this, this._closeMenu, menu) }); + // })); + } else { + this._grabHelper.ungrab({ actor: menu.actor }); + } + })); this.forcedOverview = false; }, diff --git a/windowPreview.js b/windowPreview.js index 87b34f2..cba438a 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -110,6 +110,13 @@ const thumbnailPreviewMenu = new Lang.Class({ this.shouldOpen = true; this.shouldClose = false; + // This grab is usually called when the menu is opened. However, there seems to be a bug in the + // underlying gnome-shell that causes the window contents to freeze if the grab and ungrab occur + // in quick succession (for example, clicking the icon as the preview window is opening) + // So, instead I'll issue the grab when the preview menu is actually entered. + this._source.menuManagerWindowPreview._grabHelper.grab({ actor: this.actor, focus: this.sourceActor, + onUngrab: Lang.bind(this, this.requestCloseMenu) }); + this.hoverOpen(); }, @@ -123,7 +130,7 @@ const thumbnailPreviewMenu = new Lang.Class({ this.shouldOpen = true; this.shouldClose = false; - this.hoverOpen(); + Mainloop.timeout_add(this._dtpSettings.get_int('show-window-previews-timeout'), Lang.bind(this, this.hoverOpen)); }, _onLeave: function () { From ccee4464ec2950dc6bedb7c738cdec7adea9962a Mon Sep 17 00:00:00 2001 From: jderose9 Date: Mon, 6 Feb 2017 22:23:24 -0500 Subject: [PATCH 2/3] Cancel timers rather than using flags Previously using flags in the event handlers to decide whether they should handle the timeout event, rather than just cancelling the timeout. --- Settings.ui | 2 +- taskbar.js | 2 -- windowPreview.js | 51 +++++++++++++++++++++++++++++++----------------- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/Settings.ui b/Settings.ui index ca59390..5d9dec7 100644 --- a/Settings.ui +++ b/Settings.ui @@ -305,7 +305,7 @@ 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 taskbar may feel slow to highlight applications. + 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 diff --git a/taskbar.js b/taskbar.js index 7b90164..b264795 100644 --- a/taskbar.js +++ b/taskbar.js @@ -1368,7 +1368,6 @@ const taskbarAppIcon = new Lang.Class({ this.emit('menu-state-changed', true); - this.windowPreview.shouldOpen = false; this.windowPreview.close(); this.actor.set_hover(true); @@ -1413,7 +1412,6 @@ const taskbarAppIcon = new Lang.Class({ }, activate: function(button) { - this.windowPreview.shouldOpen = false; this.windowPreview.requestCloseMenu(); let event = Clutter.get_current_event(); diff --git a/windowPreview.js b/windowPreview.js index cba438a..b836745 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -56,8 +56,6 @@ const thumbnailPreviewMenu = new Lang.Class({ this._source = source; this._app = this._source.app; - this.shouldOpen = true; - this.shouldClose = false; this.actor.add_style_class_name('app-well-menu'); this.actor.set_style("max-width: " + (Main.layoutManager.primaryMonitor.width - 22) + "px;"); @@ -107,8 +105,7 @@ const thumbnailPreviewMenu = new Lang.Class({ }, _onMenuEnter: function () { - this.shouldOpen = true; - this.shouldClose = false; + this.cancelClose(); // This grab is usually called when the menu is opened. However, there seems to be a bug in the // underlying gnome-shell that causes the window contents to freeze if the grab and ungrab occur @@ -121,35 +118,51 @@ const thumbnailPreviewMenu = new Lang.Class({ }, _onMenuLeave: function () { - this.shouldOpen = false; - this.shouldClose = true; - Mainloop.timeout_add(Taskbar.DASH_ITEM_HOVER_TIMEOUT, Lang.bind(this, this.hoverClose)); + this.cancelOpen(); + this.cancelClose(); + + this._hoverCloseTimeoutId = Mainloop.timeout_add(Taskbar.DASH_ITEM_HOVER_TIMEOUT, Lang.bind(this, this.hoverClose)); }, _onEnter: function () { - this.shouldOpen = true; - this.shouldClose = false; + this.cancelOpen(); + this.cancelClose(); - Mainloop.timeout_add(this._dtpSettings.get_int('show-window-previews-timeout'), Lang.bind(this, this.hoverOpen)); + this._hoverOpenTimeoutId = Mainloop.timeout_add(this._dtpSettings.get_int('show-window-previews-timeout'), Lang.bind(this, this.hoverOpen)); }, _onLeave: function () { - this.shouldClose = true; - this.shouldOpen = false; + this.cancelOpen(); + this.cancelClose(); - Mainloop.timeout_add(this._dtpSettings.get_int('leave-timeout'), Lang.bind(this, this.hoverClose)); + 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); + log("cancelled open"); + this._hoverOpenTimeoutId = null; + } + }, + + cancelClose: function () { + if(this._hoverCloseTimeoutId) { + Mainloop.source_remove(this._hoverCloseTimeoutId); + log("cancelled close"); + this._hoverCloseTimeoutId = null; + } }, hoverOpen: function () { - if (this.shouldOpen && !this.isOpen && this._dtpSettings.get_boolean("show-window-previews")) { + this._hoverOpenTimeoutId = null; + if (!this.isOpen && this._dtpSettings.get_boolean("show-window-previews")) this.popup(); - } }, hoverClose: function () { - if (this.shouldClose) { - this.close(~0); - } + this._hoverCloseTimeoutId = null; + this.close(~0); }, destroy: function () { @@ -173,6 +186,8 @@ const thumbnailPreviewMenu = new Lang.Class({ }, close: function(animate) { + this.cancelOpen(); + if (this.isOpen) this.emit('open-state-changed', false); if (this._activeMenuItem) From f2e159dcf0caa5101386d58bd0ccf0de78e5fa0b Mon Sep 17 00:00:00 2001 From: jderose9 Date: Mon, 6 Feb 2017 22:42:22 -0500 Subject: [PATCH 3/3] Clean up the settings UI for preview delay. Closes #26 --- Settings.ui | 6 +++++- prefs.js | 10 +++++++--- windowPreview.js | 2 -- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/Settings.ui b/Settings.ui index 5d9dec7..8bcdf75 100644 --- a/Settings.ui +++ b/Settings.ui @@ -811,14 +811,17 @@ True True False + 12 3 0 0.5 True + 4 True False + 4 Animate <i>Show Applications</i>. True @@ -980,8 +983,9 @@ True False + 12 True - Time before showing (ms) + Time (ms) before showing (100 is default) True 0 diff --git a/prefs.js b/prefs.js index a4104a3..77bc76f 100644 --- a/prefs.js +++ b/prefs.js @@ -156,9 +156,13 @@ const Settings = new Lang.Class({ 'active', Gio.SettingsBindFlags.DEFAULT); this._settings.bind('show-window-previews', - this._builder.get_object('preview_timeout_spinbutton'), - 'sensitive', - Gio.SettingsBindFlags.DEFAULT); + this._builder.get_object('preview_timeout_spinbutton'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); + this._settings.bind('show-window-previews', + this._builder.get_object('preview_timeout_label'), + 'sensitive', + Gio.SettingsBindFlags.DEFAULT); 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) { diff --git a/windowPreview.js b/windowPreview.js index b836745..79eb0a6 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -141,7 +141,6 @@ const thumbnailPreviewMenu = new Lang.Class({ cancelOpen: function () { if(this._hoverOpenTimeoutId) { Mainloop.source_remove(this._hoverOpenTimeoutId); - log("cancelled open"); this._hoverOpenTimeoutId = null; } }, @@ -149,7 +148,6 @@ const thumbnailPreviewMenu = new Lang.Class({ cancelClose: function () { if(this._hoverCloseTimeoutId) { Mainloop.source_remove(this._hoverCloseTimeoutId); - log("cancelled close"); this._hoverCloseTimeoutId = null; } },