aboutsummaryrefslogtreecommitdiff
path: root/src/color.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/color.c')
-rw-r--r--src/color.c606
1 files changed, 606 insertions, 0 deletions
diff --git a/src/color.c b/src/color.c
new file mode 100644
index 0000000..edf5f7a
--- /dev/null
+++ b/src/color.c
@@ -0,0 +1,606 @@
+/****************************************************************************
+ * Functions to handle loading colors.
+ * Copyright (C) 2004 Joe Wingbermuehle
+ ****************************************************************************/
+
+#include "jwm.h"
+#include "main.h"
+#include "color.h"
+#include "error.h"
+#include "misc.h"
+
+typedef struct {
+ ColorType type;
+ const char *value;
+} DefaultColorNode;
+
+static const float COLOR_DELTA = 0.45;
+
+unsigned long colors[COLOR_COUNT];
+static unsigned long rgbColors[COLOR_COUNT];
+
+static unsigned long *map;
+
+#ifdef USE_XFT
+static XftColor *xftColors[COLOR_COUNT] = { NULL };
+#endif
+
+static DefaultColorNode DEFAULT_COLORS[] = {
+ { COLOR_BORDER_BG, "gray" },
+ { COLOR_BORDER_FG, "black" },
+ { COLOR_BORDER_ACTIVE_BG, "red" },
+ { COLOR_BORDER_ACTIVE_FG, "white" },
+ { COLOR_TRAY_BG, "gray" },
+ { COLOR_TRAY_FG, "black" },
+ { COLOR_TASK_BG, "gray" },
+ { COLOR_TASK_FG, "black" },
+ { COLOR_TASK_ACTIVE_BG, "red" },
+ { COLOR_TASK_ACTIVE_FG, "white" },
+ { COLOR_PAGER_BG, "black" },
+ { COLOR_PAGER_FG, "gray" },
+ { COLOR_PAGER_ACTIVE_BG, "red" },
+ { COLOR_PAGER_ACTIVE_FG, "red" },
+ { COLOR_PAGER_OUTLINE, "black" },
+ { COLOR_MENU_BG, "gray" },
+ { COLOR_MENU_FG, "black" },
+ { COLOR_MENU_ACTIVE_BG, "red" },
+ { COLOR_MENU_ACTIVE_FG, "white" },
+ { COLOR_POPUP_BG, "yellow" },
+ { COLOR_POPUP_FG, "black" },
+ { COLOR_POPUP_OUTLINE, "black" },
+ { COLOR_TRAYBUTTON_FG, "black" },
+ { COLOR_TRAYBUTTON_BG, "gray" },
+ { COLOR_CLOCK_FG, "black" },
+ { COLOR_CLOCK_BG, "gray" },
+ { COLOR_COUNT, NULL }
+};
+
+static char **names = NULL;
+
+static unsigned long redShift;
+static unsigned long greenShift;
+static unsigned long blueShift;
+static unsigned long redMask;
+static unsigned long greenMask;
+static unsigned long blueMask;
+
+static void ComputeShiftMask(unsigned long maskIn,
+ unsigned long *shiftOut, unsigned long *maskOut);
+
+static void GetDirectPixel(XColor *c);
+static void GetMappedPixel(XColor *c);
+
+static int ParseColor(ColorType type, const char *value);
+static void SetDefaultColor(ColorType type);
+
+static unsigned long ReadHex(const char *hex);
+
+static unsigned long GetRGBFromXColor(const XColor *c);
+static XColor GetXColorFromRGB(unsigned long rgb);
+
+static int GetColorByName(const char *str, XColor *c);
+static void InitializeNames();
+
+static void LightenColor(ColorType oldColor, ColorType newColor);
+static void DarkenColor(ColorType oldColor, ColorType newColor);
+
+/****************************************************************************
+ ****************************************************************************/
+void InitializeColors() {
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void StartupColors() {
+
+ int x;
+ int red, green, blue;
+ XColor c;
+
+ /* Determine how to convert between RGB triples and pixels. */
+ Assert(rootVisual);
+ switch(rootVisual->class) {
+ case DirectColor:
+ case TrueColor:
+ ComputeShiftMask(rootVisual->red_mask, &redShift, &redMask);
+ ComputeShiftMask(rootVisual->green_mask, &greenShift, &greenMask);
+ ComputeShiftMask(rootVisual->blue_mask, &blueShift, &blueMask);
+ map = NULL;
+ break;
+ default:
+
+ /* Attempt to get 256 colors, pretend it worked. */
+ redMask = 0xE0;
+ greenMask = 0x1C;
+ blueMask = 0x03;
+ ComputeShiftMask(redMask, &redShift, &redMask);
+ ComputeShiftMask(greenMask, &greenShift, &greenMask);
+ ComputeShiftMask(blueMask, &blueShift, &blueMask);
+ map = Allocate(sizeof(unsigned long) * 256);
+
+ /* RGB: 3, 3, 2 */
+ x = 0;
+ for(red = 0; red < 8; red++) {
+ for(green = 0; green < 8; green++) {
+ for(blue = 0; blue < 4; blue++) {
+ c.red = 74898 * red / 8;
+ c.green = 74898 * green / 8;
+ c.blue = 87381 * blue / 4;
+ c.flags = DoRed | DoGreen | DoBlue;
+ JXAllocColor(display, rootColormap, &c);
+ map[x] = c.pixel;
+ ++x;
+ }
+ }
+ }
+
+ break;
+ }
+
+ /* Inherit unset colors from the tray for tray items. */
+ if(names) {
+ if(!names[COLOR_TASK_BG]) {
+ names[COLOR_TASK_BG] = CopyString(names[COLOR_TRAY_BG]);
+ }
+ if(!names[COLOR_TRAYBUTTON_BG]) {
+ names[COLOR_TRAYBUTTON_BG] = CopyString(names[COLOR_TRAY_BG]);
+ }
+ if(!names[COLOR_CLOCK_BG]) {
+ names[COLOR_CLOCK_BG] = CopyString(names[COLOR_TRAY_BG]);
+ }
+ if(!names[COLOR_TASK_FG]) {
+ names[COLOR_TASK_FG] = CopyString(names[COLOR_TRAY_FG]);
+ }
+ if(!names[COLOR_TRAYBUTTON_FG]) {
+ names[COLOR_TRAYBUTTON_FG] = CopyString(names[COLOR_TRAY_FG]);
+ }
+ if(!names[COLOR_CLOCK_FG]) {
+ names[COLOR_CLOCK_FG] = CopyString(names[COLOR_TRAY_FG]);
+ }
+ }
+
+ /* Get color information used for JWM stuff. */
+ for(x = 0; x < COLOR_COUNT; x++) {
+ if(names && names[x]) {
+ if(!ParseColor(x, names[x])) {
+ SetDefaultColor(x);
+ }
+ } else {
+ SetDefaultColor(x);
+ }
+ }
+
+ if(names) {
+ for(x = 0; x < COLOR_COUNT; x++) {
+ if(names[x]) {
+ Release(names[x]);
+ }
+ }
+ Release(names);
+ names = NULL;
+ }
+
+ LightenColor(COLOR_BORDER_BG, COLOR_BORDER_UP);
+ DarkenColor(COLOR_BORDER_BG, COLOR_BORDER_DOWN);
+
+ LightenColor(COLOR_BORDER_ACTIVE_BG, COLOR_BORDER_ACTIVE_UP);
+ DarkenColor(COLOR_BORDER_ACTIVE_BG, COLOR_BORDER_ACTIVE_DOWN);
+
+ LightenColor(COLOR_TRAY_BG, COLOR_TRAY_UP);
+ DarkenColor(COLOR_TRAY_BG, COLOR_TRAY_DOWN);
+
+ LightenColor(COLOR_TASK_BG, COLOR_TASK_UP);
+ DarkenColor(COLOR_TASK_BG, COLOR_TASK_DOWN);
+
+ LightenColor(COLOR_TASK_ACTIVE_BG, COLOR_TASK_ACTIVE_UP);
+ DarkenColor(COLOR_TASK_ACTIVE_BG, COLOR_TASK_ACTIVE_DOWN);
+
+ LightenColor(COLOR_MENU_BG, COLOR_MENU_UP);
+ DarkenColor(COLOR_MENU_BG, COLOR_MENU_DOWN);
+
+ LightenColor(COLOR_MENU_ACTIVE_BG, COLOR_MENU_ACTIVE_UP);
+ DarkenColor(COLOR_MENU_ACTIVE_BG, COLOR_MENU_ACTIVE_DOWN);
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void ShutdownColors() {
+
+#ifdef USE_XFT
+
+ int x;
+
+ for(x = 0; x < COLOR_COUNT; x++) {
+ if(xftColors[x]) {
+ JXftColorFree(display, rootVisual, rootColormap, xftColors[x]);
+ Release(xftColors[x]);
+ xftColors[x] = NULL;
+ }
+ }
+
+#endif
+
+ if(map != NULL) {
+ JXFreeColors(display, rootColormap, map, 256, 0);
+ Release(map);
+ map = NULL;
+ }
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void DestroyColors() {
+
+ int x;
+
+ if(names) {
+ for(x = 0; x < COLOR_COUNT; x++) {
+ if(names[x]) {
+ Release(names[x]);
+ }
+ }
+ Release(names);
+ names = NULL;
+ }
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void ComputeShiftMask(unsigned long maskIn,
+ unsigned long *shiftOut, unsigned long *maskOut) {
+
+ int shift;
+
+ Assert(shiftOut);
+ Assert(maskOut);
+
+ /* Components are stored in 16 bits.
+ * When computing pixels, we'll first shift left 16 bits
+ * so to the shift will be an offset from that 32 bit entity.
+ * shift = 16 - <shift-to-ones> + <shift-to-zeros>
+ */
+
+ shift = 0;
+ *maskOut = maskIn;
+ while(maskIn && (maskIn & (1 << 31)) == 0) {
+ ++shift;
+ maskIn <<= 1;
+ }
+ *shiftOut = shift;
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+unsigned long GetRGBFromXColor(const XColor *c) {
+
+ float red, green, blue;
+ unsigned long rgb;
+
+ Assert(c);
+
+ red = (float)c->red / 65535.0;
+ green = (float)c->green / 65535.0;
+ blue = (float)c->blue / 65535.0;
+
+ rgb = (unsigned long)(red * 255.0) << 16;
+ rgb |= (unsigned long)(green * 255.0) << 8;
+ rgb |= (unsigned long)(blue * 255.0);
+
+ return rgb;
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+XColor GetXColorFromRGB(unsigned long rgb) {
+
+ XColor ret = { 0 };
+
+ ret.flags = DoRed | DoGreen | DoBlue;
+ ret.red = (unsigned short)(((rgb >> 16) & 0xFF) * 257);
+ ret.green = (unsigned short)(((rgb >> 8) & 0xFF) * 257);
+ ret.blue = (unsigned short)((rgb & 0xFF) * 257);
+
+ return ret;
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void SetColor(ColorType c, const char *value) {
+
+ if(!value) {
+ Warning("empty color tag");
+ return;
+ }
+
+ InitializeNames();
+
+ if(names[c]) {
+ Release(names[c]);
+ }
+
+ names[c] = CopyString(value);
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+int ParseColor(ColorType type, const char *value) {
+
+ XColor temp;
+ unsigned long rgb;
+
+ if(!value) {
+ return 0;
+ }
+
+ if(value[0] == '#' && strlen(value) == 7) {
+ rgb = ReadHex(value + 1);
+ temp.red = ((rgb >> 16) & 0xFF) * 257;
+ temp.green = ((rgb >> 8) & 0xFF) * 257;
+ temp.blue = (rgb & 0xFF) * 257;
+ temp.flags = DoRed | DoGreen | DoBlue;
+ GetColor(&temp);
+ } else {
+ if(!GetColorByName(value, &temp)) {
+ Warning("bad color: \"%s\"", value);
+ return 0;
+ }
+ }
+ colors[type] = temp.pixel;
+ rgbColors[type] = GetRGBFromXColor(&temp);
+
+ return 1;
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void SetDefaultColor(ColorType type) {
+
+ int x;
+
+ for(x = 0; DEFAULT_COLORS[x].value; x++) {
+ if(DEFAULT_COLORS[x].type == type) {
+ ParseColor(type, DEFAULT_COLORS[x].value);
+ return;
+ }
+ }
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void InitializeNames() {
+
+ int x;
+
+ if(names == NULL) {
+ names = Allocate(sizeof(char*) * COLOR_COUNT);
+ for(x = 0; x < COLOR_COUNT; x++) {
+ names[x] = NULL;
+ }
+ }
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+unsigned long ReadHex(const char *hex) {
+
+ unsigned long value = 0;
+ int x;
+
+ Assert(hex);
+
+ for(x = 0; hex[x]; x++) {
+ value *= 16;
+ if(hex[x] >= '0' && hex[x] <= '9') {
+ value += hex[x] - '0';
+ } else if(hex[x] >= 'A' && hex[x] <= 'F') {
+ value += hex[x] - 'A' + 10;
+ } else if(hex[x] >= 'a' && hex[x] <= 'f') {
+ value += hex[x] - 'a' + 10;
+ }
+ }
+
+ return value;
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void LightenColor(ColorType oldColor, ColorType newColor) {
+
+ XColor temp;
+ float red, green, blue;
+ float delta = 1.0 + COLOR_DELTA;
+
+ temp = GetXColorFromRGB(rgbColors[oldColor]);
+
+ red = (float)temp.red / 65535.0;
+ green = (float)temp.green / 65535.0;
+ blue = (float)temp.blue / 65535.0;
+
+ red = Min(delta * red, 1.0);
+ green = Min(delta * green, 1.0);
+ blue = Min(delta * blue, 1.0);
+
+ temp.red = red * 65535.0;
+ temp.green = green * 65535.0;
+ temp.blue = blue * 65535.0;
+
+ GetColor(&temp);
+ colors[newColor] = temp.pixel;
+ rgbColors[newColor] = GetRGBFromXColor(&temp);
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+void DarkenColor(ColorType oldColor, ColorType newColor) {
+
+ XColor temp;
+ float red, green, blue;
+ float delta = 1.0 - COLOR_DELTA;
+
+ temp = GetXColorFromRGB(rgbColors[oldColor]);
+
+ red = (float)temp.red / 65535.0;
+ green = (float)temp.green / 65535.0;
+ blue = (float)temp.blue / 65535.0;
+
+ red = delta * red;
+ green = delta * green;
+ blue = delta * blue;
+
+ temp.red = red * 65535.0;
+ temp.green = green * 65535.0;
+ temp.blue = blue * 65535.0;
+
+ GetColor(&temp);
+ colors[newColor] = temp.pixel;
+ rgbColors[newColor] = GetRGBFromXColor(&temp);
+
+}
+
+/***************************************************************************
+ ***************************************************************************/
+int GetColorByName(const char *str, XColor *c) {
+
+ Assert(str);
+ Assert(c);
+
+ if(!JXParseColor(display, rootColormap, str, c)) {
+ return 0;
+ }
+
+ GetColor(c);
+
+ return 1;
+
+}
+
+/***************************************************************************
+ * Compute the RGB components from an index into our RGB colormap.
+ ***************************************************************************/
+void GetColorFromIndex(XColor *c) {
+
+ unsigned long red;
+ unsigned long green;
+ unsigned long blue;
+
+ Assert(c);
+
+ red = (c->pixel & redMask) << redShift;
+ green = (c->pixel & greenMask) << greenShift;
+ blue = (c->pixel & blueMask) << blueShift;
+
+ c->red = red >> 16;
+ c->green = green >> 16;
+ c->blue = blue >> 16;
+
+}
+
+/***************************************************************************
+ * Compute the pixel value from RGB components.
+ ***************************************************************************/
+void GetDirectPixel(XColor *c) {
+
+ unsigned long red;
+ unsigned long green;
+ unsigned long blue;
+
+ Assert(c);
+
+ /* Normalize. */
+ red = c->red << 16;
+ green = c->green << 16;
+ blue = c->blue << 16;
+
+ /* Shift to the correct offsets and mask. */
+ red = (red >> redShift) & redMask;
+ green = (green >> greenShift) & greenMask;
+ blue = (blue >> blueShift) & blueMask;
+
+ /* Combine. */
+ c->pixel = red | green | blue;
+
+}
+
+/***************************************************************************
+ * Compute the pixel value from RGB components.
+ ***************************************************************************/
+void GetMappedPixel(XColor *c) {
+
+ Assert(c);
+
+ GetDirectPixel(c);
+ c->pixel = map[c->pixel];
+
+}
+
+/***************************************************************************
+ * Compute the pixel value from RGB components.
+ ***************************************************************************/
+void GetColor(XColor *c) {
+
+ Assert(c);
+ Assert(rootVisual);
+
+ switch(rootVisual->class) {
+ case DirectColor:
+ case TrueColor:
+ GetDirectPixel(c);
+ return;
+ default:
+ GetMappedPixel(c);
+ return;
+ }
+
+}
+
+/***************************************************************************
+ * When loading images from external sources, we need to know the color
+ * components even if running with a colormap. So here we pretend
+ * we have a linear RGB colormap even if we don't.
+ * This prevents calls to XQueryColor later.
+ ***************************************************************************/
+void GetColorIndex(XColor *c) {
+
+ Assert(c);
+
+ GetDirectPixel(c);
+
+}
+
+/****************************************************************************
+ ****************************************************************************/
+#ifdef USE_XFT
+XftColor *GetXftColor(ColorType type) {
+
+ unsigned long rgb;
+ XRenderColor rcolor;
+
+ if(!xftColors[type]) {
+ rgb = rgbColors[type];
+ xftColors[type] = Allocate(sizeof(XftColor));
+ rcolor.alpha = 65535;
+ rcolor.red = ((rgb >> 16) & 0xFF) * 257;
+ rcolor.green = ((rgb >> 8) & 0xFF) * 257;
+ rcolor.blue = (rgb & 0xFF) * 257;
+ JXftColorAllocValue(display, rootVisual, rootColormap, &rcolor,
+ xftColors[type]);
+ }
+
+ return xftColors[type];
+
+}
+#endif
+