}
}
-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
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];
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);
}
DEFSYM (QXdndActionMove, "XdndActionMove");
DEFSYM (QXdndActionLink, "XdndActionLink");
DEFSYM (QXdndActionPrivate, "XdndActionPrivate");
+ DEFSYM (Qnow, "now");
defsubr (&Sns_disown_selection_internal);
defsubr (&Sns_get_selection);
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;
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
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,
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
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];
[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;
}