[gtk/wip/chergert/quartz4u: 106/116] macos: add zoomback on drag cancel



commit ce6cb2a0a370682b3e159fdbcb926c5278b402cb
Author: Christian Hergert <chergert redhat com>
Date:   Thu Jun 18 16:43:36 2020 -0700

    macos: add zoomback on drag cancel

 gdk/macos/gdkmacosdrag-private.h |  26 ++++++++
 gdk/macos/gdkmacosdrag.c         | 125 ++++++++++++++++++++++++++++++---------
 gdk/macos/gdkmacossurface.c      |  15 +++--
 3 files changed, 134 insertions(+), 32 deletions(-)
---
diff --git a/gdk/macos/gdkmacosdrag-private.h b/gdk/macos/gdkmacosdrag-private.h
index 7a7bf8a041..7abd2b2270 100644
--- a/gdk/macos/gdkmacosdrag-private.h
+++ b/gdk/macos/gdkmacosdrag-private.h
@@ -22,6 +22,8 @@
 
 #include "gdkdragprivate.h"
 
+#include "gdkmacosdragsurface-private.h"
+
 G_BEGIN_DECLS
 
 #define GDK_TYPE_MACOS_DRAG            (gdk_macos_drag_get_type ())
@@ -34,6 +36,30 @@ G_BEGIN_DECLS
 typedef struct _GdkMacosDrag GdkMacosDrag;
 typedef struct _GdkMacosDragClass GdkMacosDragClass;
 
+struct _GdkMacosDrag
+{
+  GdkDrag parent_instance;
+
+  GdkMacosDragSurface *drag_surface;
+
+  int hot_x;
+  int hot_y;
+
+  int last_x;
+  int last_y;
+
+  int start_x;
+  int start_y;
+
+  guint did_update : 1;
+  guint cancelled : 1;
+};
+
+struct _GdkMacosDragClass
+{
+  GdkDragClass parent_class;
+};
+
 GType gdk_macos_drag_get_type (void) G_GNUC_CONST;
 
 G_END_DECLS
diff --git a/gdk/macos/gdkmacosdrag.c b/gdk/macos/gdkmacosdrag.c
index afa488e308..6d077540a5 100644
--- a/gdk/macos/gdkmacosdrag.c
+++ b/gdk/macos/gdkmacosdrag.c
@@ -29,24 +29,14 @@
 
 #define BIG_STEP 20
 #define SMALL_STEP 1
+#define ANIM_TIME 500000 /* .5 seconds */
 
-struct _GdkMacosDrag
+typedef struct
 {
-  GdkDrag parent_instance;
-
-  GdkMacosDragSurface *drag_surface;
-
-  int hot_x;
-  int hot_y;
-
-  int last_x;
-  int last_y;
-};
-
-struct _GdkMacosDragClass
-{
-  GdkDragClass parent_class;
-};
+  GdkMacosDrag  *drag;
+  GdkFrameClock *frame_clock;
+  gint64         start_time;
+} GdkMacosZoomback;
 
 G_DEFINE_TYPE (GdkMacosDrag, gdk_macos_drag, GDK_TYPE_DRAG)
 
@@ -58,6 +48,57 @@ enum {
 
 static GParamSpec *properties [N_PROPS];
 
+static double
+ease_out_cubic (double t)
+{
+  double p = t - 1;
+  return p * p * p + 1;
+}
+
+static void
+gdk_macos_zoomback_destroy (GdkMacosZoomback *zb)
+{
+  gdk_surface_hide (GDK_SURFACE (zb->drag->drag_surface));
+  g_object_unref (zb->drag);
+  g_slice_free (GdkMacosZoomback, zb);
+}
+
+static gboolean
+gdk_macos_zoomback_timeout (gpointer data)
+{
+  GdkMacosZoomback *zb = data;
+  GdkFrameClock *frame_clock;
+  GdkMacosDrag *drag;
+  gint64 current_time;
+  double f;
+  double t;
+
+  g_assert (zb != NULL);
+  g_assert (GDK_IS_MACOS_DRAG (zb->drag));
+
+  drag = zb->drag;
+  frame_clock = zb->frame_clock;
+
+  if (!frame_clock)
+    return G_SOURCE_REMOVE;
+
+  current_time = gdk_frame_clock_get_frame_time (frame_clock);
+  f = (current_time - zb->start_time) / (double) ANIM_TIME;
+  if (f >= 1.0)
+    return G_SOURCE_REMOVE;
+
+  t = ease_out_cubic (f);
+
+  _gdk_macos_surface_move (GDK_MACOS_SURFACE (drag->drag_surface),
+                           (drag->last_x - drag->hot_x) +
+                           (drag->start_x - drag->last_x) * t,
+                           (drag->last_y - drag->hot_y) +
+                           (drag->start_y - drag->last_y) * t);
+  _gdk_macos_surface_set_opacity (GDK_MACOS_SURFACE (drag->drag_surface), 1.0 - f);
+
+  return G_SOURCE_CONTINUE;
+}
+
 static GdkSurface *
 gdk_macos_drag_get_drag_surface (GdkDrag *drag)
 {
@@ -70,13 +111,21 @@ gdk_macos_drag_set_hotspot (GdkDrag *drag,
                             int      hot_y)
 {
   GdkMacosDrag *self = (GdkMacosDrag *)drag;
+  int change_x;
+  int change_y;
 
   g_assert (GDK_IS_MACOS_DRAG (self));
 
+  change_x = hot_x - self->hot_x;
+  change_y = hot_y - self->hot_y;
+
   self->hot_x = hot_x;
   self->hot_y = hot_y;
 
-  /* TODO: move/resize to take point into account */
+  if (change_x || change_y)
+    _gdk_macos_surface_move (GDK_MACOS_SURFACE (self->drag_surface),
+                             GDK_SURFACE (self->drag_surface)->x + change_x,
+                             GDK_SURFACE (self->drag_surface)->y + change_y);
 }
 
 static void
@@ -84,15 +133,31 @@ gdk_macos_drag_drop_done (GdkDrag  *drag,
                           gboolean  success)
 {
   GdkMacosDrag *self = (GdkMacosDrag *)drag;
+  GdkMacosZoomback *zb;
+  guint id;
 
   g_assert (GDK_IS_MACOS_DRAG (self));
 
-  gdk_surface_hide (GDK_SURFACE (self->drag_surface));
+  if (success)
+    {
+      gdk_surface_hide (GDK_SURFACE (self->drag_surface));
+      g_object_unref (drag);
+      return;
+    }
 
-  /* TODO: Apple HIG suggests doing a "zoomback" animation of
-   * the surface back towards the original position.
+  /* Apple HIG suggests doing a "zoomback" animation of the surface back
+   * towards the original position.
    */
-
+  zb = g_slice_new0 (GdkMacosZoomback);
+  zb->drag = g_object_ref (self);
+  zb->frame_clock = gdk_surface_get_frame_clock (GDK_SURFACE (self->drag_surface));
+  zb->start_time = gdk_frame_clock_get_frame_time (zb->frame_clock);
+
+  id = g_timeout_add_full (G_PRIORITY_DEFAULT, 17,
+                           gdk_macos_zoomback_timeout,
+                           zb,
+                           (GDestroyNotify) gdk_macos_zoomback_destroy);
+  g_source_set_name_by_id (id, "[gtk] gdk_macos_zoomback_timeout");
   g_object_unref (drag);
 }
 
@@ -119,11 +184,9 @@ gdk_macos_drag_cancel (GdkDrag             *drag,
 
   g_assert (GDK_IS_MACOS_DRAG (self));
 
-  g_print ("Drag cancel\n");
-
   gdk_drag_drop_done (drag, FALSE);
 
-  //g_clear_pointer ((GdkSurface **)&self->drag_surface, gdk_surface_destroy);
+  self->cancelled = TRUE;
 }
 
 static void
@@ -134,7 +197,6 @@ gdk_macos_drag_drop_performed (GdkDrag *drag,
 
   g_assert (GDK_IS_MACOS_DRAG (self));
 
-  //g_clear_pointer ((GdkSurface **)&self->drag_surface, gdk_surface_destroy);
 }
 
 static void
@@ -222,6 +284,13 @@ gdk_drag_update (GdkDrag         *drag,
                                        suggested_action,
                                        possible_actions,
                                        evtime);
+
+  if (!self->did_update)
+    {
+      self->start_x = self->last_x;
+      self->start_y = self->last_y;
+      self->did_update = TRUE;
+    }
 }
 
 static gboolean
@@ -234,6 +303,10 @@ gdk_dnd_handle_motion_event (GdkDrag  *drag,
   g_assert (GDK_IS_MACOS_DRAG (drag));
   g_assert (event != NULL);
 
+  /* Ignore motion while doing zoomback */
+  if (GDK_MACOS_DRAG (drag)->cancelled)
+    return FALSE;
+
   gdk_event_get_position (event, &x, &y);
   x_root = event->surface->x + x;
   y_root = event->surface->y + y;
@@ -444,8 +517,6 @@ gdk_macos_drag_set_property (GObject      *object,
     {
     case PROP_DRAG_SURFACE:
       self->drag_surface = g_value_dup_object (value);
-      self->last_x = GDK_SURFACE (self->drag_surface)->x;
-      self->last_y = GDK_SURFACE (self->drag_surface)->y;
       break;
 
     default:
diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c
index aa5d99a095..9d22ae9a53 100644
--- a/gdk/macos/gdkmacossurface.c
+++ b/gdk/macos/gdkmacossurface.c
@@ -25,6 +25,7 @@
 
 #import "GdkMacosCairoView.h"
 
+#include "gdkdeviceprivate.h"
 #include "gdkdisplay.h"
 #include "gdkframeclockidleprivate.h"
 #include "gdkinternals.h"
@@ -290,9 +291,13 @@ gdk_macos_surface_drag_begin (GdkSurface         *surface,
 {
   GdkMacosSurface *self = (GdkMacosSurface *)surface;
   GdkMacosSurface *drag_surface;
+  GdkMacosDrag *drag;
   GdkCursor *cursor;
   GdkSeat *seat;
-  GdkDrag *drag;
+  double px;
+  double py;
+  int sx;
+  int sy;
 
   g_assert (GDK_IS_MACOS_SURFACE (self));
   g_assert (GDK_IS_MACOS_TOPLEVEL_SURFACE (self) ||
@@ -301,11 +306,12 @@ gdk_macos_surface_drag_begin (GdkSurface         *surface,
   g_assert (GDK_IS_CONTENT_PROVIDER (content));
 
   seat = gdk_device_get_seat (device);
+  _gdk_device_query_state (device, surface, NULL, &px, &py, NULL);
+  _gdk_macos_surface_get_root_coords (GDK_MACOS_SURFACE (surface), &sx, &sy);
   drag_surface = _gdk_macos_surface_new (GDK_MACOS_DISPLAY (surface->display),
                                          GDK_SURFACE_TEMP,
                                          surface,
-                                         dx, dy,
-                                         1, 1);
+                                         -99, -99, 1, 1);
   drag = g_object_new (GDK_TYPE_MACOS_DRAG,
                        "drag-surface", drag_surface,
                        "surface", surface,
@@ -317,7 +323,6 @@ gdk_macos_surface_drag_begin (GdkSurface         *surface,
   cursor = gdk_drag_get_cursor (GDK_DRAG (drag),
                                 gdk_drag_get_selected_action (GDK_DRAG (drag)));
   gdk_drag_set_cursor (GDK_DRAG (drag), cursor);
-
   gdk_seat_ungrab (seat);
 
   g_clear_object (&drag_surface);
@@ -325,7 +330,7 @@ gdk_macos_surface_drag_begin (GdkSurface         *surface,
   /* Hold a reference until drop_done is called */
   g_object_ref (drag);
 
-  return g_steal_pointer (&drag);
+  return GDK_DRAG (g_steal_pointer (&drag));
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]