From d93b51e1354460be0ef9670013f7f06527af5f3c Mon Sep 17 00:00:00 2001 From: Georges Basile Stavracas Neto Date: Thu, 25 Jun 2020 16:51:30 -0300 Subject: [PATCH] appDisplay: Use a drag monitor to check for out-of-dialog drags When the app folder dialog handles a drag hover, it starts a timeout to popdown if dragging outside the "real" dialog area. However, when dragging inside it, BaseAppView handles all drag hover events which would disarm the popdown timeout. In cases like this, it's almost impossible to prevent the timeout from triggering, which always pops down the dialog. Add a drag monitor when handling any drag hover (which only happens when dragging outside the folder's icon grid); and eventually disarm the popdown timeout from the monitor's motion event. Remove the drag monitor when dragging over the folder dialog again. https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1284 --- js/ui/appDisplay.js | 67 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index 44c4f3f5f..fdbfef677 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -2011,6 +2011,7 @@ var AppFolderDialog = GObject.registerClass({ this._grabHelper.addActor(Main.layoutManager.overviewGroup); this.connect('destroy', this._onDestroy.bind(this)); + this._dragMonitor = null; this._sourceMappedId = 0; this._popdownTimeoutId = 0; this._needsZoomAndFade = false; @@ -2224,6 +2225,22 @@ var AppFolderDialog = GObject.registerClass({ this._needsZoomAndFade = false; } + _removeDragMonitor() { + if (!this._dragMonitor) + return; + + DND.removeDragMonitor(this._dragMonitor); + this._dragMonitor = null; + } + + _removePopdownTimeout() { + if (this._popdownTimeoutId === 0) + return; + + GLib.source_remove(this._popdownTimeoutId); + this._popdownTimeoutId = 0; + } + _onDestroy() { if (this._isOpen) { this._isOpen = false; @@ -2236,10 +2253,8 @@ var AppFolderDialog = GObject.registerClass({ this._sourceMappedId = 0; } - if (this._popdownTimeoutId > 0) { - GLib.source_remove(this._popdownTimeoutId); - this._popdownTimeoutId = 0; - } + this._removePopdownTimeout(); + this._removeDragMonitor(); } vfunc_allocate(box) { @@ -2306,19 +2321,41 @@ var AppFolderDialog = GObject.registerClass({ y < childAllocation.y2; } + _setupDragMonitor() { + if (this._dragMonitor) + return; + + this._dragMonitor = { + dragMotion: dragEvent => { + if (this._withinDialog(dragEvent.x, dragEvent.y)) { + this._removePopdownTimeout(); + this._removeDragMonitor(); + } + return DND.DragMotionResult.CONTINUE; + }, + }; + DND.addDragMonitor(this._dragMonitor); + } + + _setupPopdownTimeout() { + if (this._popdownTimeoutId > 0) + return; + + this._popdownTimeoutId = + GLib.timeout_add(GLib.PRIORITY_DEFAULT, POPDOWN_DIALOG_TIMEOUT, () => { + this._popdownTimeoutId = 0; + this.popdown(); + return GLib.SOURCE_REMOVE; + }); + } + handleDragOver(source, actor, x, y) { if (this._withinDialog(x, y)) { - if (this._popdownTimeoutId > 0) { - GLib.source_remove(this._popdownTimeoutId); - this._popdownTimeoutId = 0; - } - } else if (this._popdownTimeoutId === 0) { - this._popdownTimeoutId = - GLib.timeout_add(GLib.PRIORITY_DEFAULT, POPDOWN_DIALOG_TIMEOUT, () => { - this._popdownTimeoutId = 0; - this.popdown(); - return GLib.SOURCE_REMOVE; - }); + this._removePopdownTimeout(); + this._removeDragMonitor(); + } else { + this._setupPopdownTimeout(); + this._setupDragMonitor(); } return DND.DragMotionResult.NO_DROP;