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 * Author:  Jim Fulton, MIT X Consortium
26 *
27 *
28 * 		       Xlib Extension-Writing Utilities
29 *
30 * This package contains utilities for writing the client API for various
31 * protocol extensions.  THESE INTERFACES ARE NOT PART OF THE X STANDARD AND
32 * ARE SUBJECT TO CHANGE!
33 *
34 *  Routines include:
35 *
36 *         XextCreateExtension		called once per extension
37 *         XextDestroyExtension		if no longer using extension
38 *         XextAddDisplay		add another display
39 *         XextRemoveDisplay		remove a display
40 *         XextFindDisplay		is a display open
41 *
42 * In addition, the following Xlib-style interfaces are provided:
43 *
44 *         XSetExtensionErrorHandler	establish an extension error handler
45 *         XMissingExtension		raise an error about missing ext
46 */
47
48#ifdef HAVE_CONFIG_H
49#include <config.h>
50#endif
51#include <stdio.h>
52#include <X11/Xlibint.h>
53#include <X11/extensions/Xext.h>
54#include <X11/extensions/extutil.h>
55#include <X11/extensions/ge.h>
56
57#include "extutilP.h"
58
59/*
60 * XextCreateExtension - return an extension descriptor containing context
61 * information for this extension.  This object is passed to all Xext
62 * routines.
63 */
64XExtensionInfo *XextCreateExtension (void)
65{
66    register XExtensionInfo *info = Xmalloc (sizeof (XExtensionInfo));
67
68    if (info) {
69	info->head = NULL;
70	info->cur = NULL;
71	info->ndisplays = 0;
72    }
73    return info;
74}
75
76
77/*
78 * XextDestroyExtension - free memory the given extension descriptor
79 */
80void XextDestroyExtension (XExtensionInfo *info)
81{
82    info->head = NULL;			/* to catch refs after this */
83    info->cur = NULL;
84    info->ndisplays = 0;
85    XFree (info);
86}
87
88
89
90/*
91 * XextAddDisplay - add a display to this extension
92 */
93XExtDisplayInfo *XextAddDisplay (
94    XExtensionInfo *extinfo,
95    Display *dpy,
96    _Xconst char *ext_name,
97    XExtensionHooks *hooks,
98    int nevents,
99    XPointer data)
100{
101    XExtDisplayInfo *dpyinfo;
102
103    dpyinfo = Xmalloc (sizeof (XExtDisplayInfo));
104    if (!dpyinfo) return NULL;
105    dpyinfo->display = dpy;
106    dpyinfo->data = data;
107    dpyinfo->codes = XInitExtension (dpy, ext_name);
108
109    /*
110     * if the server has the extension, then we can initialize the
111     * appropriate function vectors
112     */
113    if (dpyinfo->codes) {
114	int i, j;
115
116	for (i = 0, j = dpyinfo->codes->first_event; i < nevents; i++, j++) {
117	    XESetWireToEvent (dpy, j, hooks->wire_to_event);
118	    XESetEventToWire (dpy, j, hooks->event_to_wire);
119	}
120
121        /* register extension for XGE */
122        if (strcmp(ext_name, GE_NAME))
123            xgeExtRegister(dpy, dpyinfo->codes->major_opcode, hooks);
124
125	if (hooks->create_gc)
126	  XESetCreateGC (dpy, dpyinfo->codes->extension, hooks->create_gc);
127	if (hooks->copy_gc)
128	  XESetCopyGC (dpy, dpyinfo->codes->extension, hooks->copy_gc);
129	if (hooks->flush_gc)
130	  XESetFlushGC (dpy, dpyinfo->codes->extension, hooks->flush_gc);
131	if (hooks->free_gc)
132	  XESetFreeGC (dpy, dpyinfo->codes->extension, hooks->free_gc);
133	if (hooks->create_font)
134	  XESetCreateFont (dpy, dpyinfo->codes->extension, hooks->create_font);
135	if (hooks->free_font)
136	  XESetFreeFont (dpy, dpyinfo->codes->extension, hooks->free_font);
137	if (hooks->close_display)
138	  XESetCloseDisplay (dpy, dpyinfo->codes->extension,
139			     hooks->close_display);
140	if (hooks->error)
141	  XESetError (dpy, dpyinfo->codes->extension, hooks->error);
142	if (hooks->error_string)
143	  XESetErrorString (dpy, dpyinfo->codes->extension,
144			    hooks->error_string);
145    } else if (hooks->close_display) {
146	/* The server doesn't have this extension.
147	 * Use a private Xlib-internal extension to hang the close_display
148	 * hook on so that the "cache" (extinfo->cur) is properly cleaned.
149	 * (XBUG 7955)
150	 */
151	XExtCodes *codes = XAddExtension(dpy);
152	if (!codes) {
153	    XFree(dpyinfo);
154	    return NULL;
155	}
156	XESetCloseDisplay (dpy, codes->extension, hooks->close_display);
157    }
158
159    /*
160     * now, chain it onto the list
161     */
162    _XLockMutex(_Xglobal_lock);
163    dpyinfo->next = extinfo->head;
164    extinfo->head = dpyinfo;
165    extinfo->cur = dpyinfo;
166    extinfo->ndisplays++;
167    _XUnlockMutex(_Xglobal_lock);
168    return dpyinfo;
169}
170
171
172/*
173 * XextRemoveDisplay - remove the indicated display from the extension object
174 */
175int XextRemoveDisplay (XExtensionInfo *extinfo, Display *dpy)
176{
177    XExtDisplayInfo *dpyinfo, *prev;
178
179    /*
180     * locate this display and its back link so that it can be removed
181     */
182    _XLockMutex(_Xglobal_lock);
183    prev = NULL;
184    for (dpyinfo = extinfo->head; dpyinfo; dpyinfo = dpyinfo->next) {
185	if (dpyinfo->display == dpy) break;
186	prev = dpyinfo;
187    }
188    if (!dpyinfo) {
189	_XUnlockMutex(_Xglobal_lock);
190	return 0;		/* hmm, actually an error */
191    }
192
193    /*
194     * remove the display from the list; handles going to zero
195     */
196    if (prev)
197	prev->next = dpyinfo->next;
198    else
199	extinfo->head = dpyinfo->next;
200
201    extinfo->ndisplays--;
202    if (dpyinfo == extinfo->cur) extinfo->cur = NULL;  /* flush cache */
203    _XUnlockMutex(_Xglobal_lock);
204
205    Xfree (dpyinfo);
206    return 1;
207}
208
209
210/*
211 * XextFindDisplay - look for a display in this extension; keeps a cache
212 * of the most-recently used for efficiency.
213 */
214XExtDisplayInfo *XextFindDisplay (XExtensionInfo *extinfo, Display *dpy)
215{
216    register XExtDisplayInfo *dpyinfo;
217
218    /*
219     * see if this was the most recently accessed display
220     */
221    if ((dpyinfo = extinfo->cur)&& dpyinfo->display == dpy) return dpyinfo;
222
223
224    /*
225     * look for display in list
226     */
227    _XLockMutex(_Xglobal_lock);
228    for (dpyinfo = extinfo->head; dpyinfo; dpyinfo = dpyinfo->next) {
229	if (dpyinfo->display == dpy) {
230	    extinfo->cur = dpyinfo;	/* cache most recently used */
231	    _XUnlockMutex(_Xglobal_lock);
232	    return dpyinfo;
233	}
234    }
235    _XUnlockMutex(_Xglobal_lock);
236
237    return NULL;
238}
239
240
241
242static int _default_exterror (Display *dpy, _Xconst char *ext_name, _Xconst char *reason)
243{
244    fprintf (stderr, "Xlib:  extension \"%s\" %s on display \"%s\".\n",
245	     ext_name, reason, DisplayString(dpy));
246    return 0;
247}
248
249
250/*
251 * XSetExtensionErrorHandler - sets the handler that gets called when a
252 * requested extension is referenced.  This should eventually move into Xlib.
253 */
254
255extern XextErrorHandler _XExtensionErrorFunction;
256
257XextErrorHandler XSetExtensionErrorHandler (XextErrorHandler handler)
258{
259    XextErrorHandler oldhandler = _XExtensionErrorFunction;
260
261    _XExtensionErrorFunction = (handler ? handler :
262				_default_exterror);
263    return oldhandler;
264}
265
266
267/*
268 * XMissingExtension - call the extension error handler
269 */
270int XMissingExtension (Display *dpy, _Xconst char *ext_name)
271{
272    XextErrorHandler func = (_XExtensionErrorFunction ?
273			     _XExtensionErrorFunction : _default_exterror);
274
275    if (!ext_name) ext_name = X_EXTENSION_UNKNOWN;
276    return (*func) (dpy, ext_name, X_EXTENSION_MISSING);
277}
278