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 763298 - wayland: connection flooded when dragging
wayland: connection flooded when dragging
Status: RESOLVED FIXED
Product: gtk+
Classification: Platform
Component: Backend: Wayland
unspecified
Other Linux
: Normal normal
: ---
Assigned To: gtk-bugs
gtk-bugs
Depends on:
Blocks:
 
 
Reported: 2016-03-08 09:36 UTC by Marek Chalupa
Modified: 2016-03-14 15:56 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Don't reset the drag status if not needed (1.46 KB, patch)
2016-03-08 09:36 UTC, Marek Chalupa
rejected Details | Review
gdkdnd: Add private gdk_drag_context_commit_drag_status() call (4.54 KB, patch)
2016-03-09 17:16 UTC, Carlos Garnacho
none Details | Review
gtkdnd: Use gdk_drag_context_commit_drag_status() (942 bytes, patch)
2016-03-09 17:17 UTC, Carlos Garnacho
none Details | Review
gdkdnd: Add private means to commit the drag status (4.28 KB, patch)
2016-03-10 11:46 UTC, Carlos Garnacho
none Details | Review
gdkdnd: Add private means to commit the drag status (4.75 KB, patch)
2016-03-14 14:28 UTC, Carlos Garnacho
none Details | Review
gdkdnd: Add private means to commit the drag status (4.77 KB, patch)
2016-03-14 15:55 UTC, Carlos Garnacho
committed Details | Review

Description Marek Chalupa 2016-03-08 09:36:50 UTC
Created attachment 323362 [details] [review]
Don't reset the drag status if not needed

With wayland >= 1.9.91 GTK+ uses dnd actions. Dragging an image in shotwell or file in file-roller leads to crash because the dnd actions events and requests flood the connection
Comment 1 Carlos Garnacho 2016-03-09 17:15:25 UTC
Comment on attachment 323362 [details] [review]
Don't reset the drag status if not needed

Thanks for the patch, I'm however not sure that's the right approach, that partly breaks the contract of GTK_DEST_DEFAULT_MOTION (which is issuing gdk_drag_status calls automatically).

I've been looking these last days into GtkNotebook tab DnD and also run into this, what's really happening here is that we possibly issue multiple gdk_drag_status() calls (with different drag actions) when processing the GDK_DRAG_MOTION event. This burst of action changes actually trigger a renegotiation, with signals emitted to both the drag source and destination. The destination side queues quickly get flooded by the many .set_action requests done and .action events received.

I think the solution is to coalesce these calls, so only one happens per GDK_DRAG_MOTION event. Because of the bottom to top approach in gtk_drag_find_widget(), we will be consistently sending the same status as long as the pointer sits in the same area, so we will be triggering a lot less noise at the protocol level.

I'm attaching a couple of patches with the fix I came up with.
Comment 2 Carlos Garnacho 2016-03-09 17:16:53 UTC
Created attachment 323526 [details] [review]
gdkdnd: Add private gdk_drag_context_commit_drag_status() call

The way gdk_drag_status() may be called multiple times during the
processing of GDK_DRAG_MOTION events throughout the widget hierarchy
brings some superfluous messaging going in, esp. when it's the last
request the one we want to honor, yet we emit messaging requests on
all.

This is barely appreciable in the X11 backend, but due to the design
of the wayland protocol, quick series of changes like this it have
some self-amplificating consequences which may end up flooding the
connection.

Adding a gdk_drag_context_commit_drag_status() call, we ensure we
only do this once per GDK_DRAG_MOTION event, and only with the final
status, so we don't trigger spurious changes on the compositor
and the other peer.
Comment 3 Carlos Garnacho 2016-03-09 17:17:04 UTC
Created attachment 323527 [details] [review]
gtkdnd: Use gdk_drag_context_commit_drag_status()

This way the status can just be pushed once to the windowing
per GDK_DRAG_MOTION event.
Comment 4 Matthias Clasen 2016-03-09 17:32:44 UTC
Review of attachment 323526 [details] [review]:

While looking at this I started wondering if we shouldn't avoid this private call nonsense by just calling this on the gdk side, at the bottom of _gdk_event_emit.
Comment 5 Carlos Garnacho 2016-03-10 11:46:36 UTC
Created attachment 323608 [details] [review]
gdkdnd: Add private means to commit the drag status

The way gdk_drag_status() may be called multiple times during the
processing of GDK_DRAG_MOTION events throughout the widget hierarchy
brings some superfluous messaging going in, esp. when it's the last
request the one we want to honor, yet we emit messaging requests on
all.

This is barely appreciable in the X11 backend, but due to the design
of the wayland protocol, quick series of changes like this it have
some self-amplificating consequences which may end up flooding the
connection.

We can delegate this to a late "commit" call, performed within GDK
event management. This way gdk_drag_status() calls may be cached
and only result in windowing messaging once per GDK_DRAG_MOTION
event. Emitting the final status will also avoid spurious action
changes on the compositor and the other peer.
Comment 6 Carlos Garnacho 2016-03-10 11:51:45 UTC
Didn't think at first of that one, much better than adding private calls around indeed.
Comment 7 Matthias Clasen 2016-03-10 13:01:23 UTC
Here is another concern I came upwith this morning:

The gdk dnd api lets you pretty freely call gdk_drag_status from whereever. With this change, I'm afraid that this might not work anymore for Wayland, since gdk_drag_status will not have any effect unless it is in response to a drag motion event.

Now, I don't know if such 'freestanding gdk_drag_status calls ever worked with Wayland in the first place...
Comment 8 Carlos Garnacho 2016-03-10 13:42:04 UTC
(In reply to Matthias Clasen from comment #7)
> Here is another concern I came upwith this morning:
> 
> The gdk dnd api lets you pretty freely call gdk_drag_status from whereever.

Hmmm, wherever in response to DnD events, or crazier things like timeouts, etc? I thought the docs seemed clear enough (even if outdated/non-generic):

"This function is called by the drag destination in response to gdk_drag_motion() called by the drag source."

It's right I'm missing GDK_DRAG_ENTER in the switch though.

> With this change, I'm afraid that this might not work anymore for Wayland,
> since gdk_drag_status will not have any effect unless it is in response to a
> drag motion event.
> 
> Now, I don't know if such 'freestanding gdk_drag_status calls ever worked
> with Wayland in the first place...

According to the wayland DnD protocol, the wl_data_offer.set_actions request (which gdk_drag_status/commit_drag_status boil down to) are allowed "during dnd" (typically in response to wl_data_device.enter/motion) and once after wl_data_device.drop, only if an "ask" action was agreed previously. I guess we should also enforce the latter more pervasively.
Comment 9 Matthias Clasen 2016-03-10 14:08:45 UTC
The example I was thinking of is from the GtkWidget::drag-data-received docs:

  * The ::drag-data-received signal is emitted on the drop site when the
   * dragged data has been received. If the data was received in order to
   * determine whether the drop will be accepted, the handler is expected
   * to call gdk_drag_status() and not finish the drag.
Comment 10 Carlos Garnacho 2016-03-10 15:15:34 UTC
Oh, right. We should be supporting that too. The wayland protocol also caters for the possibility of inspecting the data early before issuing wl_data_offer.set_actions. Looks like we should also trigger this after selection events.
Comment 11 Matthias Clasen 2016-03-11 15:48:55 UTC
Review of attachment 323362 [details] [review]:

.
Comment 12 Carlos Garnacho 2016-03-14 14:28:59 UTC
Created attachment 323875 [details] [review]
gdkdnd: Add private means to commit the drag status

The way gdk_drag_status() may be called multiple times during the
processing of GDK_DRAG_MOTION events throughout the widget hierarchy
brings some superfluous messaging going in, esp. when it's the last
request the one we want to honor, yet we emit messaging requests on
all.

This is barely appreciable in the X11 backend, but due to the design
of the wayland protocol, quick series of changes like this it have
some self-amplificating consequences which may end up flooding the
connection.

We can delegate this to a late "commit" call, performed within GDK
event management. This way gdk_drag_status() calls may be cached
and only result in windowing messaging once per GDK_DRAG_MOTION
event. Emitting the final status will also avoid spurious action
changes on the compositor and the other peer.
Comment 13 Carlos Garnacho 2016-03-14 15:55:48 UTC
Created attachment 323889 [details] [review]
gdkdnd: Add private means to commit the drag status

The way gdk_drag_status() may be called multiple times during the
processing of drag and drop events throughout the widget hierarchy
brings some superfluous messaging going in, esp. when it's the last
request the one we want to honor, yet we emit messaging requests on
all.

This is barely appreciable in the X11 backend, but due to the design
of the wayland protocol, quick series of changes like this it have
some self-amplificating consequences which may end up flooding the
connection.

We can delegate this to a late "commit" call, performed within GDK
event management. This way gdk_drag_status() calls may be cached
and only result in windowing messaging once per ::drag-motion or
::drag-data-received event. Emitting the final status will also
avoid spurious action changes on the compositor and the other peer.
Comment 14 Carlos Garnacho 2016-03-14 15:56:47 UTC
This last patch fixes the issue raised in comment #9. It's now pushed to master.

Attachment 323889 [details] pushed as 2923f69 - gdkdnd: Add private means to commit the drag status