From 372c5bf8dc3eb5071d66eb3f122b951204923a4b Mon Sep 17 00:00:00 2001 From: Jurica Vukadin Date: Fri, 14 Feb 2014 12:51:07 +0100 Subject: [PATCH] Add mouse support --- README.md | 10 ++++ bar.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++++-- config.def.h | 3 + 3 files changed, 163 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0414cbb..45c6ee9 100644 --- a/README.md +++ b/README.md @@ -68,3 +68,13 @@ sp Switches to previous screen sr Switches to the rightmost screen (the latest) sl Switches to the leftmost screen (the first) ``` + +Mouse support +------------- +You can have any number of clickable areas defined. + +``` +ab Begins a new clickable area +ac The command to execute when clicked +ae Ends the current clickable area +``` diff --git a/bar.c b/bar.c index bf94dd7..fdf5ec4 100644 --- a/bar.c +++ b/bar.c @@ -34,6 +34,17 @@ typedef struct monitor_t { struct monitor_t *prev, *next; } monitor_t; +typedef struct cmd_area_t { + struct cmd_area_t *next; + struct cmd_area_t *prev; + char *cmd; + int begin; + int end; + int begin_x; + int end_x; + int align; +} cmd_area_t; + static struct config_t { int place_bottom; int force_docking; @@ -66,6 +77,9 @@ static const uint32_t palette[] = { COLOR0,COLOR1,COLOR2,COLOR3,COLOR4,COLOR5,COLOR6,COLOR7,COLOR8,COLOR9,BACKGROUND,FOREGROUND }; +static cmd_area_t *cmd_area_list_head; +static cmd_area_t *cmd_area_list_tail; + void set_bg (int i) { @@ -130,10 +144,102 @@ draw_char (monitor_t *mon, font_t *cur_font, int x, int align, int underline, ui return ch_width; } +void +xcb_handle_mouse_event (int16_t x) +{ + cmd_area_t *area = cmd_area_list_head; + while (area) { + if (area->begin <=x && area->end >= x) { + system (area->cmd); + return; + } + area = area->next; + } +} + +void +cmd_area_begin (monitor_t *mon, int x, int align) +{ + cmd_area_t *area = calloc (1, sizeof (*area)); + + area->align = align; + area->begin_x = x; + + switch (align) { + case ALIGN_L: + area->begin = x + mon->x; + break; + case ALIGN_C: + area->begin = mon->width / 2 + x / 2 + mon->x; + break; + case ALIGN_R: + area->begin = mon->width + mon->x; + break; + } + + if (!cmd_area_list_head) { + cmd_area_list_head = area; + cmd_area_list_tail = area; + } + else { + cmd_area_list_tail->next = area; + area->prev = cmd_area_list_tail; + cmd_area_list_tail = area; + } +} + +void +cmd_area_end (monitor_t *mon, int x, int align) +{ + cmd_area_t *area = cmd_area_list_tail; + area->end_x = x; + + switch (align) { + case ALIGN_L: + area->end = x + mon->x; + break; + case ALIGN_C: + area->begin -= (x - area->begin_x) / 2; + area->end = mon->width / 2 + x / 2 + mon->x; + /* + * if there were any other center aligned areas + * before this one, adjust their position + */ + cmd_area_t *a = area->prev; + if (a && a->align == ALIGN_C) { + int diff = (area->begin_x - a->end_x + area->end - area->begin) / 2; + while (a && a->align == ALIGN_C) { + a->begin -= diff; + a->end -= diff; + a = a->prev; + } + } + break; + case ALIGN_R: + area->begin -= (x - area->begin_x); + area->end = mon->width + mon->x; + /* + * if there were any other right aligned areas + * before this one, adjust their position + */ + a = area->prev; + if (a && a->align == ALIGN_R) { + int diff = area->begin_x - a->end_x + area->end - area->begin; + while (a && a->align == ALIGN_R) { + a->begin -= diff; + a->end -= diff; + a = a->prev; + } + } + break; + } +} + void parse (char *text) { char *p = text; + char *cmd_start = 0; int pos_x = 0; int align = 0; @@ -151,7 +257,7 @@ parse (char *text) if (*p == '\0' || *p == '\n') return; - if (*p == '^' && p++ && *p != '^' && strchr ("_-fbulcrs", *p)) { + if (*p == '^' && p++ && *p != '^' && strchr ("_-afbulcrs", *p)) { switch (*p++) { case 'f': set_fg (isdigit(*p) ? *p-'0' : 11); @@ -214,6 +320,25 @@ parse (char *text) align = ALIGN_R; pos_x = 0; break; + case 'a': + switch (*p) { + case 'b': + cmd_area_begin (cur_mon, pos_x, align); + break; + case 'c': + cmd_start = ++p; + while (*p != '\0' && *p != '\n' && *p != '^') + p++; + continue; + case 'e': + cmd_area_end (cur_mon, pos_x, align); + size_t cmd_len = (size_t)(p - cmd_start) - 2; + cmd_area_list_tail->cmd = calloc (cmd_len + 1, sizeof(char)); + strncpy (cmd_area_list_tail->cmd, cmd_start, cmd_len); + break; + } + p++; + break; } } else { /* utf-8 -> ucs-2 */ uint8_t *utf = (uint8_t *)p; @@ -369,7 +494,8 @@ monitor_new (int x, int y, int width, int height) x, win_y, width, cfg.height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, scr->root_visual, XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, - (const uint32_t []){ palette[10], XCB_EVENT_MASK_EXPOSURE }); + (const uint32_t []){ palette[10], XCB_EVENT_MASK_EXPOSURE + | XCB_EVENT_MASK_BUTTON_RELEASE }); xcb_change_window_attributes (c, ret->window, XCB_CW_OVERRIDE_REDIRECT, (const uint32_t []){ cfg.force_docking }); @@ -621,6 +747,17 @@ init (void) xcb_flush (c); } +static void +clear_cmd_area_list (void) +{ + while (cmd_area_list_head) { + cmd_area_t *area = cmd_area_list_head; + cmd_area_list_head = cmd_area_list_head->next; + free (area->cmd); + free (area); + } +} + void cleanup (void) { @@ -650,6 +787,8 @@ cleanup (void) xcb_free_gc (c, underl_gc); if (c) xcb_disconnect (c); + + clear_cmd_area_list(); } void @@ -705,7 +844,7 @@ parse_font_list (char *str) int main (int argc, char **argv) { - char input[1024] = {0, }; + char input[2048] = {0, }; struct pollfd pollin[2] = { { .fd = STDIN_FILENO, .events = POLLIN }, { .fd = -1 , .events = POLLIN }, @@ -713,6 +852,7 @@ main (int argc, char **argv) xcb_generic_event_t *ev; xcb_expose_event_t *expose_ev; + xcb_button_release_event_t *button_ev; char ch; while ((ch = getopt (argc, argv, "hg:bdf:a:o:p")) != -1) { @@ -764,17 +904,22 @@ main (int argc, char **argv) if (fgets (input, sizeof(input), stdin) == NULL) break; /* EOF received */ + clear_cmd_area_list(); parse (input); redraw = 1; } if (pollin[1].revents & POLLIN) { /* Xserver broadcasted an event */ while ((ev = xcb_poll_for_event (c))) { - expose_ev = (xcb_expose_event_t *)ev; - switch (ev->response_type & 0x7F) { + switch (ev->response_type & ~0x80) { case XCB_EXPOSE: + expose_ev = (xcb_expose_event_t *)ev; if (expose_ev->count == 0) redraw = 1; break; + case XCB_BUTTON_RELEASE: + button_ev = (xcb_button_release_event_t *)ev; + if (button_ev->detail == MOUSE_BUTTON) + xcb_handle_mouse_event (button_ev->root_x); } free (ev); diff --git a/config.def.h b/config.def.h index b3edf4d..379b792 100644 --- a/config.def.h +++ b/config.def.h @@ -13,3 +13,6 @@ #define COLOR8 0x425059 #define COLOR9 0xcc6666 #define FOREGROUND 0xc5c8c6 + +/* Mouse button to react to */ +#define MOUSE_BUTTON 1