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