window: Implement snapshot()

This commit is contained in:
Benjamin Otte 2016-11-08 01:42:06 +01:00
parent b1154be1c4
commit bb9626dc29
8 changed files with 137 additions and 53 deletions

View File

@ -42,6 +42,7 @@
#include "gtkmarshalers.h"
#include "gtksizerequest.h"
#include "gtksizerequestcacheprivate.h"
#include "gtksnapshotprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkwindow.h"
#include "gtkassistant.h"
@ -3158,47 +3159,16 @@ gtk_container_get_children_clip (GtkContainer *container,
gtk_container_forall (container, union_with_clip, out_clip);
}
/**
* gtk_container_propagate_draw:
* @container: a #GtkContainer
* @child: a child of @container
* @cr: Cairo context as passed to the container. If you want to use @cr
* in containers draw function, consider using cairo_save() and
* cairo_restore() before calling this function.
*
* When a container receives a call to the draw function, it must send
* synthetic #GtkWidget::draw calls to all children that dont have their
* own #GdkWindows. This function provides a convenient way of doing this.
* A container, when it receives a call to its #GtkWidget::draw function,
* calls gtk_container_propagate_draw() once for each child, passing in
* the @cr the container received.
*
* gtk_container_propagate_draw() takes care of translating the origin of @cr,
* and deciding whether the draw needs to be sent to the child. It is a
* convenient and optimized way of getting the same effect as calling
* gtk_widget_draw() on the child directly.
*
* In most cases, a container can simply either inherit the
* #GtkWidget::draw implementation from #GtkContainer, or do some drawing
* and then chain to the ::draw implementation from #GtkContainer.
**/
void
gtk_container_propagate_draw (GtkContainer *container,
GtkWidget *child,
cairo_t *cr)
static void
gtk_container_get_translation_to_child (GtkContainer *container,
GtkWidget *child,
int *x_out,
int *y_out)
{
GtkAllocation allocation;
GdkWindow *window, *w;
int x, y;
g_return_if_fail (GTK_IS_CONTAINER (container));
g_return_if_fail (GTK_IS_WIDGET (child));
g_return_if_fail (cr != NULL);
g_return_if_fail (_gtk_widget_get_parent (child) == GTK_WIDGET (container));
if (!gtk_container_should_propagate_draw (container, child, cr))
return;
/* translate coordinates. Ugly business, that. */
if (!_gtk_widget_get_has_window (GTK_WIDGET (container)))
{
@ -3235,6 +3205,51 @@ gtk_container_propagate_draw (GtkContainer *container,
y += allocation.y;
}
*x_out = x;
*y_out = y;
}
/**
* gtk_container_propagate_draw:
* @container: a #GtkContainer
* @child: a child of @container
* @cr: Cairo context as passed to the container. If you want to use @cr
* in containers draw function, consider using cairo_save() and
* cairo_restore() before calling this function.
*
* When a container receives a call to the draw function, it must send
* synthetic #GtkWidget::draw calls to all children that dont have their
* own #GdkWindows. This function provides a convenient way of doing this.
* A container, when it receives a call to its #GtkWidget::draw function,
* calls gtk_container_propagate_draw() once for each child, passing in
* the @cr the container received.
*
* gtk_container_propagate_draw() takes care of translating the origin of @cr,
* and deciding whether the draw needs to be sent to the child. It is a
* convenient and optimized way of getting the same effect as calling
* gtk_widget_draw() on the child directly.
*
* In most cases, a container can simply either inherit the
* #GtkWidget::draw implementation from #GtkContainer, or do some drawing
* and then chain to the ::draw implementation from #GtkContainer.
**/
void
gtk_container_propagate_draw (GtkContainer *container,
GtkWidget *child,
cairo_t *cr)
{
int x, y;
g_return_if_fail (GTK_IS_CONTAINER (container));
g_return_if_fail (GTK_IS_WIDGET (child));
g_return_if_fail (cr != NULL);
g_return_if_fail (_gtk_widget_get_parent (child) == GTK_WIDGET (container));
if (!gtk_container_should_propagate_draw (container, child, cr))
return;
gtk_container_get_translation_to_child (container, child, &x, &y);
cairo_save (cr);
cairo_translate (cr, x, y);
@ -3243,6 +3258,36 @@ gtk_container_propagate_draw (GtkContainer *container,
cairo_restore (cr);
}
void
gtk_container_snapshot_child (GtkContainer *container,
GskRenderNode *container_node,
GtkWidget *child,
const GtkSnapshot *snapshot)
{
GtkSnapshot child_snapshot;
GskRenderNode *child_node;
int x, y;
g_return_if_fail (GTK_IS_CONTAINER (container));
g_return_if_fail (GTK_IS_WIDGET (child));
g_return_if_fail (_gtk_widget_get_parent (child) == GTK_WIDGET (container));
g_return_if_fail (GSK_IS_RENDER_NODE (container_node));
g_return_if_fail (snapshot != NULL);
gtk_container_get_translation_to_child (container, child, &x, &y);
gtk_snapshot_init_translate (&child_snapshot, snapshot, x, y);
child_node = gtk_widget_snapshot (child, &child_snapshot);
if (child_node)
{
gsk_render_node_append_child (container_node, child_node);
gsk_render_node_unref (child_node);
}
gtk_snapshot_finish (&child_snapshot);
}
/**
* gtk_container_get_path_for_child:
* @container: a #GtkContainer

View File

@ -50,6 +50,10 @@ void gtk_container_propagate_render_node_for_child (GtkContainer *contai
GtkWidget *child,
GskRenderer *renderer,
GskRenderNode *parent_node);
void gtk_container_snapshot_child (GtkContainer *container,
GskRenderNode *container_node,
GtkWidget *child,
const GtkSnapshot *snapshot);
G_END_DECLS

View File

@ -265,8 +265,8 @@ gtk_debug_updates_queue_get_extents (GQueue *updates,
}
GskRenderNode *
gtk_debug_updates_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
gtk_debug_updates_snapshot (GtkWidget *widget,
const GtkSnapshot *snapshot)
{
GQueue *updates;
GskRenderNode *node;
@ -287,12 +287,11 @@ gtk_debug_updates_get_render_node (GtkWidget *widget,
gtk_debug_updates_print (updates, NULL, "Painting at %lli", (long long) timestamp);
node = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (node, "Debug Updates");
node = gtk_snapshot_create_render_node (snapshot, "Debug Updates");
gtk_debug_updates_queue_get_extents (updates, &rect);
gsk_render_node_set_bounds (node, &(graphene_rect_t) GRAPHENE_RECT_INIT(rect.x, rect.y, rect.width, rect.height));
cr = gsk_render_node_get_draw_context (node, renderer);
cr = gsk_render_node_get_draw_context (node, gtk_snapshot_get_renderer (snapshot));
for (l = g_queue_peek_head_link (updates); l != NULL; l = l->next)
{

View File

@ -31,8 +31,8 @@ void gtk_debug_updates_set_enabled_for_display (GdkDisplay
void gtk_debug_updates_add (GtkWidget *widget,
const cairo_region_t *region);
GskRenderNode * gtk_debug_updates_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
GskRenderNode * gtk_debug_updates_snapshot (GtkWidget *widget,
const GtkSnapshot *snapshot);
G_END_DECLS

View File

@ -31,6 +31,19 @@ gtk_snapshot_init (GtkSnapshot *state,
graphene_matrix_init_from_matrix (&state->transform, transform);
}
void
gtk_snapshot_init_translate (GtkSnapshot *state,
const GtkSnapshot *parent,
int x,
int y)
{
graphene_matrix_t matrix;
graphene_matrix_init_translate (&matrix, &(graphene_point3d_t) GRAPHENE_POINT3D_INIT (x, y, 0));
gtk_snapshot_init (state, parent, &matrix);
}
void
gtk_snapshot_init_root (GtkSnapshot *state,
GskRenderer *renderer)

View File

@ -33,9 +33,19 @@ struct _GtkSnapshot {
void gtk_snapshot_init (GtkSnapshot *state,
const GtkSnapshot *parent,
const graphene_matrix_t *transform);
void gtk_snapshot_init_translate (GtkSnapshot *state,
const GtkSnapshot *parent,
int x,
int y);
void gtk_snapshot_init_root (GtkSnapshot *state,
GskRenderer *renderer);
static inline const graphene_matrix_t *
gtk_snapshot_get_transform (const GtkSnapshot *snapshot)
{
return &snapshot->transform;
}
void gtk_snapshot_finish (GtkSnapshot *state);
G_END_DECLS

View File

@ -15742,6 +15742,9 @@ gtk_widget_snapshot (GtkWidget *widget,
}
}
if (node)
gsk_render_node_set_transform (node, gtk_snapshot_get_transform (snapshot));
return node;
}

View File

@ -447,8 +447,8 @@ static void gtk_window_real_activate_focus (GtkWindow *window);
static void gtk_window_keys_changed (GtkWindow *window);
static gboolean gtk_window_enable_debugging (GtkWindow *window,
gboolean toggle);
static GskRenderNode *gtk_window_get_render_node (GtkWidget *widget,
GskRenderer *renderer);
static GskRenderNode *gtk_window_snapshot (GtkWidget *widget,
const GtkSnapshot *snapshot);
static void gtk_window_unset_transient_for (GtkWindow *window);
static void gtk_window_transient_parent_realized (GtkWidget *parent,
GtkWidget *window);
@ -776,7 +776,7 @@ gtk_window_class_init (GtkWindowClass *klass)
widget_class->measure = gtk_window_measure;
widget_class->state_flags_changed = gtk_window_state_flags_changed;
widget_class->style_updated = gtk_window_style_updated;
widget_class->get_render_node = gtk_window_get_render_node;
widget_class->snapshot = gtk_window_snapshot;
widget_class->queue_draw_region = gtk_window_queue_draw_region;
container_class->remove = gtk_window_remove;
@ -9384,8 +9384,8 @@ gtk_window_compute_hints (GtkWindow *window,
***********************/
static GskRenderNode *
gtk_window_get_render_node (GtkWidget *widget,
GskRenderer *renderer)
gtk_window_snapshot (GtkWidget *widget,
const GtkSnapshot *snapshot)
{
GtkWindowPrivate *priv = GTK_WINDOW (widget)->priv;
GtkStyleContext *context;
@ -9397,6 +9397,7 @@ gtk_window_get_render_node (GtkWidget *widget,
graphene_matrix_t m;
graphene_point3d_t p;
cairo_t *cr;
GList *l;
context = gtk_widget_get_style_context (widget);
@ -9406,12 +9407,11 @@ gtk_window_get_render_node (GtkWidget *widget,
graphene_rect_init (&bounds, allocation.x, allocation.y, allocation.width, allocation.height);
graphene_matrix_init_translate (&m, graphene_point3d_init (&p, allocation.x, allocation.y, 0.));
node = gsk_renderer_create_render_node (renderer);
gsk_render_node_set_name (node, "Window Decoration");
node = gtk_snapshot_create_render_node (snapshot, "Window Decoration");
gsk_render_node_set_bounds (node, &bounds);
gsk_render_node_set_transform (node, &m);
cr = gsk_render_node_get_draw_context (node, renderer);
cr = gsk_render_node_get_draw_context (node, gtk_snapshot_get_renderer (snapshot));
if (priv->client_decorated &&
priv->decorated &&
@ -9478,9 +9478,19 @@ gtk_window_get_render_node (GtkWidget *widget,
cairo_destroy (cr);
gtk_container_propagate_render_node (GTK_CONTAINER (widget), renderer, node);
if (priv->title_box != NULL)
gtk_container_snapshot_child (GTK_CONTAINER (widget), node, priv->title_box, snapshot);
updates_node = gtk_debug_updates_get_render_node (widget, renderer);
if (gtk_bin_get_child (GTK_BIN (widget)))
gtk_container_snapshot_child (GTK_CONTAINER (widget), node, gtk_bin_get_child (GTK_BIN (widget)), snapshot);
for (l = priv->popovers; l; l = l->next)
{
GtkWindowPopover *data = l->data;
gtk_container_snapshot_child (GTK_CONTAINER (widget), node, data->widget, snapshot);
}
updates_node = gtk_debug_updates_snapshot (widget, snapshot);
if (updates_node)
{
gsk_render_node_append_child (node, updates_node);