summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:39 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:39 +0000
commit65a2b6d50473730673749ad2facc248ea41af00a (patch)
tree421f94bd9c97412f086dcf5352e33f391324cb47
downloadxorg-lib-libXtst-65a2b6d50473730673749ad2facc248ea41af00a.tar.gz
R6.6 is the Xorg base-lineXORG-MAINXORG-STABLE
-rw-r--r--src/XRecord.c1106
-rw-r--r--src/XTest.c488
2 files changed, 1594 insertions, 0 deletions
diff --git a/src/XRecord.c b/src/XRecord.c
new file mode 100644
index 0000000..8c32491
--- /dev/null
+++ b/src/XRecord.c
@@ -0,0 +1,1106 @@
+/*
+$Xorg: XRecord.c,v 1.4 2001/02/09 02:04:00 xorgcvs Exp $
+
+XRecord.c - client-side library for RECORD extension
+
+Copyright 1995, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+/***************************************************************************
+ * Copyright 1995 Network Computing Devices
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Network Computing Devices
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission.
+ *
+ * NETWORK COMPUTING DEVICES DISCLAIMs ALL WARRANTIES WITH REGARD TO
+ * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE
+ * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ **************************************************************************/
+/*
+ * By Stephen Gildea, X Consortium, and Martha Zimet, NCD.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+#define NEED_EVENTS
+#define NEED_REPLIES
+#include <X11/Xlibint.h>
+#include "Xext.h"
+#include <X11/Xtrans.h>
+#include "extutil.h"
+#include "recordstr.h"
+
+extern unsigned long _XSetLastRequestRead();
+
+static XExtensionInfo _xrecord_info_data;
+static XExtensionInfo *xrecord_info = &_xrecord_info_data;
+static /* const */ char *xrecord_extension_name = RECORD_NAME;
+
+#define XRecordCheckExtension(dpy,i,val) \
+ XextCheckExtension(dpy, i, xrecord_extension_name, val)
+
+/**************************************************************************
+ * *
+ * private utility routines *
+ * *
+ **************************************************************************/
+
+static XExtDisplayInfo *find_display();
+
+/*
+ * A reply buffer holds a reply from RecordEnableContext.
+ * Pieces of that buffer are passed to the XRecordEnableContext callback.
+ * ref_count is incremented each time we do that.
+ * ref_count is decremented each time XRecordFreeData is called on
+ * the buffer. When ref_count is 0, we can free or reuse the buffer.
+ */
+struct reply_buffer
+{
+ struct reply_buffer *next; /* next in list or NULL */
+ unsigned char *buf; /* pointer to malloc'd buffer */
+ int nbytes; /* size of buf */
+ int ref_count; /* callback uses pending */
+};
+
+
+/*
+ * There's some extra information the implementation finds useful
+ * to attach to an XRecordInterceptData packet to handle memory
+ * management. So we really allocate one of these.
+ */
+struct intercept_queue
+{
+ /* this struct gets passed to the user as an XRecordInterceptData,
+ so the data field must come first so we can cast the address
+ back and forth */
+ XRecordInterceptData data;
+ struct intercept_queue *next; /* next in free list or NULL */
+ struct mem_cache_str *cache; /* contains head of free list */
+};
+
+/*
+ * per-display pointers to cache of malloc'd but unused memory
+ */
+struct mem_cache_str
+{
+ struct intercept_queue *inter_data; /* free structs only */
+ struct reply_buffer *reply_buffers; /* all reply buffers */
+ int inter_data_count; /* total allocated, free and in use */
+ Bool display_closed; /* so we know when to free ourself */
+};
+
+static int close_display(dpy, codes)
+ Display *dpy;
+ XExtCodes *codes; /* not used */
+{
+ XExtDisplayInfo *info = find_display (dpy);
+
+ LockDisplay(dpy);
+ if (info && info->data) {
+ struct mem_cache_str *cache = (struct mem_cache_str *)info->data;
+ struct intercept_queue *iq, *iq_next;
+ struct reply_buffer *rbp, **rbp_next_p;
+
+ for (iq=cache->inter_data; iq; iq=iq_next) {
+ iq_next = iq->next;
+ XFree(iq);
+ cache->inter_data_count--;
+ }
+
+ /* this is a little trickier, because some of these
+ might still be in use */
+ for (rbp_next_p = &cache->reply_buffers; *rbp_next_p; ) {
+ rbp = *rbp_next_p;
+ if (rbp->ref_count == 0) {
+ *rbp_next_p = rbp->next;
+ XFree(rbp->buf);
+ XFree(rbp);
+ } else {
+ rbp_next_p = &rbp->next;
+ }
+ }
+
+ if (cache->reply_buffers == NULL && cache->inter_data_count == 0) {
+ /* every thing has been freed, can free ourselves, too */
+ XFree(cache);
+ } else {
+ cache->display_closed = True;
+ cache->inter_data = NULL; /* neatness only; won't be used */
+ }
+ }
+ UnlockDisplay(dpy);
+ return XextRemoveDisplay(xrecord_info, dpy);
+}
+
+static XPointer alloc_mem_cache()
+{
+ struct mem_cache_str *cache;
+
+ /* note that an error will go unnoticed */
+ cache = (struct mem_cache_str *) Xmalloc(sizeof(struct mem_cache_str));
+ if (cache) {
+ cache->display_closed = False;
+ cache->inter_data = NULL;
+ cache->inter_data_count = 0;
+ cache->reply_buffers = NULL;
+ }
+ return (XPointer) cache;
+}
+
+static char *xrecord_error_list[] = {
+ "XRecordBadContext (Not a defined RECORD context)",
+};
+
+static XEXT_GENERATE_ERROR_STRING (error_string, xrecord_extension_name,
+ RecordNumErrors, xrecord_error_list)
+
+static XExtensionHooks xrecord_extension_hooks = {
+ NULL, /* create_gc */
+ NULL, /* copy_gc */
+ NULL, /* flush_gc */
+ NULL, /* free_gc */
+ NULL, /* create_font */
+ NULL, /* free_font */
+ close_display, /* close_display */
+ NULL, /* wire_to_event */
+ NULL, /* event_to_wire */
+ NULL, /* error */
+ error_string /* error_string */
+};
+
+static XEXT_GENERATE_FIND_DISPLAY (find_display, xrecord_info,
+ xrecord_extension_name, &xrecord_extension_hooks, RecordNumEvents,
+ alloc_mem_cache())
+
+/**************************************************************************
+ * *
+ * private library routines *
+ * *
+ **************************************************************************/
+
+static void
+SendRange(dpy, range_item, nranges)
+ Display *dpy;
+ XRecordRange **range_item;
+ int nranges;
+{
+ int rlen = SIZEOF(xRecordRange);
+ while(nranges--)
+ {
+ xRecordRange xrange;
+
+ xrange.coreRequestsFirst = (*range_item)->core_requests.first;
+ xrange.coreRequestsLast = (*range_item)->core_requests.last;
+ xrange.coreRepliesFirst = (*range_item)->core_replies.first;
+ xrange.coreRepliesLast = (*range_item)->core_replies.last;
+ xrange.extRequestsMajorFirst = (*range_item)->ext_requests.ext_major.first;
+ xrange.extRequestsMajorLast = (*range_item)->ext_requests.ext_major.last;
+ xrange.extRequestsMinorFirst = (*range_item)->ext_requests.ext_minor.first;
+ xrange.extRequestsMinorLast = (*range_item)->ext_requests.ext_minor.last;
+ xrange.extRepliesMajorFirst = (*range_item)->ext_replies.ext_major.first;
+ xrange.extRepliesMajorLast = (*range_item)->ext_replies.ext_major.last;
+ xrange.extRepliesMinorFirst = (*range_item)->ext_replies.ext_minor.first;
+ xrange.extRepliesMinorLast = (*range_item)->ext_replies.ext_minor.last;
+ xrange.deliveredEventsFirst = (*range_item)->delivered_events.first;
+ xrange.deliveredEventsLast = (*range_item)->delivered_events.last;
+ xrange.deviceEventsFirst = (*range_item)->device_events.first;
+ xrange.deviceEventsLast = (*range_item)->device_events.last;
+ xrange.errorsFirst = (*range_item)->errors.first;
+ xrange.errorsLast = (*range_item)->errors.last;
+ xrange.clientStarted = (*range_item)->client_started;
+ xrange.clientDied = (*range_item)->client_died;
+
+ Data(dpy, (char *)&xrange, rlen);
+ range_item++;
+ }
+}
+
+/**************************************************************************
+ * *
+ * public routines *
+ * *
+ **************************************************************************/
+
+XID
+XRecordIdBaseMask(dpy)
+ Display *dpy;
+{
+ return 0x1fffffff & ~dpy->resource_mask;
+}
+
+Status
+XRecordQueryVersion (dpy, cmajor_return, cminor_return)
+ Display *dpy;
+ int *cmajor_return, *cminor_return;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xRecordQueryVersionReq *req;
+ xRecordQueryVersionReply rep;
+
+ XRecordCheckExtension (dpy, info, False);
+
+ LockDisplay(dpy);
+ GetReq(RecordQueryVersion, req);
+ req->reqType = info->codes->major_opcode;
+ req->recordReqType = X_RecordQueryVersion;
+ req->majorVersion = RECORD_MAJOR_VERSION;
+ req->minorVersion = RECORD_MINOR_VERSION;
+ if (!_XReply(dpy,(xReply *)&rep, 0, True)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ UnlockDisplay(dpy);
+ SyncHandle();
+ *cmajor_return = rep.majorVersion;
+ *cminor_return = rep.minorVersion;
+ return ((rep.majorVersion == RECORD_MAJOR_VERSION) &&
+ (rep.minorVersion >= RECORD_LOWEST_MINOR_VERSION));
+}
+
+XRecordContext
+XRecordCreateContext(dpy, datum_flags, clients, nclients, ranges, nranges)
+ Display *dpy;
+ int datum_flags;
+ XRecordClientSpec *clients;
+ int nclients;
+ XRecordRange **ranges;
+ int nranges;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xRecordCreateContextReq *req;
+ int clen = 4 * nclients;
+
+ XRecordCheckExtension (dpy, info, 0);
+ LockDisplay(dpy);
+ GetReq(RecordCreateContext, req);
+
+ req->reqType = info->codes->major_opcode;
+ req->recordReqType = X_RecordCreateContext;
+ req->context = XAllocID(dpy);
+ req->length += (nclients * 4 +
+ nranges * SIZEOF(xRecordRange)) >> 2;
+ req->elementHeader = datum_flags;
+ req->nClients = nclients;
+ req->nRanges = nranges;
+
+ Data32(dpy, (long *)clients, clen);
+ SendRange(dpy, ranges, nranges);
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return req->context;
+}
+
+XRecordRange *
+XRecordAllocRange()
+{
+ return (XRecordRange*)Xcalloc(1, sizeof(XRecordRange));
+}
+
+Status
+XRecordRegisterClients(dpy, context, datum_flags, clients, nclients, ranges, nranges)
+ Display *dpy;
+ XRecordContext context;
+ int datum_flags;
+ XRecordClientSpec *clients;
+ int nclients;
+ XRecordRange **ranges;
+ int nranges;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xRecordRegisterClientsReq *req;
+ int clen = 4 * nclients;
+
+ XRecordCheckExtension (dpy, info, 0);
+ LockDisplay(dpy);
+ GetReq(RecordRegisterClients, req);
+
+ req->reqType = info->codes->major_opcode;
+ req->recordReqType = X_RecordRegisterClients;
+ req->context = context;
+ req->length += (nclients * 4 +
+ nranges * SIZEOF(xRecordRange)) >> 2;
+ req->elementHeader = datum_flags;
+ req->nClients = nclients;
+ req->nRanges = nranges;
+
+ Data32(dpy, (long *)clients, clen);
+ SendRange(dpy, ranges, nranges);
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+Status
+XRecordUnregisterClients(dpy, context, clients, nclients)
+ Display *dpy;
+ XRecordContext context;
+ XRecordClientSpec *clients;
+ int nclients;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xRecordUnregisterClientsReq *req;
+ int clen = 4 * nclients;
+
+ XRecordCheckExtension (dpy, info, 0);
+ LockDisplay(dpy);
+ GetReq(RecordUnregisterClients, req);
+
+ req->reqType = info->codes->major_opcode;
+ req->recordReqType = X_RecordUnregisterClients;
+ req->context = context;
+ req->length += nclients;
+ req->nClients = nclients;
+
+ Data32(dpy, (long *)clients, clen);
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+static void
+WireToLibRange(wire_range, lib_range)
+ xRecordRange *wire_range;
+ XRecordRange *lib_range;
+{
+ lib_range->core_requests.first = wire_range->coreRequestsFirst;
+ lib_range->core_requests.last = wire_range->coreRequestsLast;
+ lib_range->core_replies.first = wire_range->coreRepliesFirst;
+ lib_range->core_replies.last = wire_range->coreRepliesLast;
+ lib_range->ext_requests.ext_major.first = wire_range->extRequestsMajorFirst;
+ lib_range->ext_requests.ext_major.last = wire_range->extRequestsMajorLast;
+ lib_range->ext_requests.ext_minor.first = wire_range->extRequestsMinorFirst;
+ lib_range->ext_requests.ext_minor.last = wire_range->extRequestsMinorLast;
+ lib_range->ext_replies.ext_major.first = wire_range->extRepliesMajorFirst;
+ lib_range->ext_replies.ext_major.last = wire_range->extRepliesMajorLast;
+ lib_range->ext_replies.ext_minor.first = wire_range->extRepliesMinorFirst;
+ lib_range->ext_replies.ext_minor.last = wire_range->extRepliesMinorLast;
+ lib_range->delivered_events.first = wire_range->deliveredEventsFirst;
+ lib_range->delivered_events.last = wire_range->deliveredEventsLast;
+ lib_range->device_events.first = wire_range->deviceEventsFirst;
+ lib_range->device_events.last = wire_range->deviceEventsLast;
+ lib_range->errors.first = wire_range->errorsFirst;
+ lib_range->errors.last = wire_range->errorsLast;
+ lib_range->client_started = wire_range->clientStarted;
+ lib_range->client_died = wire_range->clientDied;
+}
+
+Status
+XRecordGetContext(dpy, context, state_return)
+ Display *dpy;
+ XRecordContext context;
+ XRecordState **state_return;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xRecordGetContextReq *req;
+ xRecordGetContextReply rep;
+ int count, i, rn;
+ xRecordRange xrange;
+ XRecordRange *ranges;
+ xRecordClientInfo xclient_inf;
+ XRecordClientInfo **client_inf, *client_inf_str;
+ XRecordState *ret;
+
+ XRecordCheckExtension (dpy, info, 0);
+ LockDisplay(dpy);
+ GetReq(RecordGetContext, req);
+ req->reqType = info->codes->major_opcode;
+ req->recordReqType = X_RecordGetContext;
+ req->context = context;
+ if (!_XReply(dpy,(xReply *)&rep, 0, False)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 0;
+ }
+ count = rep.nClients;
+
+ ret = (XRecordState*)Xmalloc(sizeof(XRecordState));
+ if (!ret) {
+ /* XXX - eat data */
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 0;
+ }
+
+ ret->enabled = rep.enabled;
+ ret->datum_flags = rep.elementHeader;
+ ret->nclients = count;
+
+ if (count)
+ {
+ client_inf = (XRecordClientInfo **) Xcalloc(count, sizeof(XRecordClientInfo*));
+ ret->client_info = client_inf;
+ client_inf_str = (XRecordClientInfo *) Xmalloc(count*sizeof(XRecordClientInfo));
+ if (!client_inf || !client_inf_str)
+ {
+ for(i = 0; i < count; i++)
+ {
+ _XEatData (dpy, sizeof(xRecordClientInfo));
+ _XEatData (dpy, SIZEOF(xRecordRange)); /* XXX - don't know how many */
+ }
+ UnlockDisplay(dpy);
+ XRecordFreeState(ret);
+ SyncHandle();
+ return 0;
+ }
+ for(i = 0; i < count; i++)
+ {
+ client_inf[i] = &(client_inf_str[i]);
+ _XRead(dpy, (char *)&xclient_inf, (long)sizeof(xRecordClientInfo));
+ client_inf_str[i].client = xclient_inf.clientResource;
+ client_inf_str[i].nranges = xclient_inf.nRanges;
+
+ if (xclient_inf.nRanges)
+ {
+ client_inf_str[i].ranges = (XRecordRange**) Xcalloc(xclient_inf.nRanges, sizeof(XRecordRange*));
+ ranges = (XRecordRange*) Xmalloc(xclient_inf.nRanges * sizeof(XRecordRange));
+ if (!client_inf_str[i].ranges || !ranges) {
+ /* XXX eat data */
+ UnlockDisplay(dpy);
+ XRecordFreeState(ret);
+ SyncHandle();
+ return 0;
+ }
+ for (rn=0; rn<xclient_inf.nRanges; rn++) {
+ client_inf_str[i].ranges[rn] = &(ranges[rn]);
+ _XRead(dpy, (char *)&xrange, (long)sizeof(xRecordRange));
+ WireToLibRange(&xrange, &(ranges[rn]));
+ }
+ } else {
+ client_inf_str[i].ranges = NULL;
+ }
+ }
+ } else {
+ ret->client_info = NULL;
+ }
+
+ *state_return = ret;
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+void
+XRecordFreeState(state)
+ XRecordState *state;
+{
+ int i;
+
+ for(i=0; i<state->nclients; i++) {
+ if (state->client_info[i]->ranges) {
+ if (state->client_info[i]->ranges[0])
+ Xfree(state->client_info[i]->ranges[0]);
+ Xfree(state->client_info[i]->ranges);
+ }
+ }
+ if (state->client_info) {
+ if (state->client_info[0])
+ Xfree(state->client_info[0]);
+ Xfree(state->client_info);
+ }
+ Xfree(state);
+}
+
+static struct reply_buffer *alloc_reply_buffer(info, nbytes)
+ XExtDisplayInfo *info;
+ int nbytes;
+{
+ struct mem_cache_str *cache = (struct mem_cache_str *)info->data;
+ struct reply_buffer *rbp;
+ struct reply_buffer *saved_rb = NULL;
+ /*
+ * First look for an allocated buffer that is not in use.
+ * If we have a big enough buffer, use that, otherwise
+ * realloc an existing one.
+ */
+ for (rbp = cache->reply_buffers; rbp; rbp = rbp->next) {
+ if (rbp->ref_count == 0) {
+ if (rbp->nbytes >= nbytes)
+ return rbp;
+ else
+ saved_rb = rbp;
+ }
+ }
+ if (saved_rb) {
+ saved_rb->buf = (unsigned char *)Xrealloc(saved_rb->buf, nbytes);
+ if (!saved_rb->buf) {
+ saved_rb->nbytes = 0;
+ return NULL;
+ }
+ saved_rb->nbytes = nbytes;
+ return saved_rb;
+ }
+
+ /*
+ * nothing available; malloc a new struct
+ */
+ rbp = (struct reply_buffer *)Xmalloc(sizeof(struct reply_buffer));
+ if (!rbp)
+ return NULL;
+ rbp->buf = (unsigned char *)Xmalloc(nbytes);
+ if (!rbp->buf) {
+ Xfree(rbp);
+ return NULL;
+ }
+ rbp->nbytes = nbytes;
+ rbp->ref_count = 0;
+ rbp->next = cache->reply_buffers;
+ cache->reply_buffers = rbp;
+ return rbp;
+}
+
+static XRecordInterceptData *alloc_inter_data(info)
+ XExtDisplayInfo *info;
+{
+ struct mem_cache_str *cache = (struct mem_cache_str *)info->data;
+ struct intercept_queue *iq;
+
+ /* if there is one on the free list, pop it */
+ if (cache->inter_data) {
+ iq = cache->inter_data;
+ cache->inter_data = iq->next;
+ return &iq->data;
+ }
+ /* allocate a new one */
+ iq = (struct intercept_queue *)Xmalloc(sizeof(struct intercept_queue));
+ if (!iq)
+ return NULL;
+ iq->cache = cache;
+ cache->inter_data_count++;
+ return &iq->data;
+}
+
+void
+XRecordFreeData(data)
+ XRecordInterceptData *data;
+{
+ /* we can do this cast because that is what we really allocated */
+ struct intercept_queue *iq = (struct intercept_queue *)data;
+ struct reply_buffer *rbp = NULL;
+ struct mem_cache_str *cache = iq->cache;
+
+ /*
+ * figure out what reply_buffer this points at
+ * and decrement its ref_count.
+ */
+ if (data->data) {
+
+ for (rbp = cache->reply_buffers; rbp; rbp = rbp->next) {
+ if (data->data >= rbp->buf
+ && data->data < rbp->buf + rbp->nbytes)
+ {
+ assert(rbp->ref_count > 0);
+ rbp->ref_count--;
+ break;
+ }
+ }
+ /* it's an error if we didn't find something to free */
+ assert(rbp);
+ }
+ /*
+ * If the display is still open, put this back on the free queue.
+ *
+ * Otherwise the display is closed and we won't reuse this, so free it.
+ * See if we can free the reply buffer, too.
+ * If we can, see if this is the last reply buffer and if so
+ * free the list of reply buffers.
+ */
+ if (cache->display_closed == False) {
+ iq->next = cache->inter_data;
+ cache->inter_data = iq;
+ } else {
+ if (rbp && rbp->ref_count == 0) {
+ struct reply_buffer *rbp2, **rbp_next_p;
+
+ /* Have to search the list again to find the prev element.
+ This is not the common case, so don't slow down the code
+ above by doing it then. */
+ for (rbp_next_p = &cache->reply_buffers; *rbp_next_p; ) {
+ rbp2 = *rbp_next_p;
+ if (rbp == rbp2) {
+ *rbp_next_p = rbp2->next;
+ break;
+ } else {
+ rbp_next_p = &rbp2->next;
+ }
+ }
+ XFree(rbp->buf);
+ XFree(rbp);
+ }
+
+ XFree(iq);
+ cache->inter_data_count--;
+
+ if (cache->reply_buffers == NULL && cache->inter_data_count == 0) {
+ XFree(cache); /* all finished */
+ }
+ }
+}
+
+/* the EXTRACT macros are adapted from ICElibint.h */
+
+#ifndef WORD64
+
+#define EXTRACT_CARD16(swap, src, dst) \
+{ \
+ (dst) = *((CARD16 *) (src)); \
+ if (swap) \
+ (dst) = lswaps (dst); \
+}
+
+#define EXTRACT_CARD32(swap, src, dst) \
+{ \
+ (dst) = *((CARD32 *) (src)); \
+ if (swap) \
+ (dst) = lswapl (dst); \
+}
+
+#else /* WORD64 */
+
+#define EXTRACT_CARD16(swap, src, dst) \
+{ \
+ (dst) = *((src) + 0); \
+ (dst) <<= 8; \
+ (dst) |= *((src) + 1); \
+ if (swap) \
+ (dst) = lswaps (dst); \
+}
+
+#define EXTRACT_CARD32(swap, src, dst) \
+{ \
+ (dst) = *((src) + 0); \
+ (dst) <<= 8; \
+ (dst) |= *((src) + 1); \
+ (dst) <<= 8; \
+ (dst) |= *((src) + 2); \
+ (dst) <<= 8; \
+ (dst) |= *((src) + 3); \
+ if (swap) \
+ (dst) = lswapl (dst); \
+}
+
+#endif /* WORD64 */
+
+/* byte swapping macros from xfs/include/misc.h */
+
+/* byte swap a long literal */
+#define lswapl(x) ((((x) & 0xff) << 24) |\
+ (((x) & 0xff00) << 8) |\
+ (((x) & 0xff0000) >> 8) |\
+ (((x) >> 24) & 0xff))
+
+/* byte swap a short literal */
+#define lswaps(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff))
+
+enum parser_return { Continue, End, Error };
+
+static enum parser_return
+parse_reply_call_callback(dpy, info, rep, reply, callback, closure)
+ Display *dpy;
+ XExtDisplayInfo *info;
+ xRecordEnableContextReply *rep;
+ struct reply_buffer *reply;
+ XRecordInterceptProc callback;
+ XPointer closure;
+{
+ int current_index;
+ int datum_bytes;
+ XRecordInterceptData *data;
+
+ /* call the callback for each protocol element in the reply */
+ current_index = 0;
+ do {
+ data = alloc_inter_data(info);
+ if (!data)
+ return Error;
+
+ data->id_base = rep->idBase;
+ data->category = rep->category;
+ data->client_swapped = rep->clientSwapped;
+ data->server_time = rep->serverTime;
+ data->client_seq = rep->recordedSequenceNumber;
+ /*
+ * compute the size of this protocol element.
+ */
+ switch (rep->category) {
+ case XRecordFromServer:
+ if (rep->elementHeader&XRecordFromServerTime) {
+ EXTRACT_CARD32(rep->clientSwapped,
+ reply->buf+current_index,
+ data->server_time);
+ current_index += 4;
+ }
+ switch (reply->buf[current_index]) {
+ case X_Reply: /* reply */
+ EXTRACT_CARD32(rep->clientSwapped,
+ reply->buf+current_index+4, datum_bytes);
+ datum_bytes = (datum_bytes+8) << 2;
+ break;
+ default: /* error or event */
+ datum_bytes = 32;
+ }
+ break;
+ case XRecordFromClient:
+ if (rep->elementHeader&XRecordFromClientTime) {
+ EXTRACT_CARD32(rep->clientSwapped,
+ reply->buf+current_index,
+ data->server_time);
+ current_index += 4;
+ }
+ if (rep->elementHeader&XRecordFromClientSequence) {
+ EXTRACT_CARD32(rep->clientSwapped,
+ reply->buf+current_index,
+ data->client_seq);
+ current_index += 4;
+ }
+ if (reply->buf[current_index+2] == 0
+ && reply->buf[current_index+3] == 0) /* needn't swap 0 */
+ { /* BIG-REQUESTS */
+ EXTRACT_CARD32(rep->clientSwapped,
+ reply->buf+current_index+4, datum_bytes);
+ } else {
+ EXTRACT_CARD16(rep->clientSwapped,
+ reply->buf+current_index+2, datum_bytes);
+ }
+ datum_bytes <<= 2;
+ break;
+ case XRecordClientStarted:
+ EXTRACT_CARD16(rep->clientSwapped,
+ reply->buf+current_index+6, datum_bytes);
+ datum_bytes = (datum_bytes+2) << 2;
+ break;
+ case XRecordClientDied:
+ if (rep->elementHeader&XRecordFromClientSequence) {
+ EXTRACT_CARD32(rep->clientSwapped,
+ reply->buf+current_index,
+ data->client_seq);
+ current_index += 4;
+ }
+ /* fall through */
+ case XRecordStartOfData:
+ case XRecordEndOfData:
+ datum_bytes = 0;
+ }
+
+ if (datum_bytes > 0) {
+ if (current_index + datum_bytes > rep->length << 2)
+ fprintf(stderr,
+ "XRecord: %lu-byte reply claims %d-byte element (seq %lu)\n",
+ rep->length << 2, current_index + datum_bytes,
+ dpy->last_request_read);
+ /*
+ * This assignment (and indeed the whole buffer sharing
+ * scheme) assumes arbitrary 4-byte boundaries are
+ * addressable.
+ */
+ data->data = reply->buf+current_index;
+ reply->ref_count++;
+ } else {
+ data->data = NULL;
+ }
+ data->data_len = datum_bytes >> 2;
+
+ (*callback)(closure, data);
+
+ current_index += datum_bytes;
+ } while (current_index<rep->length<<2);
+
+ if (rep->category == XRecordEndOfData)
+ return End;
+
+ return Continue;
+}
+
+Status
+XRecordEnableContext(dpy, context, callback, closure)
+ Display *dpy;
+ XRecordContext context;
+ XRecordInterceptProc callback;
+ XPointer closure;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xRecordEnableContextReq *req;
+ xRecordEnableContextReply rep;
+ struct reply_buffer *reply;
+ enum parser_return status;
+
+ XRecordCheckExtension (dpy, info, 0);
+ LockDisplay(dpy);
+ GetReq(RecordEnableContext, req);
+
+ req->reqType = info->codes->major_opcode;
+ req->recordReqType = X_RecordEnableContext;
+ req->context = context;
+
+ while (1)
+ {
+ /* This code should match that in XRecordEnableContextAsync */
+ if (!_XReply (dpy, (xReply *)&rep, 0, xFalse))
+ {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 0;
+ }
+
+ if (rep.length > 0) {
+ reply = alloc_reply_buffer(info, rep.length<<2);
+ if (!reply) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 0;
+ }
+ _XRead (dpy, (char *)reply->buf, rep.length<<2);
+ } else {
+ reply = NULL;
+ }
+
+ status = parse_reply_call_callback(dpy, info, &rep, reply,
+ callback, closure);
+ switch (status) {
+ case Continue:
+ break;
+ case End:
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+ case Error:
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 0;
+ }
+ }
+}
+
+
+typedef struct _record_async_state
+{
+ unsigned long enable_seq;
+ _XAsyncHandler *async;
+ _XAsyncErrorState *error_state;
+ XExtDisplayInfo *info;
+ XRecordInterceptProc callback;
+ XPointer closure;
+} record_async_state;
+
+static Bool
+record_async_handler(dpy, rep, buf, len, adata)
+ register Display *dpy;
+ register xReply *rep;
+ char *buf;
+ int len;
+ XPointer adata;
+{
+ register record_async_state *state = (record_async_state *)adata;
+ struct reply_buffer *reply;
+ enum parser_return status;
+ extern void _XGetAsyncData();
+
+ if (dpy->last_request_read != state->enable_seq)
+ {
+ if (dpy->last_request_read > state->enable_seq) {
+ /* it is an error that we are still on the handler list */
+ fprintf(stderr, "XRecord: handler for seq %lu never saw XRecordEndOfData. (seq now %lu)\n",
+ state->enable_seq, dpy->last_request_read);
+ DeqAsyncHandler(dpy, state->async);
+ Xfree(state->async);
+ }
+ return False;
+ }
+ if (rep->generic.type == X_Error)
+ {
+ DeqAsyncHandler(dpy, state->async);
+ Xfree(state->async);
+ return False;
+ }
+
+ if (rep->generic.length > 0) {
+ reply = alloc_reply_buffer(state->info, rep->generic.length<<2);
+
+ if (!reply) {
+ DeqAsyncHandler(dpy, state->async);
+ Xfree(state->async);
+ return False;
+ }
+
+ _XGetAsyncData(dpy, reply->buf, buf, len,
+ SIZEOF(xRecordEnableContextReply),
+ rep->generic.length << 2, 0);
+ } else {
+ reply = NULL;
+ }
+
+ status = parse_reply_call_callback(dpy, state->info,
+ (xRecordEnableContextReply*) rep,
+ reply, state->callback, state->closure);
+
+ if (status != Continue)
+ {
+ DeqAsyncHandler(dpy, state->async);
+ Xfree(state->async);
+ if (status == Error)
+ return False;
+ }
+
+ return True;
+}
+
+/*
+ * reads the first reply, StartOfData, synchronously,
+ * then returns allowing the app to call XRecordProcessReplies
+ * to get the rest.
+ */
+Status
+XRecordEnableContextAsync(dpy, context, callback, closure)
+ Display *dpy;
+ XRecordContext context;
+ XRecordInterceptProc callback;
+ XPointer closure;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xRecordEnableContextReq *req;
+ xRecordEnableContextReply rep;
+ struct reply_buffer *reply;
+ enum parser_return status;
+ _XAsyncHandler *async;
+ record_async_state *async_state;
+
+ XRecordCheckExtension (dpy, info, 0);
+ async = (_XAsyncHandler *)Xmalloc(sizeof(_XAsyncHandler) +
+ sizeof(record_async_state));
+ if (!async)
+ return 0;
+ async_state = (record_async_state *)(async + 1);
+
+ LockDisplay(dpy);
+ GetReq(RecordEnableContext, req);
+
+ req->reqType = info->codes->major_opcode;
+ req->recordReqType = X_RecordEnableContext;
+ req->context = context;
+
+ /* Get the StartOfData reply. */
+ /* This code should match that in XRecordEnableContext */
+ if (!_XReply (dpy, (xReply *)&rep, 0, xFalse))
+ {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ Xfree(async);
+ return 0;
+ }
+
+ /* this had better be a StartOfData, which has no extra data. */
+ if (rep.length != 0) {
+ fprintf(stderr, "XRecord: malformed StartOfData for sequence %lu\n",
+ dpy->last_request_read);
+ }
+ reply = NULL;
+
+ status = parse_reply_call_callback(dpy, info, &rep, reply,
+ callback, closure);
+ if (status != Continue)
+ {
+ UnlockDisplay(dpy);
+ Xfree(async);
+ return 0;
+ }
+
+ /* hook in the async handler for the rest of the replies */
+ async_state->enable_seq = dpy->request;
+ async_state->async = async;
+ async_state->info = info;
+ async_state->callback = callback;
+ async_state->closure = closure;
+
+ async->next = dpy->async_handlers;
+ async->handler = record_async_handler;
+ async->data = (XPointer)async_state;
+ dpy->async_handlers = async;
+
+ UnlockDisplay(dpy);
+ /* Don't invoke SyncHandle here, since this is an async
+ function. Does this break XSetAfterFunction() ? */
+ return 1;
+}
+
+void
+XRecordProcessReplies(dpy)
+ Display *dpy;
+{
+ (void) XPending(dpy);
+}
+
+Status
+XRecordDisableContext(dpy, context)
+ Display *dpy;
+ XRecordContext context;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xRecordDisableContextReq *req;
+
+ XRecordCheckExtension (dpy, info, 0);
+ LockDisplay(dpy);
+ GetReq(RecordDisableContext, req);
+ req->reqType = info->codes->major_opcode;
+ req->recordReqType = X_RecordDisableContext;
+ req->context = context;
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+Status
+XRecordFreeContext(dpy, context)
+ Display *dpy;
+ XRecordContext context;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xRecordFreeContextReq *req;
+
+ XRecordCheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(RecordFreeContext, req);
+ req->reqType = info->codes->major_opcode;
+ req->recordReqType = X_RecordFreeContext;
+ req->context = context;
+
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
diff --git a/src/XTest.c b/src/XTest.c
new file mode 100644
index 0000000..108d9e4
--- /dev/null
+++ b/src/XTest.c
@@ -0,0 +1,488 @@
+/* $Xorg: XTest.c,v 1.5 2001/02/09 02:04:00 xorgcvs Exp $ */
+/*
+Copyright 1990, 1991 by UniSoft Group Limited
+*/
+
+/*
+
+Copyright 1992, 1993, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+#define NEED_REPLIES
+#include "Xlibint.h"
+#include "XTest.h"
+#include "xteststr.h"
+#include "Xext.h"
+#include "extutil.h"
+#include "XInput.h"
+#include "XIproto.h"
+
+static XExtensionInfo _xtest_info_data;
+static XExtensionInfo *xtest_info = &_xtest_info_data;
+static /* const */ char *xtest_extension_name = XTestExtensionName;
+
+#define XTestCheckExtension(dpy,i,val) \
+ XextCheckExtension (dpy, i, xtest_extension_name, val)
+
+#define XTestICheckExtension(dpy,i,val) \
+ XextCheckExtension (dpy, i, xtest_extension_name, val); \
+ if (!i->data) return val
+
+/*****************************************************************************
+ * *
+ * private utility routines *
+ * *
+ *****************************************************************************/
+
+static int close_display();
+static /* const */ XExtensionHooks xtest_extension_hooks = {
+ NULL, /* create_gc */
+ NULL, /* copy_gc */
+ NULL, /* flush_gc */
+ NULL, /* free_gc */
+ NULL, /* create_font */
+ NULL, /* free_font */
+ close_display, /* close_display */
+ NULL, /* wire_to_event */
+ NULL, /* event_to_wire */
+ NULL, /* error */
+ NULL /* error_string */
+};
+
+static XPointer
+get_xinput_base(dpy)
+ Display *dpy;
+{
+ int major_opcode, first_event, first_error;
+ first_event = 0;
+
+ XQueryExtension(dpy, INAME, &major_opcode, &first_event, &first_error);
+ return (XPointer)first_event;
+}
+
+static XEXT_GENERATE_FIND_DISPLAY (find_display, xtest_info,
+ xtest_extension_name,
+ &xtest_extension_hooks, XTestNumberEvents,
+ get_xinput_base(dpy))
+
+static XEXT_GENERATE_CLOSE_DISPLAY (close_display, xtest_info)
+
+/*****************************************************************************
+ * *
+ * public routines *
+ * *
+ *****************************************************************************/
+
+Bool
+XTestQueryExtension (dpy, event_basep, error_basep, majorp, minorp)
+ Display *dpy;
+ int *event_basep, *error_basep;
+ int *majorp, *minorp;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestGetVersionReq *req;
+ xXTestGetVersionReply rep;
+
+ if (XextHasExtension(info)) {
+ LockDisplay(dpy);
+ GetReq(XTestGetVersion, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestGetVersion;
+ req->majorVersion = XTestMajorVersion;
+ req->minorVersion = XTestMinorVersion;
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ UnlockDisplay(dpy);
+ SyncHandle();
+ *event_basep = info->codes->first_event;
+ *error_basep = info->codes->first_error;
+ *majorp = rep.majorVersion;
+ *minorp = rep.minorVersion;
+ return True;
+ } else {
+ return False;
+ }
+}
+
+Bool
+XTestCompareCursorWithWindow(dpy, window, cursor)
+ Display *dpy;
+ Window window;
+ Cursor cursor;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestCompareCursorReq *req;
+ xXTestCompareCursorReply rep;
+
+ XTestCheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestCompareCursor, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestCompareCursor;
+ req->window = window;
+ req->cursor = cursor;
+ if (!_XReply(dpy, (xReply *)&rep, 0, xFalse)) {
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return False;
+ }
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return rep.same;
+}
+
+Bool
+XTestCompareCurrentCursorWithWindow(dpy, window)
+ Display *dpy;
+ Window window;
+{
+ return XTestCompareCursorWithWindow(dpy, window, XTestCurrentCursor);
+}
+
+XTestFakeKeyEvent(dpy, keycode, is_press, delay)
+ Display *dpy;
+ unsigned int keycode;
+ Bool is_press;
+ unsigned long delay;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestFakeInputReq *req;
+
+ XTestCheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestFakeInput, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestFakeInput;
+ req->type = is_press ? KeyPress : KeyRelease;
+ req->detail = keycode;
+ req->time = delay;
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+XTestFakeButtonEvent(dpy, button, is_press, delay)
+ Display *dpy;
+ unsigned int button;
+ Bool is_press;
+ unsigned long delay;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestFakeInputReq *req;
+
+ XTestCheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestFakeInput, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestFakeInput;
+ req->type = is_press ? ButtonPress : ButtonRelease;
+ req->detail = button;
+ req->time = delay;
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+XTestFakeMotionEvent(dpy, screen, x, y, delay)
+ Display *dpy;
+ int screen;
+ int x, y;
+ unsigned long delay;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestFakeInputReq *req;
+
+ XTestCheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestFakeInput, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestFakeInput;
+ req->type = MotionNotify;
+ req->detail = False;
+ if (screen == -1)
+ req->root = None;
+ else
+ req->root = RootWindow(dpy, screen);
+ req->rootX = x;
+ req->rootY = y;
+ req->time = delay;
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+XTestFakeRelativeMotionEvent(dpy, dx, dy, delay)
+ Display *dpy;
+ int dx, dy;
+ unsigned long delay;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestFakeInputReq *req;
+
+ XTestCheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestFakeInput, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestFakeInput;
+ req->type = MotionNotify;
+ req->detail = True;
+ req->root = None;
+ req->rootX = dx;
+ req->rootY = dy;
+ req->time = delay;
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+static void
+send_axes(dpy, info, req, dev, first_axis, axes, n_axes)
+ Display *dpy;
+ XExtDisplayInfo *info;
+ xXTestFakeInputReq *req;
+ XDevice *dev;
+ int first_axis;
+ int *axes;
+ int n_axes;
+{
+ deviceValuator ev;
+ int n;
+
+ req->deviceid |= MORE_EVENTS;
+ req->length += ((n_axes + 5) / 6) * (SIZEOF(xEvent) >> 2);
+ ev.type = XI_DeviceValuator + (int)info->data;
+ ev.deviceid = dev->device_id;
+ ev.num_valuators = n_axes;
+ ev.first_valuator = first_axis;
+ while (n_axes > 0) {
+ n = n_axes;
+ if (n > 6)
+ n = 6;
+ switch (n) {
+ case 6:
+ ev.valuator5 = *(axes+5);
+ case 5:
+ ev.valuator4 = *(axes+4);
+ case 4:
+ ev.valuator3 = *(axes+3);
+ case 3:
+ ev.valuator2 = *(axes+2);
+ case 2:
+ ev.valuator1 = *(axes+1);
+ case 1:
+ ev.valuator0 = *axes;
+ }
+ Data(dpy, (char *)&ev, SIZEOF(xEvent));
+ axes += n;
+ n_axes -= n;
+ ev.first_valuator += n;
+ }
+}
+
+XTestFakeDeviceKeyEvent(dpy, dev, keycode, is_press, axes, n_axes, delay)
+ Display *dpy;
+ XDevice *dev;
+ unsigned int keycode;
+ Bool is_press;
+ int *axes;
+ int n_axes;
+ unsigned long delay;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestFakeInputReq *req;
+
+ XTestICheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestFakeInput, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestFakeInput;
+ req->type = is_press ? XI_DeviceKeyPress : XI_DeviceKeyRelease;
+ req->type += (int)info->data;
+ req->detail = keycode;
+ req->time = delay;
+ req->deviceid = dev->device_id;
+ if (n_axes)
+ send_axes(dpy, info, req, dev, 0, axes, n_axes);
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+XTestFakeDeviceButtonEvent(dpy, dev, button, is_press, axes, n_axes, delay)
+ Display *dpy;
+ XDevice *dev;
+ unsigned int button;
+ Bool is_press;
+ int *axes;
+ int n_axes;
+ unsigned long delay;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestFakeInputReq *req;
+
+ XTestICheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestFakeInput, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestFakeInput;
+ req->type = is_press ? XI_DeviceButtonPress : XI_DeviceButtonRelease;
+ req->type += (int)info->data;
+ req->detail = button;
+ req->time = delay;
+ req->deviceid = dev->device_id;
+ if (n_axes)
+ send_axes(dpy, info, req, dev, 0, axes, n_axes);
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+XTestFakeProximityEvent(dpy, dev, in_prox, axes, n_axes, delay)
+ Display *dpy;
+ XDevice *dev;
+ Bool in_prox;
+ int *axes;
+ int n_axes;
+ unsigned long delay;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestFakeInputReq *req;
+
+ XTestICheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestFakeInput, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestFakeInput;
+ req->type = in_prox ? XI_ProximityIn : XI_ProximityOut;
+ req->type += (int)info->data;
+ req->time = delay;
+ req->deviceid = dev->device_id;
+ if (n_axes)
+ send_axes(dpy, info, req, dev, 0, axes, n_axes);
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+XTestFakeDeviceMotionEvent(dpy, dev, is_relative,
+ first_axis, axes, n_axes, delay)
+ Display *dpy;
+ XDevice *dev;
+ Bool is_relative;
+ int first_axis;
+ int *axes;
+ int n_axes;
+ unsigned long delay;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestFakeInputReq *req;
+
+ XTestICheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestFakeInput, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestFakeInput;
+ req->type = XI_DeviceMotionNotify + (int)info->data;
+ req->detail = is_relative;
+ req->time = delay;
+ req->deviceid = dev->device_id;
+ send_axes(dpy, info, req, dev, first_axis, axes, n_axes);
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+XTestGrabControl(dpy, impervious)
+ Display *dpy;
+ Bool impervious;
+{
+ XExtDisplayInfo *info = find_display (dpy);
+ register xXTestGrabControlReq *req;
+
+ XTestCheckExtension (dpy, info, 0);
+
+ LockDisplay(dpy);
+ GetReq(XTestGrabControl, req);
+ req->reqType = info->codes->major_opcode;
+ req->xtReqType = X_XTestGrabControl;
+ req->impervious = impervious;
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return 1;
+}
+
+void
+XTestSetGContextOfGC(gc, gid)
+ GC gc;
+ GContext gid;
+{
+ gc->gid = gid;
+}
+
+void
+XTestSetVisualIDOfVisual(visual, visualid)
+ Visual *visual;
+ VisualID visualid;
+{
+ visual->visualid = visualid;
+}
+
+static xReq _dummy_request = {
+ 0, 0, 0
+};
+
+Status
+XTestDiscard(dpy)
+ Display *dpy;
+{
+ Bool something;
+ register char *ptr;
+
+ LockDisplay(dpy);
+ if ((something = (dpy->bufptr != dpy->buffer))) {
+ for (ptr = dpy->buffer;
+ ptr < dpy->bufptr;
+ ptr += (((xReq *)ptr)->length << 2))
+ dpy->request--;
+ dpy->bufptr = dpy->buffer;
+ dpy->last_req = (char *)&_dummy_request;
+ }
+ UnlockDisplay(dpy);
+ SyncHandle();
+ return something;
+}