1 2 /* 3 * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc. 4 * All Rights Reserved 5 * 6 * This file is a component of an X Window System-specific implementation 7 * of Xcms based on the TekColor Color Management System. Permission is 8 * hereby granted to use, copy, modify, sell, and otherwise distribute this 9 * software and its documentation for any purpose and without fee, provided 10 * that this copyright, permission, and disclaimer notice is reproduced in 11 * all copies of this software and in supporting documentation. TekColor 12 * is a trademark of Tektronix, Inc. 13 * 14 * Tektronix makes no representation about the suitability of this software 15 * for any purpose. It is provided "as is" and with all faults. 16 * 17 * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE, 18 * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 19 * PARTICULAR PURPOSE. IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY 20 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 21 * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF 22 * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 23 * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE. 24 * 25 * 26 * NAME 27 * XcmsCmap.c - Client Colormap Management Routines 28 * 29 * DESCRIPTION 30 * Routines that store additional information about 31 * colormaps being used by the X Client. 32 * 33 * 34 */ 35 36 #ifdef HAVE_CONFIG_H 37 #include <config.h> 38 #endif 39 #include "Xlibint.h" 40 #include "Xcmsint.h" 41 #include "Xutil.h" 42 #include "Cmap.h" 43 #include "Cv.h" 44 45 /* 46 * FORWARD DECLARATIONS 47 */ 48 static void _XcmsFreeClientCmaps(Display *dpy); 49 50 51 /************************************************************************ 53 * * 54 * PRIVATE INTERFACES * 55 * * 56 ************************************************************************/ 57 58 /* 59 * NAME 60 * CmapRecForColormap 61 * 62 * SYNOPSIS 63 */ 64 static XcmsCmapRec * 65 CmapRecForColormap( 66 Display *dpy, 67 Colormap cmap) 68 /* 69 * DESCRIPTION 70 * Find the corresponding XcmsCmapRec for cmap. In not found 71 * this routines attempts to create one. 72 * 73 * RETURNS 74 * Returns NULL if failed; otherwise the address to 75 * the corresponding XcmsCmapRec. 76 * 77 */ 78 { 79 XcmsCmapRec *pRec; 80 int nScrn; 81 int i, j; 82 XVisualInfo visualTemplate; /* Template of the visual we want */ 83 XVisualInfo *visualList; /* List for visuals that match */ 84 int nVisualsMatched; /* Number of visuals that match */ 85 Window tmpWindow; 86 Visual *vp; 87 unsigned long border = 0; 88 _XAsyncHandler async; 89 _XAsyncErrorState async_state; 90 91 LockDisplay(dpy); 92 for (pRec = (XcmsCmapRec *)dpy->cms.clientCmaps; pRec != NULL; 93 pRec = pRec->pNext) { 94 if (pRec->cmapID == cmap) { 95 UnlockDisplay(dpy); 96 SyncHandle(); 97 return(pRec); 98 } 99 } 100 UnlockDisplay(dpy); 101 SyncHandle(); 102 103 /* 104 * Can't find an XcmsCmapRec associated with cmap in our records. 105 * Let's try to see if its a default colormap 106 */ 107 nScrn = ScreenCount(dpy); 108 for (i = 0; i < nScrn; i++) { 109 if (cmap == DefaultColormap(dpy, i)) { 110 /* It is ... lets go ahead and store that info */ 111 if ((pRec = _XcmsAddCmapRec(dpy, cmap, RootWindow(dpy, i), 112 DefaultVisual(dpy, i))) == NULL) { 113 return((XcmsCmapRec *)NULL); 114 } 115 pRec->ccc = XcmsCreateCCC( 116 dpy, 117 i, /* screenNumber */ 118 DefaultVisual(dpy, i), 119 (XcmsColor *)NULL, /* clientWhitePt */ 120 (XcmsCompressionProc)NULL, /* gamutCompProc */ 121 (XPointer)NULL, /* gamutCompClientData */ 122 (XcmsWhiteAdjustProc)NULL, /* whitePtAdjProc */ 123 (XPointer)NULL /* whitePtAdjClientData */ 124 ); 125 return(pRec); 126 } 127 } 128 129 /* 130 * Nope, its not a default colormap, so it's probably a foreign color map 131 * of which we have no specific details. Let's go through the 132 * rigorous process of finding this colormap: 133 * for each screen 134 * for each screen's visual types 135 * create a window with cmap specified as the colormap 136 * if successful 137 * Add a CmapRec 138 * Create an XcmsCCC 139 * return the CmapRec 140 * else 141 * continue 142 */ 143 144 async_state.error_code = 0; /* don't care */ 145 async_state.major_opcode = X_CreateWindow; 146 async_state.minor_opcode = 0; 147 for (i = 0; i < nScrn; i++) { 148 visualTemplate.screen = i; 149 visualList = XGetVisualInfo(dpy, VisualScreenMask, &visualTemplate, 150 &nVisualsMatched); 151 if (visualList == NULL) { 152 continue; 153 } 154 155 /* 156 * Attempt to create a window with cmap 157 */ 158 j = 0; 159 do { 160 vp = (visualList+j)->visual; 161 LockDisplay(dpy); 162 { 163 register xCreateWindowReq *req; 164 165 GetReq(CreateWindow, req); 166 async_state.min_sequence_number = dpy->request; 167 async_state.max_sequence_number = dpy->request; 168 async_state.error_count = 0; 169 async.next = dpy->async_handlers; 170 async.handler = _XAsyncErrorHandler; 171 async.data = (XPointer)&async_state; 172 dpy->async_handlers = &async; 173 req->parent = RootWindow(dpy, i); 174 req->x = 0; 175 req->y = 0; 176 req->width = 1; 177 req->height = 1; 178 req->borderWidth = 0; 179 req->depth = (visualList+j)->depth; 180 req->class = CopyFromParent; 181 req->visual = vp->visualid; 182 tmpWindow = req->wid = XAllocID(dpy); 183 req->mask = CWBorderPixel | CWColormap; 184 req->length += 2; 185 Data32 (dpy, (long *) &border, 4); 186 Data32 (dpy, (long *) &cmap, 4); 187 } 188 { 189 xGetInputFocusReply rep; 190 _X_UNUSED register xReq *req; 191 192 GetEmptyReq(GetInputFocus, req); 193 (void) _XReply (dpy, (xReply *)&rep, 0, xTrue); 194 } 195 DeqAsyncHandler(dpy, &async); 196 UnlockDisplay(dpy); 197 SyncHandle(); 198 } while (async_state.error_count > 0 && ++j < nVisualsMatched); 199 200 Xfree(visualList); 201 202 /* 203 * if successful 204 */ 205 if (j < nVisualsMatched) { 206 if ((pRec = _XcmsAddCmapRec(dpy, cmap, tmpWindow, vp)) == NULL) 207 return((XcmsCmapRec *)NULL); 208 pRec->ccc = XcmsCreateCCC( 209 dpy, 210 i, /* screenNumber */ 211 vp, 212 (XcmsColor *)NULL, /* clientWhitePt */ 213 (XcmsCompressionProc)NULL, /* gamutCompProc */ 214 (XPointer)NULL, /* gamutCompClientData */ 215 (XcmsWhiteAdjustProc)NULL, /* whitePtAdjProc */ 216 (XPointer)NULL /* whitePtAdjClientData */ 217 ); 218 XDestroyWindow(dpy, tmpWindow); 219 return(pRec); 220 } 221 } 222 223 return(NULL); 224 } 225 226 227 228 /************************************************************************ 230 * * 231 * API PRIVATE INTERFACES * 232 * * 233 ************************************************************************/ 234 235 /* 236 * NAME 237 * _XcmsAddCmapRec 238 * 239 * SYNOPSIS 240 */ 241 XcmsCmapRec * 242 _XcmsAddCmapRec( 243 Display *dpy, 244 Colormap cmap, 245 Window windowID, 246 Visual *visual) 247 /* 248 * DESCRIPTION 249 * Create an XcmsCmapRec for the specified cmap, windowID, 250 * and visual, then adds it to its list of CmapRec's. 251 * 252 * RETURNS 253 * Returns NULL if failed; otherwise the address to 254 * the added XcmsCmapRec. 255 * 256 */ 257 { 258 XcmsCmapRec *pNew; 259 260 if ((pNew = Xcalloc(1, sizeof(XcmsCmapRec))) == NULL) { 261 return((XcmsCmapRec *)NULL); 262 } 263 264 pNew->cmapID = cmap; 265 pNew->dpy = dpy; 266 pNew->windowID = windowID; 267 pNew->visual = visual; 268 LockDisplay(dpy); 269 pNew->pNext = (XcmsCmapRec *)dpy->cms.clientCmaps; 270 dpy->cms.clientCmaps = (XPointer)pNew; 271 dpy->free_funcs->clientCmaps = _XcmsFreeClientCmaps; 272 UnlockDisplay(dpy); 273 SyncHandle(); 274 275 /* 276 * Note, we don't create the XcmsCCC for pNew->ccc here because 277 * it may require the use of XGetWindowAttributes (a round trip request) 278 * to determine the screen. 279 */ 280 return(pNew); 281 } 282 283 284 /* 286 * NAME 287 * _XcmsCopyCmapRecAndFree 288 * 289 * SYNOPSIS 290 */ 291 XcmsCmapRec * 292 _XcmsCopyCmapRecAndFree( 293 Display *dpy, 294 Colormap src_cmap, 295 Colormap copy_cmap) 296 /* 297 * DESCRIPTION 298 * Augments Xlib's XCopyColormapAndFree() to copy 299 * XcmsCmapRecs. 300 * 301 * RETURNS 302 * Returns NULL if failed; otherwise the address to 303 * the copy XcmsCmapRec. 304 * 305 */ 306 { 307 XcmsCmapRec *pRec_src; 308 XcmsCmapRec *pRec_copy; 309 310 if ((pRec_src = CmapRecForColormap(dpy, src_cmap)) != NULL) { 311 pRec_copy =_XcmsAddCmapRec(dpy, copy_cmap, pRec_src->windowID, 312 pRec_src->visual); 313 if (pRec_copy != NULL && pRec_src->ccc) { 314 pRec_copy->ccc = Xcalloc(1, sizeof(XcmsCCCRec)); 315 memcpy((char *)pRec_copy->ccc, (char *)pRec_src->ccc, 316 sizeof(XcmsCCCRec)); 317 } 318 return(pRec_copy); 319 } 320 return((XcmsCmapRec *)NULL); 321 } 322 323 324 /* 326 * NAME 327 * _XcmsDeleteCmapRec 328 * 329 * SYNOPSIS 330 */ 331 void 332 _XcmsDeleteCmapRec( 333 Display *dpy, 334 Colormap cmap) 335 /* 336 * DESCRIPTION 337 * Removes and frees the specified XcmsCmapRec structure 338 * from the linked list of structures. 339 * 340 * RETURNS 341 * void 342 * 343 */ 344 { 345 XcmsCmapRec **pPrevPtr; 346 XcmsCmapRec *pRec; 347 int scr; 348 349 /* If it is the default cmap for a screen, do not delete it, 350 * because the server will not actually free it */ 351 for (scr = ScreenCount(dpy); --scr >= 0; ) { 352 if (cmap == DefaultColormap(dpy, scr)) 353 return; 354 } 355 356 /* search for it in the list */ 357 LockDisplay(dpy); 358 pPrevPtr = (XcmsCmapRec **)&dpy->cms.clientCmaps; 359 while ((pRec = *pPrevPtr) && (pRec->cmapID != cmap)) { 360 pPrevPtr = &pRec->pNext; 361 } 362 363 if (pRec) { 364 if (pRec->ccc) { 365 XcmsFreeCCC(pRec->ccc); 366 } 367 *pPrevPtr = pRec->pNext; 368 Xfree(pRec); 369 } 370 UnlockDisplay(dpy); 371 SyncHandle(); 372 } 373 374 375 /* 377 * NAME 378 * _XcmsFreeClientCmaps 379 * 380 * SYNOPSIS 381 */ 382 static void 383 _XcmsFreeClientCmaps( 384 Display *dpy) 385 /* 386 * DESCRIPTION 387 * Frees all XcmsCmapRec structures in the linked list 388 * and sets dpy->cms.clientCmaps to NULL. 389 * 390 * RETURNS 391 * void 392 * 393 */ 394 { 395 XcmsCmapRec *pRecNext, *pRecFree; 396 397 LockDisplay(dpy); 398 pRecNext = (XcmsCmapRec *)dpy->cms.clientCmaps; 399 while (pRecNext != NULL) { 400 pRecFree = pRecNext; 401 pRecNext = pRecNext->pNext; 402 if (pRecFree->ccc) { 403 /* Free the XcmsCCC structure */ 404 XcmsFreeCCC(pRecFree->ccc); 405 } 406 /* Now free the XcmsCmapRec structure */ 407 Xfree(pRecFree); 408 } 409 dpy->cms.clientCmaps = (XPointer)NULL; 410 UnlockDisplay(dpy); 411 SyncHandle(); 412 } 413 414 415 416 /************************************************************************ 418 * * 419 * PUBLIC INTERFACES * 420 * * 421 ************************************************************************/ 422 423 /* 424 * NAME 425 * XcmsCCCOfColormap 426 * 427 * SYNOPSIS 428 */ 429 XcmsCCC 430 XcmsCCCOfColormap( 431 Display *dpy, 432 Colormap cmap) 433 /* 434 * DESCRIPTION 435 * Finds the XcmsCCC associated with the specified colormap. 436 * 437 * RETURNS 438 * Returns NULL if failed; otherwise the address to 439 * the associated XcmsCCC structure. 440 * 441 */ 442 { 443 XWindowAttributes windowAttr; 444 XcmsCmapRec *pRec; 445 int nScrn = ScreenCount(dpy); 446 int i; 447 448 if ((pRec = CmapRecForColormap(dpy, cmap)) != NULL) { 449 if (pRec->ccc) { 450 /* XcmsCmapRec already has a XcmsCCC */ 451 return(pRec->ccc); 452 } 453 454 /* 455 * The XcmsCmapRec does not have a XcmsCCC yet, so let's create 456 * one. But first, we need to know the screen associated with 457 * cmap, so use XGetWindowAttributes() to extract that 458 * information. Unless, of course there is only one screen!! 459 */ 460 if (nScrn == 1) { 461 /* Assume screenNumber == 0 */ 462 return(pRec->ccc = XcmsCreateCCC( 463 dpy, 464 0, /* screenNumber */ 465 pRec->visual, 466 (XcmsColor *)NULL, /* clientWhitePt */ 467 (XcmsCompressionProc)NULL, /* gamutCompProc */ 468 (XPointer)NULL, /* gamutCompClientData */ 469 (XcmsWhiteAdjustProc)NULL, /* whitePtAdjProc */ 470 (XPointer)NULL /* whitePtAdjClientData */ 471 )); 472 } else { 473 if (XGetWindowAttributes(dpy, pRec->windowID, &windowAttr)) { 474 for (i = 0; i < nScrn; i++) { 475 if (ScreenOfDisplay(dpy, i) == windowAttr.screen) { 476 return(pRec->ccc = XcmsCreateCCC( 477 dpy, 478 i, /* screenNumber */ 479 pRec->visual, 480 (XcmsColor *)NULL, /* clientWhitePt */ 481 (XcmsCompressionProc)NULL, /* gamutCompProc */ 482 (XPointer)NULL, /* gamutCompClientData */ 483 (XcmsWhiteAdjustProc)NULL, /* whitePtAdjProc */ 484 (XPointer)NULL /* whitePtAdjClientData */ 485 )); 486 } 487 } 488 } 489 } 490 } 491 492 /* 493 * No such cmap 494 */ 495 return(NULL); 496 } 497 498 XcmsCCC XcmsSetCCCOfColormap( 499 Display *dpy, 500 Colormap cmap, 501 XcmsCCC ccc) 502 { 503 XcmsCCC prev_ccc = NULL; 504 XcmsCmapRec *pRec; 505 506 pRec = CmapRecForColormap(dpy, cmap); 507 if (pRec) { 508 prev_ccc = pRec->ccc; 509 pRec->ccc = ccc; 510 } 511 return prev_ccc; 512 } 513