/* X Selection processing for Emacs.
- Copyright (C) 1993-1997, 2000-2015 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 int x_convert_selection (struct input_event *, Lisp_Object, Lisp_Object,
- Atom, int, struct x_display_info *);
-static int waiting_for_other_props_on_window (Display *, Window);
+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,
Atom, int);
static void unexpect_property_change (struct prop_location *);
static void wait_for_property_change (struct prop_location *);
-static Lisp_Object x_get_window_property_as_lisp_data (Display *,
+static Lisp_Object x_get_window_property_as_lisp_data (struct x_display_info *,
Window, Atom,
Lisp_Object, Atom);
-static Lisp_Object selection_data_to_lisp_data (Display *,
+static Lisp_Object selection_data_to_lisp_data (struct x_display_info *,
const unsigned char *,
ptrdiff_t, Atom, int);
-static void lisp_data_to_selection_data (Display *, Lisp_Object,
- unsigned char **, Atom *,
- ptrdiff_t *, int *, int *);
+static void lisp_data_to_selection_data (struct x_display_info *, Lisp_Object,
+ struct selection_data *);
/* Printing traces to stderr. */
#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
-/* Extreme 'short' and 'long' values suitable for libX11. */
-#define X_SHRT_MAX 0x7fff
-#define X_SHRT_MIN (-1 - X_SHRT_MAX)
-#define X_LONG_MAX 0x7fffffff
-#define X_LONG_MIN (-1 - X_LONG_MAX)
-#define X_ULONG_MAX 0xffffffffUL
-
/* If this is a smaller number than the max-request-size of the display,
emacs will use INCR selection transfer when the selection is larger
than this. The max-request-size is usually around 64k, so if you want
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);
and calls to intern whenever possible. */
static Lisp_Object
-x_atom_to_symbol (Display *dpy, Atom atom)
+x_atom_to_symbol (struct x_display_info *dpyinfo, Atom atom)
{
- struct x_display_info *dpyinfo;
char *str;
Lisp_Object val;
return QATOM;
}
- dpyinfo = x_display_info_for_display (dpy);
if (dpyinfo == NULL)
return Qnil;
if (atom == dpyinfo->Xatom_CLIPBOARD)
return QNULL;
block_input ();
- str = XGetAtomName (dpy, atom);
+ str = XGetAtomName (dpyinfo->display, atom);
unblock_input ();
TRACE1 ("XGetAtomName --> %s", str);
if (! str) return Qnil;
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 */
static Lisp_Object
x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
- int local_request, struct x_display_info *dpyinfo)
+ bool local_request, struct x_display_info *dpyinfo)
{
Lisp_Object local_value;
Lisp_Object handler_fn, value, check;
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);
died in the meantime. Handle that case. */
block_input ();
x_catch_errors (reply->display);
- XSendEvent (reply->display, reply->requestor, False, 0L, &reply_base);
+ XSendEvent (reply->display, reply->requestor, False, 0, &reply_base);
XFlush (reply->display);
x_uncatch_errors ();
unblock_input ();
/* 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. */
ptrdiff_t size;
int format;
Atom type;
- int nofree;
+ bool nofree;
Atom property;
/* This can be set to non-NULL during x_reply_selection_request, if
the selection is waiting for an INCR transfer to complete. Don't
for (cs = converted_selections; cs; cs = next)
{
next = cs->next;
- if (cs->nofree == 0 && cs->data)
+ if (! cs->nofree && cs->data)
xfree (cs->data);
xfree (cs);
}
Window window;
Atom property;
int desired_state;
- int arrived;
+ bool arrived;
struct prop_location *next;
};
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;
}
/* Now issue the SelectionNotify event. */
- XSendEvent (display, window, False, 0L, &reply_base);
+ XSendEvent (display, window, False, 0, &reply_base);
XFlush (display);
#ifdef TRACE_SELECTION
{
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;
requestor that we're done. */
block_input ();
if (! waiting_for_other_props_on_window (display, window))
- XSelectInput (display, window, 0L);
+ XSelectInput (display, window, 0);
TRACE1 ("Set %s to a 0-length chunk to indicate EOF",
XGetAtomName (display, cs->property));
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;
- Display *display = SELECTION_EVENT_DISPLAY (event);
- struct x_display_info *dpyinfo = x_display_info_for_display (display);
+ struct x_display_info *dpyinfo = SELECTION_EVENT_DPYINFO (event);
Atom selection = SELECTION_EVENT_SELECTION (event);
- Lisp_Object selection_symbol = x_atom_to_symbol (display, selection);
+ Lisp_Object selection_symbol = x_atom_to_symbol (dpyinfo, selection);
Atom target = SELECTION_EVENT_TARGET (event);
- Lisp_Object target_symbol = x_atom_to_symbol (display, target);
+ Lisp_Object target_symbol = x_atom_to_symbol (dpyinfo, target);
Atom property = SELECTION_EVENT_PROPERTY (event);
Lisp_Object local_selection_data;
- int success = 0;
+ bool success = false;
ptrdiff_t count = SPECPDL_INDEX ();
- GCPRO2 (local_selection_data, target_symbol);
if (!dpyinfo) goto DONE;
if (property == None) goto DONE;
multprop
- = x_get_window_property_as_lisp_data (display, requestor, property,
+ = x_get_window_property_as_lisp_data (dpyinfo, requestor, property,
QMULTIPLE, selection);
if (!VECTORP (multprop) || ASIZE (multprop) % 2)
AREF (multprop, 2*j+1));
if (subproperty != None)
- x_convert_selection (event, selection_symbol, subtarget,
- subproperty, 1, dpyinfo);
+ x_convert_selection (selection_symbol, subtarget,
+ subproperty, true, dpyinfo);
}
- success = 1;
+ success = true;
}
else
{
if (property == None)
property = SELECTION_EVENT_TARGET (event);
- success = x_convert_selection (event, selection_symbol,
+ success = x_convert_selection (selection_symbol,
target_symbol, property,
- 0, dpyinfo);
+ false, dpyinfo);
}
DONE:
/* 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
the converted_selections linked list, where it can be accessed by
- x_reply_selection_request. If FOR_MULTIPLE is non-zero, write out
+ x_reply_selection_request. If FOR_MULTIPLE, write out
the data even if conversion fails, using conversion_fail_tag.
- Return 0 if the selection failed to convert, 1 otherwise. */
+ Return true iff successful. */
-static int
-x_convert_selection (struct input_event *event, Lisp_Object selection_symbol,
+static bool
+x_convert_selection (Lisp_Object selection_symbol,
Lisp_Object target_symbol, Atom property,
- int for_multiple, struct x_display_info *dpyinfo)
+ 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,
- 0, dpyinfo);
+ false, dpyinfo);
/* A nil return value means we can't perform the conversion. */
if (NILP (lisp_selection)
cs->size = 1;
cs->format = 32;
cs->type = XA_ATOM;
- cs->nofree = 1;
+ cs->nofree = true;
cs->property = property;
cs->wait_object = NULL;
cs->next = converted_selections;
converted_selections = cs;
}
- UNGCPRO;
- return 0;
+ return false;
}
/* Otherwise, record the converted selection to binary. */
cs = xmalloc (sizeof *cs);
cs->data = NULL;
- cs->nofree = 1;
+ cs->nofree = true;
cs->property = property;
cs->wait_object = NULL;
cs->next = converted_selections;
converted_selections = cs;
- lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event),
- lisp_selection,
- &(cs->data), &(cs->type),
- &(cs->size), &(cs->format),
- &(cs->nofree));
- UNGCPRO;
- return 1;
+ lisp_data_to_selection_data (dpyinfo, lisp_selection, cs);
+ return true;
}
\f
/* Handle a SelectionClear event EVENT, which indicates that some
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)
{
- Display *display = SELECTION_EVENT_DISPLAY (event);
Atom selection = SELECTION_EVENT_SELECTION (event);
Time changed_owner_time = SELECTION_EVENT_TIME (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 *dpyinfo = SELECTION_EVENT_DPYINFO (event);
Lisp_Object Vselection_alist;
TRACE0 ("x_handle_selection_clear");
if (!dpyinfo) return;
- selection_symbol = x_atom_to_symbol (display, selection);
+ selection_symbol = x_atom_to_symbol (dpyinfo, selection);
local_selection_data = LOCAL_SELECTION (selection_symbol, dpyinfo);
/* Well, we already believe that we don't own it, so that's just fine. */
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;
}
}
\f
-/* Nonzero if any properties for DISPLAY and WINDOW
+/* True if any properties for DISPLAY and WINDOW
are on the list of what we are waiting for. */
-static int
+static bool
waiting_for_other_props_on_window (Display *display, Window window)
{
- struct prop_location *rest = property_change_wait_list;
- while (rest)
- if (rest->display == display && rest->window == window)
- return 1;
- else
- rest = rest->next;
- return 0;
+ for (struct prop_location *p = property_change_wait_list; p; p = p->next)
+ if (p->display == display && p->window == window)
+ return true;
+ return false;
}
/* Add an entry to the list of property changes we are waiting for.
pl->property = property;
pl->desired_state = state;
pl->next = property_change_wait_list;
- pl->arrived = 0;
+ pl->arrived = false;
property_change_wait_list = pl;
return pl;
}
static void
unexpect_property_change (struct prop_location *location)
{
- struct prop_location *prev = 0, *rest = property_change_wait_list;
- while (rest)
+ struct prop_location *prop, **pprev = &property_change_wait_list;
+
+ for (prop = property_change_wait_list; prop; prop = *pprev)
{
- if (rest == location)
+ if (prop == location)
{
- if (prev)
- prev->next = rest->next;
- else
- property_change_wait_list = rest->next;
- xfree (rest);
- return;
+ *pprev = prop->next;
+ xfree (prop);
+ break;
}
- prev = rest;
- rest = rest->next;
+ else
+ pprev = &prop->next;
}
}
{
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. */
EMACS_INT secs = timeout / 1000;
int nsecs = (timeout % 1000) * 1000000;
TRACE2 (" Waiting %"pI"d secs, %d nsecs", secs, nsecs);
- wait_reading_process_output (secs, nsecs, 0, 0,
+ wait_reading_process_output (secs, nsecs, 0, false,
property_change_reply, NULL, 0);
if (NILP (XCAR (property_change_reply)))
(event->state == PropertyDelete ? "deletion" : "change"),
XGetAtomName (event->display, event->atom));
- rest->arrived = 1;
+ rest->arrived = true;
/* If this is the one wait_for_property_change is waiting for,
tell it to wake up. */
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;
during this time. In fact, the SAVE_TARGETS mechanism requires
us to handle a clipboard manager's requests before it returns
SelectionNotify. */
-#if 0
+#if false
x_start_queuing_selection_requests ();
record_unwind_protect_void (x_stop_queuing_selection_requests);
#endif
secs = timeout / 1000;
nsecs = (timeout % 1000) * 1000000;
TRACE1 (" Start waiting %"pI"d secs for SelectionNotify", secs);
- wait_reading_process_output (secs, nsecs, 0, 0,
+ wait_reading_process_output (secs, nsecs, 0, false,
reading_selection_reply, NULL, 0);
TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply)));
/* Otherwise, the selection is waiting for us on the requested property. */
return
- x_get_window_property_as_lisp_data (display, requestor_window,
+ x_get_window_property_as_lisp_data (dpyinfo, requestor_window,
target_property, target_type,
selection_atom);
}
x_get_window_property (Display *display, Window window, Atom property,
unsigned char **data_ret, ptrdiff_t *bytes_ret,
Atom *actual_type_ret, int *actual_format_ret,
- unsigned long *actual_size_ret, int delete_p)
+ unsigned long *actual_size_ret)
{
ptrdiff_t total_size;
unsigned long bytes_remaining;
/* First probe the thing to find out how big it is. */
result = XGetWindowProperty (display, window, property,
- 0L, 0L, False, AnyPropertyType,
+ 0, 0, False, AnyPropertyType,
actual_type_ret, actual_format_ret,
actual_size_ret,
&bytes_remaining, &tmp_data);
if (total_size_max < bytes_remaining)
goto size_overflow;
total_size = bytes_remaining;
- data = malloc (total_size + 1);
- if (! data)
- goto memory_exhausted;
+ data = xmalloc (total_size + 1);
/* Now read, until we've gotten it all. */
while (bytes_remaining)
if (remaining_lim < 0 || remaining_lim < bytes_remaining)
goto size_overflow;
total_size = offset + bytes_gotten + bytes_remaining;
- data1 = realloc (data, total_size + 1);
- if (! data1)
- goto memory_exhausted;
+ data1 = xrealloc (data, total_size + 1);
data = data1;
}
return;
size_overflow:
- free (data);
+ if (data)
+ xfree (data);
unblock_input ();
memory_full (SIZE_MAX);
-
- memory_exhausted:
- free (data);
- unblock_input ();
- memory_full (total_size + 1);
}
\f
/* Use xfree, not XFree, to free the data obtained with this function. */
static void
-receive_incremental_selection (Display *display, Window window, Atom property,
+receive_incremental_selection (struct x_display_info *dpyinfo,
+ Window window, Atom property,
Lisp_Object target_type,
unsigned int min_size_bytes,
unsigned char **data_ret,
{
ptrdiff_t offset = 0;
struct prop_location *wait_object;
+ Display *display = dpyinfo->display;
+
if (min (PTRDIFF_MAX, SIZE_MAX) < min_size_bytes)
memory_full (SIZE_MAX);
*data_ret = xmalloc (min_size_bytes);
block_input ();
XSelectInput (display, window, STANDARD_EVENT_SET | PropertyChangeMask);
TRACE1 (" Delete property %s",
- SDATA (SYMBOL_NAME (x_atom_to_symbol (display, property))));
+ SDATA (SYMBOL_NAME (x_atom_to_symbol (dpyinfo, property))));
XDeleteProperty (display, window, property);
TRACE1 (" Expect new value of property %s",
- SDATA (SYMBOL_NAME (x_atom_to_symbol (display, property))));
+ SDATA (SYMBOL_NAME (x_atom_to_symbol (dpyinfo, property))));
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 (1)
+ while (true)
{
unsigned char *tmp_data;
ptrdiff_t tmp_size_bytes;
TRACE0 (" Get property value");
x_get_window_property (display, window, property,
&tmp_data, &tmp_size_bytes,
- type_ret, format_ret, size_ret, 1);
+ type_ret, format_ret, size_ret);
TRACE1 (" Read increment of %"pD"d bytes", tmp_size_bytes);
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 ();
if this fails. */
static Lisp_Object
-x_get_window_property_as_lisp_data (Display *display, Window window,
- Atom property,
+x_get_window_property_as_lisp_data (struct x_display_info *dpyinfo,
+ Window window, Atom property,
Lisp_Object target_type,
Atom selection_atom)
{
unsigned char *data = 0;
ptrdiff_t bytes = 0;
Lisp_Object val;
- struct x_display_info *dpyinfo = x_display_info_for_display (display);
+ Display *display = dpyinfo->display;
TRACE0 ("Reading selection data");
x_get_window_property (display, window, property, &data, &bytes,
- &actual_type, &actual_format, &actual_size, 1);
+ &actual_type, &actual_format, &actual_size);
if (! data)
{
- int there_is_a_selection_owner;
block_input ();
- there_is_a_selection_owner
- = XGetSelectionOwner (display, selection_atom);
+ bool there_is_a_selection_owner
+ = XGetSelectionOwner (display, selection_atom) != 0;
unblock_input ();
if (there_is_a_selection_owner)
signal_error ("Selection owner couldn't convert",
actual_type
? list2 (target_type,
- x_atom_to_symbol (display, actual_type))
+ x_atom_to_symbol (dpyinfo, actual_type))
: target_type);
else
signal_error ("No selection",
- x_atom_to_symbol (display, selection_atom));
+ x_atom_to_symbol (dpyinfo, selection_atom));
}
if (actual_type == dpyinfo->Xatom_INCR)
calls xmalloc itself. */
xfree (data);
unblock_input ();
- receive_incremental_selection (display, window, property, target_type,
+ receive_incremental_selection (dpyinfo, window, property, target_type,
min_size_bytes, &data, &bytes,
&actual_type, &actual_format,
&actual_size);
/* It's been read. Now convert it to a lisp object in some semi-rational
manner. */
- val = selection_data_to_lisp_data (display, data, bytes,
+ val = selection_data_to_lisp_data (dpyinfo, data, bytes,
actual_type, actual_format);
/* Use xfree, not XFree, because x_get_window_property
static Lisp_Object
-selection_data_to_lisp_data (Display *display, const unsigned char *data,
+selection_data_to_lisp_data (struct x_display_info *dpyinfo,
+ const unsigned char *data,
ptrdiff_t size, Atom type, int format)
{
- struct x_display_info *dpyinfo = x_display_info_for_display (display);
-
if (type == dpyinfo->Xatom_NULL)
return QNULL;
int *idata = (int *) data;
if (size == sizeof (int))
- return x_atom_to_symbol (display, (Atom) idata[0]);
+ return x_atom_to_symbol (dpyinfo, (Atom) idata[0]);
else
{
Lisp_Object v = make_uninit_vector (size / sizeof (int));
for (i = 0; i < size / sizeof (int); i++)
- ASET (v, i, x_atom_to_symbol (display, (Atom) idata[i]));
+ ASET (v, i, x_atom_to_symbol (dpyinfo, (Atom) idata[i]));
return v;
}
}
/* Use xfree, not XFree, to free the data obtained with this function. */
static void
-lisp_data_to_selection_data (Display *display, Lisp_Object obj,
- unsigned char **data_ret, Atom *type_ret,
- ptrdiff_t *size_ret,
- int *format_ret, int *nofree_ret)
+lisp_data_to_selection_data (struct x_display_info *dpyinfo,
+ Lisp_Object obj, struct selection_data *cs)
{
Lisp_Object type = Qnil;
- struct x_display_info *dpyinfo = x_display_info_for_display (display);
- *nofree_ret = 0;
+ eassert (cs != NULL);
+ cs->nofree = false;
if (CONSP (obj) && SYMBOLP (XCAR (obj)))
{
if (EQ (obj, QNULL) || (EQ (type, QNULL)))
{ /* This is not the same as declining */
- *format_ret = 32;
- *size_ret = 0;
- *data_ret = 0;
+ cs->format = 32;
+ cs->size = 0;
+ cs->data = NULL;
type = QNULL;
}
else if (STRINGP (obj))
signal_error ("Non-ASCII string must be encoded in advance", obj);
if (NILP (type))
type = QSTRING;
- *format_ret = 8;
- *size_ret = SBYTES (obj);
- *data_ret = SDATA (obj);
- *nofree_ret = 1;
+ cs->format = 8;
+ cs->size = SBYTES (obj);
+ cs->data = SDATA (obj);
+ cs->nofree = true;
}
else if (SYMBOLP (obj))
{
void *data = xmalloc (sizeof (Atom) + 1);
Atom *x_atom_ptr = data;
- *data_ret = data;
- *format_ret = 32;
- *size_ret = 1;
- (*data_ret) [sizeof (Atom)] = 0;
+ cs->data = data;
+ cs->format = 32;
+ cs->size = 1;
+ cs->data[sizeof (Atom)] = 0;
*x_atom_ptr = symbol_to_x_atom (dpyinfo, obj);
if (NILP (type)) type = QATOM;
}
{
void *data = xmalloc (sizeof (short) + 1);
short *short_ptr = data;
- *data_ret = data;
- *format_ret = 16;
- *size_ret = 1;
- (*data_ret) [sizeof (short)] = 0;
+ cs->data = data;
+ cs->format = 16;
+ cs->size = 1;
+ cs->data[sizeof (short)] = 0;
*short_ptr = XINT (obj);
if (NILP (type)) type = QINTEGER;
}
{
void *data = xmalloc (sizeof (unsigned long) + 1);
unsigned long *x_long_ptr = data;
- *data_ret = data;
- *format_ret = 32;
- *size_ret = 1;
- (*data_ret) [sizeof (unsigned long)] = 0;
+ cs->data = data;
+ cs->format = 32;
+ cs->size = 1;
+ cs->data[sizeof (unsigned long)] = 0;
*x_long_ptr = cons_to_x_long (obj);
if (NILP (type)) type = QINTEGER;
}
if (!SYMBOLP (AREF (obj, i)))
signal_error ("All elements of selection vector must have same type", obj);
- *data_ret = data = xnmalloc (size, sizeof *x_atoms);
+ cs->data = data = xnmalloc (size, sizeof *x_atoms);
x_atoms = data;
- *format_ret = 32;
- *size_ret = size;
+ cs->format = 32;
+ cs->size = size;
for (i = 0; i < size; i++)
x_atoms[i] = symbol_to_x_atom (dpyinfo, AREF (obj, i));
}
break;
}
}
- *data_ret = data = xnmalloc (size, data_size);
+ cs->data = data = xnmalloc (size, data_size);
x_atoms = data;
shorts = data;
- *format_ret = format;
- *size_ret = size;
+ cs->format = format;
+ cs->size = size;
for (i = 0; i < size; i++)
{
if (format == 32)
else
signal_error (/* Qselection_error */ "Unrecognized selection data", obj);
- *type_ret = symbol_to_x_atom (dpyinfo, type);
+ cs->type = symbol_to_x_atom (dpyinfo, type);
}
static Lisp_Object
}
else if (TERMINALP (object))
{
- struct terminal *t = get_terminal (object, 1);
+ struct terminal *t = decode_live_terminal (object);
if (t->type == output_x_window)
FOR_EACH_FRAME (tail, frame)
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);
if (!f)
error ("X selection unavailable for this frame");
- val = x_get_local_selection (selection_symbol, target_type, 1,
+ val = x_get_local_selection (selection_symbol, target_type, true,
FRAME_DISPLAY_INFO (f));
if (NILP (val) && FRAME_LIVE_P (f))
{
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_DISPLAY (&event.sie) = dpyinfo->display;
- 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;
}
static Lisp_Object
x_clipboard_manager_error_1 (Lisp_Object err)
{
- Lisp_Object args[2];
- args[0] = build_string ("X clipboard manager error: %s\n\
-If the problem persists, set `x-select-enable-clipboard-manager' to nil.");
- args[1] = CAR (CDR (err));
- Fmessage (2, args);
+ AUTO_STRING (format, "X clipboard manager error: %s\n\
+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)))
{
- Lisp_Object args[1];
- args[0] = build_string ("Saving clipboard to X clipboard manager...");
- Fmessage (1, args);
-
+ message ("Saving clipboard to X clipboard manager...");
internal_condition_case_1 (x_clipboard_manager_save, local_frame,
Qt, x_clipboard_manager_error_2);
}
void
x_fill_property_data (Display *dpy, Lisp_Object data, void *ret, int format)
{
- long val;
- long *d32 = (long *) ret;
- short *d16 = (short *) ret;
- char *d08 = (char *) ret;
+ unsigned long val;
+ unsigned long *d32 = (unsigned long *) ret;
+ unsigned short *d16 = (unsigned short *) ret;
+ unsigned char *d08 = (unsigned char *) ret;
Lisp_Object iter;
for (iter = data; CONSP (iter); iter = XCDR (iter))
{
Lisp_Object o = XCAR (iter);
- if (INTEGERP (o) || FLOATP (o) || CONSP (o))
- val = cons_to_signed (o, LONG_MIN, LONG_MAX);
+ if (NUMBERP (o) || CONSP (o))
+ {
+ if (CONSP (o)
+ && RANGED_INTEGERP (X_LONG_MIN >> 16, XCAR (o), X_LONG_MAX >> 16)
+ && RANGED_INTEGERP (- (1 << 15), XCDR (o), -1))
+ {
+ /* cons_to_x_long does not handle negative values for v2.
+ For XDnd, v2 might be y of a window, and can be negative.
+ The XDnd spec. is not explicit about negative values,
+ but let's assume negative v2 is sent modulo 2**16. */
+ unsigned long v1 = XINT (XCAR (o)) & 0xffff;
+ unsigned long v2 = XINT (XCDR (o)) & 0xffff;
+ val = (v1 << 16) | v2;
+ }
+ else
+ val = cons_to_x_long (o);
+ }
else if (STRINGP (o))
{
block_input ();
- val = (long) XInternAtom (dpy, SSDATA (o), False);
+ val = XInternAtom (dpy, SSDATA (o), False);
unblock_input ();
}
else
if (format == 8)
{
- if (CHAR_MIN <= val && val <= CHAR_MAX)
- *d08++ = val;
- else
+ if ((1 << 8) < val && val <= X_ULONG_MAX - (1 << 7))
error ("Out of 'char' range");
+ *d08++ = val;
}
else if (format == 16)
{
- if (SHRT_MIN <= val && val <= SHRT_MAX)
- *d16++ = val;
- else
+ if ((1 << 16) < val && val <= X_ULONG_MAX - (1 << 15))
error ("Out of 'short' range");
+ *d16++ = val;
}
else
*d32++ = val;
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_X_DISPLAY (f),
- data, size * format_bytes, type, format);
-}
-
-/* Get the mouse position in frame relative coordinates. */
-
-static void
-mouse_position_for_drop (struct frame *f, int *x, int *y)
-{
- Window root, dummy_window;
- int dummy;
-
- block_input ();
-
- XQueryPointer (FRAME_X_DISPLAY (f),
- DefaultRootWindow (FRAME_X_DISPLAY (f)),
-
- /* The root window which contains the pointer. */
- &root,
-
- /* Window pointer is on, not used */
- &dummy_window,
-
- /* The position on that root window. */
- x, y,
-
- /* x/y in dummy_window coordinates, not used. */
- &dummy, &dummy,
-
- /* Modifier keys and pointer buttons, about which
- we don't care. */
- (unsigned int *) &dummy);
-
-
- /* Absolute to relative. */
- *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f);
- *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f);
-
- unblock_input ();
+ return selection_data_to_lisp_data (FRAME_DISPLAY_INFO (f), data,
+ 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);
/* Convert an XClientMessageEvent to a Lisp event of type DRAG_N_DROP_EVENT. */
-int
+bool
x_handle_dnd_message (struct frame *f, const XClientMessageEvent *event,
struct x_display_info *dpyinfo, struct input_event *bufp)
{
for (i = 0; i < dpyinfo->x_dnd_atoms_length; ++i)
if (dpyinfo->x_dnd_atoms[i] == event->message_type) break;
- if (i == dpyinfo->x_dnd_atoms_length) return 0;
+ if (i == dpyinfo->x_dnd_atoms_length) return false;
XSETFRAME (frame, f);
}
vec = Fmake_vector (make_number (4), Qnil);
- ASET (vec, 0, SYMBOL_NAME (x_atom_to_symbol (FRAME_X_DISPLAY (f),
+ ASET (vec, 0, SYMBOL_NAME (x_atom_to_symbol (FRAME_DISPLAY_INFO (f),
event->message_type)));
ASET (vec, 1, frame);
ASET (vec, 2, make_number (event->format));
event->format,
size));
- mouse_position_for_drop (f, &x, &y);
+ x_relative_mouse_position (f, &x, &y);
bufp->kind = DRAG_N_DROP_EVENT;
bufp->frame_or_window = frame;
bufp->timestamp = CurrentTime;
bufp->arg = vec;
bufp->modifiers = 0;
- return 1;
+ return true;
}
DEFUN ("x-send-client-message", Fx_send_client_message,
Window wdest;
XEvent event;
struct frame *f = decode_window_system_frame (from);
- int to_root;
+ bool to_root;
CHECK_NUMBER (format);
CHECK_CONS (values);
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");
event then goes to clients selecting for events on the root window. */
x_catch_errors (dpyinfo->display);
{
- int propagate = to_root ? False : True;
+ bool propagate = !to_root;
long mask = to_root ? 0xffffff : 0;
XSendEvent (dpyinfo->display, wdest, propagate, mask, &event);
converted_selections = NULL;
conversion_fail_tag = None;
+ /* FIXME: Duplicate definition in nsselect.c. */
DEFVAR_LISP ("selection-converter-alist", Vselection_converter_alist,
doc: /* An alist associating X Windows selection-types with functions.
These functions are called to convert the selection, with three args:
the name of the selection (typically `PRIMARY', `SECONDARY', or `CLIPBOARD');
a desired type to which the selection should be converted;
-and the local selection value (whatever was given to `x-own-selection').
+and the local selection value (whatever was given to
+`x-own-selection-internal').
The function should return the value to send to the X server
\(typically a string). A return value of nil
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");