cmsCmap.c revision 3b4ba46c
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