summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gsk/gskcairorenderer.c6
-rw-r--r--gsk/gskglrenderer.c14
-rw-r--r--gsk/gskrenderer.c79
-rw-r--r--gsk/gskrenderer.h5
-rw-r--r--gsk/gskrendererprivate.h1
-rw-r--r--gtk/gtkwidget.c70
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,