XMultibuf.c revision caade7cc
1/*
2 * $Xorg: XMultibuf.c,v 1.6 2001/02/09 02:03:49 xorgcvs Exp $
3 *
4Copyright 1989, 1998  The Open Group
5
6Permission to use, copy, modify, distribute, and sell this software and its
7documentation for any purpose is hereby granted without fee, provided that
8the above copyright notice appear in all copies and that both that
9copyright notice and this permission notice appear in supporting
10documentation.
11
12The above copyright notice and this permission notice shall be included in
13all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall not be
23used in advertising or otherwise to promote the sale, use or other dealings
24in this Software without prior written authorization from The Open Group.
25 *
26 * Authors:  Jim Fulton, MIT X Consortium
27 */
28/* $XFree86: xc/lib/Xext/XMultibuf.c,v 1.5 2001/12/14 19:55:00 dawes Exp $ */
29
30#define NEED_EVENTS
31#define NEED_REPLIES
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35#include <X11/Xlibint.h>
36#include <stdio.h>
37#include <X11/extensions/Xext.h>
38#include <X11/extensions/extutil.h>
39#include <X11/extensions/multibufst.h>
40
41static XExtensionInfo _multibuf_info_data;
42static XExtensionInfo *multibuf_info = &_multibuf_info_data;
43static /* const */ char *multibuf_extension_name = MULTIBUFFER_PROTOCOL_NAME;
44
45#define MbufCheckExtension(dpy,i,val) \
46  XextCheckExtension (dpy, i, multibuf_extension_name, val)
47#define MbufSimpleCheckExtension(dpy,i) \
48  XextSimpleCheckExtension (dpy, i, multibuf_extension_name)
49
50
51/*****************************************************************************
52 *                                                                           *
53 *			   private utility routines                          *
54 *                                                                           *
55 *****************************************************************************/
56
57/*
58 * find_display - locate the display info block
59 */
60static int close_display(Display *dpy, XExtCodes *codes);
61static char *error_string(Display *dpy, int code, XExtCodes *codes, char *buf, int n);
62static Bool wire_to_event(Display *dpy, XEvent *libevent, xEvent *netevent);
63static Status event_to_wire(Display *dpy, XEvent *libevent, xEvent *netevent);
64static /* const */ XExtensionHooks multibuf_extension_hooks = {
65    NULL,				/* create_gc */
66    NULL,				/* copy_gc */
67    NULL,				/* flush_gc */
68    NULL,				/* free_gc */
69    NULL,				/* create_font */
70    NULL,				/* free_font */
71    close_display,			/* close_display */
72    wire_to_event,			/* wire_to_event */
73    event_to_wire,			/* event_to_wire */
74    NULL,				/* error */
75    error_string,			/* error_string */
76};
77
78static /* const */ char *multibuf_error_list[] = {
79    "BadBuffer",			/* MultibufferBadBuffer */
80};
81
82static XEXT_GENERATE_FIND_DISPLAY (find_display, multibuf_info,
83				   multibuf_extension_name,
84				   &multibuf_extension_hooks,
85				   MultibufferNumberEvents, NULL)
86
87static XEXT_GENERATE_CLOSE_DISPLAY (close_display, multibuf_info)
88
89static XEXT_GENERATE_ERROR_STRING (error_string, multibuf_extension_name,
90				   MultibufferNumberErrors,
91				   multibuf_error_list)
92
93/*
94 * wire_to_event - convert a wire event in network format to a C
95 * event structure
96 */
97static Bool wire_to_event (Display *dpy, XEvent *libevent, xEvent *netevent)
98{
99    XExtDisplayInfo *info = find_display (dpy);
100
101    MbufCheckExtension (dpy, info, False);
102
103    switch ((netevent->u.u.type & 0x7f) - info->codes->first_event) {
104      case MultibufferClobberNotify:
105	{
106	    XmbufClobberNotifyEvent *ev;
107	    xMbufClobberNotifyEvent *event;
108
109    	    ev = (XmbufClobberNotifyEvent *) libevent;
110	    event = (xMbufClobberNotifyEvent *) netevent;
111    	    ev->type = event->type & 0x7f;
112    	    ev->serial = _XSetLastRequestRead(dpy,(xGenericReply *) netevent);
113    	    ev->send_event = ((event->type & 0x80) != 0);
114    	    ev->display = dpy;
115    	    ev->buffer = event->buffer;
116	    ev->state = event->state;
117    	    return True;
118	}
119      case MultibufferUpdateNotify:
120	{
121	    XmbufUpdateNotifyEvent *ev;
122	    xMbufUpdateNotifyEvent *event;
123
124	    ev = (XmbufUpdateNotifyEvent *) libevent;
125	    event = (xMbufUpdateNotifyEvent *) netevent;
126	    ev->type = event->type & 0x7f;
127	    ev->serial = _XSetLastRequestRead(dpy,(xGenericReply *) netevent);
128	    ev->send_event = ((event->type & 0x80) != 0);
129	    ev->display = dpy;
130	    ev->buffer = event->buffer;
131	    return True;
132	}
133    }
134    return False;
135}
136
137
138/*
139 * event_to_wire - convert a C event structure to a wire event in
140 * network format
141 */
142static Status event_to_wire (Display *dpy, XEvent *libevent, xEvent *netevent)
143{
144    XExtDisplayInfo *info = find_display (dpy);
145
146    MbufCheckExtension (dpy, info, 0);
147
148    switch ((libevent->type & 0x7f) - info->codes->first_event) {
149      case MultibufferClobberNotify:
150	{
151	    XmbufClobberNotifyEvent *ev;
152	    xMbufClobberNotifyEvent *event;
153
154    	    ev = (XmbufClobberNotifyEvent *) libevent;
155	    event = (xMbufClobberNotifyEvent *) netevent;
156    	    event->type = ev->type;
157    	    event->sequenceNumber = (ev->serial & 0xffff);
158    	    event->buffer = ev->buffer;
159	    event->state = ev->state;
160    	    return 1;
161	}
162      case MultibufferUpdateNotify:
163	{
164	    XmbufUpdateNotifyEvent *ev;
165	    xMbufUpdateNotifyEvent *event;
166
167	    ev = (XmbufUpdateNotifyEvent *) libevent;
168	    event = (xMbufUpdateNotifyEvent *) netevent;
169	    event->type = ev->type;
170	    event->sequenceNumber = (ev->serial & 0xffff);
171	    event->buffer = ev->buffer;
172	    return 1;
173	}
174    }
175    return 0;
176}
177
178
179/*
180 * read_buffer_info - read Buffer Info descriptors from the net; if unable
181 * to allocate memory, read junk to make sure that stream is clear.
182 */
183#define TALLOC(type,count) ((type *) Xmalloc ((unsigned) count * sizeof(type)))
184
185static XmbufBufferInfo *read_buffer_info (Display *dpy, int nbufs)
186{
187    xMbufBufferInfo *netbuf = TALLOC (xMbufBufferInfo, nbufs);
188    XmbufBufferInfo *bufinfo = NULL;
189    long netbytes = nbufs * SIZEOF(xMbufBufferInfo);
190
191    if (netbuf) {
192	_XRead (dpy, (char *) netbuf, netbytes);
193
194	bufinfo = TALLOC (XmbufBufferInfo, nbufs);
195	if (bufinfo) {
196	    register XmbufBufferInfo *c;
197	    register xMbufBufferInfo *net;
198	    register int i;
199
200	    for (i = 0, c = bufinfo, net = netbuf; i < nbufs;
201		 i++, c++, net++) {
202		c->visualid = net->visualID;
203		c->max_buffers = net->maxBuffers;
204		c->depth = net->depth;
205	    }
206	}
207	Xfree ((char *) netbuf);
208    } else {				/* eat the data */
209	while (netbytes > 0) {
210	    char dummy[256];		/* stack size vs loops tradeoff */
211	    long nbytes = sizeof dummy;
212
213	    if (nbytes > netbytes) nbytes = netbytes;
214	    _XRead (dpy, dummy, nbytes);
215	    netbytes -= nbytes;
216	}
217    }
218
219    return bufinfo;
220}
221
222#undef TALLOC
223
224
225/*****************************************************************************
226 *                                                                           *
227 *		    Multibuffering/stereo public interfaces                  *
228 *                                                                           *
229 *****************************************************************************/
230
231
232/*
233 * XmbufQueryExtension -
234 * 	Returns True if the multibuffering/stereo extension is available
235 * 	on the given display.  If the extension exists, the value of the
236 * 	first event code (which should be added to the event type constants
237 * 	MultibufferClobberNotify and MultibufferUpdateNotify to get the
238 * 	actual values) is stored into event_base and the value of the first
239 * 	error code (which should be added to the error type constant
240 * 	MultibufferBadBuffer to get the actual value) is stored into
241 * 	error_base.
242 */
243Bool XmbufQueryExtension (
244    Display *dpy,
245    int *event_base_return, int *error_base_return)
246{
247    XExtDisplayInfo *info = find_display (dpy);
248
249    if (XextHasExtension (info)) {
250	*event_base_return = info->codes->first_event;
251	*error_base_return = info->codes->first_error;
252	return True;
253    } else {
254	return False;
255    }
256}
257
258
259/*
260 * XmbufGetVersion -
261 * 	Gets the major and minor version numbers of the extension.  The return
262 * 	value is zero if an error occurs or non-zero if no error happens.
263 */
264Status XmbufGetVersion (
265    Display *dpy,
266    int *major_version_return, int *minor_version_return)
267{
268    XExtDisplayInfo *info = find_display (dpy);
269    xMbufGetBufferVersionReply rep;
270    register xMbufGetBufferVersionReq *req;
271
272    MbufCheckExtension (dpy, info, 0);
273
274    LockDisplay (dpy);
275    MbufGetReq (MbufGetBufferVersion, req, info);
276    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
277	UnlockDisplay (dpy);
278	SyncHandle ();
279	return 0;
280    }
281    *major_version_return = rep.majorVersion;
282    *minor_version_return = rep.minorVersion;
283    UnlockDisplay (dpy);
284
285    SyncHandle ();
286    return 1;
287}
288
289
290/*
291 * XmbufCreateBuffers -
292 * 	Requests that "count" buffers be created with the given update_action
293 * 	and update_hint and be associated with the indicated window.  The
294 * 	number of buffers created is returned (zero if an error occurred)
295 * 	and buffers_return is filled in with that many Multibuffer identifiers.
296 */
297int XmbufCreateBuffers (
298    Display *dpy,
299    Window w,
300    int count,
301    int update_action, int update_hint,
302    Multibuffer *buffers)
303{
304    XExtDisplayInfo *info = find_display (dpy);
305    xMbufCreateImageBuffersReply rep;
306    register xMbufCreateImageBuffersReq *req;
307    int result;
308
309    MbufCheckExtension (dpy, info, 0);
310
311    LockDisplay (dpy);
312
313    XAllocIDs(dpy, buffers, count);
314    MbufGetReq (MbufCreateImageBuffers, req, info);
315    req->window = w;
316    req->updateAction = update_action;
317    req->updateHint = update_hint;
318    req->length += count;
319    count <<= 2;
320    PackData32 (dpy, buffers, count);
321    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
322	UnlockDisplay (dpy);
323	SyncHandle ();
324	return 0;
325    }
326    result = rep.numberBuffer;
327    UnlockDisplay (dpy);
328
329    SyncHandle ();
330    return result;
331}
332
333
334/*
335 * XmbufDestroyBuffers -
336 * 	Destroys the buffers associated with the given window.
337 */
338void XmbufDestroyBuffers (Display *dpy, Window window)
339{
340    XExtDisplayInfo *info = find_display (dpy);
341    register xMbufDestroyImageBuffersReq *req;
342
343    MbufSimpleCheckExtension (dpy, info);
344
345    LockDisplay (dpy);
346    MbufGetReq (MbufDestroyImageBuffers, req, info);
347    req->window = window;
348    UnlockDisplay (dpy);
349    SyncHandle ();
350}
351
352
353/*
354 * XmbufDisplayBuffers -
355 * 	Displays the indicated buffers their appropriate windows within
356 * 	max_delay milliseconds after min_delay milliseconds have passed.
357 * 	No two buffers may be associated with the same window or else a Match
358 * 	error is generated.
359 */
360void XmbufDisplayBuffers (
361    Display *dpy,
362    int count,
363    Multibuffer *buffers,
364    int min_delay, int max_delay)
365{
366    XExtDisplayInfo *info = find_display (dpy);
367    register xMbufDisplayImageBuffersReq *req;
368
369    MbufSimpleCheckExtension (dpy, info);
370
371    LockDisplay (dpy);
372    MbufGetReq (MbufDisplayImageBuffers, req, info);
373    req->minDelay = min_delay;
374    req->maxDelay = max_delay;
375    req->length += count;
376    count <<= 2;
377    PackData32 (dpy, buffers, count);
378    UnlockDisplay (dpy);
379    SyncHandle();
380}
381
382
383/*
384 * XmbufGetWindowAttributes -
385 * 	Gets the multibuffering attributes that apply to all buffers associated
386 * 	with the given window.  Returns non-zero on success and zero if an
387 * 	error occurs.
388 */
389Status XmbufGetWindowAttributes (
390    Display *dpy,
391    Window w,
392    XmbufWindowAttributes *attr)
393{
394    XExtDisplayInfo *info = find_display (dpy);
395    register xMbufGetMBufferAttributesReq *req;
396    xMbufGetMBufferAttributesReply rep;
397
398    MbufCheckExtension (dpy, info, 0);
399
400    LockDisplay (dpy);
401    MbufGetReq (MbufGetMBufferAttributes, req, info);
402    req->window = w;
403    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
404	UnlockDisplay (dpy);
405	SyncHandle ();
406	return 0;
407    }
408    attr->buffers = (Multibuffer *) NULL;
409    if ((attr->nbuffers = rep.length)) {
410	int nbytes = rep.length * sizeof(Multibuffer);
411	attr->buffers = (Multibuffer *) Xmalloc((unsigned) nbytes);
412	nbytes = rep.length << 2;
413	if (! attr->buffers) {
414	    _XEatData(dpy, (unsigned long) nbytes);
415	    UnlockDisplay(dpy);
416	    SyncHandle();
417	    return (0);
418	}
419	_XRead32 (dpy, (long *) attr->buffers, nbytes);
420    }
421    attr->displayed_index = rep.displayedBuffer;
422    attr->update_action = rep.updateAction;
423    attr->update_hint = rep.updateHint;
424    attr->window_mode = rep.windowMode;
425
426    UnlockDisplay (dpy);
427    SyncHandle();
428    return 1;
429}
430
431
432/*
433 * XmbufChangeWindowAttributes -
434 * 	Sets the multibuffering attributes that apply to all buffers associated
435 * 	with the given window.  This is currently limited to the update_hint.
436 */
437void XmbufChangeWindowAttributes (
438    Display *dpy,
439    Window w,
440    unsigned long valuemask,
441    XmbufSetWindowAttributes *attr)
442{
443    XExtDisplayInfo *info = find_display (dpy);
444    register xMbufSetMBufferAttributesReq *req;
445
446    MbufSimpleCheckExtension (dpy, info);
447
448    LockDisplay (dpy);
449    MbufGetReq (MbufSetMBufferAttributes, req, info);
450    req->window = w;
451    if ((req->valueMask = valuemask)) {	/* stolen from lib/X/XWindow.c */
452	unsigned long values[1];	/* one per element in if stmts below */
453	unsigned long *v = values;
454	unsigned int nvalues;
455
456	if (valuemask & MultibufferWindowUpdateHint)
457	  *v++ = attr->update_hint;
458	req->length += (nvalues = v - values);
459	nvalues <<= 2;			/* watch out for macros... */
460	Data32 (dpy, (long *) values, (long)nvalues);
461    }
462    UnlockDisplay (dpy);
463    SyncHandle();
464}
465
466
467/*
468 * XmbufGetBufferAttributes -
469 * 	Gets the attributes for the indicated buffer.  Returns non-zero on
470 * 	success and zero if an error occurs.
471 */
472Status XmbufGetBufferAttributes (
473    Display *dpy,
474    Multibuffer b,
475    XmbufBufferAttributes *attr)
476{
477    XExtDisplayInfo *info = find_display (dpy);
478    register xMbufGetBufferAttributesReq *req;
479    xMbufGetBufferAttributesReply rep;
480
481    MbufCheckExtension (dpy, info, 0);
482
483    LockDisplay (dpy);
484    MbufGetReq (MbufGetBufferAttributes, req, info);
485    req->buffer = b;
486    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
487	UnlockDisplay (dpy);
488	SyncHandle ();
489	return 0;
490    }
491    attr->window = rep.window;
492    attr->event_mask = rep.eventMask;
493    attr->buffer_index = rep.bufferIndex;
494    attr->side = rep.side;
495
496    UnlockDisplay (dpy);
497    SyncHandle();
498    return 1;
499}
500
501
502/*
503 * XmbufChangeBufferAttributes -
504 * 	Sets the attributes for the indicated buffer.  This is currently
505 * 	limited to the event_mask.
506 */
507void XmbufChangeBufferAttributes (
508    Display *dpy,
509    Multibuffer b,
510    unsigned long valuemask,
511    XmbufSetBufferAttributes *attr)
512{
513    XExtDisplayInfo *info = find_display (dpy);
514    register xMbufSetBufferAttributesReq *req;
515
516    MbufSimpleCheckExtension (dpy, info);
517
518    LockDisplay (dpy);
519    MbufGetReq (MbufSetBufferAttributes, req, info);
520    req->buffer = b;
521    if ((req->valueMask = valuemask)) {	/* stolen from lib/X/XWindow.c */
522	unsigned long values[1];	/* one per element in if stmts below */
523	unsigned long *v = values;
524	unsigned int nvalues;
525
526	if (valuemask & MultibufferBufferEventMask)
527	  *v++ = attr->event_mask;
528	req->length += (nvalues = v - values);
529	nvalues <<= 2;			/* watch out for macros... */
530	Data32 (dpy, (long *) values, (long)nvalues);
531    }
532    UnlockDisplay (dpy);
533    SyncHandle();
534}
535
536
537
538/*
539 * XmbufGetScreenInfo -
540 * 	Gets the parameters controlling how mono and stereo windows may be
541 * 	created on the indicated screen.  The numbers of sets of visual and
542 * 	depths are returned in nmono_return and nstereo_return.  If
543 * 	nmono_return is greater than zero, then mono_info_return is set to
544 * 	the address of an array of XmbufBufferInfo structures describing the
545 * 	various visuals and depths that may be used.  Otherwise,
546 * 	mono_info_return is set to NULL.  Similarly, stereo_info_return is
547 * 	set according to nstereo_return.  The storage returned in
548 * 	mono_info_return and stereo_info_return may be released by XFree.
549 * 	If no errors are encounted, non-zero will be returned.
550 */
551Status XmbufGetScreenInfo (
552    Display *dpy,
553    Drawable d,
554    int *nmono_return,
555    XmbufBufferInfo **mono_info_return,
556    int *nstereo_return,
557    XmbufBufferInfo **stereo_info_return)
558{
559    XExtDisplayInfo *info = find_display (dpy);
560    register xMbufGetBufferInfoReq *req;
561    xMbufGetBufferInfoReply rep;
562    int nmono, nstereo;
563    XmbufBufferInfo *minfo, *sinfo;
564
565    MbufCheckExtension (dpy, info, 0);
566
567    LockDisplay (dpy);
568    MbufGetReq (MbufGetBufferInfo, req, info);
569    req->drawable = d;
570    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
571	UnlockDisplay (dpy);
572	SyncHandle ();
573	return 0;
574    }
575    nmono = rep.normalInfo;
576    nstereo = rep.stereoInfo;
577    minfo = ((nmono > 0) ? read_buffer_info (dpy, nmono) : NULL);
578    sinfo = ((nstereo > 0) ? read_buffer_info (dpy, nstereo) : NULL);
579
580    /* check for bad reads indicating we need to return an error */
581    if ((nmono > 0 && !minfo) || (nstereo > 0 && !sinfo)) {
582	if (minfo) Xfree ((char *) minfo);
583	if (sinfo) Xfree ((char *) sinfo);
584	UnlockDisplay (dpy);
585	SyncHandle();
586	return 0;
587    }
588
589    *nmono_return = nmono;
590    *mono_info_return = minfo;
591    *nstereo_return = nstereo;
592    *stereo_info_return = sinfo;
593
594    UnlockDisplay (dpy);
595    SyncHandle();
596    return 1;
597}
598
599
600/*
601 * XmbufCreateStereoWindow -
602 * 	Creates a stereo window in the same way that XCreateWindow creates
603 * 	a mono window (in fact, use the same code, except for the request)
604 *      and returns the left and right buffers that may be
605 */
606Window XmbufCreateStereoWindow (
607    Display *dpy,
608    Window parent,
609    int x, int y,
610    unsigned int width, unsigned int height, unsigned int border_width,
611    int depth,
612    unsigned int class,
613    Visual *visual,
614    unsigned long valuemask,
615    XSetWindowAttributes *attr,
616    Multibuffer *leftp, Multibuffer *rightp)
617{
618    XExtDisplayInfo *info = find_display (dpy);
619    Window wid;
620    register xMbufCreateStereoWindowReq *req;
621
622    MbufCheckExtension (dpy, info, None);
623
624    LockDisplay(dpy);
625    MbufGetReq(MbufCreateStereoWindow, req, info);
626    wid = req->wid = XAllocID(dpy);
627    req->parent = parent;
628    req->left = *leftp = XAllocID (dpy);
629    req->right = *rightp = XAllocID (dpy);
630    req->x = x;
631    req->y = y;
632    req->width = width;
633    req->height = height;
634    req->borderWidth = border_width;
635    req->depth = depth;
636    req->class = class;
637    if (visual == CopyFromParent)
638	req->visual = CopyFromParent;
639    else
640	req->visual = visual->visualid;
641    valuemask &= (CWBackPixmap|CWBackPixel|CWBorderPixmap|
642		     CWBorderPixel|CWBitGravity|CWWinGravity|
643		     CWBackingStore|CWBackingPlanes|CWBackingPixel|
644		     CWOverrideRedirect|CWSaveUnder|CWEventMask|
645		     CWDontPropagate|CWColormap|CWCursor);
646    if ((req->mask = valuemask)) {
647	unsigned long values[32];
648	register unsigned long *value = values;
649	unsigned int nvalues;
650
651	if (valuemask & CWBackPixmap)
652	  *value++ = attr->background_pixmap;
653	if (valuemask & CWBackPixel)
654	  *value++ = attr->background_pixel;
655	if (valuemask & CWBorderPixmap)
656	  *value++ = attr->border_pixmap;
657	if (valuemask & CWBorderPixel)
658	  *value++ = attr->border_pixel;
659	if (valuemask & CWBitGravity)
660	  *value++ = attr->bit_gravity;
661	if (valuemask & CWWinGravity)
662	  *value++ = attr->win_gravity;
663	if (valuemask & CWBackingStore)
664	  *value++ = attr->backing_store;
665	if (valuemask & CWBackingPlanes)
666	  *value++ = attr->backing_planes;
667	if (valuemask & CWBackingPixel)
668	  *value++ = attr->backing_pixel;
669	if (valuemask & CWOverrideRedirect)
670	  *value++ = attr->override_redirect;
671	if (valuemask & CWSaveUnder)
672	  *value++ = attr->save_under;
673	if (valuemask & CWEventMask)
674	  *value++ = attr->event_mask;
675	if (valuemask & CWDontPropagate)
676	  *value++ = attr->do_not_propagate_mask;
677	if (valuemask & CWColormap)
678	  *value++ = attr->colormap;
679	if (valuemask & CWCursor)
680	  *value++ = attr->cursor;
681	req->length += (nvalues = value - values);
682
683	nvalues <<= 2;			    /* watch out for macros... */
684	Data32 (dpy, (long *) values, (long)nvalues);
685    }
686    UnlockDisplay(dpy);
687    SyncHandle();
688    return wid;
689}
690
691void XmbufClearBufferArea (
692    Display *dpy,
693    Multibuffer buffer,
694    int x, int y,
695    unsigned int width, unsigned int height,
696    Bool exposures)
697{
698    XExtDisplayInfo *info = find_display (dpy);
699    register xMbufClearImageBufferAreaReq *req;
700
701    MbufSimpleCheckExtension (dpy, info);
702
703    LockDisplay (dpy);
704    MbufGetReq (MbufClearImageBufferArea, req, info);
705    req->buffer = buffer;
706    req->x      = x;
707    req->y      = y;
708    req->width  = width;
709    req->height = height;
710    req->exposures = exposures;
711    UnlockDisplay (dpy);
712    SyncHandle();
713}
714
715