3 Copyright 1989, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 * Authors: Jim Fulton, MIT X Consortium
31 #include <X11/Xlibint.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>
38 static XExtensionInfo _multibuf_info_data;
39 static XExtensionInfo *multibuf_info = &_multibuf_info_data;
40 static const char *multibuf_extension_name = MULTIBUFFER_PROTOCOL_NAME;
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)
48 /*****************************************************************************
50 * private utility routines *
52 *****************************************************************************/
55 * find_display - locate the display info block
57 static int close_display(Display *dpy, XExtCodes *codes);
58 static char *error_string(Display *dpy, int code, XExtCodes *codes, char *buf, int n);
59 static Bool wire_to_event(Display *dpy, XEvent *libevent, xEvent *netevent);
60 static Status event_to_wire(Display *dpy, XEvent *libevent, xEvent *netevent);
61 static /* const */ XExtensionHooks multibuf_extension_hooks = {
66 NULL, /* create_font */
68 close_display, /* close_display */
69 wire_to_event, /* wire_to_event */
70 event_to_wire, /* event_to_wire */
72 error_string, /* error_string */
75 static const char *multibuf_error_list[] = {
76 "BadBuffer", /* MultibufferBadBuffer */
79 static XEXT_GENERATE_FIND_DISPLAY (find_display, multibuf_info,
80 multibuf_extension_name,
81 &multibuf_extension_hooks,
82 MultibufferNumberEvents, NULL)
84 static XEXT_GENERATE_CLOSE_DISPLAY (close_display, multibuf_info)
86 static XEXT_GENERATE_ERROR_STRING (error_string, multibuf_extension_name,
87 MultibufferNumberErrors,
91 * wire_to_event - convert a wire event in network format to a C
94 static Bool wire_to_event (Display *dpy, XEvent *libevent, xEvent *netevent)
96 XExtDisplayInfo *info = find_display (dpy);
98 MbufCheckExtension (dpy, info, False);
100 switch ((netevent->u.u.type & 0x7f) - info->codes->first_event) {
101 case MultibufferClobberNotify:
103 XmbufClobberNotifyEvent *ev;
104 xMbufClobberNotifyEvent *event;
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);
112 ev->buffer = event->buffer;
113 ev->state = event->state;
116 case MultibufferUpdateNotify:
118 XmbufUpdateNotifyEvent *ev;
119 xMbufUpdateNotifyEvent *event;
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);
127 ev->buffer = event->buffer;
136 * event_to_wire - convert a C event structure to a wire event in
139 static Status event_to_wire (Display *dpy, XEvent *libevent, xEvent *netevent)
141 XExtDisplayInfo *info = find_display (dpy);
143 MbufCheckExtension (dpy, info, 0);
145 switch ((libevent->type & 0x7f) - info->codes->first_event) {
146 case MultibufferClobberNotify:
148 XmbufClobberNotifyEvent *ev;
149 xMbufClobberNotifyEvent *event;
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;
159 case MultibufferUpdateNotify:
161 XmbufUpdateNotifyEvent *ev;
162 xMbufUpdateNotifyEvent *event;
164 ev = (XmbufUpdateNotifyEvent *) libevent;
165 event = (xMbufUpdateNotifyEvent *) netevent;
166 event->type = ev->type;
167 event->sequenceNumber = (ev->serial & 0xffff);
168 event->buffer = ev->buffer;
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.
180 #define TALLOC(type,count) ((type *) Xmalloc ((unsigned) count * sizeof(type)))
182 static XmbufBufferInfo *read_buffer_info (Display *dpy, int nbufs)
184 xMbufBufferInfo *netbuf = TALLOC (xMbufBufferInfo, nbufs);
185 XmbufBufferInfo *bufinfo = NULL;
186 long netbytes = nbufs * SIZEOF(xMbufBufferInfo);
189 _XRead (dpy, (char *) netbuf, netbytes);
191 bufinfo = TALLOC (XmbufBufferInfo, nbufs);
193 register XmbufBufferInfo *c;
194 register xMbufBufferInfo *net;
197 for (i = 0, c = bufinfo, net = netbuf; i < nbufs;
199 c->visualid = net->visualID;
200 c->max_buffers = net->maxBuffers;
201 c->depth = net->depth;
204 Xfree ((char *) netbuf);
205 } else { /* eat the data */
206 while (netbytes > 0) {
207 char dummy[256]; /* stack size vs loops tradeoff */
208 long nbytes = sizeof dummy;
210 if (nbytes > netbytes) nbytes = netbytes;
211 _XRead (dpy, dummy, nbytes);
222 /*****************************************************************************
224 * Multibuffering/stereo public interfaces *
226 *****************************************************************************/
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
240 Bool XmbufQueryExtension (
242 int *event_base_return, int *error_base_return)
244 XExtDisplayInfo *info = find_display (dpy);
246 if (XextHasExtension (info)) {
247 *event_base_return = info->codes->first_event;
248 *error_base_return = info->codes->first_error;
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.
261 Status XmbufGetVersion (
263 int *major_version_return, int *minor_version_return)
265 XExtDisplayInfo *info = find_display (dpy);
266 xMbufGetBufferVersionReply rep;
267 register xMbufGetBufferVersionReq *req;
269 MbufCheckExtension (dpy, info, 0);
272 MbufGetReq (MbufGetBufferVersion, req, info);
273 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
278 *major_version_return = rep.majorVersion;
279 *minor_version_return = rep.minorVersion;
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.
294 int XmbufCreateBuffers (
298 int update_action, int update_hint,
299 Multibuffer *buffers)
301 XExtDisplayInfo *info = find_display (dpy);
302 xMbufCreateImageBuffersReply rep;
303 register xMbufCreateImageBuffersReq *req;
306 MbufCheckExtension (dpy, info, 0);
310 XAllocIDs(dpy, buffers, count);
311 MbufGetReq (MbufCreateImageBuffers, req, info);
313 req->updateAction = update_action;
314 req->updateHint = update_hint;
315 req->length += count;
317 PackData32 (dpy, buffers, count);
318 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
323 result = rep.numberBuffer;
332 * XmbufDestroyBuffers -
333 * Destroys the buffers associated with the given window.
335 void XmbufDestroyBuffers (Display *dpy, Window window)
337 XExtDisplayInfo *info = find_display (dpy);
338 register xMbufDestroyImageBuffersReq *req;
340 MbufSimpleCheckExtension (dpy, info);
343 MbufGetReq (MbufDestroyImageBuffers, req, info);
344 req->window = window;
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.
357 void XmbufDisplayBuffers (
360 Multibuffer *buffers,
361 int min_delay, int max_delay)
363 XExtDisplayInfo *info = find_display (dpy);
364 register xMbufDisplayImageBuffersReq *req;
366 MbufSimpleCheckExtension (dpy, info);
369 MbufGetReq (MbufDisplayImageBuffers, req, info);
370 req->minDelay = min_delay;
371 req->maxDelay = max_delay;
372 req->length += count;
374 PackData32 (dpy, buffers, count);
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
386 Status XmbufGetWindowAttributes (
389 XmbufWindowAttributes *attr)
391 XExtDisplayInfo *info = find_display (dpy);
392 register xMbufGetMBufferAttributesReq *req;
393 xMbufGetMBufferAttributesReply rep;
395 MbufCheckExtension (dpy, info, 0);
398 MbufGetReq (MbufGetMBufferAttributes, req, info);
400 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
405 attr->buffers = (Multibuffer *) NULL;
406 if ((attr->nbuffers = rep.length)) {
407 int nbytes = rep.length * sizeof(Multibuffer);
408 attr->buffers = (Multibuffer *) Xmalloc((unsigned) nbytes);
409 nbytes = rep.length << 2;
410 if (! attr->buffers) {
411 _XEatData(dpy, (unsigned long) nbytes);
416 _XRead32 (dpy, (long *) attr->buffers, nbytes);
418 attr->displayed_index = rep.displayedBuffer;
419 attr->update_action = rep.updateAction;
420 attr->update_hint = rep.updateHint;
421 attr->window_mode = rep.windowMode;
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.
434 void XmbufChangeWindowAttributes (
437 unsigned long valuemask,
438 XmbufSetWindowAttributes *attr)
440 XExtDisplayInfo *info = find_display (dpy);
441 register xMbufSetMBufferAttributesReq *req;
443 MbufSimpleCheckExtension (dpy, info);
446 MbufGetReq (MbufSetMBufferAttributes, req, info);
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;
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);
465 * XmbufGetBufferAttributes -
466 * Gets the attributes for the indicated buffer. Returns non-zero on
467 * success and zero if an error occurs.
469 Status XmbufGetBufferAttributes (
472 XmbufBufferAttributes *attr)
474 XExtDisplayInfo *info = find_display (dpy);
475 register xMbufGetBufferAttributesReq *req;
476 xMbufGetBufferAttributesReply rep;
478 MbufCheckExtension (dpy, info, 0);
481 MbufGetReq (MbufGetBufferAttributes, req, info);
483 if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
488 attr->window = rep.window;
489 attr->event_mask = rep.eventMask;
490 attr->buffer_index = rep.bufferIndex;
491 attr->side = rep.side;
500 * XmbufChangeBufferAttributes -
501 * Sets the attributes for the indicated buffer. This is currently
502 * limited to the event_mask.
504 void XmbufChangeBufferAttributes (
507 unsigned long valuemask,
508 XmbufSetBufferAttributes *attr)
510 XExtDisplayInfo *info = find_display (dpy);
511 register xMbufSetBufferAttributesReq *req;
513 MbufSimpleCheckExtension (dpy, info);
516 MbufGetReq (MbufSetBufferAttributes, req, info);
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;
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);
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 encounted, non-zero will be returned.
548 Status XmbufGetScreenInfo (
552 XmbufBufferInfo **mono_info_return,
554 XmbufBufferInfo **stereo_info_return)
556 XExtDisplayInfo *info = find_display (dpy);
557 register xMbufGetBufferInfoReq *req;
558 xMbufGetBufferInfoReply rep;
560 XmbufBufferInfo *minfo, *sinfo;
562 MbufCheckExtension (dpy, info, 0);
565 MbufGetReq (MbufGetBufferInfo, req, info);
567 if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
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);
577 /* check for bad reads indicating we need to return an error */
578 if ((nmono > 0 && !minfo) || (nstereo > 0 && !sinfo)) {
579 if (minfo) Xfree ((char *) minfo);
580 if (sinfo) Xfree ((char *) sinfo);
586 *nmono_return = nmono;
587 *mono_info_return = minfo;
588 *nstereo_return = nstereo;
589 *stereo_info_return = sinfo;
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
603 Window XmbufCreateStereoWindow (
607 unsigned int width, unsigned int height, unsigned int border_width,
611 unsigned long valuemask,
612 XSetWindowAttributes *attr,
613 Multibuffer *leftp, Multibuffer *rightp)
615 XExtDisplayInfo *info = find_display (dpy);
617 register xMbufCreateStereoWindowReq *req;
619 MbufCheckExtension (dpy, info, None);
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);
630 req->height = height;
631 req->borderWidth = border_width;
634 if (visual == (Visual *)CopyFromParent)
635 req->visual = CopyFromParent;
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;
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);
680 nvalues <<= 2; /* watch out for macros... */
681 Data32 (dpy, (long *) values, (long)nvalues);
688 void XmbufClearBufferArea (
692 unsigned int width, unsigned int height,
695 XExtDisplayInfo *info = find_display (dpy);
696 register xMbufClearImageBufferAreaReq *req;
698 MbufSimpleCheckExtension (dpy, info);
701 MbufGetReq (MbufClearImageBufferArea, req, info);
702 req->buffer = buffer;
706 req->height = height;
707 req->exposures = exposures;