diff options
-rw-r--r-- | gsk/gskcairorenderer.c | 6 | ||||
-rw-r--r-- | gsk/gskglrenderer.c | 14 | ||||
-rw-r--r-- | gsk/gskrenderer.c | 79 | ||||
-rw-r--r-- | gsk/gskrenderer.h | 5 | ||||
-rw-r--r-- | gsk/gskrendererprivate.h | 1 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 70 |
6 files changed, 149 insertions, 26 deletions
diff --git a/gsk/gskcairorenderer.c b/gsk/gskcairorenderer.c index 3fa2ebec07..281587d958 100644 --- a/gsk/gskcairorenderer.c +++ b/gsk/gskcairorenderer.c @@ -135,7 +135,11 @@ gsk_cairo_renderer_render (GskRenderer *renderer, GdkDrawingContext *context = gsk_renderer_get_drawing_context (renderer); cairo_t *cr; - cr = gdk_drawing_context_get_cairo_context (context); + if (context != NULL) + cr = gdk_drawing_context_get_cairo_context (context); + else + cr = gsk_renderer_get_cairo_context (renderer); + if (cr == NULL) return; diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c index 373f389907..c4eec609d3 100644 --- a/gsk/gskglrenderer.c +++ b/gsk/gskglrenderer.c @@ -920,9 +920,17 @@ out: GdkWindow *window; cairo_t *cr; - /* XXX: Add GdkDrawingContext API */ - cr = gdk_drawing_context_get_cairo_context (context); - window = gdk_drawing_context_get_window (context); + if (context != NULL) + { + /* XXX: Add GdkDrawingContext API */ + cr = gdk_drawing_context_get_cairo_context (context); + window = gdk_drawing_context_get_window (context); + } + else + { + cr = gsk_renderer_get_cairo_context (renderer); + window = gsk_renderer_get_window (renderer); + } gdk_cairo_draw_from_gl (cr, window, self->texture_id, diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c index ebdb1a4b28..d77bfe1ed3 100644 --- a/gsk/gskrenderer.c +++ b/gsk/gskrenderer.c @@ -37,6 +37,7 @@ #include "gskrendererprivate.h" +#include "gskcairorendererprivate.h" #include "gskdebugprivate.h" #include "gskglrendererprivate.h" #include "gskprofilerprivate.h" @@ -68,6 +69,7 @@ typedef struct GdkDrawingContext *drawing_context; GskRenderNode *root_node; GdkDisplay *display; + cairo_t *cairo_context; GskProfiler *profiler; @@ -121,6 +123,7 @@ gsk_renderer_dispose (GObject *gobject) gsk_renderer_unrealize (self); + g_clear_pointer (&priv->cairo_context, cairo_destroy); g_clear_object (&priv->window); g_clear_object (&priv->display); @@ -603,6 +606,16 @@ gsk_renderer_render (GskRenderer *renderer, if (context != NULL) priv->drawing_context = g_object_ref (context); + else + { + if (priv->cairo_context == NULL) + { + g_critical ("The given GskRenderer instance was not created using " + "gsk_renderer_create_fallback(), but you forgot to pass " + "a GdkDrawingContext."); + return; + } + } priv->root_node = gsk_render_node_ref (root); gsk_render_node_make_immutable (priv->root_node); @@ -695,7 +708,7 @@ gsk_renderer_get_for_display (GdkDisplay *display) } if (use_software[0] != '0') - return NULL; + return g_object_new (GSK_TYPE_CAIRO_RENDERER, "display", display, NULL); #ifdef GDK_WINDOWING_X11 if (GDK_IS_X11_DISPLAY (display)) @@ -707,7 +720,7 @@ gsk_renderer_get_for_display (GdkDisplay *display) renderer_type = GSK_TYPE_GL_RENDERER; else #endif - return NULL; + renderer_type = GSK_TYPE_CAIRO_RENDERER; GSK_NOTE (RENDERER, g_print ("Creating renderer of type '%s' for display '%s'\n", g_type_name (renderer_type), @@ -717,3 +730,65 @@ gsk_renderer_get_for_display (GdkDisplay *display) return g_object_new (renderer_type, "display", display, NULL); } + +static void +gsk_renderer_set_cairo_context (GskRenderer *renderer, + cairo_t *cr) +{ + GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); + + g_clear_pointer (&priv->cairo_context, cairo_destroy); + + if (cr != NULL) + priv->cairo_context = cairo_reference (cr); +} + +cairo_t * +gsk_renderer_get_cairo_context (GskRenderer *renderer) +{ + GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); + + return priv->cairo_context; +} + +/** + * gsk_renderer_create_fallback: + * @renderer: a #GskRenderer + * @viewport: the viewport for the fallback renderer + * @cr: a Cairo context + * + * Creates a fallback #GskRenderer using the same display and window of + * the given @renderer, and instructs it to render to a given Cairo + * context. + * + * Typically, you'll use this function to implement fallback rendering + * of #GskRenderNodes on an intermediate Cairo context, instead of using + * the drawing context associated to a #GdkWindow's rendering buffer. + * + * Returns: (transfer full): a newly created fallback #GskRenderer instance + * + * Since: 3.22 + */ +GskRenderer * +gsk_renderer_create_fallback (GskRenderer *renderer, + const graphene_rect_t *viewport, + cairo_t *cr) +{ + GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); + GskRenderer *res; + + g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL); + g_return_val_if_fail (cr != NULL, NULL); + + res = g_object_new (GSK_TYPE_CAIRO_RENDERER, + "display", priv->display, + "window", priv->window, + "scale-factor", priv->scale_factor, + "viewport", viewport, + NULL); + + gsk_renderer_set_cairo_context (res, cr); + gsk_renderer_realize (res); + + return res; +} diff --git a/gsk/gskrenderer.h b/gsk/gskrenderer.h index 33dd958b7b..4c8fc58892 100644 --- a/gsk/gskrenderer.h +++ b/gsk/gskrenderer.h @@ -71,6 +71,11 @@ GDK_AVAILABLE_IN_3_22 GskRenderNode * gsk_renderer_create_render_node (GskRenderer *renderer); GDK_AVAILABLE_IN_3_22 +GskRenderer * gsk_renderer_create_fallback (GskRenderer *renderer, + const graphene_rect_t *viewport, + cairo_t *cr); + +GDK_AVAILABLE_IN_3_22 void gsk_renderer_render (GskRenderer *renderer, GskRenderNode *root, GdkDrawingContext *context); diff --git a/gsk/gskrendererprivate.h b/gsk/gskrendererprivate.h index 12671886f0..d702ae5a78 100644 --- a/gsk/gskrendererprivate.h +++ b/gsk/gskrendererprivate.h @@ -48,6 +48,7 @@ gboolean gsk_renderer_is_realized (GskRenderer *renderer); GskRenderNode * gsk_renderer_get_root_node (GskRenderer *renderer); GdkDrawingContext * gsk_renderer_get_drawing_context (GskRenderer *renderer); +cairo_t * gsk_renderer_get_cairo_context (GskRenderer *renderer); GskProfiler * gsk_renderer_get_profiler (GskRenderer *renderer); diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index e03535fd7c..504daf8a64 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -6369,6 +6369,18 @@ gtk_cairo_set_marked_for_draw (cairo_t *cr, cairo_set_user_data (cr, &mark_for_draw_key, NULL, NULL); } +static 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; +} + /** * gtk_cairo_should_draw_window: * @cr: a cairo context @@ -6436,6 +6448,7 @@ gtk_widget_draw_internal (GtkWidget *widget, if (gdk_cairo_get_clip_rectangle (cr, NULL)) { + GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (widget); GdkWindow *event_window = NULL; gboolean result; gboolean push_group; @@ -6468,17 +6481,46 @@ gtk_widget_draw_internal (GtkWidget *widget, g_warning ("%s %p is drawn without a current allocation. This should not happen.", G_OBJECT_TYPE_NAME (widget), widget); #endif - if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE)) + /* If the widget uses GSK render nodes then we need a fallback path to + * render on the Cairo context; otherwise we just go through the old + * GtkWidget::draw path + */ + if (widget_class->get_render_node != NULL) { - g_signal_emit (widget, widget_signals[DRAW], - 0, cr, - &result); + GskRenderer *renderer = gtk_widget_get_renderer (widget); + GskRenderer *fallback; + graphene_rect_t viewport; + GskRenderNode *node; + + graphene_rect_init (&viewport, + widget->priv->clip.x, + widget->priv->clip.y, + widget->priv->clip.width, + widget->priv->clip.height); + fallback = gsk_renderer_create_fallback (renderer, &viewport, cr); + node = gtk_widget_get_render_node (widget, fallback); + if (node != NULL) + { + gsk_renderer_render (fallback, node, NULL); + gsk_render_node_unref (node); + } + + g_object_unref (fallback); } - else if (GTK_WIDGET_GET_CLASS (widget)->draw) + else { - cairo_save (cr); - GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr); - cairo_restore (cr); + if (g_signal_has_handler_pending (widget, widget_signals[DRAW], 0, FALSE)) + { + g_signal_emit (widget, widget_signals[DRAW], + 0, cr, + &result); + } + else if (GTK_WIDGET_GET_CLASS (widget)->draw) + { + cairo_save (cr); + GTK_WIDGET_GET_CLASS (widget)->draw (widget, cr); + cairo_restore (cr); + } } #ifdef G_ENABLE_DEBUG @@ -16052,18 +16094,6 @@ 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_create_render_node (GtkWidget *widget, GskRenderer *renderer, |