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