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