]> git.eshelyaron.com Git - emacs.git/commitdiff
Return the correct action from the Lisp side of drag-and-drop
authorPo Lu <luangruo@yahoo.com>
Sat, 2 Jul 2022 01:06:36 +0000 (09:06 +0800)
committerPo Lu <luangruo@yahoo.com>
Sat, 2 Jul 2022 01:06:36 +0000 (09:06 +0800)
* lisp/x-dnd.el (x-dnd-handle-drag-n-drop-event): Select
`window' when handling internal DND events.
(x-dnd-handle-unsupported-drop): Return an appropriate action.
* src/keyboard.c (kbd_buffer_get_event):
* src/termhooks.h (enum event_kind): Delete
`UNSUPPORTED_DROP_EVENT'.
* src/xterm.c (x_dnd_send_unsupported_drop): Set flags instead
of recording input event.
(x_clear_dnd_monitors): Rename to `x_clear_dnd_variables'.  Also
clear unsupported drop data.
(x_dnd_begin_drag_and_drop): Run unsupported drop function
inline (and safely), and use its return value if it returned a
symbol.
(syms_of_xterm): Update doc string of
`x-dnd-unsupported-drop-function'.

* src/xterm.h: Update declarations.

lisp/x-dnd.el
src/keyboard.c
src/termhooks.h
src/xterm.c
src/xterm.h

index d78f926ee7adbc43eea5010ece857bedad3fa76f..8a7f3e24363afcec9400030909f7dc333243bd9c 100644 (file)
@@ -422,6 +422,8 @@ Currently XDND, Motif and old KDE 1.x protocols are recognized."
                                     x-dnd-xdnd-to-action)))
                 (targets (cddr client-message))
                 (local-value (nth 2 client-message)))
+            (when (windowp window)
+              (select-window window))
             (x-dnd-save-state window nil nil
                               (apply #'vector targets))
             (x-dnd-maybe-call-test-function window action)
@@ -1154,19 +1156,25 @@ X and Y are the root window coordinates of the drop.
 FRAME is the frame the drop originated on.
 WINDOW-ID is the X window the drop should happen to.
 LOCAL-SELECTION-DATA is the local selection data of the drop."
-  (not (and (or (eq action 'XdndActionCopy)
-                (eq action 'XdndActionMove))
-            (not (and x-dnd-use-offix-drop local-selection-data
-                      (or (not (eq x-dnd-use-offix-drop 'files))
-                          (member "FILE_NAME" targets))
-                      (x-dnd-do-offix-drop targets x
-                                           y frame window-id
-                                           local-selection-data)))
-            (or
-             (member "STRING" targets)
-             (member "UTF8_STRING" targets)
-             (member "COMPOUND_TEXT" targets)
-             (member "TEXT" targets)))))
+  (let ((chosen-action nil))
+    (not (and (or (eq action 'XdndActionCopy)
+                  (eq action 'XdndActionMove))
+              (not (and x-dnd-use-offix-drop local-selection-data
+                        (or (not (eq x-dnd-use-offix-drop 'files))
+                            (member "FILE_NAME" targets))
+                        (when (x-dnd-do-offix-drop targets x
+                                                   y frame window-id
+                                                   local-selection-data)
+                          (setq chosen-action 'XdndActionCopy))))
+              (let ((delegate-p (or (member "STRING" targets)
+                                    (member "UTF8_STRING" targets)
+                                    (member "COMPOUND_TEXT" targets)
+                                    (member "TEXT" targets))))
+                (prog1 delegate-p
+                  ;; A string will avoid the drop emulation done in C
+                  ;; code, but won't be returned from `x-begin-drag'.
+                  (setq chosen-action (unless delegate-p ""))))))
+    chosen-action))
 
 (defvar x-dnd-targets-list)
 (defvar x-dnd-native-test-function)
index 4cac20eb4b7f5c94710d8a180470f077c57b887c..bed8307b6f23ce53301ece2a423e2e6747c9cfe7 100644 (file)
@@ -4036,56 +4036,6 @@ kbd_buffer_get_event (KBOARD **kbp,
        }
         break;
 
-#ifdef HAVE_X_WINDOWS
-      case UNSUPPORTED_DROP_EVENT:
-       {
-         struct frame *f;
-
-         kbd_fetch_ptr = next_kbd_event (event);
-         input_pending = readable_events (0);
-
-         /* This means this event was already handled in
-            `x_dnd_begin_drag_and_drop'.  */
-         if (event->ie.modifiers < x_dnd_unsupported_event_level)
-           break;
-
-         f = XFRAME (event->ie.frame_or_window);
-
-         if (!FRAME_LIVE_P (f))
-           break;
-
-         if (!NILP (Vx_dnd_unsupported_drop_function))
-           {
-             if (!NILP (call8 (Vx_dnd_unsupported_drop_function,
-                               XCAR (XCDR (event->ie.arg)), event->ie.x,
-                               event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
-                               make_uint (event->ie.code),
-                               event->ie.frame_or_window,
-                               make_int (event->ie.timestamp),
-                               Fcopy_sequence (XCAR (event->ie.arg)))))
-               break;
-           }
-
-         /* `x-dnd-unsupported-drop-function' could have deleted the
-            event frame.  */
-         if (!FRAME_LIVE_P (f)
-             /* This means `x-dnd-use-unsupported-drop' was nil when the
-                event was generated.  */
-             || NILP (XCAR (XCDR (XCDR (XCDR (event->ie.arg))))))
-           break;
-
-         x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (f),
-                                    event->ie.frame_or_window,
-                                    XCAR (event->ie.arg),
-                                    XCAR (XCDR (event->ie.arg)),
-                                    (Window) event->ie.code,
-                                    XFIXNUM (event->ie.x),
-                                    XFIXNUM (event->ie.y),
-                                    event->ie.timestamp);
-         break;
-       }
-#endif
-
       case MONITORS_CHANGED_EVENT:
        {
          kbd_fetch_ptr = next_kbd_event (event);
index a1e3e2cde9ad06208fc0f4858778cfeffd617a98..c5f1e286e927ff6121e9755f5fe94726ff887a52 100644 (file)
@@ -209,30 +209,6 @@ enum event_kind
                                   representation of the dropped items.
                                   .timestamp gives a timestamp (in
                                   milliseconds) for the click.  */
-#ifdef HAVE_X_WINDOWS
-  UNSUPPORTED_DROP_EVENT,      /* Event sent when the regular C
-                                 drag-and-drop machinery could not
-                                 handle a drop to a window.
-
-                                 .code is the XID of the window that
-                                 could not be dropped to.
-
-                                 .arg is a list of the local value of
-                                 XdndSelection, a list of selection
-                                 targets, and the intended action to
-                                 be taken upon drop, and .timestamp
-                                 gives the timestamp where the drop
-                                 happened.
-
-                                 .modifiers gives a number that
-                                 determines if an event was already
-                                 handled by
-                                 `x_dnd_begin_drag_and_drop'.
-
-                                 .x and .y give the coordinates of
-                                 the drop originating from the root
-                                 window.  */
-#endif
   USER_SIGNAL_EVENT,           /* A user signal.
                                    code is a number identifying it,
                                    index into lispy_user_signals.  */
index c83ddc6b9ea3222743149082cbc3bd4b5e80d480..061bca0684b565b763848243692ed34c80661925 100644 (file)
@@ -1128,10 +1128,6 @@ static Window x_get_window_below (Display *, Window, int, int, int *, int *);
 /* Flag that indicates if a drag-and-drop operation is in progress.  */
 bool x_dnd_in_progress;
 
-/* Number that indicates the last "generation" of
-   UNSUPPORTED_DROP_EVENTs handled.  */
-unsigned x_dnd_unsupported_event_level;
-
 /* The frame where the drag-and-drop operation originated.  */
 struct frame *x_dnd_frame;
 
@@ -1146,6 +1142,20 @@ struct frame *x_dnd_finish_frame;
    important information.  */
 bool x_dnd_waiting_for_finish;
 
+/* Flag that means (when set in addition to
+   `x_dnd_waiting_for_finish') to run the unsupported drop function
+   with the given arguments.  */
+static bool x_dnd_run_unsupported_drop_function;
+
+/* The "before"-time of the unsupported drop.  */
+static Time x_dnd_unsupported_drop_time;
+
+/* The target window of the unsupported drop.  */
+static Window x_dnd_unsupported_drop_window;
+
+/* The Lisp data associated with the unsupported drop function.  */
+static Lisp_Object x_dnd_unsupported_drop_data;
+
 /* Whether or not to move the tooltip along with the mouse pointer
    during drag-and-drop.  */
 static bool x_dnd_update_tooltip;
@@ -3881,12 +3891,10 @@ static void
 x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_window,
                             int root_x, int root_y, Time before)
 {
-  struct input_event ie;
   Lisp_Object targets, arg;
   int i;
   char **atom_names, *name;
 
-  EVENT_INIT (ie);
   targets = Qnil;
   atom_names = alloca (sizeof *atom_names * x_dnd_n_targets);
 
@@ -3894,8 +3902,6 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
                      x_dnd_n_targets, atom_names))
       return;
 
-  x_dnd_action = dpyinfo->Xatom_XdndActionPrivate;
-
   for (i = x_dnd_n_targets; i > 0; --i)
     {
       targets = Fcons (build_string (atom_names[i - 1]),
@@ -3914,20 +3920,17 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
   else
     arg = Qnil;
 
-  ie.kind = UNSUPPORTED_DROP_EVENT;
-  ie.code = (unsigned) target_window;
-  ie.modifiers = x_dnd_unsupported_event_level;
-  ie.arg = list4 (assq_no_quit (QXdndSelection,
-                               dpyinfo->terminal->Vselection_alist),
-                 targets, arg, (x_dnd_use_unsupported_drop
-                                ? Qt : Qnil));
-  ie.timestamp = before;
-
-  XSETINT (ie.x, root_x);
-  XSETINT (ie.y, root_y);
-  XSETFRAME (ie.frame_or_window, x_dnd_frame);
+  x_dnd_run_unsupported_drop_function = true;
+  x_dnd_unsupported_drop_time = before;
+  x_dnd_unsupported_drop_window = target_window;
+  x_dnd_unsupported_drop_data
+    = listn (5, assq_no_quit (QXdndSelection,
+                             dpyinfo->terminal->Vselection_alist),
+            targets, arg, make_fixnum (root_x),
+            make_fixnum (root_y));
 
-  kbd_buffer_store_event (&ie);
+  x_dnd_waiting_for_finish = true;
+  x_dnd_finish_display = dpyinfo->display;
 }
 
 static Window
@@ -4529,10 +4532,14 @@ x_free_dnd_targets (void)
   x_dnd_n_targets = 0;
 }
 
+/* Clear some Lisp variables after the drop finishes, so they are
+   freed by the GC.  */
+
 static void
-x_clear_dnd_monitors (void)
+x_clear_dnd_variables (void)
 {
   x_dnd_monitors = Qnil;
+  x_dnd_unsupported_drop_data = Qnil;
 }
 
 static void
@@ -11311,7 +11318,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
   XWindowAttributes root_window_attrs;
   struct input_event hold_quit;
   char *atom_name, *ask_actions;
-  Lisp_Object action, ltimestamp;
+  Lisp_Object action, ltimestamp, val;
   specpdl_ref ref, count, base;
   ptrdiff_t i, end, fill;
   XTextProperty prop;
@@ -11324,9 +11331,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
 #ifndef USE_GTK
   struct x_display_info *event_display;
 #endif
-  union buffered_input_event *events, *event;
-  int n_events;
-  struct frame *event_frame;
 
   base = SPECPDL_INDEX ();
 
@@ -11334,70 +11338,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
      Fx_begin_drag.  */
   specbind (Qx_dnd_targets_list, selection_target_list);
 
-  /* Before starting drag-and-drop, walk through the keyboard buffer
-     to see if there are any UNSUPPORTED_DROP_EVENTs, and run them now
-     if they exist, to prevent race conditions from happening due to
-     multiple unsupported drops running at once.  */
-
-  block_input ();
-  events = alloca (sizeof *events * KBD_BUFFER_SIZE);
-  n_events = 0;
-  event = kbd_fetch_ptr;
-
-  while (event != kbd_store_ptr)
-    {
-      if (event->ie.kind == UNSUPPORTED_DROP_EVENT
-         && event->ie.modifiers < x_dnd_unsupported_event_level)
-       events[n_events++] = *event;
-
-      event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
-              ? kbd_buffer : event + 1);
-    }
-
-  x_dnd_unsupported_event_level += 1;
-  unblock_input ();
-
-  for (i = 0; i < n_events; ++i)
-    {
-      maybe_quit ();
-
-      event = &events[i];
-      event_frame = XFRAME (event->ie.frame_or_window);
-
-      if (!FRAME_LIVE_P (event_frame))
-       continue;
-
-      if (!NILP (Vx_dnd_unsupported_drop_function))
-       {
-         if (!NILP (call8 (Vx_dnd_unsupported_drop_function,
-                           XCAR (XCDR (event->ie.arg)), event->ie.x,
-                           event->ie.y, XCAR (XCDR (XCDR (event->ie.arg))),
-                           make_uint (event->ie.code),
-                           event->ie.frame_or_window,
-                           make_int (event->ie.timestamp),
-                           Fcopy_sequence (XCAR (event->ie.arg)))))
-           continue;
-       }
-
-      /* `x-dnd-unsupported-drop-function' could have deleted the
-        event frame.  */
-      if (!FRAME_LIVE_P (event_frame)
-         /* This means `x-dnd-use-unsupported-drop' was nil when the
-            event was generated.  */
-         || NILP (XCAR (XCDR (XCDR (XCDR (event->ie.arg))))))
-       continue;
-
-      x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (event_frame),
-                                event->ie.frame_or_window,
-                                XCAR (event->ie.arg),
-                                XCAR (XCDR (event->ie.arg)),
-                                (Window) event->ie.code,
-                                XFIXNUM (event->ie.x),
-                                XFIXNUM (event->ie.y),
-                                event->ie.timestamp);
-      break;
-    }
-
   if (!FRAME_VISIBLE_P (f))
     error ("Frame must be visible");
 
@@ -11500,6 +11440,8 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
       unbind_to (count, Qnil);
     }
 
+  record_unwind_protect_void (x_clear_dnd_variables);
+
   if (follow_tooltip)
     {
 #if defined HAVE_XRANDR || defined USE_GTK
@@ -11510,8 +11452,6 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
 #endif
        x_dnd_monitors
          = Fx_display_monitor_attributes_list (frame);
-
-      record_unwind_protect_void (x_clear_dnd_monitors);
     }
 
   x_dnd_update_tooltip = follow_tooltip;
@@ -11558,6 +11498,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
   x_dnd_xm_use_help = false;
   x_dnd_motif_setup_p = false;
   x_dnd_end_window = None;
+  x_dnd_run_unsupported_drop_function = false;
   x_dnd_use_toplevels
     = x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_client_list_stacking);
   x_dnd_toplevels = NULL;
@@ -11812,6 +11753,50 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
              unbind_to (ref, Qnil);
            }
 
+         if (x_dnd_run_unsupported_drop_function
+             && x_dnd_waiting_for_finish)
+           {
+             x_dnd_run_unsupported_drop_function = false;
+             x_dnd_waiting_for_finish = false;
+             x_dnd_unwind_flag = true;
+
+             ref = SPECPDL_INDEX ();
+             record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
+
+             if (!NILP (Vx_dnd_unsupported_drop_function))
+               val = call8 (Vx_dnd_unsupported_drop_function,
+                            XCAR (XCDR (x_dnd_unsupported_drop_data)),
+                            Fnth (make_fixnum (3), x_dnd_unsupported_drop_data),
+                            Fnth (make_fixnum (4), x_dnd_unsupported_drop_data),
+                            Fnth (make_fixnum (2), x_dnd_unsupported_drop_data),
+                            make_uint (x_dnd_unsupported_drop_window),
+                            frame, make_uint (x_dnd_unsupported_drop_time),
+                            Fcopy_sequence (XCAR (x_dnd_unsupported_drop_data)));
+             else
+               val = Qnil;
+
+             if (NILP (val))
+               x_dnd_do_unsupported_drop (FRAME_DISPLAY_INFO (f),
+                                          frame, XCAR (x_dnd_unsupported_drop_data),
+                                          XCAR (XCDR (x_dnd_unsupported_drop_data)),
+                                          x_dnd_unsupported_drop_window,
+                                          XFIXNUM (Fnth (make_fixnum (3),
+                                                         x_dnd_unsupported_drop_data)),
+                                          XFIXNUM (Fnth (make_fixnum (4),
+                                                         x_dnd_unsupported_drop_data)),
+                                          x_dnd_unsupported_drop_time);
+
+             if (SYMBOLP (val))
+               x_dnd_action_symbol = val;
+
+             x_dnd_unwind_flag = false;
+             unbind_to (ref, Qnil);
+
+             /* Break out of the loop now, since DND has
+                completed.  */
+             break;
+           }
+
 #ifdef USE_GTK
          if (xg_pending_quit_event.kind != NO_EVENT)
            {
@@ -27809,6 +27794,9 @@ syms_of_xterm (void)
   x_dnd_selection_alias_cell = Fcons (Qnil, Qnil);
   staticpro (&x_dnd_selection_alias_cell);
 
+  x_dnd_unsupported_drop_data = Qnil;
+  staticpro (&x_dnd_unsupported_drop_data);
+
   DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
   DEFSYM (Qlatin_1, "latin-1");
   DEFSYM (Qnow, "now");
@@ -28033,7 +28021,6 @@ mouse position list.  */);
 
   DEFVAR_LISP ("x-dnd-unsupported-drop-function", Vx_dnd_unsupported_drop_function,
     doc: /* Function called when trying to drop on an unsupported window.
-
 This function is called whenever the user tries to drop something on a
 window that does not support either the XDND or Motif protocols for
 drag-and-drop.  It should return a non-nil value if the drop was
@@ -28046,8 +28033,11 @@ where the drop happened, ACTION is the action that was passed to
 `x-begin-drag', FRAME is the frame which initiated the drag-and-drop
 operation, TIME is the X server time when the drop happened, and
 LOCAL-SELECTION is the contents of the `XdndSelection' when
-`x-begin-drag' was run, which can be passed to
-`x-get-local-selection'.  */);
+`x-begin-drag' was run; its contents can be retrieved by calling the
+function `x-get-local-selection'.
+
+If a symbol is returned, then it will be used as the return value of
+`x-begin-drag'.  */);
   Vx_dnd_unsupported_drop_function = Qnil;
 
   DEFVAR_INT ("x-color-cache-bucket-size", x_color_cache_bucket_size,
index 76d35aaf34f24ad85d8ea3c86d5321ada8378fbf..eee76724268152e34186045202864c36aa64f910 100644 (file)
@@ -1669,7 +1669,6 @@ extern bool x_dnd_in_progress;
 extern bool x_dnd_waiting_for_finish;
 extern struct frame *x_dnd_frame;
 extern struct frame *x_dnd_finish_frame;
-extern unsigned x_dnd_unsupported_event_level;
 extern int x_error_message_count;
 
 #ifdef HAVE_XINPUT2