1a253d6aeSmrg/* 2a253d6aeSmrgXRecord.c - client-side library for RECORD extension 3a253d6aeSmrg 4a253d6aeSmrgCopyright 1995, 1998 The Open Group 5a253d6aeSmrg 6a253d6aeSmrgPermission to use, copy, modify, distribute, and sell this software and its 7a253d6aeSmrgdocumentation for any purpose is hereby granted without fee, provided that 8a253d6aeSmrgthe above copyright notice appear in all copies and that both that 9a253d6aeSmrgcopyright notice and this permission notice appear in supporting 10a253d6aeSmrgdocumentation. 11a253d6aeSmrg 12a253d6aeSmrgThe above copyright notice and this permission notice shall be 13a253d6aeSmrgincluded in all copies or substantial portions of the Software. 14a253d6aeSmrg 15a253d6aeSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16a253d6aeSmrgEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17a253d6aeSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18a253d6aeSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 19a253d6aeSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20a253d6aeSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21a253d6aeSmrgOTHER DEALINGS IN THE SOFTWARE. 22a253d6aeSmrg 23a253d6aeSmrgExcept as contained in this notice, the name of The Open Group shall 24a253d6aeSmrgnot be used in advertising or otherwise to promote the sale, use or 25a253d6aeSmrgother dealings in this Software without prior written authorization 26a253d6aeSmrgfrom The Open Group. 27a253d6aeSmrg 28a253d6aeSmrg*/ 29a253d6aeSmrg/*************************************************************************** 30a253d6aeSmrg * Copyright 1995 Network Computing Devices 31a253d6aeSmrg * 32a253d6aeSmrg * Permission to use, copy, modify, distribute, and sell this software and 33a253d6aeSmrg * its documentation for any purpose is hereby granted without fee, provided 34a253d6aeSmrg * that the above copyright notice appear in all copies and that both that 35a253d6aeSmrg * copyright notice and this permission notice appear in supporting 36a253d6aeSmrg * documentation, and that the name of Network Computing Devices 37a253d6aeSmrg * not be used in advertising or publicity pertaining to distribution 38a253d6aeSmrg * of the software without specific, written prior permission. 39a253d6aeSmrg * 40a253d6aeSmrg * NETWORK COMPUTING DEVICES DISCLAIMs ALL WARRANTIES WITH REGARD TO 41a253d6aeSmrg * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 42a253d6aeSmrg * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES BE LIABLE 43a253d6aeSmrg * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 44a253d6aeSmrg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 45a253d6aeSmrg * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 46a253d6aeSmrg * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 47a253d6aeSmrg **************************************************************************/ 48a253d6aeSmrg/* 49a253d6aeSmrg * By Stephen Gildea, X Consortium, and Martha Zimet, NCD. 50a253d6aeSmrg */ 51a253d6aeSmrg 528584976cSmrg#ifdef HAVE_CONFIG_H 538584976cSmrg#include <config.h> 548584976cSmrg#endif 55a253d6aeSmrg#include <stdio.h> 56a253d6aeSmrg#include <assert.h> 57a253d6aeSmrg#include <X11/Xlibint.h> 58a253d6aeSmrg#include <X11/extensions/Xext.h> 59a253d6aeSmrg#include <X11/extensions/extutil.h> 60ea133fd7Smrg#include <X11/extensions/recordproto.h> 61ea133fd7Smrg#include <X11/extensions/record.h> 628584976cSmrg#include <limits.h> 638584976cSmrg 64a253d6aeSmrgstatic XExtensionInfo _xrecord_info_data; 65a253d6aeSmrgstatic XExtensionInfo *xrecord_info = &_xrecord_info_data; 66347791aaSmrgstatic const char *xrecord_extension_name = RECORD_NAME; 67a253d6aeSmrg 68a253d6aeSmrg#define XRecordCheckExtension(dpy,i,val) \ 69a253d6aeSmrg XextCheckExtension(dpy, i, xrecord_extension_name, val) 70a253d6aeSmrg 71a253d6aeSmrg/************************************************************************** 72a253d6aeSmrg * * 73a253d6aeSmrg * private utility routines * 74a253d6aeSmrg * * 75a253d6aeSmrg **************************************************************************/ 76a253d6aeSmrg 77a253d6aeSmrgstatic XExtDisplayInfo *find_display(Display *dpy); 78a253d6aeSmrg 79a253d6aeSmrg/* 80a253d6aeSmrg * A reply buffer holds a reply from RecordEnableContext. 81a253d6aeSmrg * Pieces of that buffer are passed to the XRecordEnableContext callback. 82a253d6aeSmrg * ref_count is incremented each time we do that. 83a253d6aeSmrg * ref_count is decremented each time XRecordFreeData is called on 84a253d6aeSmrg * the buffer. When ref_count is 0, we can free or reuse the buffer. 85a253d6aeSmrg */ 86a253d6aeSmrgstruct reply_buffer 87a253d6aeSmrg{ 88a253d6aeSmrg struct reply_buffer *next; /* next in list or NULL */ 89a253d6aeSmrg unsigned char *buf; /* pointer to malloc'd buffer */ 90a253d6aeSmrg int nbytes; /* size of buf */ 91a253d6aeSmrg int ref_count; /* callback uses pending */ 92a253d6aeSmrg}; 93a253d6aeSmrg 94a253d6aeSmrg 95a253d6aeSmrg/* 96a253d6aeSmrg * There's some extra information the implementation finds useful 97a253d6aeSmrg * to attach to an XRecordInterceptData packet to handle memory 98a253d6aeSmrg * management. So we really allocate one of these. 99a253d6aeSmrg */ 100a253d6aeSmrgstruct intercept_queue 101a253d6aeSmrg{ 102a253d6aeSmrg /* this struct gets passed to the user as an XRecordInterceptData, 103a253d6aeSmrg so the data field must come first so we can cast the address 104a253d6aeSmrg back and forth */ 105a253d6aeSmrg XRecordInterceptData data; 106a253d6aeSmrg struct intercept_queue *next; /* next in free list or NULL */ 107a253d6aeSmrg struct mem_cache_str *cache; /* contains head of free list */ 108a253d6aeSmrg}; 109a253d6aeSmrg 110a253d6aeSmrg/* 111a253d6aeSmrg * per-display pointers to cache of malloc'd but unused memory 112a253d6aeSmrg */ 113a253d6aeSmrgstruct mem_cache_str 114a253d6aeSmrg{ 115a253d6aeSmrg struct intercept_queue *inter_data; /* free structs only */ 116a253d6aeSmrg struct reply_buffer *reply_buffers; /* all reply buffers */ 117a253d6aeSmrg int inter_data_count; /* total allocated, free and in use */ 118a253d6aeSmrg Bool display_closed; /* so we know when to free ourself */ 119a253d6aeSmrg}; 120a253d6aeSmrg 121a253d6aeSmrgstatic int close_display( 122a253d6aeSmrg Display *dpy, 123a253d6aeSmrg XExtCodes *codes) /* not used */ 124a253d6aeSmrg{ 125a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 126a253d6aeSmrg 127a253d6aeSmrg LockDisplay(dpy); 128a253d6aeSmrg if (info && info->data) { 129a253d6aeSmrg struct mem_cache_str *cache = (struct mem_cache_str *)info->data; 130a253d6aeSmrg struct intercept_queue *iq, *iq_next; 131a253d6aeSmrg struct reply_buffer *rbp, **rbp_next_p; 132a253d6aeSmrg 133a253d6aeSmrg for (iq=cache->inter_data; iq; iq=iq_next) { 134a253d6aeSmrg iq_next = iq->next; 135a253d6aeSmrg XFree(iq); 136a253d6aeSmrg cache->inter_data_count--; 137a253d6aeSmrg } 138a253d6aeSmrg 139a253d6aeSmrg /* this is a little trickier, because some of these 140a253d6aeSmrg might still be in use */ 141a253d6aeSmrg for (rbp_next_p = &cache->reply_buffers; *rbp_next_p; ) { 142a253d6aeSmrg rbp = *rbp_next_p; 143a253d6aeSmrg if (rbp->ref_count == 0) { 144a253d6aeSmrg *rbp_next_p = rbp->next; 145a253d6aeSmrg XFree(rbp->buf); 146a253d6aeSmrg XFree(rbp); 147a253d6aeSmrg } else { 148a253d6aeSmrg rbp_next_p = &rbp->next; 149a253d6aeSmrg } 150a253d6aeSmrg } 151a253d6aeSmrg 152a253d6aeSmrg if (cache->reply_buffers == NULL && cache->inter_data_count == 0) { 153a253d6aeSmrg /* every thing has been freed, can free ourselves, too */ 154a253d6aeSmrg XFree(cache); 155a253d6aeSmrg } else { 156a253d6aeSmrg cache->display_closed = True; 157a253d6aeSmrg cache->inter_data = NULL; /* neatness only; won't be used */ 158a253d6aeSmrg } 159a253d6aeSmrg } 160a253d6aeSmrg UnlockDisplay(dpy); 161a253d6aeSmrg return XextRemoveDisplay(xrecord_info, dpy); 162a253d6aeSmrg} 163a253d6aeSmrg 164a253d6aeSmrgstatic XPointer alloc_mem_cache(void) 165a253d6aeSmrg{ 166a253d6aeSmrg struct mem_cache_str *cache; 16706f32fbeSmrg 168a253d6aeSmrg /* note that an error will go unnoticed */ 169072eb593Smrg cache = Xmalloc(sizeof(struct mem_cache_str)); 170a253d6aeSmrg if (cache) { 171a253d6aeSmrg cache->display_closed = False; 172a253d6aeSmrg cache->inter_data = NULL; 173a253d6aeSmrg cache->inter_data_count = 0; 174a253d6aeSmrg cache->reply_buffers = NULL; 175a253d6aeSmrg } 176a253d6aeSmrg return (XPointer) cache; 177a253d6aeSmrg} 178a253d6aeSmrg 179a253d6aeSmrgstatic const char *xrecord_error_list[] = { 180a253d6aeSmrg "XRecordBadContext (Not a defined RECORD context)", 181a253d6aeSmrg}; 182a253d6aeSmrg 183a253d6aeSmrgstatic XEXT_GENERATE_ERROR_STRING (error_string, xrecord_extension_name, 184a253d6aeSmrg RecordNumErrors, xrecord_error_list) 185a253d6aeSmrg 186a253d6aeSmrgstatic XExtensionHooks xrecord_extension_hooks = { 187a253d6aeSmrg NULL, /* create_gc */ 188a253d6aeSmrg NULL, /* copy_gc */ 189a253d6aeSmrg NULL, /* flush_gc */ 190a253d6aeSmrg NULL, /* free_gc */ 191a253d6aeSmrg NULL, /* create_font */ 192a253d6aeSmrg NULL, /* free_font */ 193a253d6aeSmrg close_display, /* close_display */ 194a253d6aeSmrg NULL, /* wire_to_event */ 195a253d6aeSmrg NULL, /* event_to_wire */ 196a253d6aeSmrg NULL, /* error */ 197a253d6aeSmrg error_string /* error_string */ 198a253d6aeSmrg}; 199a253d6aeSmrg 200a253d6aeSmrgstatic XEXT_GENERATE_FIND_DISPLAY (find_display, xrecord_info, 201a253d6aeSmrg xrecord_extension_name, &xrecord_extension_hooks, RecordNumEvents, 202a253d6aeSmrg alloc_mem_cache()) 203a253d6aeSmrg 204a253d6aeSmrg/************************************************************************** 205a253d6aeSmrg * * 206a253d6aeSmrg * private library routines * 207a253d6aeSmrg * * 208a253d6aeSmrg **************************************************************************/ 209a253d6aeSmrg 210a253d6aeSmrgstatic void 211a253d6aeSmrgSendRange( 212a253d6aeSmrg Display *dpy, 213a253d6aeSmrg XRecordRange **range_item, 214a253d6aeSmrg int nranges) 215a253d6aeSmrg{ 216a253d6aeSmrg int rlen = SIZEOF(xRecordRange); 217a253d6aeSmrg while(nranges--) 218a253d6aeSmrg { 219a253d6aeSmrg xRecordRange xrange; 220a253d6aeSmrg 221a253d6aeSmrg xrange.coreRequestsFirst = (*range_item)->core_requests.first; 222a253d6aeSmrg xrange.coreRequestsLast = (*range_item)->core_requests.last; 223a253d6aeSmrg xrange.coreRepliesFirst = (*range_item)->core_replies.first; 224a253d6aeSmrg xrange.coreRepliesLast = (*range_item)->core_replies.last; 225a253d6aeSmrg xrange.extRequestsMajorFirst = (*range_item)->ext_requests.ext_major.first; 226a253d6aeSmrg xrange.extRequestsMajorLast = (*range_item)->ext_requests.ext_major.last; 227a253d6aeSmrg xrange.extRequestsMinorFirst = (*range_item)->ext_requests.ext_minor.first; 228a253d6aeSmrg xrange.extRequestsMinorLast = (*range_item)->ext_requests.ext_minor.last; 229a253d6aeSmrg xrange.extRepliesMajorFirst = (*range_item)->ext_replies.ext_major.first; 230a253d6aeSmrg xrange.extRepliesMajorLast = (*range_item)->ext_replies.ext_major.last; 231a253d6aeSmrg xrange.extRepliesMinorFirst = (*range_item)->ext_replies.ext_minor.first; 232a253d6aeSmrg xrange.extRepliesMinorLast = (*range_item)->ext_replies.ext_minor.last; 233a253d6aeSmrg xrange.deliveredEventsFirst = (*range_item)->delivered_events.first; 234a253d6aeSmrg xrange.deliveredEventsLast = (*range_item)->delivered_events.last; 235a253d6aeSmrg xrange.deviceEventsFirst = (*range_item)->device_events.first; 236a253d6aeSmrg xrange.deviceEventsLast = (*range_item)->device_events.last; 237a253d6aeSmrg xrange.errorsFirst = (*range_item)->errors.first; 238a253d6aeSmrg xrange.errorsLast = (*range_item)->errors.last; 239a253d6aeSmrg xrange.clientStarted = (*range_item)->client_started; 240a253d6aeSmrg xrange.clientDied = (*range_item)->client_died; 24106f32fbeSmrg 242a253d6aeSmrg Data(dpy, (char *)&xrange, rlen); 243a253d6aeSmrg range_item++; 244a253d6aeSmrg } 245a253d6aeSmrg} 246a253d6aeSmrg 247a253d6aeSmrg/************************************************************************** 248a253d6aeSmrg * * 249a253d6aeSmrg * public routines * 250a253d6aeSmrg * * 251a253d6aeSmrg **************************************************************************/ 252a253d6aeSmrg 253a253d6aeSmrgXID 254ea133fd7SmrgXRecordIdBaseMask(Display *dpy) 255a253d6aeSmrg{ 256a253d6aeSmrg return 0x1fffffff & ~dpy->resource_mask; 257a253d6aeSmrg} 258a253d6aeSmrg 259a253d6aeSmrgStatus 260ea133fd7SmrgXRecordQueryVersion(Display *dpy, int *cmajor_return, int *cminor_return) 261a253d6aeSmrg{ 262a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 263a253d6aeSmrg register xRecordQueryVersionReq *req; 264a253d6aeSmrg xRecordQueryVersionReply rep; 265a253d6aeSmrg 266a253d6aeSmrg XRecordCheckExtension (dpy, info, False); 267a253d6aeSmrg 268a253d6aeSmrg LockDisplay(dpy); 269a253d6aeSmrg GetReq(RecordQueryVersion, req); 270a253d6aeSmrg req->reqType = info->codes->major_opcode; 271a253d6aeSmrg req->recordReqType = X_RecordQueryVersion; 272a253d6aeSmrg req->majorVersion = RECORD_MAJOR_VERSION; 273a253d6aeSmrg req->minorVersion = RECORD_MINOR_VERSION; 274a253d6aeSmrg if (!_XReply(dpy,(xReply *)&rep, 0, True)) { 275a253d6aeSmrg UnlockDisplay(dpy); 276a253d6aeSmrg SyncHandle(); 277a253d6aeSmrg return False; 278a253d6aeSmrg } 279a253d6aeSmrg UnlockDisplay(dpy); 280a253d6aeSmrg SyncHandle(); 281a253d6aeSmrg *cmajor_return = rep.majorVersion; 282a253d6aeSmrg *cminor_return = rep.minorVersion; 283a253d6aeSmrg return ((rep.majorVersion == RECORD_MAJOR_VERSION) && 284a253d6aeSmrg (rep.minorVersion >= RECORD_LOWEST_MINOR_VERSION)); 285a253d6aeSmrg} 286a253d6aeSmrg 287a253d6aeSmrgXRecordContext 288ea133fd7SmrgXRecordCreateContext(Display *dpy, int datum_flags, 289ea133fd7Smrg XRecordClientSpec *clients, int nclients, 290ea133fd7Smrg XRecordRange **ranges, int nranges) 291a253d6aeSmrg{ 292a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 293a253d6aeSmrg register xRecordCreateContextReq *req; 294a253d6aeSmrg int clen = 4 * nclients; 295a253d6aeSmrg 296a253d6aeSmrg XRecordCheckExtension (dpy, info, 0); 297a253d6aeSmrg LockDisplay(dpy); 298a253d6aeSmrg GetReq(RecordCreateContext, req); 299a253d6aeSmrg 300a253d6aeSmrg req->reqType = info->codes->major_opcode; 301a253d6aeSmrg req->recordReqType = X_RecordCreateContext; 302a253d6aeSmrg req->context = XAllocID(dpy); 303a253d6aeSmrg req->length += (nclients * 4 + 304a253d6aeSmrg nranges * SIZEOF(xRecordRange)) >> 2; 305a253d6aeSmrg req->elementHeader = datum_flags; 306a253d6aeSmrg req->nClients = nclients; 307a253d6aeSmrg req->nRanges = nranges; 308a253d6aeSmrg 309a253d6aeSmrg Data32(dpy, (long *)clients, clen); 310a253d6aeSmrg SendRange(dpy, ranges, nranges); 311a253d6aeSmrg 312a253d6aeSmrg UnlockDisplay(dpy); 313a253d6aeSmrg SyncHandle(); 314a253d6aeSmrg return req->context; 315a253d6aeSmrg} 316a253d6aeSmrg 317a253d6aeSmrgXRecordRange * 318ea133fd7SmrgXRecordAllocRange(void) 319a253d6aeSmrg{ 320072eb593Smrg return Xcalloc(1, sizeof(XRecordRange)); 321a253d6aeSmrg} 322a253d6aeSmrg 323a253d6aeSmrgStatus 324ea133fd7SmrgXRecordRegisterClients(Display *dpy, XRecordContext context, int datum_flags, 325ea133fd7Smrg XRecordClientSpec *clients, int nclients, 326ea133fd7Smrg XRecordRange **ranges, int nranges) 327a253d6aeSmrg{ 328a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 329a253d6aeSmrg register xRecordRegisterClientsReq *req; 330a253d6aeSmrg int clen = 4 * nclients; 331a253d6aeSmrg 332a253d6aeSmrg XRecordCheckExtension (dpy, info, 0); 333a253d6aeSmrg LockDisplay(dpy); 334a253d6aeSmrg GetReq(RecordRegisterClients, req); 335a253d6aeSmrg 336a253d6aeSmrg req->reqType = info->codes->major_opcode; 337a253d6aeSmrg req->recordReqType = X_RecordRegisterClients; 338a253d6aeSmrg req->context = context; 339a253d6aeSmrg req->length += (nclients * 4 + 340a253d6aeSmrg nranges * SIZEOF(xRecordRange)) >> 2; 341a253d6aeSmrg req->elementHeader = datum_flags; 342a253d6aeSmrg req->nClients = nclients; 343a253d6aeSmrg req->nRanges = nranges; 344a253d6aeSmrg 345a253d6aeSmrg Data32(dpy, (long *)clients, clen); 346a253d6aeSmrg SendRange(dpy, ranges, nranges); 347a253d6aeSmrg 348a253d6aeSmrg UnlockDisplay(dpy); 349a253d6aeSmrg SyncHandle(); 350a253d6aeSmrg return 1; 351a253d6aeSmrg} 352a253d6aeSmrg 353a253d6aeSmrgStatus 354ea133fd7SmrgXRecordUnregisterClients(Display *dpy, XRecordContext context, 355ea133fd7Smrg XRecordClientSpec *clients, int nclients) 356a253d6aeSmrg{ 357a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 358a253d6aeSmrg register xRecordUnregisterClientsReq *req; 359a253d6aeSmrg int clen = 4 * nclients; 360a253d6aeSmrg 361a253d6aeSmrg XRecordCheckExtension (dpy, info, 0); 362a253d6aeSmrg LockDisplay(dpy); 363a253d6aeSmrg GetReq(RecordUnregisterClients, req); 364a253d6aeSmrg 365a253d6aeSmrg req->reqType = info->codes->major_opcode; 366a253d6aeSmrg req->recordReqType = X_RecordUnregisterClients; 367a253d6aeSmrg req->context = context; 368a253d6aeSmrg req->length += nclients; 369a253d6aeSmrg req->nClients = nclients; 370a253d6aeSmrg 371a253d6aeSmrg Data32(dpy, (long *)clients, clen); 372a253d6aeSmrg 373a253d6aeSmrg UnlockDisplay(dpy); 374a253d6aeSmrg SyncHandle(); 375a253d6aeSmrg return 1; 376a253d6aeSmrg} 377a253d6aeSmrg 378a253d6aeSmrgstatic void 379a253d6aeSmrgWireToLibRange( 380a253d6aeSmrg xRecordRange *wire_range, 381a253d6aeSmrg XRecordRange *lib_range) 382a253d6aeSmrg{ 383a253d6aeSmrg lib_range->core_requests.first = wire_range->coreRequestsFirst; 384a253d6aeSmrg lib_range->core_requests.last = wire_range->coreRequestsLast; 385a253d6aeSmrg lib_range->core_replies.first = wire_range->coreRepliesFirst; 386a253d6aeSmrg lib_range->core_replies.last = wire_range->coreRepliesLast; 387a253d6aeSmrg lib_range->ext_requests.ext_major.first = wire_range->extRequestsMajorFirst; 388a253d6aeSmrg lib_range->ext_requests.ext_major.last = wire_range->extRequestsMajorLast; 389a253d6aeSmrg lib_range->ext_requests.ext_minor.first = wire_range->extRequestsMinorFirst; 390a253d6aeSmrg lib_range->ext_requests.ext_minor.last = wire_range->extRequestsMinorLast; 391a253d6aeSmrg lib_range->ext_replies.ext_major.first = wire_range->extRepliesMajorFirst; 392a253d6aeSmrg lib_range->ext_replies.ext_major.last = wire_range->extRepliesMajorLast; 393a253d6aeSmrg lib_range->ext_replies.ext_minor.first = wire_range->extRepliesMinorFirst; 394a253d6aeSmrg lib_range->ext_replies.ext_minor.last = wire_range->extRepliesMinorLast; 395a253d6aeSmrg lib_range->delivered_events.first = wire_range->deliveredEventsFirst; 396a253d6aeSmrg lib_range->delivered_events.last = wire_range->deliveredEventsLast; 397a253d6aeSmrg lib_range->device_events.first = wire_range->deviceEventsFirst; 398a253d6aeSmrg lib_range->device_events.last = wire_range->deviceEventsLast; 399a253d6aeSmrg lib_range->errors.first = wire_range->errorsFirst; 400a253d6aeSmrg lib_range->errors.last = wire_range->errorsLast; 401a253d6aeSmrg lib_range->client_started = wire_range->clientStarted; 402a253d6aeSmrg lib_range->client_died = wire_range->clientDied; 403a253d6aeSmrg} 404a253d6aeSmrg 405a253d6aeSmrgStatus 406ea133fd7SmrgXRecordGetContext(Display *dpy, XRecordContext context, 407ea133fd7Smrg XRecordState **state_return) 408a253d6aeSmrg{ 409a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 410a253d6aeSmrg register xRecordGetContextReq *req; 411a253d6aeSmrg xRecordGetContextReply rep; 412072eb593Smrg unsigned int count; 413a253d6aeSmrg xRecordRange xrange; 414a253d6aeSmrg xRecordClientInfo xclient_inf; 415a253d6aeSmrg XRecordState *ret; 416a253d6aeSmrg 417a253d6aeSmrg XRecordCheckExtension (dpy, info, 0); 418a253d6aeSmrg LockDisplay(dpy); 419a253d6aeSmrg GetReq(RecordGetContext, req); 420a253d6aeSmrg req->reqType = info->codes->major_opcode; 421a253d6aeSmrg req->recordReqType = X_RecordGetContext; 422a253d6aeSmrg req->context = context; 423a253d6aeSmrg if (!_XReply(dpy,(xReply *)&rep, 0, False)) { 424a253d6aeSmrg UnlockDisplay(dpy); 425a253d6aeSmrg SyncHandle(); 426a253d6aeSmrg return 0; 427a253d6aeSmrg } 428a253d6aeSmrg count = rep.nClients; 429a253d6aeSmrg 430072eb593Smrg ret = Xmalloc(sizeof(XRecordState)); 431a253d6aeSmrg if (!ret) { 4328584976cSmrg _XEatDataWords (dpy, rep.length); 433a253d6aeSmrg UnlockDisplay(dpy); 434a253d6aeSmrg SyncHandle(); 435a253d6aeSmrg return 0; 436a253d6aeSmrg } 437a253d6aeSmrg 438a253d6aeSmrg ret->enabled = rep.enabled; 439a253d6aeSmrg ret->datum_flags = rep.elementHeader; 440a253d6aeSmrg ret->nclients = count; 441a253d6aeSmrg 442a253d6aeSmrg if (count) 443a253d6aeSmrg { 4448584976cSmrg XRecordClientInfo **client_inf = NULL; 4458584976cSmrg XRecordClientInfo *client_inf_str = NULL; 4468584976cSmrg 4478584976cSmrg if (count < (INT_MAX / sizeof(XRecordClientInfo))) { 4488584976cSmrg client_inf = Xcalloc(count, sizeof(XRecordClientInfo *)); 4498584976cSmrg if (client_inf != NULL) 4508584976cSmrg client_inf_str = Xmalloc(count * sizeof(XRecordClientInfo)); 451a253d6aeSmrg } 4528584976cSmrg ret->client_info = client_inf; 453a253d6aeSmrg if (!client_inf || !client_inf_str) 454a253d6aeSmrg { 4558584976cSmrg _XEatDataWords (dpy, rep.length); 456a253d6aeSmrg UnlockDisplay(dpy); 4575bc19eebSmrg XRecordFreeState(ret); /* frees ret->client_info, aka client_inf */ 458a253d6aeSmrg SyncHandle(); 459a253d6aeSmrg return 0; 460a253d6aeSmrg } 461072eb593Smrg for (unsigned int i = 0; i < count; i++) 462a253d6aeSmrg { 463a253d6aeSmrg client_inf[i] = &(client_inf_str[i]); 464a253d6aeSmrg _XRead(dpy, (char *)&xclient_inf, (long)sizeof(xRecordClientInfo)); 465a253d6aeSmrg client_inf_str[i].client = xclient_inf.clientResource; 466a253d6aeSmrg client_inf_str[i].nranges = xclient_inf.nRanges; 467a253d6aeSmrg 468a253d6aeSmrg if (xclient_inf.nRanges) 469a253d6aeSmrg { 4708584976cSmrg XRecordRange *ranges = NULL; 4718584976cSmrg 4728584976cSmrg if (xclient_inf.nRanges < (INT_MAX / sizeof(XRecordRange))) { 4738584976cSmrg client_inf_str[i].ranges = 4748584976cSmrg Xcalloc(xclient_inf.nRanges, sizeof(XRecordRange *)); 4758584976cSmrg if (client_inf_str[i].ranges != NULL) 4768584976cSmrg ranges = 4778584976cSmrg Xmalloc(xclient_inf.nRanges * sizeof(XRecordRange)); 478a253d6aeSmrg } 4798584976cSmrg else 4808584976cSmrg client_inf_str[i].ranges = NULL; 4818584976cSmrg 482a253d6aeSmrg if (!client_inf_str[i].ranges || !ranges) { 483a253d6aeSmrg /* XXX eat data */ 484a253d6aeSmrg UnlockDisplay(dpy); 485a253d6aeSmrg XRecordFreeState(ret); 486a253d6aeSmrg SyncHandle(); 487a253d6aeSmrg return 0; 488a253d6aeSmrg } 489072eb593Smrg for (unsigned int rn = 0; rn < xclient_inf.nRanges; rn++) { 490a253d6aeSmrg client_inf_str[i].ranges[rn] = &(ranges[rn]); 491a253d6aeSmrg _XRead(dpy, (char *)&xrange, (long)sizeof(xRecordRange)); 492a253d6aeSmrg WireToLibRange(&xrange, &(ranges[rn])); 493a253d6aeSmrg } 494a253d6aeSmrg } else { 495a253d6aeSmrg client_inf_str[i].ranges = NULL; 496a253d6aeSmrg } 497a253d6aeSmrg } 498a253d6aeSmrg } else { 499a253d6aeSmrg ret->client_info = NULL; 500a253d6aeSmrg } 501a253d6aeSmrg 502a253d6aeSmrg *state_return = ret; 503a253d6aeSmrg 504a253d6aeSmrg UnlockDisplay(dpy); 505a253d6aeSmrg SyncHandle(); 506a253d6aeSmrg return 1; 507a253d6aeSmrg} 508a253d6aeSmrg 509a253d6aeSmrgvoid 510ea133fd7SmrgXRecordFreeState(XRecordState *state) 511a253d6aeSmrg{ 512a253d6aeSmrg if (state->client_info) { 5135bc19eebSmrg for (unsigned long i = 0; i < state->nclients; i++) { 5145bc19eebSmrg if (state->client_info[i]->ranges) { 5155bc19eebSmrg if (state->client_info[i]->ranges[0]) 5165bc19eebSmrg Xfree(state->client_info[i]->ranges[0]); 5175bc19eebSmrg Xfree(state->client_info[i]->ranges); 5185bc19eebSmrg } 5195bc19eebSmrg } 520a253d6aeSmrg if (state->client_info[0]) 521a253d6aeSmrg Xfree(state->client_info[0]); 522a253d6aeSmrg Xfree(state->client_info); 523a253d6aeSmrg } 524a253d6aeSmrg Xfree(state); 525a253d6aeSmrg} 526a253d6aeSmrg 527a253d6aeSmrgstatic struct reply_buffer *alloc_reply_buffer( 528a253d6aeSmrg XExtDisplayInfo *info, 529a253d6aeSmrg int nbytes) 530a253d6aeSmrg{ 531a253d6aeSmrg struct mem_cache_str *cache = (struct mem_cache_str *)info->data; 532a253d6aeSmrg struct reply_buffer *rbp; 533a253d6aeSmrg struct reply_buffer *saved_rb = NULL; 534a253d6aeSmrg /* 535a253d6aeSmrg * First look for an allocated buffer that is not in use. 536a253d6aeSmrg * If we have a big enough buffer, use that, otherwise 537a253d6aeSmrg * realloc an existing one. 538a253d6aeSmrg */ 539a253d6aeSmrg for (rbp = cache->reply_buffers; rbp; rbp = rbp->next) { 540a253d6aeSmrg if (rbp->ref_count == 0) { 541a253d6aeSmrg if (rbp->nbytes >= nbytes) 542a253d6aeSmrg return rbp; 543a253d6aeSmrg else 544a253d6aeSmrg saved_rb = rbp; 545a253d6aeSmrg } 546a253d6aeSmrg } 547a253d6aeSmrg if (saved_rb) { 548a253d6aeSmrg saved_rb->buf = (unsigned char *)Xrealloc(saved_rb->buf, nbytes); 549a253d6aeSmrg if (!saved_rb->buf) { 550a253d6aeSmrg saved_rb->nbytes = 0; 551a253d6aeSmrg return NULL; 552a253d6aeSmrg } 553a253d6aeSmrg saved_rb->nbytes = nbytes; 554a253d6aeSmrg return saved_rb; 555a253d6aeSmrg } 556a253d6aeSmrg 557a253d6aeSmrg /* 558a253d6aeSmrg * nothing available; malloc a new struct 559a253d6aeSmrg */ 560072eb593Smrg rbp = Xmalloc(sizeof(struct reply_buffer)); 561a253d6aeSmrg if (!rbp) 562a253d6aeSmrg return NULL; 563072eb593Smrg rbp->buf = Xmalloc(nbytes); 564a253d6aeSmrg if (!rbp->buf) { 565a253d6aeSmrg Xfree(rbp); 566a253d6aeSmrg return NULL; 567a253d6aeSmrg } 568a253d6aeSmrg rbp->nbytes = nbytes; 569a253d6aeSmrg rbp->ref_count = 0; 570a253d6aeSmrg rbp->next = cache->reply_buffers; 571a253d6aeSmrg cache->reply_buffers = rbp; 572a253d6aeSmrg return rbp; 573a253d6aeSmrg} 574a253d6aeSmrg 575a253d6aeSmrgstatic XRecordInterceptData *alloc_inter_data(XExtDisplayInfo *info) 576a253d6aeSmrg{ 577a253d6aeSmrg struct mem_cache_str *cache = (struct mem_cache_str *)info->data; 578a253d6aeSmrg struct intercept_queue *iq; 579a253d6aeSmrg 580a253d6aeSmrg /* if there is one on the free list, pop it */ 581a253d6aeSmrg if (cache->inter_data) { 582a253d6aeSmrg iq = cache->inter_data; 583a253d6aeSmrg cache->inter_data = iq->next; 584a253d6aeSmrg return &iq->data; 585a253d6aeSmrg } 586a253d6aeSmrg /* allocate a new one */ 587072eb593Smrg iq = Xmalloc(sizeof(struct intercept_queue)); 588a253d6aeSmrg if (!iq) 589a253d6aeSmrg return NULL; 590a253d6aeSmrg iq->cache = cache; 591a253d6aeSmrg cache->inter_data_count++; 592a253d6aeSmrg return &iq->data; 593a253d6aeSmrg} 594a253d6aeSmrg 595a253d6aeSmrgvoid 596ea133fd7SmrgXRecordFreeData(XRecordInterceptData *data) 597a253d6aeSmrg{ 598a253d6aeSmrg /* we can do this cast because that is what we really allocated */ 599a253d6aeSmrg struct intercept_queue *iq = (struct intercept_queue *)data; 600a253d6aeSmrg struct reply_buffer *rbp = NULL; 601a253d6aeSmrg struct mem_cache_str *cache = iq->cache; 602a253d6aeSmrg 603a253d6aeSmrg /* 604a253d6aeSmrg * figure out what reply_buffer this points at 605a253d6aeSmrg * and decrement its ref_count. 606a253d6aeSmrg */ 607a253d6aeSmrg if (data->data) { 608a253d6aeSmrg 609a253d6aeSmrg for (rbp = cache->reply_buffers; rbp; rbp = rbp->next) { 610a253d6aeSmrg if (data->data >= rbp->buf 611a253d6aeSmrg && data->data < rbp->buf + rbp->nbytes) 612a253d6aeSmrg { 613a253d6aeSmrg assert(rbp->ref_count > 0); 614a253d6aeSmrg rbp->ref_count--; 615a253d6aeSmrg break; 616a253d6aeSmrg } 617a253d6aeSmrg } 618a253d6aeSmrg /* it's an error if we didn't find something to free */ 619a253d6aeSmrg assert(rbp); 620a253d6aeSmrg } 621a253d6aeSmrg /* 622a253d6aeSmrg * If the display is still open, put this back on the free queue. 623a253d6aeSmrg * 624a253d6aeSmrg * Otherwise the display is closed and we won't reuse this, so free it. 625a253d6aeSmrg * See if we can free the reply buffer, too. 626a253d6aeSmrg * If we can, see if this is the last reply buffer and if so 627a253d6aeSmrg * free the list of reply buffers. 628a253d6aeSmrg */ 629a253d6aeSmrg if (cache->display_closed == False) { 630a253d6aeSmrg iq->next = cache->inter_data; 631a253d6aeSmrg cache->inter_data = iq; 632a253d6aeSmrg } else { 633a253d6aeSmrg if (rbp && rbp->ref_count == 0) { 634a253d6aeSmrg struct reply_buffer *rbp2, **rbp_next_p; 635a253d6aeSmrg 636a253d6aeSmrg /* Have to search the list again to find the prev element. 637a253d6aeSmrg This is not the common case, so don't slow down the code 638a253d6aeSmrg above by doing it then. */ 639a253d6aeSmrg for (rbp_next_p = &cache->reply_buffers; *rbp_next_p; ) { 640a253d6aeSmrg rbp2 = *rbp_next_p; 641a253d6aeSmrg if (rbp == rbp2) { 642a253d6aeSmrg *rbp_next_p = rbp2->next; 643a253d6aeSmrg break; 644a253d6aeSmrg } else { 645a253d6aeSmrg rbp_next_p = &rbp2->next; 646a253d6aeSmrg } 647a253d6aeSmrg } 648a253d6aeSmrg XFree(rbp->buf); 649a253d6aeSmrg XFree(rbp); 650a253d6aeSmrg } 651a253d6aeSmrg 652a253d6aeSmrg XFree(iq); 653a253d6aeSmrg cache->inter_data_count--; 654a253d6aeSmrg 655a253d6aeSmrg if (cache->reply_buffers == NULL && cache->inter_data_count == 0) { 656a253d6aeSmrg XFree(cache); /* all finished */ 657a253d6aeSmrg } 658a253d6aeSmrg } 659a253d6aeSmrg} 660a253d6aeSmrg 661a253d6aeSmrg/* the EXTRACT macros are adapted from ICElibint.h */ 662a253d6aeSmrg 663a253d6aeSmrg#ifndef WORD64 664a253d6aeSmrg 665a253d6aeSmrg#define EXTRACT_CARD16(swap, src, dst) \ 666a253d6aeSmrg{ \ 667a253d6aeSmrg (dst) = *((CARD16 *) (src)); \ 668a253d6aeSmrg if (swap) \ 669a253d6aeSmrg (dst) = lswaps (dst); \ 670a253d6aeSmrg} 671a253d6aeSmrg 672a253d6aeSmrg#define EXTRACT_CARD32(swap, src, dst) \ 673a253d6aeSmrg{ \ 674a253d6aeSmrg (dst) = *((CARD32 *) (src)); \ 675a253d6aeSmrg if (swap) \ 676a253d6aeSmrg (dst) = lswapl (dst); \ 677a253d6aeSmrg} 678a253d6aeSmrg 679a253d6aeSmrg#else /* WORD64 */ 680a253d6aeSmrg 681a253d6aeSmrg#define EXTRACT_CARD16(swap, src, dst) \ 682a253d6aeSmrg{ \ 683a253d6aeSmrg (dst) = *((src) + 0); \ 684a253d6aeSmrg (dst) <<= 8; \ 685a253d6aeSmrg (dst) |= *((src) + 1); \ 686a253d6aeSmrg if (swap) \ 687a253d6aeSmrg (dst) = lswaps (dst); \ 688a253d6aeSmrg} 689a253d6aeSmrg 690a253d6aeSmrg#define EXTRACT_CARD32(swap, src, dst) \ 691a253d6aeSmrg{ \ 692a253d6aeSmrg (dst) = *((src) + 0); \ 693a253d6aeSmrg (dst) <<= 8; \ 694a253d6aeSmrg (dst) |= *((src) + 1); \ 695a253d6aeSmrg (dst) <<= 8; \ 696a253d6aeSmrg (dst) |= *((src) + 2); \ 697a253d6aeSmrg (dst) <<= 8; \ 698a253d6aeSmrg (dst) |= *((src) + 3); \ 699a253d6aeSmrg if (swap) \ 700a253d6aeSmrg (dst) = lswapl (dst); \ 701a253d6aeSmrg} 702a253d6aeSmrg 703a253d6aeSmrg#endif /* WORD64 */ 704a253d6aeSmrg 705a253d6aeSmrg/* byte swapping macros from xfs/include/misc.h */ 706a253d6aeSmrg 707a253d6aeSmrg/* byte swap a long literal */ 708a253d6aeSmrg#define lswapl(x) ((((x) & 0xff) << 24) |\ 709a253d6aeSmrg (((x) & 0xff00) << 8) |\ 710a253d6aeSmrg (((x) & 0xff0000) >> 8) |\ 711a253d6aeSmrg (((x) >> 24) & 0xff)) 712a253d6aeSmrg 713a253d6aeSmrg/* byte swap a short literal */ 714a253d6aeSmrg#define lswaps(x) ((((x) & 0xff) << 8) | (((x) >> 8) & 0xff)) 715a253d6aeSmrg 716a253d6aeSmrgenum parser_return { Continue, End, Error }; 717a253d6aeSmrg 718a253d6aeSmrgstatic enum parser_return 719a253d6aeSmrgparse_reply_call_callback( 720a253d6aeSmrg Display *dpy, 721a253d6aeSmrg XExtDisplayInfo *info, 722a253d6aeSmrg xRecordEnableContextReply *rep, 723a253d6aeSmrg struct reply_buffer *reply, 724a253d6aeSmrg XRecordInterceptProc callback, 725a253d6aeSmrg XPointer closure) 726a253d6aeSmrg{ 727de79cf69Smrg XRecordInterceptData *data; 728072eb593Smrg unsigned int current_index; 729a253d6aeSmrg int datum_bytes = 0; 730a253d6aeSmrg 731a253d6aeSmrg /* call the callback for each protocol element in the reply */ 732a253d6aeSmrg current_index = 0; 733a253d6aeSmrg do { 734de79cf69Smrg data = alloc_inter_data(info); 735a253d6aeSmrg if (!data) 736a253d6aeSmrg return Error; 73706f32fbeSmrg 738a253d6aeSmrg data->id_base = rep->idBase; 739a253d6aeSmrg data->category = rep->category; 740a253d6aeSmrg data->client_swapped = rep->clientSwapped; 741a253d6aeSmrg data->server_time = rep->serverTime; 742a253d6aeSmrg data->client_seq = rep->recordedSequenceNumber; 743a253d6aeSmrg /* 744a253d6aeSmrg * compute the size of this protocol element. 745a253d6aeSmrg */ 746a253d6aeSmrg switch (rep->category) { 747a253d6aeSmrg case XRecordFromServer: 7485bc19eebSmrg if (reply == NULL) 7495bc19eebSmrg goto out; 750a253d6aeSmrg if (rep->elementHeader&XRecordFromServerTime) { 751f1c62215Smrg if (current_index + 4 > rep->length << 2) 752f1c62215Smrg return Error; 753a253d6aeSmrg EXTRACT_CARD32(rep->clientSwapped, 754a253d6aeSmrg reply->buf+current_index, 755a253d6aeSmrg data->server_time); 756a253d6aeSmrg current_index += 4; 757a253d6aeSmrg } 758f1c62215Smrg if (current_index + 1 > rep->length << 2) 759ec15139cSchristos goto out; 760a253d6aeSmrg switch (reply->buf[current_index]) { 761a253d6aeSmrg case X_Reply: /* reply */ 762f1c62215Smrg if (current_index + 8 > rep->length << 2) 763ec15139cSchristos goto out; 764a253d6aeSmrg EXTRACT_CARD32(rep->clientSwapped, 765a253d6aeSmrg reply->buf+current_index+4, datum_bytes); 766f1c62215Smrg if (datum_bytes < 0 || datum_bytes > ((INT_MAX >> 2) - 8)) 767ec15139cSchristos goto out; 768a253d6aeSmrg datum_bytes = (datum_bytes+8) << 2; 769a253d6aeSmrg break; 770a253d6aeSmrg default: /* error or event */ 771a253d6aeSmrg datum_bytes = 32; 772a253d6aeSmrg } 773a253d6aeSmrg break; 774a253d6aeSmrg case XRecordFromClient: 7755bc19eebSmrg if (reply == NULL) 7765bc19eebSmrg goto out; 777a253d6aeSmrg if (rep->elementHeader&XRecordFromClientTime) { 778f1c62215Smrg if (current_index + 4 > rep->length << 2) 779ec15139cSchristos goto out; 780a253d6aeSmrg EXTRACT_CARD32(rep->clientSwapped, 781a253d6aeSmrg reply->buf+current_index, 782a253d6aeSmrg data->server_time); 783a253d6aeSmrg current_index += 4; 784a253d6aeSmrg } 785a253d6aeSmrg if (rep->elementHeader&XRecordFromClientSequence) { 786f1c62215Smrg if (current_index + 4 > rep->length << 2) 787ec15139cSchristos goto out; 788a253d6aeSmrg EXTRACT_CARD32(rep->clientSwapped, 789a253d6aeSmrg reply->buf+current_index, 790a253d6aeSmrg data->client_seq); 791a253d6aeSmrg current_index += 4; 792a253d6aeSmrg } 793f1c62215Smrg if (current_index + 4 > rep->length<<2) 794ec15139cSchristos goto out; 795a253d6aeSmrg if (reply->buf[current_index+2] == 0 796a253d6aeSmrg && reply->buf[current_index+3] == 0) /* needn't swap 0 */ 797a253d6aeSmrg { /* BIG-REQUESTS */ 798f1c62215Smrg if (current_index + 8 > rep->length << 2) 799ec15139cSchristos goto out; 800a253d6aeSmrg EXTRACT_CARD32(rep->clientSwapped, 801a253d6aeSmrg reply->buf+current_index+4, datum_bytes); 802a253d6aeSmrg } else { 803a253d6aeSmrg EXTRACT_CARD16(rep->clientSwapped, 804a253d6aeSmrg reply->buf+current_index+2, datum_bytes); 805a253d6aeSmrg } 806f1c62215Smrg if (datum_bytes < 0 || datum_bytes > INT_MAX >> 2) 807ec15139cSchristos goto out; 808a253d6aeSmrg datum_bytes <<= 2; 809a253d6aeSmrg break; 810a253d6aeSmrg case XRecordClientStarted: 8115bc19eebSmrg if (reply == NULL) 8125bc19eebSmrg goto out; 813f1c62215Smrg if (current_index + 8 > rep->length << 2) 814ec15139cSchristos goto out; 815a253d6aeSmrg EXTRACT_CARD16(rep->clientSwapped, 816a253d6aeSmrg reply->buf+current_index+6, datum_bytes); 817a253d6aeSmrg datum_bytes = (datum_bytes+2) << 2; 818a253d6aeSmrg break; 819a253d6aeSmrg case XRecordClientDied: 820a253d6aeSmrg if (rep->elementHeader&XRecordFromClientSequence) { 8215bc19eebSmrg if (reply == NULL) 8225bc19eebSmrg goto out; 823f1c62215Smrg if (current_index + 4 > rep->length << 2) 824ec15139cSchristos goto out; 825a253d6aeSmrg EXTRACT_CARD32(rep->clientSwapped, 826a253d6aeSmrg reply->buf+current_index, 827a253d6aeSmrg data->client_seq); 828a253d6aeSmrg current_index += 4; 829f1c62215Smrg } else if (current_index < rep->length << 2) 830ec15139cSchristos goto out; 831f1c62215Smrg datum_bytes = 0; 832f1c62215Smrg break; 833a253d6aeSmrg case XRecordStartOfData: 834a253d6aeSmrg case XRecordEndOfData: 835f1c62215Smrg if (current_index < rep->length << 2) 836ec15139cSchristos goto out; 837a253d6aeSmrg datum_bytes = 0; 838f1c62215Smrg break; 839a253d6aeSmrg } 84006f32fbeSmrg 841a253d6aeSmrg if (datum_bytes > 0) { 842f1c62215Smrg if (INT_MAX - datum_bytes < (rep->length << 2) - current_index) { 843a253d6aeSmrg fprintf(stderr, 844a253d6aeSmrg "XRecord: %lu-byte reply claims %d-byte element (seq %lu)\n", 845f1c62215Smrg (unsigned long)rep->length << 2, current_index + datum_bytes, 846a253d6aeSmrg dpy->last_request_read); 847ec15139cSchristos goto out; 848f1c62215Smrg } 849a253d6aeSmrg /* 850a253d6aeSmrg * This assignment (and indeed the whole buffer sharing 851a253d6aeSmrg * scheme) assumes arbitrary 4-byte boundaries are 85206f32fbeSmrg * addressable. 853a253d6aeSmrg */ 854a253d6aeSmrg data->data = reply->buf+current_index; 855a253d6aeSmrg reply->ref_count++; 856a253d6aeSmrg } else { 857a253d6aeSmrg data->data = NULL; 858a253d6aeSmrg } 859a253d6aeSmrg data->data_len = datum_bytes >> 2; 86006f32fbeSmrg 861a253d6aeSmrg (*callback)(closure, data); 86206f32fbeSmrg 863a253d6aeSmrg current_index += datum_bytes; 864a253d6aeSmrg } while (current_index<rep->length<<2); 865a253d6aeSmrg 866a253d6aeSmrg if (rep->category == XRecordEndOfData) 867a253d6aeSmrg return End; 868a253d6aeSmrg 869a253d6aeSmrg return Continue; 870ec15139cSchristosout: 871ec15139cSchristos Xfree(data); 872ec15139cSchristos return Error; 873a253d6aeSmrg} 874a253d6aeSmrg 875a253d6aeSmrgStatus 876ea133fd7SmrgXRecordEnableContext(Display *dpy, XRecordContext context, 877ea133fd7Smrg XRecordInterceptProc callback, XPointer closure) 878a253d6aeSmrg{ 879a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 880a253d6aeSmrg register xRecordEnableContextReq *req; 881a253d6aeSmrg xRecordEnableContextReply rep; 882a253d6aeSmrg struct reply_buffer *reply; 883a253d6aeSmrg 884a253d6aeSmrg XRecordCheckExtension (dpy, info, 0); 885a253d6aeSmrg LockDisplay(dpy); 886a253d6aeSmrg GetReq(RecordEnableContext, req); 887a253d6aeSmrg 888a253d6aeSmrg req->reqType = info->codes->major_opcode; 889a253d6aeSmrg req->recordReqType = X_RecordEnableContext; 890a253d6aeSmrg req->context = context; 891a253d6aeSmrg 892a253d6aeSmrg while (1) 893a253d6aeSmrg { 894072eb593Smrg enum parser_return status; 895072eb593Smrg 896a253d6aeSmrg /* This code should match that in XRecordEnableContextAsync */ 897a253d6aeSmrg if (!_XReply (dpy, (xReply *)&rep, 0, xFalse)) 898a253d6aeSmrg { 899a253d6aeSmrg UnlockDisplay(dpy); 900a253d6aeSmrg SyncHandle(); 901a253d6aeSmrg return 0; 902a253d6aeSmrg } 903a253d6aeSmrg 904f1c62215Smrg if (rep.length > INT_MAX >> 2) { 905f1c62215Smrg UnlockDisplay(dpy); 906f1c62215Smrg SyncHandle(); 907f1c62215Smrg return 0; 908f1c62215Smrg } 909f1c62215Smrg 910a253d6aeSmrg if (rep.length > 0) { 911a253d6aeSmrg reply = alloc_reply_buffer(info, rep.length<<2); 912a253d6aeSmrg if (!reply) { 913a253d6aeSmrg UnlockDisplay(dpy); 914a253d6aeSmrg SyncHandle(); 915a253d6aeSmrg return 0; 916a253d6aeSmrg } 917a253d6aeSmrg _XRead (dpy, (char *)reply->buf, rep.length<<2); 918a253d6aeSmrg } else { 919a253d6aeSmrg reply = NULL; 920a253d6aeSmrg } 921a253d6aeSmrg 922a253d6aeSmrg status = parse_reply_call_callback(dpy, info, &rep, reply, 923a253d6aeSmrg callback, closure); 924a253d6aeSmrg switch (status) { 925a253d6aeSmrg case Continue: 926a253d6aeSmrg break; 927a253d6aeSmrg case End: 928a253d6aeSmrg UnlockDisplay(dpy); 929a253d6aeSmrg SyncHandle(); 930a253d6aeSmrg return 1; 931a253d6aeSmrg case Error: 932a253d6aeSmrg UnlockDisplay(dpy); 933a253d6aeSmrg SyncHandle(); 934a253d6aeSmrg return 0; 935a253d6aeSmrg } 936a253d6aeSmrg } 937a253d6aeSmrg} 938a253d6aeSmrg 939a253d6aeSmrg 940a253d6aeSmrgtypedef struct _record_async_state 941a253d6aeSmrg{ 942a253d6aeSmrg unsigned long enable_seq; 943a253d6aeSmrg _XAsyncHandler *async; 944a253d6aeSmrg _XAsyncErrorState *error_state; 945a253d6aeSmrg XExtDisplayInfo *info; 946a253d6aeSmrg XRecordInterceptProc callback; 947a253d6aeSmrg XPointer closure; 948a253d6aeSmrg} record_async_state; 949a253d6aeSmrg 950a253d6aeSmrgstatic Bool 951a253d6aeSmrgrecord_async_handler( 952a253d6aeSmrg register Display *dpy, 953a253d6aeSmrg register xReply *rep, 954a253d6aeSmrg char *buf, 955a253d6aeSmrg int len, 956a253d6aeSmrg XPointer adata) 957a253d6aeSmrg{ 958a253d6aeSmrg register record_async_state *state = (record_async_state *)adata; 959a253d6aeSmrg struct reply_buffer *reply; 960a253d6aeSmrg enum parser_return status; 961a253d6aeSmrg 962a253d6aeSmrg if (dpy->last_request_read != state->enable_seq) 963a253d6aeSmrg { 964a253d6aeSmrg if (dpy->last_request_read > state->enable_seq) { 965a253d6aeSmrg /* it is an error that we are still on the handler list */ 966a253d6aeSmrg fprintf(stderr, "XRecord: handler for seq %lu never saw XRecordEndOfData. (seq now %lu)\n", 967a253d6aeSmrg state->enable_seq, dpy->last_request_read); 968a253d6aeSmrg DeqAsyncHandler(dpy, state->async); 969a253d6aeSmrg Xfree(state->async); 970a253d6aeSmrg } 971a253d6aeSmrg return False; 972a253d6aeSmrg } 973a253d6aeSmrg if (rep->generic.type == X_Error) 974a253d6aeSmrg { 975a253d6aeSmrg DeqAsyncHandler(dpy, state->async); 976a253d6aeSmrg Xfree(state->async); 977a253d6aeSmrg return False; 978a253d6aeSmrg } 979a253d6aeSmrg 980a253d6aeSmrg if (rep->generic.length > 0) { 981a253d6aeSmrg reply = alloc_reply_buffer(state->info, rep->generic.length<<2); 982a253d6aeSmrg 983a253d6aeSmrg if (!reply) { 984a253d6aeSmrg DeqAsyncHandler(dpy, state->async); 985a253d6aeSmrg Xfree(state->async); 986a253d6aeSmrg return False; 987a253d6aeSmrg } 98806f32fbeSmrg 989a253d6aeSmrg _XGetAsyncData(dpy, (char *)reply->buf, buf, len, 990a253d6aeSmrg SIZEOF(xRecordEnableContextReply), 991a253d6aeSmrg rep->generic.length << 2, 0); 992a253d6aeSmrg } else { 993a253d6aeSmrg reply = NULL; 994a253d6aeSmrg } 995a253d6aeSmrg 99606f32fbeSmrg status = parse_reply_call_callback(dpy, state->info, 99706f32fbeSmrg (xRecordEnableContextReply*) rep, 998a253d6aeSmrg reply, state->callback, state->closure); 999a253d6aeSmrg 1000a253d6aeSmrg if (status != Continue) 1001a253d6aeSmrg { 1002a253d6aeSmrg DeqAsyncHandler(dpy, state->async); 1003a253d6aeSmrg Xfree(state->async); 1004a253d6aeSmrg if (status == Error) 1005a253d6aeSmrg return False; 1006a253d6aeSmrg } 1007a253d6aeSmrg 1008a253d6aeSmrg return True; 1009a253d6aeSmrg} 1010a253d6aeSmrg 1011a253d6aeSmrg/* 1012a253d6aeSmrg * reads the first reply, StartOfData, synchronously, 1013a253d6aeSmrg * then returns allowing the app to call XRecordProcessReplies 1014a253d6aeSmrg * to get the rest. 1015a253d6aeSmrg */ 1016a253d6aeSmrgStatus 1017ea133fd7SmrgXRecordEnableContextAsync(Display *dpy, XRecordContext context, 1018ea133fd7Smrg XRecordInterceptProc callback, XPointer closure) 1019a253d6aeSmrg{ 1020a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 1021a253d6aeSmrg register xRecordEnableContextReq *req; 1022a253d6aeSmrg xRecordEnableContextReply rep; 1023a253d6aeSmrg struct reply_buffer *reply; 1024a253d6aeSmrg enum parser_return status; 1025a253d6aeSmrg _XAsyncHandler *async; 1026a253d6aeSmrg record_async_state *async_state; 1027a253d6aeSmrg 1028a253d6aeSmrg XRecordCheckExtension (dpy, info, 0); 1029072eb593Smrg async = Xmalloc(sizeof(_XAsyncHandler) + sizeof(record_async_state)); 1030a253d6aeSmrg if (!async) 1031a253d6aeSmrg return 0; 1032a253d6aeSmrg async_state = (record_async_state *)(async + 1); 1033a253d6aeSmrg 1034a253d6aeSmrg LockDisplay(dpy); 1035a253d6aeSmrg GetReq(RecordEnableContext, req); 1036a253d6aeSmrg 1037a253d6aeSmrg req->reqType = info->codes->major_opcode; 1038a253d6aeSmrg req->recordReqType = X_RecordEnableContext; 1039a253d6aeSmrg req->context = context; 1040a253d6aeSmrg 1041a253d6aeSmrg /* Get the StartOfData reply. */ 1042a253d6aeSmrg /* This code should match that in XRecordEnableContext */ 1043a253d6aeSmrg if (!_XReply (dpy, (xReply *)&rep, 0, xFalse)) 1044a253d6aeSmrg { 1045a253d6aeSmrg UnlockDisplay(dpy); 1046a253d6aeSmrg SyncHandle(); 1047a253d6aeSmrg Xfree(async); 1048a253d6aeSmrg return 0; 1049a253d6aeSmrg } 1050a253d6aeSmrg 1051a253d6aeSmrg /* this had better be a StartOfData, which has no extra data. */ 1052a253d6aeSmrg if (rep.length != 0) { 1053a253d6aeSmrg fprintf(stderr, "XRecord: malformed StartOfData for sequence %lu\n", 1054a253d6aeSmrg dpy->last_request_read); 1055a253d6aeSmrg } 1056a253d6aeSmrg reply = NULL; 1057a253d6aeSmrg 1058a253d6aeSmrg status = parse_reply_call_callback(dpy, info, &rep, reply, 1059a253d6aeSmrg callback, closure); 1060a253d6aeSmrg if (status != Continue) 1061a253d6aeSmrg { 1062a253d6aeSmrg UnlockDisplay(dpy); 1063a253d6aeSmrg Xfree(async); 1064a253d6aeSmrg return 0; 1065a253d6aeSmrg } 1066a253d6aeSmrg 1067a253d6aeSmrg /* hook in the async handler for the rest of the replies */ 1068a253d6aeSmrg async_state->enable_seq = dpy->request; 1069a253d6aeSmrg async_state->async = async; 1070a253d6aeSmrg async_state->info = info; 1071a253d6aeSmrg async_state->callback = callback; 1072a253d6aeSmrg async_state->closure = closure; 1073a253d6aeSmrg 1074a253d6aeSmrg async->next = dpy->async_handlers; 1075a253d6aeSmrg async->handler = record_async_handler; 1076a253d6aeSmrg async->data = (XPointer)async_state; 1077a253d6aeSmrg dpy->async_handlers = async; 1078a253d6aeSmrg 1079a253d6aeSmrg UnlockDisplay(dpy); 1080a253d6aeSmrg /* Don't invoke SyncHandle here, since this is an async 1081a253d6aeSmrg function. Does this break XSetAfterFunction() ? */ 1082a253d6aeSmrg return 1; 1083a253d6aeSmrg} 1084a253d6aeSmrg 1085a253d6aeSmrgvoid 1086ea133fd7SmrgXRecordProcessReplies(Display *dpy) 1087a253d6aeSmrg{ 1088a253d6aeSmrg (void) XPending(dpy); 1089a253d6aeSmrg} 1090a253d6aeSmrg 1091a253d6aeSmrgStatus 1092ea133fd7SmrgXRecordDisableContext(Display *dpy, XRecordContext context) 1093a253d6aeSmrg{ 1094a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 1095a253d6aeSmrg register xRecordDisableContextReq *req; 1096a253d6aeSmrg 1097a253d6aeSmrg XRecordCheckExtension (dpy, info, 0); 1098a253d6aeSmrg LockDisplay(dpy); 1099a253d6aeSmrg GetReq(RecordDisableContext, req); 1100a253d6aeSmrg req->reqType = info->codes->major_opcode; 1101a253d6aeSmrg req->recordReqType = X_RecordDisableContext; 1102a253d6aeSmrg req->context = context; 1103a253d6aeSmrg 1104a253d6aeSmrg UnlockDisplay(dpy); 1105a253d6aeSmrg SyncHandle(); 1106a253d6aeSmrg return 1; 1107a253d6aeSmrg} 1108a253d6aeSmrg 1109a253d6aeSmrgStatus 1110ea133fd7SmrgXRecordFreeContext(Display *dpy, XRecordContext context) 1111a253d6aeSmrg{ 1112a253d6aeSmrg XExtDisplayInfo *info = find_display (dpy); 1113a253d6aeSmrg register xRecordFreeContextReq *req; 1114a253d6aeSmrg 1115a253d6aeSmrg XRecordCheckExtension (dpy, info, 0); 1116a253d6aeSmrg 1117a253d6aeSmrg LockDisplay(dpy); 1118a253d6aeSmrg GetReq(RecordFreeContext, req); 1119a253d6aeSmrg req->reqType = info->codes->major_opcode; 1120a253d6aeSmrg req->recordReqType = X_RecordFreeContext; 1121a253d6aeSmrg req->context = context; 1122a253d6aeSmrg 1123a253d6aeSmrg UnlockDisplay(dpy); 1124a253d6aeSmrg SyncHandle(); 1125a253d6aeSmrg return 1; 1126a253d6aeSmrg} 1127