diff --git a/README.pod b/README.pod index 5837bd1..6f3be14 100644 --- a/README.pod +++ b/README.pod @@ -4,7 +4,7 @@ bar - bar ain't recursive =head1 SYNOPSIS -I [-h | -g IBI | -b | -d | -f I | -a I| -p | -B I | -F I] +I [-h | -g IBIB<+>I | -b | -d | -f I | -a I| -p | -u I | -B I | -F I] =head1 DESCRIPTION @@ -18,9 +18,9 @@ B is a lightweight bar entirely based on XCB. Provides full UTF-8 support, Display the help and exit. -=item B<-g> IBI +=item B<-g> IBIB<+>I -Set the window geometry. Both the parameters can be omitted, bar defaults the former to the whole width and the height to the font height + 1 pixel. +Set the window geometry. If a parameter is omitted it's filled with the default value. =item B<-b> @@ -42,6 +42,10 @@ Set the bar alpha in range 0.0 to 1.0. This requires a compositor manager such a Make bar permanent, don't exit after the standard input is closed. +=item B<-u> I + +Sets the underline width in pixels. The default is 1. + =item B<-B> I Set the background color of the bar. I might be either in hex format (#rrggbb) or in the symbolic name format (eg. white, brightred, darkgray). diff --git a/bar.c b/bar.c index c2c84d0..230203f 100644 --- a/bar.c +++ b/bar.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -51,10 +52,11 @@ static xcb_gcontext_t gc[3]; static monitor_t *monhead, *montail; static font_t *main_font, *alt_font; static uint32_t attrs = 0; -static float ba = 1.0f; +static float ba = 1.0f; /* bar alpha */ static bool dock = false; static bool topbar = true; -static int bw = -1, bh = -1; +static int bw = -1, bh = -1, bx = 0; +static int bu = 1; /* Underline height */ static char *mfont, *afont; static uint32_t fgc, bgc, ugc; static uint32_t dfgc, dbgc; @@ -102,14 +104,13 @@ draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch) ch = (ch >> 8) | (ch << 8); /* String baseline coordinates */ - xcb_image_text_16(c, 1, canvas, gc[0], x + mon->x, bh / 2 + cur_font->height / 2 - cur_font->descent, - (xcb_char2b_t *)&ch); + xcb_image_text_16(c, 1, canvas, gc[0], x + mon->x, bh / 2 + cur_font->height / 2 - cur_font->descent, (xcb_char2b_t *)&ch); /* We can render both at the same time */ if (attrs & ATTR_OVERL) - fill_rect(gc[2], x + mon->x, 0, ch_width, 1); + fill_rect(gc[2], x + mon->x, 0, ch_width, bu); if (attrs & ATTR_UNDERL) - fill_rect(gc[2], x + mon->x, bh-1, ch_width, 1); + fill_rect(gc[2], x + mon->x, bh-bu, ch_width, bu); return ch_width; } @@ -433,6 +434,40 @@ rect_sort_cb (const void *p1, const void *p2) return 0; } +void +monitor_create_chain (xcb_rectangle_t *rects, const int num) +{ + int width = bw; + int left = bx; + + /* Sort before use */ + qsort(rects, num, sizeof(xcb_rectangle_t), rect_sort_cb); + + /* Left is a positive number or zero therefore monitors with zero width are excluded */ + for (int i = 0; i < num; i++) { + if (rects[i].width > left) { + monitor_t *mon = monitor_new( + rects[i].x + left, + rects[i].y, + min(width, rects[i].width - left), + rects[i].height); + + monitor_add(mon); + + width -= rects[i].width - left; + + /* No need to check for other monitors */ + if (width <= 0) + break; + } + + left -= rects[i].width; + + if (left < 0) + left = 0; + } +} + void get_randr_monitors (void) { @@ -440,7 +475,6 @@ get_randr_monitors (void) xcb_randr_get_screen_resources_current_reply_t *rres_reply; xcb_randr_output_t *outputs; int num, valid = 0; - int width = bw; rres_reply = xcb_randr_get_screen_resources_current_reply(c, xcb_randr_get_screen_resources_current(c, scr->root), NULL); @@ -521,26 +555,7 @@ get_randr_monitors (void) return; } - /* Sort before use */ - qsort(rects, num, sizeof(xcb_rectangle_t), rect_sort_cb); - - for (int i = 0; i < num; i++) { - if (rects[i].width) { - monitor_t *mon = monitor_new( - rects[i].x, - rects[i].y, - min(width, rects[i].width), - rects[i].height); - - monitor_add(mon); - - width -= rects[i].width; - - /* No need to check for other monitors */ - if (width <= 0) - break; - } - } + monitor_create_chain(rects, num); } void @@ -567,27 +582,9 @@ get_xinerama_monitors (void) xcb_xinerama_screen_info_next(&iter); } - /* Sort before use */ - qsort(rects, screens, sizeof(xcb_rectangle_t), rect_sort_cb); - - /* The width is consumed across all the screens */ - for (int i = 0; i < screens; i++) { - monitor_t *mon = monitor_new( - rects[i].x, - rects[i].y, - min(width, rects[i].width), - rects[i].height); - - monitor_add(mon); - - width -= rects[i].width; - - /* No need to check for other monitors */ - if (width <= 0) - break; - } - free(xqs_reply); + + monitor_create_chain(rects, screens); } void @@ -725,29 +722,55 @@ sighandle (int signal) exit(EXIT_SUCCESS); } -/* Parse an urxvt-like geometry string {width}x{height}, both the fields are - * optional. A width of -1 means that the bar spawns the whole screen. */ -void -parse_geometry_string (char *str) +/* Parse an X-styled geometry string, we don't support signed offsets tho. */ +bool +parse_geometry_string (char *str, int *tmp) { - char *p, *q; - int tmp; + char *p = str; + int i = 0, j; - if (!str) - return; + if (!str || !str[0]) + return false; - p = str; + /* The leading = is optional */ + if (*p == '=') + p++; - tmp = strtoul(p, &q, 10); - if (p != q) - bw = tmp; + while (*p) { + /* A geometry string has only 4 fields */ + if (i >= 4) { + fprintf(stderr, "Invalid geometry specified\n"); + return false; + } + /* Move on if we encounter a 'x' or '+' */ + if (*p == 'x') { + if (i > 0) /* The 'x' must precede '+' */ + break; + i++; p++; continue; + } + if (*p == '+') { + if (i < 1) /* Stray '+', skip the first two fields */ + i = 2; + else + i++; + p++; continue; + } + /* A digit must follow */ + if (!isdigit(*p)) { + fprintf(stderr, "Invalid geometry specified\n"); + return false; + } + /* Try to parse the number */ + errno = 0; + j = strtoul(p, &p, 10); + if (errno) { + fprintf(stderr, "Invalid geometry specified\n"); + return false; + } + tmp[i] = j; + } - /* P now might point to a NULL char, strtoul takes care of that */ - p = q + 1; - - tmp = strtoul(p, &q, 10); - if (p != q) - bh = tmp; + return true; } void @@ -771,14 +794,15 @@ parse_font_list (char *str) int main (int argc, char **argv) { - char input[2048] = {0, }; struct pollfd pollin[2] = { { .fd = STDIN_FILENO, .events = POLLIN }, { .fd = -1 , .events = POLLIN }, }; xcb_generic_event_t *ev; xcb_expose_event_t *expose_ev; + char input[2048] = {0, }; bool permanent = false; + int geom_v[4] = { -1, -1, 0, 0 }; /* Install the parachute! */ atexit(cleanup); @@ -793,10 +817,10 @@ main (int argc, char **argv) dfgc = fgc = scr->white_pixel; char ch; - while ((ch = getopt(argc, argv, "hg:bdf:a:pB:F:")) != -1) { + while ((ch = getopt(argc, argv, "hg:bdf:a:pu:B:F:")) != -1) { switch (ch) { case 'h': - printf ("usage: %s [-h | -g | -b | -d | -f | -a | -p | -B | -F]\n" + printf ("usage: %s [-h | -g | -b | -d | -f | -a | -p | -u | -B | -F]\n" "\t-h Show this help\n" "\t-g Set the bar geometry {width}x{height})\n" "\t-b Put bar at the bottom of the screen\n" @@ -804,21 +828,34 @@ main (int argc, char **argv) "\t-f Bar font list, comma separated\n" "\t-a Set the bar alpha ranging from 0.0 to 1.0 (requires a compositor)\n" "\t-p Don't close after the data ends\n" + "\t-u Set the underline/overline height in pixels\n" "\t-B Set background color in #RRGGBB\n" "\t-F Set foreground color in #RRGGBB\n", argv[0]); exit (EXIT_SUCCESS); case 'a': ba = strtof(optarg, NULL); break; - case 'g': parse_geometry_string(optarg); break; + case 'g': (void)parse_geometry_string(optarg, geom_v); break; case 'p': permanent = true; break; case 'b': topbar = false; break; case 'd': dock = true; break; case 'f': parse_font_list(optarg); break; + case 'u': bu = strtoul(optarg, NULL, 10); break; case 'B': dbgc = bgc = parse_color(optarg, NULL, scr->black_pixel); break; case 'F': dfgc = fgc = parse_color(optarg, NULL, scr->white_pixel); break; } } + /* Copy the geometry values in place */ + bw = geom_v[0]; + bh = geom_v[1]; + bx = geom_v[2]; + /* Sanitize the arguments */ + if (bx >= scr->width_in_pixels || bx + bw >= scr->width_in_pixels) { + bx = 0; + bw = -1; + } + if (bu >= bh) + bu = 1; if (ba > 1.0f) ba = 1.0f; if (ba < 0.0f) @@ -870,5 +907,5 @@ main (int argc, char **argv) xcb_flush(c); } - return 0; + return EXIT_SUCCESS; }