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
This commit is contained in:
Owen W. Taylor 2012-09-18 09:00:57 -04:00
parent 77bac0d6ae
commit 7753883add
5 changed files with 71 additions and 38 deletions

View File

@ -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);

View File

@ -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); */
};

View File

@ -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)
{

View File

@ -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

View File

@ -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);
}
}