[gtk+/wip/baedert/children: 35/37] add idle sizer for GtkWidget



commit d050110bd03133a9f1162cedff1cec80f0a85868
Author: Timm Bäder <mail baedert org>
Date:   Sun Dec 4 13:33:14 2016 +0100

    add idle sizer for GtkWidget
    
    didn't help my problem but keepking this anyway for future reference.

 gtk/gtkcsswidgetnode.c |   11 ++--
 gtk/gtkwidget.c        |  130 ++++++++++++++++++++++++++++++++++++++++++++++++
 gtk/gtkwidgetprivate.h |    5 ++
 3 files changed, 141 insertions(+), 5 deletions(-)
---
diff --git a/gtk/gtkcsswidgetnode.c b/gtk/gtkcsswidgetnode.c
index a112d7c..825f2ad 100644
--- a/gtk/gtkcsswidgetnode.c
+++ b/gtk/gtkcsswidgetnode.c
@@ -66,7 +66,10 @@ 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));
+  if (GTK_IS_CONTAINER (widget))
+    _gtk_container_queue_restyle (GTK_CONTAINER (widget));
+  else
+    gtk_widget_queue_restyle (widget);
 
   return G_SOURCE_CONTINUE;
 }
@@ -94,8 +97,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_widget_is_toplevel (widget_node->widget))
     widget_node->validate_cb_id = gtk_widget_add_tick_callback (widget_node->widget,
                                                                 gtk_css_widget_node_queue_callback,
                                                                 node,
@@ -107,8 +109,7 @@ 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))
+  if (widget_node->widget && _gtk_widget_is_toplevel (widget_node->widget))
     gtk_widget_remove_tick_callback (widget_node->widget,
                                      widget_node->validate_cb_id);
 }
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 2aa05c4..7ac525f 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -16002,3 +16002,133 @@ gtk_widget_get_focus_child (GtkWidget *widget)
 {
   return widget->priv->focus_child;
 }
+
+static gboolean
+gtk_widget_needs_idle_sizer (GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+
+  if (priv->restyle_pending)
+    return TRUE;
+
+  return gtk_widget_needs_allocate (widget);
+}
+
+static void
+gtk_widget_stop_idle_sizer (GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+
+  if (priv->resize_handler == 0)
+    return;
+
+  g_signal_handler_disconnect (priv->resize_clock,
+                               priv->resize_handler);
+  priv->resize_handler = 0;
+  priv->resize_clock = NULL;
+}
+
+static void
+gtk_widget_check_resize (GtkWidget *widget)
+{
+  GtkAllocation allocation;
+  GtkRequisition requisition;
+  int baseline;
+
+  if (_gtk_widget_get_alloc_needed (widget))
+    {
+      if (!_gtk_widget_is_toplevel (widget))
+        {
+          gtk_widget_get_preferred_size (widget, &requisition, NULL);
+          gtk_widget_get_allocated_size (widget, &allocation, &baseline);
+
+          if (allocation.width < requisition.width)
+            allocation.width = requisition.width;
+          if (allocation.height < requisition.height)
+            allocation.height = requisition.height;
+          gtk_widget_size_allocate_with_baseline (widget, &allocation, baseline);
+        }
+      else
+        gtk_widget_queue_resize (widget);
+    }
+  else
+    {
+      gtk_widget_ensure_allocate (widget);
+    }
+}
+
+static void
+gtk_widget_idle_sizer (GdkFrameClock *clock, GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+  /* 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 (priv->cssnode);
+    }
+
+  /* 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_widget_check_resize (widget);
+    }
+
+  if (!gtk_widget_needs_idle_sizer (widget))
+    {
+      gtk_widget_stop_idle_sizer (widget);
+    }
+  else
+    {
+      gdk_frame_clock_request_phase (clock,
+                                     GDK_FRAME_CLOCK_PHASE_LAYOUT);
+    }
+}
+
+static void
+gtk_widget_start_idle_sizer (GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+  GdkFrameClock *clock;
+
+  if (priv->resize_handler != 0)
+    return;
+
+  clock = gtk_widget_get_frame_clock (widget);
+  if (clock == NULL)
+    return;
+
+  priv->resize_clock = clock;
+  priv->resize_handler = g_signal_connect (clock, "layout",
+                                           G_CALLBACK (gtk_widget_idle_sizer),
+                                           widget);
+  gdk_frame_clock_request_phase (clock,
+                                 GDK_FRAME_CLOCK_PHASE_LAYOUT);
+
+}
+
+void
+gtk_widget_queue_restyle (GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+
+  if (priv->restyle_pending)
+    return;
+
+  gtk_widget_start_idle_sizer (widget);
+  priv->restyle_pending = TRUE;
+}
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index cfce669..585149d 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -90,6 +90,10 @@ struct _GtkWidgetPrivate
   /* SizeGroup related flags */
   guint have_size_groups      : 1;
 
+  guint restyle_pending       : 1;
+  guint resize_handler;
+  GdkFrameClock *resize_clock;
+
   /* Alignment */
   guint   halign              : 4;
   guint   valign              : 4;
@@ -313,6 +317,7 @@ GtkWidget *       gtk_widget_get_focus_child               (GtkWidget *widget);
 void              gtk_widget_forall                        (GtkWidget            *widget,
                                                             GtkCallback           callback,
                                                             gpointer              user_data);
+void              gtk_widget_queue_restyle                 (GtkWidget *widget);
 
 /* inline getters */
 


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