summaryrefslogtreecommitdiff
path: root/src/xselect.c
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2022-06-07 13:49:41 +0800
committerPo Lu <luangruo@yahoo.com>2022-06-07 13:49:41 +0800
commit3bdeedd8aca18e449bd3700c4ab65055fa183201 (patch)
tree226993cc2ebbfc9c2fb663192ca1754e6a385cc4 /src/xselect.c
parent6871e649b52e3a6154cfe2495372c4652688588f (diff)
downloademacs-3bdeedd8aca18e449bd3700c4ab65055fa183201.tar.gz
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.
Diffstat (limited to 'src/xselect.c')
-rw-r--r--src/xselect.c107
1 files changed, 78 insertions, 29 deletions
diff --git a/src/xselect.c b/src/xselect.c
index b920540620b..0271310d042 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;
}