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 /************************************************************************
52  *									*
53  *			PRIVATE INTERFACES				*
54  *									*
55  ************************************************************************/
56 
57 /*
58  *	NAME
59  *		CmapRecForColormap
60  *
61  *	SYNOPSIS
62  */
63 static XcmsCmapRec *
CmapRecForColormap(Display * dpy,Colormap cmap)64 CmapRecForColormap(
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  */
234 XcmsCmapRec *
_XcmsAddCmapRec(Display * dpy,Colormap cmap,Window windowID,Visual * visual)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  */
280 XcmsCmapRec *
_XcmsCopyCmapRecAndFree(Display * dpy,Colormap src_cmap,Colormap copy_cmap)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  */
319 void
_XcmsDeleteCmapRec(Display * dpy,Colormap cmap)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  */
366 static void
_XcmsFreeClientCmaps(Display * dpy)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  */
409 XcmsCCC
XcmsCCCOfColormap(Display * dpy,Colormap cmap)410 XcmsCCCOfColormap(
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 
XcmsSetCCCOfColormap(Display * dpy,Colormap cmap,XcmsCCC ccc)478 XcmsCCC 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