From 1efcc6100619b86e976b9e316e5b333c7b8e8e2f Mon Sep 17 00:00:00 2001 From: Jurica Vukadin Date: Mon, 13 Jan 2014 17:46:03 +0100 Subject: [PATCH] Add mouse support --- README.md | 1 + bar.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++-- config.def.h | 3 + 3 files changed, 154 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0414cbb..f7c304e 100644 --- a/README.md +++ b/README.md @@ -68,3 +68,4 @@ sp Switches to previous screen sr Switches to the rightmost screen (the latest) sl Switches to the leftmost screen (the first) ``` +Clickable areas can be defined with \\ab text \\ac command \\ae. diff --git a/bar.c b/bar.c index 3308e4b..c24452d 100644 --- a/bar.c +++ b/bar.c @@ -45,6 +45,17 @@ typedef struct screen_t { xcb_window_t window; } screen_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 xcb_connection_t *c; static xcb_drawable_t canvas; static xcb_gcontext_t draw_gc; @@ -59,11 +70,13 @@ static fontset_item_t *sel_font = NULL; static screen_t *screens; static int num_screens; static const unsigned 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; #if XINERAMA -static const char *control_characters = "fbulcsr"; +static const char *control_characters = "afbulcsr"; #else -static const char *control_characters = "fbulcr"; +static const char *control_characters = "afbulcr"; #endif static inline void @@ -100,6 +113,19 @@ xcb_set_fontset (int i) } } +static inline void +xcb_handle_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; + } +} + int draw_char (screen_t *screen, int x, int align, wchar_t ch) { @@ -143,6 +169,84 @@ draw_char (screen_t *screen, int x, int align, wchar_t ch) return ch_width; } +static void +cmd_area_begin (screen_t *screen, 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; + break; + case ALIGN_C: + area->begin = screen->width / 2 + x / 2; + break; + case ALIGN_R: + area->begin = screen->width; + 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; + } +} + +static void +cmd_area_end (screen_t *screen, int x, int align) +{ + cmd_area_t *area = cmd_area_list_tail; + area->end_x = x; + + switch (align) { + case ALIGN_L: + area->end = x; + break; + case ALIGN_C: + area->begin -= (x - area->begin_x) / 2; + area->end = screen->width / 2 + x / 2; + /* + * 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 = screen->width; + /* + * 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) { @@ -150,6 +254,7 @@ parse (char *text) int pos_x = 0; int align = 0; + char *cmd_start = 0; screen_t *screen = &screens[0]; xcb_fill_rect (clear_gc, 0, 0, bar_width, BAR_HEIGHT); @@ -215,6 +320,26 @@ parse (char *text) align = ALIGN_R; pos_x = 0; break; + case 'a': + switch (*p) { + case 'b': + cmd_area_begin (screen, pos_x, align); + break; + case 'c': + if (p++) + cmd_start = p; + while (p++ && *p != '\0' && *p != '\n' && *p != '\\') + ; + continue; + case 'e': + cmd_area_end (screen, 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 */ wchar_t t; @@ -356,7 +481,7 @@ set_ewmh_atoms () xcb_window_t create_window(xcb_window_t root, int x, int y, int width, int height, xcb_visualid_t visual) { xcb_window_t window = xcb_generate_id(c); - xcb_create_window(c, XCB_COPY_FROM_PARENT, window, root, x, y, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visual, XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, (const uint32_t []){ palette[10], XCB_EVENT_MASK_EXPOSURE }); + xcb_create_window(c, XCB_COPY_FROM_PARENT, window, root, x, y, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visual, XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK, (const uint32_t []){ palette[10], XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_RELEASE }); xcb_change_window_attributes (c, window, XCB_CW_OVERRIDE_REDIRECT, (const uint32_t []){ force_docking }); @@ -485,6 +610,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) { @@ -509,6 +645,8 @@ cleanup (void) xcb_free_gc (c, underl_gc); if (c) xcb_disconnect (c); + + clear_cmd_area_list(); } void @@ -529,6 +667,7 @@ main (int argc, char **argv) xcb_generic_event_t *ev; xcb_expose_event_t *expose_ev; + xcb_button_release_event_t *button_ev; int permanent = 0; @@ -568,17 +707,22 @@ main (int argc, char **argv) } if (pollin[0].revents & POLLIN) { /* New input, process it */ fgets (input, sizeof(input), stdin); + 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) { - case XCB_EXPOSE: + 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_event (button_ev->event_x); } free (ev); diff --git a/config.def.h b/config.def.h index b2570bb..95dc993 100644 --- a/config.def.h +++ b/config.def.h @@ -29,3 +29,6 @@ #define COLOR8 0x425059 #define COLOR9 0xcc6666 #define FOREGROUND 0xc5c8c6 + +/* Mouse button to react to */ +#define MOUSE_BUTTON 1