diff --git a/gdk/macos/GdkMacosWindow.c b/gdk/macos/GdkMacosWindow.c index 3afcdeb826..714a5047cd 100644 --- a/gdk/macos/GdkMacosWindow.c +++ b/gdk/macos/GdkMacosWindow.c @@ -28,7 +28,9 @@ #import "GdkMacosGLView.h" #import "GdkMacosWindow.h" +#include "gdkmacosclipboard-private.h" #include "gdkmacosdisplay-private.h" +#include "gdkmacosdrop-private.h" #include "gdkmacosmonitor-private.h" #include "gdkmacossurface-private.h" #include "gdkmacospopupsurface-private.h" @@ -287,6 +289,9 @@ typedef NSString *CALayerContentsGravity; [self setContentView:view]; [view release]; + /* TODO: We might want to make this more extensible at some point */ + _gdk_macos_clipboard_register_drag_types (self); + return self; } @@ -597,25 +602,86 @@ typedef NSString *CALayerContentsGravity; -(NSDragOperation)draggingEntered:(id )sender { - return NSDragOperationNone; + NSPoint location = [sender draggingLocation]; + NSDragOperation ret; + GdkMacosDrop *drop; + + if (!(drop = _gdk_macos_drop_new ([self gdkSurface], sender))) + return NSDragOperationNone; + + _gdk_macos_display_set_drop ([self gdkDisplay], + [sender draggingSequenceNumber], + GDK_DROP (drop)); + + gdk_drop_emit_enter_event (GDK_DROP (drop), + TRUE, + location.x, + GDK_SURFACE (gdk_surface)->height - location.y, + GDK_CURRENT_TIME); + + ret = _gdk_macos_drop_operation (drop); + + g_object_unref (drop); + + return ret; } -(void)draggingEnded:(id )sender { + _gdk_macos_display_set_drop ([self gdkDisplay], [sender draggingSequenceNumber], NULL); } -(void)draggingExited:(id )sender { + NSInteger sequence_number = [sender draggingSequenceNumber]; + GdkDrop *drop = _gdk_macos_display_find_drop ([self gdkDisplay], sequence_number); + + if (drop != NULL) + gdk_drop_emit_leave_event (drop, TRUE, GDK_CURRENT_TIME); + + _gdk_macos_display_set_drop ([self gdkDisplay], sequence_number, NULL); } -(NSDragOperation)draggingUpdated:(id )sender { - return NSDragOperationNone; + NSInteger sequence_number = [sender draggingSequenceNumber]; + GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (gdk_surface)); + GdkDrop *drop = _gdk_macos_display_find_drop (GDK_MACOS_DISPLAY (display), sequence_number); + NSPoint location = [sender draggingLocation]; + + if (drop == NULL) + return NSDragOperationNone; + + _gdk_macos_drop_update_actions (GDK_MACOS_DROP (drop), sender); + + gdk_drop_emit_motion_event (drop, + TRUE, + location.x, + GDK_SURFACE (gdk_surface)->height - location.y, + GDK_CURRENT_TIME); + + return _gdk_macos_drop_operation (GDK_MACOS_DROP (drop)); } -(BOOL)performDragOperation:(id )sender { - return YES; + NSInteger sequence_number = [sender draggingSequenceNumber]; + GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (gdk_surface)); + GdkDrop *drop = _gdk_macos_display_find_drop (GDK_MACOS_DISPLAY (display), sequence_number); + NSPoint location = [sender draggingLocation]; + + if (drop == NULL) + return NO; + + gdk_drop_emit_drop_event (drop, + TRUE, + location.x, + GDK_SURFACE (gdk_surface)->height - location.y, + GDK_CURRENT_TIME); + + gdk_drop_emit_leave_event (drop, TRUE, GDK_CURRENT_TIME); + + return GDK_MACOS_DROP (drop)->finish_action != 0; } -(BOOL)wantsPeriodicDraggingUpdates diff --git a/gdk/macos/gdkmacosclipboard-private.h b/gdk/macos/gdkmacosclipboard-private.h index 01a562c2b8..ba0b52bf0a 100644 --- a/gdk/macos/gdkmacosclipboard-private.h +++ b/gdk/macos/gdkmacosclipboard-private.h @@ -35,11 +35,24 @@ typedef NSString *NSPasteboardType; G_DECLARE_FINAL_TYPE (GdkMacosClipboard, _gdk_macos_clipboard, GDK, MACOS_CLIPBOARD, GdkClipboard) -GdkClipboard *_gdk_macos_clipboard_new (GdkMacosDisplay *display); -void _gdk_macos_clipboard_check_externally_modified (GdkMacosClipboard *self); -NSPasteboardType _gdk_macos_clipboard_to_ns_type (const char *mime_type, - NSPasteboardType *alternate); -const char *_gdk_macos_clipboard_from_ns_type (NSPasteboardType ns_type); +GdkClipboard *_gdk_macos_clipboard_new (GdkMacosDisplay *display); +void _gdk_macos_clipboard_check_externally_modified (GdkMacosClipboard *self); +NSPasteboardType _gdk_macos_clipboard_to_ns_type (const char *mime_type, + 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 { diff --git a/gdk/macos/gdkmacosclipboard.c b/gdk/macos/gdkmacosclipboard.c index 7ddf47d83b..ba755db0be 100644 --- a/gdk/macos/gdkmacosclipboard.c +++ b/gdk/macos/gdkmacosclipboard.c @@ -172,17 +172,15 @@ populate_content_formats (GdkContentFormatsBuilder *builder, } static GdkContentFormats * -load_offer_formats (GdkMacosClipboard *self) +load_offer_formats (NSPasteboard *pasteboard) { GDK_BEGIN_MACOS_ALLOC_POOL; GdkContentFormatsBuilder *builder; GdkContentFormats *formats; - g_assert (GDK_IS_MACOS_CLIPBOARD (self)); - builder = gdk_content_formats_builder_new (); - for (NSPasteboardType type in [self->pasteboard types]) + for (NSPasteboardType type in [pasteboard types]) populate_content_formats (builder, type); formats = gdk_content_formats_builder_free_to_formats (builder); @@ -201,7 +199,7 @@ _gdk_macos_clipboard_load_contents (GdkMacosClipboard *self) change_count = [self->pasteboard changeCount]; - formats = load_offer_formats (self); + formats = load_offer_formats (self->pasteboard); gdk_clipboard_claim_remote (GDK_CLIPBOARD (self), formats); gdk_content_formats_unref (formats); @@ -225,125 +223,13 @@ _gdk_macos_clipboard_read_async (GdkClipboard *clipboard, GAsyncReadyCallback callback, gpointer user_data) { - GDK_BEGIN_MACOS_ALLOC_POOL; - - GdkMacosClipboard *self = (GdkMacosClipboard *)clipboard; - GdkContentFormats *offer_formats = NULL; - const char *mime_type; - GInputStream *stream = NULL; - GTask *task = NULL; - - g_assert (GDK_IS_MACOS_CLIPBOARD (self)); - g_assert (formats != NULL); - - task = g_task_new (self, cancellable, callback, user_data); - g_task_set_source_tag (task, _gdk_macos_clipboard_read_async); - g_task_set_priority (task, io_priority); - - offer_formats = load_offer_formats (GDK_MACOS_CLIPBOARD (clipboard)); - 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 = [self->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 ([[self->pasteboard types] containsObject:PTYPE(FILE_URL)]) - { - GString *str = g_string_new (NULL); - NSArray *files = [self->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:self->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 = [self->pasteboard dataForType:PTYPE(TIFF)]; - stream = create_stream_from_nsdata (data); - } - else if (strcmp (mime_type, "image/png") == 0) - { - NSData *data = [self->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; + _gdk_macos_pasteboard_read_async (G_OBJECT (clipboard), + GDK_MACOS_CLIPBOARD (clipboard)->pasteboard, + formats, + io_priority, + cancellable, + callback, + user_data); } static GInputStream * @@ -352,15 +238,7 @@ _gdk_macos_clipboard_read_finish (GdkClipboard *clipboard, const char **out_mime_type, GError **error) { - GTask *task = (GTask *)result; - - g_assert (GDK_IS_MACOS_CLIPBOARD (clipboard)); - 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); + return _gdk_macos_pasteboard_read_finish (G_OBJECT (clipboard), result, out_mime_type, error); } static void @@ -622,4 +500,170 @@ on_data_ready_cb (GObject *object, 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 630daceae0..c25ff3b0c1 100644 --- a/gdk/macos/gdkmacosdisplay-private.h +++ b/gdk/macos/gdkmacosdisplay-private.h @@ -81,6 +81,10 @@ struct _GdkMacosDisplay /* The surface that is receiving keyboard events */ GdkMacosSurface *keyboard_surface; + /* [NSDraggingInfo draggingSequenceNumber] to GdkMacosDr(ag,op) */ + GHashTable *active_drags; + GHashTable *active_drops; + /* Used to translate from quartz coordinate space to GDK */ int width; int height; @@ -160,6 +164,16 @@ void _gdk_macos_display_warp_pointer (GdkMacosDisp int x, int y); NSEvent *_gdk_macos_display_get_nsevent (GdkEvent *event); +GdkDrag *_gdk_macos_display_find_drag (GdkMacosDisplay *self, + NSInteger sequence_number); +GdkDrop *_gdk_macos_display_find_drop (GdkMacosDisplay *self, + NSInteger sequence_number); +void _gdk_macos_display_set_drag (GdkMacosDisplay *self, + NSInteger sequence_number, + GdkDrag *drag); +void _gdk_macos_display_set_drop (GdkMacosDisplay *self, + NSInteger sequence_number, + GdkDrop *drop); G_END_DECLS diff --git a/gdk/macos/gdkmacosdisplay-translate.c b/gdk/macos/gdkmacosdisplay-translate.c index 2a825879a5..d64dd79e5b 100644 --- a/gdk/macos/gdkmacosdisplay-translate.c +++ b/gdk/macos/gdkmacosdisplay-translate.c @@ -788,6 +788,9 @@ get_surface_from_ns_event (GdkMacosDisplay *self, NSRect view_frame; view = (GdkMacosBaseView *)[nswindow contentView]; + if (!GDK_IS_MACOS_BASE_VIEW (view)) + goto find_under_pointer; + surface = GDK_SURFACE ([view gdkSurface]); point = [nsevent locationInWindow]; @@ -846,6 +849,8 @@ get_surface_from_ns_event (GdkMacosDisplay *self, } } +find_under_pointer: + if (!surface) { /* Fallback used when no NSSurface set. This happens e.g. when @@ -864,17 +869,24 @@ get_surface_from_ns_event (GdkMacosDisplay *self, static GdkMacosSurface * find_surface_for_keyboard_event (NSEvent *nsevent) { - GdkMacosBaseView *view = (GdkMacosBaseView *)[[nsevent window] contentView]; - GdkSurface *surface = GDK_SURFACE ([view gdkSurface]); - GdkDisplay *display = gdk_surface_get_display (surface); - GdkSeat *seat = gdk_display_get_default_seat (display); - GdkDevice *device = gdk_seat_get_keyboard (seat); - GdkDeviceGrabInfo *grab = _gdk_display_get_last_device_grab (display, device); + NSView *nsview = [[nsevent window] contentView]; - if (grab && grab->surface && !grab->owner_events) - return GDK_MACOS_SURFACE (grab->surface); + if (GDK_IS_MACOS_BASE_VIEW (nsview)) + { + GdkMacosBaseView *view = (GdkMacosBaseView *)nsview; + GdkSurface *surface = GDK_SURFACE ([view gdkSurface]); + GdkDisplay *display = gdk_surface_get_display (surface); + GdkSeat *seat = gdk_display_get_default_seat (display); + GdkDevice *device = gdk_seat_get_keyboard (seat); + GdkDeviceGrabInfo *grab = _gdk_display_get_last_device_grab (display, device); - return GDK_MACOS_SURFACE (surface); + if (grab && grab->surface && !grab->owner_events) + return GDK_MACOS_SURFACE (grab->surface); + + return GDK_MACOS_SURFACE (surface); + } + + return NULL; } static GdkMacosSurface * @@ -1090,7 +1102,8 @@ _gdk_macos_display_translate (GdkMacosDisplay *self, if (!(surface = find_surface_for_ns_event (self, nsevent, &x, &y))) return NULL; - if (!(window = (GdkMacosWindow *)_gdk_macos_surface_get_native (surface))) + if (!(window = (GdkMacosWindow *)_gdk_macos_surface_get_native (surface)) || + !GDK_IS_MACOS_WINDOW (window)) return NULL; /* Ignore events and break grabs while the window is being diff --git a/gdk/macos/gdkmacosdisplay.c b/gdk/macos/gdkmacosdisplay.c index ed15a49bf2..20041ac076 100644 --- a/gdk/macos/gdkmacosdisplay.c +++ b/gdk/macos/gdkmacosdisplay.c @@ -31,6 +31,8 @@ #include "gdkmacoscairocontext-private.h" #include "gdkmacoseventsource-private.h" #include "gdkmacosdisplay-private.h" +#include "gdkmacosdrag-private.h" +#include "gdkmacosdrop-private.h" #include "gdkmacosglcontext-private.h" #include "gdkmacoskeymap-private.h" #include "gdkmacosmonitor-private.h" @@ -663,6 +665,8 @@ gdk_macos_display_finalize (GObject *object) CFSTR ("NSUserDefaultsDidChangeNotification"), NULL); + g_clear_pointer (&self->active_drags, g_hash_table_unref); + g_clear_pointer (&self->active_drops, g_hash_table_unref); g_clear_object (&GDK_DISPLAY (self)->clipboard); g_clear_pointer (&self->frame_source, g_source_unref); g_clear_object (&self->monitors); @@ -701,6 +705,8 @@ static void gdk_macos_display_init (GdkMacosDisplay *self) { self->monitors = g_list_store_new (GDK_TYPE_MONITOR); + self->active_drags = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref); + self->active_drops = g_hash_table_new_full (NULL, NULL, NULL, g_object_unref); gdk_display_set_composited (GDK_DISPLAY (self), TRUE); gdk_display_set_input_shapes (GDK_DISPLAY (self), FALSE); @@ -1113,3 +1119,55 @@ _gdk_macos_display_get_nsevent (GdkEvent *event) return NULL; } + +GdkDrag * +_gdk_macos_display_find_drag (GdkMacosDisplay *self, + NSInteger sequence_number) +{ + g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL); + + return g_hash_table_lookup (self->active_drags, GSIZE_TO_POINTER (sequence_number)); +} + +void +_gdk_macos_display_set_drag (GdkMacosDisplay *self, + NSInteger sequence_number, + GdkDrag *drag) +{ + g_return_if_fail (GDK_IS_MACOS_DISPLAY (self)); + g_return_if_fail (!drag || GDK_IS_MACOS_DRAG (drag)); + + if (drag) + g_hash_table_insert (self->active_drags, + GSIZE_TO_POINTER (sequence_number), + g_object_ref (drag)); + else + g_hash_table_remove (self->active_drags, + GSIZE_TO_POINTER (sequence_number)); +} + +GdkDrop * +_gdk_macos_display_find_drop (GdkMacosDisplay *self, + NSInteger sequence_number) +{ + g_return_val_if_fail (GDK_IS_MACOS_DISPLAY (self), NULL); + + return g_hash_table_lookup (self->active_drops, GSIZE_TO_POINTER (sequence_number)); +} + +void +_gdk_macos_display_set_drop (GdkMacosDisplay *self, + NSInteger sequence_number, + GdkDrop *drop) +{ + g_return_if_fail (GDK_IS_MACOS_DISPLAY (self)); + g_return_if_fail (!drop || GDK_IS_MACOS_DROP (drop)); + + if (drop) + g_hash_table_insert (self->active_drops, + GSIZE_TO_POINTER (sequence_number), + g_object_ref (drop)); + else + g_hash_table_remove (self->active_drops, + GSIZE_TO_POINTER (sequence_number)); +} diff --git a/gdk/macos/gdkmacosdrag.c b/gdk/macos/gdkmacosdrag.c index c89b01948f..ee4b5e7020 100644 --- a/gdk/macos/gdkmacosdrag.c +++ b/gdk/macos/gdkmacosdrag.c @@ -326,12 +326,10 @@ gdk_drag_update (GdkDrag *drag, &suggested_action, &possible_actions); - _gdk_macos_drag_surface_drag_motion (self->drag_surface, - x_root - self->hot_x, - y_root - self->hot_y, - suggested_action, - possible_actions, - evtime); + 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) { @@ -339,6 +337,8 @@ gdk_drag_update (GdkDrag *drag, self->start_y = self->last_y; self->did_update = TRUE; } + + gdk_drag_set_actions (drag, possible_actions); } static gboolean diff --git a/gdk/macos/gdkmacosdragsurface-private.h b/gdk/macos/gdkmacosdragsurface-private.h index cf7408f308..bc84e3d30f 100644 --- a/gdk/macos/gdkmacosdragsurface-private.h +++ b/gdk/macos/gdkmacosdragsurface-private.h @@ -31,19 +31,13 @@ typedef struct _GdkMacosDragSurfaceClass GdkMacosDragSurfaceClass; #define GDK_MACOS_DRAG_SURFACE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DRAG_SURFACE, GdkMacosDragSurface)) #define GDK_IS_MACOS_DRAG_SURFACE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DRAG_SURFACE)) -GType _gdk_macos_drag_surface_get_type (void); -GdkMacosSurface *_gdk_macos_drag_surface_new (GdkMacosDisplay *display, - GdkFrameClock *frame_clock, - int x, - int y, - int width, - int height); -void _gdk_macos_drag_surface_drag_motion (GdkMacosDragSurface *self, - int x_root, - int y_root, - GdkDragAction suggested_action, - GdkDragAction possible_actions, - guint32 evtime); +GType _gdk_macos_drag_surface_get_type (void); +GdkMacosSurface *_gdk_macos_drag_surface_new (GdkMacosDisplay *display, + GdkFrameClock *frame_clock, + int x, + int y, + int width, + int height); G_END_DECLS diff --git a/gdk/macos/gdkmacosdragsurface.c b/gdk/macos/gdkmacosdragsurface.c index 2b03583604..dd6d5e520e 100644 --- a/gdk/macos/gdkmacosdragsurface.c +++ b/gdk/macos/gdkmacosdragsurface.c @@ -123,16 +123,3 @@ _gdk_macos_drag_surface_new (GdkMacosDisplay *display, return g_steal_pointer (&self); } - -void -_gdk_macos_drag_surface_drag_motion (GdkMacosDragSurface *self, - int x_root, - int y_root, - GdkDragAction suggested_action, - GdkDragAction possible_actions, - guint32 evtime) -{ - g_return_if_fail (GDK_IS_MACOS_DRAG_SURFACE (self)); - - _gdk_macos_surface_move (GDK_MACOS_SURFACE (self), x_root, y_root); -} diff --git a/gdk/macos/gdkmacosdrop-private.h b/gdk/macos/gdkmacosdrop-private.h new file mode 100644 index 0000000000..8472e87c23 --- /dev/null +++ b/gdk/macos/gdkmacosdrop-private.h @@ -0,0 +1,66 @@ +/* + * 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_DROP_PRIVATE_H__ +#define __GDK_MACOS_DROP_PRIVATE_H__ + +#include + +#include "gdkdropprivate.h" + +#include "gdkmacossurface-private.h" + +G_BEGIN_DECLS + +#define GDK_TYPE_MACOS_DROP (gdk_macos_drop_get_type ()) +#define GDK_MACOS_DROP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDK_TYPE_MACOS_DROP, GdkMacosDrop)) +#define GDK_MACOS_DROP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_MACOS_DROP, GdkMacosDropClass)) +#define GDK_IS_MACOS_DROP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDK_TYPE_MACOS_DROP)) +#define GDK_IS_MACOS_DROP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_MACOS_DROP)) +#define GDK_MACOS_DROP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_MACOS_DROP, GdkMacosDropClass)) + +typedef struct _GdkMacosDrop GdkMacosDrop; +typedef struct _GdkMacosDropClass GdkMacosDropClass; + +struct _GdkMacosDrop +{ + GdkDrop parent_instance; + + NSPasteboard *pasteboard; + + GdkDragAction all_actions; + GdkDragAction preferred_action; + GdkDragAction finish_action; +}; + +struct _GdkMacosDropClass +{ + GdkDropClass parent_class; +}; + +GType gdk_macos_drop_get_type (void) G_GNUC_CONST; +GdkMacosDrop *_gdk_macos_drop_new (GdkMacosSurface *surface, + id info); +NSDragOperation _gdk_macos_drop_operation (GdkMacosDrop *self); +void _gdk_macos_drop_update_actions (GdkMacosDrop *self, + id info); + +G_END_DECLS + +#endif /* __GDK_MACOS_DROP_PRIVATE_H__ */ diff --git a/gdk/macos/gdkmacosdrop.c b/gdk/macos/gdkmacosdrop.c new file mode 100644 index 0000000000..28c06f6220 --- /dev/null +++ b/gdk/macos/gdkmacosdrop.c @@ -0,0 +1,183 @@ +/* + * 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 "gdkmacosclipboard-private.h" +#include "gdkmacosdisplay-private.h" +#include "gdkmacosdrag-private.h" +#include "gdkmacosdrop-private.h" + +G_DEFINE_TYPE (GdkMacosDrop, gdk_macos_drop, GDK_TYPE_DROP) + +static void +gdk_macos_drop_status (GdkDrop *drop, + GdkDragAction actions, + GdkDragAction preferred) +{ + GdkMacosDrop *self = (GdkMacosDrop *)drop; + + g_assert (GDK_IS_MACOS_DROP (self)); + + self->all_actions = actions; + self->preferred_action = preferred; +} + +static void +gdk_macos_drop_read_async (GdkDrop *drop, + GdkContentFormats *content_formats, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + _gdk_macos_pasteboard_read_async (G_OBJECT (drop), + GDK_MACOS_DROP (drop)->pasteboard, + content_formats, + io_priority, + cancellable, + callback, + user_data); +} + +static GInputStream * +gdk_macos_drop_read_finish (GdkDrop *drop, + GAsyncResult *result, + const char **out_mime_type, + GError **error) +{ + return _gdk_macos_pasteboard_read_finish (G_OBJECT (drop), result, out_mime_type, error); +} + +static void +gdk_macos_drop_finish (GdkDrop *drop, + GdkDragAction action) +{ + g_assert (GDK_IS_MACOS_DROP (drop)); + + GDK_MACOS_DROP (drop)->finish_action = action; +} + +static void +gdk_macos_drop_finalize (GObject *object) +{ + GdkMacosDrop *self = (GdkMacosDrop *)object; + + if (self->pasteboard) + { + [self->pasteboard release]; + self->pasteboard = NULL; + } + + G_OBJECT_CLASS (gdk_macos_drop_parent_class)->finalize (object); +} + +static void +gdk_macos_drop_class_init (GdkMacosDropClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GdkDropClass *drop_class = GDK_DROP_CLASS (klass); + + object_class->finalize = gdk_macos_drop_finalize; + + drop_class->status = gdk_macos_drop_status; + drop_class->read_async = gdk_macos_drop_read_async; + drop_class->read_finish = gdk_macos_drop_read_finish; + drop_class->finish = gdk_macos_drop_finish; +} + +static void +gdk_macos_drop_init (GdkMacosDrop *self) +{ +} + +void +_gdk_macos_drop_update_actions (GdkMacosDrop *self, + id info) +{ + NSDragOperation op; + GdkDragAction actions = 0; + + g_assert (GDK_IS_MACOS_DROP (self)); + + op = [info draggingSourceOperationMask]; + + if (op & NSDragOperationCopy) + actions |= GDK_ACTION_COPY; + + if (op & NSDragOperationLink) + actions |= GDK_ACTION_LINK; + + if (op & NSDragOperationMove) + actions |= GDK_ACTION_MOVE; + + gdk_drop_set_actions (GDK_DROP (self), actions); +} + +GdkMacosDrop * +_gdk_macos_drop_new (GdkMacosSurface *surface, + id info) +{ + GdkDrag *drag = NULL; + GdkContentFormats *content_formats; + GdkMacosDrop *self; + GdkDisplay *display; + GdkDevice *device; + GdkSeat *seat; + + g_return_val_if_fail (GDK_IS_MACOS_SURFACE (surface), NULL); + g_return_val_if_fail (info != NULL, NULL); + + display = gdk_surface_get_display (GDK_SURFACE (surface)); + seat = gdk_display_get_default_seat (display); + device = gdk_seat_get_pointer (seat); + drag = _gdk_macos_display_find_drag (GDK_MACOS_DISPLAY (display), [info draggingSequenceNumber]); + + content_formats = _gdk_macos_pasteboard_load_formats ([info draggingPasteboard]); + + self = g_object_new (GDK_TYPE_MACOS_DROP, + "device", device, + "drag", drag, + "formats", content_formats, + "surface", surface, + NULL); + + self->pasteboard = [[info draggingPasteboard] retain]; + + _gdk_macos_drop_update_actions (self, info); + + gdk_content_formats_unref (content_formats); + + return g_steal_pointer (&self); +} + +NSDragOperation +_gdk_macos_drop_operation (GdkMacosDrop *self) +{ + if (self->preferred_action & GDK_ACTION_LINK) + return NSDragOperationLink; + + if (self->preferred_action & GDK_ACTION_MOVE) + return NSDragOperationMove; + + if (self->preferred_action & GDK_ACTION_COPY) + return NSDragOperationCopy; + + return NSDragOperationNone; +} diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c index 5fe5bb38e7..9a1f73835b 100644 --- a/gdk/macos/gdkmacossurface.c +++ b/gdk/macos/gdkmacossurface.c @@ -332,7 +332,7 @@ gdk_macos_surface_drag_begin (GdkSurface *surface, drag_surface = _gdk_macos_surface_new (GDK_MACOS_DISPLAY (surface->display), GDK_SURFACE_TEMP, surface, - -99, -99, 1, 1); + sx, sy, 1, 1); drag = g_object_new (GDK_TYPE_MACOS_DRAG, "drag-surface", drag_surface, "surface", surface, diff --git a/gdk/macos/meson.build b/gdk/macos/meson.build index 943fb84457..3a10dbf944 100644 --- a/gdk/macos/meson.build +++ b/gdk/macos/meson.build @@ -10,6 +10,7 @@ gdk_macos_sources = files([ 'gdkmacosdisplay-settings.c', 'gdkmacosdisplay-translate.c', 'gdkmacosdrag.c', + 'gdkmacosdrop.c', 'gdkmacosdragsurface.c', 'gdkmacosglcontext.c', 'gdkmacoseventsource.c',