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