Xdbe.c revision 0760f5d2
1/******************************************************************************
2 *
3 * Copyright (c) 1994, 1995  Hewlett-Packard Company
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL HEWLETT-PACKARD COMPANY BE LIABLE FOR ANY CLAIM,
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 *
24 * Except as contained in this notice, the name of the Hewlett-Packard
25 * Company shall not be used in advertising or otherwise to promote the
26 * sale, use or other dealings in this Software without prior written
27 * authorization from the Hewlett-Packard Company.
28 *
29 *     Xlib DBE code
30 *
31 *****************************************************************************/
32
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36#include <stdio.h>
37#include <X11/Xlibint.h>
38#include <X11/extensions/Xext.h>
39#include <X11/extensions/extutil.h>
40#include <X11/extensions/Xdbe.h>
41#include <X11/extensions/dbeproto.h>
42#include <limits.h>
43#include "reallocarray.h"
44
45static XExtensionInfo _dbe_info_data;
46static XExtensionInfo *dbe_info = &_dbe_info_data;
47static const char *dbe_extension_name = DBE_PROTOCOL_NAME;
48
49#define DbeCheckExtension(dpy,i,val) \
50  XextCheckExtension (dpy, i, dbe_extension_name, val)
51#define DbeSimpleCheckExtension(dpy,i) \
52  XextSimpleCheckExtension (dpy, i, dbe_extension_name)
53
54#define DbeGetReq(name,req,info) GetReq (name, req); \
55        req->reqType = info->codes->major_opcode; \
56        req->dbeReqType = X_##name;
57
58
59/*****************************************************************************
60 *                                                                           *
61 *			   private utility routines                          *
62 *                                                                           *
63 *****************************************************************************/
64
65/*
66 * find_display - locate the display info block
67 */
68static int close_display(Display *dpy, XExtCodes *codes);
69static char *error_string(Display *dpy, int code, XExtCodes *codes,
70			  char *buf, int n);
71static XExtensionHooks dbe_extension_hooks = {
72    NULL,                               /* create_gc */
73    NULL,                               /* copy_gc */
74    NULL,                               /* flush_gc */
75    NULL,                               /* free_gc */
76    NULL,                               /* create_font */
77    NULL,                               /* free_font */
78    close_display,                      /* close_display */
79    NULL,                               /* wire_to_event */
80    NULL,                               /* event_to_wire */
81    NULL,                               /* error */
82    error_string,                       /* error_string */
83};
84
85static const char *dbe_error_list[] = {
86    "BadBuffer",			/* DbeBadBuffer */
87};
88
89static XEXT_GENERATE_FIND_DISPLAY (find_display, dbe_info,
90				   dbe_extension_name,
91				   &dbe_extension_hooks,
92				   DbeNumberEvents, NULL)
93
94static XEXT_GENERATE_CLOSE_DISPLAY (close_display, dbe_info)
95
96static XEXT_GENERATE_ERROR_STRING (error_string, dbe_extension_name,
97				   DbeNumberErrors,
98				   dbe_error_list)
99
100
101/*****************************************************************************
102 *                                                                           *
103 *		       Double-Buffering public interfaces                    *
104 *                                                                           *
105 *****************************************************************************/
106
107/*
108 * XdbeQueryExtension -
109 *	Sets major_version_return and minor_verion_return to the major and
110 *	minor DBE protocol version supported by the server.  If the DBE
111 *	library is compatible with the version returned by the server, this
112 *	function returns non-zero.  If dpy does not support the DBE
113 *	extension, or if there was an error during communication with the
114 *	server, or if the server and library protocol versions are
115 *	incompatible, this functions returns zero.  No other Xdbe functions
116 *	may be called before this function.   If a client violates this rule,
117 *	the effects of all subsequent Xdbe calls are undefined.
118 */
119Status XdbeQueryExtension (
120    Display *dpy,
121    int *major_version_return,
122    int *minor_version_return)
123{
124    XExtDisplayInfo *info = find_display (dpy);
125    xDbeGetVersionReply rep;
126    register xDbeGetVersionReq *req;
127
128    if (!XextHasExtension (info))
129        return (Status)0; /* failure */
130
131    LockDisplay (dpy);
132    DbeGetReq (DbeGetVersion, req, info);
133    req->majorVersion = DBE_MAJOR_VERSION;
134    req->minorVersion = DBE_MINOR_VERSION;
135
136    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
137	UnlockDisplay (dpy);
138	SyncHandle ();
139	return (Status)0; /* failure */
140    }
141    *major_version_return = rep.majorVersion;
142    *minor_version_return = rep.minorVersion;
143    UnlockDisplay (dpy);
144
145    SyncHandle ();
146
147    if (*major_version_return != DBE_MAJOR_VERSION)
148        return (Status)0; /* failure */
149    else
150        return (Status)1; /* success */
151}
152
153
154/*
155 * XdbeAllocateBackBuffer -
156 *	This function returns a drawable ID used to refer to the back buffer
157 *	of the specified window.  The swap_action is a hint to indicate the
158 *	swap action that will likely be used in subsequent calls to
159 *	XdbeSwapBuffers.  The actual swap action used in calls to
160 *	XdbeSwapBuffers does not have to be the same as the swap_action
161 *	passed to this function, though clients are encouraged to provide
162 *	accurate information whenever possible.
163 */
164
165XdbeBackBuffer XdbeAllocateBackBufferName(
166    Display *dpy,
167    Window window,
168    XdbeSwapAction swap_action)
169{
170    XExtDisplayInfo *info = find_display (dpy);
171    register xDbeAllocateBackBufferNameReq *req;
172    XdbeBackBuffer buffer;
173
174    /* make sure extension is available; if not, return the
175     * third parameter (0).
176     */
177    DbeCheckExtension (dpy, info, (XdbeBackBuffer)0);
178
179    LockDisplay(dpy);
180    DbeGetReq(DbeAllocateBackBufferName, req, info);
181    req->window = window;
182    req->swapAction = (unsigned char)swap_action;
183    req->buffer = buffer = XAllocID (dpy);
184
185    UnlockDisplay (dpy);
186    SyncHandle ();
187    return buffer;
188
189} /* XdbeAllocateBackBufferName() */
190
191/*
192 * XdbeDeallocateBackBufferName -
193 *	This function frees a drawable ID, buffer, that was obtained via
194 *	XdbeAllocateBackBufferName.  The buffer must refer to the back buffer
195 *	of the specified window, or a protocol error results.
196 */
197Status XdbeDeallocateBackBufferName (
198    Display *dpy,
199    XdbeBackBuffer buffer)
200{
201    XExtDisplayInfo *info = find_display (dpy);
202    register xDbeDeallocateBackBufferNameReq *req;
203
204    DbeCheckExtension (dpy, info, (Status)0 /* failure */);
205
206    LockDisplay (dpy);
207    DbeGetReq (DbeDeallocateBackBufferName, req, info);
208    req->buffer = buffer;
209    UnlockDisplay (dpy);
210    SyncHandle ();
211
212    return (Status)1; /* success */
213}
214
215
216/*
217 * XdbeSwapBuffers -
218 *	This function swaps the front and back buffers for a list of windows.
219 *	The argument num_windows specifies how many windows are to have their
220 *	buffers swapped; it is the number of elements in the swap_info array.
221 *	The argument swap_info specifies the information needed per window
222 *	to do the swap.
223 */
224Status XdbeSwapBuffers (
225    Display *dpy,
226    XdbeSwapInfo *swap_info,
227    int num_windows)
228{
229    XExtDisplayInfo *info = find_display (dpy);
230    register xDbeSwapBuffersReq *req;
231    int i;
232
233    DbeCheckExtension (dpy, info, (Status)0 /* failure */);
234
235    LockDisplay (dpy);
236    DbeGetReq (DbeSwapBuffers, req, info);
237    req->length += 2*num_windows;
238    req->n = num_windows;
239
240    /* We need to handle 64-bit machines, where we can not use PackData32
241     * directly because info would be lost in translating from 32- to 64-bit.
242     * Instead we send data via a loop that accounts for the translation.
243     */
244    for (i = 0; i < num_windows; i++)
245    {
246        char tmp[4];
247        Data32 (dpy, (long *)&swap_info[i].swap_window, 4);
248        tmp[0] = swap_info[i].swap_action;
249        Data (dpy, (char *)tmp, 4);
250    }
251
252    UnlockDisplay (dpy);
253    SyncHandle ();
254
255
256    return (Status)1; /* success */
257
258} /* XdbeSwapBuffers() */
259
260
261/*
262 * XdbeBeginIdiom -
263 *	This function marks the beginning of an idiom sequence.
264 */
265Status XdbeBeginIdiom (Display *dpy)
266{
267    XExtDisplayInfo *info = find_display(dpy);
268    register xDbeBeginIdiomReq *req;
269
270    DbeCheckExtension (dpy, info, (Status)0 /* failure */);
271
272    LockDisplay (dpy);
273    DbeGetReq (DbeBeginIdiom, req, info);
274    UnlockDisplay (dpy);
275    SyncHandle ();
276
277    return (Status)1; /* success */
278}
279
280
281/*
282 * XdbeEndIdiom -
283 *	This function marks the end of an idiom sequence.
284 */
285Status XdbeEndIdiom (Display *dpy)
286{
287    XExtDisplayInfo *info = find_display(dpy);
288    register xDbeEndIdiomReq *req;
289
290    DbeCheckExtension (dpy, info, (Status)0 /* failure */);
291
292    LockDisplay (dpy);
293    DbeGetReq (DbeEndIdiom, req, info);
294    UnlockDisplay (dpy);
295    SyncHandle ();
296
297    return (Status)1; /* success */
298}
299
300
301/*
302 * XdbeGetVisualInfo -
303 *	This function returns information about which visuals support
304 *	double buffering.  The argument num_screens specifies how many
305 *	elements there are in the screen_specifiers list.  Each drawable
306 *	in screen_specifiers designates a screen for which the supported
307 *	visuals are being requested.  If num_screens is zero, information
308 *	for all screens is requested.  In this case, upon return from this
309 *	function, num_screens will be set to the number of screens that were
310 *	found.  If an error occurs, this function returns NULL, else it returns
311 *	a pointer to a list of XdbeScreenVisualInfo structures of length
312 *	num_screens.  The nth element in the returned list corresponds to the
313 *	nth drawable in the screen_specifiers list, unless num_screens was
314 *	passed in with the value zero, in which case the nth element in the
315 *	returned list corresponds to the nth screen of the server, starting
316 *	with screen zero.
317 */
318XdbeScreenVisualInfo *XdbeGetVisualInfo (
319    Display        *dpy,
320    Drawable       *screen_specifiers,
321    int            *num_screens)  /* SEND and RETURN */
322{
323    XExtDisplayInfo *info = find_display(dpy);
324    register xDbeGetVisualInfoReq *req;
325    xDbeGetVisualInfoReply rep;
326    XdbeScreenVisualInfo *scrVisInfo;
327    int i;
328
329    DbeCheckExtension (dpy, info, (XdbeScreenVisualInfo *)NULL);
330
331    LockDisplay (dpy);
332
333    DbeGetReq(DbeGetVisualInfo, req, info);
334    req->length = 2 + *num_screens;
335    req->n      = *num_screens;
336    Data32 (dpy, screen_specifiers, (*num_screens * sizeof (CARD32)));
337
338    if (!_XReply (dpy, (xReply *) &rep, 0, xFalse)) {
339        UnlockDisplay (dpy);
340        SyncHandle ();
341        return NULL;
342    }
343
344    /* return the number of screens actually found if we
345     * requested information about all screens (*num_screens == 0)
346     */
347    if (*num_screens == 0)
348       *num_screens = rep.m;
349
350    /* allocate list of visual information to be returned */
351    if ((*num_screens > 0) && (*num_screens < 65536))
352        scrVisInfo = Xcalloc(*num_screens, sizeof(XdbeScreenVisualInfo));
353    else
354        scrVisInfo = NULL;
355    if (scrVisInfo == NULL) {
356        _XEatDataWords(dpy, rep.length);
357        UnlockDisplay (dpy);
358        SyncHandle ();
359        return NULL;
360    }
361
362    for (i = 0; i < *num_screens; i++)
363    {
364        int j;
365        unsigned long c;
366
367        _XRead32 (dpy, (long *) &c, sizeof(CARD32));
368
369        if (c < 65536) {
370            scrVisInfo[i].count = c;
371            scrVisInfo[i].visinfo = Xmallocarray(c, sizeof(XdbeVisualInfo));
372        } else
373            scrVisInfo[i].visinfo = NULL;
374
375        /* if we can not allocate the list of visual/depth info
376         * then free the lists that we already allocated as well
377         * as the visual info list itself
378         */
379        if (scrVisInfo[i].visinfo == NULL) {
380            for (j = 0; j < i; j++) {
381                Xfree (scrVisInfo[j].visinfo);
382            }
383            Xfree (scrVisInfo);
384            _XEatDataWords(dpy, rep.length);
385            UnlockDisplay (dpy);
386            SyncHandle ();
387            return NULL;
388        }
389
390        /* Read the visual info item into the wire structure.  Then copy each
391         * element into the library structure.  The element sizes and/or
392         * padding may be different in the two structures.
393         */
394        for (j = 0; j < scrVisInfo[i].count; j++) {
395            xDbeVisInfo xvi;
396
397            _XRead (dpy, (char *)&xvi, sizeof(xDbeVisInfo));
398            scrVisInfo[i].visinfo[j].visual    = xvi.visualID;
399            scrVisInfo[i].visinfo[j].depth     = xvi.depth;
400            scrVisInfo[i].visinfo[j].perflevel = xvi.perfLevel;
401        }
402
403    }
404
405    UnlockDisplay (dpy);
406    SyncHandle ();
407    return scrVisInfo;
408
409} /* XdbeGetVisualInfo() */
410
411
412/*
413 * XdbeFreeVisualInfo -
414 *	This function frees the list of XdbeScreenVisualInfo returned by the
415 *	function XdbeGetVisualInfo.
416 */
417void XdbeFreeVisualInfo(XdbeScreenVisualInfo *visual_info)
418{
419    if (visual_info == NULL) {
420        return;
421    }
422
423    if (visual_info->visinfo) {
424        XFree(visual_info->visinfo);
425    }
426
427    XFree(visual_info);
428}
429
430
431/*
432 * XdbeGetBackBufferAttributes -
433 *	This function returns the attributes associated with the specified
434 *	buffer.
435 */
436XdbeBackBufferAttributes *XdbeGetBackBufferAttributes(
437    Display *dpy,
438    XdbeBackBuffer buffer)
439{
440    XExtDisplayInfo *info = find_display(dpy);
441    register xDbeGetBackBufferAttributesReq *req;
442    xDbeGetBackBufferAttributesReply rep;
443    XdbeBackBufferAttributes *attr;
444
445    DbeCheckExtension(dpy, info, (XdbeBackBufferAttributes *)NULL);
446
447    if (!(attr = Xmalloc(sizeof(XdbeBackBufferAttributes)))) {
448        return NULL;
449    }
450
451    LockDisplay(dpy);
452    DbeGetReq(DbeGetBackBufferAttributes, req, info);
453    req->buffer = buffer;
454
455    if (!_XReply (dpy, (xReply *) &rep, 0, xTrue)) {
456        UnlockDisplay (dpy);
457        SyncHandle ();
458	Xfree(attr);
459        return NULL;
460    }
461    attr->window = rep.attributes;
462
463    UnlockDisplay (dpy);
464    SyncHandle ();
465
466    return attr;
467}
468
469