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

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