diff --git a/tests/gtkclipper.c b/tests/gtkclipper.c new file mode 100644 index 0000000000..67211995d2 --- /dev/null +++ b/tests/gtkclipper.c @@ -0,0 +1,157 @@ +#include "gtk/gtk.h" +#include "gtkclipperprivate.h" + +struct _GtkClipper +{ + GObject parent_instance; + + GdkPaintable *paintable; + graphene_rect_t clip; +}; + +struct _GtkClipperClass +{ + GObjectClass parent_class; +}; + +static void +gtk_clipper_paintable_snapshot (GdkPaintable *paintable, + GdkSnapshot *snapshot, + double width, + double height) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + float sx, sy; + + gtk_snapshot_save (snapshot); + + sx = gdk_paintable_get_intrinsic_width (self->paintable) / self->clip.size.width; + sy = gdk_paintable_get_intrinsic_height (self->paintable) / self->clip.size.height; + + gtk_snapshot_push_clip (snapshot, &GRAPHENE_RECT_INIT (0, 0, width, height)); + + gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- self->clip.origin.x * width / self->clip.size.width, + - self->clip.origin.y * height / self->clip.size.height)); + gdk_paintable_snapshot (self->paintable, snapshot, width * sx, height * sy); + gtk_snapshot_pop (snapshot); + gtk_snapshot_restore (snapshot); +} + +static GdkPaintable * +gtk_clipper_paintable_get_current_image (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + GdkPaintable *current_paintable, *current_self; + + current_paintable = gdk_paintable_get_current_image (self->paintable); + current_self = gtk_clipper_new (current_paintable, &self->clip); + g_object_unref (current_paintable); + + return current_self; +} + +static GdkPaintableFlags +gtk_clipper_paintable_get_flags (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + + return gdk_paintable_get_flags (self->paintable); +} + +static int +gtk_clipper_paintable_get_intrinsic_width (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + + return self->clip.size.width; +} + +static int +gtk_clipper_paintable_get_intrinsic_height (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + + return self->clip.size.height; +} + +static double gtk_clipper_paintable_get_intrinsic_aspect_ratio (GdkPaintable *paintable) +{ + GtkClipper *self = GTK_CLIPPER (paintable); + + return self->clip.size.width / (double) self->clip.size.height; +}; + +static void +gtk_clipper_paintable_init (GdkPaintableInterface *iface) +{ + iface->snapshot = gtk_clipper_paintable_snapshot; + iface->get_current_image = gtk_clipper_paintable_get_current_image; + iface->get_flags = gtk_clipper_paintable_get_flags; + iface->get_intrinsic_width = gtk_clipper_paintable_get_intrinsic_width; + iface->get_intrinsic_height = gtk_clipper_paintable_get_intrinsic_height; + iface->get_intrinsic_aspect_ratio = gtk_clipper_paintable_get_intrinsic_aspect_ratio; +} + +G_DEFINE_TYPE_EXTENDED (GtkClipper, gtk_clipper, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE, + gtk_clipper_paintable_init)) + +static void +gtk_clipper_dispose (GObject *object) +{ + GtkClipper *self = GTK_CLIPPER (object); + + if (self->paintable) + { + const guint flags = gdk_paintable_get_flags (self->paintable); + + if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0) + g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_contents, self); + + if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0) + g_signal_handlers_disconnect_by_func (self->paintable, gdk_paintable_invalidate_size, self); + + g_clear_object (&self->paintable); + } + + G_OBJECT_CLASS (gtk_clipper_parent_class)->dispose (object); +} + +static void +gtk_clipper_class_init (GtkClipperClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gtk_clipper_dispose; +} + +static void +gtk_clipper_init (GtkClipper *self) +{ +} + +GdkPaintable * +gtk_clipper_new (GdkPaintable *paintable, + const graphene_rect_t *clip) +{ + GtkClipper *self; + guint flags; + + g_return_val_if_fail (GDK_IS_PAINTABLE (paintable), NULL); + g_return_val_if_fail (clip != NULL, NULL); + + self = g_object_new (GTK_TYPE_CLIPPER, NULL); + + self->paintable = g_object_ref (paintable); + flags = gdk_paintable_get_flags (paintable); + + if ((flags & GDK_PAINTABLE_STATIC_CONTENTS) == 0) + g_signal_connect_swapped (paintable, "invalidate-contents", G_CALLBACK (gdk_paintable_invalidate_contents), self); + + if ((flags & GDK_PAINTABLE_STATIC_SIZE) == 0) + g_signal_connect_swapped (paintable, "invalidate-size", G_CALLBACK (gdk_paintable_invalidate_size), self); + + self->clip = *clip; + + return GDK_PAINTABLE (self); +} diff --git a/tests/gtkclipperprivate.h b/tests/gtkclipperprivate.h new file mode 100644 index 0000000000..2b4a61d0cc --- /dev/null +++ b/tests/gtkclipperprivate.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_CLIPPER (gtk_clipper_get_type ()) + +G_DECLARE_FINAL_TYPE (GtkClipper, gtk_clipper, GTK, CLIPPER, GObject) + +GdkPaintable * gtk_clipper_new (GdkPaintable *paintable, + const graphene_rect_t *clip); + +G_END_DECLS + diff --git a/tests/meson.build b/tests/meson.build index 253640c461..6990712cb7 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -133,7 +133,7 @@ endif if os_linux gtk_tests += [ - ['testdmabuf'], + ['testdmabuf', ['testdmabuf.c', 'gtkclipper.c']], ] endif diff --git a/tests/padded.png b/tests/padded.png new file mode 100644 index 0000000000..0501851547 Binary files /dev/null and b/tests/padded.png differ diff --git a/tests/testdmabuf.c b/tests/testdmabuf.c index df166beea0..d603abe10c 100644 --- a/tests/testdmabuf.c +++ b/tests/testdmabuf.c @@ -9,6 +9,9 @@ #ifdef GDK_RENDERING_VULKAN #include #endif + +#include "gtkclipperprivate.h" + /* For this to work, you may need to give /dev/dma_heap/system * lax permissions. */ @@ -449,13 +452,12 @@ texture_builder_set_planes (GdkDmabufTextureBuilder *builder, } static GdkTexture * -make_dmabuf_texture (const char *filename, +make_dmabuf_texture (GdkTexture *texture, guint32 format, gboolean disjoint, gboolean premultiplied, gboolean flip) { - GdkTexture *texture; GdkTextureDownloader *downloader; int width, height; gsize rgb_stride, rgb_size; @@ -471,8 +473,6 @@ make_dmabuf_texture (const char *filename, else g_print ("Using memfd\n"); - texture = gdk_texture_new_from_filename (filename, NULL); - width = gdk_texture_get_width (texture); height = gdk_texture_get_height (texture); rgb_stride = 4 * width; @@ -490,8 +490,6 @@ make_dmabuf_texture (const char *filename, gdk_texture_downloader_download_into (downloader, rgb_data, rgb_stride); gdk_texture_downloader_free (downloader); - g_object_unref (texture); - if (flip) { for (int y = 0; y < height; y++) @@ -643,7 +641,7 @@ static void usage (void) { char *formats = supported_formats_to_string (); - g_print ("Usage: testdmabuf [--undecorated][--disjoint][--download-to FILE] FORMAT FILE\n" + g_print ("Usage: testdmabuf [--undecorated][--disjoint][--download-to FILE][--padding PADDING] FORMAT FILE\n" "Supported formats: %s\n", formats); g_free (formats); exit (1); @@ -717,6 +715,9 @@ toggle_flip (GtkWidget *widget, { GtkPicture *picture = data; + if (!texture_flipped) + return FALSE; + if (gtk_picture_get_paintable (picture) == GDK_PAINTABLE (texture)) gtk_picture_set_paintable (picture, GDK_PAINTABLE (texture_flipped)); else @@ -756,6 +757,10 @@ main (int argc, char *argv[]) GtkShortcutTrigger *trigger; GtkShortcutAction *action; GtkShortcut *shortcut; + GdkPaintable *paintable; + GdkTexture *orig; + int padding[4] = { 0, }; /* left, right, top, bottom */ + int padding_set = 0; for (i = 1; i < argc; i++) { @@ -775,6 +780,37 @@ main (int argc, char *argv[]) save_filename = argv[i]; } + else if (g_str_equal (argv[i], "--padding")) + { + if (padding_set < 4) + { + char **strv; + + i++; + if (i == argc) + usage (); + + strv = g_strsplit (argv[i], ",", 0); + if (g_strv_length (strv) > 4) + g_error ("Too much padding"); + + for (padding_set = 0; padding_set < 4; padding_set++) + { + guint64 num; + GError *error = NULL; + + if (!strv[padding_set]) + break; + + if (!g_ascii_string_to_unsigned (strv[padding_set], 10, 0, 100, &num, &error)) + g_error ("%s", error->message); + + padding[padding_set] = (int) num; + } + } + else + g_error ("Too much padding"); + } else break; } @@ -793,8 +829,21 @@ main (int argc, char *argv[]) /* Get the list of supported formats with GDK_DEBUG=opengl */ gdk_display_get_dmabuf_formats (gdk_display_get_default ()); - texture = make_dmabuf_texture (filename, format, disjoint, premultiplied, FALSE); - texture_flipped = make_dmabuf_texture (filename, format, disjoint, premultiplied, TRUE); + orig = gdk_texture_new_from_filename (filename, NULL); + texture = make_dmabuf_texture (orig, format, disjoint, premultiplied, FALSE); + texture_flipped = make_dmabuf_texture (orig, format, disjoint, premultiplied, TRUE); + g_object_unref (orig); + + if (padding_set > 0) + { + paintable = gtk_clipper_new (GDK_PAINTABLE (texture), + &GRAPHENE_RECT_INIT (padding[0], + padding[2], + gdk_texture_get_width (texture) - padding[0] - padding[1], + gdk_texture_get_height (texture) - padding[2] - padding[3])); + } + else + paintable = GDK_PAINTABLE (texture); if (save_filename) gdk_texture_save_to_png (texture, save_filename); @@ -804,7 +853,7 @@ main (int argc, char *argv[]) if (fullscreen) gtk_window_fullscreen (GTK_WINDOW (window)); - picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (texture)); + picture = gtk_picture_new_for_paintable (paintable); offload = gtk_graphics_offload_new (picture); gtk_widget_set_halign (offload, GTK_ALIGN_CENTER); gtk_widget_set_valign (offload, GTK_ALIGN_CENTER);