Issue #11613: crashing when freeing window handle.

It is a tentative fix as I had this crash once but could not reproduce
it, even redoing dozens of times the same thing I had done.

It is mostly based on something which GDK docs of
gdk_wayland_window_export_handle() says:

> To unexport the window, gdk_wayland_window_unexport_handle() must be
> called the same number of times as gdk_wayland_window_export_handle()
> was called. Any 'exported' callback may still be invoked until the
> window is unexported or destroyed.

So when the GdkWindow of the widget still exists, let's make sure we
call gdk_wayland_window_unexport_handle() as many times as necessary (no
less, but also no more!), and also that we disconnect all handlers which
could possibly call more export_handle().
This commit is contained in:
Jehan 2025-10-23 18:59:04 +02:00
parent b879deb323
commit 0ff960c45b

View file

@ -1194,15 +1194,40 @@ void
gimp_widget_free_native_handle (GtkWidget *widget,
GBytes **window_handle)
{
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
#ifdef GDK_WINDOWING_WAYLAND
GdkWindow *surface;
#endif
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (window_handle != NULL);
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ()) &&
/* The GdkWindow is likely already destroyed. */
gtk_widget_get_window (widget) != NULL)
gdk_wayland_window_unexport_handle (gtk_widget_get_window (widget));
#endif
g_signal_handlers_disconnect_by_func (toplevel,
G_CALLBACK (gimp_widget_set_handle_on_mapped),
window_handle);
g_signal_handlers_disconnect_by_func (widget,
G_CALLBACK (gimp_widget_set_handle_on_mapped),
window_handle);
g_signal_handlers_disconnect_by_func (widget,
G_CALLBACK (gimp_widget_set_handle_on_realize),
window_handle);
#ifdef GDK_WINDOWING_WAYLAND
surface = gtk_widget_get_window (widget);
if (surface != NULL && GDK_IS_WAYLAND_WINDOW (surface))
{
gint count;
count = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (surface),
"gimp_widget_set_handle_on_mapped-call-count"));
g_object_set_data (G_OBJECT (surface),
"gimp_widget_set_handle_on_mapped-call-count",
NULL);
while (count--)
gdk_wayland_window_unexport_handle (surface);
}
#endif
g_clear_pointer (window_handle, g_bytes_unref);
}
@ -1356,6 +1381,15 @@ gimp_widget_set_handle_on_mapped (GtkWidget *widget,
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_WINDOW (surface))
{
gint count;
count = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (surface),
"gimp_widget_set_handle_on_mapped-call-count"));
count += 1;
g_object_set_data (G_OBJECT (surface),
"gimp_widget_set_handle_on_mapped-call-count",
GINT_TO_POINTER (count));
/* I don't run this on "realize" event because somehow it locks
* the whole processus in Wayland. The "map-event" happens
* slightly after the window became visible and I didn't