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