[gtk+/wip/ebassi/gsk: 5/11] widget: Add GskLayer integration



commit df43d0360174082e974afa889b86fa0cec95f551
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Mon Mar 16 18:47:37 2015 +0000

    widget: Add GskLayer integration
    
    Each GtkWidget can be set up to be the entry point of a scene graph, by
    adding a GskLayer to the components of the widget itself. This means
    that it's possible to set up a GSK-based scene graph when creating a
    widget, and the widget will then be in charge of drawing it whenever
    it's needed.

 gtk/gtkwidget.c |  183 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 gtk/gtkwidget.h |    9 +++
 2 files changed, 185 insertions(+), 7 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index d9230f5..512722f 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -536,6 +536,9 @@ struct _GtkWidgetPrivate
   /* SizeGroup related flags */
   guint have_size_groups      : 1;
 
+  /* GSK layer */
+  guint has_layer             : 1;
+
   guint8 alpha;
   guint8 user_alpha;
 
@@ -599,6 +602,12 @@ struct _GtkWidgetPrivate
 #endif /* G_ENABLE_DEBUG */
 
   GList *event_controllers;
+
+  /* The GSK layer associated to the widget; if has_layer is
+   * TRUE, then the widget will draw the contents of the layer
+   * when drawing itself
+   */
+  GskLayer *layer;
 };
 
 struct _GtkWidgetClassPrivate
@@ -5575,6 +5584,9 @@ gtk_widget_realize (GtkWidget *widget)
       gtk_widget_connect_frame_clock (widget,
                                       gtk_widget_get_frame_clock (widget));
 
+      if (priv->has_layer && priv->layer != NULL)
+        gsk_layer_set_frame_clock (priv->layer, gtk_widget_get_frame_clock (widget));
+
       gtk_widget_pop_verify_invariants (widget);
     }
 }
@@ -6376,13 +6388,25 @@ gtk_widget_real_size_allocate (GtkWidget     *widget,
 
   gtk_widget_set_allocation (widget, allocation);
 
-  if (gtk_widget_get_realized (widget) &&
-      gtk_widget_get_has_window (widget))
-     {
-       gdk_window_move_resize (priv->window,
-                               allocation->x, allocation->y,
-                               allocation->width, allocation->height);
-     }
+  if (gtk_widget_get_realized (widget))
+    {
+      if (gtk_widget_get_has_window (widget))
+        {
+         gdk_window_move_resize (priv->window,
+                                  allocation->x, allocation->y,
+                                  allocation->width, allocation->height);
+        }
+
+      if (gtk_widget_get_has_layer (widget) && priv->layer != NULL)
+        {
+          graphene_rect_t bounds;
+
+          graphene_rect_init (&bounds,
+                              0, 0,
+                              allocation->width, allocation->height);
+          gsk_layer_set_bounds (priv->layer, &bounds);
+        }
+    }
 }
 
 /* translate initial/final into start/end */
@@ -6958,6 +6982,28 @@ gtk_cairo_should_draw_window (cairo_t *cr,
 }
 
 static void
+_gtk_widget_draw_layer (GtkWidget *widget,
+                        cairo_t   *cr,
+                        GdkWindow *window)
+{
+  GskRenderer *renderer = gsk_renderer_new (widget->priv->layer);
+  graphene_rect_t viewport;
+
+  graphene_rect_init (&viewport,
+                      widget->priv->allocation.x,
+                      widget->priv->allocation.y,
+                      widget->priv->allocation.width,
+                      widget->priv->allocation.height);
+
+  gsk_renderer_set_viewport (renderer, &viewport);
+  gsk_renderer_render (renderer, cr,
+                       widget->priv->allocation.width,
+                       widget->priv->allocation.height);
+
+  g_object_unref (renderer);
+}
+
+static void
 _gtk_widget_draw_internal (GtkWidget *widget,
                            cairo_t   *cr,
                            gboolean   clip_to_size,
@@ -6991,6 +7037,9 @@ _gtk_widget_draw_internal (GtkWidget *widget,
                      0, cr,
                      &result);
 
+      if (gtk_widget_get_has_layer (widget))
+        _gtk_widget_draw_layer (widget, cr, window);
+
 #ifdef G_ENABLE_DEBUG
       if (G_UNLIKELY (gtk_get_debug_flags () & GTK_DEBUG_BASELINES))
        {
@@ -9127,6 +9176,115 @@ gtk_widget_get_has_window (GtkWidget *widget)
 }
 
 /**
+ * gtk_widget_set_has_layer:
+ * @widget: a #GskLayer
+ * @has_layer: %TRUE if the widget uses GSK layers
+ *
+ * Sets whether @widget will use GSK layers when drawing.
+ *
+ * If @has_layer is %TRUE, you can use gtk_widget_get_layer() to retrieve
+ * the root #GskLayer and build a scene graph using the #GskLayer API.
+ *
+ * The widget will render the contents of the scene graph during the
+ * emission of the #GtkWidget::draw signal.
+ *
+ * Since: 3.18
+ */
+void
+gtk_widget_set_has_layer (GtkWidget *widget,
+                          gboolean   has_layer)
+{
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  widget->priv->has_layer = !!has_layer;
+}
+
+/**
+ * gtk_widget_get_has_layer:
+ * @widget: a #GtkWidget
+ *
+ * Checks whether @widget uses GSK layers when drawing.
+ *
+ * Returns: %TRUE if the widget uses GSK layers
+ *
+ * Since: 3.18
+ */
+gboolean
+gtk_widget_get_has_layer (GtkWidget *widget)
+{
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  return widget->priv->has_layer;
+}
+
+/**
+ * gtk_widget_get_layer:
+ * @widget: a #GtkWidget
+ *
+ * Retrieves the root #GskLayer used by @widget, or %NULL if the widget
+ * does not use layers.
+ *
+ * You can use the layer returned by this function to build your scene
+ * graph; the scene will be rendered every time the @widget draws itself.
+ *
+ * The returned #GskLayer has its #GskLayer:bounds set to the same size
+ * as the widget, and the #GskLayer:frame with an origin in (0, 0). The
+ * background color of the layer is transparent.
+ *
+ * Returns: (transfer none): the root layer of the scene, or %NULL
+ *
+ * Since: 3.18
+ */
+GskLayer *
+gtk_widget_get_layer (GtkWidget *widget)
+{
+  GdkRGBA transparent = { 0, 0, 0, 0 };
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+
+  if (!widget->priv->has_layer)
+    return NULL;
+
+  if (widget->priv->layer != NULL)
+    {
+      if (widget->priv->realized)
+        gsk_layer_set_frame_clock (widget->priv->layer, gtk_widget_get_frame_clock (widget));
+
+      return widget->priv->layer;
+    }
+
+  widget->priv->layer = gsk_layer_new ();
+  g_object_ref_sink (widget->priv->layer);
+
+  /* Initialize the layer */
+  if (!widget->priv->alloc_needed)
+    {
+      graphene_rect_t bounds;
+
+      graphene_rect_init (&bounds,
+                          widget->priv->allocation.x,
+                          widget->priv->allocation.y,
+                          widget->priv->allocation.width,
+                          widget->priv->allocation.height);
+      gsk_layer_set_bounds (widget->priv->layer, &bounds);
+    }
+
+  gsk_layer_set_background_color (widget->priv->layer, &transparent);
+
+  if (widget->priv->realized)
+    gsk_layer_set_frame_clock (widget->priv->layer, gtk_widget_get_frame_clock (widget));
+
+  g_signal_connect_swapped (widget->priv->layer, "queue-relayout",
+                            G_CALLBACK (gtk_widget_queue_resize),
+                            widget);
+  g_signal_connect_swapped (widget->priv->layer, "queue-redraw",
+                            G_CALLBACK (gtk_widget_queue_draw),
+                            widget);
+
+  return widget->priv->layer;
+}
+
+/**
  * gtk_widget_is_toplevel:
  * @widget: a #GtkWidget
  *
@@ -11985,6 +12143,8 @@ gtk_widget_dispose (GObject *object)
   else if (gtk_widget_get_visible (widget))
     gtk_widget_hide (widget);
 
+  g_clear_object (&priv->layer);
+
   priv->visible = FALSE;
   if (gtk_widget_get_realized (widget))
     gtk_widget_unrealize (widget);
@@ -12301,6 +12461,15 @@ gtk_widget_real_realize (GtkWidget *widget)
       priv->window = gtk_widget_get_parent_window (widget);
       g_object_ref (priv->window);
     }
+
+  if (priv->has_layer)
+    {
+      GskLayer *layer = gtk_widget_get_layer (widget);
+      graphene_rect_t bounds;
+
+      graphene_rect_init (&bounds, 0, 0, priv->allocation.width, priv->allocation.height);
+      gsk_layer_set_bounds (layer, &bounds);
+    }
 }
 
 /*****************************************
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 450cd19..33634bd 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -30,6 +30,7 @@
 #endif
 
 #include <gdk/gdk.h>
+#include <gsk/gsk.h>
 #include <gtk/gtkaccelgroup.h>
 #include <gtk/gtkborder.h>
 #include <gtk/gtktypes.h>
@@ -932,6 +933,14 @@ GDK_AVAILABLE_IN_3_8
 void                  gtk_widget_unregister_window      (GtkWidget    *widget,
                                                          GdkWindow    *window);
 
+GDK_AVAILABLE_IN_3_18
+void                  gtk_widget_set_has_layer          (GtkWidget    *widget,
+                                                         gboolean      has_layer);
+GDK_AVAILABLE_IN_3_18
+gboolean              gtk_widget_get_has_layer          (GtkWidget    *widget);
+GDK_AVAILABLE_IN_3_18
+GskLayer *            gtk_widget_get_layer              (GtkWidget    *widget);
+
 GDK_AVAILABLE_IN_ALL
 int                   gtk_widget_get_allocated_width    (GtkWidget     *widget);
 GDK_AVAILABLE_IN_ALL


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