commit - 5aeb3302439dc9eb527a49add177da9ba2970875
commit + 6bb186a7bcccf5882d7f4f146328ea1026b8b505
blob - 525faeda1e9624d0d116b08254bd63e9745eb5e1
blob + c3c2f7522465f535e59040da63b9729c8b8ed3ef
--- mymenu.c
+++ mymenu.c
#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
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)
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);
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);
// 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
}
#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
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
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:
// 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
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);
};
#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);