[gtk+/wip/baedert/children: 35/37] add idle sizer for GtkWidget
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/baedert/children: 35/37] add idle sizer for GtkWidget
- Date: Sun, 4 Dec 2016 12:56:43 +0000 (UTC)
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]