emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 3bdeedd8ac 2/2: Improve compatibility with some clients of the Mo


From: Po Lu
Subject: master 3bdeedd8ac 2/2: Improve compatibility with some clients of the Motif drop protocol
Date: Tue, 7 Jun 2022 01:49:57 -0400 (EDT)

branch: master
commit 3bdeedd8aca18e449bd3700c4ab65055fa183201
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Improve compatibility with some clients of the Motif drop protocol
    
    * lisp/select.el (x-dnd-targets-list): New defvar.
    (xselect-convert-to-targets): Convert XdndSelection based on the
    DND targets list.
    * src/xfns.c (Fx_begin_drag): Pass new argument.
    * src/xselect.c (struct x_selection_request): New struct.
    (x_push_current_selection_request):
    (x_pop_current_selection_request): New functions.
    (x_selection_request_lisp_error, x_reply_selection_request)
    (x_handle_selection_request, x_convert_selection)
    (syms_of_xselect_for_pdumper): Correctly handle recursive
    requests for MULTIPLE by maintaining a stack of selection
    requests, converted selections, and other data.
    * src/xterm.c (x_dnd_begin_drag_and_drop): New argument
    `selection_target_list'.  Bind it to the DND targets list.
    (syms_of_xterm): New defvar and associated defsym.
    * src/xterm.h: Update prototypes.
---
 lisp/select.el |  32 +++++++++++------
 src/xfns.c     |   2 +-
 src/xselect.c  | 107 +++++++++++++++++++++++++++++++++++++++++----------------
 src/xterm.c    |  14 +++++++-
 src/xterm.h    |   3 +-
 5 files changed, 115 insertions(+), 43 deletions(-)

diff --git a/lisp/select.el b/lisp/select.el
index 83dc137e23..706197e027 100644
--- a/lisp/select.el
+++ b/lisp/select.el
@@ -601,19 +601,29 @@ two markers or an overlay.  Otherwise, it is nil."
     (if len
        (xselect--int-to-cons len))))
 
+(defvar x-dnd-targets-list)
+
 (defun xselect-convert-to-targets (selection _type value)
   ;; Return a vector of atoms, but remove duplicates first.
-  (apply #'vector
-         (delete-dups
-          `( TIMESTAMP MULTIPLE
-             . ,(delq '_EMACS_INTERNAL
-                      (mapcar (lambda (conv)
-                                (if (or (not (consp (cdr conv)))
-                                        (funcall (cadr conv) selection
-                                                 (car conv) value))
-                                    (car conv)
-                                  '_EMACS_INTERNAL))
-                              selection-converter-alist))))))
+  (if (eq selection 'XdndSelection)
+      ;; This isn't required by the XDND protocol, and sure enough no
+      ;; clients seem to dependent on it, but Emacs implements the
+      ;; receiver side of the Motif drop protocol by looking at the
+      ;; initiator selection's TARGETS target (which Motif provides)
+      ;; instead of the target table on the drag window, so it seems
+      ;; plausible for other clients to rely on that as well.
+      (apply #'vector (mapcar #'intern x-dnd-targets-list))
+    (apply #'vector
+           (delete-dups
+            `( TIMESTAMP MULTIPLE
+               . ,(delq '_EMACS_INTERNAL
+                        (mapcar (lambda (conv)
+                                  (if (or (not (consp (cdr conv)))
+                                          (funcall (cadr conv) selection
+                                                   (car conv) value))
+                                      (car conv)
+                                    '_EMACS_INTERNAL))
+                                selection-converter-alist)))))))
 
 (defun xselect-convert-to-delete (selection _type _value)
   ;; This should be handled by the caller of `x-begin-drag'.
diff --git a/src/xfns.c b/src/xfns.c
index cfc6d4c212..cffb4a5d96 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -6985,7 +6985,7 @@ that mouse buttons are being held down, such as 
immediately after a
                                    xaction, return_frame, action_list,
                                    (const char **) &name_list, nnames,
                                    !NILP (allow_current_frame), target_atoms,
-                                   ntargets);
+                                   ntargets, original);
 
   SAFE_FREE ();
   return lval;
diff --git a/src/xselect.c b/src/xselect.c
index b920540620..0271310d04 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -417,14 +417,6 @@ x_decline_selection_request (struct selection_input_event 
*event)
   unblock_input ();
 }
 
-/* This is the selection request currently being processed.
-   It is set to zero when the request is fully processed.  */
-static struct selection_input_event *x_selection_current_request;
-
-/* Display info in x_selection_request.  */
-
-static struct x_display_info *selection_request_dpyinfo;
-
 /* Raw selection data, for sending to a requestor window.  */
 
 struct selection_data
@@ -442,12 +434,59 @@ struct selection_data
   struct selection_data *next;
 };
 
-/* Linked list of the above (in support of MULTIPLE targets).  */
+struct x_selection_request
+{
+  /* The last element in this stack.  */
+  struct x_selection_request *last;
+
+  /* Its display info.  */
+  struct x_display_info *dpyinfo;
+
+  /* Its selection input event.  */
+  struct selection_input_event *request;
+
+  /* Linked list of the above (in support of MULTIPLE targets).  */
+  struct selection_data *converted_selections;
 
-static struct selection_data *converted_selections;
+  /* "Data" to send a requestor for a failed MULTIPLE subtarget.  */
+  Atom conversion_fail_tag;
+
+  /* Whether or not conversion was successful.  */
+  bool converted;
+};
+
+/* Stack of selections currently being processed.
+   NULL if all requests have been fully processed.  */
+
+struct x_selection_request *selection_request_stack;
+
+static void
+x_push_current_selection_request (struct selection_input_event *se,
+                                 struct x_display_info *dpyinfo)
+{
+  struct x_selection_request *frame;
 
-/* "Data" to send a requestor for a failed MULTIPLE subtarget.  */
-static Atom conversion_fail_tag;
+  frame = xmalloc (sizeof *frame);
+  frame->converted = false;
+  frame->last = selection_request_stack;
+  frame->request = se;
+  frame->dpyinfo = dpyinfo;
+  frame->converted_selections = NULL;
+  frame->conversion_fail_tag = None;
+
+  selection_request_stack = frame;
+}
+
+static void
+x_pop_current_selection_request (void)
+{
+  struct x_selection_request *tem;
+
+  tem = selection_request_stack;
+  selection_request_stack = selection_request_stack->last;
+
+  xfree (tem);
+}
 
 /* Used as an unwind-protect clause so that, if a selection-converter signals
    an error, we tell the requestor that we were unable to do what they wanted
@@ -457,19 +496,21 @@ static void
 x_selection_request_lisp_error (void)
 {
   struct selection_data *cs, *next;
+  struct x_selection_request *frame;
+
+  frame = selection_request_stack;
 
-  for (cs = converted_selections; cs; cs = next)
+  for (cs = frame->converted_selections; cs; cs = next)
     {
       next = cs->next;
       if (! cs->nofree && cs->data)
        xfree (cs->data);
       xfree (cs);
     }
-  converted_selections = NULL;
+  frame->converted_selections = NULL;
 
-  if (x_selection_current_request != 0
-      && selection_request_dpyinfo->display)
-    x_decline_selection_request (x_selection_current_request);
+  if (!frame->converted && frame->dpyinfo->display)
+    x_decline_selection_request (frame->request);
 }
 
 static void
@@ -535,6 +576,9 @@ x_reply_selection_request (struct selection_input_event 
*event,
   int max_bytes = selection_quantum (display);
   specpdl_ref count = SPECPDL_INDEX ();
   struct selection_data *cs;
+  struct x_selection_request *frame;
+
+  frame = selection_request_stack;
 
   reply->type = SelectionNotify;
   reply->display = display;
@@ -558,7 +602,7 @@ x_reply_selection_request (struct selection_input_event 
*event,
      (section 2.7.2 of ICCCM).  Note that we store the data for a
      MULTIPLE request in the opposite order; the ICCM says only that
      the conversion itself must be done in the same order. */
-  for (cs = converted_selections; cs; cs = cs->next)
+  for (cs = frame->converted_selections; cs; cs = cs->next)
     {
       if (cs->property == None)
        continue;
@@ -613,7 +657,7 @@ x_reply_selection_request (struct selection_input_event 
*event,
      be improved; there's a chance of deadlock if more than one
      subtarget in a MULTIPLE selection requires an INCR transfer, and
      the requestor and Emacs loop waiting on different transfers.  */
-  for (cs = converted_selections; cs; cs = cs->next)
+  for (cs = frame->converted_selections; cs; cs = cs->next)
     if (cs->wait_object)
       {
        int format_bytes = cs->format / 8;
@@ -749,9 +793,11 @@ x_handle_selection_request (struct selection_input_event 
*event)
       && local_selection_time > SELECTION_EVENT_TIME (event))
     goto DONE;
 
-  x_selection_current_request = event;
-  selection_request_dpyinfo = dpyinfo;
+  block_input ();
+  x_push_current_selection_request (event, dpyinfo);
+  record_unwind_protect_void (x_pop_current_selection_request);
   record_unwind_protect_void (x_selection_request_lisp_error);
+  unblock_input ();
 
   TRACE2 ("x_handle_selection_request: selection=%s, target=%s",
          SDATA (SYMBOL_NAME (selection_symbol)),
@@ -808,11 +854,12 @@ x_handle_selection_request (struct selection_input_event 
*event)
 
  DONE:
 
+  selection_request_stack->converted = true;
+
   if (success)
     x_reply_selection_request (event, dpyinfo);
   else
     x_decline_selection_request (event);
-  x_selection_current_request = 0;
 
   /* Run the `x-sent-selection-functions' abnormal hook.  */
   if (!NILP (Vx_sent_selection_functions)
@@ -837,11 +884,14 @@ x_convert_selection (Lisp_Object selection_symbol,
 {
   Lisp_Object lisp_selection;
   struct selection_data *cs;
+  struct x_selection_request *frame;
 
   lisp_selection
     = x_get_local_selection (selection_symbol, target_symbol,
                             false, dpyinfo);
 
+  frame = selection_request_stack;
+
   /* A nil return value means we can't perform the conversion.  */
   if (NILP (lisp_selection)
       || (CONSP (lisp_selection) && NILP (XCDR (lisp_selection))))
@@ -849,15 +899,16 @@ x_convert_selection (Lisp_Object selection_symbol,
       if (for_multiple)
        {
          cs = xmalloc (sizeof *cs);
-         cs->data = (unsigned char *) &conversion_fail_tag;
+         cs->data = ((unsigned char *)
+                     &selection_request_stack->conversion_fail_tag);
          cs->size = 1;
          cs->format = 32;
          cs->type = XA_ATOM;
          cs->nofree = true;
          cs->property = property;
          cs->wait_object = NULL;
-         cs->next = converted_selections;
-         converted_selections = cs;
+         cs->next = frame->converted_selections;
+         frame->converted_selections = cs;
        }
 
       return false;
@@ -869,8 +920,8 @@ x_convert_selection (Lisp_Object selection_symbol,
   cs->nofree = true;
   cs->property = property;
   cs->wait_object = NULL;
-  cs->next = converted_selections;
-  converted_selections = cs;
+  cs->next = frame->converted_selections;
+  frame->converted_selections = cs;
   lisp_data_to_selection_data (dpyinfo, lisp_selection, cs);
   return true;
 }
@@ -2777,6 +2828,4 @@ syms_of_xselect_for_pdumper (void)
   property_change_wait_list = 0;
   prop_location_identifier = 0;
   property_change_reply = Fcons (Qnil, Qnil);
-  converted_selections = NULL;
-  conversion_fail_tag = None;
 }
diff --git a/src/xterm.c b/src/xterm.c
index 4dce24104d..ae46453eb6 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10645,7 +10645,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
                           Lisp_Object return_frame, Atom *ask_action_list,
                           const char **ask_action_names, size_t n_ask_actions,
                           bool allow_current_frame, Atom *target_atoms,
-                          int ntargets)
+                          int ntargets, Lisp_Object selection_target_list)
 {
 #ifndef USE_GTK
   XEvent next_event;
@@ -10674,6 +10674,10 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
 
   base = SPECPDL_INDEX ();
 
+  /* Bind this here to avoid juggling bindings and SAFE_FREE in
+     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
@@ -26516,6 +26520,7 @@ syms_of_xterm (void)
   DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
   DEFSYM (Qlatin_1, "latin-1");
   DEFSYM (Qnow, "now");
+  DEFSYM (Qx_dnd_targets_list, "x-dnd-targets-list");
 
 #ifdef USE_GTK
   xg_default_icon_file = build_pure_c_string 
("icons/hicolor/scalable/apps/emacs.svg");
@@ -26752,4 +26757,11 @@ operation, and TIME is the X server time when the drop 
happened.  */);
     doc: /* Max number of buckets allowed per display in the internal color 
cache.
 Values less than 1 mean 128.  This option is for debugging only.  */);
   x_color_cache_bucket_size = 128;
+
+  DEFVAR_LISP ("x-dnd-targets-list", Vx_dnd_targets_list,
+    doc: /* List of drag-and-drop targets.
+This variable contains the list of drag-and-drop selection targets
+during a drag-and-drop operation, in the same format as the TARGET
+argument to `x-begin-drag'.  */);
+  Vx_dnd_targets_list = Qnil;
 }
diff --git a/src/xterm.h b/src/xterm.h
index c6be30d73e..1ab65f15d1 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1460,7 +1460,8 @@ extern void x_handle_pending_selection_requests (void);
 extern bool x_detect_pending_selection_requests (void);
 extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom,
                                              Lisp_Object, Atom *, const char 
**,
-                                             size_t, bool, Atom *, int);
+                                             size_t, bool, Atom *, int,
+                                             Lisp_Object);
 extern void x_dnd_do_unsupported_drop (struct x_display_info *, Lisp_Object,
                                       Lisp_Object, Lisp_Object, Window, int,
                                       int, Time);



reply via email to

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