[gtk+/wip/ebassi/gsk-renderer: 1/4] gtk: Use GskRenderNode to render widgets



commit 47948a10b92d6dfd30dbe7214b621829d1c20205
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Thu Jun 23 17:35:42 2016 +0100

    gtk: Use GskRenderNode to render widgets
    
    We need a virtual function to retrieve the GskRenderNode for each
    widget, which is supposed to attach its own children's GskRenderNodes.
    Additionally, we want to maintain the existing GtkWidget::draw mechanism
    for widgets that do not implement get_render_node() — as well as widgets
    that have handlers connected to the ::draw signal.

 gtk/gtkwidget.c        |  123 ++++++++++++++++++++++++++++++++++++++++++-----
 gtk/gtkwidget.h        |    5 ++-
 gtk/gtkwidgetprivate.h |    3 +
 gtk/gtkwindow.c        |    6 ++
 4 files changed, 123 insertions(+), 14 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 5b87a33..d638716 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -17447,28 +17447,128 @@ gtk_widget_reset_controllers (GtkWidget *widget)
     }
 }
 
+GskRenderer *
+gtk_widget_get_renderer (GtkWidget *widget)
+{
+  GtkWidget *toplevel;
+
+  toplevel = _gtk_widget_get_toplevel (widget);
+  if (_gtk_widget_is_toplevel (toplevel))
+    return gtk_window_get_renderer (GTK_WINDOW (toplevel));
+
+  return NULL;
+}
+
+GskRenderNode *
+gtk_widget_get_render_node (GtkWidget   *widget,
+                            GskRenderer *renderer)
+{
+  GtkWidgetClass *klass = GTK_WIDGET_GET_CLASS (widget);
+  GskRenderNode *node;
+
+  if (klass->get_render_node == NULL)
+    {
+      GskRenderNode *tmp;
+      graphene_rect_t bounds;
+      GtkAllocation clip;
+      cairo_t *cr;
+
+      gtk_widget_get_clip (widget, &clip);
+      graphene_rect_init (&bounds, clip.x, clip.y, clip.width, clip.height);
+
+      tmp = gsk_render_node_new ();
+      gsk_render_node_set_bounds (tmp, &bounds);
+      cr = gsk_render_node_get_draw_context (tmp);
+
+      gtk_widget_draw (widget, cr);
+
+      cairo_destroy (cr);
+
+      node = tmp;
+    }
+  else
+    {
+      node = klass->get_render_node (widget, renderer);
+
+      if (klass->draw != NULL ||
+          g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
+        {
+          GskRenderNode *tmp;
+          graphene_rect_t bounds;
+          GtkAllocation clip;
+          gboolean result;
+          cairo_t *cr;
+
+          gtk_widget_get_clip (widget, &clip);
+          graphene_rect_init (&bounds, clip.x, clip.y, clip.width, clip.height);
+
+          tmp = gsk_render_node_new ();
+          gsk_render_node_set_bounds (tmp, &bounds);
+          cr = gsk_render_node_get_draw_context (tmp);
+
+          if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE))
+            {
+              g_signal_emit (widget, widget_signals[DRAW], 0, cr, &result);
+            }
+          else if (klass->draw != NULL)
+            {
+              klass->draw (widget, cr);
+            }
+
+          cairo_destroy (cr);
+
+          if (node != NULL)
+            {
+              gsk_render_node_append_child (node, tmp);
+              gsk_render_node_unref (tmp);
+            }
+          else
+            {
+              node = tmp;
+            }
+        }
+    }
+
+  return node;
+}
+
 void
 gtk_widget_render (GtkWidget            *widget,
                    GdkWindow            *window,
                    const cairo_region_t *region)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
-  GdkDrawingContext *context;
-  gboolean do_clip;
-  cairo_t *cr;
-  int x, y;
 
   if (priv->double_buffered)
     {
+      GdkDrawingContext *context;
+      GskRenderer *renderer;
+      GskRenderNode *root;
+
       /* We only render double buffered on native windows */
       if (!gdk_window_has_native (window))
         return;
 
+      renderer = gtk_widget_get_renderer (widget);
+      if (renderer == NULL)
+        return;
+
+      root = gtk_widget_get_render_node (widget, renderer);
+      if (root == NULL)
+        return;
+
       context = gdk_window_begin_draw_frame (window, region);
-      cr = gdk_drawing_context_get_cairo_context (context);
+      gsk_renderer_render (renderer, root, context);
+      gdk_window_end_draw_frame (window, context);
+
+      gsk_render_node_unref (root);
     }
   else
     {
+      gboolean do_clip;
+      cairo_t *cr;
+      int x, y;
+
       /* This is annoying, but it has to stay because Firefox
        * disables double buffering on a top-level GdkWindow,
        * which breaks the drawing context.
@@ -17478,15 +17578,12 @@ gtk_widget_render (GtkWidget            *widget,
 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
       cr = gdk_cairo_create (window);
 G_GNUC_END_IGNORE_DEPRECATIONS
-    }
 
-  do_clip = _gtk_widget_get_translation_to_window (widget, window, &x, &y);
-  cairo_translate (cr, -x, -y);
+      do_clip = _gtk_widget_get_translation_to_window (widget, window, &x, &y);
+      cairo_translate (cr, -x, -y);
 
-  gtk_widget_draw_internal (widget, cr, do_clip);
+      gtk_widget_draw_internal (widget, cr, do_clip);
 
-  if (priv->double_buffered)
-    gdk_window_end_draw_frame (window, context);
-  else
-    cairo_destroy (cr);
+      cairo_destroy (cr);
+    }
 }
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index c550dda..cf0144b 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>
@@ -599,12 +600,14 @@ struct _GtkWidgetClass
   void         (*queue_draw_region)           (GtkWidget         *widget,
                                               const cairo_region_t *region);
 
+  GskRenderNode *(* get_render_node) (GtkWidget *widget,
+                                      GskRenderer *renderer);
+
   /*< private >*/
 
   GtkWidgetClassPrivate *priv;
 
   /* Padding for future expansion */
-  void (*_gtk_reserved6) (void);
   void (*_gtk_reserved7) (void);
 };
 
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index aa7dba6..6e684dd 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -307,6 +307,9 @@ void              gtk_widget_render                        (GtkWidget
                                                             const cairo_region_t *region);
 
 
+GskRenderNode *   gtk_widget_get_render_node               (GtkWidget   *widget,
+                                                            GskRenderer *renderer);
+
 /* inline getters */
 
 static inline gboolean
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index d987434..78da819 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -7581,6 +7581,8 @@ _gtk_window_set_allocation (GtkWindow           *window,
     {
       graphene_rect_t viewport;
       graphene_matrix_t projection;
+      graphene_matrix_t modelview;
+      graphene_point3d_t tmp;
 
       graphene_rect_init (&viewport, 0, 0, allocation->width, allocation->height);
       gsk_renderer_set_viewport (priv->renderer, &viewport);
@@ -7590,6 +7592,10 @@ _gtk_window_set_allocation (GtkWindow           *window,
                                   0, allocation->height,
                                   -1, 1);
       gsk_renderer_set_projection (priv->renderer, &projection);
+
+      graphene_matrix_init_translate (&modelview,
+                                      graphene_point3d_init (&tmp, 0.f, 0.f, 0.f));
+      gsk_renderer_set_modelview (priv->renderer, &modelview);
     }
 
   get_shadow_width (window, &window_border);


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