| 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 | } |