OSDN Git Service

touched all tk files to ease next import
[pf3gnuchains/pf3gnuchains4x.git] / tk / generic / tkVisual.c
1 /* 
2  * tkVisual.c --
3  *
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.
7  *
8  * Copyright (c) 1994 The Regents of the University of California.
9  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10  *
11  * See the file "license.terms" for information on usage and redistribution
12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13  *
14  * RCS: @(#) $Id$
15  */
16
17 #include "tkInt.h"
18 #include "tkPort.h"
19
20 /*
21  * The table below maps from symbolic names for visual classes
22  * to the associated X class symbols.
23  */
24
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. */
30 } VisualDictionary;
31 static VisualDictionary visualNames[] = {
32     {"best",            1,      0},
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},
41     {NULL,              0,      0},
42 };
43
44 /*
45  * One of the following structures exists for each distinct non-default
46  * colormap allocated for a display by Tk_GetColormap.
47  */
48
49 struct TkColormap {
50     Colormap colormap;          /* X's identifier for the colormap. */
51     Visual *visual;             /* Visual for which colormap was
52                                  * allocated. */
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. */
64 };
65 \f
66 /*
67  *----------------------------------------------------------------------
68  *
69  * Tk_GetVisual --
70  *
71  *      Given a string identifying a particular kind of visual, this
72  *      procedure returns a visual and depth that matches the specification.
73  *
74  * Results:
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.
82  *
83  * Side effects:
84  *      A new colormap may be allocated.
85  *
86  *----------------------------------------------------------------------
87  */
88
89 Visual *
90 Tk_GetVisual(interp, tkwin, string, depthPtr, colormapPtr)
91     Tcl_Interp *interp;                 /* Interpreter to use for error
92                                          * reporting. */
93     Tk_Window tkwin;                    /* Window in which visual will be
94                                          * used. */
95     char *string;                       /* String describing visual.  See
96                                          * manual entry for details. */
97     int *depthPtr;                      /* The depth of the returned visual
98                                          * is stored here. */
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. */
103 {
104     Tk_Window tkwin2;
105     XVisualInfo template, *visInfoList, *bestPtr;
106     long mask;
107     Visual *visual;
108     int length, c, numVisuals, prio, bestPrio, i;
109     char *p;
110     VisualDictionary *dictPtr;
111     TkColormap *cmapPtr;
112     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
113
114     /*
115      * Parse string and set up a template for use in searching for
116      * an appropriate visual.
117      */
118
119     c = string[0];
120     if (c == '.') {
121         /*
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
125          * search.
126          */
127
128         tkwin2 = Tk_NameToWindow(interp, string, tkwin);
129         if (tkwin2 == NULL) {
130             return NULL;
131         }
132         visual = Tk_Visual(tkwin2);
133         if (Tk_Screen(tkwin) == Tk_Screen(tkwin2)) {
134             *depthPtr = Tk_Depth(tkwin2);
135             if (colormapPtr != NULL) {
136                 /*
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
139                  * allocated here).
140                  */
141
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;
147                         break;
148                     }
149                 }
150             }
151             return visual;
152         }
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))) {
165         /*
166          * Use the default visual for the window's screen.
167          */
168
169         if (colormapPtr != NULL) {
170             *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
171         }
172         *depthPtr = DefaultDepthOfScreen(Tk_Screen(tkwin));
173         return DefaultVisualOfScreen(Tk_Screen(tkwin));
174     } else if (isdigit(UCHAR(c))) {
175         int visualId;
176
177         /*
178         * This is a visual ID.
179         */
180
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);
185             return NULL;
186         }
187         template.visualid = visualId;
188         mask = VisualIDMask;
189     } else {
190         /*
191          * Parse the string into a class name (or "best") optionally
192          * followed by whitespace and a depth.
193          */
194
195         for (p = string; *p != 0; p++) {
196             if (isspace(UCHAR(*p)) || isdigit(UCHAR(*p))) {
197                 break;
198             }
199         }
200         length = p - string;
201         template.class = -1;
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;
207                 break;
208             }
209         }
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);
215             }
216             Tcl_AppendResult(interp, "or default", (char *) NULL);
217             return NULL;
218         }
219         while (isspace(UCHAR(*p))) {
220             p++;
221         }
222         if (*p == 0) {
223             template.depth = 10000;
224         } else {
225             if (Tcl_GetInt(interp, p, &template.depth) != TCL_OK) {
226                 return NULL;
227             }
228         }
229         if (c == 'b') {
230             mask = 0;
231         } else {
232             mask = VisualClassMask;
233         }
234     }
235
236     /*
237      * Find all visuals that match the template we've just created,
238      * and return an error if there are none that match.
239      */
240
241     template.screen = Tk_ScreenNumber(tkwin);
242     mask |= VisualScreenMask;
243     visInfoList = XGetVisualInfo(Tk_Display(tkwin), mask, &template,
244             &numVisuals);
245     if (visInfoList == NULL) {
246         Tcl_SetResult(interp, "couldn't find an appropriate visual",
247                 TCL_STATIC);
248         return NULL;
249     }
250
251     /*
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:
255      *
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
259      *    possible.
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.
264      */
265
266     bestPrio = 0;
267     bestPtr = NULL;
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;
277         }
278         if (visInfoList[i].visual
279                 == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
280             prio++;
281         }
282         if (bestPtr == NULL) {
283             goto newBest;
284         }
285         if (visInfoList[i].depth < bestPtr->depth) {
286             if (visInfoList[i].depth >= template.depth) {
287                 goto newBest;
288             }
289         } else if (visInfoList[i].depth > bestPtr->depth) {
290             if (bestPtr->depth < template.depth) {
291                 goto newBest;
292             }
293         } else {
294             if (prio > bestPrio) {
295                 goto newBest;
296             }
297         }
298         continue;
299
300         newBest:
301         bestPtr = &visInfoList[i];
302         bestPrio = prio;
303     }
304     *depthPtr = bestPtr->depth;
305     visual = bestPtr->visual;
306     XFree((char *) visInfoList);
307
308     /*
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
313      * colormap.
314      */
315
316     if (colormapPtr != NULL) {
317         if (visual == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
318             *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
319         } else {
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;
325                     goto done;
326                 }
327             }
328             cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap));
329             cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin),
330                     RootWindowOfScreen(Tk_Screen(tkwin)), visual,
331                     AllocNone);
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;
338         }
339     }
340
341     done:
342     return visual;
343 }
344 \f
345 /*
346  *----------------------------------------------------------------------
347  *
348  * Tk_GetColormap --
349  *
350  *      Given a string identifying a colormap, this procedure finds
351  *      an appropriate colormap.
352  *
353  * Results:
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.
357  *
358  * Side effects:
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.
362  *
363  *----------------------------------------------------------------------
364  */
365
366 Colormap
367 Tk_GetColormap(interp, tkwin, string)
368     Tcl_Interp *interp;                 /* Interpreter to use for error
369                                          * reporting. */
370     Tk_Window tkwin;                    /* Window where colormap will be
371                                          * used. */
372     char *string;                       /* String that identifies colormap:
373                                          * either "new" or the name of
374                                          * another window. */
375 {
376     Colormap colormap;
377     TkColormap *cmapPtr;
378     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
379     Tk_Window other;
380
381     /*
382      * Allocate a new colormap, if that's what is wanted.
383      */
384
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),
389                 AllocNone);
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;
396     }
397
398     /*
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).
402      */
403
404     other = Tk_NameToWindow(interp, string, tkwin);
405     if (other == NULL) {
406         return None;
407     }
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);
411         return None;
412     }
413     if (Tk_Visual(other) != Tk_Visual(tkwin)) {
414         Tcl_AppendResult(interp, "can't use colormap for ", string,
415                 ": incompatible visuals", (char *) NULL);
416         return None;
417     }
418     colormap = Tk_Colormap(other);
419
420     /*
421      * If the colormap was a special one allocated by code in this file,
422      * increment its reference count.
423      */
424
425     for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
426             cmapPtr = cmapPtr->nextPtr) {
427         if (cmapPtr->colormap == colormap) {
428             cmapPtr->refCount += 1;
429         }
430     }
431     return colormap;
432 }
433 \f
434 /*
435  *----------------------------------------------------------------------
436  *
437  * Tk_FreeColormap --
438  *
439  *      This procedure is called to release a colormap that was
440  *      previously allocated by Tk_GetColormap.
441  *
442  * Results:
443  *      None.
444  *
445  * Side effects:
446  *      The colormap's reference count is decremented.  If this was the
447  *      last reference to the colormap, then the colormap is freed.
448  *
449  *----------------------------------------------------------------------
450  */
451
452 void
453 Tk_FreeColormap(display, colormap)
454     Display *display;                   /* Display for which colormap was
455                                          * allocated. */
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. */
461 {
462     TkDisplay *dispPtr;
463     TkColormap *cmapPtr, *prevPtr;
464
465     /*
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).
469      */
470
471     dispPtr = TkGetDisplay(display);
472     if (dispPtr == NULL) {
473         panic("unknown display passed to Tk_FreeColormap");
474     }
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;
483                 } else {
484                     prevPtr->nextPtr = cmapPtr->nextPtr;
485                 }
486                 ckfree((char *) cmapPtr);
487             }
488             return;
489         }
490     } 
491 }
492 \f
493 /*
494  *----------------------------------------------------------------------
495  *
496  * Tk_PreserveColormap --
497  *
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.
502  *
503  * Results:
504  *      None.
505  *
506  * Side effects:
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.
510  *
511  *----------------------------------------------------------------------
512  */
513
514 void
515 Tk_PreserveColormap(display, colormap)
516     Display *display;                   /* Display for which colormap was
517                                          * allocated. */
518     Colormap colormap;                  /* Colormap that should be
519                                          * preserved. */
520 {
521     TkDisplay *dispPtr;
522     TkColormap *cmapPtr;
523
524     /*
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).
528      */
529
530     dispPtr = TkGetDisplay(display);
531     if (dispPtr == NULL) {
532         panic("unknown display passed to Tk_PreserveColormap");
533     }
534     for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
535             cmapPtr = cmapPtr->nextPtr) {
536         if (cmapPtr->colormap == colormap) {
537             cmapPtr->refCount += 1;
538             return;
539         }
540     } 
541 }
542