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 * Copyright © 2010, Keith Packard
30 * Copyright © 2010, Jamey Sharp
31 *
32 * Permission to use, copy, modify, distribute, and sell this software and its
33 * documentation for any purpose is hereby granted without fee, provided that
34 * the above copyright notice appear in all copies and that both that copyright
35 * notice and this permission notice appear in supporting documentation, and
36 * that the name of the copyright holders not be used in advertising or
37 * publicity pertaining to distribution of the software without specific,
38 * written prior permission.  The copyright holders make no representations
39 * about the suitability of this software for any purpose.  It is provided "as
40 * is" without express or implied warranty.
41 *
42 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
43 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
44 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
45 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
46 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
47 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
48 * OF THIS SOFTWARE.
49 */
50
51#ifdef HAVE_DIX_CONFIG_H
52#include <dix-config.h>
53#endif
54
55#include <stddef.h>
56#include "windowstr.h"
57#include "resource.h"
58#include "privates.h"
59#include "gcstruct.h"
60#include "cursorstr.h"
61#include "colormapst.h"
62#include "inputstr.h"
63#include "scrnintstr.h"
64#include "extnsionst.h"
65#include "inputstr.h"
66
67static DevPrivateSetRec global_keys[PRIVATE_LAST];
68
69static const Bool xselinux_private[PRIVATE_LAST] = {
70    [PRIVATE_SCREEN] = TRUE,
71    [PRIVATE_CLIENT] = TRUE,
72    [PRIVATE_WINDOW] = TRUE,
73    [PRIVATE_PIXMAP] = TRUE,
74    [PRIVATE_GC] = TRUE,
75    [PRIVATE_CURSOR] = TRUE,
76    [PRIVATE_COLORMAP] = TRUE,
77    [PRIVATE_DEVICE] = TRUE,
78    [PRIVATE_EXTENSION] = TRUE,
79    [PRIVATE_SELECTION] = TRUE,
80    [PRIVATE_PROPERTY] = TRUE,
81    [PRIVATE_PICTURE] = TRUE,
82    [PRIVATE_GLYPHSET] = TRUE,
83};
84
85static const char *key_names[PRIVATE_LAST] = {
86    /* XSELinux uses the same private keys for numerous objects */
87    [PRIVATE_XSELINUX] = "XSELINUX",
88
89    /* Otherwise, you get a private in just the requested structure
90     */
91    /* These can have objects created before all of the keys are registered */
92    [PRIVATE_SCREEN] = "SCREEN",
93    [PRIVATE_EXTENSION] = "EXTENSION",
94    [PRIVATE_COLORMAP] = "COLORMAP",
95    [PRIVATE_DEVICE] = "DEVICE",
96
97    /* These cannot have any objects before all relevant keys are registered */
98    [PRIVATE_CLIENT] = "CLIENT",
99    [PRIVATE_PROPERTY] = "PROPERTY",
100    [PRIVATE_SELECTION] = "SELECTION",
101    [PRIVATE_WINDOW] = "WINDOW",
102    [PRIVATE_PIXMAP] = "PIXMAP",
103    [PRIVATE_GC] = "GC",
104    [PRIVATE_CURSOR] = "CURSOR",
105    [PRIVATE_CURSOR_BITS] = "CURSOR_BITS",
106
107    /* extension privates */
108    [PRIVATE_GLYPH] = "GLYPH",
109    [PRIVATE_GLYPHSET] = "GLYPHSET",
110    [PRIVATE_PICTURE] = "PICTURE",
111    [PRIVATE_SYNC_FENCE] = "SYNC_FENCE",
112};
113
114static const Bool screen_specific_private[PRIVATE_LAST] = {
115    [PRIVATE_SCREEN] = FALSE,
116    [PRIVATE_CLIENT] = FALSE,
117    [PRIVATE_WINDOW] = TRUE,
118    [PRIVATE_PIXMAP] = TRUE,
119    [PRIVATE_GC] = TRUE,
120    [PRIVATE_CURSOR] = FALSE,
121    [PRIVATE_COLORMAP] = FALSE,
122    [PRIVATE_DEVICE] = FALSE,
123    [PRIVATE_EXTENSION] = FALSE,
124    [PRIVATE_SELECTION] = FALSE,
125    [PRIVATE_PROPERTY] = FALSE,
126    [PRIVATE_PICTURE] = TRUE,
127    [PRIVATE_GLYPHSET] = FALSE,
128};
129
130typedef Bool (*FixupFunc) (PrivatePtr *privates, int offset, unsigned bytes);
131
132typedef enum { FixupMove, FixupRealloc } FixupType;
133
134static Bool
135dixReallocPrivates(PrivatePtr *privates, int old_offset, unsigned bytes)
136{
137    void *new_privates;
138
139    new_privates = realloc(*privates, old_offset + bytes);
140    if (!new_privates)
141        return FALSE;
142    memset((char *) new_privates + old_offset, '\0', bytes);
143    *privates = new_privates;
144    return TRUE;
145}
146
147static Bool
148dixMovePrivates(PrivatePtr *privates, int new_offset, unsigned bytes)
149{
150    memmove((char *) *privates + bytes, *privates, new_offset - bytes);
151    memset(*privates, '\0', bytes);
152    return TRUE;
153}
154
155static Bool
156fixupOneScreen(ScreenPtr pScreen, FixupFunc fixup, unsigned bytes)
157{
158    uintptr_t       old;
159    char            *new;
160    DevPrivateKey   *keyp, key;
161    DevPrivateType  type;
162    int             size;
163
164    old = (uintptr_t) pScreen->devPrivates;
165    size = global_keys[PRIVATE_SCREEN].offset;
166    if (!fixup (&pScreen->devPrivates, size, bytes))
167        return FALSE;
168
169    /* Screen privates can contain screen-specific private keys
170     * for other types. When they move, the linked list we use to
171     * track them gets scrambled. Fix that by computing the change
172     * in the location of each private adjusting our linked list
173     * pointers to match
174     */
175
176    new = (char *) pScreen->devPrivates;
177
178    /* Moving means everyone shifts up in the privates by 'bytes' amount,
179     * realloc means the base pointer moves
180     */
181    if (fixup == dixMovePrivates)
182        new += bytes;
183
184    if ((uintptr_t) new != old) {
185        for (type = PRIVATE_XSELINUX; type < PRIVATE_LAST; type++)
186
187            /* Walk the privates list, being careful as the
188             * pointers are scrambled before we patch them.
189             */
190            for (keyp = &pScreen->screenSpecificPrivates[type].key;
191                 (key = *keyp) != NULL;
192                 keyp = &key->next)
193            {
194
195                /* Only mangle things if the private structure
196                 * is contained within the allocation. Privates
197                 * stored elsewhere will be left alone
198                 */
199                if (old <= (uintptr_t) key && (uintptr_t) key < old + size)
200                {
201                    /* Compute new location of key (deriving from the new
202                     * allocation to avoid UB) */
203                    key = (DevPrivateKey) (new + ((uintptr_t) key - old));
204
205                    /* Patch the list */
206                    *keyp = key;
207                }
208            }
209    }
210    return TRUE;
211}
212
213static Bool
214fixupScreens(FixupFunc fixup, unsigned bytes)
215{
216    int s;
217
218    for (s = 0; s < screenInfo.numScreens; s++)
219        if (!fixupOneScreen (screenInfo.screens[s], fixup, bytes))
220            return FALSE;
221
222    for (s = 0; s < screenInfo.numGPUScreens; s++)
223        if (!fixupOneScreen (screenInfo.gpuscreens[s], fixup, bytes))
224            return FALSE;
225    return TRUE;
226}
227
228static Bool
229fixupServerClient(FixupFunc fixup, unsigned bytes)
230{
231    if (serverClient)
232        return fixup(&serverClient->devPrivates, global_keys[PRIVATE_CLIENT].offset,
233                     bytes);
234    return TRUE;
235}
236
237static Bool
238fixupExtensions(FixupFunc fixup, unsigned bytes)
239{
240    unsigned char major;
241    ExtensionEntry *extension;
242
243    for (major = EXTENSION_BASE; (extension = GetExtensionEntry(major));
244         major++)
245        if (!fixup
246            (&extension->devPrivates, global_keys[PRIVATE_EXTENSION].offset, bytes))
247            return FALSE;
248    return TRUE;
249}
250
251static Bool
252fixupDefaultColormaps(FixupFunc fixup, unsigned bytes)
253{
254    int s;
255
256    for (s = 0; s < screenInfo.numScreens; s++) {
257        ColormapPtr cmap;
258
259        dixLookupResourceByType((void **) &cmap,
260                                screenInfo.screens[s]->defColormap, RT_COLORMAP,
261                                serverClient, DixCreateAccess);
262        if (cmap &&
263            !fixup(&cmap->devPrivates, screenInfo.screens[s]->screenSpecificPrivates[PRIVATE_COLORMAP].offset, bytes))
264            return FALSE;
265    }
266    return TRUE;
267}
268
269static Bool
270fixupDeviceList(DeviceIntPtr device, FixupFunc fixup, unsigned bytes)
271{
272    while (device) {
273        if (!fixup(&device->devPrivates, global_keys[PRIVATE_DEVICE].offset, bytes))
274            return FALSE;
275        device = device->next;
276    }
277    return TRUE;
278}
279
280static Bool
281fixupDevices(FixupFunc fixup, unsigned bytes)
282{
283    return (fixupDeviceList(inputInfo.devices, fixup, bytes) &&
284            fixupDeviceList(inputInfo.off_devices, fixup, bytes));
285}
286
287static Bool (*const allocated_early[PRIVATE_LAST]) (FixupFunc, unsigned) = {
288    [PRIVATE_SCREEN] = fixupScreens,
289    [PRIVATE_CLIENT] = fixupServerClient,
290    [PRIVATE_EXTENSION] = fixupExtensions,
291    [PRIVATE_COLORMAP] = fixupDefaultColormaps,
292    [PRIVATE_DEVICE] = fixupDevices,
293};
294
295static void
296grow_private_set(DevPrivateSetPtr set, unsigned bytes)
297{
298    DevPrivateKey       k;
299
300    for (k = set->key; k; k = k->next)
301        k->offset += bytes;
302    set->offset += bytes;
303}
304
305static void
306grow_screen_specific_set(DevPrivateType type, unsigned bytes)
307{
308    int s;
309
310    /* Update offsets for all screen-specific keys */
311    for (s = 0; s < screenInfo.numScreens; s++) {
312        ScreenPtr       pScreen = screenInfo.screens[s];
313
314        grow_private_set(&pScreen->screenSpecificPrivates[type], bytes);
315    }
316    for (s = 0; s < screenInfo.numGPUScreens; s++) {
317        ScreenPtr       pScreen = screenInfo.gpuscreens[s];
318
319        grow_private_set(&pScreen->screenSpecificPrivates[type], bytes);
320    }
321}
322
323/*
324 * Register a private key. This takes the type of object the key will
325 * be used with, which may be PRIVATE_ALL indicating that this key
326 * will be used with all of the private objects. If 'size' is
327 * non-zero, then the specified amount of space will be allocated in
328 * the private storage. Otherwise, space for a single pointer will
329 * be allocated which can be set with dixSetPrivate
330 */
331Bool
332dixRegisterPrivateKey(DevPrivateKey key, DevPrivateType type, unsigned size)
333{
334    DevPrivateType t;
335    int offset;
336    unsigned bytes;
337
338    if (key->initialized) {
339        assert(size == key->size);
340        return TRUE;
341    }
342
343    /* Compute required space */
344    bytes = size;
345    if (size == 0)
346        bytes = sizeof(void *);
347
348    /* align to pointer size */
349    bytes = (bytes + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
350
351    /* Update offsets for all affected keys */
352    if (type == PRIVATE_XSELINUX) {
353
354        /* Resize if we can, or make sure nothing's allocated if we can't
355         */
356        for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++)
357            if (xselinux_private[t]) {
358                if (!allocated_early[t])
359                    assert(!global_keys[t].created);
360                else if (!allocated_early[t] (dixReallocPrivates, bytes))
361                    return FALSE;
362            }
363
364        /* Move all existing keys up in the privates space to make
365         * room for this new global key
366         */
367        for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) {
368            if (xselinux_private[t]) {
369                grow_private_set(&global_keys[t], bytes);
370                grow_screen_specific_set(t, bytes);
371                if (allocated_early[t])
372                    allocated_early[t] (dixMovePrivates, bytes);
373            }
374
375        }
376
377        offset = 0;
378    }
379    else {
380        /* Resize if we can, or make sure nothing's allocated if we can't */
381        if (!allocated_early[type])
382            assert(!global_keys[type].created);
383        else if (!allocated_early[type] (dixReallocPrivates, bytes))
384            return FALSE;
385        offset = global_keys[type].offset;
386        global_keys[type].offset += bytes;
387        grow_screen_specific_set(type, bytes);
388    }
389
390    /* Setup this key */
391    key->offset = offset;
392    key->size = size;
393    key->initialized = TRUE;
394    key->type = type;
395    key->allocated = FALSE;
396    key->next = global_keys[type].key;
397    global_keys[type].key = key;
398
399    return TRUE;
400}
401
402Bool
403dixRegisterScreenPrivateKey(DevScreenPrivateKey screenKey, ScreenPtr pScreen,
404                            DevPrivateType type, unsigned size)
405{
406    DevPrivateKey key;
407
408    if (!dixRegisterPrivateKey(&screenKey->screenKey, PRIVATE_SCREEN, 0))
409        return FALSE;
410    key = dixGetPrivate(&pScreen->devPrivates, &screenKey->screenKey);
411    if (key != NULL) {
412        assert(key->size == size);
413        assert(key->type == type);
414        return TRUE;
415    }
416    key = calloc(sizeof(DevPrivateKeyRec), 1);
417    if (!key)
418        return FALSE;
419    if (!dixRegisterPrivateKey(key, type, size)) {
420        free(key);
421        return FALSE;
422    }
423    key->allocated = TRUE;
424    dixSetPrivate(&pScreen->devPrivates, &screenKey->screenKey, key);
425    return TRUE;
426}
427
428DevPrivateKey
429_dixGetScreenPrivateKey(const DevScreenPrivateKey key, ScreenPtr pScreen)
430{
431    return dixGetPrivate(&pScreen->devPrivates, &key->screenKey);
432}
433
434/*
435 * Initialize privates by zeroing them
436 */
437void
438_dixInitPrivates(PrivatePtr *privates, void *addr, DevPrivateType type)
439{
440    assert (!screen_specific_private[type]);
441
442    global_keys[type].created++;
443    if (xselinux_private[type])
444        global_keys[PRIVATE_XSELINUX].created++;
445    if (global_keys[type].offset == 0)
446        addr = 0;
447    *privates = addr;
448    if (addr)
449        memset(addr, '\0', global_keys[type].offset);
450}
451
452/*
453 * Clean up privates
454 */
455void
456_dixFiniPrivates(PrivatePtr privates, DevPrivateType type)
457{
458    global_keys[type].created--;
459    if (xselinux_private[type])
460        global_keys[PRIVATE_XSELINUX].created--;
461}
462
463/*
464 * Allocate new object with privates.
465 *
466 * This is expected to be invoked from the
467 * dixAllocateObjectWithPrivates macro
468 */
469void *
470_dixAllocateObjectWithPrivates(unsigned baseSize, unsigned clear,
471                               unsigned offset, DevPrivateType type)
472{
473    unsigned totalSize;
474    void *object;
475    PrivatePtr privates;
476    PrivatePtr *devPrivates;
477
478    assert(type > PRIVATE_SCREEN);
479    assert(type < PRIVATE_LAST);
480    assert(!screen_specific_private[type]);
481
482    /* round up so that void * is aligned */
483    baseSize = (baseSize + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
484    totalSize = baseSize + global_keys[type].offset;
485    object = malloc(totalSize);
486    if (!object)
487        return NULL;
488
489    memset(object, '\0', clear);
490    privates = (PrivatePtr) (((char *) object) + baseSize);
491    devPrivates = (PrivatePtr *) ((char *) object + offset);
492
493    _dixInitPrivates(devPrivates, privates, type);
494
495    return object;
496}
497
498/*
499 * Allocate privates separately from containing object.
500 * Used for clients and screens.
501 */
502Bool
503dixAllocatePrivates(PrivatePtr *privates, DevPrivateType type)
504{
505    unsigned size;
506    PrivatePtr p;
507
508    assert(type > PRIVATE_XSELINUX);
509    assert(type < PRIVATE_LAST);
510    assert(!screen_specific_private[type]);
511
512    size = global_keys[type].offset;
513    if (!size) {
514        p = NULL;
515    }
516    else {
517        if (!(p = malloc(size)))
518            return FALSE;
519    }
520
521    _dixInitPrivates(privates, p, type);
522    ++global_keys[type].allocated;
523
524    return TRUE;
525}
526
527/*
528 * Free an object that has privates
529 *
530 * This is expected to be invoked from the
531 * dixFreeObjectWithPrivates macro
532 */
533void
534_dixFreeObjectWithPrivates(void *object, PrivatePtr privates,
535                           DevPrivateType type)
536{
537    _dixFiniPrivates(privates, type);
538    free(object);
539}
540
541/*
542 * Called to free screen or client privates
543 */
544void
545dixFreePrivates(PrivatePtr privates, DevPrivateType type)
546{
547    _dixFiniPrivates(privates, type);
548    --global_keys[type].allocated;
549    free(privates);
550}
551
552/*
553 * Return size of privates for the specified type
554 */
555extern _X_EXPORT int
556dixPrivatesSize(DevPrivateType type)
557{
558    assert(type >= PRIVATE_SCREEN);
559    assert(type < PRIVATE_LAST);
560    assert (!screen_specific_private[type]);
561
562    return global_keys[type].offset;
563}
564
565/* Table of devPrivates offsets */
566static const int offsets[] = {
567    -1,                         /* RT_NONE */
568    offsetof(WindowRec, devPrivates),   /* RT_WINDOW */
569    offsetof(PixmapRec, devPrivates),   /* RT_PIXMAP */
570    offsetof(GC, devPrivates),  /* RT_GC */
571    -1,                         /* RT_FONT */
572    offsetof(CursorRec, devPrivates),   /* RT_CURSOR */
573    offsetof(ColormapRec, devPrivates), /* RT_COLORMAP */
574};
575
576int
577dixLookupPrivateOffset(RESTYPE type)
578{
579    /*
580     * Special kludge for DBE which registers a new resource type that
581     * points at pixmaps (thanks, DBE)
582     */
583    if (type & RC_DRAWABLE) {
584        if (type == RT_WINDOW)
585            return offsets[RT_WINDOW & TypeMask];
586        else
587            return offsets[RT_PIXMAP & TypeMask];
588    }
589    type = type & TypeMask;
590    if (type < ARRAY_SIZE(offsets))
591        return offsets[type];
592    return -1;
593}
594
595/*
596 * Screen-specific privates
597 */
598
599extern _X_EXPORT Bool
600dixRegisterScreenSpecificPrivateKey(ScreenPtr pScreen, DevPrivateKey key,
601                                    DevPrivateType type, unsigned size)
602{
603    int offset;
604    unsigned bytes;
605
606    if (!screen_specific_private[type])
607        FatalError("Attempt to allocate screen-specific private storage for type %s\n",
608                   key_names[type]);
609
610    if (key->initialized) {
611        assert(size == key->size);
612        return TRUE;
613    }
614
615    /* Compute required space */
616    bytes = size;
617    if (size == 0)
618        bytes = sizeof(void *);
619
620    /* align to void * size */
621    bytes = (bytes + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
622
623    assert (!allocated_early[type]);
624    assert (!pScreen->screenSpecificPrivates[type].created);
625    offset = pScreen->screenSpecificPrivates[type].offset;
626    pScreen->screenSpecificPrivates[type].offset += bytes;
627
628    /* Setup this key */
629    key->offset = offset;
630    key->size = size;
631    key->initialized = TRUE;
632    key->type = type;
633    key->allocated = FALSE;
634    key->next = pScreen->screenSpecificPrivates[type].key;
635    pScreen->screenSpecificPrivates[type].key = key;
636
637    return TRUE;
638}
639
640/* Clean up screen-specific privates before CloseScreen */
641void
642dixFreeScreenSpecificPrivates(ScreenPtr pScreen)
643{
644    DevPrivateType t;
645
646    for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) {
647        DevPrivateKey key;
648
649        for (key = pScreen->screenSpecificPrivates[t].key; key; key = key->next) {
650            key->initialized = FALSE;
651        }
652    }
653}
654
655/* Initialize screen-specific privates in AddScreen */
656void
657dixInitScreenSpecificPrivates(ScreenPtr pScreen)
658{
659    DevPrivateType      t;
660
661    for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++)
662        pScreen->screenSpecificPrivates[t].offset = global_keys[t].offset;
663}
664
665/* Initialize screen-specific privates in AddScreen */
666void
667_dixInitScreenPrivates(ScreenPtr pScreen, PrivatePtr *privates, void *addr, DevPrivateType type)
668{
669    int privates_size;
670    assert (screen_specific_private[type]);
671
672    if (pScreen) {
673        privates_size = pScreen->screenSpecificPrivates[type].offset;
674        pScreen->screenSpecificPrivates[type].created++;
675    }
676    else
677        privates_size = global_keys[type].offset;
678
679    global_keys[type].created++;
680    if (xselinux_private[type])
681        global_keys[PRIVATE_XSELINUX].created++;
682    if (privates_size == 0)
683        addr = 0;
684    *privates = addr;
685    if (addr)
686        memset(addr, '\0', privates_size);
687}
688
689void *
690_dixAllocateScreenObjectWithPrivates(ScreenPtr pScreen,
691                                     unsigned baseSize,
692                                     unsigned clear,
693                                     unsigned offset,
694                                     DevPrivateType type)
695{
696    unsigned totalSize;
697    void *object;
698    PrivatePtr privates;
699    PrivatePtr *devPrivates;
700    int privates_size;
701
702    assert(type > PRIVATE_SCREEN);
703    assert(type < PRIVATE_LAST);
704    assert (screen_specific_private[type]);
705
706    if (pScreen)
707        privates_size = pScreen->screenSpecificPrivates[type].offset;
708    else
709        privates_size = global_keys[type].offset;
710    /* round up so that pointer is aligned */
711    baseSize = (baseSize + sizeof(void *) - 1) & ~(sizeof(void *) - 1);
712    totalSize = baseSize + privates_size;
713    object = malloc(totalSize);
714    if (!object)
715        return NULL;
716
717    memset(object, '\0', clear);
718    privates = (PrivatePtr) (((char *) object) + baseSize);
719    devPrivates = (PrivatePtr *) ((char *) object + offset);
720
721    _dixInitScreenPrivates(pScreen, devPrivates, privates, type);
722
723    return object;
724}
725
726int
727dixScreenSpecificPrivatesSize(ScreenPtr pScreen, DevPrivateType type)
728{
729    assert(type >= PRIVATE_SCREEN);
730    assert(type < PRIVATE_LAST);
731
732    if (screen_specific_private[type])
733        return pScreen->screenSpecificPrivates[type].offset;
734    else
735        return global_keys[type].offset;
736}
737
738void
739dixPrivateUsage(void)
740{
741    int objects = 0;
742    int bytes = 0;
743    int alloc = 0;
744    DevPrivateType t;
745
746    for (t = PRIVATE_XSELINUX + 1; t < PRIVATE_LAST; t++) {
747        if (global_keys[t].offset) {
748            ErrorF
749                ("%s: %d objects of %d bytes = %d total bytes %d private allocs\n",
750                 key_names[t], global_keys[t].created, global_keys[t].offset,
751                 global_keys[t].created * global_keys[t].offset, global_keys[t].allocated);
752            bytes += global_keys[t].created * global_keys[t].offset;
753            objects += global_keys[t].created;
754            alloc += global_keys[t].allocated;
755        }
756    }
757    ErrorF("TOTAL: %d objects, %d bytes, %d allocs\n", objects, bytes, alloc);
758}
759
760void
761dixResetPrivates(void)
762{
763    DevPrivateType t;
764
765    for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) {
766        DevPrivateKey key, next;
767
768        for (key = global_keys[t].key; key; key = next) {
769            next = key->next;
770            key->offset = 0;
771            key->initialized = FALSE;
772            key->size = 0;
773            key->type = 0;
774            if (key->allocated)
775                free(key);
776        }
777        if (global_keys[t].created) {
778            ErrorF("%d %ss still allocated at reset\n",
779                   global_keys[t].created, key_names[t]);
780            dixPrivateUsage();
781        }
782        global_keys[t].key = NULL;
783        global_keys[t].offset = 0;
784        global_keys[t].created = 0;
785        global_keys[t].allocated = 0;
786    }
787}
788
789Bool
790dixPrivatesCreated(DevPrivateType type)
791{
792    if (global_keys[type].created)
793        return TRUE;
794    else
795        return FALSE;
796}
797