summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArjan Molenaar <gaphor@gmail.com>2023-01-09 23:01:12 +0100
committerArjan Molenaar <gaphor@gmail.com>2023-01-15 10:01:56 +0100
commitb9847795a7d060d3f2d97000c4a6d738d7fece97 (patch)
tree2f07bb91abcd80cebad9b094383f9e8355b1abab
parent420be8fb0f008959d4d5a0be0c1e98cba5a54eb7 (diff)
downloadgtk+-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.c52
-rw-r--r--gdk/macos/GdkMacosWindow.h2
-rw-r--r--gdk/macos/gdkmacosdisplay-private.h1
-rw-r--r--gdk/macos/gdkmacosdisplay.c10
-rw-r--r--gdk/macos/gdkmacosdrag-private.h16
-rw-r--r--gdk/macos/gdkmacosdrag.c97
-rw-r--r--gdk/macos/gdkmacossurface.c2
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;