JWM Source Documentation
color.c
Go to the documentation of this file.
1 
10 #include "jwm.h"
11 #include "main.h"
12 #include "color.h"
13 #include "error.h"
14 #include "misc.h"
15 #include "settings.h"
16 
18 typedef struct {
20  unsigned int value;
22 
23 unsigned long colors[COLOR_COUNT];
24 static unsigned long rgbColors[COLOR_COUNT];
25 
26 /* Map a linear 8-bit RGB space to pixel values. */
27 static unsigned long *rgbToPixel;
28 
29 /* Maximum number of colors to allocate for icons. */
30 static const unsigned MAX_COLORS = 64;
31 
32 #ifdef USE_XFT
33 static XftColor *xftColors[COLOR_COUNT] = { NULL };
34 #endif
35 
36 #define THEME_TEXT 0xFFFFFF
37 #define THEME_ACTIVE 0x0077CC
38 #define THEME_ACTIVE2 0x004488
39 #define THEME_INACTIVE 0x555555
40 #define THEME_INACTIVE2 0x333333
41 #define THEME_OUTLINE 0x000000
42 
43 static const DefaultColorNode DEFAULT_COLORS[] = {
44 
47 
52 
59 
66 
73 
77 
84 
90 
94 
95 };
96 static const unsigned DEFAULT_COUNT = ARRAY_LENGTH(DEFAULT_COLORS);
97 
98 static struct {
101 } INHERITED_COLORS[] = {
125 };
127 
128 static struct {
132 } DERIVED_COLORS[] = {
145 };
146 static const unsigned DERIVED_COUNT = ARRAY_LENGTH(DERIVED_COLORS);
147 
148 static char **names = NULL;
149 
150 static unsigned redShift;
151 static unsigned greenShift;
152 static unsigned blueShift;
153 static unsigned redBits;
154 static unsigned greenBits;
155 static unsigned blueBits;
156 
157 static unsigned ComputeShift(unsigned long maskIn, unsigned *shiftOut);
158 static unsigned long GetRGBFromXColor(const XColor *c);
159 
160 static unsigned long GetDirectPixel(const XColor *c);
161 static void GetMappedPixel(XColor *c);
162 static void AllocateColor(ColorType type, XColor *c);
163 
164 static unsigned long ReadHex(const char *hex);
165 char ParseColorToRGB(const char *value, XColor *c);
166 
167 static void InitializeNames(void);
168 
169 static XColor GetXColorFromRGB(unsigned long rgb);
170 static void LightenColor(ColorType oldColor, ColorType newColor);
171 static void DarkenColor(ColorType oldColor, ColorType newColor);
172 
174 void StartupColors(void)
175 {
176  unsigned int x;
177  XColor c;
178 
179  /* Initialize the color array. */
180  memset(rgbColors, 0xFF, sizeof(rgbColors));
181 
182  /* Determine how to convert between RGB triples and pixels. */
183  switch(rootVisual->class) {
184  case DirectColor:
185  case TrueColor:
186  redBits = ComputeShift(rootVisual->red_mask, &redShift);
187  greenBits = ComputeShift(rootVisual->green_mask, &greenShift);
188  blueBits = ComputeShift(rootVisual->blue_mask, &blueShift);
189  rgbToPixel = NULL;
190  break;
191  default:
192  /* Restrict icons to 64 colors (RGB 2, 2, 2). */
193  redBits = ComputeShift(0x30, &redShift);
195  blueBits = ComputeShift(0x03, &blueShift);
196  rgbToPixel = Allocate(sizeof(unsigned long) * MAX_COLORS);
197  memset(rgbToPixel, 0xFF, sizeof(unsigned long) * MAX_COLORS);
198  break;
199  }
200 
201  /* Inherit colors. */
202  if(names) {
203  for(x = 0; x < INHERITED_COUNT; x++) {
204  const ColorType dest = INHERITED_COLORS[x].dest;
205  if(!names[dest]) {
206  const ColorType src = INHERITED_COLORS[x].src;
207  names[dest] = CopyString(names[src]);
208  }
209  }
210  }
211 
212  /* Load custom colors. */
213  for(x = 0; x < COLOR_COUNT; x++) {
214  if(names && names[x]) {
215  if(ParseColorToRGB(names[x], &c)) {
216  AllocateColor(x, &c);
217  } else {
218  Release(names[x]);
219  names[x] = NULL;
220  }
221  }
222  }
223 
224  /* Load defaults. */
225  for(x = 0; x < DEFAULT_COUNT; x++) {
226  const ColorType type = DEFAULT_COLORS[x].type;
227  if(!names || !names[type]) {
228  const unsigned rgb = DEFAULT_COLORS[x].value;
229  c.red = ((rgb >> 16) & 0xFF) * 257;
230  c.green = ((rgb >> 8) & 0xFF) * 257;
231  c.blue = (rgb & 0xFF) * 257;
232  AllocateColor(type, &c);
233  }
234  }
235 
236  /* Derive colors. */
237  for(x = 0; x < DERIVED_COUNT; x++) {
238  if(!names || !names[DERIVED_COLORS[x].up]) {
240  }
241  if(!names || !names[DERIVED_COLORS[x].down]) {
243  }
244  }
245 
246  DestroyColors();
247 }
248 
250 void ShutdownColors(void)
251 {
252  unsigned x;
253 
254 #ifdef USE_XFT
255  for(x = 0; x < COLOR_COUNT; x++) {
256  if(xftColors[x]) {
258  Release(xftColors[x]);
259  xftColors[x] = NULL;
260  }
261  }
262 #endif
263 
264  if(rgbToPixel) {
265  for(x = 0; x < MAX_COLORS; x++) {
266  if(rgbToPixel[x] != ULONG_MAX) {
268  }
269  }
270  for(x = 0; x < COLOR_COUNT; x++) {
271  if(rgbColors[x] != ULONG_MAX) {
272  unsigned y;
274  for(y = x; y < COLOR_COUNT; y++) {
275  if(colors[y] == colors[x]) {
276  rgbColors[y] = ULONG_MAX;
277  }
278  }
279  }
280  }
282  rgbToPixel = NULL;
283  }
284 
285 }
286 
288 void DestroyColors(void)
289 {
290  if(names) {
291  unsigned int x;
292  for(x = 0; x < COLOR_COUNT; x++) {
293  if(names[x]) {
294  Release(names[x]);
295  }
296  }
297  Release(names);
298  names = NULL;
299  }
300 }
301 
303 unsigned ComputeShift(unsigned long maskIn, unsigned *shiftOut)
304 {
305  unsigned bits = 0;
306  unsigned shift = 0;
307  while(maskIn && (maskIn & 1) == 0) {
308  shift += 1;
309  maskIn >>= 1;
310  }
311  *shiftOut = shift;
312  while(maskIn) {
313  bits += 1;
314  maskIn >>= 1;
315  }
316  return bits;
317 }
318 
320 unsigned long GetRGBFromXColor(const XColor *c)
321 {
322  unsigned long red, green, blue;
323  red = (c->red >> 8) << 16;
324  green = (c->green >> 8) << 8;
325  blue = (c->blue >> 8) << 0;
326  return red | green | blue;
327 }
328 
330 void SetColor(ColorType c, const char *value)
331 {
332  if(JUNLIKELY(!value)) {
333  Warning("empty color tag");
334  return;
335  }
336 
337  InitializeNames();
338 
339  if(names[c]) {
340  Release(names[c]);
341  }
342 
343  names[c] = CopyString(value);
344 }
345 
347 char ParseColorToRGB(const char *value, XColor *c)
348 {
349  if(JUNLIKELY(!value)) {
350  return 0;
351  }
352 
353  if(value[0] == '#' && strlen(value) == 7) {
354  const unsigned long rgb = ReadHex(value + 1);
355  c->red = ((rgb >> 16) & 0xFF) * 257;
356  c->green = ((rgb >> 8) & 0xFF) * 257;
357  c->blue = (rgb & 0xFF) * 257;
358  } else {
359  if(!JXParseColor(display, rootColormap, value, c)) {
360  Warning("bad color: \"%s\"", value);
361  return 0;
362  }
363  }
364 
365  return 1;
366 }
367 
369 char ParseColor(const char *value, XColor *c)
370 {
371  if(JLIKELY(ParseColorToRGB(value, c))) {
372  GetColor(c);
373  return 1;
374  } else {
375  return 0;
376  }
377 }
378 
380 void InitializeNames(void)
381 {
382  if(names == NULL) {
383  unsigned int x;
384  names = Allocate(sizeof(char*) * COLOR_COUNT);
385  for(x = 0; x < COLOR_COUNT; x++) {
386  names[x] = NULL;
387  }
388  }
389 }
390 
392 unsigned long ReadHex(const char *hex)
393 {
394  unsigned long value = 0;
395  unsigned int x;
396 
397  for(x = 0; hex[x]; x++) {
398  value *= 16;
399  if(hex[x] >= '0' && hex[x] <= '9') {
400  value += hex[x] - '0';
401  } else if(hex[x] >= 'A' && hex[x] <= 'F') {
402  value += hex[x] - 'A' + 10;
403  } else if(hex[x] >= 'a' && hex[x] <= 'f') {
404  value += hex[x] - 'a' + 10;
405  }
406  }
407 
408  return value;
409 }
410 
412 unsigned long GetDirectPixel(const XColor *c)
413 {
414  const unsigned long red = (c->red >> (16 - redBits )) << redShift;
415  const unsigned long green = (c->green >> (16 - greenBits)) << greenShift;
416  const unsigned long blue = (c->blue >> (16 - blueBits )) << blueShift;
417  return red | green | blue;
418 }
419 
421 void GetMappedPixel(XColor *c)
422 {
423  const unsigned long index = GetDirectPixel(c);
424  if(rgbToPixel[index] == ULONG_MAX) {
425  c->red = (c->red & 0xC000) | 0x0800;
426  c->green = (c->green & 0xC000) | 0x0800;
427  c->blue = (c->blue & 0xC000) | 0x0800;
429  rgbToPixel[index] = c->pixel;
430  } else {
431  c->pixel = rgbToPixel[index];
432  }
433 }
434 
436 void AllocateColor(ColorType type, XColor *c)
437 {
438  unsigned i;
439 
440  /* Save the desired RGB color. */
441  rgbColors[type] = GetRGBFromXColor(c);
442 
443  /* Look up the pixel value to use. */
444  switch(rootVisual->class) {
445  case DirectColor:
446  case TrueColor:
447  c->pixel = GetDirectPixel(c);
448  break;
449  default:
450  /* First see if we already know about this color. */
451  for(i = 0; i < COLOR_COUNT; i++) {
452  if(i != type && rgbColors[i] == rgbColors[type]) {
453  colors[type] = colors[i];
454  return;
455  }
456  }
457 
458  /* Allocate a new read-only cell. */
460  break;
461  }
462  colors[type] = c->pixel;
463 }
464 
466 void GetColor(XColor *c)
467 {
468  switch(rootVisual->class) {
469  case DirectColor:
470  case TrueColor:
471  c->pixel = GetDirectPixel(c);
472  return;
473  default:
474  GetMappedPixel(c);
475  return;
476  }
477 }
478 
480 #ifdef USE_XFT
481 XftColor *GetXftColor(ColorType type)
482 {
483 
484  if(!xftColors[type]) {
485  XRenderColor rcolor;
486  const unsigned long rgb = rgbColors[type];
487  xftColors[type] = Allocate(sizeof(XftColor));
488  rcolor.alpha = 65535;
489  rcolor.red = ((rgb >> 16) & 0xFF) * 257;
490  rcolor.green = ((rgb >> 8) & 0xFF) * 257;
491  rcolor.blue = (rgb & 0xFF) * 257;
493  xftColors[type]);
494  }
495 
496  return xftColors[type];
497 
498 }
499 #endif
500 
502 XColor GetXColorFromRGB(unsigned long rgb)
503 {
504  XColor ret = { 0 };
505 
506  ret.flags = DoRed | DoGreen | DoBlue;
507  ret.red = (unsigned short)(((rgb >> 16) & 0xFF) * 257);
508  ret.green = (unsigned short)(((rgb >> 8) & 0xFF) * 257);
509  ret.blue = (unsigned short)((rgb & 0xFF) * 257);
510 
511  return ret;
512 }
513 
515 void LightenColor(ColorType oldColor, ColorType newColor)
516 {
517 
518  XColor temp;
519  int red, green, blue;
520 
521  temp = GetXColorFromRGB(rgbColors[oldColor]);
522 
523  /* Convert to 0.0 to 1.0 in fixed point with 8 bits for the fraction. */
524  red = temp.red >> 8;
525  green = temp.green >> 8;
526  blue = temp.blue >> 8;
527 
528  /* Multiply by 1.45 which is 371. */
529  red = (red * 371) >> 8;
530  green = (green * 371) >> 8;
531  blue = (blue * 371) >> 8;
532 
533  /* Convert back to 0-65535. */
534  red |= red << 8;
535  green |= green << 8;
536  blue |= blue << 8;
537 
538  /* Cap at 65535. */
539  red = Min(65535, red);
540  green = Min(65535, green);
541  blue = Min(65535, blue);
542 
543  temp.red = red;
544  temp.green = green;
545  temp.blue = blue;
546 
547  AllocateColor(newColor, &temp);
548 }
549 
551 void DarkenColor(ColorType oldColor, ColorType newColor)
552 {
553 
554  XColor temp;
555  int red, green, blue;
556 
557  temp = GetXColorFromRGB(rgbColors[oldColor]);
558 
559  /* Convert to 0.0 to 1.0 in fixed point with 8 bits for the fraction. */
560  red = temp.red >> 8;
561  green = temp.green >> 8;
562  blue = temp.blue >> 8;
563 
564  /* Multiply by 0.55 which is 141. */
565  red = (red * 141) >> 8;
566  green = (green * 141) >> 8;
567  blue = (blue * 141) >> 8;
568 
569  /* Convert back to 0-65535. */
570  red |= red << 8;
571  green |= green << 8;
572  blue |= blue << 8;
573 
574  temp.red = red;
575  temp.green = green;
576  temp.blue = blue;
577 
578  AllocateColor(newColor, &temp);
579 }

joewing.net / Projects / JWM