[gtk/wip/chergert/gdk-macos-gdkdrag: 8/8] macos: abstract pasteboard for use in clipboard and drag




commit 96690acd6a34a0869738d40b78f1bec3bec2d8a0
Author: Christian Hergert <chergert redhat com>
Date:   Fri Jun 18 19:51:13 2021 -0700

    macos: abstract pasteboard for use in clipboard and drag
    
    This will allow us to share a single NSPasteboardItem and data provider
    implementation for both GdkClipboard and GdkDrag.

 gdk/macos/gdkmacosclipboard-private.h  |   9 -
 gdk/macos/gdkmacosclipboard.c          | 150 ++-------------
 gdk/macos/gdkmacospasteboard-private.h |  28 ++-
 gdk/macos/gdkmacospasteboard.c         | 325 +++++++++++++++++++++++++--------
 4 files changed, 276 insertions(+), 236 deletions(-)
---
diff --git a/gdk/macos/gdkmacosclipboard-private.h b/gdk/macos/gdkmacosclipboard-private.h
index a1fa83f7ca..ef70ee3e33 100644
--- a/gdk/macos/gdkmacosclipboard-private.h
+++ b/gdk/macos/gdkmacosclipboard-private.h
@@ -43,15 +43,6 @@ NSPasteboardType   _gdk_macos_clipboard_to_ns_type                (const char
 const char        *_gdk_macos_clipboard_from_ns_type              (NSPasteboardType      ns_type);
 void               _gdk_macos_clipboard_register_drag_types       (NSWindow             *window);
 
-@interface GdkMacosClipboardDataProvider : GdkMacosPasteboardDataProvider
-{
-  GdkClipboard *clipboard;
-}
-
--(id)initClipboard:(GdkMacosClipboard *)gdkClipboard mimetypes:(const char * const *)mime_types;
-
-@end
-
 G_END_DECLS
 
 #endif /* __GDK_MACOS_CLIPBOARD_PRIVATE_H__ */
diff --git a/gdk/macos/gdkmacosclipboard.c b/gdk/macos/gdkmacosclipboard.c
index 0af6dd3c8f..db4a262092 100644
--- a/gdk/macos/gdkmacosclipboard.c
+++ b/gdk/macos/gdkmacosclipboard.c
@@ -33,26 +33,8 @@ struct _GdkMacosClipboard
   NSInteger     last_change_count;
 };
 
-typedef struct
-{
-  GMemoryOutputStream *stream;
-  NSPasteboardItem    *item;
-  NSPasteboardType     type;
-  GMainContext        *main_context;
-  guint                done : 1;
-} WriteRequest;
-
 G_DEFINE_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK_TYPE_CLIPBOARD)
 
-static void
-write_request_free (WriteRequest *wr)
-{
-  g_clear_pointer (&wr->main_context, g_main_context_unref);
-  g_clear_object (&wr->stream);
-  [wr->item release];
-  g_slice_free (WriteRequest, wr);
-}
-
 static void
 _gdk_macos_clipboard_load_contents (GdkMacosClipboard *self)
 {
@@ -100,25 +82,27 @@ static void
 _gdk_macos_clipboard_send_to_pasteboard (GdkMacosClipboard  *self,
                                          GdkContentProvider *content)
 {
-  GdkMacosClipboardDataProvider *dataProvider;
-  GdkContentFormats *serializable;
-  const char * const *mime_types;
-  gsize n_mime_types;
+  GdkMacosPasteboardItem *item;
+  NSArray<NSPasteboardItem *> *items;
 
   g_assert (GDK_IS_MACOS_CLIPBOARD (self));
   g_assert (GDK_IS_CONTENT_PROVIDER (content));
 
-  serializable = gdk_content_provider_ref_storable_formats (content);
-  serializable = gdk_content_formats_union_serialize_mime_types (serializable);
-  mime_types = gdk_content_formats_get_mime_types (serializable, &n_mime_types);
+  if (self->pasteboard == NULL)
+    return;
 
-  dataProvider = [[GdkMacosClipboardDataProvider alloc] initClipboard:self mimetypes:mime_types];
-  _gdk_macos_pasteboard_send_content (self->pasteboard, content, dataProvider);
-  [dataProvider release];
+  GDK_BEGIN_MACOS_ALLOC_POOL;
+
+  item = [[GdkMacosPasteboardItem alloc] initForClipboard:GDK_CLIPBOARD (self) withContentProvider:content];
+  items = [NSArray arrayWithObject:item];
+
+  [self->pasteboard clearContents];
+  if ([self->pasteboard writeObjects:items] == NO)
+    g_warning ("Failed to send clipboard to pasteboard");
 
   self->last_change_count = [self->pasteboard changeCount];
 
-  g_clear_pointer (&serializable, gdk_content_formats_unref);
+  GDK_END_MACOS_ALLOC_POOL;
 }
 
 static gboolean
@@ -210,111 +194,3 @@ _gdk_macos_clipboard_check_externally_modified (GdkMacosClipboard *self)
   if ([self->pasteboard changeCount] != self->last_change_count)
     _gdk_macos_clipboard_load_contents (self);
 }
-
-@implementation GdkMacosClipboardDataProvider
-
--(id)initClipboard:(GdkMacosClipboard *)gdkClipboard mimetypes:(const char * const *)mime_types;
-{
-  [super initPasteboard:gdkClipboard->pasteboard mimetypes:mime_types];
-
-  self->clipboard = g_object_ref (GDK_CLIPBOARD (gdkClipboard));
-
-  return self;
-}
-
--(void)dealloc
-{
-  g_clear_object (&self->clipboard);
-
-  [super dealloc];
-}
-
--(void)pasteboardFinishedWithDataProvider:(NSPasteboard *)pasteboard
-{
-  g_clear_object (&self->clipboard);
-}
-
-static void
-on_data_ready_cb (GObject      *object,
-                  GAsyncResult *result,
-                  gpointer      user_data)
-{
-  GDK_BEGIN_MACOS_ALLOC_POOL;
-
-  GdkClipboard *clipboard = (GdkClipboard *)object;
-  WriteRequest *wr = user_data;
-  GError *error = NULL;
-  NSData *data = nil;
-
-  g_assert (GDK_IS_CLIPBOARD (clipboard));
-  g_assert (G_IS_ASYNC_RESULT (result));
-  g_assert (wr != NULL);
-  g_assert (G_IS_MEMORY_OUTPUT_STREAM (wr->stream));
-  g_assert ([wr->item isKindOfClass:[NSPasteboardItem class]]);
-
-  if (gdk_clipboard_write_finish (clipboard, result, &error))
-    {
-      gsize size;
-      gpointer bytes;
-
-      g_output_stream_close (G_OUTPUT_STREAM (wr->stream), NULL, NULL);
-
-      size = g_memory_output_stream_get_size (wr->stream);
-      bytes = g_memory_output_stream_steal_data (wr->stream);
-      data = [[NSData alloc] initWithBytesNoCopy:bytes
-                                          length:size
-                                     deallocator:^(void *alloc, NSUInteger length) { g_free (alloc); }];
-    }
-  else
-    {
-      g_warning ("Failed to serialize clipboard contents: %s",
-                 error->message);
-      g_clear_error (&error);
-    }
-
-  [wr->item setData:data forType:wr->type];
-
-  wr->done = TRUE;
-
-  GDK_END_MACOS_ALLOC_POOL;
-}
-
--(void)pasteboard:(NSPasteboard *)pasteboard item:(NSPasteboardItem *)item 
provideDataForType:(NSPasteboardType)type
-{
-  const char *mime_type = _gdk_macos_pasteboard_from_ns_type (type);
-  GMainContext *main_context = g_main_context_default ();
-  WriteRequest *wr;
-
-  if (self->clipboard == NULL || mime_type == NULL)
-    {
-      [item setData:[NSData data] forType:type];
-      return;
-    }
-
-  wr = g_slice_new0 (WriteRequest);
-  wr->item = [item retain];
-  wr->stream = G_MEMORY_OUTPUT_STREAM (g_memory_output_stream_new_resizable ());
-  wr->type = type;
-  wr->main_context = g_main_context_ref (main_context);
-  wr->done = FALSE;
-
-  gdk_clipboard_write_async (self->clipboard,
-                             mime_type,
-                             G_OUTPUT_STREAM (wr->stream),
-                             G_PRIORITY_DEFAULT,
-                             self->cancellable,
-                             on_data_ready_cb,
-                             wr);
-
-  /* We're forced to provide data synchronously via this API
-   * so we must block on the main loop. Using another main loop
-   * than the default tends to get us locked up here, so that is
-   * what we'll do for now.
-   */
-  while (!wr->done)
-    g_main_context_iteration (wr->main_context, TRUE);
-
-  write_request_free (wr);
-}
-
-@end
diff --git a/gdk/macos/gdkmacospasteboard-private.h b/gdk/macos/gdkmacospasteboard-private.h
index c135d82d58..fdeb936535 100644
--- a/gdk/macos/gdkmacospasteboard-private.h
+++ b/gdk/macos/gdkmacospasteboard-private.h
@@ -27,15 +27,28 @@
 
 G_BEGIN_DECLS
 
-@interface GdkMacosPasteboardDataProvider : NSObject <NSPasteboardItemDataProvider>
+@interface GdkMacosPasteboardItemDataProvider : NSObject <NSPasteboardItemDataProvider>
 {
-  NSPasteboard  *pasteboard;
-  GCancellable  *cancellable;
-  char         **mimeTypes;
+  GdkContentProvider *_contentProvider;
+  GdkClipboard *_clipboard;
+  GdkDrag *_drag;
 }
 
--(id)initPasteboard:(NSPasteboard *)pasteBoard mimetypes:(const char * const *)mime_types;
--(NSArray<NSPasteboardType> *)types;
+-(id)initForClipboard:(GdkClipboard *)clipboard withContentProvider:(GdkContentProvider *)contentProvider;
+-(id)initForDrag:(GdkDrag *)drag withContentProvider:(GdkContentProvider *)contentProvider;
+
+@end
+
+@interface GdkMacosPasteboardItem : NSPasteboardItem
+{
+  GdkContentProvider *_contentProvider;
+  GdkClipboard *_clipboard;
+  GdkDrag *_drag;
+  NSRect _draggingFrame;
+}
+
+-(id)initForClipboard:(GdkClipboard *)clipboard withContentProvider:(GdkContentProvider *)contentProvider;
+-(id)initForDrag:(GdkDrag *)drag withContentProvider:(GdkContentProvider *)contentProvider;
 
 @end
 
@@ -55,9 +68,6 @@ GInputStream      *_gdk_macos_pasteboard_read_finish         (GObject
                                                               GAsyncResult                    *result,
                                                               const char                     **out_mime_type,
                                                               GError                         **error);
-void               _gdk_macos_pasteboard_send_content        (NSPasteboard                    *pasteboard,
-                                                              GdkContentProvider              *content,
-                                                              GdkMacosPasteboardDataProvider  *dataProvider);
 
 G_END_DECLS
 
diff --git a/gdk/macos/gdkmacospasteboard.c b/gdk/macos/gdkmacospasteboard.c
index 0de91518e0..fcfc5b6b96 100644
--- a/gdk/macos/gdkmacospasteboard.c
+++ b/gdk/macos/gdkmacospasteboard.c
@@ -166,87 +166,6 @@ _gdk_macos_pasteboard_load_formats (NSPasteboard *pasteboard)
   return load_offer_formats (pasteboard);
 }
 
-void
-_gdk_macos_pasteboard_send_content (NSPasteboard                   *pasteboard,
-                                    GdkContentProvider             *content,
-                                    GdkMacosPasteboardDataProvider *dataProvider)
-{
-  GDK_BEGIN_MACOS_ALLOC_POOL;
-
-  NSPasteboardItem *item;
-
-  g_return_if_fail (pasteboard != NULL);
-  g_return_if_fail (GDK_IS_CONTENT_PROVIDER (content));
-
-  item = [[NSPasteboardItem alloc] init];
-  [item setDataProvider:dataProvider forTypes:[dataProvider types]];
-
-  [pasteboard clearContents];
-  if ([pasteboard writeObjects:[NSArray arrayWithObject:item]] == NO)
-    g_warning ("Failed to write object to pasteboard");
-
-  GDK_END_MACOS_ALLOC_POOL;
-}
-
-@implementation GdkMacosPasteboardDataProvider
-
--(id)initPasteboard:(NSPasteboard *)pasteBoard mimetypes:(const char * const *)mime_types;
-{
-  [super init];
-
-  self->mimeTypes = g_strdupv ((char **)mime_types);
-  self->pasteboard = [pasteBoard retain];
-
-  return self;
-}
-
--(void)dealloc
-{
-  g_cancellable_cancel (self->cancellable);
-
-  if (self->pasteboard)
-    {
-      [self->pasteboard release];
-      self->pasteboard = nil;
-    }
-
-  g_clear_pointer (&self->mimeTypes, g_strfreev);
-  g_clear_object (&self->cancellable);
-
-  [super dealloc];
-}
-
--(void)pasteboardFinishedWithDataProvider:(NSPasteboard *)pasteboard
-{
-}
-
--(void)pasteboard:(NSPasteboard *)pasteboard item:(NSPasteboardItem *)item 
provideDataForType:(NSPasteboardType)type
-{
-}
-
--(NSArray<NSPasteboardType> *)types
-{
-  NSMutableArray *ret = [[NSMutableArray alloc] init];
-
-  for (guint i = 0; self->mimeTypes[i]; i++)
-    {
-      const char *mime_type = self->mimeTypes[i];
-      NSPasteboardType type;
-      NSPasteboardType alternate = nil;
-
-      if ((type = _gdk_macos_pasteboard_to_ns_type (mime_type, &alternate)))
-        {
-          [ret addObject:type];
-          if (alternate)
-            [ret addObject:alternate];
-        }
-    }
-
-  return g_steal_pointer (&ret);
-}
-
-@end
-
 static GInputStream *
 create_stream_from_nsdata (NSData *data)
 {
@@ -415,3 +334,247 @@ _gdk_macos_pasteboard_register_drag_types (NSWindow *window)
                                                             PTYPE(PNG),
                                                             nil]];
 }
+
+@implementation GdkMacosPasteboardItemDataProvider
+
+-(id)initForClipboard:(GdkClipboard*)clipboard withContentProvider:(GdkContentProvider*)contentProvider
+{
+  [super init];
+  g_set_object (&self->_clipboard, clipboard);
+  g_set_object (&self->_contentProvider, contentProvider);
+  return self;
+}
+
+-(id)initForDrag:(GdkDrag*)drag withContentProvider:(GdkContentProvider*)contentProvider
+{
+  [super init];
+  g_set_object (&self->_drag, drag);
+  g_set_object (&self->_contentProvider, contentProvider);
+  return self;
+}
+
+-(void)dealloc
+{
+  g_clear_object (&self->_contentProvider);
+  g_clear_object (&self->_clipboard);
+  g_clear_object (&self->_drag);
+  [super dealloc];
+}
+
+-(NSArray<NSPasteboardType> *)types
+{
+  NSMutableArray *ret = [[NSMutableArray alloc] init];
+  GdkContentFormats *serializable;
+  const char * const *mime_types;
+  gsize n_mime_types;
+
+  serializable = gdk_content_provider_ref_storable_formats (self->_contentProvider);
+  serializable = gdk_content_formats_union_serialize_mime_types (serializable);
+  mime_types = gdk_content_formats_get_mime_types (serializable, &n_mime_types);
+
+  for (guint i = 0; mime_types[i]; i++)
+    {
+      const char *mime_type = mime_types[i];
+      NSPasteboardType type;
+      NSPasteboardType alternate = nil;
+
+      if ((type = _gdk_macos_pasteboard_to_ns_type (mime_type, &alternate)))
+        {
+          [ret addObject:type];
+          if (alternate)
+            [ret addObject:alternate];
+        }
+    }
+
+  return g_steal_pointer (&ret);
+}
+
+typedef struct
+{
+  GMemoryOutputStream *stream;
+  NSPasteboardItem    *item;
+  NSPasteboardType     type;
+  GMainContext        *main_context;
+  guint                done : 1;
+} WriteRequest;
+
+static void
+write_request_free (WriteRequest *wr)
+{
+  g_clear_pointer (&wr->main_context, g_main_context_unref);
+  g_clear_object (&wr->stream);
+  [wr->item release];
+  g_slice_free (WriteRequest, wr);
+}
+
+static void
+on_data_ready_cb (GObject      *object,
+                  GAsyncResult *result,
+                  gpointer      user_data)
+{
+  GDK_BEGIN_MACOS_ALLOC_POOL;
+
+  WriteRequest *wr = user_data;
+  GError *error = NULL;
+  NSData *data = nil;
+  gboolean ret;
+
+  g_assert (G_IS_OBJECT (object));
+  g_assert (GDK_IS_CLIPBOARD (object) || GDK_IS_DRAG (object));
+  g_assert (G_IS_ASYNC_RESULT (result));
+  g_assert (wr != NULL);
+  g_assert (G_IS_MEMORY_OUTPUT_STREAM (wr->stream));
+  g_assert ([wr->item isKindOfClass:[NSPasteboardItem class]]);
+
+  if (GDK_IS_CLIPBOARD (object))
+    ret = gdk_clipboard_write_finish (GDK_CLIPBOARD (object), result, &error);
+  else
+    ret = gdk_drag_write_finish (GDK_DRAG (object), result, &error);
+
+  if (ret)
+    {
+      gsize size;
+      gpointer bytes;
+
+      g_output_stream_close (G_OUTPUT_STREAM (wr->stream), NULL, NULL);
+
+      size = g_memory_output_stream_get_size (wr->stream);
+      bytes = g_memory_output_stream_steal_data (wr->stream);
+      data = [[NSData alloc] initWithBytesNoCopy:bytes
+                                          length:size
+                                     deallocator:^(void *alloc, NSUInteger length) { g_free (alloc); }];
+    }
+  else
+    {
+      g_warning ("Failed to serialize pasteboard contents: %s", error->message);
+      g_clear_error (&error);
+    }
+
+  [wr->item setData:data forType:wr->type];
+
+  wr->done = TRUE;
+
+  GDK_END_MACOS_ALLOC_POOL;
+}
+
+-(void)pasteboard:(NSPasteboard *)pasteboard item:(NSPasteboardItem *)item 
provideDataForType:(NSPasteboardType)type
+{
+  const char *mime_type = _gdk_macos_pasteboard_from_ns_type (type);
+  GMainContext *main_context = g_main_context_default ();
+  WriteRequest *wr;
+
+  if (self->_contentProvider == NULL || mime_type == NULL)
+    {
+      [item setData:[NSData data] forType:type];
+      return;
+    }
+
+  wr = g_slice_new0 (WriteRequest);
+  wr->item = [item retain];
+  wr->stream = G_MEMORY_OUTPUT_STREAM (g_memory_output_stream_new_resizable ());
+  wr->type = type;
+  wr->main_context = g_main_context_ref (main_context);
+  wr->done = FALSE;
+
+  if (GDK_IS_CLIPBOARD (self->_clipboard))
+    gdk_clipboard_write_async (self->_clipboard,
+                               mime_type,
+                               G_OUTPUT_STREAM (wr->stream),
+                               G_PRIORITY_DEFAULT,
+                               NULL,
+                               on_data_ready_cb,
+                               wr);
+  else if (GDK_IS_DRAG (self->_drag))
+    gdk_drag_write_async (self->_drag,
+                          mime_type,
+                          G_OUTPUT_STREAM (wr->stream),
+                          G_PRIORITY_DEFAULT,
+                          NULL,
+                          on_data_ready_cb,
+                          wr);
+  else
+    g_return_if_reached ();
+
+  /* We're forced to provide data synchronously via this API
+   * so we must block on the main loop. Using another main loop
+   * than the default tends to get us locked up here, so that is
+   * what we'll do for now.
+   */
+  while (!wr->done)
+    g_main_context_iteration (wr->main_context, TRUE);
+
+  write_request_free (wr);
+}
+
+-(void)pasteboardFinishedWithDataProvider:(NSPasteboard *)pasteboard
+{
+  g_clear_object (&self->_clipboard);
+  g_clear_object (&self->_drag);
+  g_clear_object (&self->_contentProvider);
+}
+
+@end
+
+@implementation GdkMacosPasteboardItem
+
+-(id)initForClipboard:(GdkClipboard*)clipboard withContentProvider:(GdkContentProvider*)contentProvider
+{
+  GdkMacosPasteboardItemDataProvider *dataProvider;
+
+  dataProvider = [[GdkMacosPasteboardItemDataProvider alloc] initForClipboard:clipboard 
withContentProvider:contentProvider];
+
+  [super init];
+  g_set_object (&self->_clipboard, clipboard);
+  g_set_object (&self->_contentProvider, contentProvider);
+  [self setDataProvider:dataProvider forTypes:[dataProvider types]];
+
+  [dataProvider release];
+
+  return self;
+}
+
+-(id)initForDrag:(GdkDrag*)drag withContentProvider:(GdkContentProvider*)contentProvider
+{
+  GdkMacosPasteboardItemDataProvider *dataProvider;
+
+  dataProvider = [[GdkMacosPasteboardItemDataProvider alloc] initForDrag:drag 
withContentProvider:contentProvider];
+
+  [super init];
+  g_set_object (&self->_drag, drag);
+  g_set_object (&self->_contentProvider, contentProvider);
+  [self setDataProvider:dataProvider forTypes:[dataProvider types]];
+
+  [dataProvider release];
+
+  return self;
+}
+
+-(void)dealloc
+{
+  g_clear_object (&self->_contentProvider);
+  g_clear_object (&self->_clipboard);
+  g_clear_object (&self->_drag);
+  [super dealloc];
+}
+
+-(NSRect)draggingFrame
+{
+  return self->_draggingFrame;
+}
+
+-(void)setDraggingFrame:(NSRect)draggingFrame;
+{
+  self->_draggingFrame = draggingFrame;
+}
+
+-(id)item
+{
+  return self;
+}
+
+-(NSArray* (^) (void))imageComponentsProvider
+{
+  return nil;
+}
+
+@end


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