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

通讯编程

开发平台:

Visual C++

  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-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: tkCursor.c,v 1.9.2.2 2004/09/24 17:35:48 dgp Exp $
  15.  */
  16. #include "tkPort.h"
  17. #include "tkInt.h"
  18. /*
  19.  * A TkCursor structure exists for each cursor that is currently
  20.  * active.  Each structure is indexed with two hash tables defined
  21.  * below.  One of the tables is cursorIdTable, and the other is either
  22.  * cursorNameTable or cursorDataTable, each of which are stored in the
  23.  * TkDisplay structure for the current thread.
  24.  */
  25. typedef struct {
  26.     CONST char *source; /* Cursor bits. */
  27.     CONST char *mask; /* Mask bits. */
  28.     int width, height; /* Dimensions of cursor (and data
  29.  * and mask). */
  30.     int xHot, yHot; /* Location of cursor hot-spot. */
  31.     Tk_Uid fg, bg; /* Colors for cursor. */
  32.     Display *display; /* Display on which cursor will be used. */
  33. } DataKey;
  34. /*
  35.  * Forward declarations for procedures defined in this file:
  36.  */
  37. static void CursorInit _ANSI_ARGS_((TkDisplay *dispPtr));
  38. static void DupCursorObjProc _ANSI_ARGS_((Tcl_Obj *srcObjPtr,
  39.     Tcl_Obj *dupObjPtr));
  40. static void FreeCursor _ANSI_ARGS_((TkCursor *cursorPtr));
  41. static void FreeCursorObjProc _ANSI_ARGS_((Tcl_Obj *objPtr));
  42. static TkCursor * TkcGetCursor _ANSI_ARGS_((Tcl_Interp *interp,
  43.     Tk_Window tkwin, CONST char *name));
  44. static TkCursor * GetCursorFromObj _ANSI_ARGS_((Tk_Window tkwin,
  45.     Tcl_Obj *objPtr));
  46. static void InitCursorObj _ANSI_ARGS_((Tcl_Obj *objPtr));
  47. /*
  48.  * The following structure defines the implementation of the "cursor" Tcl
  49.  * object, used for drawing. The color object remembers the hash table
  50.  * entry associated with a color. The actual allocation and deallocation
  51.  * of the color should be done by the configuration package when the cursor
  52.  * option is set.
  53.  */
  54. Tcl_ObjType tkCursorObjType = {
  55.     "cursor", /* name */
  56.     FreeCursorObjProc, /* freeIntRepProc */
  57.     DupCursorObjProc, /* dupIntRepProc */
  58.     NULL, /* updateStringProc */
  59.     NULL /* setFromAnyProc */
  60. };
  61. /*
  62.  *----------------------------------------------------------------------
  63.  *
  64.  * Tk_AllocCursorFromObj --
  65.  *
  66.  * Given a Tcl_Obj *, map the value to a corresponding
  67.  * Tk_Cursor structure based on the tkwin given.
  68.  *
  69.  * Results:
  70.  * The return value is the X identifer for the desired cursor,
  71.  * unless objPtr couldn't be parsed correctly.  In this case,
  72.  * None is returned and an error message is left in the interp's result.
  73.  * The caller should never modify the cursor that is returned, and
  74.  * should eventually call Tk_FreeCursorFromObj when the cursor is no 
  75.  * longer needed.
  76.  *
  77.  * Side effects:
  78.  * The cursor is added to an internal database with a reference count.
  79.  * For each call to this procedure, there should eventually be a call
  80.  * to Tk_FreeCursorFromObj, so that the database can be cleaned up 
  81.  * when cursors aren't needed anymore.
  82.  *
  83.  *----------------------------------------------------------------------
  84.  */
  85. Tk_Cursor
  86. Tk_AllocCursorFromObj(interp, tkwin, objPtr)
  87.     Tcl_Interp *interp; /* Interp for error results. */
  88.     Tk_Window tkwin; /* Window in which the cursor will be used.*/
  89.     Tcl_Obj *objPtr; /* Object describing cursor; see manual
  90.  * entry for description of legal
  91.  * syntax of this obj's string rep. */
  92. {
  93.     TkCursor *cursorPtr;
  94.     if (objPtr->typePtr != &tkCursorObjType) {
  95. InitCursorObj(objPtr);
  96.     }
  97.     cursorPtr = (TkCursor *) objPtr->internalRep.twoPtrValue.ptr1;
  98.     /*
  99.      * If the object currently points to a TkCursor, see if it's the
  100.      * one we want.  If so, increment its reference count and return.
  101.      */
  102.     if (cursorPtr != NULL) {
  103. if (cursorPtr->resourceRefCount == 0) {
  104.     /*
  105.      * This is a stale reference: it refers to a TkCursor that's
  106.      * no longer in use.  Clear the reference.
  107.      */
  108.     FreeCursorObjProc(objPtr);
  109.     cursorPtr = NULL;
  110. } else if (Tk_Display(tkwin) == cursorPtr->display) {
  111.     cursorPtr->resourceRefCount++;
  112.     return cursorPtr->cursor;
  113. }
  114.     }
  115.     /*
  116.      * The object didn't point to the TkCursor that we wanted.  Search
  117.      * the list of TkCursors with the same name to see if one of the
  118.      * other TkCursors is the right one.
  119.      */
  120.     if (cursorPtr != NULL) {
  121. TkCursor *firstCursorPtr =
  122. (TkCursor *) Tcl_GetHashValue(cursorPtr->hashPtr);
  123. FreeCursorObjProc(objPtr);
  124. for (cursorPtr = firstCursorPtr;  cursorPtr != NULL;
  125. cursorPtr = cursorPtr->nextPtr) {
  126.     if (Tk_Display(tkwin) == cursorPtr->display) {
  127. cursorPtr->resourceRefCount++;
  128. cursorPtr->objRefCount++;
  129. objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) cursorPtr;
  130. return cursorPtr->cursor;
  131.     }
  132. }
  133.     }
  134.     /*
  135.      * Still no luck.  Call TkcGetCursor to allocate a new TkCursor object.
  136.      */
  137.     cursorPtr = TkcGetCursor(interp, tkwin, Tcl_GetString(objPtr));
  138.     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) cursorPtr;
  139.     if (cursorPtr == NULL) {
  140. return None;
  141.     } else {
  142. cursorPtr->objRefCount++;
  143. return cursorPtr->cursor;
  144.     }
  145. }
  146. /*
  147.  *----------------------------------------------------------------------
  148.  *
  149.  * Tk_GetCursor --
  150.  *
  151.  * Given a string describing a cursor, locate (or create if necessary)
  152.  * a cursor that fits the description.
  153.  *
  154.  * Results:
  155.  * The return value is the X identifer for the desired cursor,
  156.  * unless string couldn't be parsed correctly.  In this case,
  157.  * None is returned and an error message is left in the interp's result.
  158.  * The caller should never modify the cursor that is returned, and
  159.  * should eventually call Tk_FreeCursor when the cursor is no longer
  160.  * needed.
  161.  *
  162.  * Side effects:
  163.  * The cursor is added to an internal database with a reference count.
  164.  * For each call to this procedure, there should eventually be a call
  165.  * to Tk_FreeCursor, so that the database can be cleaned up when cursors
  166.  * aren't needed anymore.
  167.  *
  168.  *----------------------------------------------------------------------
  169.  */
  170. Tk_Cursor
  171. Tk_GetCursor(interp, tkwin, string)
  172.     Tcl_Interp *interp; /* Interpreter to use for error reporting. */
  173.     Tk_Window tkwin; /* Window in which cursor will be used. */
  174.     Tk_Uid string; /* Description of cursor.  See manual entry
  175.  * for details on legal syntax. */
  176. {
  177.     TkCursor *cursorPtr = TkcGetCursor(interp, tkwin, string);
  178.     if (cursorPtr == NULL) {
  179. return None;
  180.     }
  181.     return cursorPtr->cursor;
  182. }
  183. /*
  184.  *----------------------------------------------------------------------
  185.  *
  186.  * TkcGetCursor --
  187.  *
  188.  * Given a string describing a cursor, locate (or create if necessary)
  189.  * a cursor that fits the description. This routine returns the
  190.  * internal data structure for the cursor, which avoids extra
  191.  * hash table lookups in Tk_AllocCursorFromObj.
  192.  *
  193.  * Results:
  194.  * The return value is a pointer to the TkCursor for the desired
  195.  * cursor, unless string couldn't be parsed correctly.  In this
  196.  * case, NULL is returned and an error message is left in the
  197.  * interp's result. The caller should never modify the cursor that
  198.  * is returned, and should eventually call Tk_FreeCursor when the
  199.  * cursor is no longer needed.
  200.  *
  201.  * Side effects:
  202.  * The cursor is added to an internal database with a reference count.
  203.  * For each call to this procedure, there should eventually be a call
  204.  * to Tk_FreeCursor, so that the database can be cleaned up when cursors
  205.  * aren't needed anymore.
  206.  *
  207.  *----------------------------------------------------------------------
  208.  */
  209. static TkCursor *
  210. TkcGetCursor(interp, tkwin, string)
  211.     Tcl_Interp *interp; /* Interpreter to use for error reporting. */
  212.     Tk_Window tkwin; /* Window in which cursor will be used. */
  213.     CONST char *string; /* Description of cursor.  See manual entry
  214.  * for details on legal syntax. */
  215. {
  216.     Tcl_HashEntry *nameHashPtr;
  217.     register TkCursor *cursorPtr;
  218.     TkCursor *existingCursorPtr = NULL;
  219.     int new;
  220.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  221.     if (!dispPtr->cursorInit) {
  222. CursorInit(dispPtr);
  223.     }
  224.     nameHashPtr = Tcl_CreateHashEntry(&dispPtr->cursorNameTable, 
  225.             string, &new);
  226.     if (!new) {
  227. existingCursorPtr = (TkCursor *) Tcl_GetHashValue(nameHashPtr);
  228. for (cursorPtr = existingCursorPtr; cursorPtr != NULL;
  229. cursorPtr = cursorPtr->nextPtr) {
  230.     if (Tk_Display(tkwin) == cursorPtr->display) {
  231. cursorPtr->resourceRefCount++;
  232. return cursorPtr;
  233.     }
  234. }
  235.     } else {
  236. existingCursorPtr = NULL;
  237.     }
  238.     cursorPtr = TkGetCursorByName(interp, tkwin, string);
  239.     if (cursorPtr == NULL) {
  240. if (new) {
  241.     Tcl_DeleteHashEntry(nameHashPtr);
  242. }
  243. return NULL;
  244.     }
  245.     /*
  246.      * Add information about this cursor to our database.
  247.      */
  248.     cursorPtr->display = Tk_Display(tkwin);
  249.     cursorPtr->resourceRefCount = 1;
  250.     cursorPtr->objRefCount = 0;
  251.     cursorPtr->otherTable = &dispPtr->cursorNameTable;
  252.     cursorPtr->hashPtr = nameHashPtr;
  253.     cursorPtr->nextPtr = existingCursorPtr;
  254.     cursorPtr->idHashPtr = Tcl_CreateHashEntry(&dispPtr->cursorIdTable, 
  255.             (char *) cursorPtr->cursor, &new);
  256.     if (!new) {
  257. panic("cursor already registered in Tk_GetCursor");
  258.     }
  259.     Tcl_SetHashValue(nameHashPtr, cursorPtr);
  260.     Tcl_SetHashValue(cursorPtr->idHashPtr, cursorPtr);
  261.     return cursorPtr;
  262. }
  263. /*
  264.  *----------------------------------------------------------------------
  265.  *
  266.  * Tk_GetCursorFromData --
  267.  *
  268.  * Given a description of the bits and colors for a cursor,
  269.  * make a cursor that has the given properties.
  270.  *
  271.  * Results:
  272.  * The return value is the X identifer for the desired cursor,
  273.  * unless it couldn't be created properly.  In this case, None is
  274.  * returned and an error message is left in the interp's result.  The
  275.  * caller should never modify the cursor that is returned, and
  276.  * should eventually call Tk_FreeCursor when the cursor is no
  277.  * longer needed.
  278.  *
  279.  * Side effects:
  280.  * The cursor is added to an internal database with a reference count.
  281.  * For each call to this procedure, there should eventually be a call
  282.  * to Tk_FreeCursor, so that the database can be cleaned up when cursors
  283.  * aren't needed anymore.
  284.  *
  285.  *----------------------------------------------------------------------
  286.  */
  287. Tk_Cursor
  288. Tk_GetCursorFromData(interp, tkwin, source, mask, width, height,
  289. xHot, yHot, fg, bg)
  290.     Tcl_Interp *interp; /* Interpreter to use for error reporting. */
  291.     Tk_Window tkwin; /* Window in which cursor will be used. */
  292.     CONST char *source; /* Bitmap data for cursor shape. */
  293.     CONST char *mask; /* Bitmap data for cursor mask. */
  294.     int width, height; /* Dimensions of cursor. */
  295.     int xHot, yHot; /* Location of hot-spot in cursor. */
  296.     Tk_Uid fg; /* Foreground color for cursor. */
  297.     Tk_Uid bg; /* Background color for cursor. */
  298. {
  299.     DataKey dataKey;
  300.     Tcl_HashEntry *dataHashPtr;
  301.     register TkCursor *cursorPtr;
  302.     int new;
  303.     XColor fgColor, bgColor;
  304.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  305.     if (!dispPtr->cursorInit) {
  306. CursorInit(dispPtr);
  307.     }
  308.     dataKey.source = source;
  309.     dataKey.mask = mask;
  310.     dataKey.width = width;
  311.     dataKey.height = height;
  312.     dataKey.xHot = xHot;
  313.     dataKey.yHot = yHot;
  314.     dataKey.fg = fg;
  315.     dataKey.bg = bg;
  316.     dataKey.display = Tk_Display(tkwin);
  317.     dataHashPtr = Tcl_CreateHashEntry(&dispPtr->cursorDataTable, 
  318.             (char *) &dataKey, &new);
  319.     if (!new) {
  320. cursorPtr = (TkCursor *) Tcl_GetHashValue(dataHashPtr);
  321. cursorPtr->resourceRefCount++;
  322. return cursorPtr->cursor;
  323.     }
  324.     /*
  325.      * No suitable cursor exists yet.  Make one using the data
  326.      * available and add it to the database.
  327.      */
  328.     if (XParseColor(dataKey.display, Tk_Colormap(tkwin), fg, &fgColor) == 0) {
  329. Tcl_AppendResult(interp, "invalid color name "", fg, """,
  330. (char *) NULL);
  331. goto error;
  332.     }
  333.     if (XParseColor(dataKey.display, Tk_Colormap(tkwin), bg, &bgColor) == 0) {
  334. Tcl_AppendResult(interp, "invalid color name "", bg, """,
  335. (char *) NULL);
  336. goto error;
  337.     }
  338.     cursorPtr = TkCreateCursorFromData(tkwin, source, mask, width, height,
  339.     xHot, yHot, fgColor, bgColor);
  340.     if (cursorPtr == NULL) {
  341. goto error;
  342.     }
  343.     cursorPtr->resourceRefCount = 1;
  344.     cursorPtr->otherTable = &dispPtr->cursorDataTable;
  345.     cursorPtr->hashPtr = dataHashPtr;
  346.     cursorPtr->objRefCount = 0;
  347.     cursorPtr->idHashPtr = Tcl_CreateHashEntry(&dispPtr->cursorIdTable, 
  348.             (char *) cursorPtr->cursor, &new);
  349.     cursorPtr->nextPtr = NULL;
  350.     if (!new) {
  351. panic("cursor already registered in Tk_GetCursorFromData");
  352.     }
  353.     Tcl_SetHashValue(dataHashPtr, cursorPtr);
  354.     Tcl_SetHashValue(cursorPtr->idHashPtr, cursorPtr);
  355.     return cursorPtr->cursor;
  356.     error:
  357.     Tcl_DeleteHashEntry(dataHashPtr);
  358.     return None;
  359. }
  360. /*
  361.  *--------------------------------------------------------------
  362.  *
  363.  * Tk_NameOfCursor --
  364.  *
  365.  * Given a cursor, return a textual string identifying it.
  366.  *
  367.  * Results:
  368.  * If cursor was created by Tk_GetCursor, then the return
  369.  * value is the "string" that was used to create it.
  370.  * Otherwise the return value is a string giving the X
  371.  * identifier for the cursor.  The storage for the returned
  372.  * string is only guaranteed to persist up until the next
  373.  * call to this procedure.
  374.  *
  375.  * Side effects:
  376.  * None.
  377.  *
  378.  *--------------------------------------------------------------
  379.  */
  380. CONST char *
  381. Tk_NameOfCursor(display, cursor)
  382.     Display *display; /* Display for which cursor was allocated. */
  383.     Tk_Cursor cursor; /* Identifier for cursor whose name is
  384.  * wanted. */
  385. {
  386.     Tcl_HashEntry *idHashPtr;
  387.     TkCursor *cursorPtr;
  388.     TkDisplay *dispPtr;
  389.     dispPtr = TkGetDisplay(display);
  390.     if (!dispPtr->cursorInit) {
  391. printid:
  392. sprintf(dispPtr->cursorString, "cursor id 0x%x", 
  393.                 (unsigned int) cursor);
  394. return dispPtr->cursorString;
  395.     }
  396.     idHashPtr = Tcl_FindHashEntry(&dispPtr->cursorIdTable, (char *) cursor);
  397.     if (idHashPtr == NULL) {
  398. goto printid;
  399.     }
  400.     cursorPtr = (TkCursor *) Tcl_GetHashValue(idHashPtr);
  401.     if (cursorPtr->otherTable != &dispPtr->cursorNameTable) {
  402. goto printid;
  403.     }
  404.     return cursorPtr->hashPtr->key.string;
  405. }
  406. /*
  407.  *----------------------------------------------------------------------
  408.  *
  409.  * FreeCursor --
  410.  *
  411.  * This procedure is invoked by both Tk_FreeCursor and
  412.  * Tk_FreeCursorFromObj; it does all the real work of deallocating
  413.  * a cursor.
  414.  *
  415.  * Results:
  416.  * None.
  417.  *
  418.  * Side effects:
  419.  * The reference count associated with cursor is decremented, and
  420.  * it is officially deallocated if no-one is using it anymore.
  421.  *
  422.  *----------------------------------------------------------------------
  423.  */
  424. static void
  425. FreeCursor(cursorPtr)
  426.     TkCursor *cursorPtr; /* Cursor to be released. */
  427. {
  428.     TkCursor *prevPtr;
  429.     cursorPtr->resourceRefCount--;
  430.     if (cursorPtr->resourceRefCount > 0) {
  431. return;
  432.     }
  433.     Tcl_DeleteHashEntry(cursorPtr->idHashPtr);
  434.     prevPtr = (TkCursor *) Tcl_GetHashValue(cursorPtr->hashPtr);
  435.     if (prevPtr == cursorPtr) {
  436. if (cursorPtr->nextPtr == NULL) {
  437.     Tcl_DeleteHashEntry(cursorPtr->hashPtr);
  438. } else {
  439.     Tcl_SetHashValue(cursorPtr->hashPtr, cursorPtr->nextPtr);
  440. }
  441.     } else {
  442. while (prevPtr->nextPtr != cursorPtr) {
  443.     prevPtr = prevPtr->nextPtr;
  444. }
  445. prevPtr->nextPtr = cursorPtr->nextPtr;
  446.     }
  447.     TkpFreeCursor(cursorPtr);
  448.     if (cursorPtr->objRefCount == 0) {
  449. ckfree((char *) cursorPtr);
  450.     }
  451. }
  452. /*
  453.  *----------------------------------------------------------------------
  454.  *
  455.  * Tk_FreeCursor --
  456.  *
  457.  * This procedure is called to release a cursor allocated by
  458.  * Tk_GetCursor or TkGetCursorFromData.
  459.  *
  460.  * Results:
  461.  * None.
  462.  *
  463.  * Side effects:
  464.  * The reference count associated with cursor is decremented, and
  465.  * it is officially deallocated if no-one is using it anymore.
  466.  *
  467.  *----------------------------------------------------------------------
  468.  */
  469. void
  470. Tk_FreeCursor(display, cursor)
  471.     Display *display; /* Display for which cursor was allocated. */
  472.     Tk_Cursor cursor; /* Identifier for cursor to be released. */
  473. {
  474.     Tcl_HashEntry *idHashPtr;
  475.     TkDisplay *dispPtr = TkGetDisplay(display);
  476.     if (!dispPtr->cursorInit) {
  477. panic("Tk_FreeCursor called before Tk_GetCursor");
  478.     }
  479.     idHashPtr = Tcl_FindHashEntry(&dispPtr->cursorIdTable, (char *) cursor);
  480.     if (idHashPtr == NULL) {
  481. panic("Tk_FreeCursor received unknown cursor argument");
  482.     }
  483.     FreeCursor((TkCursor *) Tcl_GetHashValue(idHashPtr));
  484. }
  485. /*
  486.  *----------------------------------------------------------------------
  487.  *
  488.  * Tk_FreeCursorFromObj --
  489.  *
  490.  * This procedure is called to release a cursor allocated by
  491.  * Tk_AllocCursorFromObj. It does not throw away the Tcl_Obj *;
  492.  * it only gets rid of the hash table entry for this cursor
  493.  * and clears the cached value that is normally stored in the object.
  494.  *
  495.  * Results:
  496.  * None.
  497.  *
  498.  * Side effects:
  499.  * The reference count associated with the cursor represented by
  500.  * objPtr is decremented, and the cursor is released to X if there are 
  501.  * no remaining uses for it.
  502.  *
  503.  *----------------------------------------------------------------------
  504.  */
  505. void
  506. Tk_FreeCursorFromObj(tkwin, objPtr)
  507.     Tk_Window tkwin; /* The window this cursor lives in. Needed
  508.  * for the display value. */
  509.     Tcl_Obj *objPtr; /* The Tcl_Obj * to be freed. */
  510. {
  511.     FreeCursor(GetCursorFromObj(tkwin, objPtr));
  512.     FreeCursorObjProc(objPtr);
  513. }
  514. /*
  515.  *---------------------------------------------------------------------------
  516.  *
  517.  * FreeCursorFromObjProc -- 
  518.  *
  519.  * This proc is called to release an object reference to a cursor.
  520.  * Called when the object's internal rep is released or when
  521.  * the cached tkColPtr needs to be changed.
  522.  *
  523.  * Results:
  524.  * None.
  525.  *
  526.  * Side effects:
  527.  * The object reference count is decremented. When both it
  528.  * and the hash ref count go to zero, the color's resources
  529.  * are released.
  530.  *
  531.  *---------------------------------------------------------------------------
  532.  */
  533. static void
  534. FreeCursorObjProc(objPtr)
  535.     Tcl_Obj *objPtr; /* The object we are releasing. */
  536. {
  537.     TkCursor *cursorPtr = (TkCursor *) objPtr->internalRep.twoPtrValue.ptr1;
  538.     if (cursorPtr != NULL) {
  539. cursorPtr->objRefCount--;
  540. if ((cursorPtr->objRefCount == 0) 
  541. && (cursorPtr->resourceRefCount == 0)) {
  542.     ckfree((char *) cursorPtr);
  543. }
  544. objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL;
  545.     }
  546. }
  547. /*
  548.  *---------------------------------------------------------------------------
  549.  *
  550.  * DupCursorObjProc -- 
  551.  *
  552.  * When a cached cursor object is duplicated, this is called to
  553.  * update the internal reps.
  554.  *
  555.  * Results:
  556.  * None.
  557.  *
  558.  * Side effects:
  559.  * The color's objRefCount is incremented and the internal rep
  560.  * of the copy is set to point to it.
  561.  *
  562.  *---------------------------------------------------------------------------
  563.  */
  564. static void
  565. DupCursorObjProc(srcObjPtr, dupObjPtr)
  566.     Tcl_Obj *srcObjPtr; /* The object we are copying from. */
  567.     Tcl_Obj *dupObjPtr; /* The object we are copying to. */
  568. {
  569.     TkCursor *cursorPtr = (TkCursor *) srcObjPtr->internalRep.twoPtrValue.ptr1;
  570.     
  571.     dupObjPtr->typePtr = srcObjPtr->typePtr;
  572.     dupObjPtr->internalRep.twoPtrValue.ptr1 = (VOID *) cursorPtr;
  573.     if (cursorPtr != NULL) {
  574. cursorPtr->objRefCount++;
  575.     }
  576. }
  577. /*
  578.  *----------------------------------------------------------------------
  579.  *
  580.  * Tk_GetCursorFromObj --
  581.  *
  582.  * Returns the cursor referred to buy a Tcl object. The cursor must
  583.  * already have been allocated via a call to Tk_AllocCursorFromObj or 
  584.  * Tk_GetCursor.
  585.  *
  586.  * Results:
  587.  * Returns the Tk_Cursor that matches the tkwin and the string rep
  588.  * of the name of the cursor given in objPtr.
  589.  *
  590.  * Side effects:
  591.  * If the object is not already a cursor, the conversion will free
  592.  * any old internal representation. 
  593.  *
  594.  *----------------------------------------------------------------------
  595.  */
  596. Tk_Cursor
  597. Tk_GetCursorFromObj(tkwin, objPtr)
  598.     Tk_Window tkwin;
  599.     Tcl_Obj *objPtr; /* The object from which to get pixels. */
  600. {
  601.     TkCursor *cursorPtr = GetCursorFromObj(tkwin, objPtr);
  602.     /* GetCursorFromObj should never return NULL */
  603.     return cursorPtr->cursor;
  604. }
  605. /*
  606.  *----------------------------------------------------------------------
  607.  *
  608.  * GetCursorFromObj --
  609.  *
  610.  * Returns the cursor referred to by a Tcl object.  The cursor must
  611.  * already have been allocated via a call to Tk_AllocCursorFromObj
  612.  * or Tk_GetCursor.
  613.  *
  614.  * Results:
  615.  * Returns the TkCursor * that matches the tkwin and the string rep
  616.  * of the name of the cursor given in objPtr.
  617.  *
  618.  * Side effects:
  619.  * If the object is not already a cursor, the conversion will free
  620.  * any old internal representation. 
  621.  *
  622.  *----------------------------------------------------------------------
  623.  */
  624. static TkCursor *
  625. GetCursorFromObj(tkwin, objPtr)
  626.     Tk_Window tkwin; /* Window in which the cursor will be used. */
  627.     Tcl_Obj *objPtr; /* The object that describes the desired
  628.  * cursor. */
  629. {
  630.     TkCursor *cursorPtr;
  631.     Tcl_HashEntry *hashPtr;
  632.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  633.     if (objPtr->typePtr != &tkCursorObjType) {
  634. InitCursorObj(objPtr);
  635.     }
  636.     /*
  637.      * The internal representation is a cache of the last cursor used
  638.      * with the given name.  But there can be lots different cursors
  639.      * for each cursor name; one cursor for each display.  Check to
  640.      * see if the cursor we have cached is the one that is needed.
  641.      */
  642.     cursorPtr = (TkCursor *) objPtr->internalRep.twoPtrValue.ptr1;
  643.     if ((cursorPtr != NULL) && (Tk_Display(tkwin) == cursorPtr->display)) {
  644. return cursorPtr;
  645.     }
  646.     /*
  647.      * If we get to here, it means the cursor we need is not in the cache.
  648.      * Try to look up the cursor in the TkDisplay structure of the window.
  649.      */
  650.     hashPtr = Tcl_FindHashEntry(&dispPtr->cursorNameTable,
  651.     Tcl_GetString(objPtr));
  652.     if (hashPtr == NULL) {
  653. goto error;
  654.     }
  655.     for (cursorPtr = (TkCursor *) Tcl_GetHashValue(hashPtr);
  656.     cursorPtr != NULL; cursorPtr = cursorPtr->nextPtr) {
  657. if (Tk_Display(tkwin) == cursorPtr->display) {
  658.     FreeCursorObjProc(objPtr);
  659.     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) cursorPtr;
  660.     cursorPtr->objRefCount++;
  661.     return cursorPtr;
  662. }
  663.     }
  664.     error:
  665.     panic("GetCursorFromObj called with non-existent cursor!");
  666.     /*
  667.      * The following code isn't reached; it's just there to please compilers.
  668.      */
  669.     return NULL;
  670. }
  671. /*
  672.  *----------------------------------------------------------------------
  673.  *
  674.  * InitCursorObj --
  675.  *
  676.  * Bookeeping procedure to change an objPtr to a cursor type.
  677.  *
  678.  * Results:
  679.  * None.
  680.  *
  681.  * Side effects:
  682.  * The old internal rep of the object is freed. The internal
  683.  * rep is cleared. The final form of the object is set
  684.  * by either Tk_AllocCursorFromObj or GetCursorFromObj.
  685.  *
  686.  *----------------------------------------------------------------------
  687.  */
  688. static void
  689. InitCursorObj(objPtr)
  690.     Tcl_Obj *objPtr; /* The object to convert. */
  691. {
  692.     Tcl_ObjType *typePtr;
  693.     /*
  694.      * Free the old internalRep before setting the new one. 
  695.      */
  696.     Tcl_GetString(objPtr);
  697.     typePtr = objPtr->typePtr;
  698.     if ((typePtr != NULL) && (typePtr->freeIntRepProc != NULL)) {
  699. (*typePtr->freeIntRepProc)(objPtr);
  700.     }
  701.     objPtr->typePtr = &tkCursorObjType;
  702.     objPtr->internalRep.twoPtrValue.ptr1 = (VOID *) NULL;
  703. }
  704. /*
  705.  *----------------------------------------------------------------------
  706.  *
  707.  * CursorInit --
  708.  *
  709.  * Initialize the structures used for cursor management.
  710.  *
  711.  * Results:
  712.  * None.
  713.  *
  714.  * Side effects:
  715.  * Read the code.
  716.  *
  717.  *----------------------------------------------------------------------
  718.  */
  719. static void
  720. CursorInit(dispPtr)
  721.     TkDisplay *dispPtr;   /* Display used to store thread-specific data. */
  722. {
  723.     Tcl_InitHashTable(&dispPtr->cursorNameTable, TCL_STRING_KEYS);
  724.     Tcl_InitHashTable(&dispPtr->cursorDataTable, sizeof(DataKey)/sizeof(int));
  725.     /*
  726.      * The call below is tricky:  can't use sizeof(IdKey) because it
  727.      * gets padded with extra unpredictable bytes on some 64-bit
  728.      * machines.
  729.      */
  730.     /* 
  731.      *  Old code....
  732.      *     Tcl_InitHashTable(&dispPtr->cursorIdTable, sizeof(Display *) 
  733.      *                       /sizeof(int));
  734.      *
  735.      * The comment above doesn't make sense.
  736.      * However, XIDs should only be 32 bits, by the definition of X,
  737.      * so the code above causes Tk to crash.  Here is the real code:
  738.      */
  739.     Tcl_InitHashTable(&dispPtr->cursorIdTable, TCL_ONE_WORD_KEYS);
  740.     dispPtr->cursorInit = 1;
  741. }
  742. /*
  743.  *----------------------------------------------------------------------
  744.  *
  745.  * TkDebugCursor --
  746.  *
  747.  * This procedure returns debugging information about a cursor.
  748.  *
  749.  * Results:
  750.  * The return value is a list with one sublist for each TkCursor
  751.  * corresponding to "name".  Each sublist has two elements that
  752.  * contain the resourceRefCount and objRefCount fields from the
  753.  * TkCursor structure.
  754.  *
  755.  * Side effects:
  756.  * None.
  757.  *
  758.  *----------------------------------------------------------------------
  759.  */
  760. Tcl_Obj *
  761. TkDebugCursor(tkwin, name)
  762.     Tk_Window tkwin; /* The window in which the cursor will be
  763.  * used (not currently used). */
  764.     char *name; /* Name of the desired color. */
  765. {
  766.     TkCursor *cursorPtr;
  767.     Tcl_HashEntry *hashPtr;
  768.     Tcl_Obj *resultPtr, *objPtr;
  769.     TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
  770.     if (!dispPtr->cursorInit) {
  771. CursorInit(dispPtr);
  772.     }
  773.     resultPtr = Tcl_NewObj();
  774.     hashPtr = Tcl_FindHashEntry(&dispPtr->cursorNameTable, name);
  775.     if (hashPtr != NULL) {
  776. cursorPtr = (TkCursor *) Tcl_GetHashValue(hashPtr);
  777. if (cursorPtr == NULL) {
  778.     panic("TkDebugCursor found empty hash table entry");
  779. }
  780. for ( ; (cursorPtr != NULL); cursorPtr = cursorPtr->nextPtr) {
  781.     objPtr = Tcl_NewObj();
  782.     Tcl_ListObjAppendElement(NULL, objPtr,
  783.     Tcl_NewIntObj(cursorPtr->resourceRefCount));
  784.     Tcl_ListObjAppendElement(NULL, objPtr,
  785.     Tcl_NewIntObj(cursorPtr->objRefCount)); 
  786.     Tcl_ListObjAppendElement(NULL, resultPtr, objPtr);
  787. }
  788.     }
  789.     return resultPtr;
  790. }