Blame SOURCES/0001-dnd-Nullify-_dragActor-after-we-ve-destroyed-it-and-.patch

42f94a
From e0414e7cc7cc9e997659f297637f35d9202b6dab Mon Sep 17 00:00:00 2001
42f94a
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
42f94a
Date: Tue, 5 Dec 2017 22:41:17 +0100
42f94a
Subject: [PATCH] dnd: Nullify _dragActor after we've destroyed it, and avoid
42f94a
 invalid access
42f94a
42f94a
We need to avoid that we use the _dragActor instance after that it has
42f94a
been destroyed or we'll get errors. We now set it to null when this
42f94a
happens, protecting any access to that.
42f94a
42f94a
Add a DragState enum-like object to keep track of the state
42f94a
instead of using booleans.
42f94a
42f94a
Remove duplicated handler on 'destroy' and just use a generic one.
42f94a
42f94a
https://bugzilla.gnome.org/show_bug.cgi?id=791233
42f94a
---
42f94a
 js/ui/dnd.js | 65 +++++++++++++++++++++++++++++++---------------------
42f94a
 1 file changed, 39 insertions(+), 26 deletions(-)
42f94a
42f94a
diff --git a/js/ui/dnd.js b/js/ui/dnd.js
42f94a
index a38607c24..431c60d6c 100644
42f94a
--- a/js/ui/dnd.js
42f94a
+++ b/js/ui/dnd.js
42f94a
@@ -27,6 +27,12 @@ var DragMotionResult = {
42f94a
     CONTINUE:  3
42f94a
 };
42f94a
 
42f94a
+var DragState = {
42f94a
+    INIT:      0,
42f94a
+    DRAGGING:  1,
42f94a
+    CANCELLED: 2,
42f94a
+};
42f94a
+
42f94a
 var DRAG_CURSOR_MAP = {
42f94a
     0: Meta.Cursor.DND_UNSUPPORTED_TARGET,
42f94a
     1: Meta.Cursor.DND_COPY,
42f94a
@@ -78,6 +84,8 @@ var _Draggable = new Lang.Class({
42f94a
                                         dragActorOpacity: undefined });
42f94a
 
42f94a
         this.actor = actor;
42f94a
+        this._dragState = DragState.INIT;
42f94a
+
42f94a
         if (!params.manualMode) {
42f94a
             this.actor.connect('button-press-event',
42f94a
                                this._onButtonPress.bind(this));
42f94a
@@ -88,7 +96,7 @@ var _Draggable = new Lang.Class({
42f94a
         this.actor.connect('destroy', () => {
42f94a
             this._actorDestroyed = true;
42f94a
 
42f94a
-            if (this._dragInProgress && this._dragCancellable)
42f94a
+            if (this._dragState == DragState.DRAGGING && this._dragCancellable)
42f94a
                 this._cancelDrag(global.get_current_time());
42f94a
             this.disconnectAll();
42f94a
         });
42f94a
@@ -100,7 +108,6 @@ var _Draggable = new Lang.Class({
42f94a
         this._dragActorOpacity = params.dragActorOpacity;
42f94a
 
42f94a
         this._buttonDown = false; // The mouse button has been pressed and has not yet been released.
42f94a
-        this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
42f94a
         this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting).
42f94a
         this._dragCancellable = true;
42f94a
 
42f94a
@@ -206,9 +213,10 @@ var _Draggable = new Lang.Class({
42f94a
             (event.type() == Clutter.EventType.TOUCH_END &&
42f94a
              global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
42f94a
             this._buttonDown = false;
42f94a
-            if (this._dragInProgress) {
42f94a
+            if (this._dragState == DragState.DRAGGING) {
42f94a
                 return this._dragActorDropped(event);
42f94a
-            } else if (this._dragActor != null && !this._animationInProgress) {
42f94a
+            } else if ((this._dragActor != null || this._dragState == DragState.CANCELLED) &&
42f94a
+                       !this._animationInProgress) {
42f94a
                 // Drag must have been cancelled with Esc.
42f94a
                 this._dragComplete();
42f94a
                 return Clutter.EVENT_STOP;
42f94a
@@ -222,14 +230,14 @@ var _Draggable = new Lang.Class({
42f94a
         } else if (event.type() == Clutter.EventType.MOTION ||
42f94a
                    (event.type() == Clutter.EventType.TOUCH_UPDATE &&
42f94a
                     global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
42f94a
-            if (this._dragInProgress) {
42f94a
+            if (this._dragActor && this._dragState == DragState.DRAGGING) {
42f94a
                 return this._updateDragPosition(event);
42f94a
-            } else if (this._dragActor == null) {
42f94a
+            } else if (this._dragActor == null && this._dragState != DragState.CANCELLED) {
42f94a
                 return this._maybeStartDrag(event);
42f94a
             }
42f94a
         // We intercept KEY_PRESS event so that we can process Esc key press to cancel
42f94a
         // dragging and ignore all other key presses.
42f94a
-        } else if (event.type() == Clutter.EventType.KEY_PRESS && this._dragInProgress) {
42f94a
+        } else if (event.type() == Clutter.EventType.KEY_PRESS && this._dragState == DragState.DRAGGING) {
42f94a
             let symbol = event.get_key_symbol();
42f94a
             if (symbol == Clutter.Escape) {
42f94a
                 this._cancelDrag(event.get_time());
42f94a
@@ -265,7 +273,7 @@ var _Draggable = new Lang.Class({
42f94a
      */
42f94a
     startDrag(stageX, stageY, time, sequence) {
42f94a
         currentDraggable = this;
42f94a
-        this._dragInProgress = true;
42f94a
+        this._dragState = DragState.DRAGGING;
42f94a
 
42f94a
         // Special-case St.Button: the pointer grab messes with the internal
42f94a
         // state, so force a reset to a reasonable state here
42f94a
@@ -342,6 +350,13 @@ var _Draggable = new Lang.Class({
42f94a
             Shell.util_set_hidden_from_pick(this._dragActor, true);
42f94a
         }
42f94a
 
42f94a
+        this._dragActorDestroyId = this._dragActor.connect('destroy', () => {
42f94a
+            // Cancel ongoing animation (if any)
42f94a
+            this._finishAnimation();
42f94a
+
42f94a
+            this._dragActor = null;
42f94a
+            this._dragState = DragState.CANCELLED;
42f94a
+        });
42f94a
         this._dragOrigOpacity = this._dragActor.opacity;
42f94a
         if (this._dragActorOpacity != undefined)
42f94a
             this._dragActor.opacity = this._dragActorOpacity;
42f94a
@@ -500,7 +515,7 @@ var _Draggable = new Lang.Class({
42f94a
                                                 event.get_time())) {
42f94a
                     // If it accepted the drop without taking the actor,
42f94a
                     // handle it ourselves.
42f94a
-                    if (this._dragActor.get_parent() == Main.uiGroup) {
42f94a
+                    if (this._dragActor && this._dragActor.get_parent() == Main.uiGroup) {
42f94a
                         if (this._restoreOnSuccess) {
42f94a
                             this._restoreDragActor(event.get_time());
42f94a
                             return true;
42f94a
@@ -508,7 +523,7 @@ var _Draggable = new Lang.Class({
42f94a
                             this._dragActor.destroy();
42f94a
                     }
42f94a
 
42f94a
-                    this._dragInProgress = false;
42f94a
+                    this._dragState = DragState.INIT;
42f94a
                     global.screen.set_cursor(Meta.Cursor.DEFAULT);
42f94a
                     this.emit('drag-end', event.get_time(), true);
42f94a
                     this._dragComplete();
42f94a
@@ -557,20 +572,22 @@ var _Draggable = new Lang.Class({
42f94a
 
42f94a
     _cancelDrag(eventTime) {
42f94a
         this.emit('drag-cancelled', eventTime);
42f94a
-        this._dragInProgress = false;
42f94a
-        let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
42f94a
+        let wasCancelled = (this._dragState == DragState.CANCELLED);
42f94a
+        this._dragState = DragState.CANCELLED;
42f94a
 
42f94a
-        if (this._actorDestroyed) {
42f94a
+        if (this._actorDestroyed || wasCancelled) {
42f94a
             global.screen.set_cursor(Meta.Cursor.DEFAULT);
42f94a
             if (!this._buttonDown)
42f94a
                 this._dragComplete();
42f94a
             this.emit('drag-end', eventTime, false);
42f94a
-            if (!this._dragOrigParent)
42f94a
+            if (!this._dragOrigParent && this._dragActor)
42f94a
                 this._dragActor.destroy();
42f94a
 
42f94a
             return;
42f94a
         }
42f94a
 
42f94a
+        let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
42f94a
+
42f94a
         this._animateDragEnd(eventTime,
42f94a
                              { x: snapBackX,
42f94a
                                y: snapBackY,
42f94a
@@ -581,7 +598,7 @@ var _Draggable = new Lang.Class({
42f94a
     },
42f94a
 
42f94a
     _restoreDragActor(eventTime) {
42f94a
-        this._dragInProgress = false;
42f94a
+        this._dragState = DragState.INIT;
42f94a
         let [restoreX, restoreY, restoreScale] = this._getRestoreLocation();
42f94a
 
42f94a
         // fade the actor back in at its original location
42f94a
@@ -596,12 +613,6 @@ var _Draggable = new Lang.Class({
42f94a
     _animateDragEnd(eventTime, params) {
42f94a
         this._animationInProgress = true;
42f94a
 
42f94a
-        // finish animation if the actor gets destroyed
42f94a
-        // during it
42f94a
-        this._dragActorDestroyId =
42f94a
-            this._dragActor.connect('destroy',
42f94a
-                                    this._finishAnimation.bind(this));
42f94a
-
42f94a
         params['opacity']          = this._dragOrigOpacity;
42f94a
         params['transition']       = 'easeOutQuad';
42f94a
         params['onComplete']       = this._onAnimationComplete;
42f94a
@@ -624,9 +635,6 @@ var _Draggable = new Lang.Class({
42f94a
     },
42f94a
 
42f94a
     _onAnimationComplete(dragActor, eventTime) {
42f94a
-        dragActor.disconnect(this._dragActorDestroyId);
42f94a
-        this._dragActorDestroyId = 0;
42f94a
-
42f94a
         if (this._dragOrigParent) {
42f94a
             Main.uiGroup.remove_child(this._dragActor);
42f94a
             this._dragOrigParent.add_actor(this._dragActor);
42f94a
@@ -641,7 +649,7 @@ var _Draggable = new Lang.Class({
42f94a
     },
42f94a
 
42f94a
     _dragComplete() {
42f94a
-        if (!this._actorDestroyed)
42f94a
+        if (!this._actorDestroyed && this._dragActor)
42f94a
             Shell.util_set_hidden_from_pick(this._dragActor, false);
42f94a
 
42f94a
         this._ungrabEvents();
42f94a
@@ -652,7 +660,12 @@ var _Draggable = new Lang.Class({
42f94a
             this._updateHoverId = 0;
42f94a
         }
42f94a
 
42f94a
-        this._dragActor = undefined;
42f94a
+        if (this._dragActor) {
42f94a
+            this._dragActor.disconnect(this._dragActorDestroyId);
42f94a
+            this._dragActor = null;
42f94a
+        }
42f94a
+
42f94a
+        this._dragState = DragState.INIT;
42f94a
         currentDraggable = null;
42f94a
     }
42f94a
 });
42f94a
-- 
42f94a
2.19.1
42f94a