comparison lwlib/lwlib-colors.c @ 3094:ad2f4ae9895b

[xemacs-hg @ 2005-11-26 11:45:47 by stephent] Xft merge. <87k6ev4p8q.fsf@tleepslib.sk.tsukuba.ac.jp>
author stephent
date Sat, 26 Nov 2005 11:46:25 +0000
parents
children a6c778975d7d
comparison
equal deleted inserted replaced
3093:769dc945b085 3094:ad2f4ae9895b
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 */