/* X Selection processing for Emacs.
- Copyright (C) 1993-1997, 2000-2014 Free Software Foundation, Inc.
+ Copyright (C) 1993-1997, 2000-2016 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "lisp.h"
#include "xterm.h" /* for all of the X includes */
-#include "dispextern.h" /* frame.h seems to want this */
#include "frame.h" /* Need this to get the X window of selected_frame */
#include "blockinput.h"
-#include "character.h"
-#include "buffer.h"
-#include "process.h"
#include "termhooks.h"
#include "keyboard.h"
struct prop_location;
struct selection_data;
-static void x_decline_selection_request (struct input_event *);
-static bool x_convert_selection (struct input_event *, Lisp_Object,
- Lisp_Object, Atom, bool,
+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 *);
static bool waiting_for_other_props_on_window (Display *, Window);
static struct prop_location *expect_property_change (Display *, Window,
#define TRACE2(fmt, a0, a1) (void) 0
#endif
-
-static Lisp_Object QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP,
- QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL,
- 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. */
-
-static Lisp_Object Qcompound_text_with_extensions;
-
-static Lisp_Object Qforeign_selection;
-static Lisp_Object Qx_lost_selection_functions, Qx_sent_selection_functions;
-
/* Bytes needed to represent 'long' data. This is as per libX11; it
is not necessarily sizeof (long). */
#define X_LONG_SIZE 4
struct selection_event_queue
{
- struct input_event event;
+ struct selection_input_event event;
struct selection_event_queue *next;
};
static int x_queue_selection_requests;
+/* True if the input events are duplicates. */
+
+static bool
+selection_input_event_equal (struct selection_input_event *a,
+ struct selection_input_event *b)
+{
+ return (a->kind == b->kind && a->dpyinfo == b->dpyinfo
+ && a->requestor == b->requestor && a->selection == b->selection
+ && a->target == b->target && a->property == b->property
+ && a->time == b->time);
+}
+
/* Queue up an SELECTION_REQUEST_EVENT *EVENT, to be processed later. */
static void
-x_queue_event (struct input_event *event)
+x_queue_event (struct selection_input_event *event)
{
struct selection_event_queue *queue_tmp;
This only happens for large requests which uses the incremental protocol. */
for (queue_tmp = selection_queue; queue_tmp; queue_tmp = queue_tmp->next)
{
- if (!memcmp (&queue_tmp->event, event, sizeof (*event)))
+ if (selection_input_event_equal (event, &queue_tmp->event))
{
TRACE1 ("DECLINE DUP SELECTION EVENT %p", queue_tmp);
x_decline_selection_request (event);
x_catch_errors (display);
XSetSelectionOwner (display, selection_atom, selecting_window, timestamp);
x_check_errors (display, "Can't set selection: %s");
- x_uncatch_errors ();
+ x_uncatch_errors_after_check ();
unblock_input ();
/* Now update the local cache */
CHECK_SYMBOL (target_type);
handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist));
- /* gcpro is not needed here since nothing but HANDLER_FN
- is live, and that ought to be a symbol. */
if (!NILP (handler_fn))
value = call3 (handler_fn,
meaning we were unable to do what they wanted. */
static void
-x_decline_selection_request (struct input_event *event)
+x_decline_selection_request (struct selection_input_event *event)
{
XEvent reply_base;
XSelectionEvent *reply = &(reply_base.xselection);
/* This is the selection request currently being processed.
It is set to zero when the request is fully processed. */
-static struct input_event *x_selection_current_request;
+static struct selection_input_event *x_selection_current_request;
/* Display info in x_selection_request. */
static struct prop_location *property_change_wait_list;
+static void
+set_property_change_object (struct prop_location *location)
+{
+ /* Input must be blocked so we don't get the event before we set these. */
+ if (! input_blocked_p ())
+ emacs_abort ();
+ XSETCAR (property_change_reply, Qnil);
+ property_change_reply_object = location;
+}
+
\f
/* Send the reply to a selection request event EVENT. */
#endif /* TRACE_SELECTION */
static void
-x_reply_selection_request (struct input_event *event,
+x_reply_selection_request (struct selection_input_event *event,
struct x_display_info *dpyinfo)
{
XEvent reply_base;
{
int format_bytes = cs->format / 8;
bool had_errors_p = x_had_errors_p (display);
+
+ /* Must set this inside block_input (). unblock_input may read
+ events and setting property_change_reply in
+ wait_for_property_change is then too late. */
+ set_property_change_object (cs->wait_object);
unblock_input ();
bytes_remaining = cs->size;
: format_bytes);
XFlush (display);
had_errors_p = x_had_errors_p (display);
+ // See comment above about property_change_reply.
+ set_property_change_object (cs->wait_object);
unblock_input ();
if (had_errors_p) break;
This is called from keyboard.c when such an event is found in the queue. */
static void
-x_handle_selection_request (struct input_event *event)
+x_handle_selection_request (struct selection_input_event *event)
{
- struct gcpro gcpro1, gcpro2;
Time local_selection_time;
struct x_display_info *dpyinfo = SELECTION_EVENT_DPYINFO (event);
Lisp_Object local_selection_data;
bool success = false;
ptrdiff_t count = SPECPDL_INDEX ();
- GCPRO2 (local_selection_data, target_symbol);
if (!dpyinfo) goto DONE;
AREF (multprop, 2*j+1));
if (subproperty != None)
- x_convert_selection (event, selection_symbol, subtarget,
+ x_convert_selection (selection_symbol, subtarget,
subproperty, true, dpyinfo);
}
success = true;
{
if (property == None)
property = SELECTION_EVENT_TARGET (event);
- success = x_convert_selection (event, selection_symbol,
+ success = x_convert_selection (selection_symbol,
target_symbol, property,
false, dpyinfo);
}
/* Run the `x-sent-selection-functions' abnormal hook. */
if (!NILP (Vx_sent_selection_functions)
&& !EQ (Vx_sent_selection_functions, Qunbound))
- {
- Lisp_Object args[4];
- args[0] = Qx_sent_selection_functions;
- args[1] = selection_symbol;
- args[2] = target_symbol;
- args[3] = success ? Qt : Qnil;
- Frun_hook_with_args (4, args);
- }
+ CALLN (Frun_hook_with_args, Qx_sent_selection_functions,
+ selection_symbol, target_symbol, success ? Qt : Qnil);
unbind_to (count, Qnil);
- UNGCPRO;
}
/* Perform the requested selection conversion, and write the data to
Return true iff successful. */
static bool
-x_convert_selection (struct input_event *event, Lisp_Object selection_symbol,
+x_convert_selection (Lisp_Object selection_symbol,
Lisp_Object target_symbol, Atom property,
bool for_multiple, struct x_display_info *dpyinfo)
{
- struct gcpro gcpro1;
Lisp_Object lisp_selection;
struct selection_data *cs;
- GCPRO1 (lisp_selection);
lisp_selection
= x_get_local_selection (selection_symbol, target_symbol,
converted_selections = cs;
}
- UNGCPRO;
return false;
}
cs->next = converted_selections;
converted_selections = cs;
lisp_data_to_selection_data (dpyinfo, lisp_selection, cs);
- UNGCPRO;
return true;
}
\f
This is called from keyboard.c when such an event is found in the queue. */
static void
-x_handle_selection_clear (struct input_event *event)
+x_handle_selection_clear (struct selection_input_event *event)
{
Atom selection = SELECTION_EVENT_SELECTION (event);
Time changed_owner_time = SELECTION_EVENT_TIME (event);
tset_selection_alist (dpyinfo->terminal, Vselection_alist);
/* Run the `x-lost-selection-functions' abnormal hook. */
- {
- Lisp_Object args[2];
- args[0] = Qx_lost_selection_functions;
- args[1] = selection_symbol;
- Frun_hook_with_args (2, args);
- }
+ CALLN (Frun_hook_with_args, Qx_lost_selection_functions, selection_symbol);
redisplay_preserve_echo_area (20);
}
void
-x_handle_selection_event (struct input_event *event)
+x_handle_selection_event (struct selection_input_event *event)
{
TRACE0 ("x_handle_selection_event");
if (event->kind != SELECTION_REQUEST_EVENT)
&& EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist)))))))
{
/* Run the `x-lost-selection-functions' abnormal hook. */
- Lisp_Object args[2];
- args[0] = Qx_lost_selection_functions;
- args[1] = Fcar (Fcar (t->Vselection_alist));
- Frun_hook_with_args (2, args);
+ CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+ Fcar (Fcar (t->Vselection_alist)));
tset_selection_alist (t, XCDR (t->Vselection_alist));
}
if (CONSP (XCDR (rest))
&& EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest))))))))
{
- Lisp_Object args[2];
- args[0] = Qx_lost_selection_functions;
- args[1] = XCAR (XCAR (XCDR (rest)));
- Frun_hook_with_args (2, args);
+ CALLN (Frun_hook_with_args, Qx_lost_selection_functions,
+ XCAR (XCAR (XCDR (rest))));
XSETCDR (rest, XCDR (XCDR (rest)));
break;
}
{
ptrdiff_t count = SPECPDL_INDEX ();
- if (property_change_reply_object)
- emacs_abort ();
-
/* Make sure to do unexpect_property_change if we quit or err. */
record_unwind_protect_ptr (wait_for_property_change_unwind, location);
- XSETCAR (property_change_reply, Qnil);
- property_change_reply_object = location;
+ /* See comment in x_reply_selection_request about setting
+ property_change_reply. Do not do it here. */
/* If the event we are waiting for arrives beyond here, it will set
property_change_reply, because property_change_reply_object says so. */
XConvertSelection (display, selection_atom, type_atom, target_property,
requestor_window, requestor_time);
x_check_errors (display, "Can't convert selection: %s");
- x_uncatch_errors ();
+ x_uncatch_errors_after_check ();
/* Prepare to block until the reply has been read. */
reading_selection_window = requestor_window;
wait_object = expect_property_change (display, window, property,
PropertyNewValue);
XFlush (display);
+ // See comment in x_reply_selection_request about property_change_reply.
+ set_property_change_object (wait_object);
unblock_input ();
while (true)
XDeleteProperty (display, window, property);
wait_object = expect_property_change (display, window, property,
PropertyNewValue);
+ // See comment in x_reply_selection_request about property_change_reply.
+ set_property_change_object (wait_object);
XFlush (display);
unblock_input ();
Lisp_Object time_stamp, Lisp_Object terminal)
{
Lisp_Object val = Qnil;
- struct gcpro gcpro1, gcpro2;
struct frame *f = frame_for_x_selection (terminal);
- GCPRO2 (target_type, val); /* we store newly consed data into these */
CHECK_SYMBOL (selection_symbol);
CHECK_SYMBOL (target_type);
{
Lisp_Object frame;
XSETFRAME (frame, f);
- RETURN_UNGCPRO (x_get_foreign_selection (selection_symbol, target_type,
- time_stamp, frame));
+ return x_get_foreign_selection (selection_symbol, target_type,
+ time_stamp, frame);
}
if (CONSP (val) && SYMBOLP (XCAR (val)))
if (CONSP (val) && NILP (XCDR (val)))
val = XCAR (val);
}
- RETURN_UNGCPRO (clean_local_selection_data (val));
+ return clean_local_selection_data (val);
}
DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal,
{
Time timestamp;
Atom selection_atom;
- union {
- struct selection_input_event sie;
- struct input_event ie;
- } event;
+ struct selection_input_event event;
struct frame *f = frame_for_x_selection (terminal);
struct x_display_info *dpyinfo;
the selection owner to None. The NCD server does, the MIT Sun4 server
doesn't. So we synthesize one; this means we might get two, but
that's ok, because the second one won't have any effect. */
- SELECTION_EVENT_DPYINFO (&event.sie) = dpyinfo;
- SELECTION_EVENT_SELECTION (&event.sie) = selection_atom;
- SELECTION_EVENT_TIME (&event.sie) = timestamp;
- x_handle_selection_clear (&event.ie);
+ SELECTION_EVENT_DPYINFO (&event) = dpyinfo;
+ SELECTION_EVENT_SELECTION (&event) = selection_atom;
+ SELECTION_EVENT_TIME (&event) = timestamp;
+ x_handle_selection_clear (&event);
return Qt;
}
x_clipboard_manager_error_1 (Lisp_Object err)
{
AUTO_STRING (format, "X clipboard manager error: %s\n\
-If the problem persists, set `x-select-enable-clipboard-manager' to nil.");
- Fmessage (2, (Lisp_Object []) {format, CAR (CDR (err))});
+If the problem persists, set `%s' to nil.");
+ AUTO_STRING (varname, "x-select-enable-clipboard-manager");
+ CALLN (Fmessage, format, CAR (CDR (err)), varname);
return Qnil;
}
x_clipboard_manager_error_2 (Lisp_Object err)
{
fprintf (stderr, "Error saving to X clipboard manager.\n\
-If the problem persists, set `x-select-enable-clipboard-manager' \
-to nil.\n");
+If the problem persists, set '%s' \
+to nil.\n", "x-select-enable-clipboard-manager");
return Qnil;
}
local_frame = XCAR (XCDR (XCDR (XCDR (local_selection))));
if (FRAME_LIVE_P (XFRAME (local_frame)))
{
- AUTO_STRING (saving, "Saving clipboard to X clipboard manager...");
- Fmessage (1, &saving);
+ message ("Saving clipboard to X clipboard manager...");
internal_condition_case_1 (x_clipboard_manager_save, local_frame,
Qt, x_clipboard_manager_error_2);
}
{
Lisp_Object o = XCAR (iter);
- if (INTEGERP (o) || FLOATP (o) || CONSP (o))
+ if (NUMBERP (o) || CONSP (o))
{
if (CONSP (o)
&& RANGED_INTEGERP (X_LONG_MIN >> 16, XCAR (o), X_LONG_MAX >> 16)
Atom type, int format, unsigned long size)
{
ptrdiff_t format_bytes = format >> 3;
- if (PTRDIFF_MAX / format_bytes < size)
+ ptrdiff_t data_bytes;
+ if (INT_MULTIPLY_WRAPV (size, format_bytes, &data_bytes))
memory_full (SIZE_MAX);
return selection_data_to_lisp_data (FRAME_DISPLAY_INFO (f), data,
- size * format_bytes, type, format);
+ data_bytes, type, format);
}
DEFUN ("x-get-atom-name", Fx_get_atom_name,
x_catch_errors (dpy);
name = atom ? XGetAtomName (dpy, atom) : empty;
had_errors_p = x_had_errors_p (dpy);
- x_uncatch_errors ();
+ x_uncatch_errors_after_check ();
if (!had_errors_p)
ret = build_string (name);
else
error ("DEST as a string must be one of PointerWindow or InputFocus");
}
- else if (INTEGERP (dest) || FLOATP (dest) || CONSP (dest))
+ else if (NUMBERP (dest) || CONSP (dest))
CONS_TO_INTEGER (dest, Window, wdest);
else
error ("DEST must be a frame, nil, string, number or cons");
DEFSYM (QCLIPBOARD, "CLIPBOARD");
DEFSYM (QTIMESTAMP, "TIMESTAMP");
DEFSYM (QTEXT, "TEXT");
+
+ /* These are types of selection. */
DEFSYM (QCOMPOUND_TEXT, "COMPOUND_TEXT");
DEFSYM (QUTF8_STRING, "UTF8_STRING");
+
DEFSYM (QDELETE, "DELETE");
DEFSYM (QMULTIPLE, "MULTIPLE");
DEFSYM (QINCR, "INCR");
DEFSYM (QEMACS_TMP, "_EMACS_TMP_");
DEFSYM (QTARGETS, "TARGETS");
DEFSYM (QATOM, "ATOM");
- DEFSYM (QATOM_PAIR, "ATOM_PAIR");
DEFSYM (QCLIPBOARD_MANAGER, "CLIPBOARD_MANAGER");
DEFSYM (QSAVE_TARGETS, "SAVE_TARGETS");
DEFSYM (QNULL, "NULL");
- DEFSYM (Qcompound_text_with_extensions, "compound-text-with-extensions");
DEFSYM (Qforeign_selection, "foreign-selection");
DEFSYM (Qx_lost_selection_functions, "x-lost-selection-functions");
DEFSYM (Qx_sent_selection_functions, "x-sent-selection-functions");