Clickable areas! #38

This commit is contained in:
LemonBoy 2014-02-26 10:07:49 +00:00
parent 0e3ee04cb1
commit 3c0583a5fc
2 changed files with 81 additions and 38 deletions

View File

@ -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. Comma separated list of fonts, bar supports a maximum of two fonts.
=item B<-a> I<alpha>
Set the bar alpha in range 0.0 to 1.0. This requires a compositor manager such as Compton.
=item B<-p> =item B<-p>
Make bar permanent, don't exit after the standard input is closed. Make bar permanent, don't exit after the standard input is closed.
@ -90,6 +86,12 @@ Set the text foreground color. The parameter I<color> can be I<-> or a color in
Set the text underline color. The parameter I<color> can be I<-> or a color in one of the formats mentioned before. The special value I<-> resets the color to the default one. Set the text underline color. The parameter I<color> 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<A>:I<command>:
Create a clickable area starting from the current position, when the area is clicked I<command> is executed. The area is closed when a B<A> token, not followed by : is encountered.
Eg. I<%{A:reboot} Click here to reboot %{A}>
=item B<S>I<dir> =item B<S>I<dir>
Change the monitor bar is rendering to. I<dir> can be either Change the monitor bar is rendering to. I<dir> can be either
@ -155,3 +157,5 @@ L<git repository|https://github.com/LemonBoy/bar>
Xinerama support was kindly contributed by Stebalien Xinerama support was kindly contributed by Stebalien
RandR support was kindly contributed by jvvv RandR support was kindly contributed by jvvv
Clickable areas support was heavily based off u-ra contribution

101
bar.c
View File

@ -36,10 +36,18 @@ typedef struct monitor_t {
} monitor_t; } monitor_t;
typedef struct area_t { typedef struct area_t {
int start, end; int begin, end, align;
xcb_window_t window;
char *cmd; char *cmd;
} area_t; } area_t;
#define N 10
typedef struct area_stack_t {
int pos;
area_t slot[N];
} area_stack_t;
enum { enum {
ATTR_OVERL = (1<<0), ATTR_OVERL = (1<<0),
ATTR_UNDERL = (1<<1), ATTR_UNDERL = (1<<1),
@ -74,6 +82,7 @@ static int bu = 1; /* Underline height */
static char *mfont, *afont; static char *mfont, *afont;
static uint32_t fgc, bgc, ugc; static uint32_t fgc, bgc, ugc;
static uint32_t dfgc, dbgc; static uint32_t dfgc, dbgc;
static area_stack_t astack;
void void
update_gc (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: 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 / 2, 0,
mon->width / 2 - (x + ch_width) / 2, 0, x, bh); 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; 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, 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_t *
area_get (int x) area_get (xcb_window_t win, const int x)
{ {
for (int i = 0; i < area_stack_i; i++) for (int i = 0; i < astack.pos; i++)
if (x >= area_stack[i].start && x <= area_stack[i].end) if (astack.slot[i].window == win && x > astack.slot[i].begin && x < astack.slot[i].end)
return &area_stack[i]; return &astack.slot[i];
return NULL; 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 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; char *p = str;
area_t *a = &area_stack[area_stack_i]; area_t *a = &astack.slot[astack.pos];
if (astack.pos == N) {
fprintf(stderr, "astack overflow!\n");
return false;
}
/* A wild close area tag appeared! */
if (*p != ':') {
*end = p;
/* Basic safety checks */
if (!a->cmd || a->align != align || a->window != mon->window)
return false;
const int size = x - a->begin;
if (*p != ':' && area_stack_i < 10) {
switch (align) { switch (align) {
case ALIGN_L: a->end = x; break;
case ALIGN_R: a->start = mon->width - x; break;
case ALIGN_C: case ALIGN_C:
a->start = mon->width / 2 - (x / 2); a->begin = mon->width / 2 - size / 2 + a->begin / 2;
a->end = mon->width / 2 + (x / 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; break;
} }
*end = p; astack.pos++;
if (a->start < a->end) {
printf("(%s) (%i to %i)\n", a->cmd, a->start, a->end);
area_stack_i++;
return true; return true;
} }
return false;
}
char *trail = strchr(++p, ':'); 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; *end = p;
return false; return false;
} }
*trail = '\0'; *trail = '\0';
/* This is a pointer to the string buffer allocated in the main */
a->cmd = p; a->cmd = p;
a->align = align;
switch (align) { a->begin = x;
case ALIGN_L: a->start = x; break; a->window = mon->window;
case ALIGN_R: a->end = scr->width_in_pixels - x; break;
}
*end = trail + 1; *end = trail + 1;
return true; return true;
} }
@ -265,7 +301,7 @@ parse (char *text)
cur_font = main_font; cur_font = main_font;
cur_mon = monhead; 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); 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 }); 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; monitor_t *ret;
ret = malloc(sizeof(monitor_t)); ret = calloc(1, sizeof(monitor_t));
if (!ret) { if (!ret) {
fprintf(stderr, "Failed to allocate new monitor\n"); fprintf(stderr, "Failed to allocate new monitor\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
@ -1000,7 +1039,7 @@ main (int argc, char **argv)
press_ev = (xcb_button_press_event_t *)ev; press_ev = (xcb_button_press_event_t *)ev;
if (press_ev->detail == XCB_BUTTON_INDEX_1) { 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); if (a) system(a->cmd);
} }
break; break;