gtk2/tests/showrendernode.c
Timm Bäder 9675b8a310 showrendernode: Add some advanced options
1) Add a --compare cmd line switch that lets people compare the normal
     render path and the render_texture path.
  2) Add a -o cmd line switch that lets people render the given .node
     file to a texture and save that texture to the given png file name.
2017-12-28 16:48:35 +01:00

227 lines
6.5 KiB
C

#include <gtk/gtk.h>
static char *write_to_filename = NULL;
static gboolean compare_node;
static GOptionEntry options[] = {
{ "write", 'o', 0, G_OPTION_ARG_STRING, &write_to_filename, "Write PNG file", NULL },
{ "compare", 'c', 0, G_OPTION_ARG_NONE, &compare_node, "Compare render to render_texture", NULL },
{ NULL }
};
typedef struct _GtkNodeView GtkNodeView;
typedef struct _GtkNodeViewClass GtkNodeViewClass;
#define GTK_TYPE_NODE_VIEW (gtk_node_view_get_type ())
#define GTK_NODE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, GTK_TYPE_NODE_VIEW, GtkNodeView))
#define GTK_NODE_VIEW_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST(cls, GTK_TYPE_NODE_VIEW, GtkNodeViewClass))
struct _GtkNodeView
{
GtkWidget parent_instance;
GskRenderNode *node;
};
struct _GtkNodeViewClass
{
GtkWidgetClass parent_class;
};
GType gtk_node_view_get_type (void) G_GNUC_CONST;
G_DEFINE_TYPE(GtkNodeView, gtk_node_view, GTK_TYPE_WIDGET)
static void
gtk_node_view_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkNodeView *self = GTK_NODE_VIEW (widget);
graphene_rect_t bounds;
if (self->node == NULL)
return;
gsk_render_node_get_bounds (self->node, &bounds);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
{
*minimum = *natural = bounds.origin.x + bounds.size.width;
}
else /* VERTICAL */
{
*minimum = *natural = bounds.origin.y + bounds.size.height;
}
}
static void
gtk_node_view_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GtkNodeView *self = GTK_NODE_VIEW (widget);
if (self->node != NULL)
{
gtk_snapshot_push_clip (snapshot,
&GRAPHENE_RECT_INIT (
0, 0,
gtk_widget_get_width (widget), gtk_widget_get_height (widget)),
"nodeview clip");
gtk_snapshot_append_node (snapshot, self->node);
gtk_snapshot_pop (snapshot);
}
}
static void
gtk_node_view_finalize (GObject *object)
{
GtkNodeView *self = GTK_NODE_VIEW (object);
if (self->node)
gsk_render_node_unref (self->node);
G_OBJECT_CLASS (gtk_node_view_parent_class)->finalize (object);
}
static void
gtk_node_view_init (GtkNodeView *self)
{
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
}
static void
gtk_node_view_class_init (GtkNodeViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->finalize = gtk_node_view_finalize;
widget_class->measure = gtk_node_view_measure;
widget_class->snapshot = gtk_node_view_snapshot;
}
int
main (int argc, char **argv)
{
GtkWidget *window;
GtkWidget *nodeview;
char *contents;
gsize len;
GBytes *bytes;
graphene_rect_t node_bounds;
GOptionContext *option_context;
GError *error = NULL;
option_context = g_option_context_new ("NODE-FILE [-o OUTPUT] [--compare]");
g_option_context_add_main_entries (option_context, options, NULL);
if (argc < 2)
{
printf ("Usage: showrendernode NODEFILE [-o OUTPUT] [--compare]\n");
return 0;
}
if (!g_option_context_parse (option_context, &argc, &argv, &error))
{
g_printerr ("Option parsing failed: %s\n", error->message);
return 1;
}
g_message ("Compare: %d, write to filename: %s", compare_node, write_to_filename);
gtk_init ();
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
nodeview = g_object_new (GTK_TYPE_NODE_VIEW, NULL);
gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
g_file_get_contents (argv[1], &contents, &len, &error);
if (error)
{
g_warning ("%s", error->message);
return -1;
}
bytes = g_bytes_new_take (contents, len);
GTK_NODE_VIEW (nodeview)->node = gsk_render_node_deserialize (bytes, &error);
g_bytes_unref (bytes);
if (GTK_NODE_VIEW (nodeview)->node == NULL)
{
g_critical ("Invalid node file: %s", error->message);
g_clear_error (&error);
return -1;
}
if (write_to_filename != NULL)
{
GdkWindow *window = gdk_window_new_toplevel (gdk_display_get_default(), 10 , 10);
GskRenderer *renderer = gsk_renderer_new_for_window (window);
GdkTexture *texture = gsk_renderer_render_texture (renderer, GTK_NODE_VIEW (nodeview)->node, NULL);
cairo_surface_t *rendered_surface;
g_message ("Writing .node file to .png using %s", G_OBJECT_TYPE_NAME (renderer));
g_assert (texture != NULL);
rendered_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
gdk_texture_get_width (texture),
gdk_texture_get_height (texture));
gdk_texture_download (texture,
cairo_image_surface_get_data (rendered_surface),
cairo_image_surface_get_stride (rendered_surface));
cairo_surface_mark_dirty (rendered_surface);
cairo_surface_write_to_png (rendered_surface, write_to_filename);
gsk_renderer_unrealize (renderer);
g_object_unref (texture);
g_object_unref (renderer);
g_object_unref (window);
}
if (compare_node)
{
GtkWidget *box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
GdkWindow *gdk_window = gdk_window_new_toplevel (gdk_display_get_default(), 10 , 10);
GskRenderer *renderer = gsk_renderer_new_for_window (gdk_window);
GdkTexture *texture = gsk_renderer_render_texture (renderer, GTK_NODE_VIEW (nodeview)->node, NULL);
GtkWidget *image = gtk_image_new_from_texture (texture);
gtk_container_add (GTK_CONTAINER (box), nodeview);
gtk_container_add (GTK_CONTAINER (box), image);
gtk_container_add (GTK_CONTAINER (window), box);
gsk_renderer_unrealize (renderer);
g_object_unref (texture);
g_object_unref (renderer);
g_object_unref (gdk_window);
}
else
{
gtk_container_add (GTK_CONTAINER (window), nodeview);
}
gsk_render_node_get_bounds (GTK_NODE_VIEW (nodeview)->node, &node_bounds);
gtk_window_resize (GTK_WINDOW (window),
MAX (600, node_bounds.size.width),
MAX (500, node_bounds.size.height));
g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show (window);
gtk_main ();
return 0;
}