From: Arjan Molenaar Date: Mon, 9 Jan 2023 22:01:12 +0000 (+0100) Subject: macos: Support dragging from GdkMacosWindow X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~8^2~50^2~10 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=b9847795a7d060d3f2d97000c4a6d738d7fece97;p=gtk4.git 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. --- 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 { 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 *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;