[gnome-shell/gbsneto/icon-grid-dnd-fixes: 14/14] appDisplay: Protect against source icon destruction
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/gbsneto/icon-grid-dnd-fixes: 14/14] appDisplay: Protect against source icon destruction
- Date: Fri, 25 Sep 2020 14:50:50 +0000 (UTC)
commit d66933213495208db6948bac6ec991e54b0f35f1
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Thu Sep 24 18:57:56 2020 -0300
appDisplay: Protect against source icon destruction
When dragging icons out of a folder dialog, there is a very peculiar
combination of steps that may break GNOME Shell:
1. Open an app folder dialog
2. Start dragging an icon to outside the grid
3. Wait until the popdown animation starts
4. Before it finishes, drop the icon
5. See the warnings / crash
That's caused by the source icon being destroyed after the delayed
move timer starts, and before it finishes.
Protect against the source icon being destroyed before the delayed
move timeout triggers by connecting to the 'destroy' signal and
removing the timeout on the callback.
https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1447
js/ui/appDisplay.js | 52 +++++++++++++++++++++++++++++++---------------------
1 file changed, 31 insertions(+), 21 deletions(-)
---
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index a1558ff39f..114f1e2600 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -196,8 +196,7 @@ var BaseAppView = GObject.registerClass({
// Drag n' Drop
this._lastOvershoot = -1;
this._lastOvershootTimeoutId = 0;
- this._delayedMoveId = 0;
- this._targetDropPosition = null;
+ this._delayedMoveData = null;
this._dragBeginId = 0;
this._dragEndId = 0;
@@ -352,29 +351,40 @@ var BaseAppView = GObject.registerClass({
return;
}
- if (!this._targetDropPosition ||
- this._targetDropPosition.page !== page ||
- this._targetDropPosition.position !== position) {
+ if (!this._delayedMoveData ||
+ this._delayedMoveData.page !== page ||
+ this._delayedMoveData.position !== position) {
// Update the item with a small delay
this._removeDelayedMove();
- this._targetDropPosition = { page, position };
-
- this._delayedMoveId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
- DELAYED_MOVE_TIMEOUT, () => {
- this._moveItem(source, page, position);
- this._targetDropPosition = null;
- this._delayedMoveId = 0;
- return GLib.SOURCE_REMOVE;
- });
+ this._delayedMoveData = {
+ page,
+ position,
+ source,
+ destroyId: source.connect('destroy', () => this._removeDelayedMove()),
+ timeoutId: GLib.timeout_add(GLib.PRIORITY_DEFAULT,
+ DELAYED_MOVE_TIMEOUT, () => {
+ this._moveItem(source, page, position);
+ this._delayedMoveData.timeoutId = 0;
+ this._removeDelayedMove();
+ return GLib.SOURCE_REMOVE;
+ }),
+ };
}
}
_removeDelayedMove() {
- if (this._delayedMoveId > 0) {
- GLib.source_remove(this._delayedMoveId);
- this._delayedMoveId = 0;
- }
- this._targetDropPosition = null;
+ if (!this._delayedMoveData)
+ return;
+
+ const { source, destroyId, timeoutId } = this._delayedMoveData;
+
+ if (timeoutId > 0)
+ GLib.source_remove(timeoutId);
+
+ if (destroyId > 0)
+ source.disconnect(destroyId);
+
+ this._delayedMoveData = null;
}
_resetOvershoot() {
@@ -492,8 +502,8 @@ var BaseAppView = GObject.registerClass({
return false;
// Dropped before the icon was moved
- if (this._targetDropPosition) {
- const { page, position } = this._targetDropPosition;
+ if (this._delayedMoveData) {
+ const { page, position } = this._delayedMoveData;
this._moveItem(source, page, position);
this._removeDelayedMove();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]