/* X Selection processing for Emacs.
- Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2001
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 2000, 2001, 2003, 2004
Free Software Foundation.
This file is part of GNU Emacs.
/* Rewritten by jwz */
#include <config.h>
+#include <stdio.h> /* termhooks.h needs this */
#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 "buffer.h"
-#include "charset.h"
-#include "coding.h"
#include "process.h"
-#include "composite.h"
+#include "termhooks.h"
+
+#include <X11/Xproto.h>
struct prop_location;
static Atom symbol_to_x_atom P_ ((struct x_display_info *, Display *,
Lisp_Object));
static void x_own_selection P_ ((Lisp_Object, Lisp_Object));
-static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object));
+static Lisp_Object x_get_local_selection P_ ((Lisp_Object, Lisp_Object, int));
static void x_decline_selection_request P_ ((struct input_event *));
static Lisp_Object x_selection_request_lisp_error P_ ((Lisp_Object));
static Lisp_Object queue_selection_requests_unwind P_ ((Lisp_Object));
static void unexpect_property_change P_ ((struct prop_location *));
static Lisp_Object wait_for_property_change_unwind P_ ((Lisp_Object));
static void wait_for_property_change P_ ((struct prop_location *));
-static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object, Lisp_Object));
+static Lisp_Object x_get_foreign_selection P_ ((Lisp_Object,
+ Lisp_Object,
+ Lisp_Object));
static void x_get_window_property P_ ((Display *, Window, Atom,
unsigned char **, int *,
Atom *, int *, unsigned long *, int));
QATOM_PAIR;
Lisp_Object QCOMPOUND_TEXT; /* This is a type of selection. */
+Lisp_Object QUTF8_STRING; /* This is a type of selection. */
Lisp_Object Qcompound_text_with_extensions;
/* Coding system for the next communicating with other X clients. */
static Lisp_Object Vnext_selection_coding_system;
+static Lisp_Object Qforeign_selection;
+
/* 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
- emacs to use incremental selection transfers when the selection is
+ emacs to use incremental selection transfers when the selection is
smaller than that, set this. I added this mostly for debugging the
incremental transfer stuff, but it might improve server performance. */
#define MAX_SELECTION_QUANTUM 0xFFFFFF
/* This is an alist whose CARs are selection-types (whose names are the same
as the names of X Atoms) and whose CDRs are the names of Lisp functions to
- call to convert the given Emacs selection value to a string representing
+ call to convert the given Emacs selection value to a string representing
the given selection type. This is for Lisp-level extension of the emacs
selection handling. */
static Lisp_Object Vselection_converter_alist;
static Lisp_Object selection_data_to_lisp_data ();
static Lisp_Object x_get_window_property_as_lisp_data ();
-/* This converts a Lisp symbol to a server Atom, avoiding a server
+/* This converts a Lisp symbol to a server Atom, avoiding a server
roundtrip whenever possible. */
static Atom
if (EQ (sym, QTIMESTAMP)) return dpyinfo->Xatom_TIMESTAMP;
if (EQ (sym, QTEXT)) return dpyinfo->Xatom_TEXT;
if (EQ (sym, QCOMPOUND_TEXT)) return dpyinfo->Xatom_COMPOUND_TEXT;
+ if (EQ (sym, QUTF8_STRING)) return dpyinfo->Xatom_UTF8_STRING;
if (EQ (sym, QDELETE)) return dpyinfo->Xatom_DELETE;
if (EQ (sym, QMULTIPLE)) return dpyinfo->Xatom_MULTIPLE;
if (EQ (sym, QINCR)) return dpyinfo->Xatom_INCR;
#endif
if (!SYMBOLP (sym)) abort ();
- TRACE1 (" XInternAtom %s", (char *) XSTRING (SYMBOL_NAME (sym))->data);
+ TRACE1 (" XInternAtom %s", (char *) SDATA (SYMBOL_NAME (sym)));
BLOCK_INPUT;
- val = XInternAtom (display, (char *) XSTRING (SYMBOL_NAME (sym))->data, False);
+ val = XInternAtom (display, (char *) SDATA (SYMBOL_NAME (sym)), False);
UNBLOCK_INPUT;
return val;
}
struct x_display_info *dpyinfo;
char *str;
Lisp_Object val;
-
+
if (! atom)
return Qnil;
-
+
switch (atom)
{
case XA_PRIMARY:
return QTEXT;
if (atom == dpyinfo->Xatom_COMPOUND_TEXT)
return QCOMPOUND_TEXT;
+ if (atom == dpyinfo->Xatom_UTF8_STRING)
+ return QUTF8_STRING;
if (atom == dpyinfo->Xatom_DELETE)
return QDELETE;
if (atom == dpyinfo->Xatom_MULTIPLE)
}
\f
/* Do protocol to assert ourself as a selection owner.
- Update the Vselection_alist so that we can reply to later requests for
+ Update the Vselection_alist so that we can reply to later requests for
our selection. */
static void
/* Given a selection-name and desired type, look up our local copy of
the selection value and convert it to the type.
The value is nil or a string.
- This function is used both for remote requests
- and for local x-get-selection-internal.
+ This function is used both for remote requests (LOCAL_REQUEST is zero)
+ and for local x-get-selection-internal (LOCAL_REQUEST is nonzero).
This calls random Lisp code, and may signal or gc. */
static Lisp_Object
-x_get_local_selection (selection_symbol, target_type)
+x_get_local_selection (selection_symbol, target_type, local_request)
Lisp_Object selection_symbol, target_type;
+ int local_request;
{
Lisp_Object local_value;
Lisp_Object handler_fn, value, type, check;
pair = XVECTOR (pairs)->contents [i];
XVECTOR (pair)->contents [1]
= x_get_local_selection (XVECTOR (pair)->contents [0],
- XVECTOR (pair)->contents [1]);
+ XVECTOR (pair)->contents [1],
+ local_request);
}
return pairs;
}
/* Don't allow a quit within the converter.
When the user types C-g, he would be surprised
if by luck it came during a converter. */
- count = specpdl_ptr - specpdl;
+ count = SPECPDL_INDEX ();
specbind (Qinhibit_quit, Qt);
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,
- selection_symbol, target_type,
+ selection_symbol, (local_request ? Qnil : target_type),
XCAR (XCDR (local_value)));
else
value = Qnil;
&& SYMBOLP (XCAR (value)))
type = XCAR (value),
check = XCDR (value);
-
+
if (STRINGP (check)
|| VECTORP (check)
|| SYMBOLP (check)
{
XSelectionEvent reply;
int count;
-
+
reply.type = SelectionNotify;
reply.display = SELECTION_EVENT_DISPLAY (event);
reply.requestor = SELECTION_EVENT_REQUESTOR (event);
if (x_window_to_frame (dpyinfo, window)) /* #### debug */
error ("Attempt to transfer an INCR to ourself!");
-
+
TRACE2 ("Start sending %d bytes incrementally (%s)",
bytes_remaining, XGetAtomName (display, reply.property));
wait_object = expect_property_change (display, window, reply.property,
32, PropModeReplace,
(unsigned char *) &bytes_remaining, 1);
XSelectInput (display, window, PropertyChangeMask);
-
+
/* Tell 'em the INCR data is there... */
TRACE0 ("Send SelectionNotify event");
XSendEvent (display, window, False, 0L, (XEvent *) &reply);
TRACE1 ("Sending increment of %d bytes", i);
TRACE1 ("Set %s to increment data",
XGetAtomName (display, reply.property));
-
+
/* Append the next chunk of data to the property. */
XChangeProperty (display, window, reply.property, type, format,
PropModeAppend, data, i / format_bytes);
XGetAtomName (display, reply.property));
wait_for_property_change (wait_object);
}
-
+
/* Now write a zero-length chunk to the property to tell the
requester that we're done. */
BLOCK_INPUT;
TRACE0 ("Done sending incrementally");
}
+ /* rms, 2003-01-03: I think I have fixed this bug. */
/* The window we're communicating with may have been deleted
in the meantime (that's a real situation from a bug report).
In this case, there may be events in the event queue still
refering to the deleted window, and we'll get a BadWindow error
in XTread_socket when processing the events. I don't have
an idea how to fix that. gerd, 2001-01-98. */
- XFlush (display);
- x_uncatch_errors (display, count);
+ /* 2004-09-10: XSync and UNBLOCK so that possible protocol errors are
+ delivered before uncatch errors. */
+ XSync (display, False);
UNBLOCK_INPUT;
+ x_uncatch_errors (display, count);
}
\f
/* Handle a SelectionRequest event EVENT.
}
x_selection_current_request = event;
- count = BINDING_STACK_SIZE ();
+ count = SPECPDL_INDEX ();
selection_request_dpyinfo = dpyinfo;
record_unwind_protect (x_selection_request_lisp_error, Qnil);
if (EQ (target_symbol, QMULTIPLE))
target_symbol = fetch_multiple_target (event);
#endif
-
+
/* Convert lisp objects back into binary data */
-
+
converted_selection
- = x_get_local_selection (selection_symbol, target_symbol);
-
+ = x_get_local_selection (selection_symbol, target_symbol, 0);
+
if (! NILP (converted_selection))
{
unsigned char *data;
lisp_data_to_selection_data (SELECTION_EVENT_DISPLAY (event),
converted_selection,
&data, &type, &size, &format, &nofree);
-
+
x_reply_selection_request (event, format, data, size, type);
successful_p = Qt;
DONE:
- UNGCPRO;
-
/* Let random lisp code notice that the selection has been asked for. */
{
Lisp_Object rest;
for (; CONSP (rest); rest = Fcdr (rest))
call3 (Fcar (rest), selection_symbol, target_symbol, successful_p);
}
+
+ UNGCPRO;
}
\f
/* Handle a SelectionClear event EVENT, which indicates that some
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 prop_location *location;
{
int secs, usecs;
- int count = specpdl_ptr - specpdl;
+ int count = SPECPDL_INDEX ();
Lisp_Object tem;
tem = Fcons (Qnil, Qnil);
secs = x_selection_timeout / 1000;
usecs = (x_selection_timeout % 1000) * 1000;
TRACE2 (" Waiting %d secs, %d usecs", secs, usecs);
- wait_reading_process_input (secs, usecs, property_change_reply, 0);
+ wait_reading_process_output (secs, usecs, 0, 0,
+ property_change_reply, NULL, 0);
if (NILP (XCAR (property_change_reply)))
{
xfree (rest);
return;
}
-
+
prev = rest;
rest = rest->next;
}
int size;
if (CONSP (obj))
return Fcons (XCAR (obj), copy_multiple_data (XCDR (obj)));
-
+
CHECK_VECTOR (obj);
vec = Fmake_vector (size = XVECTOR (obj)->size, Qnil);
for (i = 0; i < size; i++)
Converts this to Lisp data and returns it. */
static Lisp_Object
-x_get_foreign_selection (selection_symbol, target_type)
- Lisp_Object selection_symbol, target_type;
+x_get_foreign_selection (selection_symbol, target_type, time_stamp)
+ Lisp_Object selection_symbol, target_type, time_stamp;
{
struct frame *sf = SELECTED_FRAME ();
Window requestor_window = FRAME_X_WINDOW (sf);
else
type_atom = symbol_to_x_atom (dpyinfo, display, target_type);
+ if (! NILP (time_stamp))
+ {
+ if (CONSP (time_stamp))
+ requestor_time = (Time) cons_to_long (time_stamp);
+ else if (INTEGERP (time_stamp))
+ requestor_time = (Time) XUINT (time_stamp);
+ else if (FLOATP (time_stamp))
+ requestor_time = (Time) XFLOAT (time_stamp);
+ else
+ error ("TIME_STAMP must be cons or number");
+ }
+
BLOCK_INPUT;
-
+
count = x_catch_errors (display);
-
+
TRACE2 ("Get selection %s, type %s",
XGetAtomName (display, type_atom),
XGetAtomName (display, target_property));
secs = x_selection_timeout / 1000;
usecs = (x_selection_timeout % 1000) * 1000;
TRACE1 (" Start waiting %d secs for SelectionNotify", secs);
- wait_reading_process_input (secs, usecs, reading_selection_reply, 0);
+ wait_reading_process_output (secs, usecs, 0, 0,
+ reading_selection_reply, NULL, 0);
TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply)));
BLOCK_INPUT;
if (NILP (XCAR (reading_selection_reply)))
error ("Timed out waiting for reply from selection owner");
if (EQ (XCAR (reading_selection_reply), Qlambda))
- error ("No `%s' selection", XSTRING (SYMBOL_NAME (selection_symbol))->data);
+ error ("No `%s' selection", SDATA (SYMBOL_NAME (selection_symbol)));
/* Otherwise, the selection is waiting for us on the requested property. */
return
unsigned char *tmp_data = 0;
int result;
int buffer_size = SELECTION_QUANTUM (display);
-
+
if (buffer_size > MAX_SELECTION_QUANTUM)
buffer_size = MAX_SELECTION_QUANTUM;
-
+
BLOCK_INPUT;
-
+
/* First probe the thing to find out how big it is. */
result = XGetWindowProperty (display, window, property,
0L, 0L, False, AnyPropertyType,
*bytes_ret = 0;
return;
}
-
+
/* This was allocated by Xlib, so use XFree. */
XFree ((char *) tmp_data);
-
+
if (*actual_type_ret == None || *actual_format_ret == 0)
{
UNBLOCK_INPUT;
total_size = bytes_remaining + 1;
*data_ret = (unsigned char *) xmalloc (total_size);
-
+
/* Now read, until we've gotten it all. */
while (bytes_remaining)
{
*actual_size_ret *= *actual_format_ret / 8;
bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret);
offset += *actual_size_ret;
-
+
/* This was allocated by Xlib, so use XFree. */
XFree ((char *) tmp_data);
}
TRACE0 (" Wait for property change");
wait_for_property_change (wait_object);
-
+
/* expect it again immediately, because x_get_window_property may
.. no it won't, I don't get it.
.. Ok, I get it now, the Xt code that implements INCR is broken. */
*size_bytes_ret = offset + tmp_size_bytes;
*data_ret = (unsigned char *) xrealloc (*data_ret, *size_bytes_ret);
}
-
+
bcopy (tmp_data, (*data_ret) + offset, tmp_size_bytes);
offset += tmp_size_bytes;
-
+
/* Use xfree, not XFree, because x_get_window_property
calls xmalloc itself. */
xfree (tmp_data);
selection_atom),
Qnil)));
}
-
+
if (actual_type == dpyinfo->Xatom_INCR)
{
/* That wasn't really the data, just the beginning. */
manner. */
val = selection_data_to_lisp_data (display, data, bytes,
actual_type, actual_format);
-
+
/* Use xfree, not XFree, because x_get_window_property
calls xmalloc itself. */
xfree ((char *) data);
/* Convert any 8-bit data to a string, for compactness. */
else if (format == 8)
{
- Lisp_Object str;
- int require_encoding = 0;
-
- if (
-#if 1
- 1
-#else
- ! NILP (buffer_defaults.enable_multibyte_characters)
-#endif
- )
- {
- /* If TYPE is `TEXT' or `COMPOUND_TEXT', we should decode
- DATA to Emacs internal format because DATA may be encoded
- in compound text format. In addtion, if TYPE is `STRING'
- and DATA contains any 8-bit Latin-1 code, we should also
- decode it. */
- if (type == dpyinfo->Xatom_TEXT
- || type == dpyinfo->Xatom_COMPOUND_TEXT)
- require_encoding = 1;
- else if (type == XA_STRING)
- {
- int i;
- for (i = 0; i < size; i++)
- {
- if (data[i] >= 0x80)
- {
- require_encoding = 1;
- break;
- }
- }
- }
- }
- if (!require_encoding)
- {
- str = make_unibyte_string ((char *) data, size);
- Vlast_coding_system_used = Qraw_text;
- }
+ Lisp_Object str, lispy_type;
+
+ str = make_unibyte_string ((char *) data, size);
+ /* Indicate that this string is from foreign selection by a text
+ property `foreign-selection' so that the caller of
+ x-get-selection-internal (usually x-get-selection) can know
+ that the string must be decode. */
+ if (type == dpyinfo->Xatom_COMPOUND_TEXT)
+ lispy_type = QCOMPOUND_TEXT;
+ else if (type == dpyinfo->Xatom_UTF8_STRING)
+ lispy_type = QUTF8_STRING;
else
- {
- int bufsize;
- unsigned char *buf;
- struct coding_system coding;
-
- if (NILP (Vnext_selection_coding_system))
- Vnext_selection_coding_system = Vselection_coding_system;
- setup_coding_system
- (Fcheck_coding_system(Vnext_selection_coding_system), &coding);
- coding.src_multibyte = 0;
- coding.dst_multibyte = 1;
- Vnext_selection_coding_system = Qnil;
- coding.mode |= CODING_MODE_LAST_BLOCK;
- bufsize = decoding_buffer_size (&coding, size);
- buf = (unsigned char *) xmalloc (bufsize);
- decode_coding (&coding, data, buf, size, bufsize);
- str = make_string_from_bytes ((char *) buf,
- coding.produced_char, coding.produced);
- xfree (buf);
-
- if (SYMBOLP (coding.post_read_conversion)
- && !NILP (Ffboundp (coding.post_read_conversion)))
- str = run_pre_post_conversion_on_str (str, &coding, 0);
- Vlast_coding_system_used = coding.symbol;
- }
- compose_chars_in_text (0, XSTRING (str)->size, str);
+ lispy_type = QSTRING;
+ Fput_text_property (make_number (0), make_number (size),
+ Qforeign_selection, lispy_type, str);
return str;
}
/* Convert a single atom to a Lisp_Symbol. Convert a set of atoms to
If the number is > 16 bits, convert it to a cons of integers,
16 bits in each half.
*/
- else if (format == 32 && size == sizeof (long))
- return long_to_cons (((unsigned long *) data) [0]);
+ else if (format == 32 && size == sizeof (int))
+ return long_to_cons (((unsigned int *) data) [0]);
else if (format == 16 && size == sizeof (short))
return make_number ((int) (((unsigned short *) data) [0]));
Lisp_Object v = Fmake_vector (make_number (size / 4), make_number (0));
for (i = 0; i < size / 4; i++)
{
- unsigned long j = ((unsigned long *) data) [i];
+ unsigned int j = ((unsigned int *) data) [i];
Faset (v, make_number (i), long_to_cons (j));
}
return v;
}
else if (STRINGP (obj))
{
- /* Since we are now handling multilingual text, we must consider
- sending back compound text. */
- int stringp;
- extern Lisp_Object Qcompound_text;
-
- if (NILP (Vnext_selection_coding_system))
- Vnext_selection_coding_system = Vselection_coding_system;
-
- *format_ret = 8;
- /* If the requested type is STRING, we must encode the selected
- text as a string, even if the coding system set by the user
- is ctext or its derivatives. */
- if (EQ (type, QSTRING)
- && (EQ (Vnext_selection_coding_system, Qcompound_text)
- || EQ (Vnext_selection_coding_system,
- Qcompound_text_with_extensions)))
- {
- Lisp_Object unibyte_string;
-
- unibyte_string = string_make_unibyte (obj);
- *data_ret = XSTRING (unibyte_string)->data;
- *nofree_ret = 1;
- }
- else
- {
- *data_ret = x_encode_text (obj, Vnext_selection_coding_system, 1,
- (int *) size_ret, &stringp);
- *nofree_ret = (*data_ret == XSTRING (obj)->data);
- }
+ xassert (! STRING_MULTIBYTE (obj));
if (NILP (type))
- type = (stringp ? QSTRING : QCOMPOUND_TEXT);
- Vlast_coding_system_used = (*nofree_ret
- ? Qraw_text
- : Vnext_selection_coding_system);
- Vnext_selection_coding_system = Qnil;
+ type = QSTRING;
+ *format_ret = 8;
+ *size_ret = SBYTES (obj);
+ *data_ret = SDATA (obj);
+ *nofree_ret = 1;
}
else if (SYMBOLP (obj))
{
Lisp_Object pair = XVECTOR (obj)->contents [i];
if (XVECTOR (pair)->size != 2)
Fsignal (Qerror,
- Fcons (build_string
+ Fcons (build_string
("elements of the vector must be vectors of exactly two elements"),
Fcons (pair, Qnil)));
-
+
(*(Atom **) data_ret) [i * 2]
= symbol_to_x_atom (dpyinfo, display,
XVECTOR (pair)->contents [0]);
Fcons (build_string
("all elements of the vector must be of the same type"),
Fcons (obj, Qnil)));
-
+
}
#endif
else
will block until all of the data has arrived. */
DEFUN ("x-get-selection-internal", Fx_get_selection_internal,
- Sx_get_selection_internal, 2, 2, 0,
+ Sx_get_selection_internal, 2, 3, 0,
doc: /* Return text selected from some X window.
SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'.
\(Those are literal upper-case symbol names, since that's what X expects.)
-TYPE is the type of data desired, typically `STRING'. */)
- (selection_symbol, target_type)
- Lisp_Object selection_symbol, target_type;
+TYPE is the type of data desired, typically `STRING'.
+TIME_STAMP is the time to use in the XConvertSelection call for foreign
+selections. If omitted, defaults to the time for the last event. */)
+ (selection_symbol, target_type, time_stamp)
+ Lisp_Object selection_symbol, target_type, time_stamp;
{
Lisp_Object val = Qnil;
struct gcpro gcpro1, gcpro2;
#endif
CHECK_SYMBOL (target_type);
- val = x_get_local_selection (selection_symbol, target_type);
+ val = x_get_local_selection (selection_symbol, target_type, 1);
if (NILP (val))
{
- val = x_get_foreign_selection (selection_symbol, target_type);
+ val = x_get_foreign_selection (selection_symbol, target_type, time_stamp);
goto DONE;
}
CHECK_SYMBOL (selection);
if (EQ (selection, Qnil)) selection = QPRIMARY;
if (EQ (selection, Qt)) selection = QSECONDARY;
-
+
if (NILP (Fassq (selection, Vselection_alist)))
return Qnil;
return Qt;
&type, &format, &size, 0);
if (!data || !format)
return Qnil;
-
+
if (format != 8 || type != XA_STRING)
Fsignal (Qerror,
Fcons (build_string ("cut buffer doesn't contain 8-bit data"),
CHECK_STRING (string);
buffer_atom = symbol_to_x_atom (FRAME_X_DISPLAY_INFO (sf),
display, buffer);
- data = (unsigned char *) XSTRING (string)->data;
- bytes = STRING_BYTES (XSTRING (string));
+ data = (unsigned char *) SDATA (string);
+ bytes = SBYTES (string);
bytes_remaining = bytes;
if (! FRAME_X_DISPLAY_INFO (sf)->cut_buffers_initialized)
#endif
\f
+/***********************************************************************
+ Drag and drop support
+***********************************************************************/
+/* Check that lisp values are of correct type for x_fill_property_data.
+ That is, number, string or a cons with two numbers (low and high 16
+ bit parts of a 32 bit number). */
+
+int
+x_check_property_data (data)
+ Lisp_Object data;
+{
+ Lisp_Object iter;
+ int size = 0;
+
+ for (iter = data; CONSP (iter) && size != -1; iter = XCDR (iter), ++size)
+ {
+ Lisp_Object o = XCAR (iter);
+
+ if (! NUMBERP (o) && ! STRINGP (o) && ! CONSP (o))
+ size = -1;
+ else if (CONSP (o) &&
+ (! NUMBERP (XCAR (o)) || ! NUMBERP (XCDR (o))))
+ size = -1;
+ }
+
+ return size;
+}
+
+/* Convert lisp values to a C array. Values may be a number, a string
+ which is taken as an X atom name and converted to the atom value, or
+ a cons containing the two 16 bit parts of a 32 bit number.
+
+ DPY is the display use to look up X atoms.
+ DATA is a Lisp list of values to be converted.
+ RET is the C array that contains the converted values. It is assumed
+ it is big enough to hol all values.
+ FORMAT is 8, 16 or 32 and gives the size in bits for each C value to
+ be stored in RET. */
+
+void
+x_fill_property_data (dpy, data, ret, format)
+ Display *dpy;
+ Lisp_Object data;
+ void *ret;
+ int format;
+{
+ CARD32 val;
+ CARD32 *d32 = (CARD32 *) ret;
+ CARD16 *d16 = (CARD16 *) ret;
+ CARD8 *d08 = (CARD8 *) ret;
+ Lisp_Object iter;
+
+ for (iter = data; CONSP (iter); iter = XCDR (iter))
+ {
+ Lisp_Object o = XCAR (iter);
+
+ if (INTEGERP (o))
+ val = (CARD32) XFASTINT (o);
+ else if (FLOATP (o))
+ val = (CARD32) XFLOAT (o);
+ else if (CONSP (o))
+ val = (CARD32) cons_to_long (o);
+ else if (STRINGP (o))
+ {
+ BLOCK_INPUT;
+ val = XInternAtom (dpy, (char *) SDATA (o), False);
+ UNBLOCK_INPUT;
+ }
+ else
+ error ("Wrong type, must be string, number or cons");
+
+ if (format == 8)
+ *d08++ = (CARD8) val;
+ else if (format == 16)
+ *d16++ = (CARD16) val;
+ else
+ *d32++ = val;
+ }
+}
+
+/* Convert an array of C values to a Lisp list.
+ F is the frame to be used to look up X atoms if the TYPE is XA_ATOM.
+ DATA is a C array of values to be converted.
+ TYPE is the type of the data. Only XA_ATOM is special, it converts
+ each number in DATA to its corresponfing X atom as a symbol.
+ FORMAT is 8, 16 or 32 and gives the size in bits for each C value to
+ be stored in RET.
+ SIZE is the number of elements in DATA.
+
+ Also see comment for selection_data_to_lisp_data above. */
+
+Lisp_Object
+x_property_data_to_lisp (f, data, type, format, size)
+ struct frame *f;
+ unsigned char *data;
+ Atom type;
+ int format;
+ unsigned long size;
+{
+ return selection_data_to_lisp_data (FRAME_X_DISPLAY (f),
+ data, size*format/8, type, format);
+}
+
+/* Get the mouse position frame relative coordinates. */
+
+static void
+mouse_position_for_drop (f, x, y)
+ FRAME_PTR 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;
+}
+
+DEFUN ("x-get-atom-name", Fx_get_atom_name,
+ Sx_get_atom_name, 1, 2, 0,
+ doc: /* Return the X atom name for VALUE as a string.
+VALUE may be a number or a cons where the car is the upper 16 bits and
+the cdr is the lower 16 bits of a 32 bit value.
+Use the display for FRAME or the current frame if FRAME is not given or nil.
+
+If the value is 0 or the atom is not known, return the empty string. */)
+ (value, frame)
+ Lisp_Object value, frame;
+{
+ struct frame *f = check_x_frame (frame);
+ char *name = 0;
+ Lisp_Object ret = Qnil;
+ int count;
+ Display *dpy = FRAME_X_DISPLAY (f);
+ Atom atom;
+
+ if (INTEGERP (value))
+ atom = (Atom) XUINT (value);
+ else if (FLOATP (value))
+ atom = (Atom) XFLOAT (value);
+ else if (CONSP (value))
+ atom = (Atom) cons_to_long (value);
+ else
+ error ("Wrong type, value must be number or cons");
+
+ BLOCK_INPUT;
+ count = x_catch_errors (dpy);
+
+ name = atom ? XGetAtomName (dpy, atom) : "";
+
+ if (! x_had_errors_p (dpy))
+ ret = make_string (name, strlen (name));
+
+ x_uncatch_errors (dpy, count);
+
+ if (atom && name) XFree (name);
+ if (NILP (ret)) ret = make_string ("", 0);
+
+ UNBLOCK_INPUT;
+
+ return ret;
+}
+
+/* Convert an XClientMessageEvent to a Lisp event of type DRAG_N_DROP_EVENT.
+ TODO: Check if this client event really is a DND event? */
+
+int
+x_handle_dnd_message (f, event, dpyinfo, bufp)
+ struct frame *f;
+ XClientMessageEvent *event;
+ struct x_display_info *dpyinfo;
+ struct input_event *bufp;
+{
+ Lisp_Object vec;
+ Lisp_Object frame;
+ unsigned long size = (8*sizeof (event->data))/event->format;
+ int x, y;
+
+ XSETFRAME (frame, f);
+
+ vec = Fmake_vector (make_number (4), Qnil);
+ AREF (vec, 0) = SYMBOL_NAME (x_atom_to_symbol (FRAME_X_DISPLAY (f),
+ event->message_type));
+ AREF (vec, 1) = frame;
+ AREF (vec, 2) = make_number (event->format);
+ AREF (vec, 3) = x_property_data_to_lisp (f,
+ event->data.b,
+ event->message_type,
+ event->format,
+ size);
+
+ mouse_position_for_drop (f, &x, &y);
+ bufp->kind = DRAG_N_DROP_EVENT;
+ bufp->frame_or_window = Fcons (frame, vec);
+ bufp->timestamp = CurrentTime;
+ bufp->x = make_number (x);
+ bufp->y = make_number (y);
+ bufp->arg = Qnil;
+ bufp->modifiers = 0;
+
+ return 1;
+}
+
+DEFUN ("x-send-client-message", Fx_send_client_event,
+ Sx_send_client_message, 6, 6, 0,
+ doc: /* Send a client message of MESSAGE-TYPE to window DEST on DISPLAY.
+
+For DISPLAY, specify either a frame or a display name (a string).
+If DISPLAY is nil, that stands for the selected frame's display.
+DEST may be a number, in which case it is a Window id. The value 0 may
+be used to send to the root window of the DISPLAY.
+If DEST is a cons, it is converted to a 32 bit number
+with the high 16 bits from the car and the lower 16 bit from the cdr. That
+number is then used as a window id.
+If DEST is a frame the event is sent to the outer window of that frame.
+Nil means the currently selected frame.
+If DEST is the string "PointerWindow" the event is sent to the window that
+contains the pointer. If DEST is the string "InputFocus" the event is
+sent to the window that has the input focus.
+FROM is the frame sending the event. Use nil for currently selected frame.
+MESSAGE-TYPE is the name of an Atom as a string.
+FORMAT must be one of 8, 16 or 32 and determines the size of the values in
+bits. VALUES is a list of numbers, cons and/or strings containing the values
+to send. If a value is a string, it is converted to an Atom and the value of
+the Atom is sent. If a value is a cons, it is converted to a 32 bit number
+with the high 16 bits from the car and the lower 16 bit from the cdr.
+If more values than fits into the event is given, the excessive values
+are ignored. */)
+ (display, dest, from, message_type, format, values)
+ Lisp_Object display, dest, from, message_type, format, values;
+{
+ struct x_display_info *dpyinfo = check_x_display_info (display);
+ Window wdest;
+ XEvent event;
+ Lisp_Object cons;
+ int size;
+ struct frame *f = check_x_frame (from);
+ int count;
+ int to_root;
+
+ CHECK_STRING (message_type);
+ CHECK_NUMBER (format);
+ CHECK_CONS (values);
+
+ if (x_check_property_data (values) == -1)
+ error ("Bad data in VALUES, must be number, cons or string");
+
+ event.xclient.type = ClientMessage;
+ event.xclient.format = XFASTINT (format);
+
+ if (event.xclient.format != 8 && event.xclient.format != 16
+ && event.xclient.format != 32)
+ error ("FORMAT must be one of 8, 16 or 32");
+
+ if (FRAMEP (dest) || NILP (dest))
+ {
+ struct frame *fdest = check_x_frame (dest);
+ wdest = FRAME_OUTER_WINDOW (fdest);
+ }
+ else if (STRINGP (dest))
+ {
+ if (strcmp (SDATA (dest), "PointerWindow") == 0)
+ wdest = PointerWindow;
+ else if (strcmp (SDATA (dest), "InputFocus") == 0)
+ wdest = InputFocus;
+ else
+ error ("DEST as a string must be one of PointerWindow or InputFocus");
+ }
+ else if (INTEGERP (dest))
+ wdest = (Window) XFASTINT (dest);
+ else if (FLOATP (dest))
+ wdest = (Window) XFLOAT (dest);
+ else if (CONSP (dest))
+ {
+ if (! NUMBERP (XCAR (dest)) || ! NUMBERP (XCDR (dest)))
+ error ("Both car and cdr for DEST must be numbers");
+ else
+ wdest = (Window) cons_to_long (dest);
+ }
+ else
+ error ("DEST must be a frame, nil, string, number or cons");
+
+ if (wdest == 0) wdest = dpyinfo->root_window;
+ to_root = wdest == dpyinfo->root_window;
+
+ for (cons = values, size = 0; CONSP (cons); cons = XCDR (cons), ++size)
+ ;
+
+ BLOCK_INPUT;
+
+ event.xclient.message_type
+ = XInternAtom (dpyinfo->display, SDATA (message_type), False);
+ event.xclient.display = dpyinfo->display;
+
+ /* Some clients (metacity for example) expects sending window to be here
+ when sending to the root window. */
+ event.xclient.window = to_root ? FRAME_OUTER_WINDOW (f) : wdest;
+
+ memset (event.xclient.data.b, 0, sizeof (event.xclient.data.b));
+ x_fill_property_data (dpyinfo->display, values, event.xclient.data.b,
+ event.xclient.format);
+
+ /* If event mask is 0 the event is sent to the client that created
+ the destination window. But if we are sending to the root window,
+ there is no such client. Then we set the event mask to 0xffff. The
+ event then goes to clients selecting for events on the root window. */
+ count = x_catch_errors (dpyinfo->display);
+ {
+ int propagate = to_root ? False : True;
+ unsigned mask = to_root ? 0xffff : 0;
+ XSendEvent (dpyinfo->display, wdest, propagate, mask, &event);
+ XFlush (dpyinfo->display);
+ }
+ x_uncatch_errors (dpyinfo->display, count);
+ UNBLOCK_INPUT;
+
+ return Qnil;
+}
+
+\f
void
syms_of_xselect ()
{
defsubr (&Sx_rotate_cut_buffers_internal);
#endif
+ defsubr (&Sx_get_atom_name);
+ defsubr (&Sx_send_client_message);
+
reading_selection_reply = Fcons (Qnil, Qnil);
staticpro (&reading_selection_reply);
reading_selection_window = 0;
DEFVAR_LISP ("next-selection-coding-system", &Vnext_selection_coding_system,
doc: /* Coding system for the next communication with other X clients.
Usually, `selection-coding-system' is used for communicating with
-other X clients. But, if this variable is set, it is used for the
-next communication only. After the communication, this variable is
+other X clients. But, if this variable is set, it is used for the
+next communication only. After the communication, this variable is
set to nil. */);
Vnext_selection_coding_system = Qnil;
QTIMESTAMP = intern ("TIMESTAMP"); staticpro (&QTIMESTAMP);
QTEXT = intern ("TEXT"); staticpro (&QTEXT);
QCOMPOUND_TEXT = intern ("COMPOUND_TEXT"); staticpro (&QCOMPOUND_TEXT);
+ QUTF8_STRING = intern ("UTF8_STRING"); staticpro (&QUTF8_STRING);
QTIMESTAMP = intern ("TIMESTAMP"); staticpro (&QTIMESTAMP);
QDELETE = intern ("DELETE"); staticpro (&QDELETE);
QMULTIPLE = intern ("MULTIPLE"); staticpro (&QMULTIPLE);
QCUT_BUFFER7 = intern ("CUT_BUFFER7"); staticpro (&QCUT_BUFFER7);
#endif
+ Qforeign_selection = intern ("foreign-selection");
+ staticpro (&Qforeign_selection);
}
+
+/* arch-tag: 7c293b0f-9918-4f69-8ac7-03e142307236
+ (do not change this comment) */