Home | History | Annotate | Line # | Download | only in xcms
      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