OSDN Git Service

Initial revision
[pf3gnuchains/pf3gnuchains3x.git] / tk / generic / tkCursor.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-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  * RCS: @(#) $Id$
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 \f
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 \f
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 \f
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 \f
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 \f
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 }