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