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