Give bar control over input generating command.
When the bar is getting input from a loop with a pause, there can be a noticable delay to visually updating the bar on click events. By letting bar call an input command it can now update instantly on a click event and still have a delay so it's not an idle hog. Something like: while true; do date; sleep 10; done | bar -d Now becomes: bar -d -c "date" -t 10 Either option may be ommited and the bar will still perform as before. If a command (-c) is given but not a timeout (-t) then the timeout defaults to 5 seconds. Changed compiler standard to gnu99 for use with popen()/pclose()
This commit is contained in:
parent
40f08d5245
commit
6ce01bb31c
2
Makefile
2
Makefile
|
@ -7,7 +7,7 @@ ifneq "$(GIT_DESC)" ""
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
CFLAGS += -Wall -std=c99 -Os -DVERSION="\"$(VERSION)\""
|
CFLAGS += -Wall -std=gnu99 -Os -DVERSION="\"$(VERSION)\""
|
||||||
LDFLAGS += -lxcb -lxcb-xinerama -lxcb-randr
|
LDFLAGS += -lxcb -lxcb-xinerama -lxcb-randr
|
||||||
CFDEBUG = -g3 -pedantic -Wall -Wunused-parameter -Wlong-long \
|
CFDEBUG = -g3 -pedantic -Wall -Wunused-parameter -Wlong-long \
|
||||||
-Wsign-conversion -Wconversion -Wimplicit-function-declaration
|
-Wsign-conversion -Wconversion -Wimplicit-function-declaration
|
||||||
|
|
71
lemonbar.c
71
lemonbar.c
|
@ -81,6 +81,7 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAX_FONT_COUNT 5
|
#define MAX_FONT_COUNT 5
|
||||||
|
#define INPUT_SIZE 4024
|
||||||
|
|
||||||
static xcb_connection_t *c;
|
static xcb_connection_t *c;
|
||||||
static xcb_screen_t *scr;
|
static xcb_screen_t *scr;
|
||||||
|
@ -100,6 +101,29 @@ static rgba_t fgc, bgc, ugc;
|
||||||
static rgba_t dfgc, dbgc, dugc;
|
static rgba_t dfgc, dbgc, dugc;
|
||||||
static area_stack_t area_stack;
|
static area_stack_t area_stack;
|
||||||
|
|
||||||
|
int
|
||||||
|
generate_input(const char * command, char * input, size_t input_size)
|
||||||
|
{
|
||||||
|
FILE * command_output;
|
||||||
|
|
||||||
|
if ((command_output = popen(command, "r")) == NULL) {
|
||||||
|
fprintf(stderr, "Could not run provided command\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fgets(input, input_size, command_output) == NULL) {
|
||||||
|
fprintf(stderr, "Command did not produce any output\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pclose(command_output) == -1) {
|
||||||
|
fprintf(stderr, "Could not close pipe to command\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
update_gc (void)
|
update_gc (void)
|
||||||
{
|
{
|
||||||
|
@ -1188,13 +1212,13 @@ init (char *wm_name)
|
||||||
|
|
||||||
// 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, (const uint32_t []){ fgc.v });
|
xcb_create_gc(c, gc[GC_DRAW], monhead->pixmap, XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES, (const uint32_t []){ fgc.v, 0 });
|
||||||
|
|
||||||
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.v });
|
xcb_create_gc(c, gc[GC_CLEAR], monhead->pixmap, XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES, (const uint32_t []){ bgc.v, 0 });
|
||||||
|
|
||||||
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.v });
|
xcb_create_gc(c, gc[GC_ATTR], monhead->pixmap, XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES, (const uint32_t []){ ugc.v, 0 });
|
||||||
|
|
||||||
// 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) {
|
||||||
|
@ -1261,12 +1285,15 @@ main (int argc, char **argv)
|
||||||
xcb_generic_event_t *ev;
|
xcb_generic_event_t *ev;
|
||||||
xcb_expose_event_t *expose_ev;
|
xcb_expose_event_t *expose_ev;
|
||||||
xcb_button_press_event_t *press_ev;
|
xcb_button_press_event_t *press_ev;
|
||||||
char input[4096] = {0, };
|
char input[INPUT_SIZE] = {0, };
|
||||||
bool permanent = false;
|
bool permanent = false;
|
||||||
int geom_v[4] = { -1, -1, 0, 0 };
|
int geom_v[4] = { -1, -1, 0, 0 };
|
||||||
int ch, areas;
|
int ch, areas;
|
||||||
char *wm_name;
|
char *wm_name;
|
||||||
|
|
||||||
|
char *input_command = NULL;
|
||||||
|
int input_timeout = -1;
|
||||||
|
|
||||||
// Install the parachute!
|
// Install the parachute!
|
||||||
atexit(cleanup);
|
atexit(cleanup);
|
||||||
signal(SIGINT, sighandle);
|
signal(SIGINT, sighandle);
|
||||||
|
@ -1284,7 +1311,7 @@ main (int argc, char **argv)
|
||||||
// Connect to the Xserver and initialize scr
|
// Connect to the Xserver and initialize scr
|
||||||
xconn();
|
xconn();
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "hg:bdf:a:pu:B:F:U:n:")) != -1) {
|
while ((ch = getopt(argc, argv, "hg:bdf:a:pu:B:F:U:n:c:t:")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'h':
|
case 'h':
|
||||||
printf ("lemonbar version %s\n", VERSION);
|
printf ("lemonbar version %s\n", VERSION);
|
||||||
|
@ -1299,7 +1326,9 @@ main (int argc, char **argv)
|
||||||
"\t-n Set the WM_NAME atom to the specified value for this bar\n"
|
"\t-n Set the WM_NAME atom to the specified value for this bar\n"
|
||||||
"\t-u Set the underline/overline height in pixels\n"
|
"\t-u Set the underline/overline height in pixels\n"
|
||||||
"\t-B Set background color in #AARRGGBB\n"
|
"\t-B Set background color in #AARRGGBB\n"
|
||||||
"\t-F Set foreground color in #AARRGGBB\n", argv[0]);
|
"\t-F Set foreground color in #AARRGGBB\n"
|
||||||
|
"\t-c Command to execute instead of reading from stdin\n"
|
||||||
|
"\t-t Timeout (sec) to wait between updating with the command\n", argv[0]);
|
||||||
exit (EXIT_SUCCESS);
|
exit (EXIT_SUCCESS);
|
||||||
case 'g': (void)parse_geometry_string(optarg, geom_v); break;
|
case 'g': (void)parse_geometry_string(optarg, geom_v); break;
|
||||||
case 'p': permanent = true; break;
|
case 'p': permanent = true; break;
|
||||||
|
@ -1312,9 +1341,21 @@ main (int argc, char **argv)
|
||||||
case 'F': dfgc = fgc = parse_color(optarg, NULL, (rgba_t)0xffffffffU); break;
|
case 'F': dfgc = fgc = parse_color(optarg, NULL, (rgba_t)0xffffffffU); break;
|
||||||
case 'U': dugc = ugc = parse_color(optarg, NULL, fgc); break;
|
case 'U': dugc = ugc = parse_color(optarg, NULL, fgc); break;
|
||||||
case 'a': areas = strtoul(optarg, NULL, 10); break;
|
case 'a': areas = strtoul(optarg, NULL, 10); break;
|
||||||
|
case 'c': input_command = optarg; break;
|
||||||
|
case 't': input_timeout = strtol(optarg, NULL, 10) * 1000; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't wait for input if there is a command, but no user defined timeout
|
||||||
|
if (input_command != NULL && input_timeout < 1) {
|
||||||
|
input_timeout = 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revert to normal usage if there is a timeout but no command
|
||||||
|
if (input_command == NULL && input_timeout >= 1) {
|
||||||
|
input_timeout = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the stack holding the clickable areas
|
// Initialize the stack holding the clickable areas
|
||||||
area_stack.at = 0;
|
area_stack.at = 0;
|
||||||
area_stack.max = areas;
|
area_stack.max = areas;
|
||||||
|
@ -1348,12 +1389,12 @@ main (int argc, char **argv)
|
||||||
if (xcb_connection_has_error(c))
|
if (xcb_connection_has_error(c))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (poll(pollin, 2, -1) > 0) {
|
if (poll(pollin, 2, input_timeout) > 0) {
|
||||||
if (pollin[0].revents & POLLHUP) { // No more data...
|
if (pollin[0].revents & POLLHUP) { // No more data...
|
||||||
if (permanent) pollin[0].fd = -1; // ...null the fd and continue polling :D
|
if (permanent) pollin[0].fd = -1; // ...null the fd and continue polling :D
|
||||||
else break; // ...bail out
|
else break; // ...bail out
|
||||||
}
|
}
|
||||||
if (pollin[0].revents & POLLIN) { // New input, process it
|
if (pollin[0].revents & POLLIN && input_command == NULL) { // New input, process it
|
||||||
if (fgets(input, sizeof(input), stdin) == NULL)
|
if (fgets(input, sizeof(input), stdin) == NULL)
|
||||||
break; // EOF received
|
break; // EOF received
|
||||||
|
|
||||||
|
@ -1370,6 +1411,9 @@ main (int argc, char **argv)
|
||||||
redraw = true;
|
redraw = true;
|
||||||
break;
|
break;
|
||||||
case XCB_BUTTON_PRESS:
|
case XCB_BUTTON_PRESS:
|
||||||
|
if (expose_ev->count == 0)
|
||||||
|
redraw = true;
|
||||||
|
|
||||||
press_ev = (xcb_button_press_event_t *)ev;
|
press_ev = (xcb_button_press_event_t *)ev;
|
||||||
{
|
{
|
||||||
area_t *area = area_get(press_ev->event, press_ev->detail, press_ev->event_x);
|
area_t *area = area_get(press_ev->event, press_ev->detail, press_ev->event_x);
|
||||||
|
@ -1387,6 +1431,17 @@ main (int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If there is a user supplied command, use it to generate input
|
||||||
|
if (input_command != NULL) {
|
||||||
|
if (generate_input(input_command, input, INPUT_SIZE) != 0) {
|
||||||
|
fprintf(stderr, "Failed to generate input from command\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(input);
|
||||||
|
redraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (redraw) { // Copy our temporary pixmap onto the window
|
if (redraw) { // Copy our temporary pixmap onto the window
|
||||||
for (monitor_t *mon = monhead; mon; mon = mon->next) {
|
for (monitor_t *mon = monhead; mon; mon = mon->next) {
|
||||||
xcb_copy_area(c, mon->pixmap, mon->window, gc[GC_DRAW], 0, 0, 0, 0, mon->width, bh);
|
xcb_copy_area(c, mon->pixmap, mon->window, gc[GC_DRAW], 0, 0, 0, 0, mon->width, bh);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user