Clean up the code doing color parsing and handling. Implement gradients as a bonus feature (not yet exposed)
This commit is contained in:
parent
392f23ef36
commit
704ba652d9
190
bar.c
190
bar.c
|
@ -10,6 +10,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
|
#include <xcb/xcbext.h>
|
||||||
#include <xcb/xinerama.h>
|
#include <xcb/xinerama.h>
|
||||||
#include <xcb/randr.h>
|
#include <xcb/randr.h>
|
||||||
|
|
||||||
|
@ -41,6 +42,16 @@ typedef struct area_t {
|
||||||
char *cmd;
|
char *cmd;
|
||||||
} area_t;
|
} area_t;
|
||||||
|
|
||||||
|
typedef union rgba_t {
|
||||||
|
struct {
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t a;
|
||||||
|
};
|
||||||
|
uint32_t v;
|
||||||
|
} rgba_t;
|
||||||
|
|
||||||
#define N 20
|
#define N 20
|
||||||
|
|
||||||
typedef struct area_stack_t {
|
typedef struct area_stack_t {
|
||||||
|
@ -82,22 +93,89 @@ static bool dock = false;
|
||||||
static bool topbar = true;
|
static bool topbar = true;
|
||||||
static int bw = -1, bh = -1, bx = 0, by = 0;
|
static int bw = -1, bh = -1, bx = 0, by = 0;
|
||||||
static int bu = 1; // Underline height
|
static int bu = 1; // Underline height
|
||||||
static uint32_t fgc, bgc, ugc;
|
static rgba_t fgc, bgc, ugc;
|
||||||
static uint32_t dfgc, dbgc;
|
static rgba_t dfgc, dbgc;
|
||||||
static area_stack_t astack;
|
static area_stack_t astack;
|
||||||
|
|
||||||
void
|
void
|
||||||
update_gc (void)
|
update_gc (void)
|
||||||
{
|
{
|
||||||
xcb_change_gc(c, gc[GC_DRAW], XCB_GC_BACKGROUND | XCB_GC_FOREGROUND, (const uint32_t []){ fgc, bgc });
|
xcb_change_gc(c, gc[GC_DRAW], XCB_GC_FOREGROUND, (const uint32_t []){ fgc.v });
|
||||||
xcb_change_gc(c, gc[GC_CLEAR], XCB_GC_FOREGROUND, (const uint32_t []){ bgc });
|
xcb_change_gc(c, gc[GC_CLEAR], XCB_GC_FOREGROUND, (const uint32_t []){ bgc.v });
|
||||||
xcb_change_gc(c, gc[GC_ATTR], XCB_GC_FOREGROUND, (const uint32_t []){ ugc });
|
xcb_change_gc(c, gc[GC_ATTR], XCB_GC_FOREGROUND, (const uint32_t []){ ugc.v });
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
fill_rect (xcb_drawable_t d, xcb_gcontext_t gc, int x, int y, int width, int height)
|
fill_gradient (xcb_drawable_t d, int x, int y, int width, int height, rgba_t start, rgba_t stop)
|
||||||
{
|
{
|
||||||
xcb_poly_fill_rectangle(c, d, gc, 1, (const xcb_rectangle_t []){ { x, y, width, height } });
|
float i;
|
||||||
|
const int K = 25; // The number of steps
|
||||||
|
|
||||||
|
for (i = 0.; i < 1.; i += (1. / K)) {
|
||||||
|
// Perform the linear interpolation magic
|
||||||
|
unsigned int rr = i * stop.r + (1. - i) * start.r;
|
||||||
|
unsigned int gg = i * stop.g + (1. - i) * start.g;
|
||||||
|
unsigned int bb = i * stop.b + (1. - i) * start.b;
|
||||||
|
|
||||||
|
// The alpha is ignored here
|
||||||
|
rgba_t step = { rr, gg, bb, 0xff };
|
||||||
|
|
||||||
|
xcb_change_gc(c, gc[GC_DRAW], XCB_GC_FOREGROUND, (const uint32_t []){ step.v });
|
||||||
|
xcb_poly_fill_rectangle(c, d, gc[GC_DRAW], 1,
|
||||||
|
(const xcb_rectangle_t []){ { x, i * bh, width, bh / K + 1 } });
|
||||||
|
}
|
||||||
|
|
||||||
|
xcb_change_gc(c, gc[GC_DRAW], XCB_GC_FOREGROUND, (const uint32_t []){ fgc.v });
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fill_rect (xcb_drawable_t d, xcb_gcontext_t _gc, int x, int y, int width, int height)
|
||||||
|
{
|
||||||
|
xcb_poly_fill_rectangle(c, d, _gc, 1, (const xcb_rectangle_t []){ { x, y, width, height } });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apparently xcb cannot seem to compose the right request for this call, hence we have to do it by
|
||||||
|
// ourselves.
|
||||||
|
// The funcion is taken from 'wmdia' (http://wmdia.sourceforge.net/)
|
||||||
|
xcb_void_cookie_t xcb_poly_text_16_simple(xcb_connection_t * c,
|
||||||
|
xcb_drawable_t drawable, xcb_gcontext_t gc, int16_t x, int16_t y,
|
||||||
|
uint32_t len, const uint16_t *str)
|
||||||
|
{
|
||||||
|
static const xcb_protocol_request_t xcb_req = {
|
||||||
|
5, // count
|
||||||
|
0, // ext
|
||||||
|
XCB_POLY_TEXT_16, // opcode
|
||||||
|
1 // isvoid
|
||||||
|
};
|
||||||
|
struct iovec xcb_parts[7];
|
||||||
|
uint8_t xcb_lendelta[2];
|
||||||
|
xcb_void_cookie_t xcb_ret;
|
||||||
|
xcb_poly_text_8_request_t xcb_out;
|
||||||
|
|
||||||
|
xcb_out.pad0 = 0;
|
||||||
|
xcb_out.drawable = drawable;
|
||||||
|
xcb_out.gc = gc;
|
||||||
|
xcb_out.x = x;
|
||||||
|
xcb_out.y = y;
|
||||||
|
|
||||||
|
xcb_lendelta[0] = len;
|
||||||
|
xcb_lendelta[1] = 0;
|
||||||
|
|
||||||
|
xcb_parts[2].iov_base = (char *)&xcb_out;
|
||||||
|
xcb_parts[2].iov_len = sizeof(xcb_out);
|
||||||
|
xcb_parts[3].iov_base = 0;
|
||||||
|
xcb_parts[3].iov_len = -xcb_parts[2].iov_len & 3;
|
||||||
|
|
||||||
|
xcb_parts[4].iov_base = xcb_lendelta;
|
||||||
|
xcb_parts[4].iov_len = sizeof(xcb_lendelta);
|
||||||
|
xcb_parts[5].iov_base = (char *)str;
|
||||||
|
xcb_parts[5].iov_len = len * sizeof(int16_t);
|
||||||
|
|
||||||
|
xcb_parts[6].iov_base = 0;
|
||||||
|
xcb_parts[6].iov_len = -(xcb_parts[4].iov_len + xcb_parts[5].iov_len) & 3;
|
||||||
|
|
||||||
|
xcb_ret.sequence = xcb_send_request(c, 0, xcb_parts + 2, &xcb_req);
|
||||||
|
return xcb_ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -107,13 +185,17 @@ draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch)
|
||||||
|
|
||||||
switch (align) {
|
switch (align) {
|
||||||
case ALIGN_C:
|
case ALIGN_C:
|
||||||
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW], mon->width / 2 - x / 2, 0,
|
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
|
||||||
mon->width / 2 - (x + ch_width) / 2, 0, x, bh);
|
mon->width / 2 - x / 2, 0,
|
||||||
|
mon->width / 2 - (x + ch_width) / 2, 0,
|
||||||
|
x, bh);
|
||||||
x = mon->width / 2 - (x + ch_width) / 2 + x;
|
x = mon->width / 2 - (x + ch_width) / 2 + x;
|
||||||
break;
|
break;
|
||||||
case ALIGN_R:
|
case ALIGN_R:
|
||||||
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW], mon->width - x, 0,
|
xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW],
|
||||||
mon->width - x - ch_width, 0, x, bh);
|
mon->width - x, 0,
|
||||||
|
mon->width - x - ch_width, 0,
|
||||||
|
x, bh);
|
||||||
x = mon->width - ch_width;
|
x = mon->width - ch_width;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -124,8 +206,10 @@ draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch)
|
||||||
// xcb accepts string in UCS-2 BE, so swap
|
// xcb accepts string in UCS-2 BE, so swap
|
||||||
ch = (ch >> 8) | (ch << 8);
|
ch = (ch >> 8) | (ch << 8);
|
||||||
|
|
||||||
// String baseline coordinates
|
// The coordinates here are those of the baseline
|
||||||
xcb_image_text_16(c, 1, mon->pixmap, gc[GC_DRAW], x, bh / 2 + cur_font->height / 2 - cur_font->descent, (xcb_char2b_t *)&ch);
|
xcb_poly_text_16_simple(c, mon->pixmap, gc[GC_DRAW],
|
||||||
|
x, bh / 2 + cur_font->height / 2 - cur_font->descent,
|
||||||
|
1, &ch);
|
||||||
|
|
||||||
// We can render both at the same time
|
// We can render both at the same time
|
||||||
if (attrs & ATTR_OVERL)
|
if (attrs & ATTR_OVERL)
|
||||||
|
@ -136,12 +220,12 @@ draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch)
|
||||||
return ch_width;
|
return ch_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t
|
rgba_t
|
||||||
parse_color (const char *str, char **end, const uint32_t def)
|
parse_color (const char *str, char **end, const rgba_t def)
|
||||||
{
|
{
|
||||||
xcb_alloc_named_color_reply_t *nc_reply;
|
xcb_alloc_named_color_reply_t *nc_reply;
|
||||||
int str_len;
|
size_t string_len;
|
||||||
uint32_t ret;
|
rgba_t ret;
|
||||||
|
|
||||||
if (!str)
|
if (!str)
|
||||||
return def;
|
return def;
|
||||||
|
@ -156,47 +240,45 @@ parse_color (const char *str, char **end, const uint32_t def)
|
||||||
// Hex representation
|
// Hex representation
|
||||||
if (str[0] == '#') {
|
if (str[0] == '#') {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
uint32_t tmp = strtoul(str + 1, end, 16);
|
rgba_t tmp = (rgba_t)(uint32_t)strtoul(str + 1, end, 16);
|
||||||
|
|
||||||
// Some error checking is definitely good
|
// Some error checking is definitely good
|
||||||
if (errno)
|
if (errno) {
|
||||||
tmp = def;
|
fprintf(stderr, "Invalid color specified\n");
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
// Xorg uses colors with premultiplied alpha
|
// Premultiply the alpha in
|
||||||
unsigned int a = (tmp&0xff000000) >> 24;
|
if (tmp.a) {
|
||||||
unsigned int r = (tmp&0x00ff0000) >> 16;
|
// The components are clamped automagically as the rgba_t is made of uint8_t
|
||||||
unsigned int g = (tmp&0x0000ff00) >> 8;
|
return (rgba_t){
|
||||||
unsigned int b = (tmp&0x000000ff);
|
.r = (tmp.r * tmp.a) / 255,
|
||||||
|
.g = (tmp.g * tmp.a) / 255,
|
||||||
|
.b = (tmp.b * tmp.a) / 255,
|
||||||
|
.a = tmp.a,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (a) {
|
return (rgba_t)0U;
|
||||||
r = (r * a) / 255;
|
|
||||||
g = (g * a) / 255;
|
|
||||||
b = (b * a) / 255;
|
|
||||||
|
|
||||||
// Clamp on overflow
|
|
||||||
if (r > 255) r = 255;
|
|
||||||
if (g > 255) g = 255;
|
|
||||||
if (b > 255) b = 255;
|
|
||||||
} else
|
|
||||||
r = g = b = 0;
|
|
||||||
|
|
||||||
return a << 24 | r << 16 | g << 8 | b;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actual color name, resolve it
|
// Actual color name, resolve it
|
||||||
str_len = 0;
|
for (string_len = 0; isalpha(str[string_len]); string_len++)
|
||||||
while (isalpha(str[str_len]))
|
;
|
||||||
str_len++;
|
|
||||||
|
|
||||||
nc_reply = xcb_alloc_named_color_reply(c, xcb_alloc_named_color(c, colormap, str_len, str), NULL);
|
nc_reply = xcb_alloc_named_color_reply(c, xcb_alloc_named_color(c, colormap, string_len, str), NULL);
|
||||||
|
|
||||||
if (!nc_reply)
|
if (!nc_reply)
|
||||||
fprintf(stderr, "Could not alloc color \"%.*s\"\n", str_len, str);
|
fprintf(stderr, "Could not alloc color \"%.*s\"\n", string_len, str);
|
||||||
ret = (nc_reply) ? nc_reply->pixel : def;
|
|
||||||
|
ret = nc_reply?
|
||||||
|
(rgba_t)nc_reply->pixel:
|
||||||
|
def;
|
||||||
|
|
||||||
free(nc_reply);
|
free(nc_reply);
|
||||||
|
|
||||||
if (end)
|
if (end)
|
||||||
*end = (char *)str + str_len;
|
*end = (char *)str + string_len;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -363,7 +445,7 @@ parse (char *text)
|
||||||
monitor_t *cur_mon;
|
monitor_t *cur_mon;
|
||||||
int pos_x, align, button;
|
int pos_x, align, button;
|
||||||
char *p = text, *end;
|
char *p = text, *end;
|
||||||
uint32_t tmp;
|
rgba_t tmp;
|
||||||
|
|
||||||
pos_x = 0;
|
pos_x = 0;
|
||||||
align = ALIGN_L;
|
align = ALIGN_L;
|
||||||
|
@ -631,7 +713,7 @@ monitor_new (int x, int y, int width, int height)
|
||||||
ret->x, ret->y, width, bh, 0,
|
ret->x, ret->y, width, bh, 0,
|
||||||
XCB_WINDOW_CLASS_INPUT_OUTPUT, visual,
|
XCB_WINDOW_CLASS_INPUT_OUTPUT, visual,
|
||||||
XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP,
|
XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK | XCB_CW_COLORMAP,
|
||||||
(const uint32_t []){ bgc, bgc, dock, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS, colormap });
|
(const uint32_t []){ bgc.v, bgc.v, dock, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS, colormap });
|
||||||
|
|
||||||
ret->pixmap = xcb_generate_id(c);
|
ret->pixmap = xcb_generate_id(c);
|
||||||
xcb_create_pixmap(c, depth, ret->pixmap, ret->window, width, bh);
|
xcb_create_pixmap(c, depth, ret->pixmap, ret->window, width, bh);
|
||||||
|
@ -1063,13 +1145,13 @@ init (void)
|
||||||
|
|
||||||
// Create the gc for drawing
|
// Create the gc for drawing
|
||||||
gc[GC_DRAW] = xcb_generate_id(c);
|
gc[GC_DRAW] = xcb_generate_id(c);
|
||||||
xcb_create_gc(c, gc[GC_DRAW], monhead->pixmap, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND, (const uint32_t []){ fgc, bgc });
|
xcb_create_gc(c, gc[GC_DRAW], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ fgc.v });
|
||||||
|
|
||||||
gc[GC_CLEAR] = xcb_generate_id(c);
|
gc[GC_CLEAR] = xcb_generate_id(c);
|
||||||
xcb_create_gc(c, gc[GC_CLEAR], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ bgc });
|
xcb_create_gc(c, gc[GC_CLEAR], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ bgc.v });
|
||||||
|
|
||||||
gc[GC_ATTR] = xcb_generate_id(c);
|
gc[GC_ATTR] = xcb_generate_id(c);
|
||||||
xcb_create_gc(c, gc[GC_ATTR], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ ugc });
|
xcb_create_gc(c, gc[GC_ATTR], monhead->pixmap, XCB_GC_FOREGROUND, (const uint32_t []){ ugc.v });
|
||||||
|
|
||||||
// Make the bar visible and clear the pixmap
|
// Make the bar visible and clear the pixmap
|
||||||
for (monitor_t *mon = monhead; mon; mon = mon->next) {
|
for (monitor_t *mon = monhead; mon; mon = mon->next) {
|
||||||
|
@ -1143,8 +1225,8 @@ main (int argc, char **argv)
|
||||||
xconn();
|
xconn();
|
||||||
|
|
||||||
// B/W combo
|
// B/W combo
|
||||||
dbgc = bgc = parse_color("black", NULL, scr->black_pixel);
|
dbgc = bgc = parse_color("black", NULL, (rgba_t)scr->black_pixel);
|
||||||
dfgc = fgc = parse_color("white", NULL, scr->white_pixel);
|
dfgc = fgc = parse_color("white", NULL, (rgba_t)scr->white_pixel);
|
||||||
|
|
||||||
ugc = fgc;
|
ugc = fgc;
|
||||||
|
|
||||||
|
@ -1169,8 +1251,8 @@ main (int argc, char **argv)
|
||||||
case 'd': dock = true; break;
|
case 'd': dock = true; break;
|
||||||
case 'f': parse_font_list(optarg); break;
|
case 'f': parse_font_list(optarg); break;
|
||||||
case 'u': bu = strtoul(optarg, NULL, 10); break;
|
case 'u': bu = strtoul(optarg, NULL, 10); break;
|
||||||
case 'B': dbgc = bgc = parse_color(optarg, NULL, scr->black_pixel); break;
|
case 'B': dbgc = bgc = parse_color(optarg, NULL, (rgba_t)scr->black_pixel); break;
|
||||||
case 'F': dfgc = fgc = parse_color(optarg, NULL, scr->white_pixel); break;
|
case 'F': dfgc = fgc = parse_color(optarg, NULL, (rgba_t)scr->white_pixel); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user