]> cvs.zerfleddert.de Git - micropolis/blob - src/tk/tkcolor.c
Fixes for compilation with gcc 15
[micropolis] / src / tk / tkcolor.c
1 /*
2 * tkColor.c --
3 *
4 * This file maintains a database of color values for the Tk
5 * toolkit, in order to avoid round-trips to the server to
6 * map color names to pixel values.
7 *
8 * Copyright 1990 Regents of the University of California
9 * Permission to use, copy, modify, and distribute this
10 * software and its documentation for any purpose and without
11 * fee is hereby granted, provided that the above copyright
12 * notice appear in all copies. The University of California
13 * makes no representations about the suitability of this
14 * software for any purpose. It is provided "as is" without
15 * express or implied warranty.
16 */
17
18 #ifndef lint
19 static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkColor.c,v 1.15 92/07/14 08:44:49 ouster Exp $ SPRITE (Berkeley)";
20 #endif /* not lint */
21
22 #include "tkconfig.h"
23 #include "tk.h"
24
25 /*
26 * A two-level data structure is used to manage the color database.
27 * The top level consists of one entry for each color name that is
28 * currently active, and the bottom level contains one entry for each
29 * pixel value that is still in use. The distinction between
30 * levels is necessary because the same pixel may have several
31 * different names. There are two hash tables, one used to index into
32 * each of the data structures. The name hash table is used when
33 * allocating colors, and the pixel hash table is used when freeing
34 * colors.
35 */
36
37 /*
38 * One of the following data structures is used to keep track of
39 * each color that this module has allocated from the X display
40 * server. These entries are indexed by two hash tables defined
41 * below: nameTable and valueTable.
42 */
43
44 #define COLOR_MAGIC 0xc6140277
45
46 typedef struct TkColor {
47 XColor color; /* Information about this color. */
48 int magic; /* Used for quick integrity check on this
49 * structure. Must always have the
50 * value COLOR_MAGIC. */
51 Screen *screen; /* Screen where this color is valid. Used
52 * to delete it. */
53 Colormap colormap; /* Colormap from which this entry was
54 * allocated. */
55 int refCount; /* Number of uses of this structure. */
56 Tcl_HashTable *tablePtr; /* Hash table that indexes this structure
57 * (needed when deleting structure). */
58 Tcl_HashEntry *hashPtr; /* Pointer to hash table entry for this
59 * structure. (for use in deleting entry). */
60 } TkColor;
61
62 typedef struct VisInfo {
63 Visual *visual;
64 Screen *screen;
65 Colormap colormap;
66 int depth;
67 Pixmap pixmap;
68 GC gc;
69 } VisInfo;
70
71 /*
72 * Hash table for name -> TkColor mapping, and key structure used to
73 * index into that table:
74 */
75
76 static Tcl_HashTable nameTable;
77 typedef struct {
78 Tk_Uid name; /* Name of desired color. */
79 Colormap colormap; /* Colormap from which color will be
80 * allocated. */
81 Display *display; /* Display for colormap. */
82 } NameKey;
83
84 /*
85 * Hash table for value -> TkColor mapping, and key structure used to
86 * index into that table:
87 */
88
89 static Tcl_HashTable valueTable;
90 typedef struct {
91 int red, green, blue; /* Values for desired color. */
92 Colormap colormap; /* Colormap from which color will be
93 * allocated. */
94 Display *display; /* Display for colormap. */
95 } ValueKey;
96
97 /*
98 * Global colormap creation flag
99 */
100 char *TK_CreateColormap = 0;
101
102 /*
103 * Hash table for screen -> VisInfo mapping, and key structure used to
104 * index into that table:
105 */
106
107 static Tcl_HashTable screenTable;
108
109 static int initialized = 0; /* 0 means static structures haven't been
110 * initialized yet. */
111
112 /*
113 * Forward declarations for procedures defined in this file:
114 */
115
116 static void ColorInit _ANSI_ARGS_((void));
117 \f
118 /*
119 *----------------------------------------------------------------------
120 *
121 * Tk_GetColor --
122 *
123 * Given a string name for a color, map the name to a corresponding
124 * XColor structure.
125 *
126 * Results:
127 * The return value is a pointer to an XColor structure that
128 * indicates the red, blue, and green intensities for the color
129 * given by "name", and also specifies a pixel value to use to
130 * draw in that color in window "tkwin". If an error occurs,
131 * then NULL is returned and an error message will be left in
132 * interp->result.
133 *
134 * Side effects:
135 * The color is added to an internal database with a reference count.
136 * For each call to this procedure, there should eventually be a call
137 * to Tk_FreeColor, so that the database is cleaned up when colors
138 * aren't in use anymore.
139 *
140 *----------------------------------------------------------------------
141 */
142
143 XColor *
144 Tk_GetColor (
145 Tcl_Interp *interp, /* Place to leave error message if
146 * color can't be found. */
147 Tk_Window tkwin, /* Window in which color will be used. */
148 Colormap colormap, /* Map from which to allocate color. None
149 * means use default. */
150 Tk_Uid name /* Name of color to allocated (in form
151 * suitable for passing to XParseColor). */
152 )
153 {
154 NameKey nameKey;
155 Tcl_HashEntry *nameHashPtr;
156 int new;
157 TkColor *tkColPtr;
158 XColor color;
159
160 if (!initialized) {
161 ColorInit();
162 }
163
164 /*
165 * First, check to see if there's already a mapping for this color
166 * name.
167 */
168
169 nameKey.name = name;
170 if (colormap == None) {
171 colormap = Tk_DefaultColormap(Tk_Screen(tkwin));
172 }
173 nameKey.colormap = colormap;
174 nameKey.display = Tk_Display(tkwin);
175 nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new);
176 if (!new) {
177 tkColPtr = (TkColor *) Tcl_GetHashValue(nameHashPtr);
178 tkColPtr->refCount++;
179 return &tkColPtr->color;
180 }
181
182 /*
183 * The name isn't currently known. Map from the name to a pixel
184 * value. Be tricky here, and call XAllocNamedColor instead of
185 * XParseColor for non-# names: this saves a server round-trip
186 * for those names.
187 */
188
189 if (*name != '#') {
190 XColor screen;
191
192 if (XAllocNamedColor(Tk_Display(tkwin), colormap, name,
193 &screen, &color) == 0) {
194 allocFailed:
195 Tcl_AppendResult(interp, "couldn't allocate a color for \"",
196 name, "\"", (char *) NULL);
197 Tcl_DeleteHashEntry(nameHashPtr);
198 return (XColor *) NULL;
199 }
200 } else {
201 if (XParseColor(Tk_Display(tkwin), colormap, name, &color) == 0) {
202 Tcl_AppendResult(interp, "invalid color name \"", name,
203 "\"", (char *) NULL);
204 Tcl_DeleteHashEntry(nameHashPtr);
205 return (XColor *) NULL;
206 }
207 if (XAllocColor(Tk_Display(tkwin), colormap, &color) == 0) {
208 goto allocFailed;
209 }
210 }
211
212 /*
213 * Now create a new TkColor structure and add it to nameTable.
214 */
215
216 tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
217 tkColPtr->color = color;
218 tkColPtr->magic = COLOR_MAGIC;
219 tkColPtr->screen = Tk_Screen(tkwin);
220 tkColPtr->colormap = colormap;
221 tkColPtr->refCount = 1;
222 tkColPtr->tablePtr = &nameTable;
223 tkColPtr->hashPtr = nameHashPtr;
224 Tcl_SetHashValue(nameHashPtr, tkColPtr);
225
226 return &tkColPtr->color;
227 }
228 \f
229 /*
230 *----------------------------------------------------------------------
231 *
232 * Tk_GetColorByValue --
233 *
234 * Given a desired set of red-green-blue intensities for a color,
235 * locate a pixel value to use to draw that color in a given
236 * window.
237 *
238 * Results:
239 * The return value is a pointer to an XColor structure that
240 * indicates the closest red, blue, and green intensities available
241 * to those specified in colorPtr, and also specifies a pixel
242 * value to use to draw in that color in window "tkwin". If an
243 * error occurs, then NULL is returned and an error message will
244 * be left in interp->result.
245 *
246 * Side effects:
247 * The color is added to an internal database with a reference count.
248 * For each call to this procedure, there should eventually be a call
249 * to Tk_FreeColor, so that the database is cleaned up when colors
250 * aren't in use anymore.
251 *
252 *----------------------------------------------------------------------
253 */
254
255 XColor *
256 Tk_GetColorByValue (
257 Tcl_Interp *interp, /* Place to leave error message if
258 * color can't be found. */
259 Tk_Window tkwin, /* Window in which color will be used. */
260 Colormap colormap, /* Map from which to allocate color. None
261 * means use default. */
262 XColor *colorPtr /* Red, green, and blue fields indicate
263 * desired color. */
264 )
265 {
266 ValueKey valueKey;
267 Tcl_HashEntry *valueHashPtr;
268 int new;
269 TkColor *tkColPtr;
270
271 if (!initialized) {
272 ColorInit();
273 }
274
275 /*
276 * First, check to see if there's already a mapping for this color
277 * name.
278 */
279
280 valueKey.red = colorPtr->red;
281 valueKey.green = colorPtr->green;
282 valueKey.blue = colorPtr->blue;
283 if (colormap == None) {
284 colormap = Tk_DefaultColormap(Tk_Screen(tkwin));
285 }
286 valueKey.colormap = colormap;
287 valueKey.display = Tk_Display(tkwin);
288 valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new);
289 if (!new) {
290 tkColPtr = (TkColor *) Tcl_GetHashValue(valueHashPtr);
291 tkColPtr->refCount++;
292 return &tkColPtr->color;
293 }
294
295 /*
296 * The name isn't currently known. Find a pixel value for this
297 * color and add a new structure to valueTable.
298 */
299
300 tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
301 tkColPtr->color.red = valueKey.red;
302 tkColPtr->color.green = valueKey.green;
303 tkColPtr->color.blue = valueKey.blue;
304 if (XAllocColor(Tk_Display(tkwin), colormap, &tkColPtr->color) == 0) {
305 sprintf(interp->result, "couldn't allocate color");
306 Tcl_DeleteHashEntry(valueHashPtr);
307 ckfree((char *) tkColPtr);
308 return (XColor *) NULL;
309 }
310 tkColPtr->magic = COLOR_MAGIC;
311 tkColPtr->screen = Tk_Screen(tkwin);
312 tkColPtr->colormap = colormap;
313 tkColPtr->refCount = 1;
314 tkColPtr->tablePtr = &valueTable;
315 tkColPtr->hashPtr = valueHashPtr;
316 Tcl_SetHashValue(valueHashPtr, tkColPtr);
317
318 return &tkColPtr->color;
319 }
320 \f
321 /*
322 *--------------------------------------------------------------
323 *
324 * Tk_NameOfColor --
325 *
326 * Given a color, return a textual string identifying
327 * the color.
328 *
329 * Results:
330 * If colorPtr was created by Tk_GetColor, then the return
331 * value is the "string" that was used to create it.
332 * Otherwise the return value is a string that could have
333 * been passed to Tk_GetColor to allocate that color. The
334 * storage for the returned string is only guaranteed to
335 * persist up until the next call to this procedure.
336 *
337 * Side effects:
338 * None.
339 *
340 *--------------------------------------------------------------
341 */
342
343 char *
344 Tk_NameOfColor (
345 XColor *colorPtr /* Color whose name is desired. */
346 )
347 {
348 register TkColor *tkColPtr = (TkColor *) colorPtr;
349 static char string[20];
350
351 if ((tkColPtr->magic == COLOR_MAGIC)
352 && (tkColPtr->tablePtr == &nameTable)) {
353 return ((NameKey *) tkColPtr->hashPtr->key.words)->name;
354 }
355 sprintf(string, "#%4x%4x%4x", colorPtr->red, colorPtr->green,
356 colorPtr->blue);
357 return string;
358 }
359 \f
360 /*
361 *----------------------------------------------------------------------
362 *
363 * Tk_FreeColor --
364 *
365 * This procedure is called to release a color allocated by
366 * Tk_GetColor.
367 *
368 * Results:
369 * None.
370 *
371 * Side effects:
372 * The reference count associated with colorPtr is deleted, and
373 * the color is released to X if there are no remaining uses
374 * for it.
375 *
376 *----------------------------------------------------------------------
377 */
378
379 void
380 Tk_FreeColor (
381 XColor *colorPtr /* Color to be released. Must have been
382 * allocated by Tk_GetColor or
383 * Tk_GetColorByValue. */
384 )
385 {
386 register TkColor *tkColPtr = (TkColor *) colorPtr;
387 Visual *visual;
388 Screen *screen = tkColPtr->screen;
389
390 /*
391 * Do a quick sanity check to make sure this color was really
392 * allocated by Tk_GetColor.
393 */
394
395 if (tkColPtr->magic != COLOR_MAGIC) {
396 panic("Tk_FreeColor called with bogus color");
397 }
398
399 tkColPtr->refCount--;
400 if (tkColPtr->refCount == 0) {
401
402 /*
403 * Careful! Don't free black or white, since this will
404 * make some servers very unhappy.
405 */
406
407 visual = Tk_DefaultVisual(screen);
408 if ((visual->class != StaticGray) && (visual->class != StaticColor)
409 && (tkColPtr->color.pixel != BlackPixelOfScreen(screen))
410 && (tkColPtr->color.pixel != WhitePixelOfScreen(screen))) {
411 XFreeColors(DisplayOfScreen(screen), tkColPtr->colormap,
412 &tkColPtr->color.pixel, 1, 0L);
413 }
414 Tcl_DeleteHashEntry(tkColPtr->hashPtr);
415 tkColPtr->magic = 0;
416 ckfree((char *) tkColPtr);
417 }
418 }
419 \f
420 /*
421 *----------------------------------------------------------------------
422 *
423 * ColorInit --
424 *
425 * Initialize the structure used for color management.
426 *
427 * Results:
428 * None.
429 *
430 * Side effects:
431 * Read the code.
432 *
433 *----------------------------------------------------------------------
434 */
435
436 static void
437 ColorInit (void)
438 {
439 initialized = 1;
440 Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int));
441 Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int));
442 Tcl_InitHashTable(&screenTable, TCL_ONE_WORD_KEYS);
443 }
444
445
446 int
447 Tk_IndexOfScreen(Screen *screen)
448 {
449 Display *dpy = DisplayOfScreen(screen);
450 int i, nscreens = ScreenCount(dpy);
451
452 for (i = 0; i < nscreens; i++) {
453 if (screen == ScreenOfDisplay(dpy, i))
454 return (i);
455 }
456 return (DefaultScreen(dpy));
457 }
458
459
460 VisInfo *
461 Tk_VisInfo(Screen *screen)
462 {
463 Tcl_HashEntry *hashPtr;
464 VisInfo *info;
465 XVisualInfo vTemplate;
466 XVisualInfo *visualList;
467 Visual *visual;
468 XGCValues values;
469 int visualsMatched, scrnum, new;
470
471 if (!initialized) {
472 ColorInit();
473 }
474
475 hashPtr = Tcl_CreateHashEntry(&screenTable, (char *) screen, &new);
476 if (!new) {
477 info = (VisInfo *) Tcl_GetHashValue(hashPtr);
478 } else {
479 info = (VisInfo *) ckalloc(sizeof(VisInfo));
480 info->screen = screen;
481
482 /* Workaround to support non-default visuals */
483 #if 0
484 info->visual = XDefaultVisualOfScreen(screen);
485 info->depth = XDefaultDepthOfScreen(screen);
486 info->colormap = XDefaultColormapOfScreen(screen);
487 info->gc = DefaultGCOfScreen(screen);
488 #else
489 scrnum = Tk_IndexOfScreen(screen);
490 vTemplate.screen = scrnum;
491 vTemplate.class = TrueColor;
492 visualList =
493 XGetVisualInfo(DisplayOfScreen(screen),
494 VisualScreenMask |
495 VisualClassMask,
496 &vTemplate, &visualsMatched);
497 info->visual = NULL;
498
499 if (visualList != NULL) {
500 int i;
501 for (i = 0; i < visualsMatched; i++) {
502 if (visualList[i].depth > 24)
503 continue; /* Most likely broken */
504
505 info->visual = visualList[i].visual;
506 info->depth = visualList[i].depth;
507
508 break;
509 }
510 }
511
512 if (info->visual == NULL) {
513 info->visual = XDefaultVisualOfScreen(screen);
514 info->depth = XDefaultDepthOfScreen(screen);
515 info->colormap = XDefaultColormapOfScreen(screen);
516 info->gc = DefaultGCOfScreen(screen);
517
518 if (info->depth == 8) {
519 vTemplate.screen = scrnum;
520 vTemplate.class = PseudoColor;
521 vTemplate.depth = 8;
522 visualList = XGetVisualInfo(DisplayOfScreen(screen),
523 VisualScreenMask |
524 VisualDepthMask |
525 VisualClassMask,
526 &vTemplate, &visualsMatched);
527
528 if (visualsMatched > 0) {
529 info->visual = visualList[0].visual;
530 info->depth = visualList[0].depth;
531
532 }
533 }
534 }
535
536 info->pixmap = XCreatePixmap(screen->display,
537 RootWindowOfScreen(screen),
538 1, 1, info->depth);
539
540 if ((TK_CreateColormap == 0) &&
541 (info->visual == DefaultVisualOfScreen(screen))) {
542 info->colormap = DefaultColormapOfScreen(screen);
543 info->gc = DefaultGCOfScreen(screen);
544 } else {
545 info->colormap =
546 XCreateColormap(screen->display,
547 RootWindowOfScreen(screen),
548 info->visual, AllocNone);
549 info->gc =
550 XCreateGC(screen->display,
551 info->pixmap, 0, &values);
552 }
553
554 XFree((char *)visualList);
555 #endif
556
557 Tcl_SetHashValue(hashPtr, info);
558 }
559
560 return (info);
561 }
562
563
564 int
565 Tk_DefaultDepth(Screen *screen)
566 {
567 return (Tk_VisInfo(screen)->depth);
568 }
569
570
571 Visual *
572 Tk_DefaultVisual(Screen *screen)
573 {
574 return (Tk_VisInfo(screen)->visual);
575 }
576
577
578 Colormap
579 Tk_DefaultColormap(Screen *screen)
580 {
581 return (Tk_VisInfo(screen)->colormap);
582 }
583
584
585 Window
586 Tk_DefaultRootWindow(Display *dpy)
587 {
588 return (DefaultRootWindow(dpy));
589 }
590
591
592 GC
593 Tk_DefaultGC(Screen *screen)
594 {
595 return (Tk_VisInfo(screen)->gc);
596 }
597
598
599 Pixmap
600 Tk_DefaultPixmap(Screen *screen)
601 {
602 return (Tk_VisInfo(screen)->pixmap);
603 }
604
605
Impressum, Datenschutz