emacs-diffs
[Top][All Lists]
Advanced

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

master 9accc800a7: Comply with the Motif requirement for unique drag ato


From: Po Lu
Subject: master 9accc800a7: Comply with the Motif requirement for unique drag atoms
Date: Wed, 15 Jun 2022 22:09:56 -0400 (EDT)

branch: master
commit 9accc800a75529c1eaf81d6844c53b6ca2f5622f
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Comply with the Motif requirement for unique drag atoms
    
    * src/xselect.c (x_handle_selection_request)
    (Fx_get_selection_internal, syms_of_xselect): New variable
    `x-selection-alias-alist'.  Respect that alist of aliases.
    
    * src/xterm.c (x_atom_refs): Intern _EMACS_DRAG_ATOM.
    (xm_get_drag_atom_1, xm_get_drag_atom): New functions.
    (xm_setup_drag_info, x_dnd_cleanup_drag_and_drop)
    (x_dnd_begin_drag_and_drop, x_dnd_update_state, handle_one_xevent)
    (x_connection_closed, x_intern_cached_atom): Alias the drag atom
    to XdndSelection.  Use it instead of XdndSelection to set the
    Motif index atom.
    (x_get_atom_name): Handle new atoms.
    (syms_of_xterm): New defsym.
    * src/xterm.h (struct x_display_info): New fields for new atoms
    and their names.
---
 src/xselect.c |  40 ++++++++++++++++
 src/xterm.c   | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 src/xterm.h   |  15 +++++-
 3 files changed, 182 insertions(+), 21 deletions(-)

diff --git a/src/xselect.c b/src/xselect.c
index 96c1e9830f..fff79fb99f 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -774,6 +774,25 @@ x_handle_selection_request (struct selection_input_event 
*event)
   bool success = false;
   specpdl_ref count = SPECPDL_INDEX ();
   bool pushed;
+  Lisp_Object alias, tem;
+
+  alias = Vx_selection_alias_alist;
+
+  FOR_EACH_TAIL_SAFE (alias)
+    {
+      tem = Qnil;
+
+      if (CONSP (alias))
+       tem = XCAR (alias);
+
+      if (CONSP (tem)
+         && EQ (XCAR (tem), selection_symbol)
+         && SYMBOLP (XCDR (tem)))
+       {
+         selection_symbol = XCDR (tem);
+         break;
+       }
+    }
 
   pushed = false;
 
@@ -2055,15 +2074,27 @@ On Nextstep, TIME-STAMP and TERMINAL are unused.  */)
    Lisp_Object time_stamp, Lisp_Object terminal)
 {
   Lisp_Object val = Qnil;
+  Lisp_Object maybe_alias;
   struct frame *f = frame_for_x_selection (terminal);
 
   CHECK_SYMBOL (selection_symbol);
   CHECK_SYMBOL (target_type);
+
   if (EQ (target_type, QMULTIPLE))
     error ("Retrieving MULTIPLE selections is currently unimplemented");
   if (!f)
     error ("X selection unavailable for this frame");
 
+  /* Quitting inside this function is okay, so we don't have to use
+     FOR_EACH_TAIL_SAFE.  */
+  maybe_alias = Fassq (selection_symbol, Vx_selection_alias_alist);
+
+  if (!NILP (maybe_alias))
+    {
+      selection_symbol = XCDR (maybe_alias);
+      CHECK_SYMBOL (selection_symbol);
+    }
+
   val = x_get_local_selection (selection_symbol, target_type, true,
                               FRAME_DISPLAY_INFO (f));
 
@@ -2818,6 +2849,15 @@ If non-nil, selection converters for string types 
(`STRING',
 when Emacs itself is converting the selection.  */);
   Vx_treat_local_requests_remotely = Qnil;
 
+  DEFVAR_LISP ("x-selection-alias-alist", Vx_selection_alias_alist,
+    doc: /* List of selections to alias to another.
+It should be an alist of a selection name to another.  When a
+selection request arrives for the first selection, Emacs will respond
+as if the request was meant for the other.
+
+Note that this does not affect setting or owning selections.  */);
+  Vx_selection_alias_alist = Qnil;
+
   /* QPRIMARY is defined in keyboard.c.  */
   DEFSYM (QSECONDARY, "SECONDARY");
   DEFSYM (QSTRING, "STRING");
diff --git a/src/xterm.c b/src/xterm.c
index f2f80b42be..0e00632174 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -931,6 +931,7 @@ static const struct x_atom_ref x_atom_refs[] =
     ATOM_REFS_INIT ("CLIPBOARD_MANAGER", Xatom_CLIPBOARD_MANAGER)
     ATOM_REFS_INIT ("_XEMBED_INFO", Xatom_XEMBED_INFO)
     ATOM_REFS_INIT ("_MOTIF_WM_HINTS", Xatom_MOTIF_WM_HINTS)
+    ATOM_REFS_INIT ("_EMACS_DRAG_ATOM", Xatom_EMACS_DRAG_ATOM)
     /* For properties of font.  */
     ATOM_REFS_INIT ("PIXEL_SIZE", Xatom_PIXEL_SIZE)
     ATOM_REFS_INIT ("AVERAGE_WIDTH", Xatom_AVERAGE_WIDTH)
@@ -1297,6 +1298,11 @@ static bool x_dnd_inside_handle_one_xevent;
    started.  */
 static int x_dnd_recursion_depth;
 
+/* The cons cell containing the selection alias between the Motif drag
+   selection and `XdndSelection'.  The car and cdr are only set when
+   initiating Motif drag-and-drop for the first time.  */
+static Lisp_Object x_dnd_selection_alias_cell;
+
 /* Structure describing a single window that can be the target of
    drag-and-drop operations.  */
 struct x_client_list_window
@@ -2172,12 +2178,95 @@ xm_setup_dnd_targets (struct x_display_info *dpyinfo,
   return idx;
 }
 
+static Atom
+xm_get_drag_atom_1 (struct x_display_info *dpyinfo)
+{
+  Atom actual_type, atom;
+  unsigned long nitems, bytes_remaining;
+  unsigned char *tmp_data;
+  unsigned long inumber;
+  int rc, actual_format;
+  char *buffer;
+
+  /* Make sure this operation is done atomically.  */
+  XGrabServer (dpyinfo->display);
+
+  rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
+                          dpyinfo->Xatom_EMACS_DRAG_ATOM,
+                          0, 1, False, XA_CARDINAL, &actual_type,
+                          &actual_format, &nitems, &bytes_remaining,
+                          &tmp_data);
+
+  if (rc == Success
+      && actual_format == 32 && nitems == 1
+      && actual_type == XA_CARDINAL)
+    {
+      inumber = *(unsigned long *) tmp_data;
+      inumber &= 0xffffffff;
+    }
+  else
+    inumber = 0;
+
+  if (tmp_data)
+    XFree (tmp_data);
+
+  if (X_LONG_MAX - inumber < 1)
+    inumber = 0;
+
+  inumber += 1;
+  buffer = dpyinfo->motif_drag_atom_name;
+
+  /* FIXME: this interns a unique atom for every Emacs session.
+     Eventually the atoms simply pile up.  It may be worth
+     implementing the Motif atoms table logic here.  */
+  sprintf (buffer, "_EMACS_ATOM_%lu", inumber);
+  atom = XInternAtom (dpyinfo->display, buffer, False);
+
+  XChangeProperty (dpyinfo->display, dpyinfo->root_window,
+                  dpyinfo->Xatom_EMACS_DRAG_ATOM, XA_CARDINAL, 32,
+                  PropModeReplace, (unsigned char *) &inumber, 1);
+
+  XUngrabServer (dpyinfo->display);
+  return atom;
+}
+
+static Atom
+xm_get_drag_atom (struct x_display_info *dpyinfo)
+{
+  Atom atom;
+
+  if (dpyinfo->motif_drag_atom != None)
+    atom = dpyinfo->motif_drag_atom;
+  else
+    atom = xm_get_drag_atom_1 (dpyinfo);
+
+  dpyinfo->motif_drag_atom = atom;
+  return atom;
+}
+
 static void
 xm_setup_drag_info (struct x_display_info *dpyinfo,
                    struct frame *source_frame)
 {
+  Atom atom;
   xm_drag_initiator_info drag_initiator_info;
-  int idx;
+  int idx, rc;
+
+  atom = xm_get_drag_atom (dpyinfo);
+
+  x_catch_errors (dpyinfo->display);
+  XSetSelectionOwner (dpyinfo->display, atom,
+                     FRAME_X_WINDOW (source_frame),
+                     dpyinfo->last_user_time);
+  rc = x_had_errors_p (dpyinfo->display);
+  x_uncatch_errors_after_check ();
+
+  if (rc)
+    return;
+
+  XSETCAR (x_dnd_selection_alias_cell,
+          x_atom_to_symbol (dpyinfo, atom));
+  XSETCDR (x_dnd_selection_alias_cell, QXdndSelection);
 
   idx = xm_setup_dnd_targets (dpyinfo, x_dnd_targets,
                              x_dnd_n_targets);
@@ -2187,10 +2276,10 @@ xm_setup_drag_info (struct x_display_info *dpyinfo,
       drag_initiator_info.byteorder = XM_BYTE_ORDER_CUR_FIRST;
       drag_initiator_info.protocol = XM_DRAG_PROTOCOL_VERSION;
       drag_initiator_info.table_index = idx;
-      drag_initiator_info.selection = dpyinfo->Xatom_XdndSelection;
+      drag_initiator_info.selection = atom;
 
-      xm_write_drag_initiator_info (dpyinfo->display, FRAME_X_WINDOW 
(source_frame),
-                                   dpyinfo->Xatom_XdndSelection,
+      xm_write_drag_initiator_info (dpyinfo->display,
+                                   FRAME_X_WINDOW (source_frame), atom,
                                    dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO,
                                    &drag_initiator_info);
 
@@ -4334,7 +4423,7 @@ x_dnd_cleanup_drag_and_drop (void *frame)
                                   XM_DROP_ACTION_DROP_CANCEL);
          dmsg.x = 0;
          dmsg.y = 0;
-         dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
+         dmsg.index_atom = xm_get_drag_atom (FRAME_DISPLAY_INFO (f));
          dmsg.source_window = FRAME_X_WINDOW (f);
 
          x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
@@ -11189,6 +11278,16 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
   record_unwind_protect_void (release_xg_select);
 #endif
 
+  /* Set up a meaningless alias.  */
+  XSETCAR (x_dnd_selection_alias_cell, QSECONDARY);
+  XSETCDR (x_dnd_selection_alias_cell, QSECONDARY);
+
+  /* Bind this here.  The cell doesn't actually alias between
+     anything until `xm_setup_dnd_targets' is called.  */
+  specbind (Qx_selection_alias_alist,
+           Fcons (x_dnd_selection_alias_cell,
+                  Vx_selection_alias_alist));
+
   /* Initialize most of the state for the drag-and-drop operation.  */
   x_dnd_in_progress = true;
   x_dnd_recursion_depth = command_loop_level + minibuf_level;
@@ -11392,7 +11491,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
                                               XM_DROP_ACTION_DROP_CANCEL);
                      dmsg.x = 0;
                      dmsg.y = 0;
-                     dmsg.index_atom = FRAME_DISPLAY_INFO 
(f)->Xatom_XdndSelection;
+                     dmsg.index_atom = xm_get_drag_atom (FRAME_DISPLAY_INFO 
(f));
                      dmsg.source_window = FRAME_X_WINDOW (f);
 
                      x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
@@ -11430,7 +11529,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
              /* Delete the Motif drag initiator info if it was set up.  */
              if (x_dnd_motif_setup_p)
                XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                                FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+                                xm_get_drag_atom (FRAME_DISPLAY_INFO (f)));
 
 
              /* Remove any type list set as well.  */
@@ -11485,7 +11584,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
                                               XM_DROP_ACTION_DROP_CANCEL);
                      dmsg.x = 0;
                      dmsg.y = 0;
-                     dmsg.index_atom = FRAME_DISPLAY_INFO 
(f)->Xatom_XdndSelection;
+                     dmsg.index_atom = xm_get_drag_atom (FRAME_DISPLAY_INFO 
(f));
                      dmsg.source_window = FRAME_X_WINDOW (f);
 
                      x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
@@ -11522,7 +11621,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
              /* Delete the Motif drag initiator info if it was set up.  */
              if (x_dnd_motif_setup_p)
                XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                                FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+                                xm_get_drag_atom (FRAME_DISPLAY_INFO (f)));
 
 
              /* Remove any type list set as well.  */
@@ -11566,7 +11665,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
   /* Delete the Motif drag initiator info if it was set up.  */
   if (x_dnd_motif_setup_p)
     XDeleteProperty (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
-                    FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection);
+                    xm_get_drag_atom (FRAME_DISPLAY_INFO (f)));
 
   /* Remove any type list set as well.  */
   if (x_dnd_init_type_lists && x_dnd_n_targets > 3)
@@ -15629,7 +15728,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, 
Time timestamp)
              emsg.zero = 0;
              emsg.timestamp = timestamp;
              emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
-             emsg.index_atom = dpyinfo->Xatom_XdndSelection;
+             emsg.index_atom = xm_get_drag_atom (dpyinfo);
 
              if (x_dnd_motif_setup_p)
                xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW 
(x_dnd_frame),
@@ -15701,8 +15800,7 @@ x_dnd_update_state (struct x_display_info *dpyinfo, 
Time timestamp)
                                   XM_DROP_ACTION_DROP_CANCEL);
          dsmsg.x = 0;
          dsmsg.y = 0;
-         dsmsg.index_atom
-           = FRAME_DISPLAY_INFO (x_dnd_frame)->Xatom_XdndSelection;
+         dsmsg.index_atom = xm_get_drag_atom (dpyinfo);
          dsmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
 
          x_dnd_send_xm_leave_for_drop (dpyinfo, x_dnd_frame,
@@ -16502,7 +16600,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
        if (x_dnd_waiting_for_finish
            && x_dnd_waiting_for_motif_finish == 2
            && dpyinfo == x_dnd_waiting_for_motif_finish_display
-           && eventp->selection == dpyinfo->Xatom_XdndSelection
+           && eventp->selection == xm_get_drag_atom (dpyinfo)
            && (eventp->target == dpyinfo->Xatom_XmTRANSFER_SUCCESS
                || eventp->target == dpyinfo->Xatom_XmTRANSFER_FAILURE))
          {
@@ -17911,7 +18009,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                    emsg.zero = 0;
                    emsg.timestamp = event->xbutton.time;
                    emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
-                   emsg.index_atom = dpyinfo->Xatom_XdndSelection;
+                   emsg.index_atom = xm_get_drag_atom (dpyinfo);
 
                    if (x_dnd_motif_setup_p)
                      xm_send_top_level_enter_message (dpyinfo, FRAME_X_WINDOW 
(x_dnd_frame),
@@ -18525,7 +18623,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                dmsg.timestamp = event->xbutton.time;
                                dmsg.x = event->xbutton.x_root;
                                dmsg.y = event->xbutton.y_root;
-                               dmsg.index_atom = dpyinfo->Xatom_XdndSelection;
+                               dmsg.index_atom = xm_get_drag_atom (dpyinfo);
                                dmsg.source_window = FRAME_X_WINDOW 
(x_dnd_frame);
 
                                if (!XM_DRAG_STYLE_IS_DROP_ONLY 
(drag_receiver_info.protocol_style))
@@ -19636,7 +19734,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          emsg.zero = 0;
                          emsg.timestamp = xev->time;
                          emsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
-                         emsg.index_atom = dpyinfo->Xatom_XdndSelection;
+                         emsg.index_atom = xm_get_drag_atom (dpyinfo);
 
                          if (x_dnd_motif_setup_p)
                            xm_send_top_level_enter_message (dpyinfo, 
FRAME_X_WINDOW (x_dnd_frame),
@@ -19932,7 +20030,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                         instances of Emacs try to drag
                                         into the same window at the same
                                         time.  */
-                                     dmsg.index_atom = 
dpyinfo->Xatom_XdndSelection;
+                                     dmsg.index_atom = xm_get_drag_atom 
(dpyinfo);
                                      dmsg.source_window = FRAME_X_WINDOW 
(x_dnd_frame);
 
                                      if (!XM_DRAG_STYLE_IS_DROP_ONLY 
(drag_receiver_info.protocol_style))
@@ -22823,7 +22921,7 @@ x_connection_closed (Display *dpy, const char 
*error_message, bool ioerror)
                                           XM_DROP_ACTION_DROP_CANCEL);
                  dmsg.x = 0;
                  dmsg.y = 0;
-                 dmsg.index_atom = FRAME_DISPLAY_INFO (f)->Xatom_XdndSelection;
+                 dmsg.index_atom = xm_get_drag_atom (FRAME_DISPLAY_INFO (f));
                  dmsg.source_window = FRAME_X_WINDOW (f);
 
                  x_dnd_send_xm_leave_for_drop (FRAME_DISPLAY_INFO (f), f,
@@ -25253,6 +25351,10 @@ x_intern_cached_atom (struct x_display_info *dpyinfo,
   if (!strcmp (name, "WINDOW"))
     return XA_WINDOW;
 
+  if (dpyinfo->motif_drag_atom != None
+      && !strcmp (name, dpyinfo->motif_drag_atom_name))
+    return dpyinfo->motif_drag_atom;
+
   for (i = 0; i < ARRAYELTS (x_atom_refs); ++i)
     {
       ptr = (char *) dpyinfo;
@@ -25311,6 +25413,10 @@ x_get_atom_name (struct x_display_info *dpyinfo, Atom 
atom,
       return xstrdup ("WINDOW");
 
     default:
+      if (dpyinfo->motif_drag_atom
+         && atom == dpyinfo->motif_drag_atom)
+       return xstrdup (dpyinfo->motif_drag_atom_name);
+
       if (atom == dpyinfo->Xatom_xsettings_sel)
        {
          sprintf (buffer, "_XSETTINGS_S%d",
@@ -27203,6 +27309,9 @@ syms_of_xterm (void)
   x_dnd_action_symbol = Qnil;
   staticpro (&x_dnd_action_symbol);
 
+  x_dnd_selection_alias_cell = Fcons (Qnil, Qnil);
+  staticpro (&x_dnd_selection_alias_cell);
+
   DEFSYM (Qvendor_specific_keysyms, "vendor-specific-keysyms");
   DEFSYM (Qlatin_1, "latin-1");
   DEFSYM (Qnow, "now");
@@ -27291,6 +27400,7 @@ With MS Windows, Haiku windowing or Nextstep, the value 
is t.  */);
   DEFSYM (Qsuper, "super");
   Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier));
   DEFSYM (QXdndSelection, "XdndSelection");
+  DEFSYM (Qx_selection_alias_alist, "x-selection-alias-alist");
 
   DEFVAR_LISP ("x-ctrl-keysym", Vx_ctrl_keysym,
     doc: /* Which keys Emacs uses for the ctrl modifier.
diff --git a/src/xterm.h b/src/xterm.h
index d710069fad..9df1feae5b 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -428,8 +428,8 @@ struct x_display_info
   /* More atoms for font properties.  The last three are private
      properties, see the comments in src/fontset.h.  */
   Atom Xatom_PIXEL_SIZE, Xatom_AVERAGE_WIDTH,
-  Xatom_MULE_BASELINE_OFFSET, Xatom_MULE_RELATIVE_COMPOSE,
-  Xatom_MULE_DEFAULT_ASCENT;
+    Xatom_MULE_BASELINE_OFFSET, Xatom_MULE_RELATIVE_COMPOSE,
+    Xatom_MULE_DEFAULT_ASCENT;
 
   /* More atoms for Ghostscript support.  */
   Atom Xatom_DONE, Xatom_PAGE;
@@ -448,6 +448,9 @@ struct x_display_info
     Xatom_MOTIF_DRAG_TARGETS, Xatom_MOTIF_DRAG_AND_DROP_MESSAGE,
     Xatom_MOTIF_DRAG_INITIATOR_INFO, Xatom_MOTIF_DRAG_RECEIVER_INFO;
 
+  /* Atoms used by Emacs internally.  */
+  Atom Xatom_EMACS_DRAG_ATOM;
+
   /* Special selections used by the Motif drop protocol to indicate
      success or failure.  */
   Atom Xatom_XmTRANSFER_SUCCESS, Xatom_XmTRANSFER_FAILURE;
@@ -562,6 +565,14 @@ struct x_display_info
   ptrdiff_t x_dnd_atoms_size;
   ptrdiff_t x_dnd_atoms_length;
 
+  /* The unique drag and drop atom used on Motif.  None if it was not
+     already computed.  */
+  Atom motif_drag_atom;
+
+  /* Its name.  */
+  char motif_drag_atom_name[sizeof "_EMACS_ATOM_%lu" - 3
+                           + INT_STRLEN_BOUND (unsigned long)];
+
   /* Extended window manager hints, Atoms supported by the window manager and
      atoms for setting the window type.  */
   Atom Xatom_net_supported, Xatom_net_supporting_wm_check;



reply via email to

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