[gtk/wip/chergert/gdk-macos-gdkdrag: 8/8] macos: abstract pasteboard for use in clipboard and drag
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/chergert/gdk-macos-gdkdrag: 8/8] macos: abstract pasteboard for use in clipboard and drag
- Date: Sat, 19 Jun 2021 02:29:04 +0000 (UTC)
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]