1 /**********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17
18 #include <X11/Intrinsic.h>
19 #include <X11/StringDefs.h>
20 #include <X11/Xlib.h>
21 #include <X11/Xutil.h>
22 #include <X11/Xos.h>
23
24 #include <limits.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27
28 #include "fcintl.h"
29 #include "log.h"
30 #include "mem.h"
31
32 #include "rgbcolor.h"
33
34 #include "gui_main.h"
35
36 #include "colors.h"
37
38 Colormap cmap;
39
40 /* This is just so we can print the visual class intelligibly */
41 /*static char *visual_class[] = {
42 "StaticGray",
43 "GrayScale",
44 "StaticColor",
45 "PseudoColor",
46 "TrueColor",
47 "DirectColor"
48 };
49 */
50
51 void alloc_color_for_colormap(XColor *color);
52
53 /****************************************************************************
54 Allocate a color (adjusting it for our colormap if necessary on paletted
55 systems) and return a pointer to it.
56 ****************************************************************************/
color_alloc(int r,int g,int b)57 struct color *color_alloc(int r, int g, int b)
58 {
59 XColor mycolor;
60 struct color *color = fc_malloc(sizeof(*color));
61
62 mycolor.red = r << 8;
63 mycolor.green = g << 8;
64 mycolor.blue = b << 8;
65
66 alloc_color_for_colormap(&mycolor);
67
68 color->color = mycolor; /* structure copy */
69 return color;
70 }
71
72 /****************************************************************************
73 Free a previously allocated color. See color_alloc.
74 ****************************************************************************/
color_free(struct color * color)75 void color_free(struct color *color)
76 {
77 free(color);
78 }
79
80
81 #if 0
82 /*************************************************************
83 ...
84 *************************************************************/
85 static void alloc_standard_colors(void)
86 {
87 XColor mycolors[COLOR_STD_LAST];
88 int i;
89
90 for(i=0; i<COLOR_STD_LAST; i++) {
91 mycolors[i].red = colors_standard_rgb[i].r << 8;
92 mycolors[i].green = colors_standard_rgb[i].g << 8;
93 mycolors[i].blue = colors_standard_rgb[i].b << 8;
94 }
95
96 alloc_colors(mycolors, COLOR_STD_LAST);
97
98 for (i = 0; i < COLOR_STD_LAST; i++) {
99 colors_standard[i] = mycolors[i].pixel;
100 }
101 }
102 #endif
103
104 /*************************************************************
105 ...
106 *************************************************************/
get_visual(void)107 enum Display_color_type get_visual(void)
108 {
109 int i, default_depth;
110 Visual *default_visual;
111 XVisualInfo visual_info;
112
113 /* Try to allocate colors for PseudoColor, TrueColor,
114 * DirectColor, and StaticColor; use black and white
115 * for StaticGray and GrayScale */
116 default_depth = DefaultDepth(display, screen_number);
117 default_visual = DefaultVisual(display, screen_number);
118
119 if (default_depth == 1) {
120 /* Must be StaticGray, use black and white */
121 log_verbose("found B/W display.");
122 return BW_DISPLAY;
123 }
124
125 i=5;
126
127 while(!XMatchVisualInfo(display, screen_number,
128 default_depth, i--, &visual_info));
129
130
131 /*
132 log_verbose("Found a %s class visual at default depth.",
133 visual_class[++i]);
134 */
135
136 if(i < StaticColor) { /* Color visual classes are 2 to 5 */
137 /* No color visual available at default depth;
138 * some applications might call XMatchVisualInfo
139 * here to try for a GrayScale visual if they
140 * can use gray to advantage, before giving up
141 * and using black and white */
142 log_verbose("found grayscale(?) display.");
143 return GRAYSCALE_DISPLAY;
144 }
145
146 /* Otherwise, got a color visual at default depth */
147 /* The visual we found is not necessarily the default
148 * visual, and therefore it is not necessarily the one
149 * we used to create our window; however, we now know
150 * for sure that color is supported, so the following
151 * code will work (or fail in a controlled way) */
152 /* Let's check just out of curiosity: */
153 if (visual_info.visual != default_visual) {
154 /* log_verbose("Found: %s class visual at default depth",
155 visual_class[i]); */
156 }
157
158 log_verbose("color system booted ok.");
159
160 return COLOR_DISPLAY;
161 }
162
163
164 #if 0
165 /*************************************************************
166 ...
167 *************************************************************/
168 void init_color_system(void)
169 {
170 cmap=DefaultColormap(display, screen_number);
171
172 alloc_standard_colors();
173 }
174 #endif
175
176 /*************************************************************
177 Allocate all needed colors given in the array.
178 *************************************************************/
alloc_colors(XColor * colors,int ncols)179 void alloc_colors(XColor *colors, int ncols)
180 {
181 int i;
182
183 if (!cmap) {
184 cmap = DefaultColormap(display, screen_number);
185 }
186
187 for (i = 0; i < ncols; i++) {
188 if (!XAllocColor(display, cmap, &colors[i])) {
189 /* We're out of colors. For the rest of the palette, just
190 * find the closest match and use it. We could instead try
191 * to use a private colormap, but this is ugly, takes extra
192 * code, and has no guarantee of getting better performance
193 * unless we do a lot of work to optimize the colormap. */
194 XColor *cells;
195 int ncells, j;
196
197 ncells = DisplayCells(display, screen_number);
198 cells = fc_malloc(sizeof(XColor) * ncells);
199
200 for (j = 0; j < ncells; j++) {
201 cells[j].pixel = j;
202 }
203
204 /* We need to lock the server so that the colors don't change
205 * while we're searching through them. */
206 XGrabServer(display);
207
208 XQueryColors(display, cmap, cells, ncells);
209
210 for (; i < ncols; i++) {
211 int best = INT_MAX;
212 unsigned long pixel = 0;
213
214 /* Find the best match among all available colors. */
215 for (j = 0; j < ncells; j++) {
216 int rd, gd, bd, dist;
217
218 rd = (cells[j].red - colors[i].red) >> 8;
219 gd = (cells[j].green - colors[i].green) >> 8;
220 bd = (cells[j].blue - colors[i].blue) >> 8;
221 dist = rd * rd + gd * gd + bd * bd;
222
223 if (dist < best) {
224 best = dist;
225 pixel = j;
226 }
227 }
228
229 XAllocColor(display, cmap, &cells[pixel]);
230 colors[i] = cells[pixel]; /* structure copy */
231 }
232
233 /* Unlock the server, since we're done querying it. */
234 XUngrabServer(display);
235
236 free(cells);
237 break;
238 }
239 }
240 }
241
242 /*************************************************************
243 Alloc given color for our colormap.
244 *************************************************************/
alloc_color_for_colormap(XColor * color)245 void alloc_color_for_colormap(XColor *color)
246 {
247 if (!cmap) {
248 cmap = DefaultColormap(display, screen_number);
249 }
250
251 if (!XAllocColor(display, cmap, color)) {
252 /* We're out of colors. For the rest of the palette, just
253 * find the closest match and use it. We could instead try
254 * to use a private colormap, but this is ugly, takes extra
255 * code, and has no guarantee of getting better performance
256 * unless we do a lot of work to optimize the colormap. */
257 XColor *cells;
258 int ncells, j;
259 int best = INT_MAX;
260 unsigned long pixel = 0;
261
262 ncells = DisplayCells(display, screen_number);
263 cells = fc_malloc(sizeof(XColor) * ncells);
264
265 for (j = 0; j < ncells; j++) {
266 cells[j].pixel = j;
267 }
268
269 /* We need to lock the server so that the colors don't change
270 * while we're searching through them. */
271 XGrabServer(display);
272
273 XQueryColors(display, cmap, cells, ncells);
274
275 /* Find the best match among all available colors. */
276 for (j = 0; j < ncells; j++) {
277 int rd, gd, bd, dist;
278
279 rd = (cells[j].red - color->red) >> 8;
280 gd = (cells[j].green - color->green) >> 8;
281 bd = (cells[j].blue - color->blue) >> 8;
282 dist = rd * rd + gd * gd + bd * bd;
283
284 if (dist < best) {
285 best = dist;
286 pixel = j;
287 }
288 }
289
290 XAllocColor(display, cmap, &cells[pixel]);
291 *color = cells[pixel]; /* structure copy */
292
293 /* Unlock the server, since we're done querying it. */
294 XUngrabServer(display);
295
296 free(cells);
297 }
298 }
299
300
301
302 /*************************************************************
303 ...
304 *************************************************************/
free_colors(unsigned long * pixels,int ncols)305 void free_colors(unsigned long *pixels, int ncols)
306 {
307 #if 0
308 XFreeColors(display, cmap, pixels, ncols, 0);
309 #endif
310 }
311
312 /****************************************************************************
313 Return a number indicating the perceptual brightness of this color
314 relative to others (larger is brighter).
315 ****************************************************************************/
color_brightness_score(struct color * pcolor)316 int color_brightness_score(struct color *pcolor)
317 {
318 struct rgbcolor *prgb = rgbcolor_new(pcolor->color.red >> 8,
319 pcolor->color.green >> 8,
320 pcolor->color.blue >> 8);
321 int score = rgbcolor_brightness_score(prgb);
322
323 rgbcolor_destroy(prgb);
324 return score;
325 }
326