OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [unix/] [tkUnixColor.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkUnixColor.c --
3
 *
4
 *      This file contains the platform specific color routines
5
 *      needed for X support.
6
 *
7
 * Copyright (c) 1996 by Sun Microsystems, Inc.
8
 *
9
 * See the file "license.terms" for information on usage and redistribution
10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11
 *
12
 * RCS: @(#) $Id: tkUnixColor.c,v 1.1.1.1 2002-01-16 10:26:01 markom Exp $
13
 */
14
 
15
#include <tkColor.h>
16
 
17
/*
18
 * If a colormap fills up, attempts to allocate new colors from that
19
 * colormap will fail.  When that happens, we'll just choose the
20
 * closest color from those that are available in the colormap.
21
 * One of the following structures will be created for each "stressed"
22
 * colormap to keep track of the colors that are available in the
23
 * colormap (otherwise we would have to re-query from the server on
24
 * each allocation, which would be very slow).  These entries are
25
 * flushed after a few seconds, since other clients may release or
26
 * reallocate colors over time.
27
 */
28
 
29
struct TkStressedCmap {
30
    Colormap colormap;                  /* X's token for the colormap. */
31
    int numColors;                      /* Number of entries currently active
32
                                         * at *colorPtr. */
33
    XColor *colorPtr;                   /* Pointer to malloc'ed array of all
34
                                         * colors that seem to be available in
35
                                         * the colormap.  Some may not actually
36
                                         * be available, e.g. because they are
37
                                         * read-write for another client;  when
38
                                         * we find this out, we remove them
39
                                         * from the array. */
40
    struct TkStressedCmap *nextPtr;     /* Next in list of all stressed
41
                                         * colormaps for the display. */
42
};
43
 
44
/*
45
 * Forward declarations for procedures defined in this file:
46
 */
47
 
48
static void             DeleteStressedCmap _ANSI_ARGS_((Display *display,
49
                            Colormap colormap));
50
static void             FindClosestColor _ANSI_ARGS_((Tk_Window tkwin,
51
                            XColor *desiredColorPtr, XColor *actualColorPtr));
52
 
53
/*
54
 *----------------------------------------------------------------------
55
 *
56
 * TkpFreeColor --
57
 *
58
 *      Release the specified color back to the system.
59
 *
60
 * Results:
61
 *      None
62
 *
63
 * Side effects:
64
 *      Invalidates the colormap cache for the colormap associated with
65
 *      the given color.
66
 *
67
 *----------------------------------------------------------------------
68
 */
69
 
70
void
71
TkpFreeColor(tkColPtr)
72
    TkColor *tkColPtr;          /* Color to be released.  Must have been
73
                                 * allocated by TkpGetColor or
74
                                 * TkpGetColorByValue. */
75
{
76
    Visual *visual;
77
    Screen *screen = tkColPtr->screen;
78
 
79
    /*
80
     * Careful!  Don't free black or white, since this will
81
     * make some servers very unhappy.  Also, there is a bug in
82
     * some servers (such Sun's X11/NeWS server) where reference
83
     * counting is performed incorrectly, so that if a color is
84
     * allocated twice in different places and then freed twice,
85
     * the second free generates an error (this bug existed as of
86
     * 10/1/92).  To get around this problem, ignore errors that
87
     * occur during the free operation.
88
     */
89
 
90
    visual = tkColPtr->visual;
91
    if ((visual->class != StaticGray) && (visual->class != StaticColor)
92
            && (tkColPtr->color.pixel != BlackPixelOfScreen(screen))
93
            && (tkColPtr->color.pixel != WhitePixelOfScreen(screen))) {
94
        Tk_ErrorHandler handler;
95
 
96
        handler = Tk_CreateErrorHandler(DisplayOfScreen(screen),
97
                -1, -1, -1, (Tk_ErrorProc *) NULL, (ClientData) NULL);
98
        XFreeColors(DisplayOfScreen(screen), tkColPtr->colormap,
99
                &tkColPtr->color.pixel, 1, 0L);
100
        Tk_DeleteErrorHandler(handler);
101
    }
102
    DeleteStressedCmap(DisplayOfScreen(screen), tkColPtr->colormap);
103
}
104
 
105
/*
106
 *----------------------------------------------------------------------
107
 *
108
 * TkpGetColor --
109
 *
110
 *      Allocate a new TkColor for the color with the given name.
111
 *
112
 * Results:
113
 *      Returns a newly allocated TkColor, or NULL on failure.
114
 *
115
 * Side effects:
116
 *      May invalidate the colormap cache associated with tkwin upon
117
 *      allocating a new colormap entry.  Allocates a new TkColor
118
 *      structure.
119
 *
120
 *----------------------------------------------------------------------
121
 */
122
 
123
TkColor *
124
TkpGetColor(tkwin, name)
125
    Tk_Window tkwin;            /* Window in which color will be used. */
126
    Tk_Uid name;                /* Name of color to allocated (in form
127
                                 * suitable for passing to XParseColor). */
128
{
129
    Display *display = Tk_Display(tkwin);
130
    Colormap colormap = Tk_Colormap(tkwin);
131
    XColor color;
132
    TkColor *tkColPtr;
133
 
134
    /*
135
     * Map from the name to a pixel value.  Call XAllocNamedColor rather than
136
     * XParseColor for non-# names: this saves a server round-trip for those
137
     * names.
138
     */
139
 
140
    if (*name != '#') {
141
        XColor screen;
142
 
143
        if (XAllocNamedColor(display, colormap, name, &screen,
144
                &color) != 0) {
145
            DeleteStressedCmap(display, colormap);
146
        } else {
147
            /*
148
             * Couldn't allocate the color.  Try translating the name to
149
             * a color value, to see whether the problem is a bad color
150
             * name or a full colormap.  If the colormap is full, then
151
             * pick an approximation to the desired color.
152
             */
153
 
154
            if (XLookupColor(display, colormap, name, &color,
155
                    &screen) == 0) {
156
                return (TkColor *) NULL;
157
            }
158
            FindClosestColor(tkwin, &screen, &color);
159
        }
160
    } else {
161
        if (XParseColor(display, colormap, name, &color) == 0) {
162
            return (TkColor *) NULL;
163
        }
164
        if (XAllocColor(display, colormap, &color) != 0) {
165
            DeleteStressedCmap(display, colormap);
166
        } else {
167
            FindClosestColor(tkwin, &color, &color);
168
        }
169
    }
170
 
171
    tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
172
    tkColPtr->color = color;
173
 
174
    return tkColPtr;
175
}
176
 
177
/*
178
 *----------------------------------------------------------------------
179
 *
180
 * TkpGetColorByValue --
181
 *
182
 *      Given a desired set of red-green-blue intensities for a color,
183
 *      locate a pixel value to use to draw that color in a given
184
 *      window.
185
 *
186
 * Results:
187
 *      The return value is a pointer to an TkColor structure that
188
 *      indicates the closest red, blue, and green intensities available
189
 *      to those specified in colorPtr, and also specifies a pixel
190
 *      value to use to draw in that color.
191
 *
192
 * Side effects:
193
 *      May invalidate the colormap cache for the specified window.
194
 *      Allocates a new TkColor structure.
195
 *
196
 *----------------------------------------------------------------------
197
 */
198
 
199
TkColor *
200
TkpGetColorByValue(tkwin, colorPtr)
201
    Tk_Window tkwin;            /* Window in which color will be used. */
202
    XColor *colorPtr;           /* Red, green, and blue fields indicate
203
                                 * desired color. */
204
{
205
    Display *display = Tk_Display(tkwin);
206
    Colormap colormap = Tk_Colormap(tkwin);
207
    TkColor *tkColPtr = (TkColor *) ckalloc(sizeof(TkColor));
208
 
209
    tkColPtr->color.red = colorPtr->red;
210
    tkColPtr->color.green = colorPtr->green;
211
    tkColPtr->color.blue = colorPtr->blue;
212
    if (XAllocColor(display, colormap, &tkColPtr->color) != 0) {
213
        DeleteStressedCmap(display, colormap);
214
    } else {
215
        FindClosestColor(tkwin, &tkColPtr->color, &tkColPtr->color);
216
    }
217
 
218
    return tkColPtr;
219
}
220
 
221
/*
222
 *----------------------------------------------------------------------
223
 *
224
 * FindClosestColor --
225
 *
226
 *      When Tk can't allocate a color because a colormap has filled
227
 *      up, this procedure is called to find and allocate the closest
228
 *      available color in the colormap.
229
 *
230
 * Results:
231
 *      There is no return value, but *actualColorPtr is filled in
232
 *      with information about the closest available color in tkwin's
233
 *      colormap.  This color has been allocated via X, so it must
234
 *      be released by the caller when the caller is done with it.
235
 *
236
 * Side effects:
237
 *      A color is allocated.
238
 *
239
 *----------------------------------------------------------------------
240
 */
241
 
242
static void
243
FindClosestColor(tkwin, desiredColorPtr, actualColorPtr)
244
    Tk_Window tkwin;                    /* Window where color will be used. */
245
    XColor *desiredColorPtr;            /* RGB values of color that was
246
                                         * wanted (but unavailable). */
247
    XColor *actualColorPtr;             /* Structure to fill in with RGB and
248
                                         * pixel for closest available
249
                                         * color. */
250
{
251
    TkStressedCmap *stressPtr;
252
    double tmp, distance, closestDistance;
253
    int i, closest, numFound;
254
    XColor *colorPtr;
255
    TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
256
    Colormap colormap = Tk_Colormap(tkwin);
257
    XVisualInfo template, *visInfoPtr;
258
 
259
    /*
260
     * Find the TkStressedCmap structure for this colormap, or create
261
     * a new one if needed.
262
     */
263
 
264
    for (stressPtr = dispPtr->stressPtr; ; stressPtr = stressPtr->nextPtr) {
265
        if (stressPtr == NULL) {
266
            stressPtr = (TkStressedCmap *) ckalloc(sizeof(TkStressedCmap));
267
            stressPtr->colormap = colormap;
268
            template.visualid = XVisualIDFromVisual(Tk_Visual(tkwin));
269
            visInfoPtr = XGetVisualInfo(Tk_Display(tkwin),
270
                    VisualIDMask, &template, &numFound);
271
            if (numFound < 1) {
272
                panic("FindClosestColor couldn't lookup visual");
273
            }
274
            stressPtr->numColors = visInfoPtr->colormap_size;
275
            XFree((char *) visInfoPtr);
276
            stressPtr->colorPtr = (XColor *) ckalloc((unsigned)
277
                    (stressPtr->numColors * sizeof(XColor)));
278
            for (i = 0; i  < stressPtr->numColors; i++) {
279
                stressPtr->colorPtr[i].pixel = (unsigned long) i;
280
            }
281
            XQueryColors(dispPtr->display, colormap, stressPtr->colorPtr,
282
                    stressPtr->numColors);
283
            stressPtr->nextPtr = dispPtr->stressPtr;
284
            dispPtr->stressPtr = stressPtr;
285
            break;
286
        }
287
        if (stressPtr->colormap == colormap) {
288
            break;
289
        }
290
    }
291
 
292
    /*
293
     * Find the color that best approximates the desired one, then
294
     * try to allocate that color.  If that fails, it must mean that
295
     * the color was read-write (so we can't use it, since it's owner
296
     * might change it) or else it was already freed.  Try again,
297
     * over and over again, until something succeeds.
298
     */
299
 
300
    while (1)  {
301
        if (stressPtr->numColors == 0) {
302
            panic("FindClosestColor ran out of colors");
303
        }
304
        closestDistance = 1e30;
305
        closest = 0;
306
        for (colorPtr = stressPtr->colorPtr, i = 0; i < stressPtr->numColors;
307
                colorPtr++, i++) {
308
            /*
309
             * Use Euclidean distance in RGB space, weighted by Y (of YIQ)
310
             * as the objective function;  this accounts for differences
311
             * in the color sensitivity of the eye.
312
             */
313
 
314
            tmp = .30*(((int) desiredColorPtr->red) - (int) colorPtr->red);
315
            distance = tmp*tmp;
316
            tmp = .61*(((int) desiredColorPtr->green) - (int) colorPtr->green);
317
            distance += tmp*tmp;
318
            tmp = .11*(((int) desiredColorPtr->blue) - (int) colorPtr->blue);
319
            distance += tmp*tmp;
320
            if (distance < closestDistance) {
321
                closest = i;
322
                closestDistance = distance;
323
            }
324
        }
325
        if (XAllocColor(dispPtr->display, colormap,
326
                &stressPtr->colorPtr[closest]) != 0) {
327
            *actualColorPtr = stressPtr->colorPtr[closest];
328
            return;
329
        }
330
 
331
        /*
332
         * Couldn't allocate the color.  Remove it from the table and
333
         * go back to look for the next best color.
334
         */
335
 
336
        stressPtr->colorPtr[closest] =
337
                stressPtr->colorPtr[stressPtr->numColors-1];
338
        stressPtr->numColors -= 1;
339
    }
340
}
341
 
342
/*
343
 *----------------------------------------------------------------------
344
 *
345
 * DeleteStressedCmap --
346
 *
347
 *      This procedure releases the information cached for "colormap"
348
 *      so that it will be refetched from the X server the next time
349
 *      it is needed.
350
 *
351
 * Results:
352
 *      None.
353
 *
354
 * Side effects:
355
 *      The TkStressedCmap structure for colormap is deleted;  the
356
 *      colormap is no longer considered to be "stressed".
357
 *
358
 * Note:
359
 *      This procedure is invoked whenever a color in a colormap is
360
 *      freed, and whenever a color allocation in a colormap succeeds.
361
 *      This guarantees that TkStressedCmap structures are always
362
 *      deleted before the corresponding Colormap is freed.
363
 *
364
 *----------------------------------------------------------------------
365
 */
366
 
367
static void
368
DeleteStressedCmap(display, colormap)
369
    Display *display;           /* Xlib's handle for the display
370
                                 * containing the colormap. */
371
    Colormap colormap;          /* Colormap to flush. */
372
{
373
    TkStressedCmap *prevPtr, *stressPtr;
374
    TkDisplay *dispPtr = TkGetDisplay(display);
375
 
376
    for (prevPtr = NULL, stressPtr = dispPtr->stressPtr; stressPtr != NULL;
377
            prevPtr = stressPtr, stressPtr = stressPtr->nextPtr) {
378
        if (stressPtr->colormap == colormap) {
379
            if (prevPtr == NULL) {
380
                dispPtr->stressPtr = stressPtr->nextPtr;
381
            } else {
382
                prevPtr->nextPtr = stressPtr->nextPtr;
383
            }
384
            ckfree((char *) stressPtr->colorPtr);
385
            ckfree((char *) stressPtr);
386
            return;
387
        }
388
    }
389
}
390
 
391
/*
392
 *----------------------------------------------------------------------
393
 *
394
 * TkpCmapStressed --
395
 *
396
 *      Check to see whether a given colormap is known to be out
397
 *      of entries.
398
 *
399
 * Results:
400
 *      1 is returned if "colormap" is stressed (i.e. it has run out
401
 *      of entries recently), 0 otherwise.
402
 *
403
 * Side effects:
404
 *      None.
405
 *
406
 *----------------------------------------------------------------------
407
 */
408
 
409
int
410
TkpCmapStressed(tkwin, colormap)
411
    Tk_Window tkwin;            /* Window that identifies the display
412
                                 * containing the colormap. */
413
    Colormap colormap;          /* Colormap to check for stress. */
414
{
415
    TkStressedCmap *stressPtr;
416
 
417
    for (stressPtr = ((TkWindow *) tkwin)->dispPtr->stressPtr;
418
            stressPtr != NULL; stressPtr = stressPtr->nextPtr) {
419
        if (stressPtr->colormap == colormap) {
420
            return 1;
421
        }
422
    }
423
    return 0;
424
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.