From 1883df2927b9d088bf31f6d02ddbffac2de319f0 Mon Sep 17 00:00:00 2001 From: Marek Chalupa Date: Thu, 31 Mar 2016 14:26:06 +0200 Subject: [PATCH] dnd: Cancel the animation on drag actor destruction If the drag actor is destroyed before the animation callback is called, the callback is never called and we're sticked with dnd grabing the events after we dropped the target. https://bugzilla.gnome.org/show_bug.cgi?id=757676 --- js/ui/dnd.js | 70 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/js/ui/dnd.js b/js/ui/dnd.js index c7140a1c2..e749dd9a8 100644 --- a/js/ui/dnd.js +++ b/js/ui/dnd.js @@ -571,20 +571,13 @@ const _Draggable = new Lang.Class({ return; } - this._animationInProgress = true; - // No target, so snap back - Tweener.addTween(this._dragActor, - { x: snapBackX, - y: snapBackY, - scale_x: snapBackScale, - scale_y: snapBackScale, - opacity: this._dragOrigOpacity, - time: SNAP_BACK_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: this._onAnimationComplete, - onCompleteScope: this, - onCompleteParams: [this._dragActor, eventTime] - }); + this._animateDragEnd(eventTime, + { x: snapBackX, + y: snapBackY, + scale_x: snapBackScale, + scale_y: snapBackScale, + time: SNAP_BACK_ANIMATION_TIME, + }); }, _restoreDragActor: function(eventTime) { @@ -596,18 +589,44 @@ const _Draggable = new Lang.Class({ this._dragActor.set_scale(restoreScale, restoreScale); this._dragActor.opacity = 0; + this._animateDragEnd(eventTime, + { time: REVERT_ANIMATION_TIME }); + }, + + _animateDragEnd: function (eventTime, params) { this._animationInProgress = true; - Tweener.addTween(this._dragActor, - { opacity: this._dragOrigOpacity, - time: REVERT_ANIMATION_TIME, - transition: 'easeOutQuad', - onComplete: this._onAnimationComplete, - onCompleteScope: this, - onCompleteParams: [this._dragActor, eventTime] - }); + + // finish animation if the actor gets destroyed + // during it + this._dragActorDestroyId = + this._dragActor.connect('destroy', + Lang.bind(this, this._finishAnimation)); + + params['opacity'] = this._dragOrigOpacity; + params['transition'] = 'easeOutQuad'; + params['onComplete'] = this._onAnimationComplete; + params['onCompleteScope'] = this; + params['onCompleteParams'] = [this._dragActor, eventTime]; + + // start the animation + Tweener.addTween(this._dragActor, params) + }, + + _finishAnimation : function () { + if (!this._animationInProgress) + return + + this._animationInProgress = false; + if (!this._buttonDown) + this._dragComplete(); + + global.screen.set_cursor(Meta.Cursor.DEFAULT); }, _onAnimationComplete : function (dragActor, eventTime) { + dragActor.disconnect(this._dragActorDestroyId); + this._dragActorDestroyId = 0; + if (this._dragOrigParent) { Main.uiGroup.remove_child(this._dragActor); this._dragOrigParent.add_actor(this._dragActor); @@ -616,12 +635,9 @@ const _Draggable = new Lang.Class({ } else { dragActor.destroy(); } - global.screen.set_cursor(Meta.Cursor.DEFAULT); - this.emit('drag-end', eventTime, false); - this._animationInProgress = false; - if (!this._buttonDown) - this._dragComplete(); + this.emit('drag-end', eventTime, false); + this._finishAnimation(); }, _dragComplete: function() {