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