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