home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tcltk805.zip / tcl805s.zip / tk8.0.5 / os2 / tkOS2Color.c < prev    next >
C/C++ Source or Header  |  2001-09-08  |  35KB  |  1,118 lines

  1. /* 
  2.  * tkOS2Color.c --
  3.  *
  4.  *    Functions to map color names to system color values.
  5.  *
  6.  * Copyright (c) 1996-2000 Illya Vaes
  7.  * Copyright (c) 1995 Sun Microsystems, Inc.
  8.  * Copyright (c) 1994 Software Research Associates, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  */
  13.  
  14. #include <tkColor.h>
  15. #include "tkOS2Int.h"
  16.  
  17. /*
  18.  * The following structure is used to keep track of each color that is
  19.  * allocated by this module.
  20.  */
  21.  
  22. typedef struct OS2Color {
  23.     TkColor info;               /* Generic color information. */
  24.     int index;                  /* Index for WinQuerySysColor(), -1 if color
  25.                                  * is not a "live" system color. */
  26. } OS2Color;
  27.  
  28. /*
  29.  * The sysColors array contains the names and index values for the
  30.  * OS/2 PM indirect system color names.  In use, all of the names will
  31.  * have the string "System" prepended, but we omit it in the table to
  32.  * save space.
  33.  */
  34.  
  35. typedef struct {
  36.     char *name;
  37.     int index;
  38. } SystemColorEntry;
  39.  
  40. static SystemColorEntry sysColors[] = {
  41.     { "3dDarkShadow",        SYSCLR_BUTTONDARK },
  42.     { "3dLight",        SYSCLR_BUTTONLIGHT },
  43.     { "ActiveBorder",        SYSCLR_ACTIVETITLETEXTBGND },
  44.     { "ActiveCaption",        SYSCLR_ACTIVETITLE },
  45.     { "AppWorkspace",        SYSCLR_APPWORKSPACE },
  46.     { "Background",        SYSCLR_BACKGROUND },
  47.     { "ButtonFace",        SYSCLR_BUTTONMIDDLE },
  48.     { "ButtonHighlight",    SYSCLR_BUTTONLIGHT },
  49.     { "ButtonShadow",        SYSCLR_BUTTONDARK },
  50.     { "ButtonText",        SYSCLR_MENUTEXT },
  51.     { "CaptionText",        SYSCLR_TITLETEXT },
  52.     { "DisabledText",        SYSCLR_MENUDISABLEDTEXT },
  53.     { "GrayText",        SYSCLR_MENUDISABLEDTEXT },
  54.     { "Highlight",        SYSCLR_HILITEBACKGROUND },
  55.     { "HighlightText",        SYSCLR_HILITEFOREGROUND },
  56.     { "InactiveBorder",        SYSCLR_INACTIVEBORDER },
  57.     { "InactiveCaption",    SYSCLR_INACTIVETITLE },
  58.     { "InactiveCaptionText",    SYSCLR_INACTIVETITLETEXTBGND },
  59.     { "InfoBackground",        SYSCLR_HILITEBACKGROUND },
  60.     { "InfoText",        SYSCLR_HILITEFOREGROUND },
  61.     { "Menu",            SYSCLR_MENU },
  62.     { "MenuText",        SYSCLR_MENUTEXT },
  63.     { "Scrollbar",        SYSCLR_SCROLLBAR },
  64.     { "Window",            SYSCLR_WINDOW },
  65.     { "WindowFrame",        SYSCLR_WINDOWFRAME },
  66.     { "WindowText",        SYSCLR_WINDOWTEXT },
  67.     { NULL,                0 }
  68. };
  69.  
  70. /* Number of colors that have been set */
  71. static int ncolors = 0;
  72.  
  73. /* Table of colors that have been set */
  74. LONG *logColorTable;
  75.  
  76. /* Hash table for reference counts of logical color table entries */
  77. Tcl_HashTable logColorRefCounts;
  78.  
  79. /* Has this module been initialized? */
  80. static int initialized = 0;
  81.  
  82. /*
  83.  * Forward declarations for functions defined later in this file.
  84.  */
  85.  
  86. static int            InitColorTable _ANSI_ARGS_((Display *display));
  87. static void           FreeColorTable _ANSI_ARGS_((ClientData clientData));
  88. static int            FindSystemColor _ANSI_ARGS_((const char *name,
  89.                           XColor *colorPtr, int *indexPtr));
  90.  
  91.  
  92.  
  93. /*
  94.  *----------------------------------------------------------------------
  95.  *
  96.  * InitColorTable --
  97.  *
  98.  *      This routine allocates space for the global color table, if
  99.  *      necessary.
  100.  *
  101.  * Results:
  102.  *      Returns non-zero on success.
  103.  *
  104.  * Side effects:
  105.  *      Sets up an exit handler for freeing the allocated space.
  106.  *
  107.  *----------------------------------------------------------------------
  108.  */
  109.  
  110. static int
  111. InitColorTable(display)
  112.     Display *display;
  113. {
  114.     int refCount;
  115.  
  116.     if (!initialized) {
  117.         /* Determine necessary size for color table */
  118.         logColorTable = (LONG *)
  119.        ckalloc((DefaultScreenOfDisplay(display))->root_visual->map_entries);
  120.         if (!logColorTable) {
  121. #ifdef VERBOSE
  122.             printf("InitColorTable couldn't allocate logColorTable (%d)\n",
  123.                (DefaultScreenOfDisplay(display))->root_visual->map_entries);
  124.             fflush(stdout);
  125. #endif
  126.             return 0;
  127.         }
  128. #ifdef VERBOSE
  129.         printf("InitColorTable allocated logColorTable (%d entries)\n",
  130.            (DefaultScreenOfDisplay(display))->root_visual->map_entries);
  131.             fflush(stdout);
  132. #endif
  133.         if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  134.             /*
  135.              * Palette support
  136.              */
  137.             HPS screenPS = WinGetScreenPS(HWND_DESKTOP);
  138.  
  139.             /* First get number of entries */
  140.             refCount = GpiQueryPaletteInfo(0L, screenPS, 0L, 0L, 0L,
  141.                                            logColorTable);
  142. #ifdef VERBOSE
  143.             printf("GpiQueryPaletteInfo says we need %d entries\n", refCount);
  144.             fflush(stdout);
  145. #endif
  146.             if (refCount >
  147.                   (DefaultScreenOfDisplay(display))->root_visual->map_entries) {
  148.                 refCount =
  149.                     (DefaultScreenOfDisplay(display))->root_visual->map_entries;
  150.             }
  151.             if (GpiQueryPaletteInfo(0L, screenPS, 0L, 0L, refCount,
  152.                                     logColorTable) == PAL_ERROR) {
  153. #ifdef VERBOSE
  154.                 printf("GpiQueryPaletteInfo PAL_ERROR: %x\n",
  155.                        WinGetLastError(TclOS2GetHAB()));
  156.                 fflush(stdout);
  157. #endif
  158.                 WinReleasePS(screenPS);
  159.                 return 0;
  160.             }
  161.             WinReleasePS(screenPS);
  162.         } else {
  163.             /*
  164.              * By default, presentation spaces have a logical color table
  165.              * consisting of the 16 default CLR_* values.
  166.          * nextColor contains the value of the next undefined entry.
  167.              */
  168.             rc = GpiQueryLogColorTable(globalPS, 0L, 0L, nextColor,
  169.                                        logColorTable);
  170. #ifdef VERBOSE
  171.             if (rc==QLCT_ERROR) {
  172.                 printf("Init: GpiQueryLogColorTable ERROR %x\n",
  173.                        WinGetLastError(TclOS2GetHAB()));
  174.             } else {
  175.                 if (rc==QLCT_RGB) {
  176.                     printf("Init: GpiQueryLogColorTable in RGB mode\n");
  177.                 } else {
  178.                     printf("Init: GpiQueryLogColorTable OK (%d elem)\n", rc);
  179.                 }
  180.             }
  181.             fflush(stdout);
  182. #endif
  183.             /* Recreate the color table in RGB mode */
  184.         rc = GpiCreateLogColorTable(globalPS, 0L, LCOLF_RGB, 0L,
  185.                                     nextColor, logColorTable);
  186. #ifdef VERBOSE
  187.             if (rc==FALSE) {
  188.                 printf("  GpiCreateLogColorTable ERROR %x\n",
  189.                        WinGetLastError(TclOS2GetHAB()));
  190.             } else {
  191.                 printf("  GpiCreateLogColorTable OK (%d elem)\n", nextColor);
  192.             }
  193.             fflush(stdout);
  194. #endif
  195.         }
  196.         Tcl_CreateExitHandler(FreeColorTable, (ClientData) NULL);
  197.     initialized = 1;
  198.     return 1;
  199.     }
  200.     return 1;
  201. }
  202.  
  203. /*
  204.  *----------------------------------------------------------------------
  205.  *
  206.  * FreeColorTable --
  207.  *
  208.  *      This routine frees the memory space of the global color table,
  209.  *      if necessary.
  210.  *
  211.  * Results:
  212.  *      None.
  213.  *
  214.  * Side effects:
  215.  *      None.
  216.  *
  217.  *----------------------------------------------------------------------
  218.  */
  219.  
  220. static void
  221. FreeColorTable(clientData)
  222.     ClientData clientData;    /* not used */
  223. {
  224. #ifdef VERBOSE
  225.     printf("FreeColorTable\n");
  226.     fflush(stdout);
  227. #endif
  228.     if (initialized) {
  229.         Tcl_DeleteExitHandler(FreeColorTable, (ClientData) NULL);
  230.     ckfree((char *)logColorTable);
  231.     initialized = 0;
  232.     }
  233. }
  234.  
  235. /*
  236.  *----------------------------------------------------------------------
  237.  *
  238.  * FindSystemColor --
  239.  *
  240.  *      This routine finds the color entry that corresponds to the
  241.  *      specified color.
  242.  *
  243.  * Results:
  244.  *      Returns non-zero on success.  The RGB values of the XColor
  245.  *      will be initialized to the proper values on success.
  246.  *
  247.  * Side effects:
  248.  *      None.
  249.  *
  250.  *----------------------------------------------------------------------
  251.  */
  252.  
  253. static int
  254. FindSystemColor(name, colorPtr, indexPtr)
  255.     const char *name;           /* Color name. */
  256.     XColor *colorPtr;           /* Where to store results. */
  257.     int *indexPtr;              /* Out parameter to store color index. */
  258. {
  259.     int l, u, r, i;
  260.  
  261.     /*
  262.      * Count the number of elements in the color array if we haven't
  263.      * done so yet.
  264.      */
  265.  
  266.     if (ncolors == 0) {
  267.         SystemColorEntry *ePtr;
  268.  
  269.         for (ePtr = sysColors; ePtr->name != NULL; ePtr++) {
  270.             ncolors++;
  271.         }
  272.     }
  273.  
  274.     /*
  275.      * Perform a binary search on the sorted array of colors.
  276.      */
  277.  
  278.     l = 0;
  279.     u = ncolors - 1;
  280.     while (l <= u) {
  281.         i = (l + u) / 2;
  282.         r = strcasecmp(name, sysColors[i].name);
  283.         if (r == 0) {
  284.             break;
  285.         } else if (r < 0) {
  286.             u = i-1;
  287.         } else {
  288.             l = i+1;
  289.         }
  290.     }
  291.     if (l > u) {
  292.         return 0;
  293.     }
  294.     *indexPtr = sysColors[i].index;
  295.     colorPtr->pixel = WinQuerySysColor(HWND_DESKTOP, sysColors[i].index, 0);
  296.     colorPtr->red = GetRValue(colorPtr->pixel) << 8;
  297.     colorPtr->green = GetGValue(colorPtr->pixel) << 8;
  298.     colorPtr->blue = GetBValue(colorPtr->pixel) << 8;
  299. #ifdef VERBOSE
  300.     printf("    SystemColor %s %d (%x): %x (%d,%d,%d)\n", sysColors[i].name,
  301.            sysColors[i].index, sysColors[i].index, colorPtr->pixel,
  302.            colorPtr->red, colorPtr->green, colorPtr->blue);
  303.             fflush(stdout);
  304. #endif
  305.     colorPtr->flags = DoRed|DoGreen|DoBlue;
  306.     colorPtr->pad = 0;
  307.     return 1;
  308. }
  309.  
  310. /*
  311.  *----------------------------------------------------------------------
  312.  *
  313.  * TkpGetColor --
  314.  *
  315.  *      Allocate a new TkColor for the color with the given name.
  316.  *
  317.  * Results:
  318.  *      Returns a newly allocated TkColor, or NULL on failure.
  319.  *
  320.  * Side effects:
  321.  *      May invalidate the colormap cache associated with tkwin upon
  322.  *      allocating a new colormap entry.  Allocates a new TkColor
  323.  *      structure.
  324.  *
  325.  *----------------------------------------------------------------------
  326.  */
  327.  
  328. TkColor *
  329. TkpGetColor(tkwin, name)
  330.     Tk_Window tkwin;            /* Window in which color will be used. */
  331.     Tk_Uid name;                /* Name of color to allocated (in form
  332.                                  * suitable for passing to XParseColor). */
  333. {
  334.     OS2Color *os2ColPtr;
  335.     XColor color;
  336.     int index = -1;             /* -1 indicates that this is not an indirect
  337.                                  * sytem color. */
  338.  
  339. #ifdef VERBOSE
  340.     printf("TkpGetColor tkwin %x name %s\n", tkwin, name);
  341.             fflush(stdout);
  342. #endif
  343.  
  344.     /*
  345.      * Check to see if it is a system color or an X color string.  If the
  346.      * color is found, allocate a new OS2Color and store the XColor and the
  347.      * system color index.
  348.      */
  349.  
  350.     if (((strncasecmp(name, "system", 6) == 0)
  351.             && FindSystemColor(name+6, &color, &index))
  352.             || XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin), name,
  353.                     &color)) {
  354.         os2ColPtr = (OS2Color *) ckalloc(sizeof(OS2Color));
  355.         if (os2ColPtr == (OS2Color *)NULL) {
  356.             return (TkColor *) NULL;
  357.         }
  358.         os2ColPtr->info.color = color;
  359.         os2ColPtr->index = index;
  360.  
  361.         if (index != -1) {
  362. #ifdef VERBOSE
  363.             printf("TkpGetColor systemcolor %d\n", index);
  364.             fflush(stdout);
  365. #endif
  366.             (&os2ColPtr->info.color)->pixel = WinQuerySysColor(HWND_DESKTOP,
  367.                                                                index, 0L);
  368.         }
  369.         XAllocColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
  370.                     &os2ColPtr->info.color);
  371. #ifdef VERBOSE
  372.         printf("TkpGetColor returns %x\n", (&os2ColPtr->info.color)->pixel);
  373.         fflush(stdout);
  374. #endif
  375.         return (TkColor *) os2ColPtr;
  376.     }
  377.     return (TkColor *) NULL;
  378. }
  379.  
  380. /*
  381.  *----------------------------------------------------------------------
  382.  *
  383.  * TkpGetColorByValue --
  384.  *
  385.  *      Given a desired set of red-green-blue intensities for a color,
  386.  *      locate a pixel value to use to draw that color in a given
  387.  *      window.
  388.  *
  389.  * Results:
  390.  *      The return value is a pointer to an TkColor structure that
  391.  *      indicates the closest red, blue, and green intensities available
  392.  *      to those specified in colorPtr, and also specifies a pixel
  393.  *      value to use to draw in that color.
  394.  *
  395.  * Side effects:
  396.  *      May invalidate the colormap cache for the specified window.
  397.  *      Allocates a new TkColor structure.
  398.  *
  399.  *----------------------------------------------------------------------
  400.  */
  401.  
  402. TkColor *
  403. TkpGetColorByValue(tkwin, colorPtr)
  404.     Tk_Window tkwin;            /* Window in which color will be used. */
  405.     XColor *colorPtr;           /* Red, green, and blue fields indicate
  406.                                  * desired color. */
  407. {
  408.     OS2Color *tkColPtr = (OS2Color *) ckalloc(sizeof(OS2Color));
  409.  
  410.     tkColPtr->info.color.red = colorPtr->red;
  411.     tkColPtr->info.color.green = colorPtr->green;
  412.     tkColPtr->info.color.blue = colorPtr->blue;
  413.     tkColPtr->info.color.pixel = 0;
  414.     tkColPtr->index = -1;
  415.     XAllocColor(Tk_Display(tkwin), Tk_Colormap(tkwin), &tkColPtr->info.color);
  416.     return (TkColor *) tkColPtr;
  417. }
  418.  
  419. /*
  420.  *----------------------------------------------------------------------
  421.  *
  422.  * TkpFreeColor --
  423.  *
  424.  *      Release the specified color back to the system.
  425.  *
  426.  * Results:
  427.  *      None
  428.  *
  429.  * Side effects:
  430.  *      Invalidates the colormap cache for the colormap associated with
  431.  *      the given color.
  432.  *
  433.  *----------------------------------------------------------------------
  434.  */
  435.  
  436. void
  437. TkpFreeColor(tkColPtr)
  438.     TkColor *tkColPtr;          /* Color to be released.  Must have been
  439.                                  * allocated by TkpGetColor or
  440.                                  * TkpGetColorByValue. */
  441. {
  442.     Screen *screen = tkColPtr->screen;
  443.  
  444.     XFreeColors(DisplayOfScreen(screen), tkColPtr->colormap,
  445.             &tkColPtr->color.pixel, 1, 0L);
  446. }
  447.  
  448. /*
  449.  *----------------------------------------------------------------------
  450.  *
  451.  * TkOS2IndexOfColor --
  452.  *
  453.  *      Given a color, return the system color index that was used
  454.  *      to create the color.
  455.  *
  456.  * Results:
  457.  *      If the color was allocated using a system indirect color name,
  458.  *      then the corresponding WinQuerySysColor() index is returned.
  459.  *      Otherwise, -1 is returned.
  460.  *
  461.  * Side effects:
  462.  *      None.
  463.  *
  464.  *----------------------------------------------------------------------
  465.  */
  466.  
  467. int
  468. TkOS2IndexOfColor(colorPtr)
  469.     XColor *colorPtr;
  470. {
  471.     register OS2Color *os2ColPtr = (OS2Color *) colorPtr;
  472.     if (os2ColPtr->info.magic == COLOR_MAGIC) {
  473.         return os2ColPtr->index;
  474.     }
  475.     return -1;
  476. }
  477.  
  478. /*
  479.  *----------------------------------------------------------------------
  480.  *
  481.  * XAllocColor --
  482.  *
  483.  *    Find the closest available color to the specified XColor.
  484.  *
  485.  * Results:
  486.  *    Updates the color argument and returns 1 on success.  Otherwise
  487.  *    returns 0.
  488.  *
  489.  * Side effects:
  490.  *    Allocates a new color in the palette.
  491.  *
  492.  *----------------------------------------------------------------------
  493.  */
  494.  
  495. int
  496. XAllocColor(display, colormap, color)
  497.     Display* display;
  498.     Colormap colormap;
  499.     XColor* color;
  500. {
  501.     TkOS2Colormap *cmap = (TkOS2Colormap *) colormap;
  502.     int new, refCount;
  503.     Tcl_HashEntry *entryPtr;
  504.     RGB entry;
  505.     HPAL oldPal;
  506.  
  507.     if (!initialized) {
  508.         InitColorTable(display);
  509.     }
  510.     color->pixel &= 0xffffff;
  511.  
  512.     /* We lose significance when converting to PM, 256 values per color */
  513.     entry.bRed = (color->red) >> 8;
  514.     entry.bGreen = (color->green) >> 8;
  515.     entry.bBlue = (color->blue) >> 8;
  516.  
  517. #ifdef VERBOSE
  518.     printf("XAllocColor %d %d %d (PM: %d %d %d) pixel %x cmap %x\n", color->red,
  519.            color->green, color->blue, entry.bRed, entry.bGreen, entry.bBlue,
  520.            color->pixel, cmap);
  521.             fflush(stdout);
  522. #endif
  523.  
  524.     if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  525.     /*
  526.      * Palette support
  527.      */
  528.     ULONG newPixel;
  529.         ULONG *palInfo;
  530.         HPS hps;
  531.         ULONG index, i;
  532.  
  533.         hps = WinGetScreenPS(HWND_DESKTOP);
  534.  
  535. #ifdef VERBOSE
  536.         printf("    Palette Manager; cmap->size %d\n", cmap->size);
  537.             fflush(stdout);
  538. #endif
  539.  
  540.     /*
  541.      * Find the nearest existing palette entry.
  542.      */
  543.     
  544.     newPixel = RGB(entry.bRed, entry.bGreen, entry.bBlue);
  545.     oldPal= GpiSelectPalette(hps, cmap->palette);
  546.     if (oldPal == PAL_ERROR) {
  547. #ifdef VERBOSE
  548.             printf("GpiSelectPalette PAL_ERROR: %x\n",
  549.                    WinGetLastError(TclOS2GetHAB()));
  550.             fflush(stdout);
  551. #endif
  552.             WinReleasePS(hps);
  553.             return 0;
  554.     }
  555.         palInfo= (ULONG *) ckalloc(sizeof(ULONG) * (cmap->size+1));
  556.  
  557.     if (GpiQueryPaletteInfo(cmap->palette, hps, 0L, 0L, cmap->size,
  558.                             palInfo) == PAL_ERROR) {
  559. #ifdef VERBOSE
  560.             printf("GpiQueryPaletteInfo size %d PAL_ERROR: %x\n", cmap->size,
  561.                    WinGetLastError(TclOS2GetHAB()));
  562.             fflush(stdout);
  563. #endif
  564.         GpiSelectPalette(hps, oldPal);
  565.             WinReleasePS(hps);
  566.             ckfree((char *) palInfo);
  567.             return 0;
  568.     }
  569.  
  570.         /*
  571.          * If this is not a duplicate, allocate a new entry.
  572.          */
  573.  
  574.         index = -1;
  575.         for (i=0; i<cmap->size; i++) {
  576. #ifdef VERBOSE
  577.             printf("    comparing palInfo[%d] (%x) to %x\n", i, palInfo[i],
  578.                    newPixel);
  579.             fflush(stdout);
  580. #endif
  581.             if (palInfo[i] == newPixel) {
  582.                 index = i;
  583.                 break;
  584.             }
  585.         }
  586.  
  587.         if (index == -1) {
  588. #ifdef VERBOSE
  589.             printf("    color not found in existing palette\n");
  590.             fflush(stdout);
  591. #endif
  592.  
  593.             /*
  594.              * Fails if the palette is full.
  595.              */
  596.             if (cmap->size == aDevCaps[CAPS_COLOR_INDEX]) {
  597. #ifdef VERBOSE
  598.                 printf("    no more entries in palette (%d)\n", cmap->size);
  599.                 fflush(stdout);
  600. #endif
  601.                 GpiSelectPalette(hps, oldPal);
  602.                 WinReleasePS(hps);
  603.                 ckfree((char *) palInfo);
  604.                 return 0;
  605.             }
  606.  
  607. index = cmap->size;
  608.             cmap->size++;
  609.             palInfo[cmap->size-1]= newPixel;
  610. #ifdef VERBOSE
  611.             printf("    adding pixel %x at %d\n", newPixel, cmap->size-1);
  612.             fflush(stdout);
  613. #endif
  614.             GpiSetPaletteEntries(cmap->palette, LCOLF_CONSECRGB, 0L, cmap->size,
  615.                                  palInfo);
  616.         }
  617.  
  618.         ckfree((char *) palInfo);
  619.  
  620.         /*
  621.          * Assign the _index_ in the palette as the pixel, for later use in
  622.          * GpiSetColor et al. ()
  623.          */
  624.         color->pixel = index;
  625. #ifdef VERBOSE
  626.         printf("Using index %d (0x%x) as color->pixel\n", index, index);
  627.         fflush(stdout);
  628. #endif
  629.     entryPtr = Tcl_CreateHashEntry(&cmap->refCounts,
  630.         (char *)color->pixel, &new);
  631.     if (new) {
  632. #ifdef VERBOSE
  633.             printf("Created new HashEntry: %d\n", color->pixel);
  634.             fflush(stdout);
  635. #endif
  636.         refCount = 1;
  637.     } else {
  638.         refCount = ((int) Tcl_GetHashValue(entryPtr)) + 1;
  639. #ifdef VERBOSE
  640.             printf("Incremented HashEntry %d to %d\n", color->pixel, refCount);
  641.             fflush(stdout);
  642. #endif
  643.     }
  644.     Tcl_SetHashValue(entryPtr, (ClientData)refCount);
  645.  
  646.     WinReleasePS(hps);
  647.  
  648.     } else {
  649.        LONG i, index = GPI_ALTERROR;
  650.  
  651. /*
  652.         color->pixel = GpiQueryNearestColor(globalPS, 0L,
  653.                                 RGB(entry.bRed, entry.bGreen, entry.bBlue));
  654. */
  655.         color->pixel = RGB(entry.bRed, entry.bGreen, entry.bBlue);
  656. #ifdef VERBOSE
  657.        printf("    no Palette Mgr, nr.colors %d (%s), nearest %x\n",
  658.               aDevCaps[CAPS_COLORS],
  659.               aDevCaps[CAPS_COLOR_TABLE_SUPPORT] ? "loadable color table" :
  660.               "no loadable color table", color->pixel);
  661.             fflush(stdout);
  662. #endif
  663.         color->red = (GetRValue(color->pixel) << 8);
  664.         color->green = (GetGValue(color->pixel) << 8);
  665.         color->blue = (GetBValue(color->pixel) << 8);
  666.  
  667.     /* Loadable color table support? */
  668.     if (aDevCaps[CAPS_COLOR_TABLE_SUPPORT]) {
  669.         /* Color table support */
  670.  
  671.         /*
  672.              * See if this color is already in the color table.
  673.              */
  674.             for (i=0; i<cmap->size; i++) {
  675. #ifdef VERBOSE
  676.                 printf("    comparing logColorTable[%d] (%x) to %x\n", i,
  677.                        logColorTable[i], color->pixel);
  678.                 fflush(stdout);
  679. #endif
  680.                 if (logColorTable[i] == color->pixel) {
  681.                     index = i;
  682.                     break;
  683.                 }
  684.             }
  685.             
  686.         /*
  687.          * If the color isn't in the table yet and loadable color table
  688.          * support, add this color to the table, else just use what's
  689.          * available.
  690.          */
  691. #ifdef VERBOSE
  692.             printf("   index %d\n", index);
  693.             printf("   nextColor (%d) <= aDevCaps[CAPS_COLOR_INDEX] (%d): %s\n",
  694.                nextColor, aDevCaps[CAPS_COLOR_INDEX],
  695.                nextColor <= aDevCaps[CAPS_COLOR_INDEX] ? "TRUE" : "FALSE");
  696.             fflush(stdout);
  697. #endif
  698.         if (index == GPI_ALTERROR) {
  699.             if (nextColor > aDevCaps[CAPS_COLOR_INDEX]) {
  700.                     return 0;
  701.                 }
  702.                 index = nextColor;
  703.  
  704.             rc = GpiCreateLogColorTable(globalPS, 0L, LCOLF_RGB,
  705.                                         nextColor, 1, &color->pixel);
  706.                 if (rc==TRUE) {
  707. #ifdef VERBOSE
  708.                     printf("    GpiCreateLogColorTable %x at %d OK\n",
  709.                    color->pixel, nextColor);
  710.                     fflush(stdout);
  711. #endif
  712.                     nextColor++;
  713.             /* Update "cache" color table */
  714.                     rc = GpiQueryLogColorTable(globalPS, 0L, 0L, nextColor,
  715.                                        logColorTable);
  716.                 }
  717.         }
  718.  
  719.         entryPtr = Tcl_CreateHashEntry(&cmap->refCounts,
  720.             (char *)color->pixel, &new);
  721.         if (new) {
  722. #ifdef VERBOSE
  723.                 printf("Created new HashEntry %d (0x%x) in %x\n", color->pixel,
  724.                        color->pixel, &cmap->refCounts);
  725.                 fflush(stdout);
  726. #endif
  727.             refCount = 1;
  728.         } else {
  729.             refCount = ((int) Tcl_GetHashValue(entryPtr)) + 1;
  730. #ifdef VERBOSE
  731.                 printf("Incremented HashEntry %d (0x%x) to %d in %x\n",
  732.                        color->pixel, color->pixel, refCount, &cmap->refCounts);
  733.                 fflush(stdout);
  734. #endif
  735.         }
  736.         Tcl_SetHashValue(entryPtr, (ClientData)refCount);
  737.         } else {
  738.     
  739.         /*
  740.          * Determine what color will actually be used on non-colormap
  741.          * systems.
  742.          */
  743.  
  744.         color->pixel = GpiQueryNearestColor(globalPS, 0L,
  745.             RGB(entry.bRed, entry.bGreen, entry.bBlue));
  746.         color->red = (GetRValue(color->pixel) << 8);
  747.         color->green = (GetGValue(color->pixel) << 8);
  748.         color->blue = (GetBValue(color->pixel) << 8);
  749. #ifdef VERBOSE
  750.             if (color->pixel==GPI_ALTERROR) {
  751.                 printf("GpiQueryNearestColor ERROR %x\n",
  752.                        WinGetLastError(TclOS2GetHAB()));
  753.             } else {
  754.                 printf(" Using nearest color %x (%d,%d,%d) for %x (%d,%d,%d)\n",
  755.                        color->pixel, GetRValue(color->pixel),
  756.                        GetGValue(color->pixel), GetBValue(color->pixel),
  757.                        RGB(entry.bRed, entry.bGreen, entry.bBlue),
  758.                        color->red, color->green, color->blue);
  759.             }
  760.             fflush(stdout);
  761. #endif
  762.             color->pixel = index;
  763.         }
  764.     }
  765. #ifdef VERBOSE
  766.     printf("color->pixel now %d/%x (%s)\n", color->pixel, color->pixel,
  767.            color->pixel == CLR_BACKGROUND ? "CLR_BACKGROUND" :
  768.            (color->pixel == CLR_BLUE ? "CLR_BLUE" :
  769.            (color->pixel == CLR_RED ? "CLR_RED" :
  770.            (color->pixel == CLR_PINK ? "CLR_PINK" :
  771.            (color->pixel == CLR_GREEN ? "CLR_GREEN" :
  772.            (color->pixel == CLR_CYAN ? "CLR_CYAN" :
  773.            (color->pixel == CLR_YELLOW ? "CLR_YELLOW" :
  774.            (color->pixel == CLR_NEUTRAL ? "CLR_NEUTRAL" :
  775.            (color->pixel == CLR_DARKGRAY ? "CLR_DARKGRAY" :
  776.            (color->pixel == CLR_DARKBLUE ? "CLR_DARKBLUE" :
  777.            (color->pixel == CLR_DARKRED ? "CLR_DARKRED" :
  778.            (color->pixel == CLR_DARKPINK ? "CLR_DARKPINK" :
  779.            (color->pixel == CLR_DARKGREEN ? "CLR_DARKGREEN" :
  780.            (color->pixel == CLR_DARKCYAN ? "CLR_DARKCYAN" :
  781.            (color->pixel == CLR_BROWN ? "CLR_BROWN" :
  782.            (color->pixel == CLR_PALEGRAY ? "CLR_PALEGRAY" : "UNKNOWN"
  783.        ))))))))))))))));
  784.             fflush(stdout);
  785. #endif
  786.  
  787.     return 1;
  788. }
  789.  
  790. /*
  791.  *----------------------------------------------------------------------
  792.  *
  793.  * XFreeColors --
  794.  *
  795.  *    Deallocate a block of colors.
  796.  *
  797.  * Results:
  798.  *    None.
  799.  *
  800.  * Side effects:
  801.  *    Removes entries for the current palette and compacts the
  802.  *    remaining set.
  803.  *
  804.  *----------------------------------------------------------------------
  805.  */
  806.  
  807. void
  808. XFreeColors(display, colormap, pixels, npixels, planes)
  809.     Display* display;
  810.     Colormap colormap;
  811.     unsigned long* pixels;
  812.     int npixels;
  813.     unsigned long planes;
  814. {
  815.     TkOS2Colormap *cmap = (TkOS2Colormap *) colormap;
  816.     ULONG delColor;
  817.     ULONG refCount;
  818.     int i, old, new;
  819.     ULONG *entries;
  820.     Tcl_HashEntry *entryPtr;
  821.  
  822. #ifdef VERBOSE
  823.     printf("XFreeColors\n");
  824.             fflush(stdout);
  825. #endif
  826.  
  827.     /*
  828.      * This is really slow for large values of npixels.
  829.      */
  830.     for (i = 0; i < npixels; i++) {
  831. #ifdef VERBOSE
  832.         printf("    pixel %d: %x\n", i, pixels[i]);
  833.             fflush(stdout);
  834. #endif
  835.         entryPtr = Tcl_FindHashEntry(&cmap->refCounts, (char *) pixels[i]);
  836.         if (!entryPtr) {
  837.             panic("Tried to free a color that isn't allocated.");
  838.         }
  839.         refCount = (int) Tcl_GetHashValue(entryPtr) - 1;
  840.         if (refCount > 0) {
  841.             Tcl_SetHashValue(entryPtr, (ClientData)refCount);
  842. #ifdef VERBOSE
  843.             printf("    decremented HashEntry %d to %d\n", pixels[i], refCount);
  844.             fflush(stdout);
  845. #endif
  846.         continue;
  847.     }
  848. #ifdef VERBOSE
  849.         printf("    refCount 0\n");
  850.             fflush(stdout);
  851. #endif
  852.         delColor = pixels[i] & 0x00ffffff;
  853.         entries = (ULONG *) ckalloc(sizeof(ULONG) * cmap->size);
  854.         if (!entries) {
  855.             return;
  856.         }
  857.  
  858.         if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  859.             /* hps value ignored for specific values of palette */
  860.             if (GpiQueryPaletteInfo(cmap->palette, NULLHANDLE, 0L, 0L,
  861.                                     cmap->size, entries) == PAL_ERROR) {
  862.                ckfree((char *)entries);
  863.                return;
  864.             }
  865.         } else {
  866.             if (GpiQueryLogColorTable(globalPS, 0L, 0L, cmap->size, entries)
  867.                 <= 0) {
  868.                ckfree((char *)entries);
  869.                return;
  870.             }
  871.         }
  872.  
  873.         /* Copy all entries except the one to delete */
  874.         for (old= new= 0; old<cmap->size; old++) {
  875.             if (old != delColor) {
  876. #ifdef VERBOSE
  877.                 printf("    copying %d\n", entries[old]);
  878.             fflush(stdout);
  879. #endif
  880.                 entries[new] = entries[old];
  881.                 new++;
  882.             }
  883.         }
  884.     cmap->size--;
  885.         if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  886.             GpiSetPaletteEntries(cmap->palette, LCOLF_CONSECRGB, 0, cmap->size,
  887.                              entries);
  888.         } else {
  889.             GpiCreateLogColorTable(globalPS, 0L, LCOLF_RGB, 0, cmap->size,
  890.                                    entries);
  891.         }
  892.         ckfree((char *) entries);
  893.         Tcl_DeleteHashEntry(entryPtr);
  894.     }
  895. }
  896.  
  897. /*
  898.  *----------------------------------------------------------------------
  899.  *
  900.  * XCreateColormap --
  901.  *
  902.  *    Allocate a new colormap.
  903.  *
  904.  * Results:
  905.  *    Returns a newly allocated colormap.
  906.  *
  907.  * Side effects:
  908.  *    Allocates an empty palette and color list.
  909.  *
  910.  *----------------------------------------------------------------------
  911.  */
  912.  
  913. Colormap
  914. XCreateColormap(display, w, visual, alloc)
  915.     Display* display;
  916.     Window w;
  917.     Visual* visual;
  918.     int alloc;
  919. {
  920.     TkOS2Colormap *cmap = (TkOS2Colormap *) ckalloc(sizeof(TkOS2Colormap));
  921.     ULONG *entryPtr;
  922.     Tcl_HashEntry *hashPtr;
  923.     ULONG logPalette[256];
  924.     ULONG lRetCount = PAL_ERROR;
  925.     ULONG i;
  926.     int new = 1;
  927.  
  928. #ifdef VERBOSE
  929.     printf("XCreateColormap (%d colors),
  930.     visual id %d class %d, bits %d, map entries %d, masks R%d G%d B%d\n",
  931.            aDevCaps[CAPS_COLOR_INDEX]+1, visual->visualid, visual->class,
  932.            visual->bits_per_rgb, visual->map_entries, visual->red_mask,
  933.            visual->green_mask, visual->blue_mask);
  934.     printf("    CAPS_COLORS %d\n", aDevCaps[CAPS_COLORS]);
  935.             fflush(stdout);
  936. #endif
  937.  
  938.     if (!initialized) {
  939.         InitColorTable(display);
  940.     }
  941.  
  942.     /*
  943.      * Create a palette when we have palette management, with default system
  944.      * entries.
  945.      * Otherwise store the presentation space handle of the window, since color
  946.      * tables are PS-specific.
  947.      */
  948.  
  949.     if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  950.  
  951.     lRetCount = GpiQueryPaletteInfo(NULLHANDLE, globalPS, 0L, 0L, 256L,
  952.                                     logPalette);
  953. #ifdef VERBOSE
  954.         if (lRetCount == PAL_ERROR) {
  955.             printf("    GpiQueryPaletteInfo PAL_ERROR %x\n",
  956.                WinGetLastError(TclOS2GetHAB()));
  957.             fflush(stdout);
  958.             ckfree((char *)cmap);
  959.         return (Colormap)NULL;
  960.         } else {
  961.             printf("    GpiQueryPaletteInfo: %x\n", cmap->palette);
  962.             fflush(stdout);
  963.         }
  964. #endif
  965.  
  966.         cmap->palette = GpiCreatePalette(TclOS2GetHAB(), 0L, LCOLF_CONSECRGB,
  967.                                          lRetCount, logPalette);
  968. #ifdef VERBOSE
  969.         if (cmap->palette == GPI_ERROR) {
  970.             printf("    GpiCreatePalette GPI_ERROR %x\n",
  971.                    WinGetLastError(TclOS2GetHAB()));
  972.             fflush(stdout);
  973.             ckfree((char *)cmap);
  974.         return (Colormap)NULL;
  975.         } else {
  976.             printf("    GpiCreatePalette: %x\n", cmap->palette);
  977.             fflush(stdout);
  978.         }
  979. #endif
  980.     } else {
  981.         cmap->palette = (HPAL)NULLHANDLE;
  982.     }
  983.  
  984.     cmap->size = 16;
  985.     cmap->stale = 0;
  986.     Tcl_InitHashTable(&cmap->refCounts, TCL_ONE_WORD_KEYS);
  987.  
  988.     if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  989.         /* Add hash entries for each of the static colors. */
  990.         for (i = 0; i < lRetCount; i++) {
  991.             entryPtr = logPalette + i;
  992.             hashPtr = Tcl_CreateHashEntry(&cmap->refCounts,
  993.             (char*) *entryPtr, &new);
  994.             Tcl_SetHashValue(hashPtr, (ClientData)1);
  995.         }
  996.     }
  997.  
  998.     return (Colormap)cmap;
  999. }
  1000.  
  1001. /*
  1002.  *----------------------------------------------------------------------
  1003.  *
  1004.  * XFreeColormap --
  1005.  *
  1006.  *    Frees the resources associated with the given colormap.
  1007.  *
  1008.  * Results:
  1009.  *    None.
  1010.  *
  1011.  * Side effects:
  1012.  *    Deletes the palette associated with the colormap.  Note that
  1013.  *    the palette must not be selected into a device context when
  1014.  *    this occurs.
  1015.  *
  1016.  *----------------------------------------------------------------------
  1017.  */
  1018.  
  1019. void
  1020. XFreeColormap(display, colormap)
  1021.     Display* display;
  1022.     Colormap colormap;
  1023. {
  1024.     TkOS2Colormap *cmap = (TkOS2Colormap *) colormap;
  1025.  
  1026. #ifdef VERBOSE
  1027.     printf("XFreeColormap\n");
  1028.             fflush(stdout);
  1029. #endif
  1030.  
  1031.     if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  1032.         /* Palette management */
  1033.         if (!GpiDeletePalette(cmap->palette)) {
  1034.             /* Try to free memory anyway */
  1035.             ckfree((char *) cmap);
  1036.         panic("Unable to free colormap, palette is still selected.");
  1037.         }
  1038.     }
  1039.     Tcl_DeleteHashTable(&cmap->refCounts);
  1040.     ckfree((char *) cmap);
  1041. }
  1042.  
  1043. /*
  1044.  *----------------------------------------------------------------------
  1045.  *
  1046.  * TkOS2SelectPalette --
  1047.  *
  1048.  *    This function sets up the specified device context with a
  1049.  *    given palette.  If the palette is stale, it realizes it in
  1050.  *    the background unless the palette is the current global
  1051.  *    palette.
  1052.  *
  1053.  * Results:
  1054.  *    Returns the previous palette selected into the device context.
  1055.  *
  1056.  * Side effects:
  1057.  *    May change the system palette.
  1058.  *
  1059.  *----------------------------------------------------------------------
  1060.  */
  1061.  
  1062. HPAL
  1063. TkOS2SelectPalette(hps, hwnd, colormap)
  1064.     HPS hps;
  1065.     HWND hwnd;
  1066.     Colormap colormap;
  1067. {
  1068.     TkOS2Colormap *cmap = (TkOS2Colormap *) colormap;
  1069.     HPAL oldPalette;
  1070.     ULONG mapped, changed;
  1071.  
  1072. #ifdef VERBOSE
  1073.     printf("TkOS2SelectPalette (cmap %x, palette %x), nextColor %d\n", cmap,
  1074.             cmap != 0 ? cmap->palette : 0, nextColor);
  1075.             fflush(stdout);
  1076. #endif
  1077.  
  1078.     if (aDevCaps[CAPS_ADDITIONAL_GRAPHICS] & CAPS_PALETTE_MANAGER) {
  1079.         oldPalette = GpiSelectPalette(hps, cmap->palette);
  1080. #ifdef VERBOSE
  1081.         if (oldPalette == PAL_ERROR) {
  1082.             printf("GpiSelectPalette PAL_ERROR: %x\n",
  1083.                    WinGetLastError(TclOS2GetHAB()));
  1084.         } else {
  1085.             printf("GpiSelectPalette: %x\n", oldPalette);
  1086.         }
  1087.             fflush(stdout);
  1088. #endif
  1089.         mapped = WinRealizePalette(hwnd, hps, &changed);
  1090. #ifdef VERBOSE
  1091.         if (mapped == PAL_ERROR) {
  1092.             printf("WinRealizePalette PAL_ERROR: %x\n",
  1093.                    WinGetLastError(TclOS2GetHAB()));
  1094.         } else {
  1095.             printf("WinRealizePalette: %x\n", mapped);
  1096.         }
  1097.             fflush(stdout);
  1098. #endif
  1099. /*
  1100. */
  1101.         return oldPalette;
  1102.     } else {
  1103.         /* Retrieve the "global" color table and create it in this PS */
  1104.         rc = GpiCreateLogColorTable(hps, 0L, LCOLF_RGB, 0, nextColor,
  1105.                                     logColorTable);
  1106. #ifdef VERBOSE
  1107.         if (rc!=TRUE) {
  1108.             printf("    GpiCreateLogColorTable (%d entries) ERROR %x\n",
  1109.                    nextColor, WinGetLastError(TclOS2GetHAB()));
  1110.         } else {
  1111.             printf("    GpiCreateLogColorTable (%d entries) OK\n", nextColor);
  1112.         }
  1113.             fflush(stdout);
  1114. #endif
  1115.         return (HPAL)0;
  1116.     }
  1117. }
  1118.