]> git.eshelyaron.com Git - emacs.git/commitdiff
Move some X11 drag and drop processing to Lisp
authorPo Lu <luangruo@yahoo.com>
Wed, 6 Apr 2022 12:29:30 +0000 (20:29 +0800)
committerPo Lu <luangruo@yahoo.com>
Wed, 6 Apr 2022 12:30:24 +0000 (20:30 +0800)
* lisp/term/x-win.el: Set unsupported drop function.
* lisp/x-dnd.el (x-dnd-handle-unsupported-drop): New function.
* src/keyboard.c (kbd_buffer_get_event): Handle
UNSUPPORTED_DROP_EVENT.
* src/termhooks.h (enum event_kind): New event
`UNSUPPORTED_DROP_EVENT'.
* src/xterm.c (x_dnd_send_unsupported_drop): Send those events
instead.
(x_dnd_do_unsupported_drop): Move actual unsupported drop
handling here.
(syms_of_xterm): New variable `x-dnd-unsupported-drop-function'.
* src/xterm.h: Update prototypes.

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

index f0b9b27f66b76c6d2116fca910240d665cb11a21..a71ae87e215e078a7c8526ab016b7ea3d6112ae7 100644 (file)
@@ -86,6 +86,7 @@
 (defvar x-session-id)
 (defvar x-session-previous-id)
 (defvar x-dnd-movement-function)
+(defvar x-dnd-unsupported-drop-function)
 
 (defun x-handle-no-bitmap-icon (_switch)
   (setq default-frame-alist (cons '(icon-type) default-frame-alist)))
@@ -1583,6 +1584,7 @@ frames on all displays."
   (redisplay))
 
 (setq x-dnd-movement-function #'x-dnd-movement)
+(setq x-dnd-unsupported-drop-function #'x-dnd-handle-unsupported-drop)
 
 (provide 'x-win)
 (provide 'term/x-win)
index af9c7b83d97460259adfbaf072f7c79e78fffa1e..47d8ae14cfcc6ec97b1f153b264b5642d9030795 100644 (file)
@@ -779,6 +779,19 @@ FORMAT is 32 (not used).  MESSAGE is the data part of an XClientMessageEvent."
 
 ;;;
 
+\f
+
+;;; Handling drops.
+
+(defun x-dnd-handle-unsupported-drop (targets _x _y action _window-id _frame)
+  "Return non-nil if the drop described by TARGETS and ACTION should not proceeed."
+  (not (and (or (eq action 'XdndActionCopy)
+                (eq action 'XdndActionMove))
+            (or (member "STRING" targets)
+                (member "UTF8_STRING" targets)
+                (member "COMPOUND_TEXT" targets)
+                (member "TEXT" targets)))))
+
 (provide 'x-dnd)
 
 ;;; x-dnd.el ends here
index d34bec48a6b8ebe558979d840afdf702acc091b7..d99fe4be09282490909102694a4d4ce3f2303f87 100644 (file)
@@ -4006,6 +4006,41 @@ 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);
+
+         f = XFRAME (event->ie.frame_or_window);
+
+         if (!FRAME_LIVE_P (f))
+           break;
+
+         if (!NILP (Vx_dnd_unsupported_drop_function))
+           {
+             if (!NILP (call6 (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)))
+               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
+
 #ifdef HAVE_EXT_MENU_BAR
       case MENU_BAR_ACTIVATE_EVENT:
        {
index 93ac9ba0d2ef9e9bf490802228497a194995d426..0f02b56e9ee6179da379a10b16b556482535381d 100644 (file)
@@ -208,6 +208,25 @@ 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.
+
+                                 .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 b6aed004ed39e8b23f9faf7e55bd9da60f6a673e..b6fe5fda0fa1e8d7c9709be7d0798edd9de7bc8c 100644 (file)
@@ -2774,45 +2774,35 @@ x_dnd_get_wm_state_and_proto (struct x_display_info *dpyinfo,
 
    Dropping on windows that do not support XDND
 
-   Since middle clicking is the universal shortcut for pasting in X,
-   one can drop data into a window that does not support XDND by:
-
-   1. After the mouse has been released to trigger the drop, obtain
-   ownership of XA_PRIMARY.
-
-   2. Send a ButtonPress event and then a ButtonRelease event to the
-   deepest subwindow containing the mouse to simulate a middle click.
-   The times for these events should be the time of the actual button
-   release +1 and +2, respectively.  These values will not be used by
-   anybody else, so one can unambiguously recognize the resulting
-   XConvertSelection() request.
-
-   3. If a request for XA_PRIMARY arrives bearing the timestamp of
-   either the ButtonPress or the ButtonRelease event, treat it as a
-   request for XdndSelection.  Note that you must use the X data
-   types instead of the MIME types in this case.  (e.g. XA_STRING
-   instead of text/plain).  */
-static void
-x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_window,
-                            int root_x, int root_y, Time before)
+   Since middle clicking is the universal shortcut for pasting
+   in X, one can drop data into a window that does not support
+   XDND by:
+
+   1. After the mouse has been released to trigger the drop,
+   obtain ownership of XA_PRIMARY.
+
+   2. Send a ButtonPress event and then a ButtonRelease event to
+   the deepest subwindow containing the mouse to simulate a
+   middle click.  The times for these events should be the time
+   of the actual button release +1 and +2, respectively.  These
+   values will not be used by anybody else, so one can
+   unambiguously recognize the resulting `XConvertSelection'
+   request.
+
+   3. If a request for XA_PRIMARY arrives bearing the timestamp
+   of either the ButtonPress or the ButtonRelease event, treat
+   it as a request for XdndSelection.  Note that you must use
+   the X data types instead of the MIME types in this case.
+   (e.g. XA_STRING instead of text/plain).  */
+void
+x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
+                          Lisp_Object frame, Lisp_Object value,
+                          Lisp_Object targets, Window target_window,
+                          int root_x, int root_y, Time before)
 {
   XEvent event;
   int dest_x, dest_y;
   Window child_return, child;
-  Lisp_Object frame;
-  int i;
-
-  for (i = 0; i < x_dnd_n_targets; ++i)
-    {
-      if (x_dnd_targets[i] == XA_STRING
-         || x_dnd_targets[i] == dpyinfo->Xatom_TEXT
-         || x_dnd_targets[i] == dpyinfo->Xatom_COMPOUND_TEXT
-         || x_dnd_targets[i] == dpyinfo->Xatom_UTF8_STRING)
-       break;
-    }
-
-  if (i == x_dnd_n_targets)
-    return;
 
   event.xbutton.type = ButtonPress;
   event.xbutton.serial = 0;
@@ -2822,8 +2812,6 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
   event.xbutton.x_root = root_x;
   event.xbutton.y_root = root_y;
 
-  XSETFRAME (frame, x_dnd_frame);
-
   x_catch_errors (dpyinfo->display);
 
   child = dpyinfo->root_window;
@@ -2868,6 +2856,55 @@ x_dnd_send_unsupported_drop (struct x_display_info *dpyinfo, Window target_windo
   x_uncatch_errors ();
 }
 
+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);
+
+  if (!XGetAtomNames (dpyinfo->display, x_dnd_targets,
+                     x_dnd_n_targets, atom_names))
+      return;
+
+  for (i = x_dnd_n_targets; i > 0; --i)
+    {
+      targets = Fcons (build_string (atom_names[i - 1]),
+                      targets);
+      XFree (atom_names[i - 1]);
+    }
+
+  name = XGetAtomName (dpyinfo->display,
+                      x_dnd_wanted_action);
+
+  if (name)
+    {
+      arg = intern (name);
+      XFree (name);
+    }
+  else
+    arg = Qnil;
+
+  ie.kind = UNSUPPORTED_DROP_EVENT;
+  ie.code = (unsigned) target_window;
+  ie.arg = list3 (assq_no_quit (QXdndSelection,
+                               dpyinfo->terminal->Vselection_alist),
+                 targets, arg);
+  ie.timestamp = before;
+
+  XSETINT (ie.x, root_x);
+  XSETINT (ie.y, root_y);
+  XSETFRAME (ie.frame_or_window, x_dnd_frame);
+
+  kbd_buffer_store_event (&ie);
+}
+
 static Window
 x_dnd_get_target_window (struct x_display_info *dpyinfo,
                         int root_x, int root_y, int *proto_out,
@@ -23273,4 +23310,19 @@ It should either be nil, or accept two arguments FRAME and POSITION,
 where FRAME is the frame the mouse is on top of, and POSITION is a
 mouse position list.  */);
   Vx_dnd_movement_function = Qnil;
+
+  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 handled by the function, and nil if it was
+not.  It should accept several arguments TARGETS, X, Y, ACTION,
+WINDOW-ID and FRAME, where TARGETS is the list of targets that
+was passed to `x-begin-drag', WINDOW-ID is the numeric XID of
+the window that is being dropped on, X and Y are the root
+window-relative coordinates where the drop happened, ACTION
+is the action that was passed to `x-begin-drag', and FRAME is
+the frame which initiated the drag-and-drop operation.  */);
+  Vx_dnd_unsupported_drop_function = Qnil;
 }
index 4eb16d0c1426c4403b3a6248dd2ebd7cb5ce6bd8..d8898162d110509f0b1b0941655a8b71628b0880 100644 (file)
@@ -1391,6 +1391,9 @@ extern void x_scroll_bar_configure (GdkEvent *);
 extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom,
                                              Lisp_Object, Atom *, const char **,
                                              size_t, bool);
+extern void x_dnd_do_unsupported_drop (struct x_display_info *, Lisp_Object,
+                                      Lisp_Object, Lisp_Object, Window, int,
+                                      int, Time);
 extern void x_set_dnd_targets (Atom *, int);
 
 INLINE int