Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /* |
2 | ||
3 | Copyright 1993, 1998 The Open Group | |
4 | ||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |
6 | documentation for any purpose is hereby granted without fee, provided that | |
7 | the above copyright notice appear in all copies and that both that | |
8 | copyright notice and this permission notice appear in supporting | |
9 | documentation. | |
10 | ||
11 | The above copyright notice and this permission notice shall be included | |
12 | in all copies or substantial portions of the Software. | |
13 | ||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
17 | IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
18 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
19 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
20 | OTHER DEALINGS IN THE SOFTWARE. | |
21 | ||
22 | Except as contained in this notice, the name of The Open Group shall | |
23 | not be used in advertising or otherwise to promote the sale, use or | |
24 | other dealings in this Software without prior written authorization | |
25 | from 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 | ||
67 | static DevPrivateSetRec global_keys[PRIVATE_LAST]; | |
68 | ||
69 | static 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 | ||
85 | static 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_DAMAGE] = "DAMAGE", | |
109 | [PRIVATE_GLYPH] = "GLYPH", | |
110 | [PRIVATE_GLYPHSET] = "GLYPHSET", | |
111 | [PRIVATE_PICTURE] = "PICTURE", | |
112 | [PRIVATE_SYNC_FENCE] = "SYNC_FENCE", | |
113 | }; | |
114 | ||
115 | static const Bool screen_specific_private[PRIVATE_LAST] = { | |
116 | [PRIVATE_SCREEN] = FALSE, | |
117 | [PRIVATE_CLIENT] = FALSE, | |
118 | [PRIVATE_WINDOW] = TRUE, | |
119 | [PRIVATE_PIXMAP] = TRUE, | |
120 | [PRIVATE_GC] = TRUE, | |
121 | [PRIVATE_CURSOR] = FALSE, | |
122 | [PRIVATE_COLORMAP] = FALSE, | |
123 | [PRIVATE_DEVICE] = FALSE, | |
124 | [PRIVATE_EXTENSION] = FALSE, | |
125 | [PRIVATE_SELECTION] = FALSE, | |
126 | [PRIVATE_PROPERTY] = FALSE, | |
127 | [PRIVATE_PICTURE] = TRUE, | |
128 | [PRIVATE_GLYPHSET] = FALSE, | |
129 | }; | |
130 | ||
131 | typedef Bool (*FixupFunc) (PrivatePtr *privates, int offset, unsigned bytes); | |
132 | ||
133 | typedef enum { FixupMove, FixupRealloc } FixupType; | |
134 | ||
135 | static Bool | |
136 | dixReallocPrivates(PrivatePtr *privates, int old_offset, unsigned bytes) | |
137 | { | |
138 | void *new_privates; | |
139 | ||
140 | new_privates = realloc(*privates, old_offset + bytes); | |
141 | if (!new_privates) | |
142 | return FALSE; | |
143 | memset((char *) new_privates + old_offset, '\0', bytes); | |
144 | *privates = new_privates; | |
145 | return TRUE; | |
146 | } | |
147 | ||
148 | static Bool | |
149 | dixMovePrivates(PrivatePtr *privates, int new_offset, unsigned bytes) | |
150 | { | |
151 | memmove((char *) *privates + bytes, *privates, new_offset - bytes); | |
152 | memset(*privates, '\0', bytes); | |
153 | return TRUE; | |
154 | } | |
155 | ||
156 | static Bool | |
157 | fixupOneScreen(ScreenPtr pScreen, FixupFunc fixup, unsigned bytes) | |
158 | { | |
159 | intptr_t dist; | |
160 | char *old; | |
161 | char *new; | |
162 | DevPrivateKey *keyp, key; | |
163 | DevPrivateType type; | |
164 | int size; | |
165 | ||
166 | old = (char *) pScreen->devPrivates; | |
167 | size = global_keys[PRIVATE_SCREEN].offset; | |
168 | if (!fixup (&pScreen->devPrivates, size, bytes)) | |
169 | return FALSE; | |
170 | ||
171 | /* Screen privates can contain screen-specific private keys | |
172 | * for other types. When they move, the linked list we use to | |
173 | * track them gets scrambled. Fix that by computing the change | |
174 | * in the location of each private adjusting our linked list | |
175 | * pointers to match | |
176 | */ | |
177 | ||
178 | new = (char *) pScreen->devPrivates; | |
179 | ||
180 | /* Moving means everyone shifts up in the privates by 'bytes' amount, | |
181 | * realloc means the base pointer moves | |
182 | */ | |
183 | if (fixup == dixMovePrivates) | |
184 | new += bytes; | |
185 | ||
186 | dist = new - old; | |
187 | ||
188 | if (dist) { | |
189 | for (type = PRIVATE_XSELINUX; type < PRIVATE_LAST; type++) | |
190 | ||
191 | /* Walk the privates list, being careful as the | |
192 | * pointers are scrambled before we patch them. | |
193 | */ | |
194 | for (keyp = &pScreen->screenSpecificPrivates[type].key; | |
195 | (key = *keyp) != NULL; | |
196 | keyp = &key->next) | |
197 | { | |
198 | ||
199 | /* Only mangle things if the private structure | |
200 | * is contained within the allocation. Privates | |
201 | * stored elsewhere will be left alone | |
202 | */ | |
203 | if (old <= (char *) key && (char *) key < old + size) | |
204 | { | |
205 | /* Compute new location of key */ | |
206 | key = (DevPrivateKey) ((char *) key + dist); | |
207 | ||
208 | /* Patch the list */ | |
209 | *keyp = key; | |
210 | } | |
211 | } | |
212 | } | |
213 | return TRUE; | |
214 | } | |
215 | ||
216 | static Bool | |
217 | fixupScreens(FixupFunc fixup, unsigned bytes) | |
218 | { | |
219 | int s; | |
220 | ||
221 | for (s = 0; s < screenInfo.numScreens; s++) | |
222 | if (!fixupOneScreen (screenInfo.screens[s], fixup, bytes)) | |
223 | return FALSE; | |
224 | ||
225 | for (s = 0; s < screenInfo.numGPUScreens; s++) | |
226 | if (!fixupOneScreen (screenInfo.gpuscreens[s], fixup, bytes)) | |
227 | return FALSE; | |
228 | return TRUE; | |
229 | } | |
230 | ||
231 | static Bool | |
232 | fixupServerClient(FixupFunc fixup, unsigned bytes) | |
233 | { | |
234 | if (serverClient) | |
235 | return fixup(&serverClient->devPrivates, global_keys[PRIVATE_CLIENT].offset, | |
236 | bytes); | |
237 | return TRUE; | |
238 | } | |
239 | ||
240 | static Bool | |
241 | fixupExtensions(FixupFunc fixup, unsigned bytes) | |
242 | { | |
243 | unsigned char major; | |
244 | ExtensionEntry *extension; | |
245 | ||
246 | for (major = EXTENSION_BASE; (extension = GetExtensionEntry(major)); | |
247 | major++) | |
248 | if (!fixup | |
249 | (&extension->devPrivates, global_keys[PRIVATE_EXTENSION].offset, bytes)) | |
250 | return FALSE; | |
251 | return TRUE; | |
252 | } | |
253 | ||
254 | static Bool | |
255 | fixupDefaultColormaps(FixupFunc fixup, unsigned bytes) | |
256 | { | |
257 | int s; | |
258 | ||
259 | for (s = 0; s < screenInfo.numScreens; s++) { | |
260 | ColormapPtr cmap; | |
261 | ||
262 | dixLookupResourceByType((pointer *) &cmap, | |
263 | screenInfo.screens[s]->defColormap, RT_COLORMAP, | |
264 | serverClient, DixCreateAccess); | |
265 | if (cmap && | |
266 | !fixup(&cmap->devPrivates, screenInfo.screens[s]->screenSpecificPrivates[PRIVATE_COLORMAP].offset, bytes)) | |
267 | return FALSE; | |
268 | } | |
269 | return TRUE; | |
270 | } | |
271 | ||
272 | static Bool | |
273 | fixupDeviceList(DeviceIntPtr device, FixupFunc fixup, unsigned bytes) | |
274 | { | |
275 | while (device) { | |
276 | if (!fixup(&device->devPrivates, global_keys[PRIVATE_DEVICE].offset, bytes)) | |
277 | return FALSE; | |
278 | device = device->next; | |
279 | } | |
280 | return TRUE; | |
281 | } | |
282 | ||
283 | static Bool | |
284 | fixupDevices(FixupFunc fixup, unsigned bytes) | |
285 | { | |
286 | return (fixupDeviceList(inputInfo.devices, fixup, bytes) && | |
287 | fixupDeviceList(inputInfo.off_devices, fixup, bytes)); | |
288 | } | |
289 | ||
290 | static Bool (*const allocated_early[PRIVATE_LAST]) (FixupFunc, unsigned) = { | |
291 | [PRIVATE_SCREEN] = fixupScreens, | |
292 | [PRIVATE_CLIENT] = fixupServerClient, | |
293 | [PRIVATE_EXTENSION] = fixupExtensions, | |
294 | [PRIVATE_COLORMAP] = fixupDefaultColormaps, | |
295 | [PRIVATE_DEVICE] = fixupDevices, | |
296 | }; | |
297 | ||
298 | static void | |
299 | grow_private_set(DevPrivateSetPtr set, unsigned bytes) | |
300 | { | |
301 | DevPrivateKey k; | |
302 | ||
303 | for (k = set->key; k; k = k->next) | |
304 | k->offset += bytes; | |
305 | set->offset += bytes; | |
306 | } | |
307 | ||
308 | static void | |
309 | grow_screen_specific_set(DevPrivateType type, unsigned bytes) | |
310 | { | |
311 | int s; | |
312 | ||
313 | /* Update offsets for all screen-specific keys */ | |
314 | for (s = 0; s < screenInfo.numScreens; s++) { | |
315 | ScreenPtr pScreen = screenInfo.screens[s]; | |
316 | ||
317 | grow_private_set(&pScreen->screenSpecificPrivates[type], bytes); | |
318 | } | |
319 | for (s = 0; s < screenInfo.numGPUScreens; s++) { | |
320 | ScreenPtr pScreen = screenInfo.gpuscreens[s]; | |
321 | ||
322 | grow_private_set(&pScreen->screenSpecificPrivates[type], bytes); | |
323 | } | |
324 | } | |
325 | ||
326 | /* | |
327 | * Register a private key. This takes the type of object the key will | |
328 | * be used with, which may be PRIVATE_ALL indicating that this key | |
329 | * will be used with all of the private objects. If 'size' is | |
330 | * non-zero, then the specified amount of space will be allocated in | |
331 | * the private storage. Otherwise, space for a single pointer will | |
332 | * be allocated which can be set with dixSetPrivate | |
333 | */ | |
334 | Bool | |
335 | dixRegisterPrivateKey(DevPrivateKey key, DevPrivateType type, unsigned size) | |
336 | { | |
337 | DevPrivateType t; | |
338 | int offset; | |
339 | unsigned bytes; | |
340 | ||
341 | if (key->initialized) { | |
342 | assert(size == key->size); | |
343 | return TRUE; | |
344 | } | |
345 | ||
346 | /* Compute required space */ | |
347 | bytes = size; | |
348 | if (size == 0) | |
349 | bytes = sizeof(void *); | |
350 | ||
351 | /* align to void * size */ | |
352 | bytes = (bytes + sizeof(void *) - 1) & ~(sizeof(void *) - 1); | |
353 | ||
354 | /* Update offsets for all affected keys */ | |
355 | if (type == PRIVATE_XSELINUX) { | |
356 | ||
357 | /* Resize if we can, or make sure nothing's allocated if we can't | |
358 | */ | |
359 | for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) | |
360 | if (xselinux_private[t]) { | |
361 | if (!allocated_early[t]) | |
362 | assert(!global_keys[t].created); | |
363 | else if (!allocated_early[t] (dixReallocPrivates, bytes)) | |
364 | return FALSE; | |
365 | } | |
366 | ||
367 | /* Move all existing keys up in the privates space to make | |
368 | * room for this new global key | |
369 | */ | |
370 | for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) { | |
371 | if (xselinux_private[t]) { | |
372 | grow_private_set(&global_keys[t], bytes); | |
373 | grow_screen_specific_set(t, bytes); | |
374 | if (allocated_early[t]) | |
375 | allocated_early[t] (dixMovePrivates, bytes); | |
376 | } | |
377 | ||
378 | } | |
379 | ||
380 | offset = 0; | |
381 | } | |
382 | else { | |
383 | /* Resize if we can, or make sure nothing's allocated if we can't */ | |
384 | if (!allocated_early[type]) | |
385 | assert(!global_keys[type].created); | |
386 | else if (!allocated_early[type] (dixReallocPrivates, bytes)) | |
387 | return FALSE; | |
388 | offset = global_keys[type].offset; | |
389 | global_keys[type].offset += bytes; | |
390 | grow_screen_specific_set(type, bytes); | |
391 | } | |
392 | ||
393 | /* Setup this key */ | |
394 | key->offset = offset; | |
395 | key->size = size; | |
396 | key->initialized = TRUE; | |
397 | key->type = type; | |
398 | key->allocated = FALSE; | |
399 | key->next = global_keys[type].key; | |
400 | global_keys[type].key = key; | |
401 | ||
402 | return TRUE; | |
403 | } | |
404 | ||
405 | Bool | |
406 | dixRegisterScreenPrivateKey(DevScreenPrivateKey screenKey, ScreenPtr pScreen, | |
407 | DevPrivateType type, unsigned size) | |
408 | { | |
409 | DevPrivateKey key; | |
410 | ||
411 | if (!dixRegisterPrivateKey(&screenKey->screenKey, PRIVATE_SCREEN, 0)) | |
412 | return FALSE; | |
413 | key = dixGetPrivate(&pScreen->devPrivates, &screenKey->screenKey); | |
414 | if (key != NULL) { | |
415 | assert(key->size == size); | |
416 | assert(key->type == type); | |
417 | return TRUE; | |
418 | } | |
419 | key = calloc(sizeof(DevPrivateKeyRec), 1); | |
420 | if (!key) | |
421 | return FALSE; | |
422 | if (!dixRegisterPrivateKey(key, type, size)) { | |
423 | free(key); | |
424 | return FALSE; | |
425 | } | |
426 | key->allocated = TRUE; | |
427 | dixSetPrivate(&pScreen->devPrivates, &screenKey->screenKey, key); | |
428 | return TRUE; | |
429 | } | |
430 | ||
431 | DevPrivateKey | |
432 | _dixGetScreenPrivateKey(const DevScreenPrivateKey key, ScreenPtr pScreen) | |
433 | { | |
434 | return dixGetPrivate(&pScreen->devPrivates, &key->screenKey); | |
435 | } | |
436 | ||
437 | /* | |
438 | * Initialize privates by zeroing them | |
439 | */ | |
440 | void | |
441 | _dixInitPrivates(PrivatePtr *privates, void *addr, DevPrivateType type) | |
442 | { | |
443 | assert (!screen_specific_private[type]); | |
444 | ||
445 | global_keys[type].created++; | |
446 | if (xselinux_private[type]) | |
447 | global_keys[PRIVATE_XSELINUX].created++; | |
448 | if (global_keys[type].offset == 0) | |
449 | addr = 0; | |
450 | *privates = addr; | |
451 | memset(addr, '\0', global_keys[type].offset); | |
452 | } | |
453 | ||
454 | /* | |
455 | * Clean up privates | |
456 | */ | |
457 | void | |
458 | _dixFiniPrivates(PrivatePtr privates, DevPrivateType type) | |
459 | { | |
460 | global_keys[type].created--; | |
461 | if (xselinux_private[type]) | |
462 | global_keys[PRIVATE_XSELINUX].created--; | |
463 | } | |
464 | ||
465 | /* | |
466 | * Allocate new object with privates. | |
467 | * | |
468 | * This is expected to be invoked from the | |
469 | * dixAllocateObjectWithPrivates macro | |
470 | */ | |
471 | void * | |
472 | _dixAllocateObjectWithPrivates(unsigned baseSize, unsigned clear, | |
473 | unsigned offset, DevPrivateType type) | |
474 | { | |
475 | unsigned totalSize; | |
476 | void *object; | |
477 | PrivatePtr privates; | |
478 | PrivatePtr *devPrivates; | |
479 | ||
480 | assert(type > PRIVATE_SCREEN && type < PRIVATE_LAST); | |
481 | assert(!screen_specific_private[type]); | |
482 | ||
483 | /* round up so that void * is aligned */ | |
484 | baseSize = (baseSize + sizeof(void *) - 1) & ~(sizeof(void *) - 1); | |
485 | totalSize = baseSize + global_keys[type].offset; | |
486 | object = malloc(totalSize); | |
487 | if (!object) | |
488 | return NULL; | |
489 | ||
490 | memset(object, '\0', clear); | |
491 | privates = (PrivatePtr) (((char *) object) + baseSize); | |
492 | devPrivates = (PrivatePtr *) ((char *) object + offset); | |
493 | ||
494 | _dixInitPrivates(devPrivates, privates, type); | |
495 | ||
496 | return object; | |
497 | } | |
498 | ||
499 | /* | |
500 | * Allocate privates separately from containing object. | |
501 | * Used for clients and screens. | |
502 | */ | |
503 | Bool | |
504 | dixAllocatePrivates(PrivatePtr *privates, DevPrivateType type) | |
505 | { | |
506 | unsigned size; | |
507 | PrivatePtr p; | |
508 | ||
509 | assert(type > PRIVATE_XSELINUX && 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 | */ | |
533 | void | |
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 | */ | |
544 | void | |
545 | dixFreePrivates(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 | */ | |
555 | extern _X_EXPORT int | |
556 | dixPrivatesSize(DevPrivateType type) | |
557 | { | |
558 | assert(type >= PRIVATE_SCREEN && type < PRIVATE_LAST); | |
559 | assert (!screen_specific_private[type]); | |
560 | ||
561 | return global_keys[type].offset; | |
562 | } | |
563 | ||
564 | /* Table of devPrivates offsets */ | |
565 | static const int offsets[] = { | |
566 | -1, /* RT_NONE */ | |
567 | offsetof(WindowRec, devPrivates), /* RT_WINDOW */ | |
568 | offsetof(PixmapRec, devPrivates), /* RT_PIXMAP */ | |
569 | offsetof(GC, devPrivates), /* RT_GC */ | |
570 | -1, /* RT_FONT */ | |
571 | offsetof(CursorRec, devPrivates), /* RT_CURSOR */ | |
572 | offsetof(ColormapRec, devPrivates), /* RT_COLORMAP */ | |
573 | }; | |
574 | ||
575 | #define NUM_OFFSETS (sizeof (offsets) / sizeof (offsets[0])) | |
576 | ||
577 | int | |
578 | dixLookupPrivateOffset(RESTYPE type) | |
579 | { | |
580 | /* | |
581 | * Special kludge for DBE which registers a new resource type that | |
582 | * points at pixmaps (thanks, DBE) | |
583 | */ | |
584 | if (type & RC_DRAWABLE) { | |
585 | if (type == RT_WINDOW) | |
586 | return offsets[RT_WINDOW & TypeMask]; | |
587 | else | |
588 | return offsets[RT_PIXMAP & TypeMask]; | |
589 | } | |
590 | type = type & TypeMask; | |
591 | if (type < NUM_OFFSETS) | |
592 | return offsets[type]; | |
593 | return -1; | |
594 | } | |
595 | ||
596 | /* | |
597 | * Screen-specific privates | |
598 | */ | |
599 | ||
600 | extern _X_EXPORT Bool | |
601 | dixRegisterScreenSpecificPrivateKey(ScreenPtr pScreen, DevPrivateKey key, | |
602 | DevPrivateType type, unsigned size) | |
603 | { | |
604 | int offset; | |
605 | unsigned bytes; | |
606 | ||
607 | if (!screen_specific_private[type]) | |
608 | FatalError("Attempt to allocate screen-specific private storage for type %s\n", | |
609 | key_names[type]); | |
610 | ||
611 | if (key->initialized) { | |
612 | assert(size == key->size); | |
613 | return TRUE; | |
614 | } | |
615 | ||
616 | /* Compute required space */ | |
617 | bytes = size; | |
618 | if (size == 0) | |
619 | bytes = sizeof(void *); | |
620 | ||
621 | /* align to void * size */ | |
622 | bytes = (bytes + sizeof(void *) - 1) & ~(sizeof(void *) - 1); | |
623 | ||
624 | assert (!allocated_early[type]); | |
625 | assert (!pScreen->screenSpecificPrivates[type].created); | |
626 | offset = pScreen->screenSpecificPrivates[type].offset; | |
627 | pScreen->screenSpecificPrivates[type].offset += bytes; | |
628 | ||
629 | /* Setup this key */ | |
630 | key->offset = offset; | |
631 | key->size = size; | |
632 | key->initialized = TRUE; | |
633 | key->type = type; | |
634 | key->allocated = FALSE; | |
635 | key->next = pScreen->screenSpecificPrivates[type].key; | |
636 | pScreen->screenSpecificPrivates[type].key = key; | |
637 | ||
638 | return TRUE; | |
639 | } | |
640 | ||
641 | /* Clean up screen-specific privates before CloseScreen */ | |
642 | void | |
643 | dixFreeScreenSpecificPrivates(ScreenPtr pScreen) | |
644 | { | |
645 | } | |
646 | ||
647 | /* Initialize screen-specific privates in AddScreen */ | |
648 | void | |
649 | dixInitScreenSpecificPrivates(ScreenPtr pScreen) | |
650 | { | |
651 | DevPrivateType t; | |
652 | ||
653 | for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) | |
654 | pScreen->screenSpecificPrivates[t].offset = global_keys[t].offset; | |
655 | } | |
656 | ||
657 | /* Initialize screen-specific privates in AddScreen */ | |
658 | void | |
659 | _dixInitScreenPrivates(ScreenPtr pScreen, PrivatePtr *privates, void *addr, DevPrivateType type) | |
660 | { | |
661 | int privates_size; | |
662 | assert (screen_specific_private[type]); | |
663 | ||
664 | if (pScreen) { | |
665 | privates_size = pScreen->screenSpecificPrivates[type].offset; | |
666 | pScreen->screenSpecificPrivates[type].created++; | |
667 | } | |
668 | else | |
669 | privates_size = global_keys[type].offset; | |
670 | ||
671 | global_keys[type].created++; | |
672 | if (xselinux_private[type]) | |
673 | global_keys[PRIVATE_XSELINUX].created++; | |
674 | if (privates_size == 0) | |
675 | addr = 0; | |
676 | *privates = addr; | |
677 | memset(addr, '\0', privates_size); | |
678 | } | |
679 | ||
680 | void * | |
681 | _dixAllocateScreenObjectWithPrivates(ScreenPtr pScreen, | |
682 | unsigned baseSize, | |
683 | unsigned clear, | |
684 | unsigned offset, | |
685 | DevPrivateType type) | |
686 | { | |
687 | unsigned totalSize; | |
688 | void *object; | |
689 | PrivatePtr privates; | |
690 | PrivatePtr *devPrivates; | |
691 | int privates_size; | |
692 | ||
693 | assert(type > PRIVATE_SCREEN && type < PRIVATE_LAST); | |
694 | assert (screen_specific_private[type]); | |
695 | ||
696 | if (pScreen) | |
697 | privates_size = pScreen->screenSpecificPrivates[type].offset; | |
698 | else | |
699 | privates_size = global_keys[type].offset; | |
700 | /* round up so that void * is aligned */ | |
701 | baseSize = (baseSize + sizeof(void *) - 1) & ~(sizeof(void *) - 1); | |
702 | totalSize = baseSize + privates_size; | |
703 | object = malloc(totalSize); | |
704 | if (!object) | |
705 | return NULL; | |
706 | ||
707 | memset(object, '\0', clear); | |
708 | privates = (PrivatePtr) (((char *) object) + baseSize); | |
709 | devPrivates = (PrivatePtr *) ((char *) object + offset); | |
710 | ||
711 | _dixInitScreenPrivates(pScreen, devPrivates, privates, type); | |
712 | ||
713 | return object; | |
714 | } | |
715 | ||
716 | int | |
717 | dixScreenSpecificPrivatesSize(ScreenPtr pScreen, DevPrivateType type) | |
718 | { | |
719 | assert(type >= PRIVATE_SCREEN && type < PRIVATE_LAST); | |
720 | ||
721 | if (screen_specific_private[type]) | |
722 | return pScreen->screenSpecificPrivates[type].offset; | |
723 | else | |
724 | return global_keys[type].offset; | |
725 | } | |
726 | ||
727 | void | |
728 | dixPrivateUsage(void) | |
729 | { | |
730 | int objects = 0; | |
731 | int bytes = 0; | |
732 | int alloc = 0; | |
733 | DevPrivateType t; | |
734 | ||
735 | for (t = PRIVATE_XSELINUX + 1; t < PRIVATE_LAST; t++) { | |
736 | if (global_keys[t].offset) { | |
737 | ErrorF | |
738 | ("%s: %d objects of %d bytes = %d total bytes %d private allocs\n", | |
739 | key_names[t], global_keys[t].created, global_keys[t].offset, | |
740 | global_keys[t].created * global_keys[t].offset, global_keys[t].allocated); | |
741 | bytes += global_keys[t].created * global_keys[t].offset; | |
742 | objects += global_keys[t].created; | |
743 | alloc += global_keys[t].allocated; | |
744 | } | |
745 | } | |
746 | ErrorF("TOTAL: %d objects, %d bytes, %d allocs\n", objects, bytes, alloc); | |
747 | } | |
748 | ||
749 | void | |
750 | dixResetPrivates(void) | |
751 | { | |
752 | DevPrivateType t; | |
753 | ||
754 | for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) { | |
755 | DevPrivateKey key, next; | |
756 | ||
757 | for (key = global_keys[t].key; key; key = next) { | |
758 | next = key->next; | |
759 | key->offset = 0; | |
760 | key->initialized = FALSE; | |
761 | key->size = 0; | |
762 | key->type = 0; | |
763 | if (key->allocated) | |
764 | free(key); | |
765 | } | |
766 | if (global_keys[t].created) { | |
767 | ErrorF("%d %ss still allocated at reset\n", | |
768 | global_keys[t].created, key_names[t]); | |
769 | dixPrivateUsage(); | |
770 | } | |
771 | global_keys[t].key = NULL; | |
772 | global_keys[t].offset = 0; | |
773 | global_keys[t].created = 0; | |
774 | global_keys[t].allocated = 0; | |
775 | } | |
776 | } |