diff --git a/gdk/macos/GdkMacosBaseView.c b/gdk/macos/GdkMacosBaseView.c
index a86d9712b24d2f93049b450e47b19264b5f464eb..42bbe1ab17a3179573aaf3d2e3b7d86923b0340d 100644
--- a/gdk/macos/GdkMacosBaseView.c
+++ b/gdk/macos/GdkMacosBaseView.c
@@ -29,6 +29,7 @@
#include "gdkmacossurface-private.h"
#include "gdkdebug.h"
+#include "gdkdragprivate.h"
@implementation GdkMacosBaseView
diff --git a/gdk/macos/GdkMacosDraggingSource.c b/gdk/macos/GdkMacosDraggingSource.c
new file mode 100644
index 0000000000000000000000000000000000000000..fc53a9e68b235a4061fa5f63521b34c2e35ea1c6
--- /dev/null
+++ b/gdk/macos/GdkMacosDraggingSource.c
@@ -0,0 +1,92 @@
+/* GdkMacosDraggingSource.c
+ *
+ * Copyright 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#import "GdkMacosDraggingSource.h"
+
+#include "gdkdebug.h"
+#include "gdkmacosdisplay-private.h"
+#include "gdkmacosdrag-private.h"
+
+@implementation GdkMacosDraggingSource
+
+- (id)init:(GdkDrag *)drag
+{
+ g_return_val_if_fail (GDK_IS_MACOS_DRAG (drag), self);
+
+ g_set_object (&self->gdk_drag, drag);
+ return self;
+}
+
+- (void)dealloc
+{
+ g_clear_object (&self->gdk_drag);
+ [super dealloc];
+}
+
+- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context
+{
+ GdkDrag *drag = self->gdk_drag;
+ GdkDisplay *display = gdk_drag_get_display (drag);
+
+ GdkModifierType state = _gdk_macos_display_get_current_keyboard_modifiers (GDK_MACOS_DISPLAY (display));
+ _gdk_macos_drag_set_actions (drag, state);
+
+ return _gdk_macos_drag_operation (GDK_MACOS_DRAG (drag));
+}
+
+- (void)draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint
+{
+ GdkDrag *drag = self->gdk_drag;
+ GdkDisplay *display = gdk_drag_get_display (drag);
+ int x, y;
+
+ _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display), screenPoint.x, screenPoint.y, &x, &y);
+ _gdk_macos_drag_set_start_position (drag, x, y);
+ _gdk_macos_drag_set_last_position (drag, x, y);
+ _gdk_macos_drag_surface_move (GDK_MACOS_DRAG (drag), x, y);
+}
+
+- (void)draggingSession:(NSDraggingSession *)session movedToPoint:(NSPoint)screenPoint
+{
+ GdkDrag *drag = self->gdk_drag;
+ GdkDisplay *display = gdk_drag_get_display (drag);
+ int x, y;
+
+ _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display), screenPoint.x, screenPoint.y, &x, &y);
+ _gdk_macos_drag_set_last_position (drag, x, y);
+ _gdk_macos_drag_surface_move (GDK_MACOS_DRAG (drag), x, y);
+}
+
+- (void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation
+{
+ GdkDrag *drag = self->gdk_drag;
+ GdkDisplay *display = gdk_drag_get_display (drag);
+
+ if (gdk_drag_get_selected_action (drag) != 0)
+ g_signal_emit_by_name (drag, "drop-performed");
+ else
+ gdk_drag_cancel (drag, GDK_DRAG_CANCEL_NO_TARGET);
+
+ _gdk_macos_display_set_drag (GDK_MACOS_DISPLAY (display), [session draggingSequenceNumber], NULL);
+}
+
+@end
diff --git a/gdk/macos/GdkMacosDraggingSource.h b/gdk/macos/GdkMacosDraggingSource.h
new file mode 100644
index 0000000000000000000000000000000000000000..5c550a3f7c18edd912673f139ad0bbc97811d774
--- /dev/null
+++ b/gdk/macos/GdkMacosDraggingSource.h
@@ -0,0 +1,36 @@
+/* GdkMacosDraggingSource.h
+ *
+ * Copyright © 2020 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#import
+#import
+
+#include
+
+#define GDK_IS_MACOS_DRAGGING_SOURCE(obj) ((obj) && [obj isKindOfClass:[GdkMacosDraggingSource class]])
+
+@interface GdkMacosDraggingSource : NSObject
+{
+ GdkDisplay *gdk_display;
+ GdkDrag *gdk_drag;
+}
+
+- (id)init:(GdkDrag *)drag;
+
+@end
diff --git a/gdk/macos/GdkMacosWindow.c b/gdk/macos/GdkMacosWindow.c
index 0eb1ec7ca8a533e98b3bb84cb233a6d82b0ade8f..8c5a19e26b4f2f9e050de8d6aaee898706ee23e5 100644
--- a/gdk/macos/GdkMacosWindow.c
+++ b/gdk/macos/GdkMacosWindow.c
@@ -27,12 +27,13 @@
#import "GdkMacosView.h"
#import "GdkMacosWindow.h"
-#include "gdkmacosclipboard-private.h"
#include "gdkmacosdisplay-private.h"
+#include "gdkmacosdrag-private.h"
#include "gdkmacosdrop-private.h"
#include "gdkmacosmonitor-private.h"
-#include "gdkmacossurface-private.h"
+#include "gdkmacospasteboard-private.h"
#include "gdkmacospopupsurface-private.h"
+#include "gdkmacossurface-private.h"
#include "gdkmacostoplevelsurface-private.h"
#include "gdkmacosutils-private.h"
@@ -246,7 +247,7 @@ typedef NSString *CALayerContentsGravity;
[view release];
/* TODO: We might want to make this more extensible at some point */
- _gdk_macos_clipboard_register_drag_types (self);
+ _gdk_macos_pasteboard_register_drag_types (self);
return self;
}
@@ -604,6 +605,7 @@ typedef NSString *CALayerContentsGravity;
-(void)draggingEnded:(id )sender
{
+ // [sender draggingSource] != nil if in-app dnd
_gdk_macos_display_set_drop ([self gdkDisplay], [sender draggingSequenceNumber], NULL);
}
@@ -649,6 +651,7 @@ typedef NSString *CALayerContentsGravity;
if (drop == NULL)
return NO;
+ gdk_drop_set_actions (drop, GDK_MACOS_DROP (drop)->preferred_action);
gdk_drop_emit_drop_event (drop,
TRUE,
location.x,
@@ -665,10 +668,6 @@ typedef NSString *CALayerContentsGravity;
return NO;
}
--(void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation
-{
-}
-
-(void)setStyleMask:(NSWindowStyleMask)styleMask
{
gboolean was_fullscreen;
diff --git a/gdk/macos/gdkmacosclipboard-private.h b/gdk/macos/gdkmacosclipboard-private.h
index ba0b52bf0a203381a125139e88744734751f59e9..ef70ee3e330987ef4b31ca5750e30baea9fce348 100644
--- a/gdk/macos/gdkmacosclipboard-private.h
+++ b/gdk/macos/gdkmacosclipboard-private.h
@@ -24,6 +24,7 @@
#include "gdkclipboardprivate.h"
#include "gdkmacosdisplay-private.h"
+#include "gdkmacospasteboard-private.h"
G_BEGIN_DECLS
@@ -41,30 +42,6 @@ NSPasteboardType _gdk_macos_clipboard_to_ns_type (const char
NSPasteboardType *alternate);
const char *_gdk_macos_clipboard_from_ns_type (NSPasteboardType ns_type);
void _gdk_macos_clipboard_register_drag_types (NSWindow *window);
-GdkContentFormats *_gdk_macos_pasteboard_load_formats (NSPasteboard *pasteboard);
-void _gdk_macos_pasteboard_read_async (GObject *object,
- NSPasteboard *pasteboard,
- GdkContentFormats *formats,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data);
-GInputStream *_gdk_macos_pasteboard_read_finish (GObject *object,
- GAsyncResult *result,
- const char **out_mime_type,
- GError **error);
-
-@interface GdkMacosClipboardDataProvider : NSObject
-{
- GCancellable *cancellable;
- GdkClipboard *clipboard;
- char **mimeTypes;
-}
-
--(id)initClipboard:(GdkClipboard *)gdkClipboard mimetypes:(const char * const *)mime_types;
--(NSArray *)types;
-
-@end
G_END_DECLS
diff --git a/gdk/macos/gdkmacosclipboard.c b/gdk/macos/gdkmacosclipboard.c
index ba755db0be741ff6f84b46ba7803dea7ee3a59a6..db4a262092670cdc70f716377849b60cf922eac8 100644
--- a/gdk/macos/gdkmacosclipboard.c
+++ b/gdk/macos/gdkmacosclipboard.c
@@ -22,6 +22,7 @@
#include
#include "gdkmacosclipboard-private.h"
+#include "gdkmacospasteboard-private.h"
#include "gdkmacosutils-private.h"
#include "gdk-private.h"
@@ -32,163 +33,8 @@ struct _GdkMacosClipboard
NSInteger last_change_count;
};
-typedef struct
-{
- GMemoryOutputStream *stream;
- NSPasteboardItem *item;
- NSPasteboardType type;
- GMainContext *main_context;
- guint done : 1;
-} WriteRequest;
-
-enum {
- TYPE_STRING,
- TYPE_PBOARD,
- TYPE_URL,
- TYPE_FILE_URL,
- TYPE_COLOR,
- TYPE_TIFF,
- TYPE_PNG,
- TYPE_LAST
-};
-
-#define PTYPE(k) (get_pasteboard_type(TYPE_##k))
-
-static NSPasteboardType pasteboard_types[TYPE_LAST];
-
G_DEFINE_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK_TYPE_CLIPBOARD)
-static NSPasteboardType
-get_pasteboard_type (int type)
-{
- static gsize initialized = FALSE;
-
- g_assert (type >= 0);
- g_assert (type < TYPE_LAST);
-
- if (g_once_init_enter (&initialized))
- {
- pasteboard_types[TYPE_PNG] = NSPasteboardTypePNG;
- pasteboard_types[TYPE_STRING] = NSPasteboardTypeString;
- pasteboard_types[TYPE_TIFF] = NSPasteboardTypeTIFF;
- pasteboard_types[TYPE_COLOR] = NSPasteboardTypeColor;
-
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS
- pasteboard_types[TYPE_PBOARD] = NSStringPboardType;
- G_GNUC_END_IGNORE_DEPRECATIONS
-
-#ifdef AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
- pasteboard_types[TYPE_URL] = NSPasteboardTypeURL;
- pasteboard_types[TYPE_FILE_URL] = NSPasteboardTypeFileURL;
-#else
- pasteboard_types[TYPE_URL] = [[NSString alloc] initWithUTF8String:"public.url"];
- pasteboard_types[TYPE_FILE_URL] = [[NSString alloc] initWithUTF8String:"public.file-url"];
-#endif
-
- g_once_init_leave (&initialized, TRUE);
- }
-
- return pasteboard_types[type];
-}
-
-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);
-}
-
-const char *
-_gdk_macos_clipboard_from_ns_type (NSPasteboardType type)
-{
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-
- if ([type isEqualToString:PTYPE(STRING)] ||
- [type isEqualToString:PTYPE(PBOARD)])
- return g_intern_string ("text/plain;charset=utf-8");
- else if ([type isEqualToString:PTYPE(URL)] ||
- [type isEqualToString:PTYPE(FILE_URL)])
- return g_intern_string ("text/uri-list");
- else if ([type isEqualToString:PTYPE(COLOR)])
- return g_intern_string ("application/x-color");
- else if ([type isEqualToString:PTYPE(TIFF)])
- return g_intern_string ("image/tiff");
- else if ([type isEqualToString:PTYPE(PNG)])
- return g_intern_string ("image/png");
-
- G_GNUC_END_IGNORE_DEPRECATIONS;
-
- return NULL;
-}
-
-NSPasteboardType
-_gdk_macos_clipboard_to_ns_type (const char *mime_type,
- NSPasteboardType *alternate)
-{
- if (alternate)
- *alternate = NULL;
-
- if (g_strcmp0 (mime_type, "text/plain;charset=utf-8") == 0)
- {
- return PTYPE(STRING);
- }
- else if (g_strcmp0 (mime_type, "text/uri-list") == 0)
- {
- if (alternate)
- *alternate = PTYPE(URL);
- return PTYPE(FILE_URL);
- }
- else if (g_strcmp0 (mime_type, "application/x-color") == 0)
- {
- return PTYPE(COLOR);
- }
- else if (g_strcmp0 (mime_type, "image/tiff") == 0)
- {
- return PTYPE(TIFF);
- }
- else if (g_strcmp0 (mime_type, "image/png") == 0)
- {
- return PTYPE(PNG);
- }
-
- return nil;
-}
-
-static void
-populate_content_formats (GdkContentFormatsBuilder *builder,
- NSPasteboardType type)
-{
- const char *mime_type;
-
- g_return_if_fail (builder != NULL);
- g_return_if_fail (type != NULL);
-
- mime_type = _gdk_macos_clipboard_from_ns_type (type);
-
- if (mime_type != NULL)
- gdk_content_formats_builder_add_mime_type (builder, mime_type);
-}
-
-static GdkContentFormats *
-load_offer_formats (NSPasteboard *pasteboard)
-{
- GDK_BEGIN_MACOS_ALLOC_POOL;
-
- GdkContentFormatsBuilder *builder;
- GdkContentFormats *formats;
-
- builder = gdk_content_formats_builder_new ();
- for (NSPasteboardType type in [pasteboard types])
- populate_content_formats (builder, type);
- formats = gdk_content_formats_builder_free_to_formats (builder);
-
- GDK_END_MACOS_ALLOC_POOL;
-
- return g_steal_pointer (&formats);
-}
-
static void
_gdk_macos_clipboard_load_contents (GdkMacosClipboard *self)
{
@@ -199,22 +45,13 @@ _gdk_macos_clipboard_load_contents (GdkMacosClipboard *self)
change_count = [self->pasteboard changeCount];
- formats = load_offer_formats (self->pasteboard);
+ formats = _gdk_macos_pasteboard_load_formats (self->pasteboard);
gdk_clipboard_claim_remote (GDK_CLIPBOARD (self), formats);
gdk_content_formats_unref (formats);
self->last_change_count = change_count;
}
-static GInputStream *
-create_stream_from_nsdata (NSData *data)
-{
- const guint8 *bytes = [data bytes];
- gsize len = [data length];
-
- return g_memory_input_stream_new_from_data (g_memdup2 (bytes, len), len, g_free);
-}
-
static void
_gdk_macos_clipboard_read_async (GdkClipboard *clipboard,
GdkContentFormats *formats,
@@ -245,34 +82,26 @@ static void
_gdk_macos_clipboard_send_to_pasteboard (GdkMacosClipboard *self,
GdkContentProvider *content)
{
- GDK_BEGIN_MACOS_ALLOC_POOL;
+ GdkMacosPasteboardItem *item;
+ NSArray *items;
- GdkMacosClipboardDataProvider *dataProvider;
- GdkContentFormats *serializable;
- NSPasteboardItem *item;
- const char * const *mime_types;
- gsize n_mime_types;
+ g_assert (GDK_IS_MACOS_CLIPBOARD (self));
+ g_assert (GDK_IS_CONTENT_PROVIDER (content));
- g_return_if_fail (GDK_IS_MACOS_CLIPBOARD (self));
- g_return_if_fail (GDK_IS_CONTENT_PROVIDER (content));
+ if (self->pasteboard == NULL)
+ return;
- 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);
+ GDK_BEGIN_MACOS_ALLOC_POOL;
- dataProvider = [[GdkMacosClipboardDataProvider alloc] initClipboard:GDK_CLIPBOARD (self)
- mimetypes:mime_types];
- item = [[NSPasteboardItem alloc] init];
- [item setDataProvider:dataProvider forTypes:[dataProvider types]];
+ item = [[GdkMacosPasteboardItem alloc] initForClipboard:GDK_CLIPBOARD (self) withContentProvider:content];
+ items = [NSArray arrayWithObject:item];
[self->pasteboard clearContents];
- if ([self->pasteboard writeObjects:[NSArray arrayWithObject:item]] == NO)
- g_warning ("Failed to write object to pasteboard");
+ 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;
}
@@ -365,305 +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:(GdkClipboard *)gdkClipboard mimetypes:(const char * const *)mime_types;
-{
- [super init];
-
- self->mimeTypes = g_strdupv ((char **)mime_types);
- self->clipboard = g_object_ref (gdkClipboard);
-
- return self;
-}
-
--(void)dealloc
-{
- g_cancellable_cancel (self->cancellable);
-
- g_clear_pointer (&self->mimeTypes, g_strfreev);
- g_clear_object (&self->clipboard);
- g_clear_object (&self->cancellable);
-
- [super dealloc];
-}
-
--(void)pasteboardFinishedWithDataProvider:(NSPasteboard *)pasteboard
-{
- g_clear_object (&self->clipboard);
-}
-
--(NSArray *)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_clipboard_to_ns_type (mime_type, &alternate)))
- {
- [ret addObject:type];
- if (alternate)
- [ret addObject:alternate];
- }
- }
-
- return g_steal_pointer (&ret);
-}
-
-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_clipboard_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);
-}
-
-void
-_gdk_macos_clipboard_register_drag_types (NSWindow *window)
-{
- [window registerForDraggedTypes:[NSArray arrayWithObjects:PTYPE(STRING),
- PTYPE(PBOARD),
- PTYPE(URL),
- PTYPE(FILE_URL),
- PTYPE(COLOR),
- PTYPE(TIFF),
- PTYPE(PNG),
- nil]];
-}
-
-@end
-
-GdkContentFormats *
-_gdk_macos_pasteboard_load_formats (NSPasteboard *pasteboard)
-{
- return load_offer_formats (pasteboard);
-}
-
-void
-_gdk_macos_pasteboard_read_async (GObject *object,
- NSPasteboard *pasteboard,
- GdkContentFormats *formats,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GDK_BEGIN_MACOS_ALLOC_POOL;
-
- GdkContentFormats *offer_formats = NULL;
- const char *mime_type;
- GInputStream *stream = NULL;
- GTask *task = NULL;
-
- g_assert (G_IS_OBJECT (object));
- g_assert (pasteboard != NULL);
- g_assert (formats != NULL);
-
- task = g_task_new (object, cancellable, callback, user_data);
- g_task_set_source_tag (task, _gdk_macos_pasteboard_read_async);
- g_task_set_priority (task, io_priority);
-
- offer_formats = load_offer_formats (pasteboard);
- mime_type = gdk_content_formats_match_mime_type (formats, offer_formats);
-
- if (mime_type == NULL)
- {
- g_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- "%s",
- _("No compatible transfer format found"));
- goto cleanup;
- }
-
- if (strcmp (mime_type, "text/plain;charset=utf-8") == 0)
- {
- NSString *nsstr = [pasteboard stringForType:NSPasteboardTypeString];
-
- if (nsstr != NULL)
- {
- const char *str = [nsstr UTF8String];
- stream = g_memory_input_stream_new_from_data (g_strdup (str),
- strlen (str) + 1,
- g_free);
- }
- }
- else if (strcmp (mime_type, "text/uri-list") == 0)
- {
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-
- if ([[pasteboard types] containsObject:PTYPE(FILE_URL)])
- {
- GString *str = g_string_new (NULL);
- NSArray *files = [pasteboard propertyListForType:NSFilenamesPboardType];
- gsize n_files = [files count];
- char *data;
- guint len;
-
- for (gsize i = 0; i < n_files; ++i)
- {
- NSString* uriString = [files objectAtIndex:i];
- uriString = [@"file://" stringByAppendingString:uriString];
- uriString = [uriString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
-
- g_string_append_printf (str,
- "%s\r\n",
- [uriString cStringUsingEncoding:NSUTF8StringEncoding]);
- }
-
- len = str->len;
- data = g_string_free (str, FALSE);
- stream = g_memory_input_stream_new_from_data (data, len, g_free);
- }
-
- G_GNUC_END_IGNORE_DEPRECATIONS;
- }
- else if (strcmp (mime_type, "application/x-color") == 0)
- {
- NSColorSpace *colorspace;
- NSColor *nscolor;
- guint16 color[4];
-
- colorspace = [NSColorSpace genericRGBColorSpace];
- nscolor = [[NSColor colorFromPasteboard:pasteboard]
- colorUsingColorSpace:colorspace];
-
- color[0] = 0xffff * [nscolor redComponent];
- color[1] = 0xffff * [nscolor greenComponent];
- color[2] = 0xffff * [nscolor blueComponent];
- color[3] = 0xffff * [nscolor alphaComponent];
-
- stream = g_memory_input_stream_new_from_data (g_memdup2 (&color, sizeof color),
- sizeof color,
- g_free);
- }
- else if (strcmp (mime_type, "image/tiff") == 0)
- {
- NSData *data = [pasteboard dataForType:PTYPE(TIFF)];
- stream = create_stream_from_nsdata (data);
- }
- else if (strcmp (mime_type, "image/png") == 0)
- {
- NSData *data = [pasteboard dataForType:PTYPE(PNG)];
- stream = create_stream_from_nsdata (data);
- }
-
- if (stream != NULL)
- {
- g_task_set_task_data (task, g_strdup (mime_type), g_free);
- g_task_return_pointer (task, g_steal_pointer (&stream), g_object_unref);
- }
- else
- {
- g_task_return_new_error (task,
- G_IO_ERROR,
- G_IO_ERROR_FAILED,
- _("Failed to decode contents with mime-type of '%s'"),
- mime_type);
- }
-
-cleanup:
- g_clear_object (&task);
- g_clear_pointer (&offer_formats, gdk_content_formats_unref);
-
- GDK_END_MACOS_ALLOC_POOL;
-}
-
-GInputStream *
-_gdk_macos_pasteboard_read_finish (GObject *object,
- GAsyncResult *result,
- const char **out_mime_type,
- GError **error)
-{
- GTask *task = (GTask *)result;
-
- g_assert (G_IS_OBJECT (object));
- g_assert (G_IS_TASK (task));
-
- if (out_mime_type != NULL)
- *out_mime_type = g_strdup (g_task_get_task_data (task));
-
- return g_task_propagate_pointer (task, error);
-}
diff --git a/gdk/macos/gdkmacosdisplay-private.h b/gdk/macos/gdkmacosdisplay-private.h
index 83ae435e49db2c1f0131d31377c194fdd0874da9..122d004cec6ee7f9d769b9858755edd724574ced 100644
--- a/gdk/macos/gdkmacosdisplay-private.h
+++ b/gdk/macos/gdkmacosdisplay-private.h
@@ -161,6 +161,7 @@ void _gdk_macos_display_warp_pointer (GdkMacosDisp
int x,
int y);
NSEvent *_gdk_macos_display_get_nsevent (GdkEvent *event);
+NSEvent *_gdk_macos_display_get_last_nsevent (void);
GdkDrag *_gdk_macos_display_find_drag (GdkMacosDisplay *self,
NSInteger sequence_number);
GdkDrop *_gdk_macos_display_find_drop (GdkMacosDisplay *self,
diff --git a/gdk/macos/gdkmacosdisplay.c b/gdk/macos/gdkmacosdisplay.c
index 41be42cfbee8619e94e24b715859aa45b7e85aeb..7c133f9c0bdc2d418017c2ba33e2b24697b43ffc 100644
--- a/gdk/macos/gdkmacosdisplay.c
+++ b/gdk/macos/gdkmacosdisplay.c
@@ -1028,6 +1028,16 @@ _gdk_macos_display_get_nsevent (GdkEvent *event)
return NULL;
}
+NSEvent *
+_gdk_macos_display_get_last_nsevent ()
+{
+ const GdkToNSEventMap *map = g_queue_peek_tail (&event_map);
+ if (map)
+ return map->nsevent;
+
+ return NULL;
+}
+
GdkDrag *
_gdk_macos_display_find_drag (GdkMacosDisplay *self,
NSInteger sequence_number)
diff --git a/gdk/macos/gdkmacosdrag-private.h b/gdk/macos/gdkmacosdrag-private.h
index 98075f27ef51dbc41f63fa913336570f6aba17b4..f2b20010c331921633750a69aa26cb3da71d255f 100644
--- a/gdk/macos/gdkmacosdrag-private.h
+++ b/gdk/macos/gdkmacosdrag-private.h
@@ -23,6 +23,7 @@
#include "gdkdragprivate.h"
#include "gdkmacosdragsurface-private.h"
+#include "gdkmacospasteboard-private.h"
G_BEGIN_DECLS
@@ -44,6 +45,8 @@ struct _GdkMacosDrag
GdkSeat *drag_seat;
GdkCursor *cursor;
+ NSInteger sequence;
+
int hot_x;
int hot_y;
@@ -53,8 +56,7 @@ struct _GdkMacosDrag
int start_x;
int start_y;
- guint did_update : 1;
- guint cancelled : 1;
+ gboolean cancelled;
};
struct _GdkMacosDragClass
@@ -62,8 +64,24 @@ struct _GdkMacosDragClass
GdkDragClass parent_class;
};
-GType gdk_macos_drag_get_type (void) G_GNUC_CONST;
-gboolean _gdk_macos_drag_begin (GdkMacosDrag *self);
+GType gdk_macos_drag_get_type (void) G_GNUC_CONST;
+gboolean _gdk_macos_drag_begin (GdkMacosDrag *self,
+ GdkContentProvider *provider,
+ NSWindow *window,
+ double quartz_x,
+ double quartz_y);
+void _gdk_macos_drag_surface_move (GdkMacosDrag *self,
+ double x_root,
+ double y_root);
+void _gdk_macos_drag_set_start_position (GdkDrag *drag,
+ int start_x,
+ int start_y);
+void _gdk_macos_drag_set_last_position (GdkDrag *drag,
+ int last_x,
+ int last_y);
+void _gdk_macos_drag_set_actions (GdkDrag *drag,
+ GdkModifierType mods);
+NSDragOperation _gdk_macos_drag_operation (GdkMacosDrag *self);
G_END_DECLS
diff --git a/gdk/macos/gdkmacosdrag.c b/gdk/macos/gdkmacosdrag.c
index c9e2dd19a6a935c5ffbe80782c8436e95ed126f6..9039d3c55c06b2fbb3d673652c76e52d3793d7a7 100644
--- a/gdk/macos/gdkmacosdrag.c
+++ b/gdk/macos/gdkmacosdrag.c
@@ -32,6 +32,8 @@
#include "gdk/gdkseatprivate.h"
#include "gdk/gdk-private.h"
+#import "GdkMacosDraggingSource.h"
+
#define BIG_STEP 20
#define SMALL_STEP 1
#define ANIM_TIME 500000 /* .5 seconds */
@@ -53,6 +55,17 @@ enum {
static GParamSpec *properties [N_PROPS];
+static void
+gdk_macos_drag_drop_from_display (GdkMacosDrag *self)
+{
+ GdkDisplay *display;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ display = gdk_drag_get_display (GDK_DRAG (self));
+ _gdk_macos_display_set_drag (GDK_MACOS_DISPLAY (display), self->sequence, NULL);
+}
+
static double
ease_out_cubic (double t)
{
@@ -85,12 +98,12 @@ gdk_macos_zoomback_timeout (gpointer data)
frame_clock = zb->frame_clock;
if (!frame_clock)
- return G_SOURCE_REMOVE;
+ goto hide_surface;
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;
+ goto hide_surface;
t = ease_out_cubic (f);
@@ -105,6 +118,11 @@ gdk_macos_zoomback_timeout (gpointer data)
_gdk_macos_surface_show (GDK_MACOS_SURFACE (drag->drag_surface));
return G_SOURCE_CONTINUE;
+
+hide_surface:
+ gdk_surface_hide (GDK_SURFACE (drag->drag_surface));
+
+ return G_SOURCE_REMOVE;
}
static GdkSurface *
@@ -146,6 +164,8 @@ gdk_macos_drag_drop_done (GdkDrag *drag,
g_assert (GDK_IS_MACOS_DRAG (self));
+ g_print ("Drop done! success=%d\n", success);
+
if (success)
{
gdk_surface_hide (GDK_SURFACE (self->drag_surface));
@@ -187,29 +207,6 @@ gdk_macos_drag_set_cursor (GdkDrag *drag,
[nscursor set];
}
-static gboolean
-drag_grab (GdkMacosDrag *self)
-{
- GdkSeat *seat;
-
- g_assert (GDK_IS_MACOS_DRAG (self));
-
- seat = gdk_device_get_seat (gdk_drag_get_device (GDK_DRAG (self)));
-
- if (gdk_seat_grab (seat,
- GDK_SURFACE (self->drag_surface),
- GDK_SEAT_CAPABILITY_ALL_POINTING,
- FALSE,
- self->cursor,
- NULL,
- NULL,
- NULL) != GDK_GRAB_SUCCESS)
- return FALSE;
-
- g_set_object (&self->drag_seat, seat);
-
- return TRUE;
-}
static void
drag_ungrab (GdkMacosDrag *self)
@@ -235,22 +232,8 @@ gdk_macos_drag_cancel (GdkDrag *drag,
self->cancelled = TRUE;
drag_ungrab (self);
- gdk_drag_drop_done (drag, FALSE);
-}
-
-static void
-gdk_macos_drag_drop_performed (GdkDrag *drag,
- guint32 time)
-{
- GdkMacosDrag *self = (GdkMacosDrag *)drag;
-
- g_assert (GDK_IS_MACOS_DRAG (self));
-
- g_object_ref (self);
- drag_ungrab (self);
- g_signal_emit_by_name (drag, "dnd-finished");
- gdk_drag_drop_done (drag, TRUE);
- g_object_unref (self);
+ gdk_surface_hide (GDK_SURFACE (self->drag_surface));
+ gdk_macos_drag_drop_from_display (self);
}
static void
@@ -311,222 +294,9 @@ gdk_drag_get_current_actions (GdkModifierType state,
}
static void
-gdk_drag_update (GdkDrag *drag,
- double x_root,
- double y_root,
- GdkModifierType mods,
- guint32 evtime)
+gdk_macos_drag_dnd_finished (GdkDrag *drag)
{
- GdkMacosDrag *self = (GdkMacosDrag *)drag;
- GdkDragAction suggested_action;
- GdkDragAction possible_actions;
-
- g_assert (GDK_IS_MACOS_DRAG (self));
-
- self->last_x = x_root;
- self->last_y = y_root;
-
- gdk_drag_get_current_actions (mods,
- GDK_BUTTON_PRIMARY,
- gdk_drag_get_actions (drag),
- &suggested_action,
- &possible_actions);
-
- if (GDK_IS_MACOS_SURFACE (self->drag_surface))
- _gdk_macos_surface_move (GDK_MACOS_SURFACE (self->drag_surface),
- x_root - self->hot_x,
- y_root - self->hot_y);
-
- if (!self->did_update)
- {
- self->start_x = self->last_x;
- self->start_y = self->last_y;
- self->did_update = TRUE;
- }
-
- gdk_drag_set_actions (drag, possible_actions);
-}
-
-static gboolean
-gdk_dnd_handle_motion_event (GdkDrag *drag,
- GdkEvent *event)
-{
- double x, y;
- int x_root, y_root;
-
- 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;
- gdk_drag_update (drag, x_root, y_root,
- gdk_event_get_modifier_state (event),
- gdk_event_get_time (event));
-
- return TRUE;
-}
-
-static gboolean
-gdk_dnd_handle_grab_broken_event (GdkDrag *drag,
- GdkEvent *event)
-{
- GdkMacosDrag *self = GDK_MACOS_DRAG (drag);
- gboolean is_implicit = gdk_grab_broken_event_get_implicit (event);
- GdkSurface *grab_surface = gdk_grab_broken_event_get_grab_surface (event);
-
- /* Don't cancel if we break the implicit grab from the initial button_press. */
- if (is_implicit || grab_surface == (GdkSurface *)self->drag_surface)
- return FALSE;
-
- if (gdk_event_get_device (event) != gdk_drag_get_device (drag))
- return FALSE;
-
- gdk_drag_cancel (drag, GDK_DRAG_CANCEL_ERROR);
-
- return TRUE;
-}
-
-static gboolean
-gdk_dnd_handle_button_event (GdkDrag *drag,
- GdkEvent *event)
-{
- GdkMacosDrag *self = GDK_MACOS_DRAG (drag);
-
- g_assert (GDK_IS_MACOS_DRAG (self));
- g_assert (event != NULL);
-
-#if 0
- /* FIXME: Check the button matches */
- if (event->button != self->button)
- return FALSE;
-#endif
-
- if (gdk_drag_get_selected_action (drag) != 0)
- g_signal_emit_by_name (drag, "drop-performed");
- else
- gdk_drag_cancel (drag, GDK_DRAG_CANCEL_NO_TARGET);
-
- return TRUE;
-}
-
-static gboolean
-gdk_dnd_handle_key_event (GdkDrag *drag,
- GdkEvent *event)
-{
- GdkMacosDrag *self = GDK_MACOS_DRAG (drag);
- GdkModifierType state;
- GdkDevice *pointer;
- GdkSeat *seat;
- int dx, dy;
-
- dx = dy = 0;
- state = gdk_event_get_modifier_state (event);
- seat = gdk_event_get_seat (event);
- pointer = gdk_seat_get_pointer (seat);
-
- if (event->event_type == GDK_KEY_PRESS)
- {
- guint keyval = gdk_key_event_get_keyval (event);
-
- switch (keyval)
- {
- case GDK_KEY_Escape:
- gdk_drag_cancel (drag, GDK_DRAG_CANCEL_USER_CANCELLED);
- return TRUE;
-
- case GDK_KEY_space:
- case GDK_KEY_Return:
- case GDK_KEY_ISO_Enter:
- case GDK_KEY_KP_Enter:
- case GDK_KEY_KP_Space:
- if (gdk_drag_get_selected_action (drag) != 0)
- g_signal_emit_by_name (drag, "drop-performed");
- else
- gdk_drag_cancel (drag, GDK_DRAG_CANCEL_NO_TARGET);
-
- return TRUE;
-
- case GDK_KEY_Up:
- case GDK_KEY_KP_Up:
- dy = (state & GDK_ALT_MASK) ? -BIG_STEP : -SMALL_STEP;
- break;
-
- case GDK_KEY_Down:
- case GDK_KEY_KP_Down:
- dy = (state & GDK_ALT_MASK) ? BIG_STEP : SMALL_STEP;
- break;
-
- case GDK_KEY_Left:
- case GDK_KEY_KP_Left:
- dx = (state & GDK_ALT_MASK) ? -BIG_STEP : -SMALL_STEP;
- break;
-
- case GDK_KEY_Right:
- case GDK_KEY_KP_Right:
- dx = (state & GDK_ALT_MASK) ? BIG_STEP : SMALL_STEP;
- break;
-
- default:
- break;
- }
- }
-
- /* The state is not yet updated in the event, so we need
- * to query it here. We could use XGetModifierMapping, but
- * that would be overkill.
- */
- gdk_macos_device_query_state (pointer, NULL, NULL, NULL, NULL, &state);
-
- if (dx != 0 || dy != 0)
- {
- GdkDisplay *display = gdk_event_get_display ((GdkEvent *)event);
-
- self->last_x += dx;
- self->last_y += dy;
-
- _gdk_macos_display_warp_pointer (GDK_MACOS_DISPLAY (display),
- self->last_x,
- self->last_y);
- }
-
- gdk_drag_update (drag,
- self->last_x, self->last_y,
- state,
- gdk_event_get_time (event));
-
- return TRUE;
-}
-
-static gboolean
-gdk_macos_drag_handle_event (GdkDrag *drag,
- GdkEvent *event)
-{
- g_assert (GDK_IS_MACOS_DRAG (drag));
- g_assert (event != NULL);
-
- switch ((guint) event->event_type)
- {
- case GDK_MOTION_NOTIFY:
- return gdk_dnd_handle_motion_event (drag, event);
-
- case GDK_BUTTON_RELEASE:
- return gdk_dnd_handle_button_event (drag, event);
-
- case GDK_KEY_PRESS:
- case GDK_KEY_RELEASE:
- return gdk_dnd_handle_key_event (drag, event);
-
- case GDK_GRAB_BROKEN:
- return gdk_dnd_handle_grab_broken_event (drag, event);
-
- default:
- return FALSE;
- }
+ gdk_macos_drag_drop_from_display (GDK_MACOS_DRAG (drag));
}
static void
@@ -597,8 +367,7 @@ gdk_macos_drag_class_init (GdkMacosDragClass *klass)
drag_class->drop_done = gdk_macos_drag_drop_done;
drag_class->set_cursor = gdk_macos_drag_set_cursor;
drag_class->cancel = gdk_macos_drag_cancel;
- drag_class->drop_performed = gdk_macos_drag_drop_performed;
- drag_class->handle_event = gdk_macos_drag_handle_event;
+ drag_class->dnd_finished = gdk_macos_drag_dnd_finished;
properties [PROP_DRAG_SURFACE] =
g_param_spec_object ("drag-surface", NULL, NULL,
@@ -613,12 +382,122 @@ gdk_macos_drag_init (GdkMacosDrag *self)
{
}
+NSDragOperation
+_gdk_macos_drag_operation (GdkMacosDrag *self)
+{
+ NSDragOperation operation = NSDragOperationNone;
+ GdkDragAction actions;
+
+ g_return_val_if_fail (GDK_IS_MACOS_DRAG (self), NSDragOperationNone);
+
+ actions = gdk_drag_get_actions (GDK_DRAG (self));
+
+ if (actions & GDK_ACTION_LINK)
+ operation |= NSDragOperationLink;
+
+ if (actions & GDK_ACTION_MOVE)
+ operation |= NSDragOperationMove;
+
+ if (actions & GDK_ACTION_COPY)
+ operation |= NSDragOperationCopy;
+
+ return operation;
+}
+
gboolean
-_gdk_macos_drag_begin (GdkMacosDrag *self)
+_gdk_macos_drag_begin (GdkMacosDrag *self,
+ GdkContentProvider *content,
+ NSWindow *window,
+ double quartz_x,
+ double quartz_y)
{
+ NSArray *items;
+ NSDraggingSession *session;
+ NSPasteboardItem *item;
+ NSEvent *nsevent;
+ GdkMacosDraggingSource *source;
+
g_return_val_if_fail (GDK_IS_MACOS_DRAG (self), FALSE);
- _gdk_macos_surface_show (GDK_MACOS_SURFACE (self->drag_surface));
+ GDK_BEGIN_MACOS_ALLOC_POOL;
- return drag_grab (self);
+ item = [[GdkMacosPasteboardItem alloc] initForDrag:GDK_DRAG (self) withContentProvider:content];
+ items = [NSArray arrayWithObject:item];
+ source = [[GdkMacosDraggingSource alloc] init:GDK_DRAG (self)];
+ nsevent = _gdk_macos_display_get_last_nsevent ();
+
+ session = [[window contentView] beginDraggingSessionWithItems:items
+ event:nsevent
+ source:source];
+ self->sequence = [session draggingSequenceNumber];
+
+ [source autorelease];
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ gdk_surface_hide (GDK_SURFACE (self->drag_surface));
+
+ _gdk_macos_display_set_drag (GDK_MACOS_DISPLAY (gdk_drag_get_display (GDK_DRAG (self))),
+ self->sequence,
+ GDK_DRAG (self));
+ return TRUE;
+}
+
+void
+_gdk_macos_drag_surface_move (GdkMacosDrag *self,
+ double x_root,
+ double y_root)
+{
+ g_return_if_fail (GDK_IS_MACOS_DRAG (self));
+
+ if (GDK_IS_MACOS_SURFACE (self->drag_surface))
+ _gdk_macos_surface_move (GDK_MACOS_SURFACE (self->drag_surface),
+ x_root - self->hot_x,
+ y_root - self->hot_y);
+}
+
+void
+_gdk_macos_drag_set_start_position (GdkDrag *drag,
+ int start_x,
+ int start_y)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *) drag;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ self->start_x = start_x;
+ self->start_y = start_y;
+}
+
+void
+_gdk_macos_drag_set_last_position (GdkDrag *drag,
+ int last_x,
+ int last_y)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *) drag;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ self->last_x = last_x;
+ self->last_y = last_y;
+}
+
+void
+_gdk_macos_drag_set_actions (GdkDrag *drag,
+ GdkModifierType mods)
+{
+ GdkMacosDrag *self = (GdkMacosDrag *) drag;
+ GdkDragAction suggested_action;
+ GdkDragAction possible_actions;
+
+ g_assert (GDK_IS_MACOS_DRAG (self));
+
+ gdk_drag_get_current_actions (mods,
+ GDK_BUTTON_PRIMARY,
+ gdk_drag_get_actions (drag),
+ &suggested_action,
+ &possible_actions);
+
+ gdk_drag_set_selected_action (drag, suggested_action);
+ gdk_drag_set_actions (drag, possible_actions);
}
diff --git a/gdk/macos/gdkmacospasteboard-private.h b/gdk/macos/gdkmacospasteboard-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..166fa9b6a95abc57c71a4d8596462cbe223d7da8
--- /dev/null
+++ b/gdk/macos/gdkmacospasteboard-private.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#ifndef __GDK_MACOS_PASTEBOARD_PRIVATE_H__
+#define __GDK_MACOS_PASTEBOARD_PRIVATE_H__
+
+#include
+#include
+
+#include "gdkclipboardprivate.h"
+
+G_BEGIN_DECLS
+
+#define GDK_MACOS_LOCAL_DND_MIME_TYPE "application/x-gtk-local-dnd"
+
+@interface GdkMacosPasteboardItemDataProvider : NSObject
+{
+ GdkContentProvider *_contentProvider;
+ GdkClipboard *_clipboard;
+ GdkDrag *_drag;
+}
+
+-(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
+
+NSPasteboardType _gdk_macos_pasteboard_to_ns_type (const char *mime_type,
+ NSPasteboardType *alternate);
+const char *_gdk_macos_pasteboard_from_ns_type (NSPasteboardType type);
+GdkContentFormats *_gdk_macos_pasteboard_load_formats (NSPasteboard *pasteboard);
+void _gdk_macos_pasteboard_register_drag_types (NSWindow *window);
+void _gdk_macos_pasteboard_read_async (GObject *object,
+ NSPasteboard *pasteboard,
+ GdkContentFormats *formats,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GInputStream *_gdk_macos_pasteboard_read_finish (GObject *object,
+ GAsyncResult *result,
+ const char **out_mime_type,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __GDK_MACOS_PASTEBOARD_PRIVATE_H__ */
diff --git a/gdk/macos/gdkmacospasteboard.c b/gdk/macos/gdkmacospasteboard.c
new file mode 100644
index 0000000000000000000000000000000000000000..6a2959a7cca19f0733d55d5d09a43cbadf8e6c6d
--- /dev/null
+++ b/gdk/macos/gdkmacospasteboard.c
@@ -0,0 +1,606 @@
+/*
+ * Copyright © 2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include
+
+#include "gdkmacospasteboard-private.h"
+#include "gdkmacosutils-private.h"
+#include "gdk-private.h"
+#include "gdkdragprivate.h"
+
+enum {
+ TYPE_STRING,
+ TYPE_PBOARD,
+ TYPE_URL,
+ TYPE_FILE_URL,
+ TYPE_COLOR,
+ TYPE_TIFF,
+ TYPE_PNG,
+ TYPE_INTERNAL,
+ TYPE_LAST
+};
+
+#define PTYPE(k) (get_pasteboard_type(TYPE_##k))
+
+static NSPasteboardType pasteboard_types[TYPE_LAST];
+
+static NSPasteboardType
+get_pasteboard_type (int type)
+{
+ static gsize initialized = FALSE;
+
+ g_assert (type >= 0);
+ g_assert (type < TYPE_LAST);
+
+ if (g_once_init_enter (&initialized))
+ {
+ pasteboard_types[TYPE_PNG] = NSPasteboardTypePNG;
+ pasteboard_types[TYPE_STRING] = NSPasteboardTypeString;
+ pasteboard_types[TYPE_TIFF] = NSPasteboardTypeTIFF;
+ pasteboard_types[TYPE_COLOR] = NSPasteboardTypeColor;
+
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ pasteboard_types[TYPE_PBOARD] = NSStringPboardType;
+ G_GNUC_END_IGNORE_DEPRECATIONS
+
+#ifdef AVAILABLE_MAC_OS_X_VERSION_10_13_AND_LATER
+ pasteboard_types[TYPE_URL] = NSPasteboardTypeURL;
+ pasteboard_types[TYPE_FILE_URL] = NSPasteboardTypeFileURL;
+#else
+ pasteboard_types[TYPE_URL] = [[NSString alloc] initWithUTF8String:"public.url"];
+ pasteboard_types[TYPE_FILE_URL] = [[NSString alloc] initWithUTF8String:"public.file-url"];
+#endif
+
+ pasteboard_types[TYPE_INTERNAL] = [[NSString alloc] initWithUTF8String:"org.gtk.pasteboard.internal"];
+
+ g_once_init_leave (&initialized, TRUE);
+ }
+
+ return pasteboard_types[type];
+}
+
+const char *
+_gdk_macos_pasteboard_from_ns_type (NSPasteboardType type)
+{
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+
+ if ([type isEqualToString:PTYPE(STRING)] ||
+ [type isEqualToString:PTYPE(PBOARD)])
+ return g_intern_string ("text/plain;charset=utf-8");
+ else if ([type isEqualToString:PTYPE(URL)] ||
+ [type isEqualToString:PTYPE(FILE_URL)])
+ return g_intern_string ("text/uri-list");
+ else if ([type isEqualToString:PTYPE(COLOR)])
+ return g_intern_string ("application/x-color");
+ else if ([type isEqualToString:PTYPE(TIFF)])
+ return g_intern_string ("image/tiff");
+ else if ([type isEqualToString:PTYPE(PNG)])
+ return g_intern_string ("image/png");
+ else if ([type isEqualToString:PTYPE(INTERNAL)])
+ return g_intern_string (GDK_MACOS_LOCAL_DND_MIME_TYPE);
+
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+
+ return NULL;
+}
+
+NSPasteboardType
+_gdk_macos_pasteboard_to_ns_type (const char *mime_type,
+ NSPasteboardType *alternate)
+{
+ if (alternate)
+ *alternate = NULL;
+
+ if (g_strcmp0 (mime_type, "text/plain;charset=utf-8") == 0)
+ {
+ return PTYPE(STRING);
+ }
+ else if (g_strcmp0 (mime_type, "text/uri-list") == 0)
+ {
+ if (alternate)
+ *alternate = PTYPE(URL);
+ return PTYPE(FILE_URL);
+ }
+ else if (g_strcmp0 (mime_type, "application/x-color") == 0)
+ {
+ return PTYPE(COLOR);
+ }
+ else if (g_strcmp0 (mime_type, "image/tiff") == 0)
+ {
+ return PTYPE(TIFF);
+ }
+ else if (g_strcmp0 (mime_type, "image/png") == 0)
+ {
+ return PTYPE(PNG);
+ }
+ else if (g_strcmp0 (mime_type, GDK_MACOS_LOCAL_DND_MIME_TYPE) == 0)
+ {
+ return PTYPE(INTERNAL);
+ }
+
+ return nil;
+}
+
+static void
+populate_content_formats (GdkContentFormatsBuilder *builder,
+ NSPasteboardType type)
+{
+ const char *mime_type;
+
+ g_assert (builder != NULL);
+ g_assert (type != NULL);
+
+ if ((mime_type = _gdk_macos_pasteboard_from_ns_type (type)))
+ gdk_content_formats_builder_add_mime_type (builder, mime_type);
+}
+
+static GdkContentFormats *
+load_offer_formats (NSPasteboard *pasteboard)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkContentFormatsBuilder *builder;
+ GdkContentFormats *formats;
+
+ builder = gdk_content_formats_builder_new ();
+ for (NSPasteboardType type in [pasteboard types])
+ populate_content_formats (builder, type);
+ formats = gdk_content_formats_builder_free_to_formats (builder);
+
+ GDK_END_MACOS_ALLOC_POOL;
+
+ return g_steal_pointer (&formats);
+}
+
+GdkContentFormats *
+_gdk_macos_pasteboard_load_formats (NSPasteboard *pasteboard)
+{
+ return load_offer_formats (pasteboard);
+}
+
+static GInputStream *
+create_stream_from_nsdata (NSData *data)
+{
+ const guint8 *bytes = [data bytes];
+ gsize len = [data length];
+
+ return g_memory_input_stream_new_from_data (g_memdup2 (bytes, len), len, g_free);
+}
+
+void
+_gdk_macos_pasteboard_read_async (GObject *object,
+ NSPasteboard *pasteboard,
+ GdkContentFormats *formats,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GDK_BEGIN_MACOS_ALLOC_POOL;
+
+ GdkContentFormats *offer_formats = NULL;
+ const char *mime_type;
+ GInputStream *stream = NULL;
+ GTask *task = NULL;
+
+ g_assert (G_IS_OBJECT (object));
+ g_assert (pasteboard != NULL);
+ g_assert (formats != NULL);
+
+ task = g_task_new (object, cancellable, callback, user_data);
+ g_task_set_source_tag (task, _gdk_macos_pasteboard_read_async);
+ g_task_set_priority (task, io_priority);
+
+ offer_formats = load_offer_formats (pasteboard);
+ mime_type = gdk_content_formats_match_mime_type (formats, offer_formats);
+
+ if (mime_type == NULL)
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_SUPPORTED,
+ "%s",
+ _("No compatible transfer format found"));
+ goto cleanup;
+ }
+
+ if (strcmp (mime_type, "text/plain;charset=utf-8") == 0)
+ {
+ NSString *nsstr = [pasteboard stringForType:NSPasteboardTypeString];
+
+ if (nsstr != NULL)
+ {
+ const char *str = [nsstr UTF8String];
+ stream = g_memory_input_stream_new_from_data (g_strdup (str),
+ strlen (str) + 1,
+ g_free);
+ }
+ }
+ else if (strcmp (mime_type, "text/uri-list") == 0)
+ {
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
+
+ if ([[pasteboard types] containsObject:PTYPE(FILE_URL)])
+ {
+ GString *str = g_string_new (NULL);
+ NSArray *files = [pasteboard propertyListForType:NSFilenamesPboardType];
+ gsize n_files = [files count];
+ char *data;
+ guint len;
+
+ for (gsize i = 0; i < n_files; ++i)
+ {
+ NSString* uriString = [files objectAtIndex:i];
+ uriString = [@"file://" stringByAppendingString:uriString];
+ uriString = [uriString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+
+ g_string_append_printf (str,
+ "%s\r\n",
+ [uriString cStringUsingEncoding:NSUTF8StringEncoding]);
+ }
+
+ len = str->len;
+ data = g_string_free (str, FALSE);
+ stream = g_memory_input_stream_new_from_data (data, len, g_free);
+ }
+
+ G_GNUC_END_IGNORE_DEPRECATIONS;
+ }
+ else if (strcmp (mime_type, "application/x-color") == 0)
+ {
+ NSColorSpace *colorspace;
+ NSColor *nscolor;
+ guint16 color[4];
+
+ colorspace = [NSColorSpace genericRGBColorSpace];
+ nscolor = [[NSColor colorFromPasteboard:pasteboard]
+ colorUsingColorSpace:colorspace];
+
+ color[0] = 0xffff * [nscolor redComponent];
+ color[1] = 0xffff * [nscolor greenComponent];
+ color[2] = 0xffff * [nscolor blueComponent];
+ color[3] = 0xffff * [nscolor alphaComponent];
+
+ stream = g_memory_input_stream_new_from_data (g_memdup2 (&color, sizeof color),
+ sizeof color,
+ g_free);
+ }
+ else if (strcmp (mime_type, "image/tiff") == 0)
+ {
+ NSData *data = [pasteboard dataForType:PTYPE(TIFF)];
+ stream = create_stream_from_nsdata (data);
+ }
+ else if (strcmp (mime_type, "image/png") == 0)
+ {
+ NSData *data = [pasteboard dataForType:PTYPE(PNG)];
+ stream = create_stream_from_nsdata (data);
+ }
+ else if (strcmp (mime_type, GDK_MACOS_LOCAL_DND_MIME_TYPE) == 0)
+ {
+ /* Should be internal copy */
+ g_warn_if_reached ();
+ }
+
+ if (stream != NULL)
+ {
+ g_task_set_task_data (task, g_strdup (mime_type), g_free);
+ g_task_return_pointer (task, g_steal_pointer (&stream), g_object_unref);
+ }
+ else
+ {
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Failed to decode contents with mime-type of '%s'"),
+ mime_type);
+ }
+
+cleanup:
+ g_clear_object (&task);
+ g_clear_pointer (&offer_formats, gdk_content_formats_unref);
+
+ GDK_END_MACOS_ALLOC_POOL;
+}
+
+GInputStream *
+_gdk_macos_pasteboard_read_finish (GObject *object,
+ GAsyncResult *result,
+ const char **out_mime_type,
+ GError **error)
+{
+ GTask *task = (GTask *)result;
+
+ g_assert (G_IS_OBJECT (object));
+ g_assert (G_IS_TASK (task));
+
+ if (out_mime_type != NULL)
+ *out_mime_type = g_strdup (g_task_get_task_data (task));
+
+ return g_task_propagate_pointer (task, error);
+}
+
+void
+_gdk_macos_pasteboard_register_drag_types (NSWindow *window)
+{
+ [window registerForDraggedTypes:[NSArray arrayWithObjects:PTYPE(STRING),
+ PTYPE(PBOARD),
+ PTYPE(URL),
+ PTYPE(FILE_URL),
+ PTYPE(COLOR),
+ PTYPE(TIFF),
+ PTYPE(PNG),
+ PTYPE(INTERNAL),
+ 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 *)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; i < n_mime_types; 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];
+ }
+ }
+
+ if ([ret count] == 0)
+ {
+ NSPasteboardType type;
+ NSPasteboardType alternate = nil;
+
+ if ((type = _gdk_macos_pasteboard_to_ns_type (GDK_MACOS_LOCAL_DND_MIME_TYPE, &alternate)))
+ [ret addObject:type];
+ }
+
+
+ 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
diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c
index d10992ffd47fc395b762cc179b8e30f4cbd9e000..31da0b37130b4c8276a5fc996ed0df72f1d7b9ae 100644
--- a/gdk/macos/gdkmacossurface.c
+++ b/gdk/macos/gdkmacossurface.c
@@ -24,6 +24,7 @@
#include
#import "GdkMacosView.h"
+#import "GdkMacosDraggingSource.h"
#include "gdkmacossurface-private.h"
@@ -35,8 +36,9 @@
#include "gdkseatprivate.h"
#include "gdksurfaceprivate.h"
-#include "gdkmacosdevice.h"
+#include "gdkmacosclipboard-private.h"
#include "gdkmacosdevice-private.h"
+#include "gdkmacosdevice.h"
#include "gdkmacosdisplay-private.h"
#include "gdkmacosdrag-private.h"
#include "gdkmacosdragsurface-private.h"
@@ -419,10 +421,9 @@ gdk_macos_surface_drag_begin (GdkSurface *surface,
GdkMacosSurface *self = (GdkMacosSurface *)surface;
GdkMacosSurface *drag_surface;
GdkMacosDrag *drag;
- GdkCursor *cursor;
+ GdkDisplay *display;
GdkSeat *seat;
- double px;
- double py;
+ int quartz_x, quartz_y;
int sx;
int sy;
@@ -432,13 +433,18 @@ gdk_macos_surface_drag_begin (GdkSurface *surface,
g_assert (GDK_IS_MACOS_DEVICE (device));
g_assert (GDK_IS_CONTENT_PROVIDER (content));
+ display = gdk_surface_get_display (surface);
+ _gdk_macos_display_to_display_coords (GDK_MACOS_DISPLAY (display),
+ surface->x + dx,
+ surface->y + dy,
+ &quartz_x, &quartz_y);
+
seat = gdk_device_get_seat (device);
- gdk_macos_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,
- sx, sy, 1, 1);
+ quartz_x, quartz_y, 1, 1);
drag = g_object_new (GDK_TYPE_MACOS_DRAG,
"drag-surface", drag_surface,
"surface", surface,
@@ -446,18 +452,16 @@ gdk_macos_surface_drag_begin (GdkSurface *surface,
"content", content,
"actions", actions,
NULL);
- g_clear_object (&drag_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);
+ g_object_unref (drag_surface);
- if (!_gdk_macos_drag_begin (drag))
+ if (!_gdk_macos_drag_begin (drag, content, self->window, quartz_x, quartz_y))
{
g_object_unref (drag);
return NULL;
}
+ gdk_seat_ungrab (seat);
+
/* Hold a reference until drop_done is called */
g_object_ref (drag);
diff --git a/gdk/macos/meson.build b/gdk/macos/meson.build
index bd7bbb532453c24b742abe6951034812af84533d..8f8d66c6e48d5692029bb0949522ffceec2ded96 100644
--- a/gdk/macos/meson.build
+++ b/gdk/macos/meson.build
@@ -19,6 +19,7 @@ gdk_macos_sources = files([
'gdkmacoseventsource.c',
'gdkmacoskeymap.c',
'gdkmacosmonitor.c',
+ 'gdkmacospasteboard.c',
'gdkmacospopupsurface.c',
'gdkmacosseat.c',
'gdkmacossurface.c',
@@ -27,6 +28,7 @@ gdk_macos_sources = files([
'GdkMacosLayer.c',
'GdkMacosTile.c',
'GdkMacosView.c',
+ 'GdkMacosDraggingSource.c',
'GdkMacosWindow.c',
])