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.
This commit is contained in:
Emmanuele Bassi
2016-06-23 17:35:42 +01:00
parent 258af60c18
commit b997f4c575
4 changed files with 110 additions and 9 deletions

View File

@@ -15827,27 +15827,116 @@ 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)
{
GdkDrawingContext *context;
gboolean do_clip;
cairo_t *cr;
int x, y;
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);
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);
gsk_renderer_render (renderer, root, context);
gsk_render_node_unref (root);
gdk_window_end_draw_frame (window, context);
}

View File

@@ -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>
@@ -593,12 +594,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);
};

View File

@@ -296,6 +296,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

View File

@@ -7252,6 +7252,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);
@@ -7261,6 +7263,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);