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

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