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