tkVisual.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:16k
源码类别:

通讯编程

开发平台:

Visual 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: tkVisual.c,v 1.4 2002/08/05 04:30:40 dgp Exp $
  15.  */
  16. #include "tkInt.h"
  17. #include "tkPort.h"
  18. /*
  19.  * The table below maps from symbolic names for visual classes
  20.  * to the associated X class symbols.
  21.  */
  22. typedef struct VisualDictionary {
  23.     char *name; /* Textual name of class. */
  24.     int minLength; /* Minimum # characters that must be
  25.  * specified for an unambiguous match. */
  26.     int class; /* X symbol for class. */
  27. } VisualDictionary;
  28. static VisualDictionary visualNames[] = {
  29.     {"best", 1, 0},
  30.     {"directcolor", 2, DirectColor},
  31.     {"grayscale", 1, GrayScale},
  32.     {"greyscale", 1, GrayScale},
  33.     {"pseudocolor", 1, PseudoColor},
  34.     {"staticcolor", 7, StaticColor},
  35.     {"staticgray", 7, StaticGray},
  36.     {"staticgrey", 7, StaticGray},
  37.     {"truecolor", 1, TrueColor},
  38.     {NULL, 0, 0},
  39. };
  40. /*
  41.  * One of the following structures exists for each distinct non-default
  42.  * colormap allocated for a display by Tk_GetColormap.
  43.  */
  44. struct TkColormap {
  45.     Colormap colormap; /* X's identifier for the colormap. */
  46.     Visual *visual; /* Visual for which colormap was
  47.  * allocated. */
  48.     int refCount; /* How many uses of the colormap are still
  49.  * outstanding (calls to Tk_GetColormap
  50.  * minus calls to Tk_FreeColormap). */
  51.     int shareable; /* 0 means this colormap was allocated by
  52.  * a call to Tk_GetColormap with "new",
  53.  * implying that the window wants it all
  54.  * for itself.  1 means that the colormap
  55.  * was allocated as a default for a particular
  56.  * visual, so it can be shared. */
  57.     struct TkColormap *nextPtr; /* Next in list of colormaps for this display,
  58.  * or NULL for end of list. */
  59. };
  60. /*
  61.  *----------------------------------------------------------------------
  62.  *
  63.  * Tk_GetVisual --
  64.  *
  65.  * Given a string identifying a particular kind of visual, this
  66.  * procedure returns a visual and depth that matches the specification.
  67.  *
  68.  * Results:
  69.  * The return value is normally a pointer to a visual.  If an
  70.  * error occurred in looking up the visual, NULL is returned and
  71.  * an error message is left in the interp's result.  The depth of the
  72.  * visual is returned to *depthPtr under normal returns.  If
  73.  * colormapPtr is non-NULL, then this procedure also finds a
  74.  * suitable colormap for use with the visual in tkwin, and it
  75.  * returns that colormap in *colormapPtr unless an error occurs.
  76.  *
  77.  * Side effects:
  78.  * A new colormap may be allocated.
  79.  *
  80.  *----------------------------------------------------------------------
  81.  */
  82. Visual *
  83. Tk_GetVisual(interp, tkwin, string, depthPtr, colormapPtr)
  84.     Tcl_Interp *interp; /* Interpreter to use for error
  85.  * reporting. */
  86.     Tk_Window tkwin; /* Window in which visual will be
  87.  * used. */
  88.     CONST char *string; /* String describing visual.  See
  89.  * manual entry for details. */
  90.     int *depthPtr; /* The depth of the returned visual
  91.  * is stored here. */
  92.     Colormap *colormapPtr; /* If non-NULL, then a suitable
  93.  * colormap for visual is placed here.
  94.  * This colormap must eventually be
  95.  * freed by calling Tk_FreeColormap. */
  96. {
  97.     Tk_Window tkwin2;
  98.     XVisualInfo template, *visInfoList, *bestPtr;
  99.     long mask;
  100.     Visual *visual;
  101.     int length, c, numVisuals, prio, bestPrio, i;
  102.     CONST char *p;
  103.     VisualDictionary *dictPtr;
  104.     TkColormap *cmapPtr;
  105.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  106.     /*
  107.      * Parse string and set up a template for use in searching for
  108.      * an appropriate visual.
  109.      */
  110.     c = string[0];
  111.     if (c == '.') {
  112. /*
  113.  * The string must be a window name.  If the window is on the
  114.  * same screen as tkwin, then just use its visual.  Otherwise
  115.  * use the information about the visual as a template for the
  116.  * search.
  117.  */
  118. tkwin2 = Tk_NameToWindow(interp, string, tkwin);
  119. if (tkwin2 == NULL) {
  120.     return NULL;
  121. }
  122. visual = Tk_Visual(tkwin2);
  123. if (Tk_Screen(tkwin) == Tk_Screen(tkwin2)) {
  124.     *depthPtr = Tk_Depth(tkwin2);
  125.     if (colormapPtr != NULL) {
  126. /*
  127.  * Use the colormap from the other window too (but be sure
  128.  * to increment its reference count if it's one of the ones
  129.  * allocated here).
  130.  */
  131. *colormapPtr = Tk_Colormap(tkwin2);
  132. for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  133. cmapPtr = cmapPtr->nextPtr) {
  134.     if (cmapPtr->colormap == *colormapPtr) {
  135. cmapPtr->refCount += 1;
  136. break;
  137.     }
  138. }
  139.     }
  140.     return visual;
  141. }
  142. template.depth = Tk_Depth(tkwin2);
  143. template.class = visual->class;
  144. template.red_mask = visual->red_mask;
  145. template.green_mask = visual->green_mask;
  146. template.blue_mask = visual->blue_mask;
  147. template.colormap_size = visual->map_entries;
  148. template.bits_per_rgb = visual->bits_per_rgb;
  149. mask = VisualDepthMask|VisualClassMask|VisualRedMaskMask
  150. |VisualGreenMaskMask|VisualBlueMaskMask|VisualColormapSizeMask
  151. |VisualBitsPerRGBMask;
  152.     } else if ((c == 0) || ((c == 'd') && (string[1] != 0)
  153.     && (strncmp(string, "default", strlen(string)) == 0))) {
  154. /*
  155.  * Use the default visual for the window's screen.
  156.  */
  157. if (colormapPtr != NULL) {
  158.     *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
  159. }
  160. *depthPtr = DefaultDepthOfScreen(Tk_Screen(tkwin));
  161. return DefaultVisualOfScreen(Tk_Screen(tkwin));
  162.     } else if (isdigit(UCHAR(c))) {
  163. int visualId;
  164. /*
  165. * This is a visual ID.
  166. */
  167. if (Tcl_GetInt(interp, string, &visualId) == TCL_ERROR) {
  168.     Tcl_ResetResult(interp);
  169.     Tcl_AppendResult(interp, "bad X identifier for visual: ",
  170.     string, """, (char *) NULL);
  171.     return NULL;
  172. }
  173. template.visualid = visualId;
  174. mask = VisualIDMask;
  175.     } else {
  176. /*
  177.  * Parse the string into a class name (or "best") optionally
  178.  * followed by whitespace and a depth.
  179.  */
  180. for (p = string; *p != 0; p++) {
  181.     if (isspace(UCHAR(*p)) || isdigit(UCHAR(*p))) {
  182. break;
  183.     }
  184. }
  185. length = p - string;
  186. template.class = -1;
  187. for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) {
  188.     if ((dictPtr->name[0] == c) && (length >= dictPtr->minLength)
  189.     && (strncmp(string, dictPtr->name,
  190.     (size_t) length) == 0)) {
  191. template.class = dictPtr->class;
  192. break;
  193.     }
  194. }
  195. if (template.class == -1) {
  196.     Tcl_AppendResult(interp, "unknown or ambiguous visual name "",
  197.     string, "": class must be ", (char *) NULL);
  198.     for (dictPtr = visualNames; dictPtr->name != NULL; dictPtr++) {
  199. Tcl_AppendResult(interp, dictPtr->name, ", ", (char *) NULL);
  200.     }
  201.     Tcl_AppendResult(interp, "or default", (char *) NULL);
  202.     return NULL;
  203. }
  204. while (isspace(UCHAR(*p))) {
  205.     p++;
  206. }
  207. if (*p == 0) {
  208.     template.depth = 10000;
  209. } else {
  210.     if (Tcl_GetInt(interp, p, &template.depth) != TCL_OK) {
  211. return NULL;
  212.     }
  213. }
  214. if (c == 'b') {
  215.     mask = 0;
  216. } else {
  217.     mask = VisualClassMask;
  218. }
  219.     }
  220.     /*
  221.      * Find all visuals that match the template we've just created,
  222.      * and return an error if there are none that match.
  223.      */
  224.     template.screen = Tk_ScreenNumber(tkwin);
  225.     mask |= VisualScreenMask;
  226.     visInfoList = XGetVisualInfo(Tk_Display(tkwin), mask, &template,
  227.     &numVisuals);
  228.     if (visInfoList == NULL) {
  229. Tcl_SetResult(interp, "couldn't find an appropriate visual",
  230. TCL_STATIC);
  231. return NULL;
  232.     }
  233.     /*
  234.      * Search through the visuals that were returned to find the best
  235.      * one.  The choice is based on the following criteria, in decreasing
  236.      * order of importance:
  237.      *
  238.      * 1. Depth: choose a visual with exactly the desired depth,
  239.      *   else one with more bits than requested but as few bits
  240.      *   as possible, else one with fewer bits but as many as
  241.      *    possible.
  242.      * 2. Class: some visual classes are more desirable than others;
  243.      *    pick the visual with the most desirable class.
  244.      * 3. Default: the default visual for the screen gets preference
  245.      *    over other visuals, all else being equal.
  246.      */
  247.     bestPrio = 0;
  248.     bestPtr = NULL;
  249.     for (i = 0; i < numVisuals; i++) {
  250. switch (visInfoList[i].class) {
  251.     case DirectColor: prio = 5; break;
  252.     case GrayScale: prio = 1; break;
  253.     case PseudoColor: prio = 7; break;
  254.     case StaticColor: prio = 3; break;
  255.     case StaticGray: prio = 1; break;
  256.     case TrueColor: prio = 5; break;
  257.     default: prio = 0; break;
  258. }
  259. if (visInfoList[i].visual
  260. == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
  261.     prio++;
  262. }
  263. if (bestPtr == NULL) {
  264.     goto newBest;
  265. }
  266. if (visInfoList[i].depth < bestPtr->depth) {
  267.     if (visInfoList[i].depth >= template.depth) {
  268. goto newBest;
  269.     }
  270. } else if (visInfoList[i].depth > bestPtr->depth) {
  271.     if (bestPtr->depth < template.depth) {
  272. goto newBest;
  273.     }
  274. } else {
  275.     if (prio > bestPrio) {
  276. goto newBest;
  277.     }
  278. }
  279. continue;
  280. newBest:
  281. bestPtr = &visInfoList[i];
  282. bestPrio = prio;
  283.     }
  284.     *depthPtr = bestPtr->depth;
  285.     visual = bestPtr->visual;
  286.     XFree((char *) visInfoList);
  287.     /*
  288.      * If we need to find a colormap for this visual, do it now.
  289.      * If the visual is the default visual for the screen, then
  290.      * use the default colormap.  Otherwise search for an existing
  291.      * colormap that's shareable.  If all else fails, create a new
  292.      * colormap.
  293.      */
  294.     if (colormapPtr != NULL) {
  295. if (visual == DefaultVisualOfScreen(Tk_Screen(tkwin))) {
  296.     *colormapPtr = DefaultColormapOfScreen(Tk_Screen(tkwin));
  297. } else {
  298.     for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  299.     cmapPtr = cmapPtr->nextPtr) {
  300. if (cmapPtr->shareable && (cmapPtr->visual == visual)) {
  301.     *colormapPtr = cmapPtr->colormap;
  302.     cmapPtr->refCount += 1;
  303.     goto done;
  304. }
  305.     }
  306.     cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap));
  307.     cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin),
  308.     RootWindowOfScreen(Tk_Screen(tkwin)), visual,
  309.     AllocNone);
  310.     cmapPtr->visual = visual;
  311.     cmapPtr->refCount = 1;
  312.     cmapPtr->shareable = 1;
  313.     cmapPtr->nextPtr = dispPtr->cmapPtr;
  314.     dispPtr->cmapPtr = cmapPtr;
  315.     *colormapPtr = cmapPtr->colormap;
  316. }
  317.     }
  318.     done:
  319.     return visual;
  320. }
  321. /*
  322.  *----------------------------------------------------------------------
  323.  *
  324.  * Tk_GetColormap --
  325.  *
  326.  * Given a string identifying a colormap, this procedure finds
  327.  * an appropriate colormap.
  328.  *
  329.  * Results:
  330.  * The return value is normally the X resource identifier for the
  331.  * colormap.  If an error occurs, None is returned and an error
  332.  * message is placed in the interp's result.
  333.  *
  334.  * Side effects:
  335.  * A reference count is incremented for the colormap, so
  336.  * Tk_FreeColormap must eventually be called exactly once for
  337.  * each call to Tk_GetColormap.
  338.  *
  339.  *----------------------------------------------------------------------
  340.  */
  341. Colormap
  342. Tk_GetColormap(interp, tkwin, string)
  343.     Tcl_Interp *interp; /* Interpreter to use for error
  344.  * reporting. */
  345.     Tk_Window tkwin; /* Window where colormap will be
  346.  * used. */
  347.     CONST char *string; /* String that identifies colormap:
  348.  * either "new" or the name of
  349.  * another window. */
  350. {
  351.     Colormap colormap;
  352.     TkColormap *cmapPtr;
  353.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  354.     Tk_Window other;
  355.     /*
  356.      * Allocate a new colormap, if that's what is wanted.
  357.      */
  358.     if (strcmp(string, "new") == 0) {
  359. cmapPtr = (TkColormap *) ckalloc(sizeof(TkColormap));
  360. cmapPtr->colormap = XCreateColormap(Tk_Display(tkwin),
  361. RootWindowOfScreen(Tk_Screen(tkwin)), Tk_Visual(tkwin),
  362. AllocNone);
  363. cmapPtr->visual = Tk_Visual(tkwin);
  364. cmapPtr->refCount = 1;
  365. cmapPtr->shareable = 0;
  366. cmapPtr->nextPtr = dispPtr->cmapPtr;
  367. dispPtr->cmapPtr = cmapPtr;
  368. return cmapPtr->colormap;
  369.     }
  370.     /*
  371.      * Use a colormap from an existing window.  It must have the same
  372.      * visual as tkwin (which means, among other things, that the
  373.      * other window must be on the same screen).
  374.      */
  375.     other = Tk_NameToWindow(interp, string, tkwin);
  376.     if (other == NULL) {
  377. return None;
  378.     }
  379.     if (Tk_Screen(other) != Tk_Screen(tkwin)) {
  380. Tcl_AppendResult(interp, "can't use colormap for ", string,
  381. ": not on same screen", (char *) NULL);
  382. return None;
  383.     }
  384.     if (Tk_Visual(other) != Tk_Visual(tkwin)) {
  385. Tcl_AppendResult(interp, "can't use colormap for ", string,
  386. ": incompatible visuals", (char *) NULL);
  387. return None;
  388.     }
  389.     colormap = Tk_Colormap(other);
  390.     /*
  391.      * If the colormap was a special one allocated by code in this file,
  392.      * increment its reference count.
  393.      */
  394.     for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  395.     cmapPtr = cmapPtr->nextPtr) {
  396. if (cmapPtr->colormap == colormap) {
  397.     cmapPtr->refCount += 1;
  398. }
  399.     }
  400.     return colormap;
  401. }
  402. /*
  403.  *----------------------------------------------------------------------
  404.  *
  405.  * Tk_FreeColormap --
  406.  *
  407.  * This procedure is called to release a colormap that was
  408.  * previously allocated by Tk_GetColormap.
  409.  *
  410.  * Results:
  411.  * None.
  412.  *
  413.  * Side effects:
  414.  * The colormap's reference count is decremented.  If this was the
  415.  * last reference to the colormap, then the colormap is freed.
  416.  *
  417.  *----------------------------------------------------------------------
  418.  */
  419. void
  420. Tk_FreeColormap(display, colormap)
  421.     Display *display; /* Display for which colormap was
  422.  * allocated. */
  423.     Colormap colormap; /* Colormap that is no longer needed.
  424.  * Must have been returned by previous
  425.  * call to Tk_GetColormap, or
  426.  * preserved by a previous call to
  427.  * Tk_PreserveColormap. */
  428. {
  429.     TkDisplay *dispPtr;
  430.     TkColormap *cmapPtr, *prevPtr;
  431.     /*
  432.      * Find Tk's information about the display, then see if this
  433.      * colormap is a non-default one (if it's a default one, there
  434.      * won't be an entry for it in the display's list).
  435.      */
  436.     dispPtr = TkGetDisplay(display);
  437.     if (dispPtr == NULL) {
  438. panic("unknown display passed to Tk_FreeColormap");
  439.     }
  440.     for (prevPtr = NULL, cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  441.     prevPtr = cmapPtr, cmapPtr = cmapPtr->nextPtr) {
  442. if (cmapPtr->colormap == colormap) {
  443.     cmapPtr->refCount -= 1;
  444.     if (cmapPtr->refCount == 0) {
  445. XFreeColormap(display, colormap);
  446. if (prevPtr == NULL) {
  447.     dispPtr->cmapPtr = cmapPtr->nextPtr;
  448. } else {
  449.     prevPtr->nextPtr = cmapPtr->nextPtr;
  450. }
  451. ckfree((char *) cmapPtr);
  452.     }
  453.     return;
  454. }
  455.     } 
  456. }
  457. /*
  458.  *----------------------------------------------------------------------
  459.  *
  460.  * Tk_PreserveColormap --
  461.  *
  462.  * This procedure is called to indicate to Tk that the specified
  463.  * colormap is being referenced from another location and should
  464.  * not be freed until all extra references are eliminated.  The
  465.  * colormap must have been returned by Tk_GetColormap.
  466.  *
  467.  * Results:
  468.  * None.
  469.  *
  470.  * Side effects:
  471.  * The colormap's reference count is incremented, so
  472.  * Tk_FreeColormap must eventually be called exactly once for
  473.  * each call to Tk_PreserveColormap.
  474.  *
  475.  *----------------------------------------------------------------------
  476.  */
  477. void
  478. Tk_PreserveColormap(display, colormap)
  479.     Display *display; /* Display for which colormap was
  480.  * allocated. */
  481.     Colormap colormap; /* Colormap that should be
  482.  * preserved. */
  483. {
  484.     TkDisplay *dispPtr;
  485.     TkColormap *cmapPtr;
  486.     /*
  487.      * Find Tk's information about the display, then see if this
  488.      * colormap is a non-default one (if it's a default one, there
  489.      * won't be an entry for it in the display's list).
  490.      */
  491.     dispPtr = TkGetDisplay(display);
  492.     if (dispPtr == NULL) {
  493. panic("unknown display passed to Tk_PreserveColormap");
  494.     }
  495.     for (cmapPtr = dispPtr->cmapPtr; cmapPtr != NULL;
  496.     cmapPtr = cmapPtr->nextPtr) {
  497. if (cmapPtr->colormap == colormap) {
  498.     cmapPtr->refCount += 1;
  499.     return;
  500. }
  501.     } 
  502. }