3094
|
1 /* Color data structures for X and Xft.
|
|
2
|
|
3 Copyright (C) 2004 Free Software Foundation, Inc.
|
|
4
|
|
5 Author: Stephen J. Turnbull <stephen@xemacs.org>
|
|
6 Created: 24 Jul 2004 by Stephen J. Turnbull
|
|
7
|
|
8 This file is part of XEmacs.
|
|
9
|
|
10 XEmacs is free software; you can redistribute it and/or modify it
|
|
11 under the terms of the GNU General Public License as published by the
|
|
12 Free Software Foundation; either version 2, or (at your option) any
|
|
13 later version.
|
|
14
|
|
15 XEmacs is distributed in the hope that it will be useful, but WITHOUT
|
|
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
18 for more details.
|
|
19
|
|
20 You should have received a copy of the GNU General Public License
|
|
21 along with XEmacs; see the file COPYING. If not, write to
|
|
22 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
23 Boston, MA 02111-1307, USA. */
|
|
24
|
|
25 /* Synched up with: Not in GNU Emacs. */
|
|
26
|
|
27 #include <config.h>
|
|
28 #include <limits.h> /* for ULONG_MAX */
|
|
29 #include <stdlib.h> /* for malloc() */
|
|
30 #include <stdio.h>
|
|
31 #include <X11/Xlib.h>
|
|
32 #include <X11/IntrinsicP.h>
|
|
33 #include <X11/ShellP.h> /* for ShellWidget */
|
|
34 #include "lwlib-colors.h"
|
|
35
|
|
36 static int debug_colors = 1;
|
|
37
|
|
38 #ifdef __cplusplus
|
|
39 #define X_CLASSFIELD c_class
|
|
40 #else
|
|
41 #define X_CLASSFIELD class
|
|
42 #endif
|
|
43
|
|
44 #define MINL(x,y) ((((unsigned long) (x)) < ((unsigned long) (y))) \
|
|
45 ? ((unsigned long) (x)) : ((unsigned long) (y)))
|
|
46
|
|
47 /* WIDGET is an Xt widget, VISUAL and DEPTH are return values */
|
|
48 void
|
|
49 visual_info_from_widget (Widget widget, Visual **visual, int *depth)
|
|
50 {
|
|
51 /* grab the visual and depth from the nearest shell ancestor */
|
|
52 Widget p = XtParent(widget);
|
|
53
|
|
54 *visual = CopyFromParent;
|
|
55 *depth = -1;
|
|
56 while (*visual == CopyFromParent && p)
|
|
57 {
|
|
58 if (XtIsShell(p))
|
|
59 {
|
|
60 *visual = ((ShellWidget)p)->shell.visual;
|
|
61 *depth = p->core.depth;
|
|
62 }
|
|
63 p = XtParent(p);
|
|
64 }
|
|
65 if (*visual == CopyFromParent || !*visual)
|
|
66 {
|
|
67 if (debug_colors > 1)
|
|
68 fprintf (stderr, "\nvisual_info_from_widget:"
|
|
69 " failed, using DefaultVisualOfScreen");
|
|
70 *visual = DefaultVisualOfScreen (XtScreen (widget));
|
|
71 *depth = DefaultDepthOfScreen (XtScreen (widget));
|
|
72 }
|
|
73 else if (debug_colors > 1)
|
|
74 fprintf (stderr, "\nvisual_info_from_widget: succeeded");
|
|
75 }
|
|
76
|
|
77 /* Do we need all this hair on modern hardware? */
|
|
78
|
|
79 /* Replacement for XAllocColor() that tries to return the nearest
|
|
80 available color if the colormap is full. Original was from FSFmacs,
|
|
81 but rewritten by Jareth Hein <jareth@camelot-soft.com> 97/11/25
|
|
82 Modified by Lee Kindness <lkindness@csl.co.uk> 31/08/99 to handle previous
|
|
83 total failure which was due to a read/write colorcell being the nearest
|
|
84 match - tries the next nearest...
|
|
85
|
|
86 Return value is 1 for normal success, 2 for nearest color success,
|
|
87 3 for Non-deallocable success. */
|
|
88 int
|
|
89 x_allocate_nearest_color (Display *display, Colormap colormap,
|
|
90 Visual *visual, XColor *color_def)
|
|
91 {
|
|
92 int status;
|
|
93
|
|
94 /* #### [[Apparently this is often called with data derived from a widget
|
|
95 with no ShellWidget ancestor, or before the shell has a visual.
|
|
96 Currently this recovery code is in xlwmenu.c and xlwscrollbar.c, but
|
|
97 likely should come here.]]
|
|
98 I suspect the problem is that the visual-tracing code was improperly
|
|
99 written, missing a level of indirection.
|
|
100 CopyFromParent == NULL in XFree86/Darwin.
|
|
101 */
|
|
102 if (visual == CopyFromParent || !visual)
|
|
103 {
|
|
104 Screen *screen = DefaultScreenOfDisplay (display);
|
|
105 fprintf (stderr, "\nx_allocate_nearest_color: bad visual (%08lx)",
|
|
106 (unsigned long) visual);
|
|
107 visual = DefaultVisualOfScreen (screen);
|
|
108 }
|
|
109
|
|
110 if (visual->X_CLASSFIELD == DirectColor || visual->X_CLASSFIELD == TrueColor)
|
|
111 {
|
|
112 if (XAllocColor (display, colormap, color_def) != 0)
|
|
113 {
|
|
114 status = 1;
|
|
115 }
|
|
116 else
|
|
117 {
|
|
118 /* We're dealing with a TrueColor/DirectColor visual, so play games
|
|
119 with the RGB values in the XColor struct. */
|
|
120 /* #### JH: I'm not sure how a call to XAllocColor can fail in a
|
|
121 TrueColor or DirectColor visual, so I will just reformat the
|
|
122 request to match the requirements of the visual, and re-issue
|
|
123 the request. If this fails for anybody, I wanna know about it
|
|
124 so I can come up with a better plan */
|
|
125
|
|
126 unsigned long rshift,gshift,bshift,rbits,gbits,bbits,junk;
|
|
127 junk = visual->red_mask;
|
|
128 rshift = 0;
|
|
129 while ((junk & 0x1) == 0) {
|
|
130 junk = junk >> 1;
|
|
131 rshift ++;
|
|
132 }
|
|
133 rbits = 0;
|
|
134 while (junk != 0) {
|
|
135 junk = junk >> 1;
|
|
136 rbits++;
|
|
137 }
|
|
138 junk = visual->green_mask;
|
|
139 gshift = 0;
|
|
140 while ((junk & 0x1) == 0) {
|
|
141 junk = junk >> 1;
|
|
142 gshift ++;
|
|
143 }
|
|
144 gbits = 0;
|
|
145 while (junk != 0) {
|
|
146 junk = junk >> 1;
|
|
147 gbits++;
|
|
148 }
|
|
149 junk = visual->blue_mask;
|
|
150 bshift = 0;
|
|
151 while ((junk & 0x1) == 0) {
|
|
152 junk = junk >> 1;
|
|
153 bshift ++;
|
|
154 }
|
|
155 bbits = 0;
|
|
156 while (junk != 0) {
|
|
157 junk = junk >> 1;
|
|
158 bbits++;
|
|
159 }
|
|
160
|
|
161 color_def->red = color_def->red >> (16 - rbits);
|
|
162 color_def->green = color_def->green >> (16 - gbits);
|
|
163 color_def->blue = color_def->blue >> (16 - bbits);
|
|
164 if (XAllocColor (display, colormap, color_def) != 0)
|
|
165 status = 1;
|
|
166 else
|
|
167 {
|
|
168 int rd, gr, bl;
|
|
169 /* #### JH: I'm punting here, knowing that doing this will at
|
|
170 least draw the color correctly. However, unless we convert
|
|
171 all of the functions that allocate colors (graphics
|
|
172 libraries, etc) to use this function doing this is very
|
|
173 likely to cause problems later... */
|
|
174
|
|
175 if (rbits > 8)
|
|
176 rd = color_def->red << (rbits - 8);
|
|
177 else
|
|
178 rd = color_def->red >> (8 - rbits);
|
|
179 if (gbits > 8)
|
|
180 gr = color_def->green << (gbits - 8);
|
|
181 else
|
|
182 gr = color_def->green >> (8 - gbits);
|
|
183 if (bbits > 8)
|
|
184 bl = color_def->blue << (bbits - 8);
|
|
185 else
|
|
186 bl = color_def->blue >> (8 - bbits);
|
|
187 color_def->pixel = (rd << rshift) | (gr << gshift) | (bl <<
|
|
188 bshift);
|
|
189 status = 3;
|
|
190 }
|
|
191 }
|
|
192 }
|
|
193 else
|
|
194 {
|
|
195 XColor *cells = NULL;
|
|
196 /* JH: I can't believe there's no way to go backwards from a
|
|
197 colormap ID and get its visual and number of entries, but X
|
|
198 apparently isn't built that way... */
|
|
199 int no_cells = visual->map_entries;
|
|
200 status = 0;
|
|
201
|
|
202 if (XAllocColor (display, colormap, color_def) != 0)
|
|
203 status = 1;
|
|
204 else while( status != 2 )
|
|
205 {
|
|
206 /* If we got to this point, the colormap is full, so we're
|
|
207 going to try and get the next closest color. The algorithm used
|
|
208 is a least-squares matching, which is what X uses for closest
|
|
209 color matching with StaticColor visuals. */
|
|
210 int nearest;
|
|
211 long nearest_delta, trial_delta;
|
|
212 int x;
|
|
213
|
|
214 if( cells == NULL )
|
|
215 {
|
|
216 /* #### this could be annoyingly slow
|
|
217 tell me again why lwlib can't use alloca & friends? */
|
|
218 cells = (XColor *) malloc (sizeof(XColor)*no_cells);
|
|
219 for (x = 0; x < no_cells; x++)
|
|
220 cells[x].pixel = x;
|
|
221
|
|
222 /* read the current colormap */
|
|
223 XQueryColors (display, colormap, cells, no_cells);
|
|
224 }
|
|
225
|
|
226 nearest = 0;
|
|
227 /* I'm assuming CSE so I'm not going to condense this. */
|
|
228 nearest_delta = ((((color_def->red >> 8) - (cells[0].red >> 8))
|
|
229 * ((color_def->red >> 8) - (cells[0].red >> 8)))
|
|
230 +
|
|
231 (((color_def->green >> 8) - (cells[0].green >> 8))
|
|
232 * ((color_def->green >> 8) - (cells[0].green >>
|
|
233 8)))
|
|
234 +
|
|
235 (((color_def->blue >> 8) - (cells[0].blue >> 8))
|
|
236 * ((color_def->blue >> 8) - (cells[0].blue >>
|
|
237 8))));
|
|
238 for (x = 1; x < no_cells; x++)
|
|
239 {
|
|
240 trial_delta = ((((color_def->red >> 8) - (cells[x].red >> 8))
|
|
241 * ((color_def->red >> 8) - (cells[x].red >> 8)))
|
|
242 +
|
|
243 (((color_def->green >> 8) - (cells[x].green >> 8))
|
|
244 * ((color_def->green >> 8) - (cells[x].green >>
|
|
245 8)))
|
|
246 +
|
|
247 (((color_def->blue >> 8) - (cells[x].blue >> 8))
|
|
248 * ((color_def->blue >> 8) - (cells[x].blue >>
|
|
249 8))));
|
|
250
|
|
251 /* less? Ignore cells marked as previously failing */
|
|
252 if( (trial_delta < nearest_delta) &&
|
|
253 (cells[x].pixel != ULONG_MAX) )
|
|
254 {
|
|
255 nearest = x;
|
|
256 nearest_delta = trial_delta;
|
|
257 }
|
|
258 }
|
|
259 color_def->red = cells[nearest].red;
|
|
260 color_def->green = cells[nearest].green;
|
|
261 color_def->blue = cells[nearest].blue;
|
|
262 if (XAllocColor (display, colormap, color_def) != 0)
|
|
263 status = 2;
|
|
264 else
|
|
265 /* LSK: Either the colour map has changed since
|
|
266 * we read it, or the colour is allocated
|
|
267 * read/write... Mark this cmap entry so it's
|
|
268 * ignored in the next iteration.
|
|
269 */
|
|
270 cells[nearest].pixel = ULONG_MAX;
|
|
271 }
|
|
272 }
|
|
273 return status;
|
|
274 }
|
|
275
|
|
276 #if 0
|
|
277 /* Replacement for XAllocColor() that tries to return the nearest
|
|
278 available color if the colormap is full. From GNU Emacs.
|
|
279 #### Review this to see if there's anything our hairy version could use. */
|
|
280
|
|
281 int
|
|
282 FIXME_allocate_nearest_color (Display *display, Colormap screen_colormap,
|
|
283 XColor *color_def)
|
|
284 {
|
|
285 int status = XAllocColor (display, screen_colormap, color_def);
|
|
286 if (status)
|
|
287 return status;
|
|
288
|
|
289 {
|
|
290 /* If we got to this point, the colormap is full, so we're
|
|
291 going to try to get the next closest color.
|
|
292 The algorithm used is a least-squares matching, which is
|
|
293 what X uses for closest color matching with StaticColor visuals. */
|
|
294
|
|
295 int nearest, x;
|
|
296 unsigned long nearest_delta = ULONG_MAX;
|
|
297
|
|
298 int no_cells = XDisplayCells (display, XDefaultScreen (display));
|
|
299 /* Don't use alloca here because lwlib doesn't have the
|
|
300 necessary configuration information that src does. */
|
|
301 XColor *cells = (XColor *) malloc (sizeof (XColor) * no_cells);
|
|
302
|
|
303 for (x = 0; x < no_cells; x++)
|
|
304 cells[x].pixel = x;
|
|
305
|
|
306 XQueryColors (display, screen_colormap, cells, no_cells);
|
|
307
|
|
308 for (nearest = 0, x = 0; x < no_cells; x++)
|
|
309 {
|
|
310 long dred = (color_def->red >> 8) - (cells[x].red >> 8);
|
|
311 long dgreen = (color_def->green >> 8) - (cells[x].green >> 8);
|
|
312 long dblue = (color_def->blue >> 8) - (cells[x].blue >> 8);
|
|
313 unsigned long delta = dred * dred + dgreen * dgreen + dblue * dblue;
|
|
314
|
|
315 if (delta < nearest_delta)
|
|
316 {
|
|
317 nearest = x;
|
|
318 nearest_delta = delta;
|
|
319 }
|
|
320 }
|
|
321 color_def->red = cells[nearest].red;
|
|
322 color_def->green = cells[nearest].green;
|
|
323 color_def->blue = cells[nearest].blue;
|
|
324 free (cells);
|
|
325 return XAllocColor (display, screen_colormap, color_def);
|
|
326 }
|
|
327 }
|
|
328 #endif
|
|
329
|
|
330
|
|
331 #ifdef USE_XFT
|
|
332
|
|
333 XftColor
|
|
334 xft_convert_color (Display *dpy, Colormap cmap, Visual *visual, int c, int dim)
|
|
335 {
|
|
336 static XColor color; /* #### why is this static ?? */
|
|
337 XftColor result;
|
|
338
|
|
339 color.pixel = c;
|
|
340 XQueryColor(dpy, cmap, &color);
|
|
341
|
|
342 if (dim)
|
|
343 {
|
|
344 color.red = MINL (65535, color.red * 1.5);
|
|
345 color.green = MINL (65535, color.green * 1.5);
|
|
346 color.blue = MINL (65535, color.blue * 1.5);
|
|
347 x_allocate_nearest_color (dpy, cmap, visual, &color);
|
|
348 }
|
|
349
|
|
350 result.pixel = color.pixel;
|
|
351 result.color.red = color.red;
|
|
352 result.color.green = color.green;
|
|
353 result.color.blue = color.blue;
|
|
354 result.color.alpha = 0xffff;
|
|
355
|
|
356 return result;
|
|
357 }
|
|
358
|
|
359 #endif /* USE_XFT */
|
|
360
|
|
361 /* end of lwlib-colors.c */
|