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
andsleep 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 ininfo->drop_timeout
. This timer is cancelled bygtk_drag_source_info_destroy
.
- Each of these 5 lines comes before the next one. If I add breakpoints with 1-second pauses (
- plugin: gtk_drag_finish(del=1)
- plugin: gtk_drag_finish(del=0)
- If I make
Group::onDragDataReceived
callgtk_drag_finish(context, TRUE, TRUE, time)
, I get another two calls togtk_drag_finish
with del=1 and del=0.
- If I make
[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.