4 * This file contains library procedures for allocating and
5 * freeing visuals and colormaps. This code is based on a
6 * prototype implementation by Paul Mackerras.
8 * Copyright (c) 1994 The Regents of the University of California.
9 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
21 * The table below maps from symbolic names for visual classes
22 * to the associated X class symbols.
25 typedef struct VisualDictionary {
26 char *name; /* Textual name of class. */
27 int minLength; /* Minimum # characters that must be
28 * specified for an unambiguous match. */
29 int class; /* X symbol for class. */
31 static VisualDictionary visualNames[] = {
33 {"directcolor", 2, DirectColor},
34 {"grayscale", 1, GrayScale},
35 {"greyscale", 1, GrayScale},
36 {"pseudocolor", 1, PseudoColor},
37 {"staticcolor", 7, StaticColor},
38 {"staticgray", 7, StaticGray},
39 {"staticgrey", 7, StaticGray},
40 {"truecolor", 1, TrueColor},
45 * One of the following structures exists for each distinct non-default
46 * colormap allocated for a display by Tk_GetColormap.
50 Colormap colormap; /* X's identifier for the colormap. */
51 Visual *visual; /* Visual for which colormap was
53 int refCount; /* How many uses of the colormap are still
54 * outstanding (calls to Tk_GetColormap
55 * minus calls to Tk_FreeColormap). */
56 int shareable; /* 0 means this colormap was allocated by
57 * a call to Tk_GetColormap with "new",
58 * implying that the window wants it all
59 * for itself. 1 means that the colormap
60 * was allocated as a default for a particular
61 * visual, so it can be shared. */
62 struct TkColormap *nextPtr; /* Next in list of colormaps for this display,
63 * or NULL for end of list. */
67 *----------------------------------------------------------------------
71 * Given a string identifying a particular kind of visual, this
72 * procedure returns a visual and depth that matches the specification.
75 * The return value is normally a pointer to a visual. If an
76 * error occurred in looking up the visual, NULL is returned and
77 * an error message is left in the interp's result. The depth of the
78 * visual is returned to *depthPtr under normal returns. If
79 * colormapPtr is non-NULL, then this procedure also finds a
80 * suitable colormap for use with the visual in tkwin, and it
81 * returns that colormap in *colormapPtr unless an error occurs.
84 * A new colormap may be allocated.
86 *----------------------------------------------------------------------
90 Tk_GetVisual(interp, tkwin, string, depthPtr, colormapPtr)
91 Tcl_Interp *interp; /* Interpreter to use for error
93 Tk_Window tkwin; /* Window in which visual will be
95 char *string; /* String describing visual. See
96 * manual entry for details. */
97 int *depthPtr; /* The depth of the returned visual
99 Colormap *colormapPtr; /* If non-NULL, then a suitable
100 * colormap for visual is placed here.
101 * This colormap must eventually be
102 * freed by calling Tk_FreeColormap. */
105 XVisualInfo template, *visInfoList, *bestPtr;
108 int length, c, numVisuals, prio, bestPrio, i;
110 VisualDictionary *dictPtr;
112 TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
115 * Parse string and set up a template for use in searching for
116 * an appropriate visual.
122 * The string must be a window name. If the window is on the
123 * same screen as tkwin, then just use its visual. Otherwise
124 * use the information about the visual as a template for the
128 tkwin2 = Tk_NameToWindow(interp, string, tkwin);
129 if (tkwin2 == NULL) {
132 visual = Tk_Visual(tkwin2);
133 if (Tk_Screen(tkwin) == Tk_Screen(tkwin2)) {
134 *depthPtr = Tk_Depth(tkwin2);
135 if (colormapPtr != NULL) {
137 * Use the colormap from the other window too (but be sure
138 * to increment its reference count if it's one of the ones
142 *colormapPtr = Tk_Colormap(tkwin2);
143 for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
144 cmapPtr = cmapPtr->nextPtr) {
145 if (cmapPtr->colormap == *colormapPtr) {
146 cmapPtr->refCount += 1;
153 template.depth = Tk_Depth(tkwin2);
154 template.class = visual->class;
155 template.red_mask = visual->red_mask;
156 template.green_mask = visual->green_mask;
157 template.blue_mask = visual->blue_mask;
158 template.colormap_size = visual->map_entries;
159 template.bits_per_rgb = visual->bits_per_rgb;
160 mask = VisualDepthMask|VisualClassMask|VisualRedMaskMask
161 |VisualGreenMaskMask|VisualBlueMaskMask|VisualColormapSizeMask
162 |VisualBitsPerRGBMask;
163 } else if ((c == 0) || ((c == 'd') && (string[1] != 0)
164 && (strncmp(string, "default", strlen(string)) == 0))) {
166 * Use the default visual for the window's screen.
169 if (colormapPtr != NULL) {
170 *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
172 *depthPtr = DefaultDepthOfScreen(Tk_Screen(tkwin));
173 return DefaultVisualOfScreen(Tk_Screen(tkwin));
174 } else if (isdigit(UCHAR(c))) {
178 * This is a visual ID.
181 if (Tcl_GetInt(interp, string, &visualId) == TCL_ERROR) {
182 Tcl_ResetResult(interp);
183 Tcl_AppendResult(interp, "bad X identifier for visual: ",
184 string, "\"", (char *) NULL);
187 template.visualid = visualId;
191 * Parse the string into a class name (or "best") optionally
192 * followed by whitespace and a depth.
195 for (p = string; *p != 0; p++) {
196 if (isspace(UCHAR(*p)) || isdigit(UCHAR(*p))) {
202 for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) {
203 if ((dictPtr->name[0] == c) && (length >= dictPtr->minLength)
204 && (strncmp(string, dictPtr->name,
205 (size_t) length) == 0)) {
206 template.class = dictPtr->class;
210 if (template.class == -1) {
211 Tcl_AppendResult(interp, "unknown or ambiguous visual name \"",
212 string, "\": class must be ", (char *) NULL);
213 for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) {
214 Tcl_AppendResult(interp, dictPtr->name, ", ", (char *) NULL);
216 Tcl_AppendResult(interp, "or default", (char *) NULL);
219 while (isspace(UCHAR(*p))) {
223 template.depth = 10000;
225 if (Tcl_GetInt(interp, p, &template.depth) != TCL_OK) {
232 mask = VisualClassMask;
237 * Find all visuals that match the template we've just created,
238 * and return an error if there are none that match.
241 template.screen = Tk_ScreenNumber(tkwin);
242 mask |= VisualScreenMask;
243 visInfoList = XGetVisualInfo(Tk_Display(tkwin), mask, &template,
245 if (visInfoList == NULL) {
246 Tcl_SetResult(interp, "couldn't find an appropriate visual",
252 * Search through the visuals that were returned to find the best
253 * one. The choice is based on the following criteria, in decreasing
254 * order of importance:
256 * 1. Depth: choose a visual with exactly the desired depth,
257 * else one with more bits than requested but as few bits
258 * as possible, else one with fewer bits but as many as
260 * 2. Class: some visual classes are more desirable than others;
261 * pick the visual with the most desirable class.
262 * 3. Default: the default visual for the screen gets preference
263 * over other visuals, all else being equal.
268 for (i = 0; i < numVisuals; i++) {
269 switch (visInfoList[i].class) {
270 case DirectColor: prio = 5; break;
271 case GrayScale: prio = 1; break;
272 case PseudoColor: prio = 7; break;
273 case StaticColor: prio = 3; break;
274 case StaticGray: prio = 1; break;
275 case TrueColor: prio = 5; break;
276 default: prio = 0; break;
278 if (visInfoList[i].visual
279 == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
282 if (bestPtr == NULL) {
285 if (visInfoList[i].depth < bestPtr->depth) {
286 if (visInfoList[i].depth >= template.depth) {
289 } else if (visInfoList[i].depth > bestPtr->depth) {
290 if (bestPtr->depth < template.depth) {
294 if (prio > bestPrio) {
301 bestPtr = &visInfoList[i];
304 *depthPtr = bestPtr->depth;
305 visual = bestPtr->visual;
306 XFree((char *) visInfoList);
309 * If we need to find a colormap for this visual, do it now.
310 * If the visual is the default visual for the screen, then
311 * use the default colormap. Otherwise search for an existing
312 * colormap that's shareable. If all else fails, create a new
316 if (colormapPtr != NULL) {
317 if (visual == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
318 *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
320 for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
321 cmapPtr = cmapPtr->nextPtr) {
322 if (cmapPtr->shareable && (cmapPtr->visual == visual)) {
323 *colormapPtr = cmapPtr->colormap;
324 cmapPtr->refCount += 1;
328 cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap));
329 cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin),
330 RootWindowOfScreen(Tk_Screen(tkwin)), visual,
332 cmapPtr->visual = visual;
333 cmapPtr->refCount = 1;
334 cmapPtr->shareable = 1;
335 cmapPtr->nextPtr = dispPtr->cmapPtr;
336 dispPtr->cmapPtr = cmapPtr;
337 *colormapPtr = cmapPtr->colormap;
346 *----------------------------------------------------------------------
350 * Given a string identifying a colormap, this procedure finds
351 * an appropriate colormap.
354 * The return value is normally the X resource identifier for the
355 * colormap. If an error occurs, None is returned and an error
356 * message is placed in the interp's result.
359 * A reference count is incremented for the colormap, so
360 * Tk_FreeColormap must eventually be called exactly once for
361 * each call to Tk_GetColormap.
363 *----------------------------------------------------------------------
367 Tk_GetColormap(interp, tkwin, string)
368 Tcl_Interp *interp; /* Interpreter to use for error
370 Tk_Window tkwin; /* Window where colormap will be
372 char *string; /* String that identifies colormap:
373 * either "new" or the name of
378 TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
382 * Allocate a new colormap, if that's what is wanted.
385 if (strcmp(string, "new") == 0) {
386 cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap));
387 cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin),
388 RootWindowOfScreen(Tk_Screen(tkwin)), Tk_Visual(tkwin),
390 cmapPtr->visual = Tk_Visual(tkwin);
391 cmapPtr->refCount = 1;
392 cmapPtr->shareable = 0;
393 cmapPtr->nextPtr = dispPtr->cmapPtr;
394 dispPtr->cmapPtr = cmapPtr;
395 return cmapPtr->colormap;
399 * Use a colormap from an existing window. It must have the same
400 * visual as tkwin (which means, among other things, that the
401 * other window must be on the same screen).
404 other = Tk_NameToWindow(interp, string, tkwin);
408 if (Tk_Screen(other) != Tk_Screen(tkwin)) {
409 Tcl_AppendResult(interp, "can't use colormap for ", string,
410 ": not on same screen", (char *) NULL);
413 if (Tk_Visual(other) != Tk_Visual(tkwin)) {
414 Tcl_AppendResult(interp, "can't use colormap for ", string,
415 ": incompatible visuals", (char *) NULL);
418 colormap = Tk_Colormap(other);
421 * If the colormap was a special one allocated by code in this file,
422 * increment its reference count.
425 for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
426 cmapPtr = cmapPtr->nextPtr) {
427 if (cmapPtr->colormap == colormap) {
428 cmapPtr->refCount += 1;
435 *----------------------------------------------------------------------
439 * This procedure is called to release a colormap that was
440 * previously allocated by Tk_GetColormap.
446 * The colormap's reference count is decremented. If this was the
447 * last reference to the colormap, then the colormap is freed.
449 *----------------------------------------------------------------------
453 Tk_FreeColormap(display, colormap)
454 Display *display; /* Display for which colormap was
456 Colormap colormap; /* Colormap that is no longer needed.
457 * Must have been returned by previous
458 * call to Tk_GetColormap, or
459 * preserved by a previous call to
460 * Tk_PreserveColormap. */
463 TkColormap *cmapPtr, *prevPtr;
466 * Find Tk's information about the display, then see if this
467 * colormap is a non-default one (if it's a default one, there
468 * won't be an entry for it in the display's list).
471 dispPtr = TkGetDisplay(display);
472 if (dispPtr == NULL) {
473 panic("unknown display passed to Tk_FreeColormap");
475 for (prevPtr = NULL, cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
476 prevPtr = cmapPtr, cmapPtr = cmapPtr->nextPtr) {
477 if (cmapPtr->colormap == colormap) {
478 cmapPtr->refCount -= 1;
479 if (cmapPtr->refCount == 0) {
480 XFreeColormap(display, colormap);
481 if (prevPtr == NULL) {
482 dispPtr->cmapPtr = cmapPtr->nextPtr;
484 prevPtr->nextPtr = cmapPtr->nextPtr;
486 ckfree((char *) cmapPtr);
494 *----------------------------------------------------------------------
496 * Tk_PreserveColormap --
498 * This procedure is called to indicate to Tk that the specified
499 * colormap is being referenced from another location and should
500 * not be freed until all extra references are eliminated. The
501 * colormap must have been returned by Tk_GetColormap.
507 * The colormap's reference count is incremented, so
508 * Tk_FreeColormap must eventually be called exactly once for
509 * each call to Tk_PreserveColormap.
511 *----------------------------------------------------------------------
515 Tk_PreserveColormap(display, colormap)
516 Display *display; /* Display for which colormap was
518 Colormap colormap; /* Colormap that should be
525 * Find Tk's information about the display, then see if this
526 * colormap is a non-default one (if it's a default one, there
527 * won't be an entry for it in the display's list).
530 dispPtr = TkGetDisplay(display);
531 if (dispPtr == NULL) {
532 panic("unknown display passed to Tk_PreserveColormap");
534 for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
535 cmapPtr = cmapPtr->nextPtr) {
536 if (cmapPtr->colormap == colormap) {
537 cmapPtr->refCount += 1;