[gtk+/wip/ebassi/gsk: 5/11] widget: Add GskLayer integration
- From: Emmanuele Bassi <ebassi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/ebassi/gsk: 5/11] widget: Add GskLayer integration
- Date: Sun, 9 Aug 2015 15:51:00 +0000 (UTC)
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]