494 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			494 lines
		
	
	
		
			13 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.
 | |
| 
 | |
| */
 | |
| /*
 | |
|  * Copyright © 2010, Keith Packard
 | |
|  * Copyright © 2010, Jamey Sharp
 | |
|  *
 | |
|  * 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, and
 | |
|  * that the name of the copyright holders not be used in advertising or
 | |
|  * publicity pertaining to distribution of the software without specific,
 | |
|  * written prior permission.  The copyright holders make no representations
 | |
|  * about the suitability of this software for any purpose.  It is provided "as
 | |
|  * is" without express or implied warranty.
 | |
|  *
 | |
|  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 | |
|  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 | |
|  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 | |
|  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 | |
|  * OF THIS SOFTWARE.
 | |
|  */
 | |
| 
 | |
| #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"
 | |
| #include "scrnintstr.h"
 | |
| #include "extnsionst.h"
 | |
| 
 | |
| static struct {
 | |
|     DevPrivateKey	key;
 | |
|     unsigned		offset;
 | |
|     int			created;
 | |
|     int			allocated;
 | |
| } keys[PRIVATE_LAST];
 | |
| 
 | |
| static const Bool xselinux_private[PRIVATE_LAST] = {
 | |
|     [PRIVATE_CLIENT] = TRUE,
 | |
|     [PRIVATE_WINDOW] = TRUE,
 | |
|     [PRIVATE_PIXMAP] = TRUE,
 | |
|     [PRIVATE_GC] = TRUE,
 | |
|     [PRIVATE_CURSOR] = TRUE,
 | |
|     [PRIVATE_COLORMAP] = TRUE,
 | |
|     [PRIVATE_DEVICE] = TRUE,
 | |
|     [PRIVATE_EXTENSION] = TRUE,
 | |
|     [PRIVATE_SELECTION] = TRUE,
 | |
|     [PRIVATE_PROPERTY] = TRUE,
 | |
|     [PRIVATE_PICTURE] = TRUE,
 | |
|     [PRIVATE_GLYPHSET] = TRUE,
 | |
| };
 | |
| 
 | |
| typedef Bool (*FixupFunc)(PrivatePtr *privates, int offset, unsigned bytes);
 | |
| 
 | |
| static Bool
 | |
| dixReallocPrivates(PrivatePtr *privates, int old_offset, unsigned bytes)
 | |
| {
 | |
|     void	*new_privates;
 | |
| 
 | |
|     new_privates = realloc(*privates, old_offset + bytes);
 | |
|     if (!new_privates)
 | |
| 	return FALSE;
 | |
|     memset((char *) new_privates + old_offset, '\0', bytes);
 | |
|     *privates = new_privates;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| dixMovePrivates(PrivatePtr *privates, int new_offset, unsigned bytes)
 | |
| {
 | |
|     memmove((char *) *privates + bytes, *privates, new_offset - bytes);
 | |
|     memset(*privates, '\0', bytes);
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| fixupScreens(FixupFunc fixup, unsigned bytes)
 | |
| {
 | |
|     int s;
 | |
|     for (s = 0; s < screenInfo.numScreens; s++)
 | |
| 	if (!fixup(&screenInfo.screens[s]->devPrivates, keys[PRIVATE_SCREEN].offset, bytes))
 | |
| 	    return FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| fixupServerClient(FixupFunc fixup, unsigned bytes)
 | |
| {
 | |
|     if (serverClient)
 | |
| 	return fixup(&serverClient->devPrivates, keys[PRIVATE_CLIENT].offset, bytes);
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| fixupExtensions(FixupFunc fixup, unsigned bytes)
 | |
| {
 | |
|     unsigned char 	major;
 | |
|     ExtensionEntry	*extension;
 | |
|     for (major = EXTENSION_BASE; (extension = GetExtensionEntry(major)); major++)
 | |
| 	if (!fixup(&extension->devPrivates, keys[PRIVATE_EXTENSION].offset, bytes))
 | |
| 	    return FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool
 | |
| fixupDefaultColormaps(FixupFunc fixup, unsigned bytes)
 | |
| {
 | |
|     int s;
 | |
|     for (s = 0; s < screenInfo.numScreens; s++) {
 | |
| 	ColormapPtr cmap;
 | |
| 	dixLookupResourceByType((pointer *) &cmap, screenInfo.screens[s]->defColormap,
 | |
| 	                        RT_COLORMAP, serverClient, DixCreateAccess);
 | |
| 	if (cmap && !fixup(&cmap->devPrivates, keys[PRIVATE_COLORMAP].offset, bytes))
 | |
| 	    return FALSE;
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| static Bool (* const allocated_early[PRIVATE_LAST])(FixupFunc, unsigned) = {
 | |
|     [PRIVATE_SCREEN] = fixupScreens,
 | |
|     [PRIVATE_CLIENT] = fixupServerClient,
 | |
|     [PRIVATE_EXTENSION] = fixupExtensions,
 | |
|     [PRIVATE_COLORMAP] = fixupDefaultColormaps,
 | |
| };
 | |
| 
 | |
| /*
 | |
|  * Register a private key. This takes the type of object the key will
 | |
|  * be used with, which may be PRIVATE_ALL indicating that this key
 | |
|  * will be used with all of the private objects. If 'size' is
 | |
|  * non-zero, then the specified amount of space will be allocated in
 | |
|  * the private storage. Otherwise, space for a single pointer will
 | |
|  * be allocated which can be set with dixSetPrivate
 | |
|  */
 | |
| Bool
 | |
| dixRegisterPrivateKey(DevPrivateKey key, DevPrivateType type, unsigned size)
 | |
| {
 | |
|     DevPrivateType	t;
 | |
|     int			offset;
 | |
|     unsigned		bytes;
 | |
| 
 | |
|     if (key->initialized) {
 | |
| 	assert (size == key->size);
 | |
| 	return TRUE;
 | |
|     }
 | |
| 
 | |
|     /* Compute required space */
 | |
|     bytes = size;
 | |
|     if (size == 0)
 | |
| 	bytes = sizeof (void *);
 | |
| 
 | |
|     /* align to void * size */
 | |
|     bytes = (bytes + sizeof (void *) - 1) & ~(sizeof (void *) - 1);
 | |
| 
 | |
|     /* Update offsets for all affected keys */
 | |
|     if (type == PRIVATE_XSELINUX) {
 | |
| 	DevPrivateKey	k;
 | |
| 
 | |
| 	/* Resize if we can, or make sure nothing's allocated if we can't
 | |
| 	 */
 | |
| 	for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++)
 | |
| 	    if (xselinux_private[t]) {
 | |
| 		if (!allocated_early[t])
 | |
| 		    assert (!keys[t].created);
 | |
| 		else if (!allocated_early[t](dixReallocPrivates, bytes))
 | |
| 		    return FALSE;
 | |
| 	    }
 | |
| 
 | |
| 	/* Move all existing keys up in the privates space to make
 | |
| 	 * room for this new global key
 | |
| 	 */
 | |
| 	for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) {
 | |
| 	    if (xselinux_private[t]) {
 | |
| 		for (k = keys[t].key; k; k = k->next)
 | |
| 		    k->offset += bytes;
 | |
| 		keys[t].offset += bytes;
 | |
| 		if (allocated_early[t])
 | |
| 		    allocated_early[t](dixMovePrivates, bytes);
 | |
| 	    }
 | |
| 	}
 | |
| 
 | |
| 	offset = 0;
 | |
|     } else {
 | |
| 	/* Resize if we can, or make sure nothing's allocated if we can't */
 | |
| 	if (!allocated_early[type])
 | |
| 	    assert(!keys[type].created);
 | |
| 	else if (!allocated_early[type](dixReallocPrivates, bytes))
 | |
| 	    return FALSE;
 | |
| 	offset = keys[type].offset;
 | |
| 	keys[type].offset += bytes;
 | |
|     }
 | |
| 
 | |
|     /* Setup this key */
 | |
|     key->offset = offset;
 | |
|     key->size = size;
 | |
|     key->initialized = TRUE;
 | |
|     key->type = type;
 | |
|     key->allocated = FALSE;
 | |
|     key->next = keys[type].key;
 | |
|     keys[type].key = key;
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Allocate a new private key.
 | |
|  *
 | |
|  * This manages the storage of the key object itself, freeing it when the
 | |
|  * privates system is restarted at server reset time. All other keys
 | |
|  * are expected to be statically allocated as the privates must be
 | |
|  * reset after all objects have been freed
 | |
|  */
 | |
| DevPrivateKey
 | |
| dixCreatePrivateKey(DevPrivateType type, unsigned size)
 | |
| {
 | |
|     DevPrivateKey	key;
 | |
| 
 | |
|     key = calloc(sizeof (DevPrivateKeyRec), 1);
 | |
|     if (!key)
 | |
| 	return NULL;
 | |
|     if (!dixRegisterPrivateKey(key, type, size)) {
 | |
| 	free(key);
 | |
| 	return NULL;
 | |
|     }
 | |
|     key->allocated = TRUE;
 | |
|     return key;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Initialize privates by zeroing them
 | |
|  */
 | |
| void
 | |
| _dixInitPrivates(PrivatePtr *privates, void *addr, DevPrivateType type)
 | |
| {
 | |
|     keys[type].created++;
 | |
|     if (xselinux_private[type])
 | |
| 	keys[PRIVATE_XSELINUX].created++;
 | |
|     if (keys[type].offset == 0)
 | |
| 	addr = 0;
 | |
|     *privates = addr;
 | |
|     memset(addr, '\0', keys[type].offset);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Clean up privates
 | |
|  */
 | |
| void
 | |
| _dixFiniPrivates(PrivatePtr privates, DevPrivateType type)
 | |
| {
 | |
|     keys[type].created--;
 | |
|     if (xselinux_private[type])
 | |
| 	keys[PRIVATE_XSELINUX].created--;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Allocate new object with privates.
 | |
|  *
 | |
|  * This is expected to be invoked from the
 | |
|  * dixAllocateObjectWithPrivates macro
 | |
|  */
 | |
| void *
 | |
| _dixAllocateObjectWithPrivates(unsigned baseSize, unsigned clear, unsigned offset, DevPrivateType type)
 | |
| {
 | |
|     unsigned		totalSize;
 | |
|     void		*object;
 | |
|     PrivatePtr		privates;
 | |
|     PrivatePtr		*devPrivates;
 | |
| 
 | |
|     assert (type > PRIVATE_SCREEN && type < PRIVATE_LAST);
 | |
| 
 | |
|     /* round up so that void * is aligned */
 | |
|     baseSize = (baseSize + sizeof (void *) - 1) & ~(sizeof (void *) - 1);
 | |
|     totalSize = baseSize + keys[type].offset;
 | |
|     object = malloc(totalSize);
 | |
|     if (!object)
 | |
| 	return NULL;
 | |
| 
 | |
|     memset(object, '\0', clear);
 | |
|     privates = (PrivatePtr) (((char *) object) + baseSize);
 | |
|     devPrivates = (PrivatePtr *) ((char *) object + offset);
 | |
| 
 | |
|     _dixInitPrivates(devPrivates, privates, type);
 | |
| 
 | |
|     return object;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Allocate privates separately from containing object.
 | |
|  * Used for clients and screens.
 | |
|  */
 | |
| Bool
 | |
| dixAllocatePrivates(PrivatePtr *privates, DevPrivateType type)
 | |
| {
 | |
|     unsigned 	size;
 | |
|     PrivatePtr	p;
 | |
| 
 | |
|     assert (type > PRIVATE_XSELINUX && type < PRIVATE_LAST);
 | |
| 
 | |
|     size = keys[type].offset;
 | |
|     if (!size) {
 | |
| 	p = NULL;
 | |
|     } else {
 | |
| 	if (!(p = malloc(size)))
 | |
| 	    return FALSE;
 | |
|     }
 | |
| 
 | |
|     _dixInitPrivates(privates, p, type);
 | |
|     ++keys[type].allocated;
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Free an object that has privates
 | |
|  *
 | |
|  * This is expected to be invoked from the
 | |
|  * dixFreeObjectWithPrivates macro
 | |
|  */
 | |
| void
 | |
| _dixFreeObjectWithPrivates(void *object, PrivatePtr privates, DevPrivateType type)
 | |
| {
 | |
|     _dixFiniPrivates(privates, type);
 | |
|     free(object);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Called to free screen or client privates
 | |
|  */
 | |
| void
 | |
| dixFreePrivates(PrivatePtr privates, DevPrivateType type)
 | |
| {
 | |
|     _dixFiniPrivates(privates, type);
 | |
|     --keys[type].allocated;
 | |
|     free(privates);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Return size of privates for the specified type
 | |
|  */
 | |
| extern _X_EXPORT int
 | |
| dixPrivatesSize(DevPrivateType type)
 | |
| {
 | |
|     assert (type >= PRIVATE_SCREEN && type < PRIVATE_LAST);
 | |
| 
 | |
|     return keys[type].offset;
 | |
| }
 | |
| 
 | |
| /* Table of devPrivates offsets */
 | |
| static const int offsets[] = {
 | |
|     -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 */
 | |
| };
 | |
| 
 | |
| #define NUM_OFFSETS	(sizeof (offsets) / sizeof (offsets[0]))
 | |
| 
 | |
| int
 | |
| dixLookupPrivateOffset(RESTYPE type)
 | |
| {
 | |
|     /*
 | |
|      * Special kludge for DBE which registers a new resource type that
 | |
|      * points at pixmaps (thanks, DBE)
 | |
|      */
 | |
|     if (type & RC_DRAWABLE) {
 | |
| 	if (type == RT_WINDOW)
 | |
| 	    return offsets[RT_WINDOW & TypeMask];
 | |
| 	else
 | |
| 	    return offsets[RT_PIXMAP & TypeMask];
 | |
|     }
 | |
|     type = type & TypeMask;
 | |
|     if (type < NUM_OFFSETS)
 | |
| 	return offsets[type];
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| static const char *key_names[PRIVATE_LAST] = {
 | |
|     /* XSELinux uses the same private keys for numerous objects */
 | |
|     [PRIVATE_XSELINUX] = "XSELINUX",
 | |
| 
 | |
|     /* Otherwise, you get a private in just the requested structure
 | |
|      */
 | |
|     /* These can have objects created before all of the keys are registered */
 | |
|     [PRIVATE_SCREEN] = "SCREEN",
 | |
|     [PRIVATE_EXTENSION] = "EXTENSION",
 | |
|     [PRIVATE_COLORMAP] = "COLORMAP",
 | |
| 
 | |
|     /* These cannot have any objects before all relevant keys are registered */
 | |
|     [PRIVATE_DEVICE] = "DEVICE",
 | |
|     [PRIVATE_CLIENT] = "CLIENT",
 | |
|     [PRIVATE_PROPERTY] = "PROPERTY",
 | |
|     [PRIVATE_SELECTION] = "SELECTION",
 | |
|     [PRIVATE_WINDOW] = "WINDOW",
 | |
|     [PRIVATE_PIXMAP] = "PIXMAP",
 | |
|     [PRIVATE_GC] = "GC",
 | |
|     [PRIVATE_CURSOR] = "CURSOR",
 | |
|     [PRIVATE_CURSOR_BITS] = "CURSOR_BITS",
 | |
| 
 | |
|     /* extension privates */
 | |
|     [PRIVATE_DBE_WINDOW] = "DBE_WINDOW",
 | |
|     [PRIVATE_DAMAGE] = "DAMAGE",
 | |
|     [PRIVATE_GLYPH] = "GLYPH",
 | |
|     [PRIVATE_GLYPHSET] = "GLYPHSET",
 | |
|     [PRIVATE_PICTURE] = "PICTURE",
 | |
| };
 | |
| 
 | |
| void
 | |
| dixPrivateUsage(void)
 | |
| {
 | |
|     int objects = 0;
 | |
|     int	bytes = 0;
 | |
|     int alloc = 0;
 | |
|     DevPrivateType t;
 | |
| 
 | |
|     for (t = PRIVATE_XSELINUX + 1; t < PRIVATE_LAST; t++) {
 | |
| 	if (keys[t].offset) {
 | |
| 	    ErrorF("%s: %d objects of %d bytes = %d total bytes %d private allocs\n",
 | |
| 		   key_names[t], keys[t].created, keys[t].offset, keys[t].created * keys[t].offset,
 | |
| 		   keys[t].allocated);
 | |
| 	    bytes += keys[t].created * keys[t].offset;
 | |
| 	    objects += keys[t].created;
 | |
| 	    alloc += keys[t].allocated;
 | |
| 	}
 | |
|     }
 | |
|     ErrorF("TOTAL: %d objects, %d bytes, %d allocs\n",
 | |
| 	   objects, bytes, alloc);
 | |
| }
 | |
| 
 | |
| void
 | |
| dixResetPrivates(void)
 | |
| {
 | |
|     DevPrivateType	t;
 | |
| 
 | |
|     for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) {
 | |
| 	DevPrivateKey	key, next;
 | |
| 
 | |
| 	for (key = keys[t].key; key; key = next) {
 | |
| 	    next = key->next;
 | |
| 	    key->offset = 0;
 | |
| 	    key->initialized = FALSE;
 | |
| 	    key->size = 0;
 | |
| 	    key->type = 0;
 | |
| 	    if (key->allocated)
 | |
| 		free(key);
 | |
| 	}
 | |
| 	if (keys[t].created) {
 | |
| 	    ErrorF("%d %ss still allocated at reset\n",
 | |
| 		   keys[t].created, key_names[t]);
 | |
| 	    dixPrivateUsage();
 | |
| 	}
 | |
| 	keys[t].key = NULL;
 | |
| 	keys[t].offset = 0;
 | |
| 	keys[t].created = 0;
 | |
| 	keys[t].allocated = 0;
 | |
|     }
 | |
| }
 |