commit 6bb186a7bcccf5882d7f4f146328ea1026b8b505 from: Omar Polo date: Thu Sep 13 17:00:13 2018 UTC TRANSPARENCY EVERYWHERE! + bugfix commit - 5aeb3302439dc9eb527a49add177da9ba2970875 commit + 6bb186a7bcccf5882d7f4f146328ea1026b8b505 blob - 525faeda1e9624d0d116b08254bd63e9745eb5e1 blob + c3c2f7522465f535e59040da63b9729c8b8ed3ef --- mymenu.c +++ mymenu.c @@ -46,6 +46,8 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define EXPANDBITS(x) ((0xffff * x) / 0xff) + // If we don't have it or we don't want an "ignore case" completion // style, fall back to `strstr(3)` #ifndef USE_STRCASESTR @@ -170,6 +172,17 @@ struct completions *compls_new(size_t lenght) { return cs; } +/* idea stolen from lemonbar. ty lemonboy */ +typedef union { + struct { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; + }; + uint32_t v; +} rgba_t; + // Delete the wrapper and the whole list void compls_delete(struct completions *cs) { if (cs == nil) @@ -455,8 +468,10 @@ char *strdupn(char *str) { void draw_horizontally(struct rendering *r, char *text, struct completions *cs) { int prompt_width = 20; // char + char *ps1dup = strdupn(r->ps1); int width, height; - int ps1xlen = text_extents(r->ps1, r->ps1len, r, &width, &height); + int ps1xlen = text_extents(ps1dup != nil ? ps1dup : r->ps1, r->ps1len, r, &width, &height); + free(ps1dup); int start_at = ps1xlen; start_at = r->x_zero + text_extents("n", 1, r, nil, nil); @@ -509,7 +524,9 @@ void draw_vertically(struct rendering *r, char *text, XFillRectangle(r->d, r->w, r->completion_bg, r->x_zero, r->y_zero, r->width, r->height); XFillRectangle(r->d, r->w, r->prompt_bg, r->x_zero, r->y_zero, r->width, start_at); - int ps1xlen = text_extents(r->ps1, r->ps1len, r, nil, nil); + char *ps1dup = strdupn(r->ps1); + int ps1xlen = text_extents(ps1dup != nil ? ps1dup : r->ps1, r->ps1len, r, nil, nil); + free(ps1dup); draw_string(r->ps1, r->ps1len, r->x_zero + r->padding, r->y_zero + height + r->padding, r, PROMPT); draw_string(text, strlen(text), r->x_zero + r->padding + ps1xlen, r->y_zero + height + r->padding, r, PROMPT); @@ -659,6 +676,54 @@ int take_keyboard(Display *d, Window w) { // release the keyboard. void release_keyboard(Display *d) { XUngrabKeyboard(d, CurrentTime); +} + +unsigned long parse_color(const char *str, const char *def) { + if (str == nil) + goto invc; + + size_t len = strlen(str); + + // +1 for the '#' at the start, hence 9 and 4 (instead of 8 and 3) + if (*str != '#' || len > 9 || len < 4) + goto invc; + ++str; // skip the '#' + + char *ep; + errno = 0; + rgba_t tmp = (rgba_t)(uint32_t)strtoul(str, &ep, 16); + + if (errno) + goto invc; + + switch (len-1) { + case 3: + // expand: #rgb -> #rrggbb + tmp.v = (tmp.v & 0xf00) * 0x1100 + | (tmp.v & 0x0f0) * 0x0110 + | (tmp.v & 0x00f) * 0x0011; + case 6: + // assume it has 100% opacity + tmp.a = 0xff; + break; + } // colors in aarrggbb format needs no fixes + + // premultiply the alpha + if (tmp.a) { + tmp.r = (tmp.r * tmp.a) / 255; + tmp.g = (tmp.g * tmp.a) / 255; + tmp.b = (tmp.b * tmp.a) / 255; + return tmp.v; + } + + return 0U; + +invc: + fprintf(stderr, "Invalid color: \"%s\".\n", str); + if (def != nil) + return parse_color(def, nil); + else + return 0U; } // Given a string, try to parse it as a number or return @@ -1166,12 +1231,24 @@ int main(int argc, char **argv) { } #endif - Colormap cmap = DefaultColormap(d, DefaultScreen(d)); - XColor p_fg, p_bg, - compl_fg, compl_bg, - compl_highlighted_fg, compl_highlighted_bg, - border_n_bg, border_e_bg, border_s_bg, border_w_bg; + /* Colormap cmap = DefaultColormap(d, DefaultScreen(d)); */ + XVisualInfo vinfo; + XMatchVisualInfo(d, DefaultScreen(d), 32, TrueColor, &vinfo); + Colormap cmap; + cmap = XCreateColormap(d, XDefaultRootWindow(d), vinfo.visual, AllocNone); + + unsigned long p_fg = parse_color("#fff", nil); + unsigned long compl_fg = parse_color("#fff", nil); + unsigned long compl_highlighted_fg = parse_color("#000", nil); + + unsigned long p_bg = parse_color("#000", nil); + unsigned long compl_bg = parse_color("#000", nil); + unsigned long compl_highlighted_bg = parse_color("#fff", nil); + + unsigned long border_n_bg, border_e_bg, border_s_bg, border_w_bg; + border_n_bg = border_e_bg = border_s_bg = border_w_bg = parse_color("#000", nil); + bool horizontal_layout = true; // read resource @@ -1242,70 +1319,46 @@ int main(int argc, char **argv) { fprintf(stderr, "no border defined, using 0.\n"); } - XColor tmp; + /* XColor tmp; */ // TODO: tmp needs to be free'd after every allocation? // prompt if (XrmGetResource(xdb, "MyMenu.prompt.foreground", "*", datatype, &value) == true) - XAllocNamedColor(d, cmap, value.addr, &p_fg, &tmp); - else - XAllocNamedColor(d, cmap, "white", &p_fg, &tmp); + p_fg = parse_color(value.addr, "#fff"); if (XrmGetResource(xdb, "MyMenu.prompt.background", "*", datatype, &value) == true) - XAllocNamedColor(d, cmap, value.addr, &p_bg, &tmp); - else - XAllocNamedColor(d, cmap, "black", &p_bg, &tmp); + p_bg = parse_color(value.addr, "#000"); // completion if (XrmGetResource(xdb, "MyMenu.completion.foreground", "*", datatype, &value) == true) - XAllocNamedColor(d, cmap, value.addr, &compl_fg, &tmp); - else - XAllocNamedColor(d, cmap, "white", &compl_fg, &tmp); + compl_fg = parse_color(value.addr, "#fff"); if (XrmGetResource(xdb, "MyMenu.completion.background", "*", datatype, &value) == true) - XAllocNamedColor(d, cmap, value.addr, &compl_bg, &tmp); + compl_bg = parse_color(value.addr, "#000"); else - XAllocNamedColor(d, cmap, "black", &compl_bg, &tmp); + compl_bg = parse_color("#000", nil); // completion highlighted if (XrmGetResource(xdb, "MyMenu.completion_highlighted.foreground", "*", datatype, &value) == true) - XAllocNamedColor(d, cmap, value.addr, &compl_highlighted_fg, &tmp); - else - XAllocNamedColor(d, cmap, "black", &compl_highlighted_fg, &tmp); + compl_highlighted_fg = parse_color(value.addr, "#000"); if (XrmGetResource(xdb, "MyMenu.completion_highlighted.background", "*", datatype, &value) == true) - XAllocNamedColor(d, cmap, value.addr, &compl_highlighted_bg, &tmp); + compl_highlighted_bg = parse_color(value.addr, "#fff"); else - XAllocNamedColor(d, cmap, "white", &compl_highlighted_bg, &tmp); + compl_highlighted_bg = parse_color("#fff", nil); // border if (XrmGetResource(xdb, "MyMenu.border.color", "*", datatype, &value) == true) { char **colors = parse_csslike(value.addr); if (colors != nil) { - XAllocNamedColor(d, cmap, colors[0], &border_n_bg, &tmp); - XAllocNamedColor(d, cmap, colors[1], &border_e_bg, &tmp); - XAllocNamedColor(d, cmap, colors[2], &border_s_bg, &tmp); - XAllocNamedColor(d, cmap, colors[3], &border_w_bg, &tmp); + border_n_bg = parse_color(colors[0], "#000"); + border_e_bg = parse_color(colors[1], "#000"); + border_s_bg = parse_color(colors[2], "#000"); + border_w_bg = parse_color(colors[3], "#000"); } else { fprintf(stderr, "error while parsing MyMenu.border.color\n"); } - } else { - XAllocNamedColor(d, cmap, "white", &border_n_bg, &tmp); - XAllocNamedColor(d, cmap, "white", &border_e_bg, &tmp); - XAllocNamedColor(d, cmap, "white", &border_s_bg, &tmp); - XAllocNamedColor(d, cmap, "white", &border_w_bg, &tmp); } - } else { - XColor tmp; - XAllocNamedColor(d, cmap, "white", &p_fg, &tmp); - XAllocNamedColor(d, cmap, "black", &p_bg, &tmp); - XAllocNamedColor(d, cmap, "white", &compl_fg, &tmp); - XAllocNamedColor(d, cmap, "black", &compl_bg, &tmp); - XAllocNamedColor(d, cmap, "black", &compl_highlighted_fg, &tmp); - XAllocNamedColor(d, cmap, "white", &border_n_bg, &tmp); - XAllocNamedColor(d, cmap, "white", &border_e_bg, &tmp); - XAllocNamedColor(d, cmap, "white", &border_s_bg, &tmp); - XAllocNamedColor(d, cmap, "white", &border_w_bg, &tmp); } // second round of args parsing @@ -1375,44 +1428,37 @@ int main(int argc, char **argv) { case 'B': { char **colors = parse_csslike(optarg); if (colors != nil) { - XColor tmp; - XAllocNamedColor(d, cmap, colors[0], &border_n_bg, &tmp); - XAllocNamedColor(d, cmap, colors[1], &border_e_bg, &tmp); - XAllocNamedColor(d, cmap, colors[2], &border_s_bg, &tmp); - XAllocNamedColor(d, cmap, colors[3], &border_w_bg, &tmp); + border_n_bg = parse_color(colors[0], "#000"); + border_e_bg = parse_color(colors[1], "#000"); + border_s_bg = parse_color(colors[2], "#000"); + border_w_bg = parse_color(colors[3], "#000"); } else { fprintf(stderr, "error while parsing B option\n"); } break; } case 't': { - XColor tmp; - XAllocNamedColor(d, cmap, optarg, &p_fg, &tmp); + p_fg = parse_color(optarg, nil); break; } case 'T': { - XColor tmp; - XAllocNamedColor(d, cmap, optarg, &p_bg, &tmp); + p_bg = parse_color(optarg, nil); break; } case 'c': { - XColor tmp; - XAllocNamedColor(d, cmap, optarg, &compl_fg, &tmp); + compl_fg = parse_color(optarg, nil); break; } case 'C': { - XColor tmp; - XAllocNamedColor(d, cmap, optarg, &compl_bg, &tmp); + compl_bg = parse_color(optarg, nil); break; } case 's': { - XColor tmp; - XAllocNamedColor(d, cmap, optarg, &compl_highlighted_fg, &tmp); + compl_highlighted_fg = parse_color(optarg, nil); break; } case 'S': { - XColor tmp; - XAllocNamedColor(d, cmap, optarg, &compl_highlighted_bg, &tmp); + compl_highlighted_bg = parse_color(optarg, nil); break; } default: @@ -1441,7 +1487,10 @@ int main(int argc, char **argv) { // create the window XSetWindowAttributes attr; + attr.colormap = cmap; attr.override_redirect = true; + attr.border_pixel = 0; + attr.background_pixel = 0x80808080; attr.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask; Window w = XCreateWindow(d, // display @@ -1449,10 +1498,10 @@ int main(int argc, char **argv) { x + offset_x, y + offset_y, // x y width, height, // w h 0, // border width - CopyFromParent, // depth + vinfo.depth, // depth InputOutput, // class - CopyFromParent, // visual - CWEventMask | CWOverrideRedirect, // value mask (CWBackPixel in the future also?) + vinfo.visual, // visual + CWBorderPixel | CWBackPixel | CWColormap | CWEventMask | CWOverrideRedirect, // value mask &attr); set_win_atoms_hints(d, w, width, height); @@ -1518,42 +1567,53 @@ int main(int argc, char **argv) { }; #ifdef USE_XFT - r.xftdraw = XftDrawCreate(d, w, DefaultVisual(d, 0), DefaultColormap(d, 0)); + r.xftdraw = XftDrawCreate(d, w, vinfo.visual, DefaultColormap(d, 0)); - // prompt - XRenderColor xrcolor; - xrcolor.red = p_fg.red; - xrcolor.green = p_fg.red; - xrcolor.blue = p_fg.red; - xrcolor.alpha = 65535; - XftColorAllocValue(d, DefaultVisual(d, 0), DefaultColormap(d, 0), &xrcolor, &r.xft_prompt); + { + rgba_t c; - // completion - xrcolor.red = compl_fg.red; - xrcolor.green = compl_fg.green; - xrcolor.blue = compl_fg.blue; - xrcolor.alpha = 65535; - XftColorAllocValue(d, DefaultVisual(d, 0), DefaultColormap(d, 0), &xrcolor, &r.xft_completion); + XRenderColor xrcolor; - // completion highlighted - xrcolor.red = compl_highlighted_fg.red; - xrcolor.green = compl_highlighted_fg.green; - xrcolor.blue = compl_highlighted_fg.blue; - xrcolor.alpha = 65535; - XftColorAllocValue(d, DefaultVisual(d, 0), DefaultColormap(d, 0), &xrcolor, &r.xft_completion_highlighted); + // prompt + c = *(rgba_t*)&p_fg; + xrcolor.red = EXPANDBITS(c.r); + xrcolor.green = EXPANDBITS(c.g); + xrcolor.blue = EXPANDBITS(c.b); + xrcolor.alpha = EXPANDBITS(c.a); + XftColorAllocValue(d, DefaultVisual(d, 0), DefaultColormap(d, 0), &xrcolor, &r.xft_prompt); + + // completion + c = *(rgba_t*)&compl_fg; + xrcolor.red = EXPANDBITS(c.r); + xrcolor.green = EXPANDBITS(c.g); + xrcolor.blue = EXPANDBITS(c.b); + xrcolor.alpha = EXPANDBITS(c.a); + XftColorAllocValue(d, DefaultVisual(d, 0), DefaultColormap(d, 0), &xrcolor, &r.xft_completion); + + // completion highlighted + c = *(rgba_t*)&compl_highlighted_fg; + xrcolor.red = EXPANDBITS(c.r); + xrcolor.green = EXPANDBITS(c.g); + xrcolor.blue = EXPANDBITS(c.b); + xrcolor.alpha = EXPANDBITS(c.a); + XftColorAllocValue(d, DefaultVisual(d, 0), DefaultColormap(d, 0), &xrcolor, &r.xft_completion_highlighted); + } #endif // load the colors in our GCs - XSetForeground(d, r.prompt, p_fg.pixel); - XSetForeground(d, r.prompt_bg, p_bg.pixel); - XSetForeground(d, r.completion, compl_fg.pixel); - XSetForeground(d, r.completion_bg, compl_bg.pixel); - XSetForeground(d, r.completion_highlighted, compl_highlighted_fg.pixel); - XSetForeground(d, r.completion_highlighted_bg, compl_highlighted_bg.pixel); - XSetForeground(d, r.border_n_bg, border_n_bg.pixel); - XSetForeground(d, r.border_e_bg, border_e_bg.pixel); - XSetForeground(d, r.border_s_bg, border_s_bg.pixel); - XSetForeground(d, r.border_w_bg, border_w_bg.pixel); + /* XSetForeground(d, r.prompt, p_fg.pixel); */ + XSetForeground(d, r.prompt, p_fg); + XSetForeground(d, r.prompt_bg, p_bg); + /* XSetForeground(d, r.completion, compl_fg.pixel); */ + XSetForeground(d, r.completion, compl_fg); + XSetForeground(d, r.completion_bg, compl_bg); + /* XSetForeground(d, r.completion_highlighted, compl_highlighted_fg.pixel); */ + XSetForeground(d, r.completion_highlighted, compl_highlighted_fg); + XSetForeground(d, r.completion_highlighted_bg, compl_highlighted_bg); + XSetForeground(d, r.border_n_bg, border_n_bg); + XSetForeground(d, r.border_e_bg, border_e_bg); + XSetForeground(d, r.border_s_bg, border_s_bg); + XSetForeground(d, r.border_w_bg, border_w_bg); // open the X input method XIM xim = XOpenIM(d, xdb, resname, resclass);