Try to save selections from being disowned during frame deletion

* lisp/cus-start.el (standard): Add
`x-auto-preserve-selections'.
* src/xselect.c (x_clear_frame_selections): Collect deleted
selections into a variable and preserve them.
* src/xterm.c (x_preserve_selections): New function.
(syms_of_xterm): New variable `x-auto-preserve-selections'.
* src/xterm.h: Update prototypes.
This commit is contained in:
Po Lu 2022-07-12 10:47:23 +08:00
parent 7ac313ea87
commit 86d128c6c3
5 changed files with 93 additions and 7 deletions

View file

@ -2448,6 +2448,15 @@ be kept aligned with the buffer contents when the user switches
This minor mode makes Emacs deactivate the mark in all buffers when
the primary selection is obtained by another program.
---
** On X, Emacs will try to preserve selection ownership when a frame is deleted.
This means that if you make Emacs the owner of a selection, such as by
selecting some text into the clipboard or primary selection, and then
delete the current frame, you will still be able to insert the
contents of that selection into other programs as long as another
frame is open on the same display. This behavior can be disabled by
setting the variable 'x-auto-preserve-selections' to nil.
+++
** New predicate 'char-uppercase-p'.
This returns non-nil if its argument its an uppercase character.

View file

@ -834,6 +834,7 @@ since it could result in memory overflow and make Emacs crash."
(x-scroll-event-delta-factor mouse float "29.1")
(x-gtk-use-native-input keyboard boolean "29.1")
(x-dnd-disable-motif-drag dnd boolean "29.1")
(x-auto-preserve-selections x boolean "29.1")
;; xselect.c
(x-select-enable-clipboard-manager killing boolean "24.1")
;; xsettings.c
@ -874,6 +875,8 @@ since it could result in memory overflow and make Emacs crash."
(equal "x-scroll-event-delta-factor"
(symbol-name symbol))
(equal "x-dnd-disable-motif-drag"
(symbol-name symbol))
(equal "x-auto-preserve-selections"
(symbol-name symbol)))
(featurep 'x))
((string-match "\\`x-" (symbol-name symbol))

View file

@ -1091,20 +1091,23 @@ x_handle_selection_event (struct selection_input_event *event)
void
x_clear_frame_selections (struct frame *f)
{
Lisp_Object frame;
Lisp_Object rest;
Lisp_Object frame, rest, lost;
struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
struct terminal *t = dpyinfo->terminal;
XSETFRAME (frame, f);
lost = Qnil;
/* Delete elements from the beginning of Vselection_alist. */
while (CONSP (t->Vselection_alist)
&& EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
{
/* Run the `x-lost-selection-functions' abnormal hook. */
CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
Fcar (Fcar (t->Vselection_alist)));
if (!x_auto_preserve_selections)
/* Run the `x-lost-selection-functions' abnormal hook. */
CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
Fcar (Fcar (t->Vselection_alist)));
else
lost = Fcons (Fcar (t->Vselection_alist), lost);
tset_selection_alist (t, XCDR (t->Vselection_alist));
}
@ -1114,11 +1117,18 @@ x_clear_frame_selections (struct frame *f)
if (CONSP (XCDR (rest))
&& EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
{
CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
XCAR (XCAR (XCDR (rest))));
if (!x_auto_preserve_selections)
CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
XCAR (XCAR (XCDR (rest))));
else
lost = Fcons (XCAR (XCDR (rest)), lost);
XSETCDR (rest, XCDR (XCDR (rest)));
break;
}
if (x_auto_preserve_selections)
x_preserve_selections (dpyinfo, lost);
}
/* True if any properties for DISPLAY and WINDOW

View file

@ -27951,6 +27951,62 @@ x_uncatch_errors_for_lisp (struct x_display_info *dpyinfo)
x_stop_ignoring_errors (dpyinfo);
}
/* Preserve the selections in LOST in another frame on DPYINFO. LOST
is a list of local selections that were lost, due to their frame
being deleted. */
void
x_preserve_selections (struct x_display_info *dpyinfo, Lisp_Object lost)
{
Lisp_Object tail, frame, new_owner, tem;
Time timestamp;
Window owner;
new_owner = Qnil;
FOR_EACH_FRAME (tail, frame)
{
if (FRAME_X_P (XFRAME (frame))
&& FRAME_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
{
new_owner = frame;
break;
}
}
tail = lost;
FOR_EACH_TAIL_SAFE (tail)
{
tem = XCAR (tail);
/* The selection is really lost (since we cannot find a new
owner), so run the appropriate hooks. */
if (NILP (new_owner))
CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
XCAR (tem));
else
{
CONS_TO_INTEGER (XCAR (XCDR (XCDR (tem))), Time, timestamp);
/* This shouldn't be able to signal any errors, despite the
call to `x_check_errors' inside. */
x_own_selection (XCAR (tem), XCAR (XCDR (tem)),
new_owner, XCAR (XCDR (XCDR (XCDR (XCDR (tem))))),
timestamp);
/* Now check if we still don't own that selection, which can
happen if another program set itself as the owner. */
owner = XGetSelectionOwner (dpyinfo->display,
symbol_to_x_atom (dpyinfo, XCAR (tem)));
if (owner != FRAME_X_WINDOW (XFRAME (new_owner)))
CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
XCAR (tem));
}
}
}
void
syms_of_xterm (void)
{
@ -28265,4 +28321,11 @@ reply from the X server, and signal any errors that occurred while
executing the protocol request. Otherwise, errors will be silently
ignored without waiting, which is generally faster. */);
x_fast_protocol_requests = false;
DEFVAR_BOOL ("x-auto-preserve-selections", x_auto_preserve_selections,
doc: /* Whether or not to transfer selection ownership when deleting a frame.
When non-nil, deleting a frame that is currently the owner of a
selection will cause its ownership to be transferred to another frame
on the same display. */);
x_auto_preserve_selections = true;
}

View file

@ -1643,6 +1643,7 @@ extern void xic_set_statusarea (struct frame *);
extern void xic_set_xfontset (struct frame *, const char *);
extern bool x_defined_color (struct frame *, const char *, Emacs_Color *,
bool, bool);
extern void x_preserve_selections (struct x_display_info *, Lisp_Object);
#ifdef HAVE_X_I18N
extern void free_frame_xic (struct frame *);
# if defined HAVE_X_WINDOWS && defined USE_X_TOOLKIT