diff --git a/gtk/gtkcsswidgetnode.c b/gtk/gtkcsswidgetnode.c index b8aaf45302..ec49fbeea7 100644 --- a/gtk/gtkcsswidgetnode.c +++ b/gtk/gtkcsswidgetnode.c @@ -46,7 +46,7 @@ gtk_css_widget_node_queue_callback (GtkWidget *widget, GtkCssNode *node = user_data; gtk_css_node_invalidate_frame_clock (node, TRUE); - gtk_window_queue_restyle (GTK_WINDOW (widget)); + gtk_root_queue_restyle (GTK_ROOT (widget)); return G_SOURCE_CONTINUE; } @@ -56,7 +56,7 @@ gtk_css_widget_node_queue_validate (GtkCssNode *node) { GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node); - if (widget_node->widget && GTK_IS_ROOT (widget_node->widget)) + if (GTK_IS_ROOT (widget_node->widget)) widget_node->validate_cb_id = gtk_widget_add_tick_callback (widget_node->widget, gtk_css_widget_node_queue_callback, node, diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c index 0252b85856..24d3860b1d 100644 --- a/gtk/gtkroot.c +++ b/gtk/gtkroot.c @@ -43,6 +43,9 @@ * The obvious example of a #GtkRoot is #GtkWindow. */ +static GQuark quark_restyle_pending; +static GQuark quark_resize_handler; + G_DEFINE_INTERFACE_WITH_CODE (GtkRoot, gtk_root, GTK_TYPE_WIDGET, g_type_interface_add_prerequisite (g_define_type_id, GTK_TYPE_NATIVE)) @@ -78,6 +81,9 @@ gtk_root_default_init (GtkRootInterface *iface) iface->get_constraint_solver = gtk_root_default_get_constraint_solver; iface->get_focus = gtk_root_default_get_focus; iface->set_focus = gtk_root_default_set_focus; + + quark_restyle_pending = g_quark_from_static_string ("gtk-root-restyle-pending"); + quark_resize_handler = g_quark_from_static_string ("gtk-root-resize-handler"); } /** @@ -154,3 +160,100 @@ gtk_root_get_focus (GtkRoot *self) return GTK_ROOT_GET_IFACE (self)->get_focus (self); } + +static gboolean +gtk_root_needs_layout (GtkRoot *self) +{ + if (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending)) + return TRUE; + + return gtk_widget_needs_allocate (GTK_WIDGET (self)); +} + +static void +gtk_root_layout_cb (GdkFrameClock *clock, + GtkRoot *self) +{ + GtkWidget *widget = GTK_WIDGET (self); + + /* 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 css_changed 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 (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending)) + { + g_object_set_qdata (G_OBJECT (self), quark_restyle_pending, NULL); + gtk_css_node_validate (gtk_widget_get_css_node (widget)); + } + + /* 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 (widget)) + gtk_native_check_resize (GTK_NATIVE (self)); + + if (!gtk_root_needs_layout (self)) + gtk_root_stop_layout (self); + else + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); +} + +void +gtk_root_start_layout (GtkRoot *self) +{ + GdkFrameClock *clock; + guint resize_handler; + + if (g_object_get_qdata (G_OBJECT (self), quark_resize_handler)) + return; + + if (!gtk_root_needs_layout (self)) + return; + + clock = gtk_widget_get_frame_clock (GTK_WIDGET (self)); + if (clock == NULL) + return; + + resize_handler = g_signal_connect (clock, "layout", + G_CALLBACK (gtk_root_layout_cb), self); + g_object_set_qdata (G_OBJECT (self), quark_resize_handler, GINT_TO_POINTER (resize_handler)); + + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); +} + +void +gtk_root_stop_layout (GtkRoot *self) +{ + GdkFrameClock *clock; + guint resize_handler; + + resize_handler = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (self), quark_resize_handler)); + + if (resize_handler == 0) + return; + + clock = gtk_widget_get_frame_clock (GTK_WIDGET (self)); + g_signal_handler_disconnect (clock, resize_handler); + g_object_set_qdata (G_OBJECT (self), quark_resize_handler, NULL); +} + +void +gtk_root_queue_restyle (GtkRoot *self) +{ + if (g_object_get_qdata (G_OBJECT (self), quark_restyle_pending)) + return; + + g_object_set_qdata (G_OBJECT (self), quark_restyle_pending, GINT_TO_POINTER (1)); + + gtk_root_start_layout (self); +} + diff --git a/gtk/gtkrootprivate.h b/gtk/gtkrootprivate.h index 57246127a5..d4c3174ae0 100644 --- a/gtk/gtkrootprivate.h +++ b/gtk/gtkrootprivate.h @@ -30,6 +30,10 @@ struct _GtkRootInterface GtkConstraintSolver * gtk_root_get_constraint_solver (GtkRoot *self); +void gtk_root_start_layout (GtkRoot *self); +void gtk_root_stop_layout (GtkRoot *self); +void gtk_root_queue_restyle (GtkRoot *self); + G_END_DECLS #endif /* __GTK_ROOT_PRIVATE_H__ */ diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index da4f588f19..cf5499b8d4 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -10429,9 +10429,9 @@ gtk_widget_set_alloc_needed (GtkWidget *widget) if (!priv->visible) break; - if (GTK_IS_WINDOW (widget)) + if (GTK_IS_ROOT (widget)) { - gtk_window_start_layout (GTK_WINDOW (widget)); + gtk_root_start_layout (GTK_ROOT (widget)); break; } diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c index 49726ea322..f35c1c0066 100644 --- a/gtk/gtkwindow.c +++ b/gtk/gtkwindow.c @@ -241,12 +241,8 @@ typedef struct guint hide_on_close : 1; guint in_emit_close_request : 1; - guint restyle_pending : 1; - GdkSurfaceTypeHint type_hint; - guint resize_handler; - GtkGesture *click_gesture; GtkGesture *drag_gesture; GtkGesture *bubble_drag_gesture; @@ -4016,9 +4012,6 @@ gtk_window_destroy (GtkWidget *widget) if (priv->group) gtk_window_group_remove_window (priv->group, window); - if (priv->restyle_pending) - priv->restyle_pending = FALSE; - GTK_WIDGET_CLASS (gtk_window_parent_class)->destroy (widget); } @@ -4830,7 +4823,7 @@ gtk_window_realize (GtkWidget *widget) GTK_WIDGET_CLASS (gtk_window_parent_class)->realize (widget); - gtk_window_start_layout (window); + gtk_root_start_layout (GTK_ROOT (window)); if (priv->renderer == NULL) priv->renderer = gsk_renderer_new_for_surface (surface); @@ -4947,7 +4940,7 @@ gtk_window_unrealize (GtkWidget *widget) g_signal_handlers_disconnect_by_func (surface, surface_render, widget); g_signal_handlers_disconnect_by_func (surface, surface_event, widget); - gtk_window_stop_layout (window); + gtk_root_stop_layout (GTK_ROOT (window)); GTK_WIDGET_CLASS (gtk_window_parent_class)->unrealize (widget); @@ -8111,100 +8104,3 @@ gtk_window_maybe_update_cursor (GtkWindow *window, break; } } - -static gboolean -gtk_window_needs_layout (GtkWindow *window) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - - if (priv->restyle_pending) - return TRUE; - - return gtk_widget_needs_allocate (GTK_WIDGET (window)); -} - -static void -gtk_window_layout_cb (GdkFrameClock *clock, - GtkWindow *window) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GtkWidget *widget = GTK_WIDGET (window); - - /* 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 css_changed 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 (widget)); - } - - /* 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 (widget)) - gtk_native_check_resize (GTK_NATIVE (window)); - - if (!gtk_window_needs_layout (window)) - gtk_window_stop_layout (window); - else - gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); -} - -void -gtk_window_start_layout (GtkWindow *window) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GdkFrameClock *clock; - - if (priv->resize_handler != 0) - return; - - if (!gtk_window_needs_layout (window)) - return; - - clock = gtk_widget_get_frame_clock (GTK_WIDGET (window)); - if (clock == NULL) - return; - - priv->resize_handler = g_signal_connect (clock, "layout", - G_CALLBACK (gtk_window_layout_cb), window); - gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); -} - -void -gtk_window_stop_layout (GtkWindow *window) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - GdkFrameClock *clock; - - if (priv->resize_handler == 0) - return; - - clock = gtk_widget_get_frame_clock (GTK_WIDGET (window)); - g_signal_handler_disconnect (clock, priv->resize_handler); - priv->resize_handler = 0; -} - -void -gtk_window_queue_restyle (GtkWindow *window) -{ - GtkWindowPrivate *priv = gtk_window_get_instance_private (window); - - if (priv->restyle_pending) - return; - - priv->restyle_pending = TRUE; - - gtk_window_start_layout (window); -} diff --git a/gtk/gtkwindowprivate.h b/gtk/gtkwindowprivate.h index 15a6639327..2392f8668a 100644 --- a/gtk/gtkwindowprivate.h +++ b/gtk/gtkwindowprivate.h @@ -139,10 +139,6 @@ GtkWidget * gtk_window_pick_popover (GtkWindow *window, void gtk_window_set_extra_input_region (GtkWindow *window, cairo_region_t *region); -void gtk_window_start_layout (GtkWindow *window); -void gtk_window_stop_layout (GtkWindow *window); -void gtk_window_queue_restyle (GtkWindow *window); - G_END_DECLS