testdndresize: Add non-resizing redrawing GL surface
authorIvan Molodetskikh <yalterz@gmail.com>
Wed, 15 Mar 2023 23:09:51 +0000 (16:09 -0700)
committerIvan Molodetskikh <yalterz@gmail.com>
Wed, 15 Mar 2023 23:09:51 +0000 (16:09 -0700)
The GL Wayland drag surface code path has a bug where it does not reset
the hotspot, so if a GL-backed draw surface redraws without resizing or
resetting the hotspot, it moves away. The next commit will fix that, but
this commit adds a test for that.

tests/testdndresize.c

index 39bcbcdc5b21ea67bee3a25fe445e68c1787a8ef..5c78bf560691a2e5f35c432ec027fcc4df01e549 100644 (file)
@@ -5,6 +5,58 @@ static GtkRequisition size;
 static gint64 start_time;
 static gboolean stop_update_size;
 
+// Animated paintable for testing content-invalidating drag surfaces.
+#define GTK_TYPE_ANIMATED_ICON (gtk_animated_icon_get_type ())
+G_DECLARE_FINAL_TYPE (GtkAnimatedIcon, gtk_animated_icon, GTK, ANIMATED_ICON, GObject)
+
+struct _GtkAnimatedIcon
+{
+  GObject parent_instance;
+};
+
+struct _GtkAnimatedIconClass
+{
+  GObjectClass parent_class;
+};
+
+static void
+gtk_animated_icon_snapshot (GdkPaintable *paintable,
+                            GdkSnapshot  *snapshot,
+                            double        width,
+                            double        height)
+{
+  gint64 now = g_get_monotonic_time ();
+  float t;
+
+  t = fmodf ((now - start_time) / (float) G_TIME_SPAN_SECOND, 1);
+  if (t >= 0.5)
+    t = 1 - t;
+
+  gtk_snapshot_append_color (snapshot,
+                             &(GdkRGBA) { 0, t + 0.5, 0, 1 },
+                             &GRAPHENE_RECT_INIT (0, 0, width, height));
+}
+
+static void
+gtk_animated_icon_paintable_init (GdkPaintableInterface *iface)
+{
+  iface->snapshot = gtk_animated_icon_snapshot;
+}
+
+G_DEFINE_TYPE_WITH_CODE (GtkAnimatedIcon, gtk_animated_icon, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (GDK_TYPE_PAINTABLE,
+                                                gtk_animated_icon_paintable_init))
+
+static void
+gtk_animated_icon_class_init (GtkAnimatedIconClass *klass)
+{
+}
+
+static void
+gtk_animated_icon_init (GtkAnimatedIcon *nuclear)
+{
+}
+
 static gboolean
 update_size (GtkWidget *widget, GdkFrameClock *clock, gpointer data)
 {
@@ -60,6 +112,30 @@ drag_end (GtkDragSource *source,
   stop_update_size = TRUE;
 }
 
+static gboolean
+invalidate_contents (GtkWidget *widget, GdkFrameClock *clock, gpointer data)
+{
+  GdkPaintable *paintable = data;
+  gdk_paintable_invalidate_contents (paintable);
+  return G_SOURCE_CONTINUE;
+}
+
+static void
+drag_begin_non_resizing (GtkDragSource *source,
+                         GdkDrag       *drag)
+{
+  GdkPaintable *paintable;
+  GtkWidget *widget;
+  int width = 64, height = 32;
+
+  paintable = GDK_PAINTABLE (g_object_new (GTK_TYPE_ANIMATED_ICON, NULL));
+  gtk_drag_icon_set_from_paintable (drag, paintable, width / 2, height / 2);
+
+  widget = gtk_drag_icon_get_child (GTK_DRAG_ICON (gtk_drag_icon_get_for_drag (drag)));
+  gtk_widget_set_size_request (widget, width, height);
+  gtk_widget_add_tick_callback (widget, invalidate_contents, paintable, NULL);
+}
+
 static void
 quit_cb (GtkWidget *widget,
          gpointer   data)
@@ -76,6 +152,7 @@ main (int argc, char *argv[])
 {
   GtkCssProvider *provider;
   GtkWidget *window;
+  GtkWidget *box;
   GtkWidget *label;
   GtkDragSource *source;
   GdkContentProvider *content;
@@ -97,7 +174,10 @@ main (int argc, char *argv[])
   window = gtk_window_new ();
   g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
 
-  label = gtk_label_new ("Drag Me");
+  box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+
+  // The resizing icon label.
+  label = gtk_label_new ("Drag Me (Resizing)");
   g_object_set (label,
                 "margin-start", 64,
                 "margin-end", 64,
@@ -112,7 +192,26 @@ main (int argc, char *argv[])
   g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), NULL);
   gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (source));
 
-  gtk_window_set_child (GTK_WINDOW (window), label);
+  gtk_box_append (GTK_BOX (box), label);
+
+  // The non-resizing icon label.
+  label = gtk_label_new ("Drag Me (Non-Resizing)");
+  g_object_set (label,
+                "margin-start", 64,
+                "margin-end", 64,
+                "margin-top", 64,
+                "margin-bottom", 64,
+                NULL);
+
+  source = gtk_drag_source_new ();
+  content = gdk_content_provider_new_typed (G_TYPE_STRING, "I'm data!");
+  gtk_drag_source_set_content (source, content);
+  g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin_non_resizing), NULL);
+  gtk_widget_add_controller (label, GTK_EVENT_CONTROLLER (source));
+
+  gtk_box_append (GTK_BOX (box), label);
+
+  gtk_window_set_child (GTK_WINDOW (window), box);
 
   gtk_window_present (GTK_WINDOW (window));