From 4e06d8f73c9eabd405ed32ec2e141715a8cca505 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 13 Nov 2016 20:47:34 +0100 Subject: [PATCH] snapshot: Add gtk_css_gadget_snapshot() Including a snpahsot() vfunc, wee! --- gtk/gtkcssgadget.c | 142 ++++++++++++++++++++++++++++++++++++++ gtk/gtkcssgadgetprivate.h | 8 +++ gtk/gtksnapshot.c | 7 ++ gtk/gtksnapshot.h | 4 ++ 4 files changed, 161 insertions(+) diff --git a/gtk/gtkcssgadget.c b/gtk/gtkcssgadget.c index 1559fac1a0..5bc0e0ffdf 100644 --- a/gtk/gtkcssgadget.c +++ b/gtk/gtkcssgadget.c @@ -121,6 +121,51 @@ gtk_css_gadget_real_draw (GtkCssGadget *gadget, return FALSE; } +static void +gtk_css_gadget_get_clip (GtkCssGadget *gadget, + graphene_rect_t *bounds) +{ + GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget); + + if (priv->owner && !gtk_widget_get_has_window (priv->owner)) + { + GtkAllocation widget_alloc; + gtk_widget_get_allocation (priv->owner, &widget_alloc); + + graphene_rect_init (bounds, + priv->clip.x - widget_alloc.x, priv->clip.y - widget_alloc.y, + priv->clip.width, priv->clip.height); + } + else + { + graphene_rect_init (bounds, + priv->clip.x, priv->clip.y, + priv->clip.width, priv->clip.height); + } +} + +static gboolean +gtk_css_gadget_real_snapshot (GtkCssGadget *gadget, + GtkSnapshot *snapshot, + int x, + int y, + int width, + int height) +{ + graphene_rect_t bounds; + gboolean result; + cairo_t *cr; + + gtk_css_gadget_get_clip (gadget, &bounds); + cr = gtk_snapshot_append_cairo_node (snapshot, &bounds, "Fallback<%s>", G_OBJECT_TYPE_NAME (gadget)); + + result = GTK_CSS_GADGET_GET_CLASS (gadget)->draw (gadget, cr, x, y, width, height); + + cairo_destroy (cr); + + return result; +} + static void gtk_css_gadget_real_style_changed (GtkCssGadget *gadget, GtkCssStyleChange *change) @@ -277,6 +322,7 @@ gtk_css_gadget_class_init (GtkCssGadgetClass *klass) klass->get_preferred_size = gtk_css_gadget_real_get_preferred_size; klass->allocate = gtk_css_gadget_real_allocate; klass->draw = gtk_css_gadget_real_draw; + klass->snapshot = gtk_css_gadget_real_snapshot; klass->get_render_node = gtk_css_gadget_real_get_render_node; klass->style_changed = gtk_css_gadget_real_style_changed; klass->has_content = gtk_css_gadget_has_content; @@ -1117,6 +1163,102 @@ gtk_css_gadget_draw (GtkCssGadget *gadget, #endif } +/** + * gtk_css_gadget_snapshot: + * @gadget: The gadget to snapshot + * @snapshot: The snapshot to use + * + * Will draw the gadget at the position allocated via + * gtk_css_gadget_allocate(). It is your responsibility to make + * sure that those 2 coordinate systems match. + * + * The drawing virtual function will be passed an untransformed @cr. + * This is important because functions like + * gtk_container_propagate_draw() depend on that. + */ +void +gtk_css_gadget_snapshot (GtkCssGadget *gadget, + GtkSnapshot *snapshot) +{ + GtkCssGadgetPrivate *priv = gtk_css_gadget_get_instance_private (gadget); + GtkBorder margin, border, padding; + gboolean draw_focus = FALSE; + GtkCssStyle *style; + int x, y, width, height; + int contents_x, contents_y, contents_width, contents_height; + GtkAllocation margin_box; + graphene_rect_t bounds; + + if (!gtk_css_gadget_get_visible (gadget)) + return; + + gtk_css_gadget_get_clip (gadget, &bounds); + if (gtk_snapshot_clips_rect (snapshot, &bounds)) + return; + + gtk_css_gadget_get_margin_box (gadget, &margin_box); + + x = margin_box.x; + y = margin_box.y; + width = margin_box.width; + height = margin_box.height; + + if (width < 0 || height < 0) + { + g_warning ("Drawing a gadget with negative dimensions. " + "Did you forget to allocate a size? (node %s owner %s)", + gtk_css_node_get_name (gtk_css_gadget_get_node (gadget)), + G_OBJECT_TYPE_NAME (gtk_css_gadget_get_owner (gadget))); + x = 0; + y = 0; + width = gtk_widget_get_allocated_width (priv->owner); + height = gtk_widget_get_allocated_height (priv->owner); + } + + style = gtk_css_gadget_get_style (gadget); + get_box_margin (style, &margin); + get_box_border (style, &border); + get_box_padding (style, &padding); + + gtk_snapshot_push (snapshot, &bounds, "%s<%s>", gtk_css_node_get_name (priv->node), G_OBJECT_TYPE_NAME (priv->owner)); + + gtk_snapshot_translate_2d (snapshot, x + margin.left, y + margin.top); + gtk_css_style_snapshot_background (style, + snapshot, + width - margin.left - margin.right, + height - margin.top - margin.bottom, + gtk_css_node_get_junction_sides (priv->node)); + gtk_css_style_snapshot_border (style, + snapshot, + width - margin.left - margin.right, + height - margin.top - margin.bottom, + gtk_css_node_get_junction_sides (priv->node)); + gtk_snapshot_translate_2d (snapshot, - x - margin.left, - y - margin.top); + + contents_x = x + margin.left + border.left + padding.left; + contents_y = y + margin.top + border.top + padding.top; + contents_width = width - margin.left - margin.right - border.left - border.right - padding.left - padding.right; + contents_height = height - margin.top - margin.bottom - border.top - border.bottom - padding.top - padding.bottom; + + if (contents_width > 0 && contents_height > 0) + draw_focus = GTK_CSS_GADGET_GET_CLASS (gadget)->snapshot (gadget, + snapshot, + contents_x, contents_y, + contents_width, contents_height); + + if (draw_focus) + { + gtk_snapshot_translate_2d (snapshot, x + margin.left, y + margin.top); + gtk_css_style_snapshot_outline (style, + snapshot, + width - margin.left - margin.right, + height - margin.top - margin.bottom); + gtk_snapshot_translate_2d (snapshot, - x - margin.left, - y - margin.top); + } + + gtk_snapshot_pop (snapshot); +} + GskRenderNode * gtk_css_gadget_get_render_node (GtkCssGadget *gadget, GskRenderer *renderer, diff --git a/gtk/gtkcssgadgetprivate.h b/gtk/gtkcssgadgetprivate.h index 347920d0ad..3542746e02 100644 --- a/gtk/gtkcssgadgetprivate.h +++ b/gtk/gtkcssgadgetprivate.h @@ -67,6 +67,12 @@ struct _GtkCssGadgetClass int y, int width, int height); + gboolean (* snapshot) (GtkCssGadget *gadget, + GtkSnapshot *snapshot, + int x, + int y, + int width, + int height); GskRenderNode * (* get_render_node) (GtkCssGadget *gadget, GskRenderer *renderer, @@ -130,6 +136,8 @@ void gtk_css_gadget_allocate (GtkCssGadget GtkAllocation *out_clip); void gtk_css_gadget_draw (GtkCssGadget *gadget, cairo_t *cr); +void gtk_css_gadget_snapshot (GtkCssGadget *gadget, + GtkSnapshot *snapshot); GskRenderNode * gtk_css_gadget_get_render_node (GtkCssGadget *gadget, GskRenderer *renderer, diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c index 2a0507a338..26aef79382 100644 --- a/gtk/gtksnapshot.c +++ b/gtk/gtksnapshot.c @@ -251,6 +251,13 @@ gtk_snapshot_push_cairo_node (GtkSnapshot *state, return gsk_render_node_get_draw_context (node, state->renderer); } +gboolean +gtk_snapshot_clips_rect (GtkSnapshot *snapshot, + const graphene_rect_t *bounds) +{ + return FALSE; +} + void gtk_snapshot_render_background (GtkSnapshot *state, GtkStyleContext *context, diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h index 90ecef0d9e..159c25362c 100644 --- a/gtk/gtksnapshot.h +++ b/gtk/gtksnapshot.h @@ -78,6 +78,10 @@ cairo_t * gtk_snapshot_append_cairo_node (GtkSnapshot const char *name, ...) G_GNUC_PRINTF(3, 4); +GDK_AVAILABLE_IN_3_90 +gboolean gtk_snapshot_clips_rect (GtkSnapshot *snapshot, + const graphene_rect_t *bounds); + GDK_AVAILABLE_IN_3_90 void gtk_snapshot_render_background (GtkSnapshot *state, GtkStyleContext *context,