#include <config.h>
#include <stdio.h> /* termhooks.h needs this */
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
#include "lisp.h"
#include "xterm.h" /* for all of the X includes */
#include "dispextern.h" /* frame.h seems to want this */
#include "buffer.h"
#include "process.h"
#include "termhooks.h"
+#include "keyboard.h"
#include <X11/Xproto.h>
/* If the selection owner takes too long to reply to a selection request,
we give up on it. This is in milliseconds (0 = no timeout.) */
static EMACS_INT x_selection_timeout;
+
+
\f
-/* Utility functions */
+/* Define a queue to save up SELECTION_REQUEST_EVENT events for later
+ handling. */
+
+struct selection_event_queue
+ {
+ struct input_event event;
+ struct selection_event_queue *next;
+ };
-static void lisp_data_to_selection_data ();
-static Lisp_Object selection_data_to_lisp_data ();
-static Lisp_Object x_get_window_property_as_lisp_data ();
+static struct selection_event_queue *selection_queue;
+
+/* Nonzero means queue up SELECTION_REQUEST_EVENT events. */
+
+static int x_queue_selection_requests;
+
+/* Queue up an SELECTION_REQUEST_EVENT *EVENT, to be processed later. */
+
+static void
+x_queue_event (event)
+ struct input_event *event;
+{
+ struct selection_event_queue *queue_tmp;
+
+ /* Don't queue repeated requests.
+ This only happens for large requests which uses the incremental protocol. */
+ for (queue_tmp = selection_queue; queue_tmp; queue_tmp = queue_tmp->next)
+ {
+ if (!bcmp (&queue_tmp->event, event, sizeof (*event)))
+ {
+ TRACE1 ("DECLINE DUP SELECTION EVENT %08lx", (unsigned long)queue_tmp);
+ x_decline_selection_request (event);
+ return;
+ }
+ }
+
+ queue_tmp
+ = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue));
+
+ if (queue_tmp != NULL)
+ {
+ TRACE1 ("QUEUE SELECTION EVENT %08lx", (unsigned long)queue_tmp);
+ queue_tmp->event = *event;
+ queue_tmp->next = selection_queue;
+ selection_queue = queue_tmp;
+ }
+}
+
+/* Start queuing SELECTION_REQUEST_EVENT events. */
+
+static void
+x_start_queuing_selection_requests ()
+{
+ if (x_queue_selection_requests)
+ abort ();
+
+ x_queue_selection_requests++;
+ TRACE1 ("x_start_queuing_selection_requests %d", x_queue_selection_requests);
+}
+
+/* Stop queuing SELECTION_REQUEST_EVENT events. */
+
+static void
+x_stop_queuing_selection_requests ()
+{
+ TRACE1 ("x_stop_queuing_selection_requests %d", x_queue_selection_requests);
+ --x_queue_selection_requests;
+
+ /* Take all the queued events and put them back
+ so that they get processed afresh. */
+
+ while (selection_queue != NULL)
+ {
+ struct selection_event_queue *queue_tmp = selection_queue;
+ TRACE1 ("RESTORE SELECTION EVENT %08lx", (unsigned long)queue_tmp);
+ kbd_buffer_unget_event (&queue_tmp->event);
+ selection_queue = queue_tmp->next;
+ xfree ((char *)queue_tmp);
+ }
+}
+\f
/* This converts a Lisp symbol to a server Atom, avoiding a server
roundtrip whenever possible. */
Lisp_Object selection_name, selection_value;
{
struct frame *sf = SELECTED_FRAME ();
- Window selecting_window = FRAME_X_WINDOW (sf);
- Display *display = FRAME_X_DISPLAY (sf);
+ Window selecting_window;
+ Display *display;
Time time = last_event_timestamp;
Atom selection_atom;
- struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+ struct x_display_info *dpyinfo;
int count;
+ 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);
static struct prop_location *property_change_wait_list;
static Lisp_Object
-queue_selection_requests_unwind (frame)
- Lisp_Object frame;
+queue_selection_requests_unwind (tem)
+ Lisp_Object tem;
{
- FRAME_PTR f = XFRAME (frame);
-
- if (! NILP (frame))
- x_stop_queuing_selection_requests (FRAME_X_DISPLAY (f));
+ x_stop_queuing_selection_requests ();
return Qnil;
}
FOR_EACH_FRAME (list, frame)
{
- if (FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
+ if (FRAME_X_P (XFRAME (frame))
+ && FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
return frame;
}
bother trying to queue them. */
if (!NILP (frame))
{
- x_start_queuing_selection_requests (display);
+ x_start_queuing_selection_requests ();
record_unwind_protect (queue_selection_requests_unwind,
- frame);
+ Qnil);
}
if (x_window_to_frame (dpyinfo, window)) /* #### debug */
TRACE1 ("Set %s to number of bytes to send",
XGetAtomName (display, reply.property));
- XChangeProperty (display, window, reply.property, dpyinfo->Xatom_INCR,
- 32, PropModeReplace,
- (unsigned char *) &bytes_remaining, 1);
+ {
+ /* XChangeProperty expects an array of long even if long is more than
+ 32 bits. */
+ long value[1];
+
+ value[0] = bytes_remaining;
+ XChangeProperty (display, window, reply.property, dpyinfo->Xatom_INCR,
+ 32, PropModeReplace,
+ (unsigned char *) value, 1);
+ }
+
XSelectInput (display, window, PropertyChangeMask);
/* Tell 'em the INCR data is there... */
XGetAtomName (display, reply.property));
wait_for_property_change (wait_object);
}
+ else
+ unexpect_property_change (wait_object);
TRACE0 ("Got ACK");
while (bytes_remaining)
{
- int i = ((bytes_remaining < max_bytes)
- ? bytes_remaining
- : max_bytes);
+ int i = ((bytes_remaining < max_bytes)
+ ? bytes_remaining
+ : max_bytes);
BLOCK_INPUT;
/* Handle a SelectionRequest event EVENT.
This is called from keyboard.c when such an event is found in the queue. */
-void
+static void
x_handle_selection_request (event)
struct input_event *event;
{
struct x_display_info *dpyinfo
= x_display_info_for_display (SELECTION_EVENT_DISPLAY (event));
+ TRACE2 ("x_handle_selection_request, from=0x%08lx time=%lu",
+ (unsigned long) SELECTION_EVENT_REQUESTOR (event),
+ (unsigned long) SELECTION_EVENT_TIME (event));
+
local_selection_data = Qnil;
target_symbol = Qnil;
converted_selection = Qnil;
client cleared out our previously asserted selection.
This is called from keyboard.c when such an event is found in the queue. */
-void
+static void
x_handle_selection_clear (event)
struct input_event *event;
{
struct x_display_info *dpyinfo = x_display_info_for_display (display);
struct x_display_info *t_dpyinfo;
+ TRACE0 ("x_handle_selection_clear");
+
/* If the new selection owner is also Emacs,
don't clear the new selection. */
BLOCK_INPUT;
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->kboard == dpyinfo->kboard)
+ if (t_dpyinfo->frame_display->kboard == dpyinfo->frame_display->kboard)
{
Window owner_window
= XGetSelectionOwner (t_dpyinfo->display, selection);
}
}
+void
+x_handle_selection_event (event)
+ struct input_event *event;
+{
+ TRACE0 ("x_handle_selection_event");
+
+ if (event->kind == SELECTION_REQUEST_EVENT)
+ {
+ if (x_queue_selection_requests)
+ x_queue_event (event);
+ else
+ x_handle_selection_request (event);
+ }
+ else
+ x_handle_selection_clear (event);
+}
+
+
/* Clear all selections that were made from frame F.
We do this when about to delete a frame. */
/* Remove the property change expectation element for IDENTIFIER. */
static Lisp_Object
-wait_for_property_change_unwind (identifierval)
- Lisp_Object identifierval;
+wait_for_property_change_unwind (loc)
+ Lisp_Object loc;
{
- unexpect_property_change ((struct prop_location *)
- (XFASTINT (XCAR (identifierval)) << 16
- | XFASTINT (XCDR (identifierval))));
+ struct prop_location *location = XSAVE_VALUE (loc)->pointer;
+
+ unexpect_property_change (location);
+ if (location == property_change_reply_object)
+ property_change_reply_object = 0;
return Qnil;
}
{
int secs, usecs;
int count = SPECPDL_INDEX ();
- Lisp_Object tem;
- tem = Fcons (Qnil, Qnil);
- XSETCARFASTINT (tem, (EMACS_UINT)location >> 16);
- XSETCDRFASTINT (tem, (EMACS_UINT)location & 0xffff);
+ if (property_change_reply_object)
+ abort ();
/* Make sure to do unexpect_property_change if we quit or err. */
- record_unwind_protect (wait_for_property_change_unwind, tem);
+ record_unwind_protect (wait_for_property_change_unwind,
+ make_save_value (location, 0));
XSETCAR (property_change_reply, Qnil);
-
property_change_reply_object = location;
+
/* If the event we are waiting for arrives beyond here, it will set
property_change_reply, because property_change_reply_object says so. */
if (! location->arrived)
while (rest)
{
- if (rest->property == event->atom
+ if (!rest->arrived
+ && rest->property == event->atom
&& rest->window == event->window
&& rest->display == event->display
&& rest->desired_state == event->state)
if (rest == property_change_reply_object)
XSETCAR (property_change_reply, Qt);
- if (prev)
- prev->next = rest->next;
- else
- property_change_wait_list = rest->next;
- xfree (rest);
return;
}
Lisp_Object selection_symbol, target_type, time_stamp;
{
struct frame *sf = SELECTED_FRAME ();
- Window requestor_window = FRAME_X_WINDOW (sf);
- Display *display = FRAME_X_DISPLAY (sf);
- struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+ Window requestor_window;
+ Display *display;
+ struct x_display_info *dpyinfo;
Time requestor_time = last_event_timestamp;
- Atom target_property = dpyinfo->Xatom_EMACS_TMP;
- Atom selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol);
+ Atom target_property;
+ Atom selection_atom;
Atom type_atom;
int secs, usecs;
int count;
Lisp_Object frame;
+ if (! FRAME_X_P (sf))
+ return Qnil;
+
+ requestor_window = FRAME_X_WINDOW (sf);
+ display = FRAME_X_DISPLAY (sf);
+ dpyinfo = FRAME_X_DISPLAY_INFO (sf);
+ target_property = dpyinfo->Xatom_EMACS_TMP;
+ selection_atom = symbol_to_x_atom (dpyinfo, display, selection_symbol);
+
if (CONSP (target_type))
type_atom = symbol_to_x_atom (dpyinfo, display, XCAR (target_type));
else
else if (INTEGERP (time_stamp))
requestor_time = (Time) XUINT (time_stamp);
else if (FLOATP (time_stamp))
- requestor_time = (Time) XFLOAT (time_stamp);
+ requestor_time = (Time) XFLOAT_DATA (time_stamp);
else
error ("TIME_STAMP must be cons or number");
}
bother trying to queue them. */
if (!NILP (frame))
{
- x_start_queuing_selection_requests (display);
+ x_start_queuing_selection_requests ();
record_unwind_protect (queue_selection_requests_unwind,
- frame);
+ Qnil);
}
UNBLOCK_INPUT;
reading it. Deal with that, I guess.... */
if (result != Success)
break;
- *actual_size_ret *= *actual_format_ret / 8;
- bcopy (tmp_data, (*data_ret) + offset, *actual_size_ret);
- offset += *actual_size_ret;
+
+ /* The man page for XGetWindowProperty says:
+ "If the returned format is 32, the returned data is represented
+ as a long array and should be cast to that type to obtain the
+ elements."
+ This applies even if long is more than 32 bits, the X library
+ converts from 32 bit elements received from the X server to long
+ and passes the long array to us. Thus, for that case bcopy can not
+ be used. We convert to a 32 bit type here, because so much code
+ assume on that.
+
+ The bytes and offsets passed to XGetWindowProperty refers to the
+ property and those are indeed in 32 bit quantities if format is 32. */
+
+ if (*actual_format_ret == 32 && *actual_format_ret < BITS_PER_LONG)
+ {
+ unsigned long i;
+ int *idata = (int *) ((*data_ret) + offset);
+ long *ldata = (long *) tmp_data;
+
+ for (i = 0; i < *actual_size_ret; ++i)
+ {
+ idata[i]= (int) ldata[i];
+ offset += 4;
+ }
+ }
+ else
+ {
+ *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);
BLOCK_INPUT;
XSelectInput (display, window, STANDARD_EVENT_SET | PropertyChangeMask);
TRACE1 (" Delete property %s",
- SDATA (XSYMBOL (x_atom_to_symbol (display, property))->xname));
+ SDATA (SYMBOL_NAME (x_atom_to_symbol (display, property))));
XDeleteProperty (display, window, property);
TRACE1 (" Expect new value of property %s",
- SDATA (XSYMBOL (x_atom_to_symbol (display, property))->xname));
+ SDATA (SYMBOL_NAME (x_atom_to_symbol (display, property))));
wait_object = expect_property_change (display, window, property,
PropertyNewValue);
XFlush (display);
if (! waiting_for_other_props_on_window (display, window))
XSelectInput (display, window, STANDARD_EVENT_SET);
- unexpect_property_change (wait_object);
/* Use xfree, not XFree, because x_get_window_property
calls xmalloc itself. */
if (tmp_data) xfree (tmp_data);
When converting an object to C, it may be of the form (SYMBOL . <data>)
where SYMBOL is what we should claim that the type is. Format and
- representation are as above. */
+ representation are as above.
+
+ Important: When format is 32, data should contain an array of int,
+ not an array of long as the X library returns. This makes a difference
+ when sizeof(long) != sizeof(int). */
else if (type == XA_ATOM)
{
int i;
- if (size == sizeof (Atom))
- return x_atom_to_symbol (display, *((Atom *) data));
+ /* On a 64 bit machine sizeof(Atom) == sizeof(long) == 8.
+ But the callers of these function has made sure the data for
+ format == 32 is an array of int. Thus, use int instead
+ of Atom. */
+ int *idata = (int *) data;
+
+ if (size == sizeof (int))
+ return x_atom_to_symbol (display, (Atom) idata[0]);
else
{
- Lisp_Object v = Fmake_vector (make_number (size / sizeof (Atom)),
+ Lisp_Object v = Fmake_vector (make_number (size / sizeof (int)),
make_number (0));
- for (i = 0; i < size / sizeof (Atom); i++)
+ for (i = 0; i < size / sizeof (int); i++)
Faset (v, make_number (i),
- x_atom_to_symbol (display, ((Atom *) data) [i]));
+ x_atom_to_symbol (display, (Atom) idata[i]));
return v;
}
}
}
else if (STRINGP (obj))
{
- xassert (! STRING_MULTIBYTE (obj));
+ if (SCHARS (obj) < SBYTES (obj))
+ /* OBJ is a multibyte string containing a non-ASCII char. */
+ Fsignal (Qerror, /* Qselection_error */
+ Fcons (build_string
+ ("Non-ASCII string must be encoded in advance"),
+ Fcons (obj, Qnil)));
if (NILP (type))
type = QSTRING;
*format_ret = 8;
else
/* This vector is an INTEGER set, or something like it */
{
+ int data_size = 2;
*size_ret = XVECTOR (obj)->size;
if (NILP (type)) type = QINTEGER;
*format_ret = 16;
("elements of selection vector must be integers or conses of integers"),
Fcons (obj, Qnil)));
- *data_ret = (unsigned char *) xmalloc (*size_ret * (*format_ret/8));
+ /* Use sizeof(long) even if it is more than 32 bits. See comment
+ in x_get_window_property and x_fill_property_data. */
+
+ if (*format_ret == 32) data_size = sizeof(long);
+ *data_ret = (unsigned char *) xmalloc (*size_ret * data_size);
for (i = 0; i < *size_ret; i++)
if (*format_ret == 32)
(*((unsigned long **) data_ret)) [i]
}
else
Fsignal (Qerror, /* Qselection_error */
- Fcons (build_string ("unrecognised selection data"),
+ Fcons (build_string ("unrecognized selection data"),
Fcons (obj, Qnil)));
*type_ret = symbol_to_x_atom (dpyinfo, display, type);
{
check_x ();
CHECK_SYMBOL (selection_name);
- if (NILP (selection_value)) error ("selection-value may not be nil");
+ if (NILP (selection_value)) error ("SELECTION-VALUE may not be nil");
x_own_selection (selection_name, selection_value);
return selection_value;
}
{
Time timestamp;
Atom selection_atom;
- struct selection_input_event event;
+ union {
+ struct selection_input_event sie;
+ struct input_event ie;
+ } event;
Display *display;
struct x_display_info *dpyinfo;
struct frame *sf = SELECTED_FRAME ();
check_x ();
+ if (! FRAME_X_P (sf))
+ return Qnil;
+
display = FRAME_X_DISPLAY (sf);
dpyinfo = FRAME_X_DISPLAY_INFO (sf);
CHECK_SYMBOL (selection);
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) = display;
- SELECTION_EVENT_SELECTION (&event) = selection_atom;
- SELECTION_EVENT_TIME (&event) = timestamp;
- x_handle_selection_clear ((struct input_event *) &event);
+ SELECTION_EVENT_DISPLAY (&event.sie) = display;
+ SELECTION_EVENT_SELECTION (&event.sie) = selection_atom;
+ SELECTION_EVENT_TIME (&event.sie) = timestamp;
+ x_handle_selection_clear (&event.ie);
return Qt;
}
struct frame *sf = SELECTED_FRAME ();
check_x ();
+
+ if (! FRAME_X_P (sf))
+ return Qnil;
+
display = FRAME_X_DISPLAY (sf);
dpyinfo = FRAME_X_DISPLAY_INFO (sf);
window = RootWindow (display, 0); /* Cut buffers are on screen 0 */
Fcons (x_atom_to_symbol (display, type),
Fcons (make_number (format), Qnil))));
- ret = (bytes ? make_string ((char *) data, bytes) : Qnil);
+ ret = (bytes ? make_unibyte_string ((char *) data, bytes) : Qnil);
/* Use xfree, not XFree, because x_get_window_property
calls xmalloc itself. */
xfree (data);
struct frame *sf = SELECTED_FRAME ();
check_x ();
+
+ if (! FRAME_X_P (sf))
+ return Qnil;
+
display = FRAME_X_DISPLAY (sf);
window = RootWindow (display, 0); /* Cut buffers are on screen 0 */
Atom props[8];
Display *display;
struct frame *sf = SELECTED_FRAME ();
-
+
check_x ();
+
+ if (! FRAME_X_P (sf))
+ return Qnil;
+
display = FRAME_X_DISPLAY (sf);
window = RootWindow (display, 0); /* Cut buffers are on screen 0 */
CHECK_NUMBER (n);
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. */
+ it is big enough to hold all values.
+ FORMAT is 8, 16 or 32 and denotes char/short/long for each C value to
+ be stored in RET. Note that long is used for 32 even if long is more
+ than 32 bits (see man pages for XChangeProperty, XGetWindowProperty and
+ XClientMessageEvent). */
void
x_fill_property_data (dpy, data, ret, format)
void *ret;
int format;
{
- CARD32 val;
- CARD32 *d32 = (CARD32 *) ret;
- CARD16 *d16 = (CARD16 *) ret;
- CARD8 *d08 = (CARD8 *) ret;
+ long val;
+ long *d32 = (long *) ret;
+ short *d16 = (short *) ret;
+ char *d08 = (char *) ret;
Lisp_Object iter;
for (iter = data; CONSP (iter); iter = XCDR (iter))
Lisp_Object o = XCAR (iter);
if (INTEGERP (o))
- val = (CARD32) XFASTINT (o);
+ val = (long) XFASTINT (o);
else if (FLOATP (o))
- val = (CARD32) XFLOAT (o);
+ val = (long) XFLOAT_DATA (o);
else if (CONSP (o))
- val = (CARD32) cons_to_long (o);
+ val = (long) cons_to_long (o);
else if (STRINGP (o))
{
BLOCK_INPUT;
- val = XInternAtom (dpy, (char *) SDATA (o), False);
+ val = (long) XInternAtom (dpy, (char *) SDATA (o), False);
UNBLOCK_INPUT;
}
else
error ("Wrong type, must be string, number or cons");
if (format == 8)
- *d08++ = (CARD8) val;
+ *d08++ = (char) val;
else if (format == 16)
- *d16++ = (CARD16) val;
+ *d16++ = (short) val;
else
*d32++ = val;
}
be stored in RET.
SIZE is the number of elements in DATA.
+ Important: When format is 32, data should contain an array of int,
+ not an array of long as the X library returns. This makes a difference
+ when sizeof(long) != sizeof(int).
+
Also see comment for selection_data_to_lisp_data above. */
Lisp_Object
data, size*format/8, type, format);
}
-/* Get the mouse position frame relative coordinates. */
+/* Get the mouse position in frame relative coordinates. */
static void
mouse_position_for_drop (f, x, y)
if (INTEGERP (value))
atom = (Atom) XUINT (value);
else if (FLOATP (value))
- atom = (Atom) XFLOAT (value);
+ atom = (Atom) XFLOAT_DATA (value);
else if (CONSP (value))
atom = (Atom) cons_to_long (value);
else
{
Lisp_Object vec;
Lisp_Object frame;
- unsigned long size = (8*sizeof (event->data))/event->format;
+ /* format 32 => size 5, format 16 => size 10, format 8 => size 20 */
+ unsigned long size = 160/event->format;
int x, y;
+ unsigned char *data = (unsigned char *) event->data.b;
+ int idata[5];
XSETFRAME (frame, f);
+ /* On a 64 bit machine, the event->data.l array members are 64 bits (long),
+ but the x_property_data_to_lisp (or rather selection_data_to_lisp_data)
+ function expects them to be of size int (i.e. 32). So to be able to
+ use that function, put the data in the form it expects if format is 32. */
+
+ if (event->format == 32 && event->format < BITS_PER_LONG)
+ {
+ int i;
+ for (i = 0; i < 5; ++i) /* There are only 5 longs in a ClientMessage. */
+ idata[i] = (int) event->data.l[i];
+ data = (unsigned char *) idata;
+ }
+
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,
+ data,
event->message_type,
event->format,
size);
else if (INTEGERP (dest))
wdest = (Window) XFASTINT (dest);
else if (FLOATP (dest))
- wdest = (Window) XFLOAT (dest);
+ wdest = (Window) XFLOAT_DATA (dest);
else if (CONSP (dest))
{
if (! NUMBERP (XCAR (dest)) || ! NUMBERP (XCDR (dest)))
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);