diff options
author | Arjan Molenaar <gaphor@gmail.com> | 2023-01-09 23:01:12 +0100 |
---|---|---|
committer | Arjan Molenaar <gaphor@gmail.com> | 2023-01-15 10:01:56 +0100 |
commit | b9847795a7d060d3f2d97000c4a6d738d7fece97 (patch) | |
tree | 2f07bb91abcd80cebad9b094383f9e8355b1abab | |
parent | 420be8fb0f008959d4d5a0be0c1e98cba5a54eb7 (diff) | |
download | gtk+-b9847795a7d060d3f2d97000c4a6d738d7fece97.tar.gz |
macos: Support dragging from GdkMacosWindow
The handling is done similar to drag targets.
Note that dragging is a modal action on macos: no events
are sent to the main window. This could cause trouble when
we finish the drag, and not finish the gesture in GTK.
-rw-r--r-- | gdk/macos/GdkMacosWindow.c | 52 | ||||
-rw-r--r-- | gdk/macos/GdkMacosWindow.h | 2 | ||||
-rw-r--r-- | gdk/macos/gdkmacosdisplay-private.h | 1 | ||||
-rw-r--r-- | gdk/macos/gdkmacosdisplay.c | 10 | ||||
-rw-r--r-- | gdk/macos/gdkmacosdrag-private.h | 16 | ||||
-rw-r--r-- | gdk/macos/gdkmacosdrag.c | 97 | ||||
-rw-r--r-- | gdk/macos/gdkmacossurface.c | 2 |
7 files changed, 172 insertions, 8 deletions
diff --git a/gdk/macos/GdkMacosWindow.c b/gdk/macos/GdkMacosWindow.c index 7680e6d8b0..79e2ec8001 100644 --- a/gdk/macos/GdkMacosWindow.c +++ b/gdk/macos/GdkMacosWindow.c @@ -28,6 +28,7 @@ #import "GdkMacosWindow.h" #include "gdkmacosdisplay-private.h" +#include "gdkmacosdrag-private.h" #include "gdkmacosdrop-private.h" #include "gdkmacosmonitor-private.h" #include "gdkmacospasteboard-private.h" @@ -668,7 +669,56 @@ typedef NSString *CALayerContentsGravity; } // NSDraggingSource protocol -// ... + +- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context +{ + NSInteger sequence_number = [session draggingSequenceNumber]; + GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (gdk_surface)); + GdkDrag *drag = _gdk_macos_display_find_drag (GDK_MACOS_DISPLAY (display), sequence_number); + GdkModifierType state = _gdk_macos_display_get_current_keyboard_modifiers (GDK_MACOS_DISPLAY (display)); + + _gdk_macos_drag_set_actions (GDK_MACOS_DRAG (drag), state); + + return _gdk_macos_drag_operation (GDK_MACOS_DRAG (drag)); +} + +- (void)draggingSession:(NSDraggingSession *)session willBeginAtPoint:(NSPoint)screenPoint +{ + NSInteger sequence_number = [session draggingSequenceNumber]; + GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (gdk_surface)); + GdkDrag *drag = _gdk_macos_display_find_drag (GDK_MACOS_DISPLAY (display), sequence_number); + 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 (GDK_MACOS_DRAG (drag), x, y); + _gdk_macos_drag_surface_move (GDK_MACOS_DRAG (drag), x, y); +} + +- (void)draggingSession:(NSDraggingSession *)session movedToPoint:(NSPoint)screenPoint +{ + NSInteger sequence_number = [session draggingSequenceNumber]; + GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (gdk_surface)); + GdkDrag *drag = _gdk_macos_display_find_drag (GDK_MACOS_DISPLAY (display), sequence_number); + int x, y; + + _gdk_macos_display_from_display_coords (GDK_MACOS_DISPLAY (display), screenPoint.x, screenPoint.y, &x, &y); + _gdk_macos_drag_surface_move (GDK_MACOS_DRAG (drag), x, y); +} + +- (void)draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation +{ + NSInteger sequence_number = [session draggingSequenceNumber]; + GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (gdk_surface)); + GdkDrag *drag = _gdk_macos_display_find_drag (GDK_MACOS_DISPLAY (display), sequence_number); + + 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 -(void)setStyleMask:(NSWindowStyleMask)styleMask diff --git a/gdk/macos/GdkMacosWindow.h b/gdk/macos/GdkMacosWindow.h index 1cf9ec805c..66fcd45717 100644 --- a/gdk/macos/GdkMacosWindow.h +++ b/gdk/macos/GdkMacosWindow.h @@ -32,7 +32,7 @@ #define GDK_IS_MACOS_WINDOW(obj) ([obj isKindOfClass:[GdkMacosWindow class]]) -@interface GdkMacosWindow : NSWindow { +@interface GdkMacosWindow : NSWindow <NSDraggingSource, NSDraggingDestination> { GdkMacosSurface *gdk_surface; BOOL inMove; diff --git a/gdk/macos/gdkmacosdisplay-private.h b/gdk/macos/gdkmacosdisplay-private.h index 83ae435e49..122d004cec 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 0e5a9b8eb6..b9869fae7c 100644 --- a/gdk/macos/gdkmacosdisplay.c +++ b/gdk/macos/gdkmacosdisplay.c @@ -1024,6 +1024,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 98075f27ef..fbc525d247 100644 --- a/gdk/macos/gdkmacosdrag-private.h +++ b/gdk/macos/gdkmacosdrag-private.h @@ -62,8 +62,20 @@ 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 *content, + GdkMacosWindow *window); +NSDragOperation _gdk_macos_drag_operation (GdkMacosDrag *self); +void _gdk_macos_drag_surface_move (GdkMacosDrag *self, + int x_root, + int y_root); +void _gdk_macos_drag_set_start_position (GdkMacosDrag *self, + int start_x, + int start_y); +void _gdk_macos_drag_set_actions (GdkMacosDrag *self, + GdkModifierType mods); + G_END_DECLS diff --git a/gdk/macos/gdkmacosdrag.c b/gdk/macos/gdkmacosdrag.c index 10a756998d..50c1ac814d 100644 --- a/gdk/macos/gdkmacosdrag.c +++ b/gdk/macos/gdkmacosdrag.c @@ -25,6 +25,7 @@ #include "gdkmacoscursor-private.h" #include "gdkmacosdisplay-private.h" #include "gdkmacosdragsurface-private.h" +#include "gdkmacospasteboard-private.h" #include "gdk/gdkdeviceprivate.h" #include "gdk/gdkeventsprivate.h" @@ -624,11 +625,101 @@ gdk_macos_drag_init (GdkMacosDrag *self) } gboolean -_gdk_macos_drag_begin (GdkMacosDrag *self) +_gdk_macos_drag_begin (GdkMacosDrag *self, + GdkContentProvider *content, + GdkMacosWindow *window) { + NSArray<NSDraggingItem *> *items; + NSDraggingSession *session; + NSPasteboardItem *item; + NSEvent *nsevent; + g_return_val_if_fail (GDK_IS_MACOS_DRAG (self), FALSE); + g_return_val_if_fail (GDK_IS_MACOS_WINDOW (window), FALSE); + + GDK_BEGIN_MACOS_ALLOC_POOL; + + item = [[GdkMacosPasteboardItem alloc] initForDrag:GDK_DRAG (self) withContentProvider:content]; + items = [NSArray arrayWithObject:item]; + nsevent = _gdk_macos_display_get_last_nsevent (); + + session = [[window contentView] beginDraggingSessionWithItems:items + event:nsevent + source:window]; + + GDK_END_MACOS_ALLOC_POOL; + + _gdk_macos_display_set_drag (GDK_MACOS_DISPLAY (gdk_drag_get_display (GDK_DRAG (self))), + [session draggingSequenceNumber], + GDK_DRAG (self)); + + return TRUE; +} + +NSDragOperation +_gdk_macos_drag_operation (GdkMacosDrag *self) +{ + NSDragOperation operation = NSDragOperationNone; + GdkDragAction actions; - _gdk_macos_surface_show (GDK_MACOS_SURFACE (self->drag_surface)); + 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; +} + +void +_gdk_macos_drag_surface_move (GdkMacosDrag *self, + int x_root, + int y_root) +{ + g_return_if_fail (GDK_IS_MACOS_DRAG (self)); + + self->last_x = x_root; + self->last_y = y_root; + + 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 (GdkMacosDrag *self, + int start_x, + int start_y) +{ + g_return_if_fail (GDK_IS_MACOS_DRAG (self)); + + self->start_x = start_x; + self->start_y = start_y; +} + +void +_gdk_macos_drag_set_actions (GdkMacosDrag *self, + GdkModifierType mods) +{ + 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 (GDK_DRAG (self)), + &suggested_action, + &possible_actions); - return drag_grab (self); + gdk_drag_set_selected_action (GDK_DRAG (self), suggested_action); + gdk_drag_set_actions (GDK_DRAG (self), possible_actions); } diff --git a/gdk/macos/gdkmacossurface.c b/gdk/macos/gdkmacossurface.c index 37400d1892..a002dc7db3 100644 --- a/gdk/macos/gdkmacossurface.c +++ b/gdk/macos/gdkmacossurface.c @@ -446,7 +446,7 @@ gdk_macos_surface_drag_begin (GdkSurface *surface, gdk_drag_get_selected_action (GDK_DRAG (drag))); gdk_drag_set_cursor (GDK_DRAG (drag), cursor); - if (!_gdk_macos_drag_begin (drag)) + if (!_gdk_macos_drag_begin (drag, content, self->window)) { g_object_unref (drag); return NULL; |