| 1 | /* |
| 2 | |
| 3 | Copyright 1993 by Davor Matic |
| 4 | |
| 5 | Permission to use, copy, modify, distribute, and sell this software |
| 6 | and its documentation for any purpose is hereby granted without fee, |
| 7 | provided that the above copyright notice appear in all copies and that |
| 8 | both that copyright notice and this permission notice appear in |
| 9 | supporting documentation. Davor Matic makes no representations about |
| 10 | the suitability of this software for any purpose. It is provided "as |
| 11 | is" without express or implied warranty. |
| 12 | |
| 13 | */ |
| 14 | |
| 15 | #ifdef HAVE_XNEST_CONFIG_H |
| 16 | #include <xnest-config.h> |
| 17 | #endif |
| 18 | |
| 19 | #include <X11/X.h> |
| 20 | #include <X11/Xproto.h> |
| 21 | #include "scrnintstr.h" |
| 22 | #include "window.h" |
| 23 | #include "windowstr.h" |
| 24 | #include "colormapst.h" |
| 25 | #include "resource.h" |
| 26 | |
| 27 | #include "Xnest.h" |
| 28 | |
| 29 | #include "Display.h" |
| 30 | #include "Screen.h" |
| 31 | #include "Color.h" |
| 32 | #include "Visual.h" |
| 33 | #include "XNWindow.h" |
| 34 | #include "Args.h" |
| 35 | |
| 36 | DevPrivateKeyRec xnestColormapPrivateKeyRec; |
| 37 | |
| 38 | static DevPrivateKeyRec cmapScrPrivateKeyRec; |
| 39 | |
| 40 | #define cmapScrPrivateKey (&cmapScrPrivateKeyRec) |
| 41 | |
| 42 | #define GetInstalledColormap(s) ((ColormapPtr) dixLookupPrivate(&(s)->devPrivates, cmapScrPrivateKey)) |
| 43 | #define SetInstalledColormap(s,c) (dixSetPrivate(&(s)->devPrivates, cmapScrPrivateKey, c)) |
| 44 | |
| 45 | Bool |
| 46 | xnestCreateColormap(ColormapPtr pCmap) |
| 47 | { |
| 48 | VisualPtr pVisual; |
| 49 | XColor *colors; |
| 50 | int i, ncolors; |
| 51 | Pixel red, green, blue; |
| 52 | Pixel redInc, greenInc, blueInc; |
| 53 | |
| 54 | pVisual = pCmap->pVisual; |
| 55 | ncolors = pVisual->ColormapEntries; |
| 56 | |
| 57 | xnestColormapPriv(pCmap)->colormap = |
| 58 | XCreateColormap(xnestDisplay, |
| 59 | xnestDefaultWindows[pCmap->pScreen->myNum], |
| 60 | xnestVisual(pVisual), |
| 61 | (pVisual->class & DynamicClass) ? AllocAll : AllocNone); |
| 62 | |
| 63 | switch (pVisual->class) { |
| 64 | case StaticGray: /* read only */ |
| 65 | colors = (XColor *) malloc(ncolors * sizeof(XColor)); |
| 66 | for (i = 0; i < ncolors; i++) |
| 67 | colors[i].pixel = i; |
| 68 | XQueryColors(xnestDisplay, xnestColormap(pCmap), colors, ncolors); |
| 69 | for (i = 0; i < ncolors; i++) { |
| 70 | pCmap->red[i].co.local.red = colors[i].red; |
| 71 | pCmap->red[i].co.local.green = colors[i].red; |
| 72 | pCmap->red[i].co.local.blue = colors[i].red; |
| 73 | } |
| 74 | free(colors); |
| 75 | break; |
| 76 | |
| 77 | case StaticColor: /* read only */ |
| 78 | colors = (XColor *) malloc(ncolors * sizeof(XColor)); |
| 79 | for (i = 0; i < ncolors; i++) |
| 80 | colors[i].pixel = i; |
| 81 | XQueryColors(xnestDisplay, xnestColormap(pCmap), colors, ncolors); |
| 82 | for (i = 0; i < ncolors; i++) { |
| 83 | pCmap->red[i].co.local.red = colors[i].red; |
| 84 | pCmap->red[i].co.local.green = colors[i].green; |
| 85 | pCmap->red[i].co.local.blue = colors[i].blue; |
| 86 | } |
| 87 | free(colors); |
| 88 | break; |
| 89 | |
| 90 | case TrueColor: /* read only */ |
| 91 | colors = (XColor *) malloc(ncolors * sizeof(XColor)); |
| 92 | red = green = blue = 0L; |
| 93 | redInc = lowbit(pVisual->redMask); |
| 94 | greenInc = lowbit(pVisual->greenMask); |
| 95 | blueInc = lowbit(pVisual->blueMask); |
| 96 | for (i = 0; i < ncolors; i++) { |
| 97 | colors[i].pixel = red | green | blue; |
| 98 | red += redInc; |
| 99 | if (red > pVisual->redMask) |
| 100 | red = 0L; |
| 101 | green += greenInc; |
| 102 | if (green > pVisual->greenMask) |
| 103 | green = 0L; |
| 104 | blue += blueInc; |
| 105 | if (blue > pVisual->blueMask) |
| 106 | blue = 0L; |
| 107 | } |
| 108 | XQueryColors(xnestDisplay, xnestColormap(pCmap), colors, ncolors); |
| 109 | for (i = 0; i < ncolors; i++) { |
| 110 | pCmap->red[i].co.local.red = colors[i].red; |
| 111 | pCmap->green[i].co.local.green = colors[i].green; |
| 112 | pCmap->blue[i].co.local.blue = colors[i].blue; |
| 113 | } |
| 114 | free(colors); |
| 115 | break; |
| 116 | |
| 117 | case GrayScale: /* read and write */ |
| 118 | break; |
| 119 | |
| 120 | case PseudoColor: /* read and write */ |
| 121 | break; |
| 122 | |
| 123 | case DirectColor: /* read and write */ |
| 124 | break; |
| 125 | } |
| 126 | |
| 127 | return True; |
| 128 | } |
| 129 | |
| 130 | void |
| 131 | xnestDestroyColormap(ColormapPtr pCmap) |
| 132 | { |
| 133 | XFreeColormap(xnestDisplay, xnestColormap(pCmap)); |
| 134 | } |
| 135 | |
| 136 | #define SEARCH_PREDICATE \ |
| 137 | (xnestWindow(pWin) != None && wColormap(pWin) == icws->cmapIDs[i]) |
| 138 | |
| 139 | static int |
| 140 | xnestCountInstalledColormapWindows(WindowPtr pWin, pointer ptr) |
| 141 | { |
| 142 | xnestInstalledColormapWindows *icws = (xnestInstalledColormapWindows *) ptr; |
| 143 | int i; |
| 144 | |
| 145 | for (i = 0; i < icws->numCmapIDs; i++) |
| 146 | if (SEARCH_PREDICATE) { |
| 147 | icws->numWindows++; |
| 148 | return WT_DONTWALKCHILDREN; |
| 149 | } |
| 150 | |
| 151 | return WT_WALKCHILDREN; |
| 152 | } |
| 153 | |
| 154 | static int |
| 155 | xnestGetInstalledColormapWindows(WindowPtr pWin, pointer ptr) |
| 156 | { |
| 157 | xnestInstalledColormapWindows *icws = (xnestInstalledColormapWindows *) ptr; |
| 158 | int i; |
| 159 | |
| 160 | for (i = 0; i < icws->numCmapIDs; i++) |
| 161 | if (SEARCH_PREDICATE) { |
| 162 | icws->windows[icws->index++] = xnestWindow(pWin); |
| 163 | return WT_DONTWALKCHILDREN; |
| 164 | } |
| 165 | |
| 166 | return WT_WALKCHILDREN; |
| 167 | } |
| 168 | |
| 169 | static Window *xnestOldInstalledColormapWindows = NULL; |
| 170 | static int xnestNumOldInstalledColormapWindows = 0; |
| 171 | |
| 172 | static Bool |
| 173 | xnestSameInstalledColormapWindows(Window *windows, int numWindows) |
| 174 | { |
| 175 | if (xnestNumOldInstalledColormapWindows != numWindows) |
| 176 | return False; |
| 177 | |
| 178 | if (xnestOldInstalledColormapWindows == windows) |
| 179 | return True; |
| 180 | |
| 181 | if (xnestOldInstalledColormapWindows == NULL || windows == NULL) |
| 182 | return False; |
| 183 | |
| 184 | if (memcmp(xnestOldInstalledColormapWindows, windows, |
| 185 | numWindows * sizeof(Window))) |
| 186 | return False; |
| 187 | |
| 188 | return True; |
| 189 | } |
| 190 | |
| 191 | void |
| 192 | xnestSetInstalledColormapWindows(ScreenPtr pScreen) |
| 193 | { |
| 194 | xnestInstalledColormapWindows icws; |
| 195 | int numWindows; |
| 196 | |
| 197 | icws.cmapIDs = (Colormap *) malloc(pScreen->maxInstalledCmaps * |
| 198 | sizeof(Colormap)); |
| 199 | icws.numCmapIDs = xnestListInstalledColormaps(pScreen, icws.cmapIDs); |
| 200 | icws.numWindows = 0; |
| 201 | WalkTree(pScreen, xnestCountInstalledColormapWindows, (pointer) &icws); |
| 202 | if (icws.numWindows) { |
| 203 | icws.windows = |
| 204 | (Window *) malloc((icws.numWindows + 1) * sizeof(Window)); |
| 205 | icws.index = 0; |
| 206 | WalkTree(pScreen, xnestGetInstalledColormapWindows, (pointer) &icws); |
| 207 | icws.windows[icws.numWindows] = xnestDefaultWindows[pScreen->myNum]; |
| 208 | numWindows = icws.numWindows + 1; |
| 209 | } |
| 210 | else { |
| 211 | icws.windows = NULL; |
| 212 | numWindows = 0; |
| 213 | } |
| 214 | |
| 215 | free(icws.cmapIDs); |
| 216 | |
| 217 | if (!xnestSameInstalledColormapWindows(icws.windows, icws.numWindows)) { |
| 218 | free(xnestOldInstalledColormapWindows); |
| 219 | |
| 220 | #ifdef _XSERVER64 |
| 221 | { |
| 222 | int i; |
| 223 | Window64 *windows = |
| 224 | (Window64 *) malloc(numWindows * sizeof(Window64)); |
| 225 | |
| 226 | for (i = 0; i < numWindows; ++i) |
| 227 | windows[i] = icws.windows[i]; |
| 228 | XSetWMColormapWindows(xnestDisplay, |
| 229 | xnestDefaultWindows[pScreen->myNum], windows, |
| 230 | numWindows); |
| 231 | free(windows); |
| 232 | } |
| 233 | #else |
| 234 | XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], |
| 235 | icws.windows, numWindows); |
| 236 | #endif |
| 237 | |
| 238 | xnestOldInstalledColormapWindows = icws.windows; |
| 239 | xnestNumOldInstalledColormapWindows = icws.numWindows; |
| 240 | |
| 241 | #ifdef DUMB_WINDOW_MANAGERS |
| 242 | /* |
| 243 | This code is for dumb window managers. |
| 244 | This will only work with default local visual colormaps. |
| 245 | */ |
| 246 | if (icws.numWindows) { |
| 247 | WindowPtr pWin; |
| 248 | Visual *visual; |
| 249 | ColormapPtr pCmap; |
| 250 | |
| 251 | pWin = xnestWindowPtr(icws.windows[0]); |
| 252 | visual = xnestVisualFromID(pScreen, wVisual(pWin)); |
| 253 | |
| 254 | if (visual == xnestDefaultVisual(pScreen)) |
| 255 | dixLookupResourceByType((pointer *) &pCmap, wColormap(pWin), |
| 256 | RT_COLORMAP, serverClient, |
| 257 | DixUseAccess); |
| 258 | else |
| 259 | dixLookupResourceByType((pointer *) &pCmap, |
| 260 | pScreen->defColormap, RT_COLORMAP, |
| 261 | serverClient, DixUseAccess); |
| 262 | |
| 263 | XSetWindowColormap(xnestDisplay, |
| 264 | xnestDefaultWindows[pScreen->myNum], |
| 265 | xnestColormap(pCmap)); |
| 266 | } |
| 267 | #endif /* DUMB_WINDOW_MANAGERS */ |
| 268 | } |
| 269 | else |
| 270 | free(icws.windows); |
| 271 | } |
| 272 | |
| 273 | void |
| 274 | xnestSetScreenSaverColormapWindow(ScreenPtr pScreen) |
| 275 | { |
| 276 | free(xnestOldInstalledColormapWindows); |
| 277 | |
| 278 | #ifdef _XSERVER64 |
| 279 | { |
| 280 | Window64 window; |
| 281 | |
| 282 | window = xnestScreenSaverWindows[pScreen->myNum]; |
| 283 | XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], |
| 284 | &window, 1); |
| 285 | xnestScreenSaverWindows[pScreen->myNum] = window; |
| 286 | } |
| 287 | #else |
| 288 | XSetWMColormapWindows(xnestDisplay, xnestDefaultWindows[pScreen->myNum], |
| 289 | &xnestScreenSaverWindows[pScreen->myNum], 1); |
| 290 | #endif /* _XSERVER64 */ |
| 291 | |
| 292 | xnestOldInstalledColormapWindows = NULL; |
| 293 | xnestNumOldInstalledColormapWindows = 0; |
| 294 | |
| 295 | xnestDirectUninstallColormaps(pScreen); |
| 296 | } |
| 297 | |
| 298 | void |
| 299 | xnestDirectInstallColormaps(ScreenPtr pScreen) |
| 300 | { |
| 301 | int i, n; |
| 302 | Colormap pCmapIDs[MAXCMAPS]; |
| 303 | |
| 304 | if (!xnestDoDirectColormaps) |
| 305 | return; |
| 306 | |
| 307 | n = (*pScreen->ListInstalledColormaps) (pScreen, pCmapIDs); |
| 308 | |
| 309 | for (i = 0; i < n; i++) { |
| 310 | ColormapPtr pCmap; |
| 311 | |
| 312 | dixLookupResourceByType((pointer *) &pCmap, pCmapIDs[i], RT_COLORMAP, |
| 313 | serverClient, DixInstallAccess); |
| 314 | if (pCmap) |
| 315 | XInstallColormap(xnestDisplay, xnestColormap(pCmap)); |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | void |
| 320 | xnestDirectUninstallColormaps(ScreenPtr pScreen) |
| 321 | { |
| 322 | int i, n; |
| 323 | Colormap pCmapIDs[MAXCMAPS]; |
| 324 | |
| 325 | if (!xnestDoDirectColormaps) |
| 326 | return; |
| 327 | |
| 328 | n = (*pScreen->ListInstalledColormaps) (pScreen, pCmapIDs); |
| 329 | |
| 330 | for (i = 0; i < n; i++) { |
| 331 | ColormapPtr pCmap; |
| 332 | |
| 333 | dixLookupResourceByType((pointer *) &pCmap, pCmapIDs[i], RT_COLORMAP, |
| 334 | serverClient, DixUninstallAccess); |
| 335 | if (pCmap) |
| 336 | XUninstallColormap(xnestDisplay, xnestColormap(pCmap)); |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | void |
| 341 | xnestInstallColormap(ColormapPtr pCmap) |
| 342 | { |
| 343 | ColormapPtr pOldCmap = GetInstalledColormap(pCmap->pScreen); |
| 344 | |
| 345 | if (pCmap != pOldCmap) { |
| 346 | xnestDirectUninstallColormaps(pCmap->pScreen); |
| 347 | |
| 348 | /* Uninstall pInstalledMap. Notify all interested parties. */ |
| 349 | if (pOldCmap != (ColormapPtr) None) |
| 350 | WalkTree(pCmap->pScreen, TellLostMap, (pointer) &pOldCmap->mid); |
| 351 | |
| 352 | SetInstalledColormap(pCmap->pScreen, pCmap); |
| 353 | WalkTree(pCmap->pScreen, TellGainedMap, (pointer) &pCmap->mid); |
| 354 | |
| 355 | xnestSetInstalledColormapWindows(pCmap->pScreen); |
| 356 | xnestDirectInstallColormaps(pCmap->pScreen); |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | void |
| 361 | xnestUninstallColormap(ColormapPtr pCmap) |
| 362 | { |
| 363 | ColormapPtr pCurCmap = GetInstalledColormap(pCmap->pScreen); |
| 364 | |
| 365 | if (pCmap == pCurCmap) { |
| 366 | if (pCmap->mid != pCmap->pScreen->defColormap) { |
| 367 | dixLookupResourceByType((pointer *) &pCurCmap, |
| 368 | pCmap->pScreen->defColormap, |
| 369 | RT_COLORMAP, |
| 370 | serverClient, DixInstallAccess); |
| 371 | (*pCmap->pScreen->InstallColormap) (pCurCmap); |
| 372 | } |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | static Bool xnestInstalledDefaultColormap = False; |
| 377 | |
| 378 | int |
| 379 | xnestListInstalledColormaps(ScreenPtr pScreen, Colormap * pCmapIDs) |
| 380 | { |
| 381 | if (xnestInstalledDefaultColormap) { |
| 382 | *pCmapIDs = GetInstalledColormap(pScreen)->mid; |
| 383 | return 1; |
| 384 | } |
| 385 | else |
| 386 | return 0; |
| 387 | } |
| 388 | |
| 389 | void |
| 390 | xnestStoreColors(ColormapPtr pCmap, int nColors, xColorItem * pColors) |
| 391 | { |
| 392 | if (pCmap->pVisual->class & DynamicClass) |
| 393 | #ifdef _XSERVER64 |
| 394 | { |
| 395 | int i; |
| 396 | XColor *pColors64 = (XColor *) malloc(nColors * sizeof(XColor)); |
| 397 | |
| 398 | for (i = 0; i < nColors; ++i) { |
| 399 | pColors64[i].pixel = pColors[i].pixel; |
| 400 | pColors64[i].red = pColors[i].red; |
| 401 | pColors64[i].green = pColors[i].green; |
| 402 | pColors64[i].blue = pColors[i].blue; |
| 403 | pColors64[i].flags = pColors[i].flags; |
| 404 | } |
| 405 | XStoreColors(xnestDisplay, xnestColormap(pCmap), pColors64, nColors); |
| 406 | free(pColors64); |
| 407 | } |
| 408 | #else |
| 409 | XStoreColors(xnestDisplay, xnestColormap(pCmap), |
| 410 | (XColor *) pColors, nColors); |
| 411 | #endif |
| 412 | } |
| 413 | |
| 414 | void |
| 415 | xnestResolveColor(unsigned short *pRed, unsigned short *pGreen, |
| 416 | unsigned short *pBlue, VisualPtr pVisual) |
| 417 | { |
| 418 | int shift; |
| 419 | unsigned int lim; |
| 420 | |
| 421 | shift = 16 - pVisual->bitsPerRGBValue; |
| 422 | lim = (1 << pVisual->bitsPerRGBValue) - 1; |
| 423 | |
| 424 | if ((pVisual->class == PseudoColor) || (pVisual->class == DirectColor)) { |
| 425 | /* rescale to rgb bits */ |
| 426 | *pRed = ((*pRed >> shift) * 65535) / lim; |
| 427 | *pGreen = ((*pGreen >> shift) * 65535) / lim; |
| 428 | *pBlue = ((*pBlue >> shift) * 65535) / lim; |
| 429 | } |
| 430 | else if (pVisual->class == GrayScale) { |
| 431 | /* rescale to gray then rgb bits */ |
| 432 | *pRed = (30L * *pRed + 59L * *pGreen + 11L * *pBlue) / 100; |
| 433 | *pBlue = *pGreen = *pRed = ((*pRed >> shift) * 65535) / lim; |
| 434 | } |
| 435 | else if (pVisual->class == StaticGray) { |
| 436 | unsigned int limg; |
| 437 | |
| 438 | limg = pVisual->ColormapEntries - 1; |
| 439 | /* rescale to gray then [0..limg] then [0..65535] then rgb bits */ |
| 440 | *pRed = (30L * *pRed + 59L * *pGreen + 11L * *pBlue) / 100; |
| 441 | *pRed = ((((*pRed * (limg + 1))) >> 16) * 65535) / limg; |
| 442 | *pBlue = *pGreen = *pRed = ((*pRed >> shift) * 65535) / lim; |
| 443 | } |
| 444 | else { |
| 445 | unsigned limr, limg, limb; |
| 446 | |
| 447 | limr = pVisual->redMask >> pVisual->offsetRed; |
| 448 | limg = pVisual->greenMask >> pVisual->offsetGreen; |
| 449 | limb = pVisual->blueMask >> pVisual->offsetBlue; |
| 450 | /* rescale to [0..limN] then [0..65535] then rgb bits */ |
| 451 | *pRed = ((((((*pRed * (limr + 1)) >> 16) * |
| 452 | 65535) / limr) >> shift) * 65535) / lim; |
| 453 | *pGreen = ((((((*pGreen * (limg + 1)) >> 16) * |
| 454 | 65535) / limg) >> shift) * 65535) / lim; |
| 455 | *pBlue = ((((((*pBlue * (limb + 1)) >> 16) * |
| 456 | 65535) / limb) >> shift) * 65535) / lim; |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | Bool |
| 461 | xnestCreateDefaultColormap(ScreenPtr pScreen) |
| 462 | { |
| 463 | VisualPtr pVisual; |
| 464 | ColormapPtr pCmap; |
| 465 | unsigned short zero = 0, ones = 0xFFFF; |
| 466 | Pixel wp, bp; |
| 467 | |
| 468 | if (!dixRegisterPrivateKey(&cmapScrPrivateKeyRec, PRIVATE_SCREEN, 0)) |
| 469 | return FALSE; |
| 470 | |
| 471 | for (pVisual = pScreen->visuals; |
| 472 | pVisual->vid != pScreen->rootVisual; pVisual++); |
| 473 | |
| 474 | if (CreateColormap(pScreen->defColormap, pScreen, pVisual, &pCmap, |
| 475 | (pVisual->class & DynamicClass) ? AllocNone : AllocAll, |
| 476 | 0) |
| 477 | != Success) |
| 478 | return False; |
| 479 | |
| 480 | wp = pScreen->whitePixel; |
| 481 | bp = pScreen->blackPixel; |
| 482 | if ((AllocColor(pCmap, &ones, &ones, &ones, &wp, 0) != |
| 483 | Success) || |
| 484 | (AllocColor(pCmap, &zero, &zero, &zero, &bp, 0) != Success)) |
| 485 | return FALSE; |
| 486 | pScreen->whitePixel = wp; |
| 487 | pScreen->blackPixel = bp; |
| 488 | (*pScreen->InstallColormap) (pCmap); |
| 489 | |
| 490 | xnestInstalledDefaultColormap = True; |
| 491 | |
| 492 | return True; |
| 493 | } |