Skip to content

Misbehavior and crashing when dragging or ctrl+dragging tray icons

Drag warning

When I run xfce4-panel in a console, click a tray icon, drag my mouse outside the panel, and release my mouse, I start getting console messages saying (wrapper-2.0:251984): GLib-CRITICAL **: 16:40:52.908: Source ID 4879 was not found when attempting to remove it. One stack trace is:

(gdb) bt
#0  0x00007ffff684f92b in g_logv () at /usr/lib/libglib-2.0.so.0
#1  0x00007ffff684fc00 in g_log () at /usr/lib/libglib-2.0.so.0
#2  0x00007ffff684663e in g_source_remove () at /usr/lib/libglib-2.0.so.0
#3  0x00007ffff01e3e42 in operator() (__closure=0x0, widget=0x625000060340, event=<optimized out>, me=0x6120000adec0) at Group.cpp:143
#4  _FUN(GtkWidget*, GdkEventCrossing*, Group*) () at Group.cpp:143
#5  0x00007ffff6e3df78 in _gtk_marshal_BOOLEAN__BOXED (closure=0x6070002d9cb0, return_value=0x7fffffffdb20, n_param_values=<optimized out>, param_values=0x7fffffffdb80, invocation_hint=<optimized out>, marshal_data=<optimized out>) at gtk/gtkmarshalers.c:84
#6  0x00007ffff6954d8f in g_closure_invoke () at /usr/lib/libgobject-2.0.so.0
#7  0x00007ffff6970718 in  () at /usr/lib/libgobject-2.0.so.0
#8  0x00007ffff697140b in g_signal_emit_valist () at /usr/lib/libgobject-2.0.so.0
#9  0x00007ffff6972330 in g_signal_emit () at /usr/lib/libgobject-2.0.so.0
#10 0x00007ffff70fe295 in gtk_widget_event_internal.part.0.lto_priv.0 (widget=0x625000060340, event=0x62100000bda0) at ../gtk/gtk/gtkwidget.c:7812
#11 0x00007ffff6f9bcce in gtk_main_do_event (event=<optimized out>) at ../gtk/gtk/gtkmain.c:1928
#12 gtk_main_do_event (event=<optimized out>) at ../gtk/gtk/gtkmain.c:1691
#13 0x00007ffff6cffd43 in _gdk_event_emit (event=0x62100000bda0) at ../gtk/gdk/gdkevents.c:73
#14 _gdk_event_emit (event=0x62100000bda0) at ../gtk/gdk/gdkevents.c:67
#15 0x00007ffff6d4c2d8 in gdk_event_source_dispatch.lto_priv () at ../gtk/gdk/x11/gdkeventsource.c:351
#16 0x00007ffff68474dc in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#17 0x00007ffff689b799 in  () at /usr/lib/libglib-2.0.so.0
#18 0x00007ffff6846a63 in g_main_loop_run () at /usr/lib/libglib-2.0.so.0
#19 0x00007ffff6f91b4f in gtk_main () at ../gtk/gtk/gtkmain.c:1329
#20 0x000055555555b497 in main (argc=7, argv=0x7fffffffe318) at main.c:432

The line points to the g_signal_connect(G_OBJECT(mButton), "enter-notify-event", …) macro invocation (not method body) in Group.cpp:143.

Ctrl+drag warnings, timeouts, and crashes

When I ctrl+drag an icon, it seems xfce4-panel and wrapper-2.0 share responsibility handling the drag operation.

Every time I move my mouse outside the Docklike widget, I get (xfce4-panel:251979): Gtk-CRITICAL **: 16:43:34.496: gtk_widget_destroy: assertion 'GTK_IS_WIDGET (widget)' failed.

If I end a ctrl+drag within Docklike, 300 seconds after I release the left mouse button, I get a call to gtk_drag_abort_timeout. I've never been able to reproduce this crash, but I have 1 or 2 coredumps of a segfault at gtk_drag_abort_timeout > gtk_drag_drop_finished(...result=GTK_DRAG_RESULT_TIMEOUT_EXPIRED...) > gtk_drag_finish, bringing down xfce4-panel and forcing it to restart. I don't know why the segfault happens, since I can't reproduce the crash. It might be a use-after-free in GTK3 or xfce4-panel (or docklike?).

I recompiled GTK3 with a 3 second timeout. When the timeout expires, I get a gtk_widget_destroy: assertion 'GTK_IS_WIDGET (widget)' failed message.

Logging

I recompiled system GTK3 with extra logging statements added to certain functions. To differentiate logging prints from xfce4-panel and wrapper-2.0, I attached gdb instances to xfce4-panel and wrapper-2.0 (be sure to make your breakpoints resume execution by itself, otherwise Xorg will hang until you kill gdb from TTY!). I edited my ~/.gdbinit to add auto-resuming breakpoints (used as log func_name and sleep func_name):

define log
	b $arg0
	commands
		c
	end
end

define sleep
	b $arg0
	commands
		shell sleep 1
		c
	end
end

Initiate a drag:

  • plugin: gtk_drag_begin_internal
  • plugin: gtk_drag_get_source_info(create=TRUE)
  • plugin: gtk_drag_get_source_info(create=FALSE)
  • panel: gtk_drag_proxy_begin
  • panel: gtk_drag_get_source_info(create=TRUE)
  • both: gtk_drag_get_source_info...
  • Both the plugin and panel call gtk_drag_get_source_info(create=FALSE) as you move your mouse.

Mouse exits Docklike widget:

  • panel: gtk_drag_source_info_destroy
  • panel: gtk_drag_clear_source_info
  • (xfce4-panel:240001): Gtk-CRITICAL **: 15:48:54.314: gtk_widget_destroy: assertion 'GTK_IS_WIDGET (widget)' failed

I theorize both calls (and possibly the message) arise from static void gtk_drag_dest_leave in GTK3.

Release left mouse button outside the widget:

  • plugin: gtk_drag_source_info_destroy
  • plugin: gtk_drag_clear_source_info

Note that "Mouse exits widget" does not block "Release left mouse button". If you add a 1-second delay to "panel: gtk_drag_source_info_destroy", then release the left mouse button during the delay, "plugin: gtk_drag_source_info_destroy" is printed immediately, before the delay completes and "panel: gtk_drag_source_info_destroy" is printed.


Initiate a drag:

  • plugin: gtk_drag_begin_internal
  • plugin: gtk_drag_get_source_info(create=TRUE)
  • plugin: gtk_drag_get_source_info(create=FALSE)
  • panel: gtk_drag_proxy_begin
  • panel: gtk_drag_get_source_info(create=TRUE)
  • both: gtk_drag_get_source_info...

Drag icon onto itself:

  • plugin: gtk_drag_drop
  • panel: gtk_drag_dest_drop
  • panel: gtk_drag_drop
  • plugin: gtk_drag_dest_drop
  • plugin: Group::onDragDataReceived
    • Each of these 5 lines comes before the next one. If I add breakpoints with 1-second pauses ((gdb) sleep gtk_drag_drop and sleep gtk_drag_dest_drop) in the panel and plugin, then the plugin hits gtk_drag_drop first, then the panel hits both breakpoints, then the plugin hits gtk_drag_dest_drop, with a 1-second delay each time.
    • gtk_drag_drop starts a 300 second timeout to call gtk_drag_abort_timeout, stored in info->drop_timeout. This timer is cancelled by gtk_drag_source_info_destroy.
  • plugin: gtk_drag_finish(del=1)
  • plugin: gtk_drag_finish(del=0)
    • If I make Group::onDragDataReceived call gtk_drag_finish(context, TRUE, TRUE, time), I get another two calls to gtk_drag_finish with del=1 and del=0.

[300 seconds later]

  • plugin: gtk_drag_abort_timeout (and gtk_drag_drop_finished at some point)
  • plugin: gtk_drag_drop_finished
  • plugin: gtk_drag_source_info_destroy
  • plugin: gtk_drag_clear_source_info
  • panel: gtk_drag_abort_timeout
  • panel: gtk_drag_drop_finished
  • panel: gtk_drag_source_info_destroy
  • panel: gtk_drag_clear_source_info
    • Both processes hit their gtk_drag_abort_timeout timeouts separately and simultaneously.
  • panel: (xfce4-panel:251979): Gtk-CRITICAL **: 15:56:47.183: gtk_widget_destroy: assertion 'GTK_IS_WIDGET (widget)' failed

Maybe there's a call to gtk_drag_finish before gtk_drag_source_info_destroy. I'm not seeing it now with unmodified Docklike; maybe it only happens when I make Group::onDragDataReceived call gtk_drag_finish(context, TRUE, TRUE, time).

Sorry for not capturing the call stacks of all function calls. I'm scared of locking up my X session. If necessary I could rerun my tests and add an extra bt command to my log gdb command.

The issue?

I rebuilt Docklike to call gtk_drag_finish(context, TRUE, TRUE, time) in Group::onDragDataReceived(). Apparently it doesn't call gtk_drag_source_info_destroy in either the plugin or the panel, producing a dangling drag operation in both processes, waiting for who knows what. Now gtk_drag_finish is called 4 times in the plugin process when I drag an icon onto itself... and 0 times in the panel, until the 3 (or 300) second timeout expires.

I don't know if this project is using gtk_drag_* correctly, and I don't know how to properly use drags. I'm unsure if https://wiki.gnome.org/Newcomers/OldDragNDropTutorial is still a good tutorial. Or perhaps xfce4-panel's multi-process architecture, and proxying drags incorrectly between the plugin and panel, is the problem. I'm not sure; I don't know any other plugins with drag-and-drop functionality.

Why doesn't gtk_drag_finish call gtk_drag_drop_finished (which would call gtk_drag_source_info_destroy)? Maybe it's _gtk_drag_source_handle_event that should call it. Maybe I should add more debug prints into GTK3.

Properly functioning drag and drop

In gtk3-demo, Icon View -> Editing and Drag-and-Drop, gtk_drag_drop_finished doesn't get called (at least gdb's breakpoint doesn't trip). But gtk_drag_source_info_destroy does.

#0  gtk_drag_source_info_destroy (info=0x555555a35fe0) at /usr/include/bits/stdio2.h:105
#1  0x00007ffff757c1c0 in g_signal_emit_valist () at /usr/lib/libgobject-2.0.so.0
#2  0x00007ffff757c55a in g_signal_emit_by_name () at /usr/lib/libgobject-2.0.so.0
#3  0x00007ffff7764c3a in gdk_dnd_handle_drop_finished (event=<optimized out>, event=0x555555b44500, context=0x555555ce72e0) at ../gtk/gdk/x11/gdkdnd-x11.c:3132
#4  gdk_x11_drag_context_handle_event (event=0x555555b44500, context=0x555555ce72e0) at ../gtk/gdk/x11/gdkdnd-x11.c:3162
#5  gdk_x11_drag_context_handle_event (context=0x555555ce72e0, event=0x555555b44500) at ../gtk/gdk/x11/gdkdnd-x11.c:3138
#6  0x00007ffff7718d1e in gdk_drag_context_handle_source_event (event=0x555555b44500) at ../gtk/gdk/gdkdnd.c:748
#7  _gdk_event_emit (event=0x555555b44500) at ../gtk/gdk/gdkevents.c:69
#8  0x00007ffff77652d8 in gdk_event_source_dispatch.lto_priv () at ../gtk/gdk/x11/gdkeventsource.c:351
#9  0x00007ffff75fa4dc in g_main_context_dispatch () at /usr/lib/libglib-2.0.so.0
#10 0x00007ffff764e799 in  () at /usr/lib/libglib-2.0.so.0
#11 0x00007ffff75f7bc1 in g_main_context_iteration () at /usr/lib/libglib-2.0.so.0
#12 0x00007ffff74632fe in g_application_run () at /usr/lib/libgio-2.0.so.0
#13 0x00005555555711e2 in main (argc=1, argv=0x7fffffffe4d8) at ../gtk/demos/gtk-demo/main.c:1208

"Editing and Drag-and-Drop" (gtk3/demos/gtk-demo/iconview_edit.c) lets GTK3 handle drag-and-drop (using gtk_icon_view_set_reorderable) rather than implementing the events itself. Is this practical in docklike?

Somehow gdk_dnd_handle_drop_finished can be breakpointed in gtk3-demo but not xfce4-panel or wrapper-2.0. So I think we can't use the icon view as a guide for how drag-and-drop should work in panel plugins.