privates.c revision 4642e01f
1/*
2
3Copyright 1993, 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
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29#ifdef HAVE_DIX_CONFIG_H
30#include <dix-config.h>
31#endif
32
33#include <stddef.h>
34#include "windowstr.h"
35#include "resource.h"
36#include "privates.h"
37#include "gcstruct.h"
38#include "cursorstr.h"
39#include "colormapst.h"
40#include "inputstr.h"
41
42struct _Private {
43    int state;
44    pointer value;
45};
46
47typedef struct _PrivateDesc {
48    DevPrivateKey key;
49    unsigned size;
50    CallbackListPtr initfuncs;
51    CallbackListPtr deletefuncs;
52} PrivateDescRec;
53
54#define PRIV_MAX 256
55#define PRIV_STEP 16
56
57/* list of all allocated privates */
58static PrivateDescRec items[PRIV_MAX];
59static int nextPriv;
60
61static PrivateDescRec *
62findItem(const DevPrivateKey key)
63{
64    if (!*key) {
65	if (nextPriv >= PRIV_MAX)
66	    return NULL;
67
68	items[nextPriv].key = key;
69	*key = nextPriv;
70	nextPriv++;
71    }
72
73    return items + *key;
74}
75
76static _X_INLINE int
77privateExists(PrivateRec **privates, const DevPrivateKey key)
78{
79    return *key && *privates &&
80	(*privates)[0].state > *key &&
81	(*privates)[*key].state;
82}
83
84/*
85 * Request pre-allocated space.
86 */
87_X_EXPORT int
88dixRequestPrivate(const DevPrivateKey key, unsigned size)
89{
90    PrivateDescRec *item = findItem(key);
91    if (!item)
92	return FALSE;
93    if (size > item->size)
94	item->size = size;
95    return TRUE;
96}
97
98/*
99 * Allocate a private and attach it to an existing object.
100 */
101_X_EXPORT pointer *
102dixAllocatePrivate(PrivateRec **privates, const DevPrivateKey key)
103{
104    PrivateDescRec *item = findItem(key);
105    PrivateCallbackRec calldata;
106    PrivateRec *ptr;
107    pointer value;
108    int oldsize, newsize;
109
110    newsize = (*key / PRIV_STEP + 1) * PRIV_STEP;
111
112    /* resize or init privates array */
113    if (!item)
114	return NULL;
115
116    /* initialize privates array if necessary */
117    if (!*privates) {
118	ptr = xcalloc(newsize, sizeof(*ptr));
119	if (!ptr)
120	    return NULL;
121	*privates = ptr;
122	(*privates)[0].state = newsize;
123    }
124
125    oldsize = (*privates)[0].state;
126
127    /* resize privates array if necessary */
128    if (*key >= oldsize) {
129	ptr = xrealloc(*privates, newsize * sizeof(*ptr));
130	if (!ptr)
131	    return NULL;
132	memset(ptr + oldsize, 0, (newsize - oldsize) * sizeof(*ptr));
133	*privates = ptr;
134	(*privates)[0].state = newsize;
135    }
136
137    /* initialize slot */
138    ptr = *privates + *key;
139    ptr->state = 1;
140    if (item->size) {
141	value = xcalloc(item->size, 1);
142	if (!value)
143	    return NULL;
144	ptr->value = value;
145    }
146
147    calldata.key = key;
148    calldata.value = &ptr->value;
149    CallCallbacks(&item->initfuncs, &calldata);
150
151    return &ptr->value;
152}
153
154/*
155 * Look up a private pointer.
156 */
157_X_EXPORT pointer
158dixLookupPrivate(PrivateRec **privates, const DevPrivateKey key)
159{
160    pointer *ptr;
161
162    if (privateExists(privates, key))
163	return (*privates)[*key].value;
164
165    ptr = dixAllocatePrivate(privates, key);
166    return ptr ? *ptr : NULL;
167}
168
169/*
170 * Look up the address of a private pointer.
171 */
172_X_EXPORT pointer *
173dixLookupPrivateAddr(PrivateRec **privates, const DevPrivateKey key)
174{
175    if (privateExists(privates, key))
176	return &(*privates)[*key].value;
177
178    return dixAllocatePrivate(privates, key);
179}
180
181/*
182 * Set a private pointer.
183 */
184_X_EXPORT int
185dixSetPrivate(PrivateRec **privates, const DevPrivateKey key, pointer val)
186{
187 top:
188    if (privateExists(privates, key)) {
189	(*privates)[*key].value = val;
190	return TRUE;
191    }
192
193    if (!dixAllocatePrivate(privates, key))
194	return FALSE;
195    goto top;
196}
197
198/*
199 * Called to free privates at object deletion time.
200 */
201_X_EXPORT void
202dixFreePrivates(PrivateRec *privates)
203{
204    int i;
205    PrivateCallbackRec calldata;
206
207    if (privates)
208	for (i = 1; i < privates->state; i++)
209	    if (privates[i].state) {
210		/* call the delete callbacks */
211		calldata.key = items[i].key;
212		calldata.value = &privates[i].value;
213		CallCallbacks(&items[i].deletefuncs, &calldata);
214
215		/* free pre-allocated memory */
216		if (items[i].size)
217		    xfree(privates[i].value);
218	    }
219
220    xfree(privates);
221}
222
223/*
224 * Callback registration
225 */
226_X_EXPORT int
227dixRegisterPrivateInitFunc(const DevPrivateKey key,
228			   CallbackProcPtr callback, pointer data)
229{
230    PrivateDescRec *item = findItem(key);
231    if (!item)
232	return FALSE;
233
234    return AddCallback(&item->initfuncs, callback, data);
235}
236
237_X_EXPORT int
238dixRegisterPrivateDeleteFunc(const DevPrivateKey key,
239			     CallbackProcPtr callback, pointer data)
240{
241    PrivateDescRec *item = findItem(key);
242    if (!item)
243	return FALSE;
244
245    return AddCallback(&item->deletefuncs, callback, data);
246}
247
248/* Table of devPrivates offsets */
249static const int offsetDefaults[] = {
250    -1,					/* RT_NONE */
251    offsetof(WindowRec, devPrivates),	/* RT_WINDOW */
252    offsetof(PixmapRec, devPrivates),	/* RT_PIXMAP */
253    offsetof(GC, devPrivates),		/* RT_GC */
254    -1,		    			/* RT_FONT */
255    offsetof(CursorRec, devPrivates),	/* RT_CURSOR */
256    offsetof(ColormapRec, devPrivates),	/* RT_COLORMAP */
257    -1,			  		/* RT_CMAPENTRY */
258    -1,					/* RT_OTHERCLIENT */
259    -1					/* RT_PASSIVEGRAB */
260};
261
262static int *offsets = NULL;
263static int offsetsSize = 0;
264
265/*
266 * Specify where the devPrivates field is located in a structure type
267 */
268_X_EXPORT int
269dixRegisterPrivateOffset(RESTYPE type, int offset)
270{
271    type = type & TypeMask;
272
273    /* resize offsets table if necessary */
274    while (type >= offsetsSize) {
275	unsigned i = offsetsSize * 2 * sizeof(int);
276	offsets = (int *)xrealloc(offsets, i);
277	if (!offsets) {
278	    offsetsSize = 0;
279	    return FALSE;
280	}
281	for (i=offsetsSize; i < 2*offsetsSize; i++)
282	    offsets[i] = -1;
283	offsetsSize *= 2;
284    }
285
286    offsets[type] = offset;
287    return TRUE;
288}
289
290_X_EXPORT int
291dixLookupPrivateOffset(RESTYPE type)
292{
293    type = type & TypeMask;
294    assert(type < offsetsSize);
295    return offsets[type];
296}
297
298int
299dixResetPrivates(void)
300{
301    int i;
302
303    /* reset private descriptors */
304    for (i = 1; i < nextPriv; i++) {
305	*items[i].key = 0;
306	DeleteCallbackList(&items[i].initfuncs);
307	DeleteCallbackList(&items[i].deletefuncs);
308    }
309    nextPriv = 1;
310
311    /* reset offsets */
312    if (offsets)
313	xfree(offsets);
314    offsetsSize = sizeof(offsetDefaults);
315    offsets = (int *)xalloc(offsetsSize);
316    offsetsSize /= sizeof(int);
317    if (!offsets)
318	return FALSE;
319    memcpy(offsets, offsetDefaults, sizeof(offsetDefaults));
320    return TRUE;
321}
322