[gtk/wip/matthiasc/popup: 42/63] Redo the idle sizer



commit c43f886ce5d37f9b553a23802805b1a7aeb59da0
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Feb 24 22:09:24 2019 -0500

    Redo the idle sizer
    
    Move the idle size code from gtkcontainer.c to
    gtkroot.c, Rename it from 'idle sizer' to 'layout phase',
    and make it work for all roots by adding a check_resize
    vfunc. Implement it for GtkWindow and GtkPopup.
    
    Update all callers.

 gtk/gtkcontainer.c        | 108 ----------------------------------------------
 gtk/gtkcontainerprivate.h |   3 --
 gtk/gtkcsswidgetnode.c    |  17 ++++----
 gtk/gtkpopup.c            |  81 +++++++++++++++++-----------------
 gtk/gtkpopup.h            |   2 -
 gtk/gtkroot.c             | 107 +++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkroot.h             |   1 +
 gtk/gtkrootprivate.h      |   7 ++-
 gtk/gtkwidget.c           |  13 +++---
 gtk/gtkwindow.c           |   7 +++
 10 files changed, 178 insertions(+), 168 deletions(-)
---
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 387f3d3c3f..0ebbe3f98b 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -118,12 +118,6 @@
  *
  */
 
-
-struct _GtkContainerPrivate
-{
-  guint resize_handler;
-};
-
 enum {
   ADD,
   REMOVE,
@@ -225,9 +219,6 @@ gtk_container_get_type (void)
         g_type_register_static (GTK_TYPE_WIDGET, I_("GtkContainer"),
                                 &container_info, G_TYPE_FLAG_ABSTRACT);
 
-      GtkContainer_private_offset =
-        g_type_add_instance_private (container_type, sizeof (GtkContainerPrivate));
-
       g_type_add_interface_static (container_type,
                                    GTK_TYPE_BUILDABLE,
                                    &buildable_info);
@@ -1329,105 +1320,6 @@ gtk_container_remove (GtkContainer *container,
   g_object_unref (container);
 }
 
-static gboolean
-gtk_container_needs_idle_sizer (GtkContainer *container)
-{
-  if (gtk_css_node_is_invalid (gtk_widget_get_css_node (GTK_WIDGET (container))))
-    return TRUE;
-
-  return gtk_widget_needs_allocate (GTK_WIDGET (container));
-}
-
-static void
-gtk_container_idle_sizer (GdkFrameClock *clock,
-                         GtkContainer  *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 (gtk_css_node_is_invalid (gtk_widget_get_css_node (GTK_WIDGET (container))))
-    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 if (GTK_IS_POPUP (container))
-        gtk_popup_check_resize (GTK_POPUP (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)
-{
-  g_return_if_fail (GTK_CONTAINER (container));
-
-  if (!gtk_css_node_is_invalid (gtk_widget_get_css_node (GTK_WIDGET (container))))
-    return;
-
-  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/gtkcsswidgetnode.c b/gtk/gtkcsswidgetnode.c
index 3b1440d169..4329a0c1ac 100644
--- a/gtk/gtkcsswidgetnode.c
+++ b/gtk/gtkcsswidgetnode.c
@@ -19,7 +19,7 @@
 
 #include "gtkcsswidgetnodeprivate.h"
 
-#include "gtkcontainerprivate.h"
+#include "gtkrootprivate.h"
 #include "gtkcssanimatedstyleprivate.h"
 #include "gtkprivate.h"
 #include "gtksettingsprivate.h"
@@ -60,7 +60,7 @@ gtk_css_widget_node_queue_callback (GtkWidget     *widget,
   GtkCssNode *node = user_data;
 
   gtk_css_node_invalidate_frame_clock (node, TRUE);
-  _gtk_container_queue_restyle (GTK_CONTAINER (widget));
+  gtk_root_queue_restyle (GTK_ROOT (widget));
 
   return G_SOURCE_CONTINUE;
 }
@@ -70,8 +70,7 @@ gtk_css_widget_node_queue_validate (GtkCssNode *node)
 {
   GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node);
 
-  if (widget_node->widget && _gtk_widget_is_toplevel (widget_node->widget) &&
-      GTK_IS_CONTAINER (widget_node->widget))
+  if (widget_node->widget && 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,
@@ -83,10 +82,12 @@ gtk_css_widget_node_dequeue_validate (GtkCssNode *node)
 {
   GtkCssWidgetNode *widget_node = GTK_CSS_WIDGET_NODE (node);
 
-  if (widget_node->widget && _gtk_widget_is_toplevel (widget_node->widget) &&
-      GTK_IS_CONTAINER (widget_node->widget))
-    gtk_widget_remove_tick_callback (widget_node->widget,
-                                     widget_node->validate_cb_id);
+  if (widget_node->validate_cb_id)
+    {
+      gtk_widget_remove_tick_callback (widget_node->widget,
+                                       widget_node->validate_cb_id);
+      widget_node->validate_cb_id = 0;
+    }
 }
 
 static void
diff --git a/gtk/gtkpopup.c b/gtk/gtkpopup.c
index ed81a2fdde..e3b7485af7 100644
--- a/gtk/gtkpopup.c
+++ b/gtk/gtkpopup.c
@@ -76,12 +76,53 @@ gtk_popup_root_get_surface_transform (GtkRoot *root,
   *y = margin.top + border.top + padding.top;
 }
 
+static void
+gtk_popup_move_resize (GtkPopup *popup)
+{
+  GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+  GdkRectangle rect;
+ 
+  rect.x = 0;
+  rect.y = 0;
+  rect.width = gtk_widget_get_width (priv->relative_to);
+  rect.height = gtk_widget_get_height (priv->relative_to);
+  gtk_widget_translate_coordinates (priv->relative_to, gtk_widget_get_toplevel (priv->relative_to),
+                                    rect.x, rect.y, &rect.x, &rect.y);
+
+  gdk_surface_move_to_rect (priv->surface,
+                            &rect,
+                            GDK_GRAVITY_SOUTH,
+                            GDK_GRAVITY_NORTH,
+                            GDK_ANCHOR_FLIP_Y,
+                            0, 10);
+}
+
+static void
+gtk_popup_root_check_resize (GtkRoot *root)
+{
+  GtkPopup *popup = GTK_POPUP (root);
+  GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
+  GtkWidget *widget = GTK_WIDGET (popup);
+
+  if (!_gtk_widget_get_alloc_needed (widget))
+    gtk_widget_ensure_allocate (widget);
+  else if (gtk_widget_get_visible (widget))
+    {
+      gtk_popup_move_resize (popup);
+      gtk_widget_allocate (GTK_WIDGET (popup),
+                           gdk_surface_get_width (priv->surface),
+                           gdk_surface_get_height (priv->surface),
+                           -1, NULL);
+    }
+}
+
 static void
 gtk_popup_root_interface_init (GtkRootInterface *iface)
 {
   iface->get_display = gtk_popup_root_get_display;
   iface->get_renderer = gtk_popup_root_get_renderer;
   iface->get_surface_transform = gtk_popup_root_get_surface_transform;
+  iface->check_resize = gtk_popup_root_check_resize;
 }
 
 static void
@@ -219,27 +260,6 @@ gtk_popup_measure (GtkWidget      *widget,
                       minimum_baseline, natural_baseline);
 }
 
-static void
-gtk_popup_move_resize (GtkPopup *popup)
-{
-  GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
-  GdkRectangle rect;
- 
-  rect.x = 0;
-  rect.y = 0;
-  rect.width = gtk_widget_get_width (priv->relative_to);
-  rect.height = gtk_widget_get_height (priv->relative_to);
-  gtk_widget_translate_coordinates (priv->relative_to, gtk_widget_get_toplevel (priv->relative_to),
-                                    rect.x, rect.y, &rect.x, &rect.y);
-
-  gdk_surface_move_to_rect (priv->surface,
-                            &rect,
-                            GDK_GRAVITY_SOUTH,
-                            GDK_GRAVITY_NORTH,
-                            GDK_ANCHOR_FLIP_Y,
-                            0, 10);
-}
-
 static void
 gtk_popup_size_allocate (GtkWidget *widget,
                          int        width,
@@ -306,22 +326,3 @@ gtk_popup_set_relative_to (GtkPopup  *popup,
   g_signal_connect (priv->relative_to, "size-allocate", G_CALLBACK (size_changed), popup);
   priv->display = gtk_widget_get_display (relative_to);
 }
-
-void
-gtk_popup_check_resize (GtkPopup *popup)
-{
-  GtkWidget *widget = GTK_WIDGET (popup);
-  GtkPopupPrivate *priv = gtk_popup_get_instance_private (popup);
-
-  if (!_gtk_widget_get_alloc_needed (widget))
-    gtk_widget_ensure_allocate (widget);
-  else if (gtk_widget_get_visible (widget))
-    {
-      gtk_popup_move_resize (popup);
-      gtk_widget_allocate (GTK_WIDGET (popup),
-                           gdk_surface_get_width (priv->surface),
-                           gdk_surface_get_height (priv->surface),
-                           -1, NULL);
-    }
-}
-
diff --git a/gtk/gtkpopup.h b/gtk/gtkpopup.h
index 7760b24878..a316741933 100644
--- a/gtk/gtkpopup.h
+++ b/gtk/gtkpopup.h
@@ -59,8 +59,6 @@ GDK_AVAILABLE_IN_ALL
 void            gtk_popup_set_relative_to (GtkPopup   *popup,
                                            GtkWidget  *relative_to);
 
-void gtk_popup_check_resize (GtkPopup *popup);
-
 G_END_DECLS
 
 #endif /* __GTK_POPUP_H__ */
diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c
index 249d7405b1..24d7e7359a 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,102 @@ 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)
+{
+  GtkRootInterface *iface;
+
+  g_return_if_fail (GTK_IS_ROOT (self));
+
+  iface = GTK_ROOT_GET_IFACE (self);
+  iface->check_resize (self);
+}
+
+static gboolean
+gtk_root_needs_layout_phase (GtkRoot *root)
+{
+  if (gtk_css_node_is_invalid (gtk_widget_get_css_node (GTK_WIDGET (root))))
+    return TRUE;
+
+  return 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_css_node_is_invalid (gtk_widget_get_css_node (GTK_WIDGET (root))))
+    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_css_node_is_invalid (gtk_widget_get_css_node (GTK_WIDGET (root))))
+    return;
+
+  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..c7c942c203 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
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index d0888f9535..ba2db56f5d 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -56,6 +56,7 @@
 #include "gtkprivate.h"
 #include "gtkrenderbackgroundprivate.h"
 #include "gtkrenderborderprivate.h"
+#include "gtkrootprivate.h"
 #include "gtkscrollable.h"
 #include "gtkselection.h"
 #include "gtksettingsprivate.h"
@@ -3665,8 +3666,8 @@ gtk_widget_connect_frame_clock (GtkWidget *widget)
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
   GdkFrameClock *frame_clock;
 
-  if (GTK_IS_CONTAINER (widget) && _gtk_widget_is_toplevel (widget))
-    gtk_container_start_idle_sizer (GTK_CONTAINER (widget));
+  if (GTK_IS_ROOT (widget))
+    gtk_root_start_layout_phase (GTK_ROOT (widget));
 
   frame_clock = gtk_widget_get_frame_clock (widget);
 
@@ -3686,8 +3687,8 @@ gtk_widget_disconnect_frame_clock (GtkWidget *widget)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
 
-  if (GTK_IS_CONTAINER (widget) && _gtk_widget_is_toplevel (widget))
-    gtk_container_stop_idle_sizer (GTK_CONTAINER (widget));
+  if (GTK_IS_ROOT (widget))
+    gtk_root_stop_layout_phase (GTK_ROOT (widget));
 
   gtk_css_node_invalidate_frame_clock (priv->cssnode, FALSE);
 
@@ -11662,9 +11663,9 @@ gtk_widget_set_alloc_needed (GtkWidget *widget)
       if (!priv->visible)
         break;
 
-      if (_gtk_widget_is_toplevel (widget))
+      if (GTK_IS_ROOT (widget))
         {
-          gtk_container_start_idle_sizer (GTK_CONTAINER (widget));
+          gtk_root_start_layout_phase (GTK_ROOT (widget));
           break;
         }
 
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 2b131641f7..757897f176 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -2448,12 +2448,19 @@ gtk_window_root_get_surface_transform (GtkRoot *root,
   *y = margin.top + border.top + padding.top;
 }
 
+static void
+gtk_window_root_check_resize (GtkRoot *root)
+{
+  gtk_window_check_resize (GTK_WINDOW (root));
+}
+
 static void
 gtk_window_root_interface_init (GtkRootInterface *iface)
 {
   iface->get_display = gtk_window_root_get_display;
   iface->get_renderer = gtk_window_root_get_renderer;
   iface->get_surface_transform = gtk_window_root_get_surface_transform;
+  iface->check_resize = gtk_window_root_check_resize;
 }
 
 /**


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]