diff options
author | Po Lu <luangruo@yahoo.com> | 2022-06-30 09:45:49 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2022-06-30 09:46:41 +0800 |
commit | e161b5fa3c8241a34961b378501247fb3978e6dc (patch) | |
tree | 43d3ca65518a6041a149622a104d0fc7a9b2beaf | |
parent | d7dc8c5fe4ac1735a7565473621d7504cc5ef089 (diff) | |
download | emacs-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.c | 62 | ||||
-rw-r--r-- | src/xterm.c | 35 | ||||
-rw-r--r-- | src/xterm.h | 3 |
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 *) |