diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c index bbc6968bdf..da469960d7 100644 --- a/gtk/gtkcontainer.c +++ b/gtk/gtkcontainer.c @@ -85,14 +85,6 @@ * See more about implementing custom widgets at https://wiki.gnome.org/HowDoI/CustomWidgets */ - -struct _GtkContainerPrivate -{ - guint resize_handler; - - guint restyle_pending : 1; -}; - enum { ADD, REMOVE, @@ -126,7 +118,6 @@ static GQuark hadjustment_key_id; static guint container_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkContainer, gtk_container, GTK_TYPE_WIDGET, - G_ADD_PRIVATE (GtkContainer) G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gtk_container_buildable_init)) @@ -245,10 +236,6 @@ static void gtk_container_destroy (GtkWidget *widget) { GtkContainer *container = GTK_CONTAINER (widget); - GtkContainerPrivate *priv = gtk_container_get_instance_private (container); - - if (priv->restyle_pending) - priv->restyle_pending = FALSE; gtk_container_foreach (container, (GtkCallback) gtk_widget_destroy, NULL); @@ -333,113 +320,6 @@ gtk_container_remove (GtkContainer *container, g_object_unref (container); } -static gboolean -gtk_container_needs_idle_sizer (GtkContainer *container) -{ - GtkContainerPrivate *priv = gtk_container_get_instance_private (container); - - if (priv->restyle_pending) - return TRUE; - - return gtk_widget_needs_allocate (GTK_WIDGET (container)); -} - -static void -gtk_container_idle_sizer (GdkFrameClock *clock, - GtkContainer *container) -{ - 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) - { - priv->restyle_pending = FALSE; - gtk_css_node_validate (gtk_widget_get_css_node (GTK_WIDGET (container))); - } - - /* 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))) - { - if (GTK_IS_WINDOW (container)) - gtk_window_check_resize (GTK_WINDOW (container)); - else - g_warning ("gtk_container_idle_sizer() called on a non-window"); - } - - 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); - } -} - -void -gtk_container_start_idle_sizer (GtkContainer *container) -{ - GtkContainerPrivate *priv = gtk_container_get_instance_private (container); - GdkFrameClock *clock; - - if (priv->resize_handler != 0) - return; - - if (!gtk_container_needs_idle_sizer (container)) - return; - - clock = gtk_widget_get_frame_clock (GTK_WIDGET (container)); - if (clock == NULL) - return; - - 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_stop_idle_sizer (GtkContainer *container) -{ - GtkContainerPrivate *priv = gtk_container_get_instance_private (container); - - if (priv->resize_handler == 0) - return; - - g_signal_handler_disconnect (gtk_widget_get_frame_clock (GTK_WIDGET (container)), - priv->resize_handler); - priv->resize_handler = 0; -} - -void -_gtk_container_queue_restyle (GtkContainer *container) -{ - GtkContainerPrivate *priv = gtk_container_get_instance_private (container); - - g_return_if_fail (GTK_CONTAINER (container)); - - if (priv->restyle_pending) - return; - - priv->restyle_pending = TRUE; - gtk_container_start_idle_sizer (container); -} - static GtkSizeRequestMode gtk_container_get_request_mode (GtkWidget *widget) { diff --git a/gtk/gtkcontainerprivate.h b/gtk/gtkcontainerprivate.h index 74f24ddc90..c5eb15f01a 100644 --- a/gtk/gtkcontainerprivate.h +++ b/gtk/gtkcontainerprivate.h @@ -26,9 +26,6 @@ G_BEGIN_DECLS -void _gtk_container_queue_restyle (GtkContainer *container); -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); diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c index 249d7405b1..34528f8cca 100644 --- a/gtk/gtkroot.c +++ b/gtk/gtkroot.c @@ -20,6 +20,8 @@ #include "config.h" #include "gtkrootprivate.h" +#include "gtkcssnodeprivate.h" +#include "gtkwidgetprivate.h" #include "gdk/gdk-private.h" #include "gtkprivate.h" #include "gtkintl.h" @@ -61,12 +63,18 @@ gtk_root_default_get_surface_transform (GtkRoot *self, *y = 0; } +static void +gtk_root_default_check_resize (GtkRoot *self) +{ +} + static void gtk_root_default_init (GtkRootInterface *iface) { iface->get_display = gtk_root_default_get_display; iface->get_renderer = gtk_root_default_get_renderer; iface->get_surface_transform = gtk_root_default_get_surface_transform; + iface->check_resize = gtk_root_default_check_resize; g_object_interface_install_property (iface, g_param_spec_object ("focus-widget", @@ -193,3 +201,114 @@ gtk_root_install_properties (GObjectClass *object_class, g_object_class_override_property (object_class, first_prop + GTK_ROOT_PROP_FOCUS_WIDGET, "focus-widget"); return GTK_ROOT_NUM_PROPERTIES; } + +static void +gtk_root_check_resize (GtkRoot *self) +{ + g_return_if_fail (GTK_IS_ROOT (self)); + + GTK_ROOT_GET_IFACE (self)->check_resize (self); +} + +static gboolean +gtk_root_get_restyle_pending (GtkRoot *root) +{ + return GPOINTER_TO_INT (g_object_get_data (G_OBJECT (root), "restyle-pending")); +} + +static void +gtk_root_set_restyle_pending (GtkRoot *root, + gboolean pending) +{ + g_object_set_data (G_OBJECT (root), "restyle-pending", GINT_TO_POINTER (pending)); +} + +static gboolean +gtk_root_needs_layout_phase (GtkRoot *root) +{ + return gtk_root_get_restyle_pending (root) || + gtk_widget_needs_allocate (GTK_WIDGET (root)); +} + +static void +gtk_root_do_layout_phase (GdkFrameClock *clock, + GtkRoot *root) +{ + /* 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 (gtk_root_get_restyle_pending (root)) + { + gtk_root_set_restyle_pending (root, FALSE); + gtk_css_node_validate (gtk_widget_get_css_node (GTK_WIDGET (root))); + } + + /* 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 (root))) + gtk_root_check_resize (root); + + if (!gtk_root_needs_layout_phase (root)) + gtk_root_stop_layout_phase (root); + else + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); +} + +void +gtk_root_start_layout_phase (GtkRoot *root) +{ + GdkFrameClock *clock; + guint resize_handler; + + resize_handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (root), "resize-handler")); + if (resize_handler != 0) + return; + + if (!gtk_root_needs_layout_phase (root)) + return; + + clock = gtk_widget_get_frame_clock (GTK_WIDGET (root)); + if (clock == NULL) + return; + + resize_handler = g_signal_connect (clock, "layout", G_CALLBACK (gtk_root_do_layout_phase), root); + g_object_set_data (G_OBJECT (root), "resize-handler", GUINT_TO_POINTER (resize_handler)); + gdk_frame_clock_request_phase (clock, GDK_FRAME_CLOCK_PHASE_LAYOUT); +} + +void +gtk_root_stop_layout_phase (GtkRoot *root) +{ + guint resize_handler; + + resize_handler = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (root), "resize-handler")); + if (resize_handler == 0) + return; + + g_signal_handler_disconnect (gtk_widget_get_frame_clock (GTK_WIDGET (root)), resize_handler); + g_object_set_data (G_OBJECT (root), "resize-handler", NULL); +} + +void +gtk_root_queue_restyle (GtkRoot *root) +{ + g_return_if_fail (GTK_ROOT (root)); + + if (gtk_root_get_restyle_pending (root)) + return; + + gtk_root_set_restyle_pending (root, TRUE); + gtk_root_start_layout_phase (root); +} diff --git a/gtk/gtkroot.h b/gtk/gtkroot.h index 4c7ae89e37..32a528e582 100644 --- a/gtk/gtkroot.h +++ b/gtk/gtkroot.h @@ -51,6 +51,7 @@ struct _GtkRootInterface void (* get_surface_transform) (GtkRoot *root, int *x, int *y); + void (* check_resize) (GtkRoot *root); }; GDK_AVAILABLE_IN_ALL diff --git a/gtk/gtkrootprivate.h b/gtk/gtkrootprivate.h index 357bc6441f..b7c385c212 100644 --- a/gtk/gtkrootprivate.h +++ b/gtk/gtkrootprivate.h @@ -5,12 +5,17 @@ G_BEGIN_DECLS -GdkDisplay * gtk_root_get_display (GtkRoot *root); +GdkDisplay * gtk_root_get_display (GtkRoot *self); GskRenderer * gtk_root_get_renderer (GtkRoot *self); void gtk_root_get_surface_transform (GtkRoot *self, int *x, int *y); + +void gtk_root_queue_restyle (GtkRoot *self); +void gtk_root_start_layout_phase (GtkRoot *self); +void gtk_root_stop_layout_phase (GtkRoot *self); + enum { GTK_ROOT_PROP_FOCUS_WIDGET, GTK_ROOT_NUM_PROPERTIES