summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPo Lu <luangruo@yahoo.com>2022-06-30 09:45:49 +0800
committerPo Lu <luangruo@yahoo.com>2022-06-30 09:46:41 +0800
commite161b5fa3c8241a34961b378501247fb3978e6dc (patch)
tree43d3ca65518a6041a149622a104d0fc7a9b2beaf
parentd7dc8c5fe4ac1735a7565473621d7504cc5ef089 (diff)
downloademacs-e161b5fa3c8241a34961b378501247fb3978e6dc.tar.gz
Fix preservation of the original value of PRIMARY after dropping on xterm
* src/xselect.c (x_own_selection): New arg `dnd_data'. Record it. (x_get_local_selection, x_handle_selection_request) (x_convert_selection): Convert the DND data instead if the situation warrants. (Fx_own_selection_internal, Fx_get_selection_internal) (Fx_get_local_selection): Update calls to x_get_local_selection. * src/xterm.c (x_dnd_do_unsupported_drop): If obtaining selection ownership failed, return. Record DND value and preserve the current value of PRIMARY, if it exists. * src/xterm.h: Update prototypes.
-rw-r--r--src/xselect.c62
-rw-r--r--src/xterm.c35
-rw-r--r--src/xterm.h3
3 files changed, 69 insertions, 31 deletions
diff --git a/src/xselect.c b/src/xselect.c
index 5796b0034a0..41fa837c5a4 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -47,7 +47,7 @@ struct selection_data;
static void x_decline_selection_request (struct selection_input_event *);
static bool x_convert_selection (Lisp_Object, Lisp_Object, Atom, bool,
- struct x_display_info *);
+ struct x_display_info *, bool);
static bool waiting_for_other_props_on_window (Display *, Window);
static struct prop_location *expect_property_change (Display *, Window,
Atom, int);
@@ -250,20 +250,26 @@ x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom)
/* Do protocol to assert ourself as a selection owner.
FRAME shall be the owner; it must be a valid X frame.
+ TIMESTAMP should be the timestamp where selection ownership will be
+ assumed.
+ DND_DATA is the local value that will be used for selection requests
+ with `pending_dnd_time'.
Update the Vselection_alist so that we can reply to later requests for
our selection. */
void
x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
- Lisp_Object frame)
+ Lisp_Object frame, Lisp_Object dnd_data, Time timestamp)
{
struct frame *f = XFRAME (frame);
Window selecting_window = FRAME_X_WINDOW (f);
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
Display *display = dpyinfo->display;
- Time timestamp = dpyinfo->last_user_time;
Atom selection_atom = symbol_to_x_atom (dpyinfo, selection_name);
+ if (!timestamp)
+ timestamp = dpyinfo->last_user_time;
+
block_input ();
x_catch_errors (display);
XSetSelectionOwner (display, selection_atom, selecting_window, timestamp);
@@ -276,8 +282,9 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
Lisp_Object selection_data;
Lisp_Object prev_value;
- selection_data = list4 (selection_name, selection_value,
- INT_TO_INTEGER (timestamp), frame);
+ selection_data = list5 (selection_name, selection_value,
+ INT_TO_INTEGER (timestamp), frame,
+ dnd_data);
prev_value = LOCAL_SELECTION (selection_name, dpyinfo);
tset_selection_alist
@@ -310,12 +317,15 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
If LOCAL_VALUE is non-nil, use it as the local copy. Also allow
quitting in that case, and let DPYINFO be NULL.
+ If NEED_ALTERNATE is true, use the drag-and-drop local value
+ instead.
+
This calls random Lisp code, and may signal or gc. */
static Lisp_Object
x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
bool local_request, struct x_display_info *dpyinfo,
- Lisp_Object local_value)
+ Lisp_Object local_value, bool need_alternate)
{
Lisp_Object tem;
Lisp_Object handler_fn, value, check;
@@ -354,7 +364,10 @@ x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
if (CONSP (handler_fn))
handler_fn = XCDR (handler_fn);
- tem = XCAR (XCDR (local_value));
+ if (!need_alternate)
+ tem = XCAR (XCDR (local_value));
+ else
+ tem = XCAR (XCDR (XCDR (XCDR (XCDR (local_value)))));
if (STRINGP (tem))
{
@@ -788,7 +801,7 @@ x_handle_selection_request (struct selection_input_event *event)
Lisp_Object local_selection_data;
bool success = false;
specpdl_ref count = SPECPDL_INDEX ();
- bool pushed;
+ bool pushed, use_alternate;
Lisp_Object alias, tem;
alias = Vx_selection_alias_alist;
@@ -814,14 +827,6 @@ x_handle_selection_request (struct selection_input_event *event)
if (!dpyinfo)
goto REALLY_DONE;
- /* This is how the XDND protocol recommends dropping text onto a
- target that doesn't support XDND. */
- if (SELECTION_EVENT_TIME (event) == pending_dnd_time + 1
- || SELECTION_EVENT_TIME (event) == pending_dnd_time + 2)
- /* Always reply with the contents of PRIMARY, since that's where
- the selection data is. */
- selection_symbol = QPRIMARY;
-
local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
/* Decline if we don't own any selections. */
@@ -834,6 +839,14 @@ x_handle_selection_request (struct selection_input_event *event)
&& local_selection_time > SELECTION_EVENT_TIME (event))
goto DONE;
+ use_alternate = false;
+
+ /* This is how the XDND protocol recommends dropping text onto a
+ target that doesn't support XDND. */
+ if (SELECTION_EVENT_TIME (event) == pending_dnd_time + 1
+ || SELECTION_EVENT_TIME (event) == pending_dnd_time + 2)
+ use_alternate = true;
+
block_input ();
pushed = true;
x_push_current_selection_request (event, dpyinfo);
@@ -874,7 +887,8 @@ x_handle_selection_request (struct selection_input_event *event)
if (subproperty != None)
subsuccess = x_convert_selection (selection_symbol, subtarget,
- subproperty, true, dpyinfo);
+ subproperty, true, dpyinfo,
+ use_alternate);
if (!subsuccess)
ASET (multprop, 2*j+1, Qnil);
}
@@ -891,7 +905,8 @@ x_handle_selection_request (struct selection_input_event *event)
property = SELECTION_EVENT_TARGET (event);
success = x_convert_selection (selection_symbol,
target_symbol, property,
- false, dpyinfo);
+ false, dpyinfo,
+ use_alternate);
}
DONE:
@@ -926,7 +941,8 @@ x_handle_selection_request (struct selection_input_event *event)
static bool
x_convert_selection (Lisp_Object selection_symbol,
Lisp_Object target_symbol, Atom property,
- bool for_multiple, struct x_display_info *dpyinfo)
+ bool for_multiple, struct x_display_info *dpyinfo,
+ bool use_alternate)
{
Lisp_Object lisp_selection;
struct selection_data *cs;
@@ -934,7 +950,7 @@ x_convert_selection (Lisp_Object selection_symbol,
lisp_selection
= x_get_local_selection (selection_symbol, target_symbol,
- false, dpyinfo, Qnil);
+ false, dpyinfo, Qnil, use_alternate);
frame = selection_request_stack;
@@ -2100,7 +2116,7 @@ On Nextstep, FRAME is unused. */)
CHECK_SYMBOL (selection);
if (NILP (value)) error ("VALUE may not be nil");
- x_own_selection (selection, value, frame);
+ x_own_selection (selection, value, frame, Qnil, 0);
return value;
}
@@ -2150,7 +2166,7 @@ On Nextstep, TIME-STAMP and TERMINAL are unused. */)
}
val = x_get_local_selection (selection_symbol, target_type, true,
- FRAME_DISPLAY_INFO (f), Qnil);
+ FRAME_DISPLAY_INFO (f), Qnil, false);
if (NILP (val) && FRAME_LIVE_P (f))
{
@@ -2318,7 +2334,7 @@ run. */)
check_window_system (decode_live_frame (frame));
result = x_get_local_selection (name, target, true,
- NULL, value);
+ NULL, value, false);
if (CONSP (result) && SYMBOLP (XCAR (result)))
{
diff --git a/src/xterm.c b/src/xterm.c
index 76da1064eb9..9d260ded831 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -3798,7 +3798,14 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
{
XEvent event;
int dest_x, dest_y;
- Window child_return, child;
+ Window child_return, child, owner;
+ Lisp_Object current_value;
+ struct frame *f;
+
+ f = decode_window_system_frame (frame);
+
+ if (NILP (value))
+ return;
event.xbutton.serial = 0;
event.xbutton.send_event = True;
@@ -3806,7 +3813,6 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
event.xbutton.root = dpyinfo->root_window;
event.xbutton.x_root = root_x;
event.xbutton.y_root = root_y;
-
x_catch_errors (dpyinfo->display);
child = dpyinfo->root_window;
@@ -3819,11 +3825,25 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
&& child_return != None)
child = child_return;
- if (CONSP (value))
- x_own_selection (QPRIMARY, Fnth (make_fixnum (1), value),
- frame);
- else
- error ("Lost ownership of XdndSelection");
+ if (!CONSP (value))
+ goto cancel;
+
+ current_value = assq_no_quit (QPRIMARY,
+ dpyinfo->terminal->Vselection_alist);
+
+ if (!NILP (current_value))
+ current_value = XCAR (XCDR (current_value));
+
+ x_own_selection (QPRIMARY, current_value, frame,
+ XCAR (XCDR (value)), before);
+
+ owner = XGetSelectionOwner (dpyinfo->display, XA_PRIMARY);
+
+ /* If we didn't successfully obtain selection ownership, refrain
+ from generating events that will insert something else. */
+
+ if (owner != FRAME_X_WINDOW (f))
+ goto cancel;
event.xbutton.window = child;
event.xbutton.subwindow = None;
@@ -3847,6 +3867,7 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
XSendEvent (dpyinfo->display, child,
True, ButtonReleaseMask, &event);
+ cancel:
x_uncatch_errors ();
}
diff --git a/src/xterm.h b/src/xterm.h
index f7b93529cbd..76d35aaf34f 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -1600,7 +1600,8 @@ extern void x_clipboard_manager_save_all (void);
extern Lisp_Object x_timestamp_for_selection (struct x_display_info *,
Lisp_Object);
extern void x_set_pending_dnd_time (Time);
-extern void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object);
+extern void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object,
+ Lisp_Object, Time);
extern Atom x_intern_cached_atom (struct x_display_info *, const char *,
bool);
extern char *x_get_atom_name (struct x_display_info *, Atom, bool *)