210 lines
8.6 KiB
Diff
210 lines
8.6 KiB
Diff
|
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
|
||
|
|