emacs-diffs
[Top][All Lists]
Advanced

[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;
 }
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]