[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;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- master 9accc800a7: Comply with the Motif requirement for unique drag atoms,
Po Lu <=