From 0e3ee04cb1a9110077f9084ac29ce9b645ecde0d Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 24 Feb 2014 12:46:46 +0000 Subject: [PATCH 1/5] ababcc --- bar.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/bar.c b/bar.c index 5d17968..aa05042 100644 --- a/bar.c +++ b/bar.c @@ -35,6 +35,11 @@ typedef struct monitor_t { struct monitor_t *prev, *next; } monitor_t; +typedef struct area_t { + int start, end; + char *cmd; +} area_t; + enum { ATTR_OVERL = (1<<0), ATTR_UNDERL = (1<<1), @@ -187,6 +192,64 @@ set_attribute (const char modifier, const char attribute) } } +area_t area_stack[10]; +int area_stack_i = 0; + +area_t * +area_get (int x) +{ + for (int i = 0; i < area_stack_i; i++) + if (x >= area_stack[i].start && x <= area_stack[i].end) + return &area_stack[i]; + return NULL; +} + +bool +area_add (char *str, char *optend, char **end, monitor_t *mon, const int x, const int align) +{ + char *p = str; + area_t *a = &area_stack[area_stack_i]; + + if (*p != ':' && area_stack_i < 10) { + switch (align) { + case ALIGN_L: a->end = x; break; + case ALIGN_R: a->start = mon->width - x; break; + case ALIGN_C: + a->start = mon->width / 2 - (x / 2); + a->end = mon->width / 2 + (x / 2); + break; + } + + *end = p; + + if (a->start < a->end) { + printf("(%s) (%i to %i)\n", a->cmd, a->start, a->end); + area_stack_i++; + return true; + } + return false; + } + + char *trail = strchr(++p, ':'); + + if (!trail || trail > optend) { + *end = p; + return false; + } + + *trail = '\0'; + + a->cmd = p; + + switch (align) { + case ALIGN_L: a->start = x; break; + case ALIGN_R: a->end = scr->width_in_pixels - x; break; + } + + *end = trail + 1; + return true; +} + void parse (char *text) { @@ -202,6 +265,8 @@ parse (char *text) cur_font = main_font; cur_mon = monhead; + area_stack_i = 0; + fill_rect(cur_mon->pixmap, gc[GC_CLEAR], 0, 0, bw, bh); for (;;) { @@ -229,6 +294,10 @@ parse (char *text) case 'c': pos_x = 0; align = ALIGN_C; break; case 'r': pos_x = 0; align = ALIGN_R; break; + case 'A': + area_add(p, end, &p, cur_mon, pos_x, align); + break; + case 'B': bgc = parse_color(p, &p, dbgc); update_gc(); break; case 'F': fgc = parse_color(p, &p, dfgc); update_gc(); break; case 'U': ugc = parse_color(p, &p, dbgc); update_gc(); break; @@ -414,7 +483,7 @@ monitor_new (int x, int y, int width, int height) x, win_y, width, bh, 0, 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, - (const uint32_t []){ bgc, bgc, dock, XCB_EVENT_MASK_EXPOSURE, colormap }); + (const uint32_t []){ bgc, bgc, dock, XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS, colormap }); ret->pixmap = xcb_generate_id(c); xcb_create_pixmap(c, depth, ret->pixmap, ret->window, width, bh); @@ -842,6 +911,7 @@ main (int argc, char **argv) }; xcb_generic_event_t *ev; xcb_expose_event_t *expose_ev; + xcb_button_press_event_t *press_ev; char input[2048] = {0, }; bool permanent = false; int geom_v[4] = { -1, -1, 0, 0 }; @@ -902,6 +972,8 @@ main (int argc, char **argv) /* Get the fd to Xserver */ pollin[1].fd = xcb_get_file_descriptor(c); + area_t *a; + for (;;) { bool redraw = false; @@ -924,6 +996,13 @@ main (int argc, char **argv) switch (ev->response_type & 0x7F) { case XCB_EXPOSE: if (expose_ev->count == 0) redraw = true; + case XCB_BUTTON_PRESS: + press_ev = (xcb_button_press_event_t *)ev; + + if (press_ev->detail == XCB_BUTTON_INDEX_1) { + a = area_get(press_ev->event_x); + if (a) system(a->cmd); + } break; } From 3c0583a5fca335d0be6cea9baf867f38f2745f75 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 26 Feb 2014 10:07:49 +0000 Subject: [PATCH 2/5] Clickable areas! #38 --- README.pod | 12 ++++-- bar.c | 107 ++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 81 insertions(+), 38 deletions(-) diff --git a/README.pod b/README.pod index 412e0bd..a7000c0 100644 --- a/README.pod +++ b/README.pod @@ -34,10 +34,6 @@ Force docking without asking the window manager. This is needed if the window ma Comma separated list of fonts, bar supports a maximum of two fonts. -=item B<-a> I - -Set the bar alpha in range 0.0 to 1.0. This requires a compositor manager such as Compton. - =item B<-p> Make bar permanent, don't exit after the standard input is closed. @@ -90,6 +86,12 @@ Set the text foreground color. The parameter I can be I<-> or a color in Set the text underline color. The parameter I can be I<-> or a color in one of the formats mentioned before. The special value I<-> resets the color to the default one. +=item B:I: + +Create a clickable area starting from the current position, when the area is clicked I is executed. The area is closed when a B token, not followed by : is encountered. + +Eg. I<%{A:reboot} Click here to reboot %{A}> + =item BI Change the monitor bar is rendering to. I can be either @@ -155,3 +157,5 @@ L Xinerama support was kindly contributed by Stebalien RandR support was kindly contributed by jvvv + +Clickable areas support was heavily based off u-ra contribution diff --git a/bar.c b/bar.c index aa05042..76282c9 100644 --- a/bar.c +++ b/bar.c @@ -36,10 +36,18 @@ typedef struct monitor_t { } monitor_t; typedef struct area_t { - int start, end; + int begin, end, align; + xcb_window_t window; char *cmd; } area_t; +#define N 10 + +typedef struct area_stack_t { + int pos; + area_t slot[N]; +} area_stack_t; + enum { ATTR_OVERL = (1<<0), ATTR_UNDERL = (1<<1), @@ -74,6 +82,7 @@ static int bu = 1; /* Underline height */ static char *mfont, *afont; static uint32_t fgc, bgc, ugc; static uint32_t dfgc, dbgc; +static area_stack_t astack; void update_gc (void) @@ -102,7 +111,7 @@ draw_char (monitor_t *mon, font_t *cur_font, int x, int align, uint16_t ch) case ALIGN_C: xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW], 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 - ch_width / 2 + x / 2; break; case ALIGN_R: xcb_copy_area(c, mon->pixmap, mon->pixmap, gc[GC_DRAW], mon->width - x, 0, @@ -192,61 +201,88 @@ set_attribute (const char modifier, const char attribute) } } -area_t area_stack[10]; -int area_stack_i = 0; area_t * -area_get (int x) +area_get (xcb_window_t win, const int x) { - for (int i = 0; i < area_stack_i; i++) - if (x >= area_stack[i].start && x <= area_stack[i].end) - return &area_stack[i]; + for (int i = 0; i < astack.pos; i++) + if (astack.slot[i].window == win && x > astack.slot[i].begin && x < astack.slot[i].end) + return &astack.slot[i]; return NULL; } +void +area_shift (xcb_window_t win, const int align, int delta) +{ + if (align == ALIGN_L) + return; + if (align == ALIGN_C) + delta /= 2; + + for (int i = 0; i < astack.pos; i++) { + if (astack.slot[i].window == win && astack.slot[i].align == align) { + astack.slot[i].begin -= delta; + astack.slot[i].end -= delta; + } + } +} + bool -area_add (char *str, char *optend, char **end, monitor_t *mon, const int x, const int align) +area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x, const int align) { char *p = str; - area_t *a = &area_stack[area_stack_i]; + area_t *a = &astack.slot[astack.pos]; - if (*p != ':' && area_stack_i < 10) { - switch (align) { - case ALIGN_L: a->end = x; break; - case ALIGN_R: a->start = mon->width - x; break; - case ALIGN_C: - a->start = mon->width / 2 - (x / 2); - a->end = mon->width / 2 + (x / 2); - break; - } + if (astack.pos == N) { + fprintf(stderr, "astack overflow!\n"); + return false; + } + /* A wild close area tag appeared! */ + if (*p != ':') { *end = p; - if (a->start < a->end) { - printf("(%s) (%i to %i)\n", a->cmd, a->start, a->end); - area_stack_i++; - return true; + /* Basic safety checks */ + if (!a->cmd || a->align != align || a->window != mon->window) + return false; + + const int size = x - a->begin; + + switch (align) { + case ALIGN_C: + a->begin = mon->width / 2 - size / 2 + a->begin / 2; + a->end = a->begin + size; + break; + case ALIGN_R: + /* The newest is the rightmost one */ + a->begin = mon->width - size; + a->end = mon->width; + break; } - return false; + + astack.pos++; + + return true; } char *trail = strchr(++p, ':'); - if (!trail || trail > optend) { + /* Find the trailing : and make sure it's whitin the formatting block, also reject empty commands */ + if (!trail || p == trail || trail > optend) { *end = p; return false; } *trail = '\0'; + /* This is a pointer to the string buffer allocated in the main */ a->cmd = p; - - switch (align) { - case ALIGN_L: a->start = x; break; - case ALIGN_R: a->end = scr->width_in_pixels - x; break; - } + a->align = align; + a->begin = x; + a->window = mon->window; *end = trail + 1; + return true; } @@ -265,7 +301,7 @@ parse (char *text) cur_font = main_font; cur_mon = monhead; - area_stack_i = 0; + memset(&astack, 0, sizeof(area_stack_t)); fill_rect(cur_mon->pixmap, gc[GC_CLEAR], 0, 0, bw, bh); @@ -357,7 +393,10 @@ parse (char *text) xcb_change_gc(c, gc[GC_DRAW] , XCB_GC_FONT, (const uint32_t []){ cur_font->ptr }); - pos_x += draw_char(cur_mon, cur_font, pos_x, align, ucs); + int w = draw_char(cur_mon, cur_font, pos_x, align, ucs); + + pos_x += w; + area_shift(cur_mon->window, align, w); } } } @@ -465,7 +504,7 @@ monitor_new (int x, int y, int width, int height) { monitor_t *ret; - ret = malloc(sizeof(monitor_t)); + ret = calloc(1, sizeof(monitor_t)); if (!ret) { fprintf(stderr, "Failed to allocate new monitor\n"); exit(EXIT_FAILURE); @@ -1000,7 +1039,7 @@ main (int argc, char **argv) press_ev = (xcb_button_press_event_t *)ev; if (press_ev->detail == XCB_BUTTON_INDEX_1) { - a = area_get(press_ev->event_x); + a = area_get(press_ev->event, press_ev->event_x); if (a) system(a->cmd); } break; From 6977bb96d2495b7f2edfa28d1ceda2e5dd34d2a3 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 26 Feb 2014 12:02:33 +0000 Subject: [PATCH 3/5] Fixes and cleanup --- bar.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/bar.c b/bar.c index 76282c9..e6bd632 100644 --- a/bar.c +++ b/bar.c @@ -20,16 +20,14 @@ typedef struct font_t { xcb_font_t ptr; - uint32_t descent; - uint32_t height; + int descent, height; uint16_t char_max; uint16_t char_min; xcb_charinfo_t *width_lut; } font_t; typedef struct monitor_t { - uint32_t x; - uint32_t width; + int x, width; xcb_window_t window; xcb_pixmap_t pixmap; struct monitor_t *prev, *next; @@ -68,7 +66,6 @@ enum { static xcb_connection_t *c; static xcb_screen_t *scr; -static xcb_drawable_t canvas; static xcb_gcontext_t gc[GC_MAX]; static xcb_visualid_t visual; static xcb_colormap_t colormap; @@ -298,7 +295,6 @@ parse (char *text) pos_x = 0; align = ALIGN_L; - cur_font = main_font; cur_mon = monhead; memset(&astack, 0, sizeof(area_stack_t)); @@ -597,7 +593,6 @@ monitor_create_chain (xcb_rectangle_t *rects, const int num) void get_randr_monitors (void) { - xcb_generic_error_t *err; xcb_randr_get_screen_resources_current_reply_t *rres_reply; xcb_randr_output_t *outputs; int num, valid = 0; @@ -689,7 +684,7 @@ get_xinerama_monitors (void) { xcb_xinerama_query_screens_reply_t *xqs_reply; xcb_xinerama_screen_info_iterator_t iter; - int screens, width = bw; + int screens; xqs_reply = xcb_xinerama_query_screens_reply(c, xcb_xinerama_query_screens_unchecked(c), NULL); @@ -1011,8 +1006,6 @@ main (int argc, char **argv) /* Get the fd to Xserver */ pollin[1].fd = xcb_get_file_descriptor(c); - area_t *a; - for (;;) { bool redraw = false; @@ -1034,15 +1027,17 @@ main (int argc, char **argv) switch (ev->response_type & 0x7F) { case XCB_EXPOSE: - if (expose_ev->count == 0) redraw = true; + if (expose_ev->count == 0) + redraw = true; + break; case XCB_BUTTON_PRESS: press_ev = (xcb_button_press_event_t *)ev; - + /* Respond to left click */ if (press_ev->detail == XCB_BUTTON_INDEX_1) { - a = area_get(press_ev->event, press_ev->event_x); + area_t *a = area_get(press_ev->event, press_ev->event_x); if (a) system(a->cmd); } - break; + break; } free(ev); From 24c1da491fbcdb0a12b7cdc05a30bc4d2a63da94 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 26 Feb 2014 16:42:31 +0000 Subject: [PATCH 4/5] Handle left aligned areas --- bar.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bar.c b/bar.c index e6bd632..b9481d0 100644 --- a/bar.c +++ b/bar.c @@ -246,6 +246,9 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x const int size = x - a->begin; switch (align) { + case ALIGN_L: + a->end = x; + break; case ALIGN_C: a->begin = mon->width / 2 - size / 2 + a->begin / 2; a->end = a->begin + size; From 23c531078c72283eb815f87ef327cc751d98f837 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Wed, 26 Feb 2014 16:43:09 +0000 Subject: [PATCH 5/5] Fix a typo in the manpage --- README.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.pod b/README.pod index a7000c0..fc8d287 100644 --- a/README.pod +++ b/README.pod @@ -90,7 +90,7 @@ Set the text underline color. The parameter I can be I<-> or a color in o Create a clickable area starting from the current position, when the area is clicked I is executed. The area is closed when a B token, not followed by : is encountered. -Eg. I<%{A:reboot} Click here to reboot %{A}> +Eg. I<%{A:reboot:} Click here to reboot %{A}> =item BI