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

189dc3
From b334c8c248f849be996963cdafb1b0b69476bdf1 Mon Sep 17 00:00:00 2001
189dc3
From: =?UTF-8?q?Jonas=20=C3=85dahl?= <jadahl@redhat.com>
189dc3
Date: Tue, 2 Nov 2021 09:20:11 +0100
189dc3
Subject: [PATCH] desktop-icons: Fix stuck grab issue with rubber banding
189dc3
189dc3
The desktop icons extension can get into a state where the desktop no longer
189dc3
takes mouse input.
189dc3
189dc3
This happens if a user starts a rubber banding operation and then drags
189dc3
the mouse to somewhere on screen that has a pop up menu, and then pops
189dc3
the menu up.
189dc3
189dc3
This commit addresses the bug by limiting the grab actor to the
189dc3
backgrounds, and by explicitly ending the rubber banding operation
189dc3
when one of the icons own menus is shown.
189dc3
189dc3
One side effect of limiting the grab actor to the backgrounds, is the
189dc3
rubber banding code never gets to see motion outside of the backgrounds
189dc3
anymore. In order to keep drag operations feeling fluid when the user moves
189dc3
toward the edge of the screen, this commit also overrides the
189dc3
grab helpers captured-event handler so those motion events keep coming.
189dc3
189dc3
We also start to end the rubber band if for any reason the grab it had
189dc3
was released.
189dc3
---
189dc3
 extensions/desktop-icons/desktopGrid.js    |  1 +
189dc3
 extensions/desktop-icons/desktopManager.js | 75 ++++++++++++++--------
189dc3
 extensions/desktop-icons/fileItem.js       |  1 +
189dc3
 3 files changed, 49 insertions(+), 28 deletions(-)
189dc3
189dc3
diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js
189dc3
index 602fa7f..bd27e2a 100644
189dc3
--- a/extensions/desktop-icons/desktopGrid.js
189dc3
+++ b/extensions/desktop-icons/desktopGrid.js
189dc3
@@ -365,6 +365,7 @@ var DesktopGrid = class {
189dc3
     }
189dc3
 
189dc3
     _openMenu(x, y) {
189dc3
+        Extension.desktopManager.endRubberBand();
189dc3
         Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
189dc3
         this.actor._desktopBackgroundMenu.open(BoxPointer.PopupAnimation.NONE);
189dc3
         /* Since the handler is in the press event it needs to ignore the release event
189dc3
diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js
189dc3
index a70cd98..c37e1e7 100644
189dc3
--- a/extensions/desktop-icons/desktopManager.js
189dc3
+++ b/extensions/desktop-icons/desktopManager.js
189dc3
@@ -79,6 +79,7 @@ var DesktopManager = GObject.registerClass({
189dc3
         this._queryFileInfoCancellable = null;
189dc3
         this._unixMode = null;
189dc3
         this._writableByOthers = null;
189dc3
+        this._rubberBandActive = false;
189dc3
 
189dc3
         this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._recreateDesktopIcons());
189dc3
         this._rubberBand = new St.Widget({ style_class: 'rubber-band' });
189dc3
@@ -86,6 +87,20 @@ var DesktopManager = GObject.registerClass({
189dc3
         Main.layoutManager._backgroundGroup.add_child(this._rubberBand);
189dc3
         this._grabHelper = new GrabHelper.GrabHelper(global.stage);
189dc3
 
189dc3
+        let origCapturedEvent = this._grabHelper.onCapturedEvent;
189dc3
+        this._grabHelper.onCapturedEvent = (event) => {
189dc3
+            if (event.type() === Clutter.EventType.MOTION) {
189dc3
+                /* We handle motion events from a captured event handler so we
189dc3
+                 * we can see motion over actors that are on other parts of the
189dc3
+                 * stage.
189dc3
+                 */
189dc3
+                this._handleMotion(event);
189dc3
+                return Clutter.EVENT_STOP;
189dc3
+            }
189dc3
+
189dc3
+            return origCapturedEvent.bind(this._grabHelper)(event);
189dc3
+        };
189dc3
+
189dc3
         this._addDesktopIcons();
189dc3
         this._monitorDesktopFolder();
189dc3
 
189dc3
@@ -108,30 +123,15 @@ var DesktopManager = GObject.registerClass({
189dc3
         this._initRubberBandColor();
189dc3
         this._updateRubberBand(x, y);
189dc3
         this._rubberBand.show();
189dc3
-        this._grabHelper.grab({ actor: global.stage });
189dc3
+        this._rubberBandActive = true;
189dc3
+        this._grabHelper.grab({
189dc3
+            actor: Main.layoutManager._backgroundGroup,
189dc3
+            onUngrab: () => this.endRubberBand(false),
189dc3
+        });
189dc3
         Extension.lockActivitiesButton = true;
189dc3
         this._stageReleaseEventId = global.stage.connect('button-release-event', (actor, event) => {
189dc3
             this.endRubberBand();
189dc3
         });
189dc3
-        this._rubberBandId = global.stage.connect('motion-event', (actor, event) => {
189dc3
-            /* In some cases, when the user starts a rubberband selection and ends it
189dc3
-             * (by releasing the left button) over a window instead of doing it over
189dc3
-             * the desktop, the stage doesn't receive the "button-release" event.
189dc3
-             * This happens currently with, at least, Dash to Dock extension, but
189dc3
-             * it probably also happens with other applications or extensions.
189dc3
-             * To fix this, we also end the rubberband selection if we detect mouse
189dc3
-             * motion in the stage without the left button pressed during a
189dc3
-             * rubberband selection.
189dc3
-             *  */
189dc3
-            let button = event.get_state();
189dc3
-            if (!(button & Clutter.ModifierType.BUTTON1_MASK)) {
189dc3
-                this.endRubberBand();
189dc3
-                return;
189dc3
-            }
189dc3
-            [x, y] = event.get_coords();
189dc3
-            this._updateRubberBand(x, y);
189dc3
-            this._updateSelection(x, y);
189dc3
-        });
189dc3
         this._rubberBandTouchId = global.stage.connect('touch-event', (actor, event) => {
189dc3
             // Let x11 pointer emulation do the job on X11
189dc3
             if (!Meta.is_wayland_compositor())
189dc3
@@ -175,14 +175,37 @@ var DesktopManager = GObject.registerClass({
189dc3
         }
189dc3
     }
189dc3
 
189dc3
-    endRubberBand() {
189dc3
+    _handleMotion(event) {
189dc3
+        /* In some cases, when the user starts a rubberband selection and ends it
189dc3
+         * (by releasing the left button) over a window instead of doing it over
189dc3
+         * the desktop, the stage doesn't receive the "button-release" event.
189dc3
+         * This happens currently with, at least, Dash to Dock extension, but
189dc3
+         * it probably also happens with other applications or extensions.
189dc3
+         * To fix this, we also end the rubberband selection if we detect mouse
189dc3
+         * motion in the stage without the left button pressed during a
189dc3
+         * rubberband selection.
189dc3
+         *  */
189dc3
+        let button = event.get_state();
189dc3
+        if (!(button & Clutter.ModifierType.BUTTON1_MASK)) {
189dc3
+            this.endRubberBand();
189dc3
+            return;
189dc3
+        }
189dc3
+        let [x, y] = event.get_coords();
189dc3
+        this._updateRubberBand(x, y);
189dc3
+        this._updateSelection(x, y);
189dc3
+    }
189dc3
+
189dc3
+    endRubberBand(ungrab=true) {
189dc3
+        if (!this._rubberBandActive)
189dc3
+             return;
189dc3
+
189dc3
+        this._rubberBandActive = false;
189dc3
         this._rubberBand.hide();
189dc3
         Extension.lockActivitiesButton = false;
189dc3
-        this._grabHelper.ungrab();
189dc3
-        global.stage.disconnect(this._rubberBandId);
189dc3
+        if (ungrab)
189dc3
+            this._grabHelper.ungrab();
189dc3
         global.stage.disconnect(this._rubberBandTouchId);
189dc3
         global.stage.disconnect(this._stageReleaseEventId);
189dc3
-        this._rubberBandId = 0;
189dc3
         this._rubberBandTouchId = 0;
189dc3
         this._stageReleaseEventId = 0;
189dc3
 
189dc3
@@ -760,10 +783,6 @@ var DesktopManager = GObject.registerClass({
189dc3
             global.stage.disconnect(this._stageReleaseEventId);
189dc3
         this._stageReleaseEventId = 0;
189dc3
 
189dc3
-        if (this._rubberBandId)
189dc3
-            global.stage.disconnect(this._rubberBandId);
189dc3
-        this._rubberBandId = 0;
189dc3
-
189dc3
         if (this._rubberBandTouchId)
189dc3
             global.stage.disconnect(this._rubberBandTouchId);
189dc3
         this._rubberBandTouchId = 0;
189dc3
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
189dc3
index 1cb47e8..90f326d 100644
189dc3
--- a/extensions/desktop-icons/fileItem.js
189dc3
+++ b/extensions/desktop-icons/fileItem.js
189dc3
@@ -676,6 +676,7 @@ var FileItem = class {
189dc3
     }
189dc3
 
189dc3
     _onPressButton(actor, event) {
189dc3
+        Extension.desktopManager.endRubberBand();
189dc3
         this._updateClickState(event);
189dc3
         let button = this._eventButton(event);
189dc3
         if (button == 3) {
189dc3
-- 
189dc3
2.31.1
189dc3