Robust geometry string parsing. Support for x offset. Underline/overline width is now configurable (fixes #43)
This commit is contained in:
parent
66e8b40be1
commit
b70edf4c4b
10
README.pod
10
README.pod
|
@ -4,7 +4,7 @@ bar - bar ain't recursive
|
|||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
I<bar> [-h | -g I<width>B<x>I<height> | -b | -d | -f I<font> | -a I<alpha>| -p | -B I<color> | -F I<color>]
|
||||
I<bar> [-h | -g I<width>B<x>I<height>B<+>I<x> | -b | -d | -f I<font> | -a I<alpha>| -p | -u I<pixel> | -B I<color> | -F I<color>]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
|
@ -18,9 +18,9 @@ B<bar> is a lightweight bar entirely based on XCB. Provides full UTF-8 support,
|
|||
|
||||
Display the help and exit.
|
||||
|
||||
=item B<-g> I<width>B<x>I<height>
|
||||
=item B<-g> I<width>B<x>I<height>B<+>I<x>
|
||||
|
||||
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<pixel>
|
||||
|
||||
Sets the underline width in pixels. The default is 1.
|
||||
|
||||
=item B<-B> I<color>
|
||||
|
||||
Set the background color of the bar. I<color> might be either in hex format (#rrggbb) or in the symbolic name format (eg. white, brightred, darkgray).
|
||||
|
|
177
bar.c
177
bar.c
|
@ -7,6 +7,7 @@
|
|||
#include <poll.h>
|
||||
#include <getopt.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xinerama.h>
|
||||
#include <xcb/randr.h>
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user