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.
8 * Copyright (c) 1990-1994 The Regents of the University of California.
9 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
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.
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
33 static Tcl_HashTable nameTable;
35 Tk_Uid name; /* Textual name for desired cursor. */
36 Display *display; /* Display for which cursor will be used. */
40 * Hash table to map from a collection of in-core data about a
41 * cursor (bitmap contents, etc.) to a TkCursor structure:
44 static Tcl_HashTable dataTable;
46 char *source; /* Cursor bits. */
47 char *mask; /* Mask bits. */
48 int width, height; /* Dimensions of cursor (and data
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. */
56 * Hash table that maps from <display + cursor id> to the TkCursor structure
57 * for the cursor. This table is used by Tk_FreeCursor.
60 static Tcl_HashTable idTable;
62 Display *display; /* Display for which cursor was allocated. */
63 Tk_Cursor cursor; /* Cursor identifier. */
66 static int initialized = 0; /* 0 means static structures haven't been
70 * Forward declarations for procedures defined in this file:
73 static void CursorInit _ANSI_ARGS_((void));
76 *----------------------------------------------------------------------
80 * Given a string describing a cursor, locate (or create if necessary)
81 * a cursor that fits the description.
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
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.
97 *----------------------------------------------------------------------
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. */
109 Tcl_HashEntry *nameHashPtr, *idHashPtr;
110 register TkCursor *cursorPtr;
117 nameKey.name = string;
118 nameKey.display = Tk_Display(tkwin);
119 nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new);
121 cursorPtr = (TkCursor *) Tcl_GetHashValue(nameHashPtr);
122 cursorPtr->refCount++;
123 return cursorPtr->cursor;
126 cursorPtr = TkGetCursorByName(interp, tkwin, string);
128 if (cursorPtr == NULL) {
129 Tcl_DeleteHashEntry(nameHashPtr);
134 * Add information about this cursor to our database.
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);
144 panic("cursor already registered in Tk_GetCursor");
146 Tcl_SetHashValue(nameHashPtr, cursorPtr);
147 Tcl_SetHashValue(idHashPtr, cursorPtr);
149 return cursorPtr->cursor;
153 *----------------------------------------------------------------------
155 * Tk_GetCursorFromData --
157 * Given a description of the bits and colors for a cursor,
158 * make a cursor that has the given properties.
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
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.
174 *----------------------------------------------------------------------
178 Tk_GetCursorFromData(interp, tkwin, source, mask, width, height,
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. */
191 Tcl_HashEntry *dataHashPtr, *idHashPtr;
192 register TkCursor *cursorPtr;
194 XColor fgColor, bgColor;
200 dataKey.source = source;
202 dataKey.width = width;
203 dataKey.height = height;
208 dataKey.display = Tk_Display(tkwin);
209 dataHashPtr = Tcl_CreateHashEntry(&dataTable, (char *) &dataKey, &new);
211 cursorPtr = (TkCursor *) Tcl_GetHashValue(dataHashPtr);
212 cursorPtr->refCount++;
213 return cursorPtr->cursor;
217 * No suitable cursor exists yet. Make one using the data
218 * available and add it to the database.
221 if (XParseColor(dataKey.display, Tk_Colormap(tkwin), fg, &fgColor) == 0) {
222 Tcl_AppendResult(interp, "invalid color name \"", fg, "\"",
226 if (XParseColor(dataKey.display, Tk_Colormap(tkwin), bg, &bgColor) == 0) {
227 Tcl_AppendResult(interp, "invalid color name \"", bg, "\"",
232 cursorPtr = TkCreateCursorFromData(tkwin, source, mask, width, height,
233 xHot, yHot, fgColor, bgColor);
235 if (cursorPtr == NULL) {
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);
246 panic("cursor already registered in Tk_GetCursorFromData");
248 Tcl_SetHashValue(dataHashPtr, cursorPtr);
249 Tcl_SetHashValue(idHashPtr, cursorPtr);
250 return cursorPtr->cursor;
253 Tcl_DeleteHashEntry(dataHashPtr);
258 *--------------------------------------------------------------
262 * Given a cursor, return a textual string identifying it.
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.
275 *--------------------------------------------------------------
279 Tk_NameOfCursor(display, cursor)
280 Display *display; /* Display for which cursor was allocated. */
281 Tk_Cursor cursor; /* Identifier for cursor whose name is
285 Tcl_HashEntry *idHashPtr;
287 static char string[20];
291 sprintf(string, "cursor id 0x%x", (unsigned int) cursor);
294 idKey.display = display;
295 idKey.cursor = cursor;
296 idHashPtr = Tcl_FindHashEntry(&idTable, (char *) &idKey);
297 if (idHashPtr == NULL) {
300 cursorPtr = (TkCursor *) Tcl_GetHashValue(idHashPtr);
301 if (cursorPtr->otherTable != &nameTable) {
304 return ((NameKey *) cursorPtr->hashPtr->key.words)->name;
308 *----------------------------------------------------------------------
312 * This procedure is called to release a cursor allocated by
313 * Tk_GetCursor or TkGetCursorFromData.
319 * The reference count associated with cursor is decremented, and
320 * it is officially deallocated if no-one is using it anymore.
322 *----------------------------------------------------------------------
326 Tk_FreeCursor(display, cursor)
327 Display *display; /* Display for which cursor was allocated. */
328 Tk_Cursor cursor; /* Identifier for cursor to be released. */
331 Tcl_HashEntry *idHashPtr;
332 register TkCursor *cursorPtr;
335 panic("Tk_FreeCursor called before Tk_GetCursor");
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");
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);
354 *----------------------------------------------------------------------
358 * Initialize the structures used for cursor management.
366 *----------------------------------------------------------------------
373 Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int));
374 Tcl_InitHashTable(&dataTable, sizeof(DataKey)/sizeof(int));
377 * The call below is tricky: can't use sizeof(IdKey) because it
378 * gets padded with extra unpredictable bytes on some 64-bit
382 Tcl_InitHashTable(&idTable, (sizeof(Display *) + sizeof(Tk_Cursor))