From 6475376931bf316a4fd791114408f7c1fc2fe836 Mon Sep 17 00:00:00 2001 From: Paul Cornett Date: Wed, 2 Nov 2016 10:30:44 -0700 Subject: [PATCH] Fix some sizing problems with GTK3 A change in size-allocate handling with GTK+ 3.20 exposed a flaw in our method for deferring queue-resize requests. Using an idle callback to process the requests did not work well with the GdkFrameClock-based system used since GTK+ 3.8. Using the "check-resize" signal works better. Also with GTK+ >= 3.20, it seems necessary to manually work the queue-resize up to the TLW, as otherwise the resized widgets don't get updated without an external size-allocate event. See #17585 (backport of 3b4ee5a031b1c2fa29772b90751a82dd7f1d3de0) --- src/gtk/window.cpp | 102 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 26 deletions(-) diff --git a/src/gtk/window.cpp b/src/gtk/window.cpp index d27f889..ab56baa 100644 --- a/src/gtk/window.cpp +++ b/src/gtk/window.cpp @@ -221,6 +221,8 @@ int g_lastButtonNumber = 0; #ifdef __WXGTK3__ static GList* gs_sizeRevalidateList; +static GSList* gs_queueResizeList; +static bool gs_inSizeAllocate; void wxGTKSizeRevalidate(wxWindow*); #endif @@ -2083,6 +2085,54 @@ static void frame_clock_layout(GdkFrameClock*, wxWindow* win) } #endif // GTK_CHECK_VERSION(3,8,0) +#ifdef __WXGTK3__ +//----------------------------------------------------------------------------- +// "check-resize" +//----------------------------------------------------------------------------- + +static void check_resize(GtkContainer*, wxWindow*) +{ + gs_inSizeAllocate = true; +} + +static void check_resize_after(GtkContainer*, wxWindow*) +{ + gs_inSizeAllocate = false; + if (gs_queueResizeList) + { + for (GSList* p = gs_queueResizeList; p; p = p->next) + { + if (p->data == NULL) + continue; + + wxWindowGTK* w = static_cast(p->data); + g_object_remove_weak_pointer(G_OBJECT(w->m_widget), &p->data); + gtk_widget_set_size_request(w->m_widget, w->m_width, w->m_height); + + // in case only the position is changing + gtk_widget_queue_resize(w->m_widget); + + // need to force the queue-resize up to the TLW with GTK >= 3.20 + if (gtk_check_version(3,20,0) == NULL) + { + GtkWidget* widget = w->m_widget; + for (;;) + { + widget = gtk_widget_get_parent(widget); + if (widget == NULL) + break; + gtk_widget_queue_resize(widget); + if (gtk_widget_is_toplevel(widget)) + break; + } + } + } + g_slist_free(gs_queueResizeList); + gs_queueResizeList = NULL; + } +} +#endif // __WXGTK3__ + } // extern "C" void wxWindowGTK::GTKHandleRealized() @@ -2670,6 +2720,13 @@ void wxWindowGTK::PostCreation() g_signal_connect(m_wxwindow ? m_wxwindow : m_widget, "size_allocate", G_CALLBACK(size_allocate), this); } +#ifdef __WXGTK3__ + else + { + g_signal_connect(m_widget, "check-resize", G_CALLBACK(check_resize), this); + g_signal_connect_after(m_widget, "check-resize", G_CALLBACK(check_resize_after), this); + } +#endif #if GTK_CHECK_VERSION(2, 8, 0) #ifndef __WXGTK3__ @@ -2778,46 +2835,39 @@ void wxWindowGTK::ConnectWidget( GtkWidget *widget ) G_CALLBACK (gtk_window_leave_callback), this); } -static GSList* gs_queueResizeList; - -extern "C" { -static gboolean queue_resize(void*) -{ - gdk_threads_enter(); - for (GSList* p = gs_queueResizeList; p; p = p->next) - { - if (p->data) - { - gtk_widget_queue_resize(GTK_WIDGET(p->data)); - g_object_remove_weak_pointer(G_OBJECT(p->data), &p->data); - } - } - g_slist_free(gs_queueResizeList); - gs_queueResizeList = NULL; - gdk_threads_leave(); - return false; -} -} - void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height) { - gtk_widget_set_size_request(m_widget, width, height); GtkWidget* parent = gtk_widget_get_parent(m_widget); if (WX_IS_PIZZA(parent)) + { WX_PIZZA(parent)->move(m_widget, x, y, width, height); + if ( +#ifdef __WXGTK3__ + !gs_inSizeAllocate && +#endif + gtk_widget_get_visible(m_widget)) + { + // in case only the position is changing + gtk_widget_queue_resize(m_widget); + } + } +#ifdef __WXGTK3__ // With GTK3, gtk_widget_queue_resize() is ignored while a size-allocate // is in progress. This situation is common in wxWidgets, since // size-allocate can generate wxSizeEvent and size event handlers often // call SetSize(), directly or indirectly. Work around this by deferring // the queue-resize until after size-allocate processing is finished. - if (g_slist_find(gs_queueResizeList, m_widget) == NULL) + if (!gs_inSizeAllocate || !gtk_widget_get_visible(m_widget)) + gtk_widget_set_size_request(m_widget, width, height); + else { - if (gs_queueResizeList == NULL) - g_idle_add_full(GTK_PRIORITY_RESIZE, queue_resize, NULL, NULL); - gs_queueResizeList = g_slist_prepend(gs_queueResizeList, m_widget); + gs_queueResizeList = g_slist_prepend(gs_queueResizeList, this); g_object_add_weak_pointer(G_OBJECT(m_widget), &gs_queueResizeList->data); } +#else // !__WXGTK3__ + gtk_widget_set_size_request(m_widget, width, height); +#endif // !__WXGTK3__ } void wxWindowGTK::ConstrainSize()