[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 2021835326 2/3: Implement `return-frame' for DND on NS
From: |
Po Lu |
Subject: |
master 2021835326 2/3: Implement `return-frame' for DND on NS |
Date: |
Tue, 31 May 2022 06:06:43 -0400 (EDT) |
branch: master
commit 20218353262dc38d82adb945a6a38d6e629c1417
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>
Implement `return-frame' for DND on NS
* src/nsselect.m (Fns_begin_drag): New argument `return-frame'.
(syms_of_nsselect): New defsym.
* src/nsterm.h (EmacsWindow): New fields.
* src/nsterm.m (ns_read_socket): Split parts off to
ns_read_socket_1.
(ns_read_socket_1): New function.
(ns_flush_display): Use that function instead.
([EmacsWindow beginDrag:forPasteboard:]): Update for
return-frame.
---
src/nsselect.m | 36 ++++++++++++++---
src/nsterm.h | 14 ++++++-
src/nsterm.m | 121 ++++++++++++++++++++++++++++++++++++++++++++-------------
3 files changed, 139 insertions(+), 32 deletions(-)
diff --git a/src/nsselect.m b/src/nsselect.m
index 1ff627e657..63cea365e2 100644
--- a/src/nsselect.m
+++ b/src/nsselect.m
@@ -662,7 +662,7 @@ ns_dnd_action_from_operation (NSDragOperation operation)
}
}
-DEFUN ("ns-begin-drag", Fns_begin_drag, Sns_begin_drag, 3, 3, 0,
+DEFUN ("ns-begin-drag", Fns_begin_drag, Sns_begin_drag, 3, 4, 0,
doc: /* Begin a drag-and-drop operation on FRAME.
FRAME must be a window system frame. PBOARD is an alist of (TYPE
@@ -680,13 +680,30 @@ data inside PBOARD.
Return the action that the drop target actually chose to perform, or
nil if no action was performed (either because there was no drop
-target, or the drop was rejected). */)
- (Lisp_Object frame, Lisp_Object pboard, Lisp_Object action)
+target, or the drop was rejected). If RETURN_FRAME is the symbol
+`now', also return any frame that mouse moves into during the
+drag-and-drop operation, whilst simultaneously cancelling it. Any
+other non-nil value means to do the same, but to wait for the mouse to
+leave FRAME first. */)
+ (Lisp_Object frame, Lisp_Object pboard, Lisp_Object action,
+ Lisp_Object return_frame)
{
- struct frame *f;
+ struct frame *f, *return_to;
NSPasteboard *pasteboard;
EmacsWindow *window;
NSDragOperation operation;
+ enum ns_return_frame_mode mode;
+ Lisp_Object val;
+
+ if (EQ (return_frame, Qnow))
+ mode = RETURN_FRAME_NOW;
+ else if (!NILP (return_frame))
+ mode = RETURN_FRAME_EVENTUALLY;
+ else
+ mode = RETURN_FRAME_NEVER;
+
+ if (NILP (pboard))
+ signal_error ("Empty pasteboard", pboard);
f = decode_window_system_frame (frame);
pasteboard = [NSPasteboard pasteboardWithName: NSPasteboardNameDrag];
@@ -696,7 +713,15 @@ target, or the drop was rejected). */)
ns_lisp_to_pasteboard (pboard, pasteboard);
operation = [window beginDrag: operation
- forPasteboard: pasteboard];
+ forPasteboard: pasteboard
+ withMode: mode
+ returnFrameTo: &return_to];
+
+ if (return_to)
+ {
+ XSETFRAME (val, return_to);
+ return val;
+ }
return ns_dnd_action_from_operation (operation);
}
@@ -714,6 +739,7 @@ syms_of_nsselect (void)
DEFSYM (QXdndActionMove, "XdndActionMove");
DEFSYM (QXdndActionLink, "XdndActionLink");
DEFSYM (QXdndActionPrivate, "XdndActionPrivate");
+ DEFSYM (Qnow, "now");
defsubr (&Sns_disown_selection_internal);
defsubr (&Sns_get_selection);
diff --git a/src/nsterm.h b/src/nsterm.h
index f74c457fe3..c39b66534f 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -408,6 +408,13 @@ typedef id instancetype;
@end
#endif
+enum ns_return_frame_mode
+ {
+ RETURN_FRAME_NEVER,
+ RETURN_FRAME_EVENTUALLY,
+ RETURN_FRAME_NOW,
+ };
+
/* EmacsWindow */
@interface EmacsWindow : NSWindow
{
@@ -415,6 +422,9 @@ typedef id instancetype;
NSEvent *last_drag_event;
NSDragOperation drag_op;
NSDragOperation selected_op;
+
+ struct frame *dnd_return_frame;
+ enum ns_return_frame_mode dnd_mode;
}
#ifdef NS_IMPL_GNUSTEP
@@ -432,7 +442,9 @@ typedef id instancetype;
- (void) setAppearance;
- (void) setLastDragEvent: (NSEvent *) event;
- (NSDragOperation) beginDrag: (NSDragOperation) op
- forPasteboard: (NSPasteboard *) pasteboard;
+ forPasteboard: (NSPasteboard *) pasteboard
+ withMode: (enum ns_return_frame_mode) mode
+ returnFrameTo: (struct frame **) frame_return;
@end
diff --git a/src/nsterm.m b/src/nsterm.m
index 0f1b597457..f4fde9bd12 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -4529,11 +4529,14 @@ check_native_fs ()
static int
-ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
+ns_read_socket_1 (struct terminal *terminal, struct input_event *hold_quit,
+ BOOL no_release)
/* --------------------------------------------------------------------------
External (hook): Post an event to ourself and keep reading events until
we read it back again. In effect process all events which were waiting.
From 21+ we have to manage the event buffer ourselves.
+
+ NO_RELEASE means not to touch the global autorelease pool.
--------------------------------------------------------------------------
*/
{
struct input_event ev;
@@ -4564,11 +4567,14 @@ ns_read_socket (struct terminal *terminal, struct
input_event *hold_quit)
ns_init_events (&ev);
q_event_ptr = hold_quit;
- /* We manage autorelease pools by allocate/reallocate each time around
- the loop; strict nesting is occasionally violated but seems not to
- matter... earlier methods using full nesting caused major memory
leaks. */
- [outerpool release];
- outerpool = [[NSAutoreleasePool alloc] init];
+ if (!no_release)
+ {
+ /* We manage autorelease pools by allocate/reallocate each time around
+ the loop; strict nesting is occasionally violated but seems not to
+ matter... earlier methods using full nesting caused major memory
leaks. */
+ [outerpool release];
+ outerpool = [[NSAutoreleasePool alloc] init];
+ }
/* If have pending open-file requests, attend to the next one of those.
*/
if (ns_pending_files && [ns_pending_files count] != 0
@@ -4607,6 +4613,12 @@ ns_read_socket (struct terminal *terminal, struct
input_event *hold_quit)
return nevents;
}
+static int
+ns_read_socket (struct terminal *terminal, struct input_event *hold_quit)
+{
+ return ns_read_socket_1 (terminal, hold_quit, NO);
+}
+
static int
ns_select_1 (int nfds, fd_set *readfds, fd_set *writefds,
@@ -5191,19 +5203,10 @@ ns_update_window_end (struct window *w, bool
cursor_on_p,
static void
ns_flush_display (struct frame *f)
{
- NSAutoreleasePool *ap;
-
- ap = [[NSAutoreleasePool alloc] init];
-
- /* Called from some of the minibuffer code. Run the event loop once
- to make the toolkit make changes that were made to the back
- buffer visible again. */
-
- send_appdefined = YES;
- ns_send_appdefined (-1);
+ struct input_event ie;
- [NSApp run];
- [ap release];
+ EVENT_INIT (ie);
+ ns_read_socket_1 (FRAME_TERMINAL (f), &ie, YES);
}
/* This and next define (many of the) public functions in this
@@ -9579,14 +9582,51 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
selected_op = operation;
}
+#ifdef NS_IMPL_COCOA
+- (void) draggedImage: (NSImage *) dragged_image
+ movedTo: (NSPoint) screen_point
+{
+ NSInteger window_number;
+ NSWindow *w;
+
+ if (dnd_mode == RETURN_FRAME_NEVER)
+ return;
+
+ window_number = [NSWindow windowNumberAtPoint: [NSEvent mouseLocation]
+ belowWindowWithWindowNumber: 0];
+ w = [NSApp windowWithWindowNumber: window_number];
+
+ if (!w || w != self)
+ dnd_mode = RETURN_FRAME_NOW;
+
+ if (dnd_mode != RETURN_FRAME_NOW
+ || ![[w delegate] isKindOfClass: [EmacsView class]])
+ return;
+
+ dnd_return_frame = ((EmacsView *) [w delegate])->emacsframe;
+
+ /* FIXME: there must be a better way to leave the event loop. */
+ [NSException raise: @""
+ format: @"Must return DND frame"];
+}
+#endif
+
- (NSDragOperation) beginDrag: (NSDragOperation) op
forPasteboard: (NSPasteboard *) pasteboard
+ withMode: (enum ns_return_frame_mode) mode
+ returnFrameTo: (struct frame **) frame_return
{
NSImage *image;
+#ifdef NS_IMPL_COCOA
+ NSInteger window_number;
+ NSWindow *w;
+#endif
drag_op = op;
selected_op = NSDragOperationNone;
image = [[NSImage alloc] initWithSize: NSMakeSize (1.0, 1.0)];
+ dnd_mode = mode;
+ dnd_return_frame = NULL;
/* Now draw transparency onto the image. */
[image lockFocus];
@@ -9596,18 +9636,47 @@ nswindow_orderedIndex_sort (id w1, id w2, void *c)
[image unlockFocus];
block_input ();
- if (last_drag_event)
- [self dragImage: image
- at: NSMakePoint (0, 0)
- offset: NSMakeSize (0, 0)
- event: last_drag_event
- pasteboard: pasteboard
- source: self
- slideBack: NO];
+#ifdef NS_IMPL_COCOA
+ if (mode == RETURN_FRAME_NOW)
+ {
+ window_number = [NSWindow windowNumberAtPoint: [NSEvent mouseLocation]
+ belowWindowWithWindowNumber: 0];
+ w = [NSApp windowWithWindowNumber: window_number];
+
+ if (w && [[w delegate] isKindOfClass: [EmacsView class]])
+ {
+ *frame_return = ((EmacsView *) [w delegate])->emacsframe;
+ [image release];
+ unblock_input ();
+
+ return NSDragOperationNone;
+ }
+ }
+
+ @try
+ {
+#endif
+ if (last_drag_event)
+ [self dragImage: image
+ at: NSMakePoint (0, 0)
+ offset: NSMakeSize (0, 0)
+ event: last_drag_event
+ pasteboard: pasteboard
+ source: self
+ slideBack: NO];
+#ifdef NS_IMPL_COCOA
+ }
+ @catch (NSException *e)
+ {
+ /* Ignore. This is probably the wrong way to leave the
+ drag-and-drop run loop. */
+ }
+#endif
unblock_input ();
[image release];
+ *frame_return = dnd_return_frame;
return selected_op;
}