Commit a9f737ee authored by Chong Yidong's avatar Chong Yidong
Browse files

Support X clipboard managers.

* lisp/select.el (xselect-convert-to-targets): Add MULTIPLE target to list.
(xselect-convert-to-save-targets): New function.

* src/xselect.c: Support for clipboard managers.
(Vselection_alist): Move to termhooks.h as terminal-local var.
(LOCAL_SELECTION): New macro.
(x_atom_to_symbol): Handle x_display_info_for_display fail case.
(symbol_to_x_atom): Remove gratuitous arg.
(x_handle_selection_request, lisp_data_to_selection_data)
(x_get_foreign_selection, Fx_register_dnd_atom): Callers changed.
(x_own_selection, x_get_local_selection, x_convert_selection): New
arg, specifying work frame.  Use terminal-local Vselection_alist.
(some_frame_on_display): Delete unused function.
(Fx_own_selection_internal, Fx_get_selection_internal)
(Fx_disown_selection_internal, Fx_selection_owner_p)
(Fx_selection_exists_p): New optional frame arg.
(frame_for_x_selection, Fx_clipboard_manager_save): New functions.
(x_handle_selection_clear): Don't treat other terminals with the
same keyboard specially.  Use the terminal-local Vselection_alist.
(x_clear_frame_selections): Use Frun_hook_with_args.

* src/termhooks.h (Vselection_alist): Make it terminal-local.

* src/terminal.c (create_terminal): Initialize it.

* src/xterm.c (x_term_init): Intern ATOM and CLIPBOARD_MANAGER atoms.

* src/xterm.h: Add support for those atoms.
parent be520aca
2011-05-27 Chong Yidong <cyd@stupidchicken.com>
* select.el: Support clipboard managers with built-in function
x-clipboard-manager-save, via delete-frame-functions and
kill-emacs-hook.
(xselect-convert-to-targets): Add MULTIPLE target to list.
(xselect-convert-to-save-targets): New function.
2011-05-27 Kenichi Handa <handa@m17n.org>
* mail/sendmail.el (mail-encode-header): Avoid double encoding by
......
......@@ -289,7 +289,9 @@ two markers or an overlay. Otherwise, it is nil."
(defun xselect-convert-to-targets (_selection _type _value)
;; return a vector of atoms, but remove duplicates first.
(let* ((all (cons 'TIMESTAMP (mapcar 'car selection-converter-alist)))
(let* ((all (cons 'TIMESTAMP
(cons 'MULTIPLE
(mapcar 'car selection-converter-alist))))
(rest all))
(while rest
(cond ((memq (car rest) (cdr rest))
......@@ -365,6 +367,12 @@ This function returns the string \"emacs\"."
(defun xselect-convert-to-identity (_selection _type value) ; used internally
(vector value))
;; Null target that tells clipboard managers we support SAVE_TARGETS
;; (see freedesktop.org Clipboard Manager spec).
(defun xselect-convert-to-save-targets (selection _type _value)
(when (eq selection 'CLIPBOARD)
'NULL))
(setq selection-converter-alist
'((TEXT . xselect-convert-to-string)
(COMPOUND_TEXT . xselect-convert-to-string)
......@@ -384,8 +392,13 @@ This function returns the string \"emacs\"."
(NAME . xselect-convert-to-name)
(ATOM . xselect-convert-to-atom)
(INTEGER . xselect-convert-to-integer)
(SAVE_TARGETS . xselect-convert-to-save-targets)
(_EMACS_INTERNAL . xselect-convert-to-identity)))
(when (fboundp 'x-clipboard-manager-save)
(add-hook 'delete-frame-functions 'x-clipboard-manager-save)
(add-hook 'kill-emacs-hook 'x-clipboard-manager-save))
(provide 'select)
;;; select.el ends here
2011-05-27 Chong Yidong <cyd@stupidchicken.com>
* termhooks.h (Vselection_alist): Make it terminal-local.
* terminal.c (create_terminal): Initialize it.
* xselect.c: Support for clipboard managers.
(Vselection_alist): Move to termhooks.h as terminal-local var.
(LOCAL_SELECTION): New macro.
(x_atom_to_symbol): Handle x_display_info_for_display fail case.
(symbol_to_x_atom): Remove gratuitous arg.
(x_handle_selection_request, lisp_data_to_selection_data)
(x_get_foreign_selection, Fx_register_dnd_atom): Callers changed.
(x_own_selection, x_get_local_selection, x_convert_selection): New
arg, specifying work frame. Use terminal-local Vselection_alist.
(some_frame_on_display): Delete unused function.
(Fx_own_selection_internal, Fx_get_selection_internal)
(Fx_disown_selection_internal, Fx_selection_owner_p)
(Fx_selection_exists_p): New optional frame arg.
(frame_for_x_selection, Fx_clipboard_manager_save): New functions.
(x_handle_selection_clear): Don't treat other terminals with the
same keyboard specially. Use the terminal-local Vselection_alist.
(x_clear_frame_selections): Use Frun_hook_with_args.
* xterm.c (x_term_init): Intern ATOM and CLIPBOARD_MANAGER atoms.
* xterm.h: Add support for those atoms.
2011-05-26 Chong Yidong <cyd@stupidchicken.com>
* xselect.c: ICCCM-compliant handling of MULTIPLE targets.
......
......@@ -335,6 +335,22 @@ struct terminal
the member terminal_coding. */
Lisp_Object charset_list;
/* This is an association list containing the X selections that
Emacs might own on this terminal. Each element has the form
(SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME)
SELECTION-NAME is a lisp symbol, whose name is the name of an X Atom.
SELECTION-VALUE is the value that emacs owns for that selection.
It may be any kind of Lisp object.
SELECTION-TIMESTAMP is the time at which emacs began owning this
selection, as a cons of two 16-bit numbers (making a 32 bit
time.)
FRAME is the frame for which we made the selection. If there is
an entry in this alist, then it can be assumed that Emacs owns
that selection.
The only (eq) parts of this list that are visible from Lisp are
the selection-values. */
Lisp_Object Vselection_alist;
/* All fields before `next_terminal' should be Lisp_Object and are traced
by the GC. All fields afterwards are ignored by the GC. */
......
......@@ -256,6 +256,8 @@ create_terminal (void)
setup_coding_system (terminal_coding, terminal->terminal_coding);
terminal->param_alist = Qnil;
terminal->charset_list = Qnil;
terminal->Vselection_alist = Qnil;
return terminal;
}
......
......@@ -46,27 +46,25 @@ struct prop_location;
struct selection_data;
static Lisp_Object x_atom_to_symbol (Display *dpy, Atom atom);
static Atom symbol_to_x_atom (struct x_display_info *, Display *,
Lisp_Object);
static void x_own_selection (Lisp_Object, Lisp_Object);
static Lisp_Object x_get_local_selection (Lisp_Object, Lisp_Object, int);
static Atom symbol_to_x_atom (struct x_display_info *, Lisp_Object);
static void x_own_selection (Lisp_Object, Lisp_Object, Lisp_Object);
static Lisp_Object x_get_local_selection (Lisp_Object, Lisp_Object, int,
struct x_display_info *);
static void x_decline_selection_request (struct input_event *);
static Lisp_Object x_selection_request_lisp_error (Lisp_Object);
static Lisp_Object queue_selection_requests_unwind (Lisp_Object);
static Lisp_Object some_frame_on_display (struct x_display_info *);
static Lisp_Object x_catch_errors_unwind (Lisp_Object);
static void x_reply_selection_request (struct input_event *, struct x_display_info *);
static int x_convert_selection (struct input_event *, Lisp_Object, Lisp_Object,
Atom, int);
Atom, int, struct x_display_info *);
static int waiting_for_other_props_on_window (Display *, Window);
static struct prop_location *expect_property_change (Display *, Window,
Atom, int);
static void unexpect_property_change (struct prop_location *);
static Lisp_Object wait_for_property_change_unwind (Lisp_Object);
static void wait_for_property_change (struct prop_location *);
static Lisp_Object x_get_foreign_selection (Lisp_Object,
Lisp_Object,
Lisp_Object);
static Lisp_Object x_get_foreign_selection (Lisp_Object, Lisp_Object,
Lisp_Object, Lisp_Object);
static void x_get_window_property (Display *, Window, Atom,
unsigned char **, int *,
Atom *, int *, unsigned long *, int);
......@@ -105,7 +103,7 @@ static Lisp_Object clean_local_selection_data (Lisp_Object);
static Lisp_Object QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP,
QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL,
QATOM_PAIR;
QATOM_PAIR, QCLIPBOARD_MANAGER, QSAVE_TARGETS;
static Lisp_Object QCOMPOUND_TEXT; /* This is a type of selection. */
static Lisp_Object QUTF8_STRING; /* This is a type of selection. */
......@@ -124,20 +122,8 @@ static Lisp_Object Qforeign_selection;
#define SELECTION_QUANTUM(dpy) ((XMaxRequestSize(dpy) << 2) - 100)
/* This is an association list whose elements are of the form
( SELECTION-NAME SELECTION-VALUE SELECTION-TIMESTAMP FRAME)
SELECTION-NAME is a lisp symbol, whose name is the name of an X Atom.
SELECTION-VALUE is the value that emacs owns for that selection.
It may be any kind of Lisp object.
SELECTION-TIMESTAMP is the time at which emacs began owning this selection,
as a cons of two 16-bit numbers (making a 32 bit time.)
FRAME is the frame for which we made the selection.
If there is an entry in this alist, then it can be assumed that Emacs owns
that selection.
The only (eq) parts of this list that are visible from Lisp are the
selection-values. */
static Lisp_Object Vselection_alist;
#define LOCAL_SELECTION(selection_symbol,dpyinfo) \
assq_no_quit (selection_symbol, dpyinfo->terminal->Vselection_alist)
/* Define a queue to save up SELECTION_REQUEST_EVENT events for later
......@@ -224,7 +210,7 @@ x_stop_queuing_selection_requests (void)
roundtrip whenever possible. */
static Atom
symbol_to_x_atom (struct x_display_info *dpyinfo, Display *display, Lisp_Object sym)
symbol_to_x_atom (struct x_display_info *dpyinfo, Lisp_Object sym)
{
Atom val;
if (NILP (sym)) return 0;
......@@ -248,7 +234,7 @@ symbol_to_x_atom (struct x_display_info *dpyinfo, Display *display, Lisp_Object
TRACE1 (" XInternAtom %s", SSDATA (SYMBOL_NAME (sym)));
BLOCK_INPUT;
val = XInternAtom (display, SSDATA (SYMBOL_NAME (sym)), False);
val = XInternAtom (dpyinfo->display, SSDATA (SYMBOL_NAME (sym)), False);
UNBLOCK_INPUT;
return val;
}
......@@ -282,6 +268,8 @@ x_atom_to_symbol (Display *dpy, Atom atom)
}
dpyinfo = x_display_info_for_display (dpy);
if (dpyinfo == NULL)
return Qnil;
if (atom == dpyinfo->Xatom_CLIPBOARD)
return QCLIPBOARD;
if (atom == dpyinfo->Xatom_TIMESTAMP)
......@@ -319,28 +307,20 @@ x_atom_to_symbol (Display *dpy, Atom atom)
}
/* Do protocol to assert ourself as a selection owner.
FRAME shall be the owner; it must be a valid X frame.
Update the Vselection_alist so that we can reply to later requests for
our selection. */
static void
x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value)
x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value,
Lisp_Object frame)
{
struct frame *sf = SELECTED_FRAME ();
Window selecting_window;
Display *display;
struct frame *f = XFRAME (frame);
Window selecting_window = FRAME_X_WINDOW (f);
struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
Display *display = dpyinfo->display;
Time timestamp = last_event_timestamp;
Atom selection_atom;
struct x_display_info *dpyinfo;
if (! FRAME_X_P (sf))
return;
selecting_window = FRAME_X_WINDOW (sf);
display = FRAME_X_DISPLAY (sf);
dpyinfo = FRAME_X_DISPLAY_INFO (sf);
CHECK_SYMBOL (selection_name);
selection_atom = symbol_to_x_atom (dpyinfo, display, selection_name);
Atom selection_atom = symbol_to_x_atom (dpyinfo, selection_name);
BLOCK_INPUT;
x_catch_errors (display);
......@@ -351,27 +331,26 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value)
/* Now update the local cache */
{
Lisp_Object selection_time;
Lisp_Object selection_data;
Lisp_Object prev_value;
selection_time = long_to_cons (timestamp);
selection_data = list4 (selection_name, selection_value,
selection_time, selected_frame);
prev_value = assq_no_quit (selection_name, Vselection_alist);
long_to_cons (timestamp), frame);
prev_value = LOCAL_SELECTION (selection_name, dpyinfo);
Vselection_alist = Fcons (selection_data, Vselection_alist);
dpyinfo->terminal->Vselection_alist
= Fcons (selection_data, dpyinfo->terminal->Vselection_alist);
/* If we already owned the selection, remove the old selection data.
Perhaps we should destructively modify it instead.
Don't use Fdelq as that may QUIT. */
/* If we already owned the selection, remove the old selection
data. Don't use Fdelq as that may QUIT. */
if (!NILP (prev_value))
{
Lisp_Object rest; /* we know it's not the CAR, so it's easy. */
for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
/* We know it's not the CAR, so it's easy. */
Lisp_Object rest = dpyinfo->terminal->Vselection_alist;
for (; CONSP (rest); rest = XCDR (rest))
if (EQ (prev_value, Fcar (XCDR (rest))))
{
XSETCDR (rest, Fcdr (XCDR (rest)));
XSETCDR (rest, XCDR (XCDR (rest)));
break;
}
}
......@@ -387,17 +366,18 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value)
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, int local_request)
x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
int local_request, struct x_display_info *dpyinfo)
{
Lisp_Object local_value;
Lisp_Object handler_fn, value, check;
int count;
local_value = assq_no_quit (selection_symbol, Vselection_alist);
local_value = LOCAL_SELECTION (selection_symbol, dpyinfo);
if (NILP (local_value)) return Qnil;
/* TIMESTAMP and MULTIPLE are special cases 'cause that's easiest. */
/* TIMESTAMP is a special case. */
if (EQ (target_type, QTIMESTAMP))
{
handler_fn = Qnil;
......@@ -585,23 +565,6 @@ queue_selection_requests_unwind (Lisp_Object tem)
return Qnil;
}
/* Return some frame whose display info is DPYINFO.
Return nil if there is none. */
static Lisp_Object
some_frame_on_display (struct x_display_info *dpyinfo)
{
Lisp_Object list, frame;
FOR_EACH_FRAME (list, frame)
{
if (FRAME_X_P (XFRAME (frame))
&& FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
return frame;
}
return Qnil;
}
/* Send the reply to a selection request event EVENT. */
......@@ -648,36 +611,36 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy
the conversion itself must be done in the same order. */
for (cs = converted_selections; cs; cs = cs->next)
{
if (cs->property != None)
if (cs->property == None)
continue;
bytes_remaining = cs->size * (cs->format / 8);
if (bytes_remaining <= max_bytes)
{
bytes_remaining = cs->size * (cs->format / 8);
if (bytes_remaining <= max_bytes)
{
/* Send all the data at once, with minimal handshaking. */
TRACE1 ("Sending all %d bytes", bytes_remaining);
XChangeProperty (display, window, cs->property,
cs->type, cs->format, PropModeReplace,
cs->data, cs->size);
}
else
{
/* Send an INCR tag to initiate incremental transfer. */
long value[1];
TRACE2 ("Start sending %d bytes incrementally (%s)",
bytes_remaining, XGetAtomName (display, cs->property));
cs->wait_object
= expect_property_change (display, window, cs->property,
PropertyDelete);
/* XChangeProperty expects an array of long even if long
is more than 32 bits. */
value[0] = bytes_remaining;
XChangeProperty (display, window, cs->property,
dpyinfo->Xatom_INCR, 32, PropModeReplace,
(unsigned char *) value, 1);
XSelectInput (display, window, PropertyChangeMask);
}
/* Send all the data at once, with minimal handshaking. */
TRACE1 ("Sending all %d bytes", bytes_remaining);
XChangeProperty (display, window, cs->property,
cs->type, cs->format, PropModeReplace,
cs->data, cs->size);
}
else
{
/* Send an INCR tag to initiate incremental transfer. */
long value[1];
TRACE2 ("Start sending %d bytes incrementally (%s)",
bytes_remaining, XGetAtomName (display, cs->property));
cs->wait_object
= expect_property_change (display, window, cs->property,
PropertyDelete);
/* XChangeProperty expects an array of long even if long is
more than 32 bits. */
value[0] = bytes_remaining;
XChangeProperty (display, window, cs->property,
dpyinfo->Xatom_INCR, 32, PropModeReplace,
(unsigned char *) value, 1);
XSelectInput (display, window, PropertyChangeMask);
}
}
......@@ -740,7 +703,8 @@ x_reply_selection_request (struct input_event *event, struct x_display_info *dpy
cs->type, cs->format, PropModeAppend,
cs->data, i);
bytes_remaining -= i * format_bytes;
cs->data += i * ((cs->format == 32) ? sizeof (long) : format_bytes);
cs->data += i * ((cs->format == 32) ? sizeof (long)
: format_bytes);
XFlush (display);
had_errors = x_had_errors_p (display);
UNBLOCK_INPUT;
......@@ -800,19 +764,20 @@ x_handle_selection_request (struct input_event *event)
Display *display = SELECTION_EVENT_DISPLAY (event);
struct x_display_info *dpyinfo = x_display_info_for_display (display);
Atom selection = SELECTION_EVENT_SELECTION (event);
Lisp_Object selection_symbol = x_atom_to_symbol (display, selection);
Atom target = SELECTION_EVENT_TARGET (event);
Lisp_Object target_symbol = x_atom_to_symbol (display, target);
Atom property = SELECTION_EVENT_PROPERTY (event);
Lisp_Object local_selection_data
= assq_no_quit (selection_symbol, Vselection_alist);
Lisp_Object local_selection_data;
int success = 0;
int count = SPECPDL_INDEX ();
GCPRO2 (local_selection_data, target_symbol);
if (!dpyinfo) goto DONE;
local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
/* Decline if we don't own any selections. */
if (NILP (local_selection_data)) goto DONE;
......@@ -846,8 +811,9 @@ x_handle_selection_request (struct input_event *event)
int j, nselections;
if (property == None) goto DONE;
multprop = x_get_window_property_as_lisp_data (display, requestor, property,
QMULTIPLE, selection);
multprop
= x_get_window_property_as_lisp_data (display, requestor, property,
QMULTIPLE, selection);
if (!VECTORP (multprop) || ASIZE (multprop) % 2)
goto DONE;
......@@ -858,12 +824,12 @@ x_handle_selection_request (struct input_event *event)
{
struct selection_data *cs = converted_selections + j;
Lisp_Object subtarget = AREF (multprop, 2*j);
Atom subproperty = symbol_to_x_atom (dpyinfo, display,
Atom subproperty = symbol_to_x_atom (dpyinfo,
AREF (multprop, 2*j+1));
if (subproperty != None)
x_convert_selection (event, selection_symbol, subtarget,
subproperty, 1);
subproperty, 1, dpyinfo);
}
success = 1;
}
......@@ -872,7 +838,8 @@ x_handle_selection_request (struct input_event *event)
if (property == None)
property = SELECTION_EVENT_TARGET (event);
success = x_convert_selection (event, selection_symbol,
target_symbol, property, 0);
target_symbol, property,
0, dpyinfo);
}
DONE:
......@@ -907,10 +874,9 @@ x_handle_selection_request (struct input_event *event)
Return 0 if the selection failed to convert, 1 otherwise. */
static int
x_convert_selection (struct input_event *event,
Lisp_Object selection_symbol,
Lisp_Object target_symbol,
Atom property, int for_multiple)
x_convert_selection (struct input_event *event, Lisp_Object selection_symbol,
Lisp_Object target_symbol, Atom property,
int for_multiple, struct x_display_info *dpyinfo)
{
struct gcpro gcpro1;
Lisp_Object lisp_selection;
......@@ -918,7 +884,8 @@ x_convert_selection (struct input_event *event,
GCPRO1 (lisp_selection);
lisp_selection
= x_get_local_selection (selection_symbol, target_symbol, 0);
= x_get_local_selection (selection_symbol, target_symbol,
0, dpyinfo);
/* A nil return value means we can't perform the conversion. */
if (NILP (lisp_selection)
......@@ -970,32 +937,14 @@ x_handle_selection_clear (struct input_event *event)
Lisp_Object selection_symbol, local_selection_data;
Time local_selection_time;
struct x_display_info *dpyinfo = x_display_info_for_display (display);
struct x_display_info *t_dpyinfo;
Lisp_Object Vselection_alist;
TRACE0 ("x_handle_selection_clear");
/* If the new selection owner is also Emacs,
don't clear the new selection. */
BLOCK_INPUT;
/* Check each display on the same terminal,
to see if this Emacs job now owns the selection
through that display. */
for (t_dpyinfo = x_display_list; t_dpyinfo; t_dpyinfo = t_dpyinfo->next)
if (t_dpyinfo->terminal->kboard == dpyinfo->terminal->kboard)
{
Window owner_window
= XGetSelectionOwner (t_dpyinfo->display, selection);
if (x_window_to_frame (t_dpyinfo, owner_window) != 0)
{
UNBLOCK_INPUT;
return;
}
}
UNBLOCK_INPUT;
if (!dpyinfo) return;
selection_symbol = x_atom_to_symbol (display, selection);
local_selection_data = assq_no_quit (selection_symbol, Vselection_alist);
local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
/* Well, we already believe that we don't own it, so that's just fine. */
if (NILP (local_selection_data)) return;
......@@ -1003,43 +952,38 @@ x_handle_selection_clear (struct input_event *event)
local_selection_time = (Time)
cons_to_long (XCAR (XCDR (XCDR (local_selection_data))));
/* This SelectionClear is for a selection that we no longer own, so we can
disregard it. (That is, we have reasserted the selection since this
request was generated.) */
/* We have reasserted the selection since this SelectionClear was
generated, so we can disregard it. */
if (changed_owner_time != CurrentTime
&& local_selection_time > changed_owner_time)
return;
/* Otherwise, we're really honest and truly being told to drop it.
Don't use Fdelq as that may QUIT;. */
if (EQ (local_selection_data, Fcar (Vselection_alist)))
Vselection_alist = Fcdr (Vselection_alist);
/* Otherwise, really clear. Don't use Fdelq as that may QUIT;. */
Vselection_alist = dpyinfo->terminal->Vselection_alist;
if (EQ (local_selection_data, CAR (Vselection_alist)))
Vselection_alist = XCDR (Vselection_alist);
else
{
Lisp_Object rest;
for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
if (EQ (local_selection_data, Fcar (XCDR (rest))))
if (EQ (local_selection_data, CAR (XCDR (rest))))
{
XSETCDR (rest, Fcdr (XCDR (rest)));
XSETCDR (rest, XCDR (XCDR (rest)));
break;
}
}
dpyinfo->terminal->Vselection_alist = Vselection_alist;
/* Let random lisp code notice that the selection has been stolen. */
/* Run the `x-lost-selection-functions' abnormal hook. */
{
Lisp_Object rest;
rest = Vx_lost_selection_functions;
if (!EQ (rest, Qunbound))
{
for (; CONSP (rest); rest = Fcdr (rest))
call1 (Fcar (rest), selection_symbol);
prepare_menu_bars ();
redisplay_preserve_echo_area (20);
}
Lisp_Object args[2];
args[0] = Vx_lost_selection_functions;
args[1] = selection_symbol;
Frun_hook_with_args (2, args);
}
prepare_menu_bars ();
redisplay_preserve_echo_area (20);
}
void
......@@ -1063,55 +1007,34 @@ x_clear_frame_selections (FRAME_PTR f)
{
Lisp_Object frame;
Lisp_Object rest;
struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
struct terminal *t = dpyinfo->terminal;
XSETFRAME (frame, f);
/* Otherwise, we're really honest and truly being told to drop it.
Don't use Fdelq as that may QUIT;. */
/* Delete elements from the beginning of Vselection_alist. */
while (!NILP (Vselection_alist)
&& EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (Vselection_alist)))))))
while (CONSP (t->Vselection_alist)
&& EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
{
/* Let random Lisp code notice that the selection has been stolen. */
Lisp_Object hooks, selection_symbol;
hooks = Vx_lost_selection_functions;
selection_symbol = Fcar (Fcar (Vselection_alist));
if (!EQ (hooks, Qunbound))
{
for (; CONSP (hooks); hooks = Fcdr (hooks))
call1 (Fcar (hooks), selection_symbol);
#if 0 /* This can crash when deleting a frame
from x_connection_closed. Anyway, it seems unnecessary;
something else should cause a redisplay. */
redisplay_preserve_echo_area (21);
#endif
}
/* Run the `x-lost-selection-functions' abnormal hook. */
Lisp_Object args[2];
args[0] = Vx_lost_selection_functions;
args[1] = Fcar (Fcar (t->Vselection_alist));
Frun_hook_with_args (2, args);
Vselection_alist = Fcdr (Vselection_alist);
t->Vselection_alist = XCDR (t->Vselection_alist);
}
/* Delete elements after the beginning of Vselection_alist. */
for (rest = Vselection_alist; CONSP (rest); rest = XCDR (rest))
if (EQ (frame, Fcar (Fcdr (Fcdr (Fcdr (Fcar (XCDR (rest))))))))
for (rest = t->Vselection_alist; CONSP (rest); rest = XCDR (rest))
if (CONSP (XCDR (rest))
&& EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))