diff options
Diffstat (limited to '0001-desktop-icons-Fix-stuck-grab-issue-with-rubber-bandi.patch')
-rw-r--r-- | 0001-desktop-icons-Fix-stuck-grab-issue-with-rubber-bandi.patch | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/0001-desktop-icons-Fix-stuck-grab-issue-with-rubber-bandi.patch b/0001-desktop-icons-Fix-stuck-grab-issue-with-rubber-bandi.patch new file mode 100644 index 0000000..81878f4 --- /dev/null +++ b/0001-desktop-icons-Fix-stuck-grab-issue-with-rubber-bandi.patch @@ -0,0 +1,209 @@ +From 73000f25e578b3ce6654fdf0d3da2ec3d9b95dd2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@redhat.com> +Date: Tue, 2 Nov 2021 09:20:11 +0100 +Subject: [PATCH] desktop-icons: Fix stuck grab issue with rubber banding + +The desktop icons extension can get into a state where the desktop no longer +takes mouse input. + +This happens if a user starts a rubber banding operation and then drags +the mouse to somewhere on screen that has a pop up menu, and then pops +the menu up. + +This commit addresses the bug by limiting the grab actor to the +backgrounds, and by explicitly ending the rubber banding operation +when one of the icons own menus is shown. + +One side effect of limiting the grab actor to the backgrounds, is the +rubber banding code never gets to see motion outside of the backgrounds +anymore. In order to keep drag operations feeling fluid when the user moves +toward the edge of the screen, this commit also overrides the +grab helpers captured-event handler so those motion events keep coming. + +We also start to end the rubber band if for any reason the grab it had +was released. +--- + extensions/desktop-icons/desktopGrid.js | 1 + + extensions/desktop-icons/desktopManager.js | 109 ++++++++++++--------- + extensions/desktop-icons/fileItem.js | 1 + + 3 files changed, 67 insertions(+), 44 deletions(-) + +diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js +index 002803c..c7846bf 100644 +--- a/extensions/desktop-icons/desktopGrid.js ++++ b/extensions/desktop-icons/desktopGrid.js +@@ -388,6 +388,7 @@ var DesktopGrid = GObject.registerClass({ + } + + _openMenu(x, y) { ++ Extension.desktopManager.endRubberBand(); + Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0); + this._submenu.menu.removeAll(); + let templates = Extension.templateManager.getTemplates(); +diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js +index 10e3ce0..08bc82b 100644 +--- a/extensions/desktop-icons/desktopManager.js ++++ b/extensions/desktop-icons/desktopManager.js +@@ -81,6 +81,7 @@ var DesktopManager = GObject.registerClass({ + this._unixMode = null; + this._writableByOthers = null; + this._discreteGpuAvailable = false; ++ this._rubberBandActive = false; + + this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._recreateDesktopIcons()); + this._rubberBand = new St.Widget({ style_class: 'rubber-band' }); +@@ -94,6 +95,20 @@ var DesktopManager = GObject.registerClass({ + this._mountRemovedId = this._mountMonitor.connect('mount-removed', (monitor, mount) => { + this._recreateDesktopIcons(); }); + ++ let origCapturedEvent = this._grabHelper.onCapturedEvent; ++ this._grabHelper.onCapturedEvent = (event) => { ++ if (event.type() === Clutter.EventType.MOTION) { ++ /* We handle motion events from a captured event handler so we ++ * we can see motion over actors that are on other parts of the ++ * stage. ++ */ ++ this._handleMotion(event); ++ return Clutter.EVENT_STOP; ++ } ++ ++ return origCapturedEvent.bind(this._grabHelper)(event); ++ }; ++ + this._addDesktopIcons(); + this._monitorDesktopFolder(); + +@@ -133,57 +148,67 @@ var DesktopManager = GObject.registerClass({ + this._rubberBandInitialY = y; + this._updateRubberBand(x, y); + this._rubberBand.show(); +- this._grabHelper.grab({ actor: global.stage }); ++ this._rubberBandActive = true; ++ this._grabHelper.grab({ ++ actor: Main.layoutManager._backgroundGroup, ++ onUngrab: () => this.endRubberBand(false), ++ }); + Extension.lockActivitiesButton = true; + this._stageReleaseEventId = global.stage.connect('button-release-event', (actor, event) => { + this.endRubberBand(); + }); + this._rubberBandId = global.stage.connect('motion-event', (actor, event) => { +- /* In some cases, when the user starts a rubberband selection and ends it +- * (by releasing the left button) over a window instead of doing it over +- * the desktop, the stage doesn't receive the "button-release" event. +- * This happens currently with, at least, Dash to Dock extension, but +- * it probably also happens with other applications or extensions. +- * To fix this, we also end the rubberband selection if we detect mouse +- * motion in the stage without the left button pressed during a +- * rubberband selection. +- * */ +- let button = event.get_state(); +- if (!(button & Clutter.ModifierType.BUTTON1_MASK)) { +- this.endRubberBand(); +- return; +- } +- [x, y] = event.get_coords(); +- this._updateRubberBand(x, y); +- let x0, y0, x1, y1; +- if (x >= this._rubberBandInitialX) { +- x0 = this._rubberBandInitialX; +- x1 = x; +- } else { +- x1 = this._rubberBandInitialX; +- x0 = x; +- } +- if (y >= this._rubberBandInitialY) { +- y0 = this._rubberBandInitialY; +- y1 = y; +- } else { +- y1 = this._rubberBandInitialY; +- y0 = y; +- } +- for (let [fileUri, fileItem] of this._fileItems) { +- fileItem.emit('selected', true, true, +- fileItem.intersectsWith(x0, y0, x1 - x0, y1 - y0)); +- } + }); + } + +- endRubberBand() { ++ _handleMotion(event) { ++ /* In some cases, when the user starts a rubberband selection and ends it ++ * (by releasing the left button) over a window instead of doing it over ++ * the desktop, the stage doesn't receive the "button-release" event. ++ * This happens currently with, at least, Dash to Dock extension, but ++ * it probably also happens with other applications or extensions. ++ * To fix this, we also end the rubberband selection if we detect mouse ++ * motion in the stage without the left button pressed during a ++ * rubberband selection. ++ * */ ++ let button = event.get_state(); ++ if (!(button & Clutter.ModifierType.BUTTON1_MASK)) { ++ this.endRubberBand(); ++ return; ++ } ++ let [x, y] = event.get_coords(); ++ this._updateRubberBand(x, y); ++ let x0, y0, x1, y1; ++ if (x >= this._rubberBandInitialX) { ++ x0 = this._rubberBandInitialX; ++ x1 = x; ++ } else { ++ x1 = this._rubberBandInitialX; ++ x0 = x; ++ } ++ if (y >= this._rubberBandInitialY) { ++ y0 = this._rubberBandInitialY; ++ y1 = y; ++ } else { ++ y1 = this._rubberBandInitialY; ++ y0 = y; ++ } ++ for (let [fileUri, fileItem] of this._fileItems) { ++ fileItem.emit('selected', true, true, ++ fileItem.intersectsWith(x0, y0, x1 - x0, y1 - y0)); ++ } ++ } ++ ++ endRubberBand(ungrab=true) { ++ if (!this._rubberBandActive) ++ return; ++ ++ this._rubberBandActive = false; + this._rubberBand.hide(); + Extension.lockActivitiesButton = false; +- this._grabHelper.ungrab(); +- global.stage.disconnect(this._rubberBandId); ++ if (ungrab) ++ this._grabHelper.ungrab(); + global.stage.disconnect(this._stageReleaseEventId); +- this._rubberBandId = 0; + this._stageReleaseEventId = 0; + + this._selection = new Set([...this._selection, ...this._currentSelection]); +@@ -825,10 +850,6 @@ var DesktopManager = GObject.registerClass({ + global.stage.disconnect(this._stageReleaseEventId); + this._stageReleaseEventId = 0; + +- if (this._rubberBandId) +- global.stage.disconnect(this._rubberBandId); +- this._rubberBandId = 0; +- + this._rubberBand.destroy(); + + if (this._queryFileInfoCancellable) +diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js +index 1e8ea89..37ee54d 100644 +--- a/extensions/desktop-icons/fileItem.js ++++ b/extensions/desktop-icons/fileItem.js +@@ -747,6 +747,7 @@ var FileItem = GObject.registerClass({ + } + + _onPressButton(actor, event) { ++ Extension.desktopManager.endRubberBand(); + this._updateClickState(event); + let button = event.get_button(); + if (button == 3) { +-- +2.31.1 + |