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.
This commit is contained in:
parent
d7dc8c5fe4
commit
e161b5fa3c
3 changed files with 69 additions and 31 deletions
|
@ -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)))
|
||||
{
|
||||
|
|
35
src/xterm.c
35
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 ();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 *)
|
||||
|
|
Loading…
Add table
Reference in a new issue