#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtksizerequest.h"
+#include "gtksizerequestcacheprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkwindow.h"
#include "gtkassistant.h"
{
GtkWidget *focus_child;
+ guint resize_handler;
+ GdkFrameClock *resize_clock;
+
guint border_width : 16;
guint has_focus_chain : 1;
guint reallocate_redraws : 1;
+ guint resize_pending : 1;
+ guint restyle_pending : 1;
guint resize_mode : 2;
guint request_mode : 2;
};
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 guint container_signals[LAST_SIGNAL] = { 0 };
static GtkWidgetClass *parent_class = NULL;
extern GParamSpecPool *_gtk_widget_child_property_pool;
GtkContainer *container = GTK_CONTAINER (widget);
GtkContainerPrivate *priv = container->priv;
- if (_gtk_widget_get_resize_pending (GTK_WIDGET (container)))
+ if (priv->resize_pending)
_gtk_container_dequeue_resize_handler (container);
+ if (priv->restyle_pending)
+ priv->restyle_pending = FALSE;
+
if (priv->focus_child)
{
g_object_unref (priv->focus_child);
_gtk_container_dequeue_resize_handler (GtkContainer *container)
{
g_return_if_fail (GTK_IS_CONTAINER (container));
- g_return_if_fail (_gtk_widget_get_resize_pending (GTK_WIDGET (container)));
+ g_return_if_fail (container->priv->resize_pending);
- container_resize_queue = g_slist_remove (container_resize_queue, container);
- _gtk_widget_set_resize_pending (GTK_WIDGET (container), FALSE);
+ container->priv->resize_pending = FALSE;
}
/**
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,
+ * because both style_updated and size_allocate functions often change
+ * styles and so could cause infinite loops in this function.
+ *
+ * It's important to note that even an invalid style context returns
+ * sane values. So the result of an invalid style context will never be
+ * a program crash, but only a wrong layout or rendering.
+ */
+ if (container->priv->restyle_pending)
+ {
+ 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)),
+ current_time,
+ 0,
+ empty);
+
+ _gtk_bitmask_free (empty);
+ }
/* we may be invoked with a container_resize_queue of NULL, because
* queue_resize could have been adding an extra idle function while
* than trying to explicitely work around them with some extra flags,
* since it doesn't cause any actual harm.
*/
-
- /* 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,
- * because size_allocate functions often change styles and so could
- * cause infinite loops in this function.
- */
- current_time = g_get_monotonic_time ();
- for (slist = container_resize_queue; slist; slist = slist->next)
+ if (container->priv->resize_pending)
{
- _gtk_style_context_validate (gtk_widget_get_style_context (slist->data),
- current_time,
- 0);
+ container->priv->resize_pending = FALSE;
+ gtk_container_check_resize (container);
}
- while (container_resize_queue)
+ if (!container->priv->restyle_pending && !container->priv->resize_pending)
+ {
+ _gtk_container_stop_idle_sizer (container);
+ }
+ else
{
- GtkWidget *widget;
+ gdk_frame_clock_request_phase (clock,
+ GDK_FRAME_CLOCK_PHASE_LAYOUT);
+ }
+}
- slist = container_resize_queue;
- container_resize_queue = slist->next;
- widget = slist->data;
- g_slist_free_1 (slist);
+static void
+gtk_container_start_idle_sizer (GtkContainer *container)
+{
+ GdkFrameClock *clock;
- _gtk_widget_set_resize_pending (widget, FALSE);
- gtk_container_check_resize (GTK_CONTAINER (widget));
- }
+ if (container->priv->resize_handler != 0)
+ return;
- gdk_window_process_all_updates ();
+ clock = gtk_widget_get_frame_clock (GTK_WIDGET (container));
+ if (clock == NULL)
+ return;
- return FALSE;
+ 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_phase (clock,
+ GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
void
-_gtk_container_queue_resize_handler (GtkContainer *container)
+_gtk_container_stop_idle_sizer (GtkContainer *container)
+{
+ if (container->priv->resize_handler == 0)
+ return;
+
+ g_signal_handler_disconnect (container->priv->resize_clock,
+ container->priv->resize_handler);
+ container->priv->resize_handler = 0;
+ container->priv->resize_clock = NULL;
+}
+
+static void
+gtk_container_queue_resize_handler (GtkContainer *container)
{
GtkWidget *widget;
switch (container->priv->resize_mode)
{
case GTK_RESIZE_QUEUE:
- if (!_gtk_widget_get_resize_pending (widget))
+ if (!container->priv->resize_pending)
{
- _gtk_widget_set_resize_pending (widget, TRUE);
- if (container_resize_queue == NULL)
- gdk_threads_add_idle_full (GTK_PRIORITY_RESIZE,
- gtk_container_idle_sizer,
- NULL, NULL);
- container_resize_queue = g_slist_prepend (container_resize_queue, container);
+ container->priv->resize_pending = TRUE;
+ gtk_container_start_idle_sizer (container);
}
break;
case GTK_RESIZE_IMMEDIATE:
- _gtk_style_context_validate (gtk_widget_get_style_context (widget),
- g_get_monotonic_time (),
- 0);
gtk_container_check_resize (container);
+ break;
case GTK_RESIZE_PARENT:
default:
do
{
_gtk_widget_set_alloc_needed (widget, TRUE);
- _gtk_widget_set_width_request_needed (widget, TRUE);
- _gtk_widget_set_height_request_needed (widget, TRUE);
+ _gtk_size_request_cache_clear (_gtk_widget_peek_request_cache (widget));
if (GTK_IS_RESIZE_CONTAINER (widget))
break;
while (widget);
if (widget && !invalidate_only)
- _gtk_container_queue_resize_handler (GTK_CONTAINER (widget));
+ gtk_container_queue_resize_handler (GTK_CONTAINER (widget));
+}
+
+void
+_gtk_container_queue_restyle (GtkContainer *container)
+{
+ GtkContainerPrivate *priv;
+
+ g_return_if_fail (GTK_CONTAINER (container));
+
+ priv = container->priv;
+
+ if (priv->restyle_pending)
+ return;
+
+ gtk_container_start_idle_sizer (container);
+ priv->restyle_pending = TRUE;
}
/**
_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)
{
container = GTK_CONTAINER (widget);
- if (!GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width)
+ if (GTK_CONTAINER_GET_CLASS (widget)->_handle_border_width)
{
- parent_class->adjust_size_allocation (widget, orientation,
- minimum_size, natural_size, allocated_pos,
- allocated_size);
- return;
- }
-
- border_width = container->priv->border_width;
-
- *allocated_size -= border_width * 2;
-
- /* If we get a pathological too-small allocation to hold
- * even the border width, leave all allocation to the actual
- * widget, and leave x,y unchanged. (GtkWidget's min size is
- * 1x1 if you're wondering why <1 and not <0)
- *
- * As long as we have space, set x,y properly.
- */
+ border_width = container->priv->border_width;
- if (*allocated_size < 1)
- {
- *allocated_size += border_width * 2;
- }
- else
- {
+ *allocated_size -= border_width * 2;
*allocated_pos += border_width;
*minimum_size -= border_width * 2;
*natural_size -= border_width * 2;
static GtkSizeRequestMode
gtk_container_get_request_mode (GtkWidget *widget)
{
- GtkContainer *container = GTK_CONTAINER (widget);
- GtkContainerPrivate *priv = container->priv;
-
- /* Recalculate the request mode of the children by majority
- * vote whenever the internal content changes */
- if (_gtk_widget_get_width_request_needed (widget) ||
- _gtk_widget_get_height_request_needed (widget))
- {
- RequestModeCount count = { 0, 0 };
-
- gtk_container_forall (container, (GtkCallback)count_request_modes, &count);
+ GtkContainer *container = GTK_CONTAINER (widget);
+ RequestModeCount count = { 0, 0 };
- if (!count.hfw && !count.wfh)
- priv->request_mode = GTK_SIZE_REQUEST_CONSTANT_SIZE;
- else
- priv->request_mode = count.wfh > count.hfw ?
- GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
- GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
- }
+ gtk_container_forall (container, (GtkCallback)count_request_modes, &count);
- return priv->request_mode;
+ if (!count.hfw && !count.wfh)
+ return GTK_SIZE_REQUEST_CONSTANT_SIZE;
+ else
+ return count.wfh > count.hfw ?
+ GTK_SIZE_REQUEST_WIDTH_FOR_HEIGHT :
+ GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
}
/**