Compare commits

...

3 Commits

Author SHA1 Message Date
Timm Bäder
65317ce335 Delay widget size invalidation until layout phase
Instead of marking widgets as needing a resize or allocate directly
inside queue_resize, only add them to a list of widgets needing a
resize. Delay the actual invalidation (i.e. the old queue_resize call)
until we run the toplevel window's idle sizer.
2018-06-23 12:05:02 +02:00
Timm Bäder
75bfa9b5c5 frameclockidle: Remove layout phase iterations
We will do something similar later in gtk.
2018-06-23 07:51:32 +02:00
Timm Bäder
9ed1e801fe widget: Remove queue_allocate and queue_resize_no_redraw
This will make later stages easier. Maybe they will come back later.
2018-06-23 07:51:29 +02:00
7 changed files with 183 additions and 49 deletions

View File

@@ -414,7 +414,6 @@ gdk_frame_clock_paint_idle (void *data)
case GDK_FRAME_CLOCK_PHASE_LAYOUT:
if (priv->freeze_count == 0)
{
int iter;
#ifdef G_ENABLE_DEBUG
if (GDK_DEBUG_CHECK (FRAMES))
{
@@ -430,15 +429,8 @@ gdk_frame_clock_paint_idle (void *data)
* happen in some situation like races between user window
* resizes and natural size changes.
*/
iter = 0;
while ((priv->requested & GDK_FRAME_CLOCK_PHASE_LAYOUT) &&
priv->freeze_count == 0 && iter++ < 4)
{
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
_gdk_frame_clock_emit_layout (clock);
}
if (iter == 5)
g_warning ("gdk-frame-clock: layout continuously requested, giving up after 4 tries");
priv->requested &= ~GDK_FRAME_CLOCK_PHASE_LAYOUT;
_gdk_frame_clock_emit_layout (clock);
}
/* fallthrough */
case GDK_FRAME_CLOCK_PHASE_PAINT:

View File

@@ -143,12 +143,15 @@
*/
#define MAX_RESIZE_ITERATIONS 2
struct _GtkContainerPrivate
{
guint resize_handler;
guint has_focus_chain : 1;
guint restyle_pending : 1;
guint last_resize_iteration : 1;
};
enum {
@@ -1538,7 +1541,18 @@ gtk_container_needs_idle_sizer (GtkContainer *container)
if (priv->restyle_pending)
return TRUE;
return gtk_widget_needs_allocate (GTK_WIDGET (container));
if (GTK_IS_WINDOW (container))
return gtk_window_get_resize_widgets (GTK_WINDOW (container))->len > 0;
return FALSE;
}
gboolean
gtk_container_in_last_resize_iteration (GtkContainer *container)
{
GtkContainerPrivate *priv = gtk_container_get_instance_private (container);
return priv->last_resize_iteration;
}
static void
@@ -1547,42 +1561,71 @@ gtk_container_idle_sizer (GdkFrameClock *clock,
{
GtkContainerPrivate *priv = gtk_container_get_instance_private (container);
/* 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 (priv->restyle_pending)
if (GTK_IS_WINDOW (container))
{
priv->restyle_pending = FALSE;
gtk_css_node_validate (gtk_widget_get_css_node (GTK_WIDGET (container)));
GPtrArray *resize_widgets = gtk_window_get_resize_widgets (GTK_WINDOW (container));
static int k;
guint resize_iteration;
#if 0
g_message ("=== %d", k++);
#endif
for (resize_iteration = 0; resize_iteration < MAX_RESIZE_ITERATIONS; resize_iteration ++)
{
const gboolean last_iteration = (resize_iteration == MAX_RESIZE_ITERATIONS - 1);
guint i, p;
priv->last_resize_iteration = last_iteration;
/* 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 (priv->restyle_pending)
{
priv->restyle_pending = FALSE;
gtk_css_node_validate (gtk_widget_get_css_node (GTK_WIDGET (container)));
}
for (i = 0, p = resize_widgets->len; i < p; i ++)
{
GtkWidget *w = g_ptr_array_index (resize_widgets, i);
#if 0
g_message (" (%d): %s %s %p", resize_iteration, G_OBJECT_TYPE_NAME (w),
gtk_css_node_get_name (gtk_widget_get_css_node (w)), w);
#endif
gtk_widget_invalidate_size (w);
}
g_ptr_array_remove_range (resize_widgets, 0, p);
/* queue_resize could have been adding an extra idle function while
* the queue still got processed. we better just ignore such case
* than trying to explicitly work around them with some extra flags,
* since it doesn't cause any actual harm.
*/
if (gtk_widget_needs_allocate (GTK_WIDGET (container)))
{
gtk_container_check_resize (container);
}
}
/* Ignore all resize widgets after the last iteration */
g_ptr_array_remove_range (resize_widgets, 0, resize_widgets->len);
}
/* we may be invoked with a container_resize_queue of NULL, because
* queue_resize could have been adding an extra idle function while
* the queue still got processed. we better just ignore such case
* than trying to explicitly work around them with some extra flags,
* since it doesn't cause any actual harm.
*/
if (gtk_widget_needs_allocate (GTK_WIDGET (container)))
{
gtk_container_check_resize (container);
}
if (!gtk_container_needs_idle_sizer (container))
{
gtk_container_stop_idle_sizer (container);
}
else
{
gdk_frame_clock_request_phase (clock,
GDK_FRAME_CLOCK_PHASE_LAYOUT);
}
/* Unconditionally stop the idle sizer, since we are at worst already
* MAX_RESIZE_ITERATIONS into resize territory and we don't want to
* go any further. */
gtk_container_stop_idle_sizer (container);
priv->last_resize_iteration = FALSE;
}
void

View File

@@ -31,6 +31,7 @@ void gtk_container_stop_idle_sizer (GtkContainer *container);
void gtk_container_start_idle_sizer (GtkContainer *container);
void gtk_container_set_focus_child (GtkContainer *container,
GtkWidget *child);
gboolean gtk_container_in_last_resize_iteration (GtkContainer *container);
G_END_DECLS

View File

@@ -3870,10 +3870,13 @@ gtk_widget_queue_allocate (GtkWidget *widget)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
#if 0
if (_gtk_widget_get_realized (widget))
gtk_widget_queue_draw (widget);
gtk_widget_set_alloc_needed (widget);
#endif
gtk_widget_queue_resize (widget);
}
static inline gboolean
@@ -3922,6 +3925,15 @@ gtk_widget_queue_resize_internal (GtkWidget *widget)
}
}
void
gtk_widget_invalidate_size (GtkWidget *widget)
{
if (_gtk_widget_get_realized (widget))
gtk_widget_queue_draw (widget);
gtk_widget_queue_resize_internal (widget);
}
/**
* gtk_widget_queue_resize:
* @widget: a #GtkWidget
@@ -3940,12 +3952,42 @@ gtk_widget_queue_resize_internal (GtkWidget *widget)
void
gtk_widget_queue_resize (GtkWidget *widget)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
GtkWidget *toplevel;
g_return_if_fail (GTK_IS_WIDGET (widget));
#if 0
if (_gtk_widget_get_realized (widget))
gtk_widget_queue_draw (widget);
gtk_widget_queue_resize_internal (widget);
#endif
toplevel = _gtk_widget_get_toplevel (widget);
if (GTK_IS_WINDOW (toplevel))
{
if (gtk_container_in_last_resize_iteration (GTK_CONTAINER (toplevel)))
g_warning ("Queueing a resize on %s %s %p inside the last resize iteration. "
"This should not happen. The resize request will be ignored.",
G_OBJECT_TYPE_NAME (widget),
gtk_css_node_get_name (gtk_widget_get_css_node (widget)), widget);
else
gtk_window_add_resize_widget (GTK_WINDOW (toplevel), widget);
}
/* Clear the size request cache for all the parent widgets, since a change
* in size of @widget might cause a change in size of all the parents. */
while (widget)
{
priv = gtk_widget_get_instance_private (widget);
gtk_widget_invalidate_paintable_size (widget);
_gtk_size_request_cache_clear (&priv->requests);
widget = priv->parent;
}
}
/**
@@ -3959,8 +4001,10 @@ void
gtk_widget_queue_resize_no_redraw (GtkWidget *widget)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
#if 0
gtk_widget_queue_resize_internal (widget);
#endif
gtk_widget_queue_resize (widget);
}
/**

View File

@@ -336,10 +336,7 @@ void gtk_widget_cancel_event_sequence (GtkWidget
GtkGesture *gesture,
GdkEventSequence *sequence,
GtkEventSequenceState state);
void gtk_widget_invalidate_size (GtkWidget *widget);
/* inline getters */

View File

@@ -289,6 +289,8 @@ typedef struct
GskRenderer *renderer;
GList *foci;
GPtrArray *resize_widgets;
} GtkWindowPrivate;
#ifdef GDK_WINDOWING_X11
@@ -1920,6 +1922,8 @@ gtk_window_init (GtkWindow *window)
toplevel_list = g_slist_prepend (toplevel_list, window);
gtk_window_update_debugging ();
priv->resize_widgets = g_ptr_array_new ();
#ifdef GDK_WINDOWING_X11
g_signal_connect (gtk_settings_get_for_display (priv->display),
"notify::gtk-application-prefer-dark-theme",
@@ -11303,3 +11307,50 @@ gtk_window_maybe_update_cursor (GtkWindow *window,
break;
}
}
void
gtk_window_add_resize_widget (GtkWindow *window,
GtkWidget *widget)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
g_assert (gtk_widget_get_toplevel (widget) == (GtkWidget *)window);
/* XXX LEAK */
g_ptr_array_add (priv->resize_widgets, g_object_ref (widget));
gtk_container_start_idle_sizer (GTK_CONTAINER (window));
}
void
gtk_window_remove_resize_widget (GtkWindow *window,
GtkWidget *widget)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
guint i, p;
g_assert (gtk_widget_get_toplevel (widget) == (GtkWidget *)window);
for (i = 0, p = priv->resize_widgets->len; i < p; i ++)
{
GtkWidget *w = g_ptr_array_index (priv->resize_widgets, i);
if (w == widget)
{
g_ptr_array_remove_index_fast (priv->resize_widgets, i);
i --;
p --;
}
}
if (p == 0)
gtk_container_stop_idle_sizer (GTK_CONTAINER (window));
}
GPtrArray *
gtk_window_get_resize_widgets (GtkWindow *window)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
return priv->resize_widgets;
}

View File

@@ -167,6 +167,12 @@ void gtk_window_maybe_update_cursor (GtkWindow *window,
GtkWidget *widget,
GdkDevice *device);
void gtk_window_add_resize_widget (GtkWindow *window,
GtkWidget *widget);
void gtk_window_remove_resize_widget (GtkWindow *window,
GtkWidget *widget);
GPtrArray * gtk_window_get_resize_widgets (GtkWindow *window);
G_END_DECLS
#endif /* __GTK_WINDOW_PRIVATE_H__ */