After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 620389 - while dragging a window, if it's unmapped, the shell crashes
while dragging a window, if it's unmapped, the shell crashes
Status: RESOLVED FIXED
Product: gnome-shell
Classification: Core
Component: general
unspecified
Other Linux
: Normal normal
: ---
Assigned To: Florian Müllner
gnome-shell-maint
Depends on:
Blocks:
 
 
Reported: 2010-06-02 18:09 UTC by Colin Walters
Modified: 2010-10-24 01:50 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
[dnd] If actor destroyed, cancel drag (824 bytes, patch)
2010-06-11 11:19 UTC, Maxim Ermilov
needs-work Details | Review
[dnd] If actor destroyed, cancel drag (5.44 KB, patch)
2010-09-27 14:16 UTC, Maxim Ermilov
needs-work Details | Review
[dnd] If actor destroyed, cancel drag (4.50 KB, patch)
2010-09-30 17:30 UTC, Maxim Ermilov
needs-work Details | Review
[dnd] If actor destroyed, cancel drag (1.79 KB, patch)
2010-10-22 08:59 UTC, Maxim Ermilov
committed Details | Review

Description Colin Walters 2010-06-02 18:09:52 UTC
Reported on IRC.
Comment 1 Maxim Ermilov 2010-06-11 11:19:49 UTC
Created attachment 163380 [details] [review]
[dnd] If actor destroyed, cancel drag
Comment 2 Florian Müllner 2010-06-16 18:27:45 UTC
Review of attachment 163380 [details] [review]:

The patch looks good and fixes the problem, the only "flaw" is this warning:

Window manager warning: Log level 16: gsignal.c:2390: instance `0x9e104d0' has no handler with id `1999'

This is obviously way better than crashing, so unless there's a quick fix you should push the change.
Comment 3 Owen Taylor 2010-06-16 18:32:56 UTC
A temporary fix crash that leaves a warning like that can be OK, but basically any warning like that is *not* OK, and this bug needs to be left open until we have a fix that doesn't warn. 

Being sloppy about serious warnings means that you can't distinguish errors that we need to fix from stuff that's "expected" - if we're always getting stray "instance '...' has no handler with id '...'" warnings, then we'll never notice if we start disconnecting junk signal handler ids.

(Yes, we are sloppy about leaving some other warnings around for a long time, like the warnings that the window triggers. That's bad, and we shouldn't be adding more such.)
Comment 4 Florian Müllner 2010-06-16 18:53:27 UTC
Comment on attachment 163380 [details] [review]
[dnd] If actor destroyed, cancel drag

> A temporary fix crash that leaves a warning like that can be OK, but
> basically any warning like that is *not* OK, and this bug needs to be
> left open until we have a fix that doesn't warn. 

Marking as needs-work based on Owen's comment then.
Comment 5 Maxim Ermilov 2010-09-27 14:16:11 UTC
Created attachment 171207 [details] [review]
[dnd] If actor destroyed, cancel drag
Comment 6 Florian Müllner 2010-09-30 10:46:00 UTC
Review of attachment 171207 [details] [review]:

This is a pretty intrusive patch - nothing wrong with that per se, but the already complicated code gets quite a bit harder to read (e.g. I doubt that we really need two new status properties to handle the case of the actor going away during drag).

::: js/ui/dnd.js
@@ +88,2 @@
         this.actor.connect('destroy', Lang.bind(this, function() {
+            this._actorDestoyed = true;

Typo: dest_r_oyed

@@ +88,3 @@
         this.actor.connect('destroy', Lang.bind(this, function() {
+            this._actorDestoyed = true;
+            if (!this._acceptDropInProgress) {

Uhm - disabling the handler during drop and then calling its code manually elsewhere is rather confusing.  It would be much cleaner to check this._actorDestroyed during drop handling and cancel when necessary.

@@ +332,2 @@
         // If we are dragging, update the position
+        if (this._dragActor && this._dragInProgress) {

Why is this necessary?

@@ +431,3 @@
+                        this._acceptDropInProgress = false;
+                        this._restoreDragActor(event.get_time());
+                        return true;

Not that the code was very clear before, but the replacement looks wrong - it does something else than what the comment above implies and does handle the case where this._restoreOnSuccess == false differently if dragOrigParent is set.

@@ +436,3 @@
+                    this._emitDragEnd(this._dragActor, event.get_time(), false);
+                    if (this._actorDestoyed)
+                        this.disconnectAll();

Again, this looks like it changes dnd behavior: if this._dragOrigParent is set, this._emitDragEnd() will reparent/reposition/resize the dragActor, while previously this._dragActor had been destroyed at this point.

@@ +501,3 @@
     },
 
+    _emitDragEnd: function (dragActor, eventTime, dragActorDestroying) {

_emitDragEnd? This sounds like all it does is emit a signal and possibly update some internal status variables, but for a function which changes an actor's parent/scale/position, this is a clear misnomer.

Also the use of a boolean parameter to change the behavior of the function completely is rather unintuitive.
Comment 7 Maxim Ermilov 2010-09-30 17:30:47 UTC
Created attachment 171445 [details] [review]
[dnd] If actor destroyed, cancel drag

> It would be much cleaner to check this._actorDestroyed during drop handling and cancel when necessary.
done.
Now 'drag-end' can be emited during call to acceptDrop (I try avoid this In previous patch. It was source of complexity)
Comment 8 Florian Müllner 2010-09-30 18:59:52 UTC
Comment on attachment 171445 [details] [review]
[dnd] If actor destroyed, cancel drag

(In reply to comment #7)
> Now 'drag-end' can be emited during call to acceptDrop (I try avoid this In
> previous patch. It was source of complexity)

The code is much cleaner, but I get this exception repeatedly:

    JS ERROR: !!!   Exception was: TypeError: currentDraggable is null
    JS ERROR: !!!     lineNumber = '54'
    JS ERROR: !!!     fileName = '/home/florian/src/gnome-shell/js/ui/dnd.js'
    JS ERROR: !!!     stack = '([object _private_Clutter_Rectangle],[object _private_Clutter_Event])@/home/florian/src/gnome-shell/js/ui/dnd.js:54
'
    JS ERROR: !!!     message = 'currentDraggable is null'


Keyboard and pointer remain grabbed, so killing the shell is the only way out.

(Tested with 'zenity --info & sleep 5; kill %1', then dragging the zenity window in the overview until it goes away)
Comment 9 Florian Müllner 2010-09-30 19:05:27 UTC
Comment on attachment 171445 [details] [review]
[dnd] If actor destroyed, cancel drag

Nevermind, I had some crap in my local tree ...
Comment 10 Florian Müllner 2010-10-15 10:25:15 UTC
Review of attachment 171445 [details] [review]:

The patch fixes the crash, but I think it can still be improved:

 - Cancelling the drag completely on destruction of the drag actor means that the pointer grab
   is released. Now when the user releases the mouse button, the event is processed by the actor
   beneath the pointer - that's certainly not what the user intended, so it's wrong.

 - I get this:
   Window manager warning: Log level 8: g_object_unref: assertion `G_IS_OBJECT (object)' failed

::: js/ui/dnd.js
@@ +466,3 @@
         this._animationInProgress = true;
         // No target, so snap back
+        if (animate)

The animate parameter is actually this._actorDestroyed, right?

Further, with the additional conditions you added to _onAnimationComplete(), the function is reduced to

  global.unset_cursor();
  this.emit('drag-end', eventTime, false);
  this._dragComplete();

As noted before, I think the call to this._dragComplete() is actually wrong at this point (see how the Escape key is handled), which leaves two lines of code - in my opinion it is better to actually duplicate those lines (as already done in _dragActorDropped()) instead of calling _onAnimationComplete() without having animated anything. So what I propose is something like:

if (this._actorDestroyed) {
  global.unset_cursor();
  this.emit('drag-end', eventTime, false);
  return;
}

this._animationInProgress = true;
...

(or use an else part if you prefer ...)
Comment 11 Maxim Ermilov 2010-10-22 08:59:18 UTC
Created attachment 172982 [details] [review]
[dnd] If actor destroyed, cancel drag

> - Cancelling the drag completely on destruction of the drag actor means that
> the pointer grab is released.
fixed

> I get this: Window manager warning: Log level 8: g_object_unref: assertion
> `G_IS_OBJECT (object)' failed
I think, It is not related with this patch. (I get the bunch of such messages, when I open overview)
Comment 12 Florian Müllner 2010-10-22 09:38:33 UTC
Review of attachment 172982 [details] [review]:

Code looks good and works fine - even the warning seems to have been fixed by recent gjs updates! So OK to commit with a slightly more verbose commit message, e.g.

[dnd] Handle destruction of drag actor during drag

The shell crashes if the drag actor is destroyed during the drag
operation. Cancel the drag gracefully in this case.