322 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
| 
 | |
| Copyright 1993, 1998  The Open Group
 | |
| 
 | |
| Permission to use, copy, modify, distribute, and sell this software and its
 | |
| documentation for any purpose is hereby granted without fee, provided that
 | |
| the above copyright notice appear in all copies and that both that
 | |
| copyright notice and this permission notice appear in supporting
 | |
| documentation.
 | |
| 
 | |
| The above copyright notice and this permission notice shall be included
 | |
| in all copies or substantial portions of the Software.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 | |
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | |
| IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | |
| OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | |
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | |
| OTHER DEALINGS IN THE SOFTWARE.
 | |
| 
 | |
| Except as contained in this notice, the name of The Open Group shall
 | |
| not be used in advertising or otherwise to promote the sale, use or
 | |
| other dealings in this Software without prior written authorization
 | |
| from The Open Group.
 | |
| 
 | |
| */
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stddef.h>
 | |
| #include "windowstr.h"
 | |
| #include "resource.h"
 | |
| #include "privates.h"
 | |
| #include "gcstruct.h"
 | |
| #include "cursorstr.h"
 | |
| #include "colormapst.h"
 | |
| #include "inputstr.h"
 | |
| 
 | |
| struct _Private {
 | |
|     int state;
 | |
|     pointer value;
 | |
| };
 | |
| 
 | |
| typedef struct _PrivateDesc {
 | |
|     DevPrivateKey key;
 | |
|     unsigned size;
 | |
|     CallbackListPtr initfuncs;
 | |
|     CallbackListPtr deletefuncs;
 | |
| } PrivateDescRec;
 | |
| 
 | |
| #define PRIV_MAX 256
 | |
| #define PRIV_STEP 16
 | |
| 
 | |
| /* list of all allocated privates */
 | |
| static PrivateDescRec items[PRIV_MAX];
 | |
| static int nextPriv;
 | |
| 
 | |
| static PrivateDescRec *
 | |
| findItem(const DevPrivateKey key)
 | |
| {
 | |
|     if (!*key) {
 | |
| 	if (nextPriv >= PRIV_MAX)
 | |
| 	    return NULL;
 | |
| 
 | |
| 	items[nextPriv].key = key;
 | |
| 	*key = nextPriv;
 | |
| 	nextPriv++;
 | |
|     }
 | |
| 
 | |
|     return items + *key;
 | |
| }
 | |
| 
 | |
| static _X_INLINE int
 | |
| privateExists(PrivateRec **privates, const DevPrivateKey key)
 | |
| {
 | |
|     return *key && *privates &&
 | |
| 	(*privates)[0].state > *key &&
 | |
| 	(*privates)[*key].state;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Request pre-allocated space.
 | |
|  */
 | |
| int
 | |
| dixRequestPrivate(const DevPrivateKey key, unsigned size)
 | |
| {
 | |
|     PrivateDescRec *item = findItem(key);
 | |
|     if (!item)
 | |
| 	return FALSE;
 | |
|     if (size > item->size)
 | |
| 	item->size = size;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Allocate a private and attach it to an existing object.
 | |
|  */
 | |
| pointer *
 | |
| dixAllocatePrivate(PrivateRec **privates, const DevPrivateKey key)
 | |
| {
 | |
|     PrivateDescRec *item = findItem(key);
 | |
|     PrivateCallbackRec calldata;
 | |
|     PrivateRec *ptr;
 | |
|     pointer value;
 | |
|     int oldsize, newsize;
 | |
| 
 | |
|     newsize = (*key / PRIV_STEP + 1) * PRIV_STEP;
 | |
| 
 | |
|     /* resize or init privates array */
 | |
|     if (!item)
 | |
| 	return NULL;
 | |
| 
 | |
|     /* initialize privates array if necessary */
 | |
|     if (!*privates) {
 | |
| 	ptr = xcalloc(newsize, sizeof(*ptr));
 | |
| 	if (!ptr)
 | |
| 	    return NULL;
 | |
| 	*privates = ptr;
 | |
| 	(*privates)[0].state = newsize;
 | |
|     }
 | |
| 
 | |
|     oldsize = (*privates)[0].state;
 | |
| 
 | |
|     /* resize privates array if necessary */
 | |
|     if (*key >= oldsize) {
 | |
| 	ptr = xrealloc(*privates, newsize * sizeof(*ptr));
 | |
| 	if (!ptr)
 | |
| 	    return NULL;
 | |
| 	memset(ptr + oldsize, 0, (newsize - oldsize) * sizeof(*ptr));
 | |
| 	*privates = ptr;
 | |
| 	(*privates)[0].state = newsize;
 | |
|     }
 | |
| 
 | |
|     /* initialize slot */
 | |
|     ptr = *privates + *key;
 | |
|     ptr->state = 1;
 | |
|     if (item->size) {
 | |
| 	value = xcalloc(item->size, 1);
 | |
| 	if (!value)
 | |
| 	    return NULL;
 | |
| 	ptr->value = value;
 | |
|     }
 | |
| 
 | |
|     calldata.key = key;
 | |
|     calldata.value = &ptr->value;
 | |
|     CallCallbacks(&item->initfuncs, &calldata);
 | |
| 
 | |
|     return &ptr->value;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Look up a private pointer.
 | |
|  */
 | |
| pointer
 | |
| dixLookupPrivate(PrivateRec **privates, const DevPrivateKey key)
 | |
| {
 | |
|     pointer *ptr;
 | |
| 
 | |
|     if (privateExists(privates, key))
 | |
| 	return (*privates)[*key].value;
 | |
| 
 | |
|     ptr = dixAllocatePrivate(privates, key);
 | |
|     return ptr ? *ptr : NULL;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Look up the address of a private pointer.
 | |
|  */
 | |
| pointer *
 | |
| dixLookupPrivateAddr(PrivateRec **privates, const DevPrivateKey key)
 | |
| {
 | |
|     if (privateExists(privates, key))
 | |
| 	return &(*privates)[*key].value;
 | |
| 
 | |
|     return dixAllocatePrivate(privates, key);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Set a private pointer.
 | |
|  */
 | |
| int
 | |
| dixSetPrivate(PrivateRec **privates, const DevPrivateKey key, pointer val)
 | |
| {
 | |
|  top:
 | |
|     if (privateExists(privates, key)) {
 | |
| 	(*privates)[*key].value = val;
 | |
| 	return TRUE;
 | |
|     }
 | |
| 
 | |
|     if (!dixAllocatePrivate(privates, key))
 | |
| 	return FALSE;
 | |
|     goto top;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Called to free privates at object deletion time.
 | |
|  */
 | |
| void
 | |
| dixFreePrivates(PrivateRec *privates)
 | |
| {
 | |
|     int i;
 | |
|     PrivateCallbackRec calldata;
 | |
| 
 | |
|     if (privates)
 | |
| 	for (i = 1; i < privates->state; i++)
 | |
| 	    if (privates[i].state) {
 | |
| 		/* call the delete callbacks */
 | |
| 		calldata.key = items[i].key;
 | |
| 		calldata.value = &privates[i].value;
 | |
| 		CallCallbacks(&items[i].deletefuncs, &calldata);
 | |
| 
 | |
| 		/* free pre-allocated memory */
 | |
| 		if (items[i].size)
 | |
| 		    xfree(privates[i].value);
 | |
| 	    }
 | |
| 
 | |
|     xfree(privates);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Callback registration
 | |
|  */
 | |
| int
 | |
| dixRegisterPrivateInitFunc(const DevPrivateKey key,
 | |
| 			   CallbackProcPtr callback, pointer data)
 | |
| {
 | |
|     PrivateDescRec *item = findItem(key);
 | |
|     if (!item)
 | |
| 	return FALSE;
 | |
| 
 | |
|     return AddCallback(&item->initfuncs, callback, data);
 | |
| }
 | |
| 
 | |
| int
 | |
| dixRegisterPrivateDeleteFunc(const DevPrivateKey key,
 | |
| 			     CallbackProcPtr callback, pointer data)
 | |
| {
 | |
|     PrivateDescRec *item = findItem(key);
 | |
|     if (!item)
 | |
| 	return FALSE;
 | |
| 
 | |
|     return AddCallback(&item->deletefuncs, callback, data);
 | |
| }
 | |
| 
 | |
| /* Table of devPrivates offsets */
 | |
| static const int offsetDefaults[] = {
 | |
|     -1,					/* RT_NONE */
 | |
|     offsetof(WindowRec, devPrivates),	/* RT_WINDOW */
 | |
|     offsetof(PixmapRec, devPrivates),	/* RT_PIXMAP */
 | |
|     offsetof(GC, devPrivates),		/* RT_GC */
 | |
|     -1,		    			/* RT_FONT */
 | |
|     offsetof(CursorRec, devPrivates),	/* RT_CURSOR */
 | |
|     offsetof(ColormapRec, devPrivates),	/* RT_COLORMAP */
 | |
|     -1,			  		/* RT_CMAPENTRY */
 | |
|     -1,					/* RT_OTHERCLIENT */
 | |
|     -1					/* RT_PASSIVEGRAB */
 | |
| };
 | |
|     
 | |
| static int *offsets = NULL;
 | |
| static int offsetsSize = 0;
 | |
| 
 | |
| /*
 | |
|  * Specify where the devPrivates field is located in a structure type
 | |
|  */
 | |
| int
 | |
| dixRegisterPrivateOffset(RESTYPE type, int offset)
 | |
| {
 | |
|     type = type & TypeMask;
 | |
| 
 | |
|     /* resize offsets table if necessary */
 | |
|     while (type >= offsetsSize) {
 | |
| 	unsigned i = offsetsSize * 2 * sizeof(int);
 | |
| 	offsets = (int *)xrealloc(offsets, i);
 | |
| 	if (!offsets) {
 | |
| 	    offsetsSize = 0;
 | |
| 	    return FALSE;
 | |
| 	}
 | |
| 	for (i=offsetsSize; i < 2*offsetsSize; i++)
 | |
| 	    offsets[i] = -1;
 | |
| 	offsetsSize *= 2;
 | |
|     }
 | |
| 
 | |
|     offsets[type] = offset;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| int
 | |
| dixLookupPrivateOffset(RESTYPE type)
 | |
| {
 | |
|     type = type & TypeMask;
 | |
|     assert(type < offsetsSize);
 | |
|     return offsets[type];
 | |
| }
 | |
| 
 | |
| int
 | |
| dixResetPrivates(void)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     /* reset private descriptors */
 | |
|     for (i = 1; i < nextPriv; i++) {
 | |
| 	*items[i].key = 0;
 | |
| 	DeleteCallbackList(&items[i].initfuncs);
 | |
| 	DeleteCallbackList(&items[i].deletefuncs);
 | |
|     }
 | |
|     nextPriv = 1;
 | |
| 
 | |
|     /* reset offsets */
 | |
|     if (offsets)
 | |
| 	xfree(offsets);
 | |
|     offsetsSize = sizeof(offsetDefaults);
 | |
|     offsets = xalloc(offsetsSize);
 | |
|     offsetsSize /= sizeof(int);
 | |
|     if (!offsets)
 | |
| 	return FALSE;
 | |
|     memcpy(offsets, offsetDefaults, sizeof(offsetDefaults));
 | |
|     return TRUE;
 | |
| }
 |