From 7753883add412a4bbc6b49b9bc7ef037c5a34c36 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Tue, 18 Sep 2012 09:00:57 -0400 Subject: [PATCH] Use GdkFrameClock for relayout Add a ::layout signal to GdkFrameClock and use it instead of an idle handler to drive the restyling and relayout of containers. https://bugzilla.gnome.org/show_bug.cgi?id=685460 --- gdk/gdkframeclock.c | 21 ++++++++++ gdk/gdkframeclock.h | 1 + gtk/gtkcontainer.c | 83 +++++++++++++++++++++------------------ gtk/gtkcontainerprivate.h | 1 + gtk/gtkwidget.c | 3 ++ 5 files changed, 71 insertions(+), 38 deletions(-) diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c index 6b23ce6321..ca5484080d 100644 --- a/gdk/gdkframeclock.c +++ b/gdk/gdkframeclock.c @@ -79,6 +79,7 @@ G_DEFINE_INTERFACE (GdkFrameClock, gdk_frame_clock, G_TYPE_OBJECT) enum { FRAME_REQUESTED, BEFORE_PAINT, + LAYOUT, PAINT, AFTER_PAINT, LAST_SIGNAL @@ -122,6 +123,23 @@ gdk_frame_clock_default_init (GdkFrameClockInterface *iface) g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); + /** + * GdkFrameClock::layout: + * @clock: the frame clock emitting the signal + * + * This signal is emitted immediately before the paint signal and + * indicates that the frame time has been updated, and signal + * handlers should perform any preparatory work before painting. + */ + signals[LAYOUT] = + g_signal_new (g_intern_static_string ("layout"), + GDK_TYPE_FRAME_CLOCK, + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /** * GdkFrameClock::paint: * @clock: the frame clock emitting the signal @@ -279,6 +297,9 @@ gdk_frame_clock_paint (GdkFrameClock *clock) g_signal_emit (G_OBJECT (clock), signals[BEFORE_PAINT], 0); + g_signal_emit (G_OBJECT (clock), + signals[LAYOUT], 0); + g_signal_emit (G_OBJECT (clock), signals[PAINT], 0); diff --git a/gdk/gdkframeclock.h b/gdk/gdkframeclock.h index 62124e2e7d..043a890514 100644 --- a/gdk/gdkframeclock.h +++ b/gdk/gdkframeclock.h @@ -54,6 +54,7 @@ struct _GdkFrameClockInterface /* signals */ /* void (* frame_requested) (GdkFrameClock *clock); */ /* void (* before_paint) (GdkFrameClock *clock); */ + /* void (* layout) 1(GdkFrameClock *clock); */ /* void (* paint) (GdkFrameClock *clock); */ /* void (* after_paint) (GdkFrameClock *clock); */ }; diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index 4377a5f683..938887ea14 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -236,6 +236,9 @@ struct _GtkContainerPrivate { GtkWidget *focus_child; + guint resize_handler; + GdkFrameClock *resize_clock; + guint border_width : 16; guint has_focus_chain : 1; @@ -344,8 +347,6 @@ static const gchar vadjustment_key[] = "gtk-vadjustment"; static guint vadjustment_key_id = 0; static const gchar hadjustment_key[] = "gtk-hadjustment"; static guint hadjustment_key_id = 0; -static GSList *container_resize_queue = NULL; -static GSList *container_restyle_queue = NULL; static guint container_signals[LAST_SIGNAL] = { 0 }; static GtkWidgetClass *parent_class = NULL; extern GParamSpecPool *_gtk_widget_child_property_pool; @@ -1357,10 +1358,15 @@ gtk_container_destroy (GtkWidget *widget) if (priv->resize_pending) _gtk_container_dequeue_resize_handler (container); + if (priv->restyle_pending) + priv->restyle_pending = FALSE; + + if (priv->resize_handler) { - container_restyle_queue = g_slist_remove (container_restyle_queue, container); - priv->restyle_pending = FALSE; + g_signal_handler_disconnect (priv->resize_clock, priv->resize_handler); + priv->resize_handler = 0; + priv->resize_clock = NULL; } if (priv->focus_child) @@ -1553,7 +1559,6 @@ _gtk_container_dequeue_resize_handler (GtkContainer *container) g_return_if_fail (GTK_IS_CONTAINER (container)); g_return_if_fail (container->priv->resize_pending); - container_resize_queue = g_slist_remove (container_resize_queue, container); container->priv->resize_pending = FALSE; } @@ -1630,12 +1635,10 @@ gtk_container_set_reallocate_redraws (GtkContainer *container, container->priv->reallocate_redraws = needs_redraws ? TRUE : FALSE; } -static gboolean -gtk_container_idle_sizer (gpointer data) +static void +gtk_container_idle_sizer (GdkFrameClock *clock, + GtkContainer *container) { - GSList *slist; - gint64 current_time; - /* We validate the style contexts in a single loop before even trying * to handle resizes instead of doing validations inline. * This is mostly necessary for compatibility reasons with old code, @@ -1646,16 +1649,13 @@ gtk_container_idle_sizer (gpointer data) * sane values. So the result of an invalid style context will never be * a program crash, but only a wrong layout or rendering. */ - current_time = g_get_monotonic_time (); - slist = container_restyle_queue; - container_restyle_queue = NULL; - while (slist) + if (container->priv->restyle_pending) { - GSList *next = slist->next; - GtkContainer *container = slist->data; GtkBitmask *empty; + gint64 current_time; empty = _gtk_bitmask_new (); + current_time = g_get_monotonic_time (); container->priv->restyle_pending = FALSE; _gtk_style_context_validate (gtk_widget_get_style_context (GTK_WIDGET (container)), @@ -1663,8 +1663,6 @@ gtk_container_idle_sizer (gpointer data) 0, empty); - g_slist_free_1 (slist); - slist = next; _gtk_bitmask_free (empty); } @@ -1674,35 +1672,40 @@ gtk_container_idle_sizer (gpointer data) * than trying to explicitely work around them with some extra flags, * since it doesn't cause any actual harm. */ - while (container_resize_queue) + if (container->priv->resize_pending) { - GtkContainer *container; - - slist = container_resize_queue; - container_resize_queue = slist->next; - container = slist->data; - g_slist_free_1 (slist); - container->priv->resize_pending = FALSE; gtk_container_check_resize (container); } - gdk_window_process_all_updates (); - - return container_resize_queue != NULL || container_restyle_queue != NULL; + if (!container->priv->restyle_pending && !container->priv->resize_pending) + { + g_signal_handler_disconnect (clock, container->priv->resize_handler); + container->priv->resize_handler = 0; + container->priv->resize_clock = NULL; + } + else + { + gdk_frame_clock_request_frame (clock); + } } static void gtk_container_start_idle_sizer (GtkContainer *container) { - /* already started */ - if (container_resize_queue != NULL || - container_restyle_queue != NULL) + GdkFrameClock *clock; + + if (container->priv->resize_handler != 0) return; - gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE, - gtk_container_idle_sizer, - NULL, NULL); + clock = gtk_widget_get_frame_clock (GTK_WIDGET (container)); + if (clock == NULL) + return; + + container->priv->resize_clock = clock; + container->priv->resize_handler = g_signal_connect (clock, "layout", + G_CALLBACK (gtk_container_idle_sizer), container); + gdk_frame_clock_request_frame (clock); } static void @@ -1725,7 +1728,6 @@ gtk_container_queue_resize_handler (GtkContainer *container) { container->priv->resize_pending = TRUE; gtk_container_start_idle_sizer (container); - container_resize_queue = g_slist_prepend (container_resize_queue, container); } break; @@ -1780,8 +1782,6 @@ _gtk_container_queue_restyle (GtkContainer *container) return; gtk_container_start_idle_sizer (container); - - container_restyle_queue = g_slist_prepend (container_restyle_queue, container); priv->restyle_pending = TRUE; } @@ -1815,6 +1815,13 @@ _gtk_container_resize_invalidate (GtkContainer *container) _gtk_container_queue_resize_internal (container, TRUE); } +void +_gtk_container_maybe_start_idle_sizer (GtkContainer *container) +{ + if (container->priv->restyle_pending || container->priv->resize_pending) + gtk_container_start_idle_sizer (container); +} + void gtk_container_check_resize (GtkContainer *container) { diff --git a/gtk/gtkcontainerprivate.h b/gtk/gtkcontainerprivate.h index f12148bb4f..cd4bc5b2e9 100644 --- a/gtk/gtkcontainerprivate.h +++ b/gtk/gtkcontainerprivate.h @@ -39,6 +39,7 @@ GList * _gtk_container_focus_sort (GtkContainer *container, GtkWidget *old_focus); gboolean _gtk_container_get_reallocate_redraws (GtkContainer *container); +void _gtk_container_maybe_start_idle_sizer (GtkContainer *container); G_END_DECLS diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index a3509c4cc7..e1cf124f68 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -4585,6 +4585,9 @@ gtk_widget_realize (GtkWidget *widget) _gtk_widget_enable_device_events (widget); gtk_widget_update_devices_mask (widget, TRUE); + if (GTK_IS_CONTAINER (widget)) + _gtk_container_maybe_start_idle_sizer (GTK_CONTAINER (widget)); + gtk_widget_pop_verify_invariants (widget); } }