home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tkisrc04.zip / tk / os2 / tkCursor.c < prev    next >
C/C++ Source or Header  |  1998-08-07  |  11KB  |  385 lines

  1. /* 
  2.  * tkCursor.c --
  3.  *
  4.  *    This file maintains a database of read-only cursors for the Tk
  5.  *    toolkit.  This allows cursors to be shared between widgets and
  6.  *    also avoids round-trips to the X server.
  7.  *
  8.  * Copyright (c) 1990-1994 The Regents of the University of California.
  9.  * Copyright (c) 1994-1995 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.  * SCCS: @(#) tkCursor.c 1.27 96/02/15 18:52:40
  15.  */
  16.  
  17. #include "tkPort.h"
  18. #include "tkInt.h"
  19.  
  20. /*
  21.  * A TkCursor structure exists for each cursor that is currently
  22.  * active.  Each structure is indexed with two hash tables defined
  23.  * below.  One of the tables is idTable, and the other is either
  24.  * nameTable or dataTable, also defined below.
  25.  */
  26.  
  27. /*
  28.  * Hash table to map from a textual description of a cursor to the
  29.  * TkCursor record for the cursor, and key structure used in that
  30.  * hash table:
  31.  */
  32.  
  33. static Tcl_HashTable nameTable;
  34. typedef struct {
  35.     Tk_Uid name;        /* Textual name for desired cursor. */
  36.     Display *display;        /* Display for which cursor will be used. */
  37. } NameKey;
  38.  
  39. /*
  40.  * Hash table to map from a collection of in-core data about a
  41.  * cursor (bitmap contents, etc.) to a TkCursor structure:
  42.  */
  43.  
  44. static Tcl_HashTable dataTable;
  45. typedef struct {
  46.     char *source;        /* Cursor bits. */
  47.     char *mask;            /* Mask bits. */
  48.     int width, height;        /* Dimensions of cursor (and data
  49.                  * and mask). */
  50.     int xHot, yHot;        /* Location of cursor hot-spot. */
  51.     Tk_Uid fg, bg;        /* Colors for cursor. */
  52.     Display *display;        /* Display on which cursor will be used. */
  53. } DataKey;
  54.  
  55. /*
  56.  * Hash table that maps from <display + cursor id> to the TkCursor structure
  57.  * for the cursor.  This table is used by Tk_FreeCursor.
  58.  */
  59.  
  60. static Tcl_HashTable idTable;
  61. typedef struct {
  62.     Display *display;        /* Display for which cursor was allocated. */
  63.     Tk_Cursor cursor;        /* Cursor identifier. */
  64. } IdKey;
  65.  
  66. static int initialized = 0;    /* 0 means static structures haven't been
  67.                  * initialized yet. */
  68.  
  69. /*
  70.  * Forward declarations for procedures defined in this file:
  71.  */
  72.  
  73. static void        CursorInit _ANSI_ARGS_((void));
  74.  
  75. /*
  76.  *----------------------------------------------------------------------
  77.  *
  78.  * Tk_GetCursor --
  79.  *
  80.  *    Given a string describing a cursor, locate (or create if necessary)
  81.  *    a cursor that fits the description.
  82.  *
  83.  * Results:
  84.  *    The return value is the X identifer for the desired cursor,
  85.  *    unless string couldn't be parsed correctly.  In this case,
  86.  *    None is returned and an error message is left in interp->result.
  87.  *    The caller should never modify the cursor that is returned, and
  88.  *    should eventually call Tk_FreeCursor when the cursor is no longer
  89.  *    needed.
  90.  *
  91.  * Side effects:
  92.  *    The cursor is added to an internal database with a reference count.
  93.  *    For each call to this procedure, there should eventually be a call
  94.  *    to Tk_FreeCursor, so that the database can be cleaned up when cursors
  95.  *    aren't needed anymore.
  96.  *
  97.  *----------------------------------------------------------------------
  98.  */
  99.  
  100. Tk_Cursor
  101. Tk_GetCursor(interp, tkwin, string)
  102.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  103.     Tk_Window tkwin;        /* Window in which cursor will be used. */
  104.     Tk_Uid string;        /* Description of cursor.  See manual entry
  105.                  * for details on legal syntax. */
  106. {
  107.     NameKey nameKey;
  108.     IdKey idKey;
  109.     Tcl_HashEntry *nameHashPtr, *idHashPtr;
  110.     register TkCursor *cursorPtr;
  111.     int new;
  112.  
  113.     if (!initialized) {
  114.     CursorInit();
  115.     }
  116.  
  117.     nameKey.name = string;
  118.     nameKey.display = Tk_Display(tkwin);
  119.     nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new);
  120.     if (!new) {
  121.     cursorPtr = (TkCursor *) Tcl_GetHashValue(nameHashPtr);
  122.     cursorPtr->refCount++;
  123.     return cursorPtr->cursor;
  124.     }
  125.  
  126.     cursorPtr = TkGetCursorByName(interp, tkwin, string);
  127.  
  128.     if (cursorPtr == NULL) {
  129.     Tcl_DeleteHashEntry(nameHashPtr);
  130.     return None;
  131.     }
  132.  
  133.     /*
  134.      * Add information about this cursor to our database.
  135.      */
  136.  
  137.     cursorPtr->refCount = 1;
  138.     cursorPtr->otherTable = &nameTable;
  139.     cursorPtr->hashPtr = nameHashPtr;
  140.     idKey.display = nameKey.display;
  141.     idKey.cursor = cursorPtr->cursor;
  142.     idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new);
  143.     if (!new) {
  144.     panic("cursor already registered in Tk_GetCursor");
  145.     }
  146.     Tcl_SetHashValue(nameHashPtr, cursorPtr);
  147.     Tcl_SetHashValue(idHashPtr, cursorPtr);
  148.  
  149.     return cursorPtr->cursor;
  150. }
  151.  
  152. /*
  153.  *----------------------------------------------------------------------
  154.  *
  155.  * Tk_GetCursorFromData --
  156.  *
  157.  *    Given a description of the bits and colors for a cursor,
  158.  *    make a cursor that has the given properties.
  159.  *
  160.  * Results:
  161.  *    The return value is the X identifer for the desired cursor,
  162.  *    unless it couldn't be created properly.  In this case, None is
  163.  *    returned and an error message is left in interp->result.  The
  164.  *    caller should never modify the cursor that is returned, and
  165.  *    should eventually call Tk_FreeCursor when the cursor is no
  166.  *    longer needed.
  167.  *
  168.  * Side effects:
  169.  *    The cursor is added to an internal database with a reference count.
  170.  *    For each call to this procedure, there should eventually be a call
  171.  *    to Tk_FreeCursor, so that the database can be cleaned up when cursors
  172.  *    aren't needed anymore.
  173.  *
  174.  *----------------------------------------------------------------------
  175.  */
  176.  
  177. Tk_Cursor
  178. Tk_GetCursorFromData(interp, tkwin, source, mask, width, height,
  179.     xHot, yHot, fg, bg)
  180.     Tcl_Interp *interp;        /* Interpreter to use for error reporting. */
  181.     Tk_Window tkwin;        /* Window in which cursor will be used. */
  182.     char *source;        /* Bitmap data for cursor shape. */
  183.     char *mask;            /* Bitmap data for cursor mask. */
  184.     int width, height;        /* Dimensions of cursor. */
  185.     int xHot, yHot;        /* Location of hot-spot in cursor. */
  186.     Tk_Uid fg;            /* Foreground color for cursor. */
  187.     Tk_Uid bg;            /* Background color for cursor. */
  188. {
  189.     DataKey dataKey;
  190.     IdKey idKey;
  191.     Tcl_HashEntry *dataHashPtr, *idHashPtr;
  192.     register TkCursor *cursorPtr;
  193.     int new;
  194.     XColor fgColor, bgColor;
  195.  
  196.     if (!initialized) {
  197.     CursorInit();
  198.     }
  199.  
  200.     dataKey.source = source;
  201.     dataKey.mask = mask;
  202.     dataKey.width = width;
  203.     dataKey.height = height;
  204.     dataKey.xHot = xHot;
  205.     dataKey.yHot = yHot;
  206.     dataKey.fg = fg;
  207.     dataKey.bg = bg;
  208.     dataKey.display = Tk_Display(tkwin);
  209.     dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &dataKey, &new);
  210.     if (!new) {
  211.     cursorPtr = (TkCursor *) Tcl_GetHashValue(dataHashPtr);
  212.     cursorPtr->refCount++;
  213.     return cursorPtr->cursor;
  214.     }
  215.  
  216.     /*
  217.      * No suitable cursor exists yet.  Make one using the data
  218.      * available and add it to the database.
  219.      */
  220.  
  221.     if (XParseColor(dataKey.display, Tk_Colormap(tkwin), fg, &fgColor) == 0) {
  222.     Tcl_AppendResult(interp, "invalid color name \"", fg, "\"",
  223.         (char *) NULL);
  224.     goto error;
  225.     }
  226.     if (XParseColor(dataKey.display, Tk_Colormap(tkwin), bg, &bgColor) == 0) {
  227.     Tcl_AppendResult(interp, "invalid color name \"", bg, "\"",
  228.         (char *) NULL);
  229.     goto error;
  230.     }
  231.  
  232.     cursorPtr = TkCreateCursorFromData(tkwin, source, mask, width, height,
  233.         xHot, yHot, fgColor, bgColor);
  234.  
  235.     if (cursorPtr == NULL) {
  236.     goto error;
  237.     }
  238.  
  239.     cursorPtr->refCount = 1;
  240.     cursorPtr->otherTable = &dataTable;
  241.     cursorPtr->hashPtr = dataHashPtr;
  242.     idKey.display = dataKey.display;
  243.     idKey.cursor = cursorPtr->cursor;
  244.     idHashPtr = Tcl_CreateHashEntry(&idTable, (char *) &idKey, &new);
  245.     if (!new) {
  246.     panic("cursor already registered in Tk_GetCursorFromData");
  247.     }
  248.     Tcl_SetHashValue(dataHashPtr, cursorPtr);
  249.     Tcl_SetHashValue(idHashPtr, cursorPtr);
  250.     return cursorPtr->cursor;
  251.  
  252.     error:
  253.     Tcl_DeleteHashEntry(dataHashPtr);
  254.     return None;
  255. }
  256.  
  257. /*
  258.  *--------------------------------------------------------------
  259.  *
  260.  * Tk_NameOfCursor --
  261.  *
  262.  *    Given a cursor, return a textual string identifying it.
  263.  *
  264.  * Results:
  265.  *    If cursor was created by Tk_GetCursor, then the return
  266.  *    value is the "string" that was used to create it.
  267.  *    Otherwise the return value is a string giving the X
  268.  *    identifier for the cursor.  The storage for the returned
  269.  *    string is only guaranteed to persist up until the next
  270.  *    call to this procedure.
  271.  *
  272.  * Side effects:
  273.  *    None.
  274.  *
  275.  *--------------------------------------------------------------
  276.  */
  277.  
  278. char *
  279. Tk_NameOfCursor(display, cursor)
  280.     Display *display;        /* Display for which cursor was allocated. */
  281.     Tk_Cursor cursor;        /* Identifier for cursor whose name is
  282.                  * wanted. */
  283. {
  284.     IdKey idKey;
  285.     Tcl_HashEntry *idHashPtr;
  286.     TkCursor *cursorPtr;
  287.     static char string[20];
  288.  
  289.     if (!initialized) {
  290.     printid:
  291.     sprintf(string, "cursor id 0x%x", (unsigned int) cursor);
  292.     return string;
  293.     }
  294.     idKey.display = display;
  295.     idKey.cursor = cursor;
  296.     idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey);
  297.     if (idHashPtr == NULL) {
  298.     goto printid;
  299.     }
  300.     cursorPtr = (TkCursor *) Tcl_GetHashValue(idHashPtr);
  301.     if (cursorPtr->otherTable != &nameTable) {
  302.     goto printid;
  303.     }
  304.     return ((NameKey *) cursorPtr->hashPtr->key.words)->name;
  305. }
  306.  
  307. /*
  308.  *----------------------------------------------------------------------
  309.  *
  310.  * Tk_FreeCursor --
  311.  *
  312.  *    This procedure is called to release a cursor allocated by
  313.  *    Tk_GetCursor or TkGetCursorFromData.
  314.  *
  315.  * Results:
  316.  *    None.
  317.  *
  318.  * Side effects:
  319.  *    The reference count associated with cursor is decremented, and
  320.  *    it is officially deallocated if no-one is using it anymore.
  321.  *
  322.  *----------------------------------------------------------------------
  323.  */
  324.  
  325. void
  326. Tk_FreeCursor(display, cursor)
  327.     Display *display;        /* Display for which cursor was allocated. */
  328.     Tk_Cursor cursor;        /* Identifier for cursor to be released. */
  329. {
  330.     IdKey idKey;
  331.     Tcl_HashEntry *idHashPtr;
  332.     register TkCursor *cursorPtr;
  333.  
  334.     if (!initialized) {
  335.     panic("Tk_FreeCursor called before Tk_GetCursor");
  336.     }
  337.  
  338.     idKey.display = display;
  339.     idKey.cursor = cursor;
  340.     idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey);
  341.     if (idHashPtr == NULL) {
  342.     panic("Tk_FreeCursor received unknown cursor argument");
  343.     }
  344.     cursorPtr = (TkCursor *) Tcl_GetHashValue(idHashPtr);
  345.     cursorPtr->refCount--;
  346.     if (cursorPtr->refCount == 0) {
  347.     Tcl_DeleteHashEntry(cursorPtr->hashPtr);
  348.     Tcl_DeleteHashEntry(idHashPtr);
  349.     TkFreeCursor(cursorPtr);
  350.     }
  351. }
  352.  
  353. /*
  354.  *----------------------------------------------------------------------
  355.  *
  356.  * CursorInit --
  357.  *
  358.  *    Initialize the structures used for cursor management.
  359.  *
  360.  * Results:
  361.  *    None.
  362.  *
  363.  * Side effects:
  364.  *    Read the code.
  365.  *
  366.  *----------------------------------------------------------------------
  367.  */
  368.  
  369. static void
  370. CursorInit()
  371. {
  372.     initialized = 1;
  373.     Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int));
  374.     Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int));
  375.  
  376.     /*
  377.      * The call below is tricky:  can't use sizeof(IdKey) because it
  378.      * gets padded with extra unpredictable bytes on some 64-bit
  379.      * machines.
  380.      */
  381.  
  382.     Tcl_InitHashTable(&idTable, (sizeof(Display *) + sizeof(Tk_Cursor))
  383.         /sizeof(int));
  384. }
  385.