Blame SOURCES/0001-desktop-icons-Fix-stuck-grab-issue-with-rubber-bandi.patch

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