]> cvs.zerfleddert.de Git - micropolis/blame_incremental - src/tk/tkcolor.c
Optimize redrawing so that the mouse is more responsive, from Marc Espie.
[micropolis] / src / tk / tkcolor.c
... / ...
CommitLineData
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
19static 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
46typedef 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
62typedef 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
76static Tcl_HashTable nameTable;
77typedef 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
89static Tcl_HashTable valueTable;
90typedef 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 */
100char *TK_CreateColormap = 0;
101
102/*
103 * Hash table for screen -> VisInfo mapping, and key structure used to
104 * index into that table:
105 */
106
107static Tcl_HashTable screenTable;
108
109static 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
116static 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
143XColor *
144Tk_GetColor(interp, tkwin, colormap, name)
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 NameKey nameKey;
154 Tcl_HashEntry *nameHashPtr;
155 int new;
156 TkColor *tkColPtr;
157 XColor color;
158
159 if (!initialized) {
160 ColorInit();
161 }
162
163 /*
164 * First, check to see if there's already a mapping for this color
165 * name.
166 */
167
168 nameKey.name = name;
169 if (colormap == None) {
170 colormap = Tk_DefaultColormap(Tk_Screen(tkwin));
171 }
172 nameKey.colormap = colormap;
173 nameKey.display = Tk_Display(tkwin);
174 nameHashPtr = Tcl_CreateHashEntry(&nameTable, (char *) &nameKey, &new);
175 if (!new) {
176 tkColPtr = (TkColor *) Tcl_GetHashValue(nameHashPtr);
177 tkColPtr->refCount++;
178 return &tkColPtr->color;
179 }
180
181 /*
182 * The name isn't currently known. Map from the name to a pixel
183 * value. Be tricky here, and call XAllocNamedColor instead of
184 * XParseColor for non-# names: this saves a server round-trip
185 * for those names.
186 */
187
188 if (*name != '#') {
189 XColor screen;
190
191 if (XAllocNamedColor(Tk_Display(tkwin), colormap, name,
192 &screen, &color) == 0) {
193 allocFailed:
194 Tcl_AppendResult(interp, "couldn't allocate a color for \"",
195 name, "\"", (char *) NULL);
196 Tcl_DeleteHashEntry(nameHashPtr);
197 return (XColor *) NULL;
198 }
199 } else {
200 if (XParseColor(Tk_Display(tkwin), colormap, name, &color) == 0) {
201 Tcl_AppendResult(interp, "invalid color name \"", name,
202 "\"", (char *) NULL);
203 Tcl_DeleteHashEntry(nameHashPtr);
204 return (XColor *) NULL;
205 }
206 if (XAllocColor(Tk_Display(tkwin), colormap, &color) == 0) {
207 goto allocFailed;
208 }
209 }
210
211 /*
212 * Now create a new TkColor structure and add it to nameTable.
213 */
214
215 tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
216 tkColPtr->color = color;
217 tkColPtr->magic = COLOR_MAGIC;
218 tkColPtr->screen = Tk_Screen(tkwin);
219 tkColPtr->colormap = colormap;
220 tkColPtr->refCount = 1;
221 tkColPtr->tablePtr = &nameTable;
222 tkColPtr->hashPtr = nameHashPtr;
223 Tcl_SetHashValue(nameHashPtr, tkColPtr);
224
225 return &tkColPtr->color;
226}
227\f
228/*
229 *----------------------------------------------------------------------
230 *
231 * Tk_GetColorByValue --
232 *
233 * Given a desired set of red-green-blue intensities for a color,
234 * locate a pixel value to use to draw that color in a given
235 * window.
236 *
237 * Results:
238 * The return value is a pointer to an XColor structure that
239 * indicates the closest red, blue, and green intensities available
240 * to those specified in colorPtr, and also specifies a pixel
241 * value to use to draw in that color in window "tkwin". If an
242 * error occurs, then NULL is returned and an error message will
243 * be left in interp->result.
244 *
245 * Side effects:
246 * The color is added to an internal database with a reference count.
247 * For each call to this procedure, there should eventually be a call
248 * to Tk_FreeColor, so that the database is cleaned up when colors
249 * aren't in use anymore.
250 *
251 *----------------------------------------------------------------------
252 */
253
254XColor *
255Tk_GetColorByValue(interp, tkwin, colormap, colorPtr)
256 Tcl_Interp *interp; /* Place to leave error message if
257 * color can't be found. */
258 Tk_Window tkwin; /* Window in which color will be used. */
259 Colormap colormap; /* Map from which to allocate color. None
260 * means use default. */
261 XColor *colorPtr; /* Red, green, and blue fields indicate
262 * desired color. */
263{
264 ValueKey valueKey;
265 Tcl_HashEntry *valueHashPtr;
266 int new;
267 TkColor *tkColPtr;
268
269 if (!initialized) {
270 ColorInit();
271 }
272
273 /*
274 * First, check to see if there's already a mapping for this color
275 * name.
276 */
277
278 valueKey.red = colorPtr->red;
279 valueKey.green = colorPtr->green;
280 valueKey.blue = colorPtr->blue;
281 if (colormap == None) {
282 colormap = Tk_DefaultColormap(Tk_Screen(tkwin));
283 }
284 valueKey.colormap = colormap;
285 valueKey.display = Tk_Display(tkwin);
286 valueHashPtr = Tcl_CreateHashEntry(&valueTable, (char *) &valueKey, &new);
287 if (!new) {
288 tkColPtr = (TkColor *) Tcl_GetHashValue(valueHashPtr);
289 tkColPtr->refCount++;
290 return &tkColPtr->color;
291 }
292
293 /*
294 * The name isn't currently known. Find a pixel value for this
295 * color and add a new structure to valueTable.
296 */
297
298 tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
299 tkColPtr->color.red = valueKey.red;
300 tkColPtr->color.green = valueKey.green;
301 tkColPtr->color.blue = valueKey.blue;
302 if (XAllocColor(Tk_Display(tkwin), colormap, &tkColPtr->color) == 0) {
303 sprintf(interp->result, "couldn't allocate color");
304 Tcl_DeleteHashEntry(valueHashPtr);
305 ckfree((char *) tkColPtr);
306 return (XColor *) NULL;
307 }
308 tkColPtr->magic = COLOR_MAGIC;
309 tkColPtr->screen = Tk_Screen(tkwin);
310 tkColPtr->colormap = colormap;
311 tkColPtr->refCount = 1;
312 tkColPtr->tablePtr = &valueTable;
313 tkColPtr->hashPtr = valueHashPtr;
314 Tcl_SetHashValue(valueHashPtr, tkColPtr);
315
316 return &tkColPtr->color;
317}
318\f
319/*
320 *--------------------------------------------------------------
321 *
322 * Tk_NameOfColor --
323 *
324 * Given a color, return a textual string identifying
325 * the color.
326 *
327 * Results:
328 * If colorPtr was created by Tk_GetColor, then the return
329 * value is the "string" that was used to create it.
330 * Otherwise the return value is a string that could have
331 * been passed to Tk_GetColor to allocate that color. The
332 * storage for the returned string is only guaranteed to
333 * persist up until the next call to this procedure.
334 *
335 * Side effects:
336 * None.
337 *
338 *--------------------------------------------------------------
339 */
340
341char *
342Tk_NameOfColor(colorPtr)
343 XColor *colorPtr; /* Color whose name is desired. */
344{
345 register TkColor *tkColPtr = (TkColor *) colorPtr;
346 static char string[20];
347
348 if ((tkColPtr->magic == COLOR_MAGIC)
349 && (tkColPtr->tablePtr == &nameTable)) {
350 return ((NameKey *) tkColPtr->hashPtr->key.words)->name;
351 }
352 sprintf(string, "#%4x%4x%4x", colorPtr->red, colorPtr->green,
353 colorPtr->blue);
354 return string;
355}
356\f
357/*
358 *----------------------------------------------------------------------
359 *
360 * Tk_FreeColor --
361 *
362 * This procedure is called to release a color allocated by
363 * Tk_GetColor.
364 *
365 * Results:
366 * None.
367 *
368 * Side effects:
369 * The reference count associated with colorPtr is deleted, and
370 * the color is released to X if there are no remaining uses
371 * for it.
372 *
373 *----------------------------------------------------------------------
374 */
375
376void
377Tk_FreeColor(colorPtr)
378 XColor *colorPtr; /* Color to be released. Must have been
379 * allocated by Tk_GetColor or
380 * Tk_GetColorByValue. */
381{
382 register TkColor *tkColPtr = (TkColor *) colorPtr;
383 Visual *visual;
384 Screen *screen = tkColPtr->screen;
385
386 /*
387 * Do a quick sanity check to make sure this color was really
388 * allocated by Tk_GetColor.
389 */
390
391 if (tkColPtr->magic != COLOR_MAGIC) {
392 panic("Tk_FreeColor called with bogus color");
393 }
394
395 tkColPtr->refCount--;
396 if (tkColPtr->refCount == 0) {
397
398 /*
399 * Careful! Don't free black or white, since this will
400 * make some servers very unhappy.
401 */
402
403 visual = Tk_DefaultVisual(screen);
404 if ((visual->class != StaticGray) && (visual->class != StaticColor)
405 && (tkColPtr->color.pixel != BlackPixelOfScreen(screen))
406 && (tkColPtr->color.pixel != WhitePixelOfScreen(screen))) {
407 XFreeColors(DisplayOfScreen(screen), tkColPtr->colormap,
408 &tkColPtr->color.pixel, 1, 0L);
409 }
410 Tcl_DeleteHashEntry(tkColPtr->hashPtr);
411 tkColPtr->magic = 0;
412 ckfree((char *) tkColPtr);
413 }
414}
415\f
416/*
417 *----------------------------------------------------------------------
418 *
419 * ColorInit --
420 *
421 * Initialize the structure used for color management.
422 *
423 * Results:
424 * None.
425 *
426 * Side effects:
427 * Read the code.
428 *
429 *----------------------------------------------------------------------
430 */
431
432static void
433ColorInit()
434{
435 initialized = 1;
436 Tcl_InitHashTable(&nameTable, sizeof(NameKey)/sizeof(int));
437 Tcl_InitHashTable(&valueTable, sizeof(ValueKey)/sizeof(int));
438 Tcl_InitHashTable(&screenTable, TCL_ONE_WORD_KEYS);
439}
440
441
442int
443Tk_IndexOfScreen(Screen *screen)
444{
445 Display *dpy = DisplayOfScreen(screen);
446 int i, nscreens = ScreenCount(dpy);
447
448 for (i = 0; i < nscreens; i++) {
449 if (screen == ScreenOfDisplay(dpy, i))
450 return (i);
451 }
452 return (DefaultScreen(dpy));
453}
454
455
456VisInfo *
457Tk_VisInfo(Screen *screen)
458{
459 Tcl_HashEntry *hashPtr;
460 VisInfo *info;
461 XVisualInfo vTemplate;
462 XVisualInfo *visualList;
463 Visual *visual;
464 XGCValues values;
465 int visualsMatched, scrnum, new;
466
467 if (!initialized) {
468 ColorInit();
469 }
470
471 hashPtr = Tcl_CreateHashEntry(&screenTable, (char *) screen, &new);
472 if (!new) {
473 info = (VisInfo *) Tcl_GetHashValue(hashPtr);
474 } else {
475 info = (VisInfo *) ckalloc(sizeof(VisInfo));
476 info->screen = screen;
477
478/* Workaround to support non-default visuals */
479#if 0
480 info->visual = XDefaultVisualOfScreen(screen);
481 info->depth = XDefaultDepthOfScreen(screen);
482 info->colormap = XDefaultColormapOfScreen(screen);
483 info->gc = DefaultGCOfScreen(screen);
484#else
485 scrnum = Tk_IndexOfScreen(screen);
486 vTemplate.screen = scrnum;
487 vTemplate.class = TrueColor;
488 visualList =
489 XGetVisualInfo(DisplayOfScreen(screen),
490 VisualScreenMask |
491 VisualClassMask,
492 &vTemplate, &visualsMatched);
493 info->visual = NULL;
494
495 if (visualList != NULL) {
496 int i;
497 for (i = 0; i < visualsMatched; i++) {
498 if (visualList[i].depth > 24)
499 continue; /* Most likely broken */
500
501 info->visual = visualList[i].visual;
502 info->depth = visualList[i].depth;
503
504 break;
505 }
506 }
507
508 if (info->visual == NULL) {
509 info->visual = XDefaultVisualOfScreen(screen);
510 info->depth = XDefaultDepthOfScreen(screen);
511 info->colormap = XDefaultColormapOfScreen(screen);
512 info->gc = DefaultGCOfScreen(screen);
513
514 if (info->depth == 8) {
515 vTemplate.screen = scrnum;
516 vTemplate.class = PseudoColor;
517 vTemplate.depth = 8;
518 visualList = XGetVisualInfo(DisplayOfScreen(screen),
519 VisualScreenMask |
520 VisualDepthMask |
521 VisualClassMask,
522 &vTemplate, &visualsMatched);
523
524 if (visualsMatched > 0) {
525 info->visual = visualList[0].visual;
526 info->depth = visualList[0].depth;
527
528 }
529 }
530 }
531
532 info->pixmap = XCreatePixmap(screen->display,
533 RootWindowOfScreen(screen),
534 1, 1, info->depth);
535
536 if ((TK_CreateColormap == 0) &&
537 (info->visual == DefaultVisualOfScreen(screen))) {
538 info->colormap = DefaultColormapOfScreen(screen);
539 info->gc = DefaultGCOfScreen(screen);
540 } else {
541 info->colormap =
542 XCreateColormap(screen->display,
543 RootWindowOfScreen(screen),
544 info->visual, AllocNone);
545 info->gc =
546 XCreateGC(screen->display,
547 info->pixmap, 0, &values);
548 }
549
550 XFree((char *)visualList);
551#endif
552
553 Tcl_SetHashValue(hashPtr, info);
554 }
555
556 return (info);
557}
558
559
560int
561Tk_DefaultDepth(Screen *screen)
562{
563 return (Tk_VisInfo(screen)->depth);
564}
565
566
567Visual *
568Tk_DefaultVisual(Screen *screen)
569{
570 return (Tk_VisInfo(screen)->visual);
571}
572
573
574Colormap
575Tk_DefaultColormap(Screen *screen)
576{
577 return (Tk_VisInfo(screen)->colormap);
578}
579
580
581Window
582Tk_DefaultRootWindow(Display *dpy)
583{
584 return (DefaultRootWindow(dpy));
585}
586
587
588GC
589Tk_DefaultGC(Screen *screen)
590{
591 return (Tk_VisInfo(screen)->gc);
592}
593
594
595Pixmap
596Tk_DefaultPixmap(Screen *screen)
597{
598 return (Tk_VisInfo(screen)->pixmap);
599}
600
601
Impressum, Datenschutz