diff --git a/modules/i3/dynlist-exposable.c b/modules/i3/dynlist-exposable.c index 4f868e1..a68b2a0 100644 --- a/modules/i3/dynlist-exposable.c +++ b/modules/i3/dynlist-exposable.c @@ -2,6 +2,9 @@ #include +#define LOG_MODULE "dynlist" +#include "../../log.h" + struct private { int left_spacing; int right_spacing; @@ -11,6 +14,21 @@ struct private { int *widths; }; +static void +dynlist_destroy(struct exposable *exposable) +{ + struct private *e = exposable->private; + for (size_t i = 0; i < e->count; i++) { + struct exposable *ee = e->exposables[i]; + ee->destroy(ee); + } + + free(e->exposables); + free(e->widths); + free(e); + free(exposable); +} + static int dynlist_begin_expose(struct exposable *exposable, cairo_t *cr) { @@ -47,18 +65,32 @@ dynlist_expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int } static void -dynlist_destroy(struct exposable *exposable) +on_mouse(struct exposable *exposable, struct bar *bar, + enum mouse_event event, int x, int y) { - struct private *e = exposable->private; - for (size_t i = 0; i < e->count; i++) { - struct exposable *ee = e->exposables[i]; - ee->destroy(ee); + //const struct particle *p = exposable->particle; + const struct private *e = exposable->private; + + if (exposable->on_click != NULL) { + exposable_default_on_mouse(exposable, bar, event, x, y); + return; } - free(e->exposables); - free(e->widths); - free(e); - free(exposable); + int px = /*p->left_margin;*/0; + for (size_t i = 0; i < e->count; i++) { + if (x >= px && x < px + e->exposables[i]->width) { + if (e->exposables[i]->on_mouse != NULL) { + e->exposables[i]->on_mouse( + e->exposables[i], bar, event, x - px, y); + } + return; + } + + px += e->left_spacing + e->exposables[i]->width + e->right_spacing; + } + + LOG_DBG("on_mouse missed all sub-particles"); + exposable_default_on_mouse(exposable, bar, event, x, y); } struct exposable * @@ -75,11 +107,11 @@ dynlist_exposable_new(struct exposable **exposables, size_t count, for (size_t i = 0; i < count; i++) e->exposables[i] = exposables[i]; - struct exposable *exposable = malloc(sizeof(*exposable)); + struct exposable *exposable = exposable_common_new(NULL, NULL); exposable->private = e; - exposable->particle = NULL; exposable->destroy = &dynlist_destroy; exposable->begin_expose = &dynlist_begin_expose; exposable->expose = &dynlist_expose; + exposable->on_mouse = &on_mouse; return exposable; } diff --git a/particles/string.c b/particles/string.c index 276589d..fbe568a 100644 --- a/particles/string.c +++ b/particles/string.c @@ -77,90 +77,13 @@ expose(const struct exposable *exposable, cairo_t *cr, int x, int y, int height) } -struct sbuf { - char *s; - size_t size; - size_t len; -}; - -static void -sbuf_strncat(struct sbuf *s1, const char *s2, size_t n) -{ - size_t s2_actual_len = strlen(s2); - size_t s2_len = s2_actual_len < n ? s2_actual_len : n; - - if (s1->len + s2_len >= s1->size) { - size_t required_size = s1->len + s2_len + 1; - s1->size = 2 * required_size; - - s1->s = realloc(s1->s, s1->size); - s1->s[s1->len] = '\0'; - } - - strncat(s1->s, s2, s2_len); - s1->len += s2_len; -} - -static void -sbuf_strcat(struct sbuf *s1, const char *s2) -{ - sbuf_strncat(s1, s2, strlen(s2)); -} - static struct exposable * instantiate(const struct particle *particle, const struct tag_set *tags) { const struct private *p = particle->private; struct private *e = malloc(sizeof(*e)); - struct sbuf formatted = {0}; - const char *src = p->text; - - while (true) { - /* Find next tag opening '{' */ - const char *begin = strchr(src, '{'); - - if (begin == NULL) { - /* No more tags, copy remaining characters */ - sbuf_strcat(&formatted, src); - break; - } - - /* Find closing '}' */ - const char *end = strchr(begin, '}'); - if (end == NULL) { - /* Wasn't actually a tag, copy as-is instead */ - sbuf_strncat(&formatted, src, begin - src + 1); - src = begin + 1; - continue; - } - - /* Extract tag name */ - char tag_name[end - begin]; - strncpy(tag_name, begin + 1, end - begin - 1); - tag_name[end - begin - 1] = '\0'; - - /* Lookup tag */ - const struct tag *tag = tag_for_name(tags, tag_name); - if (tag == NULL) { - /* No such tag, copy as-is instead */ - sbuf_strncat(&formatted, src, begin - src + 1); - src = begin + 1; - continue; - } - - /* Copy characters preceeding the tag (name) */ - sbuf_strncat(&formatted, src, begin - src); - - /* Copy tag value */ - const char *value = tag->as_string(tag); - sbuf_strcat(&formatted, value); - - /* Skip past tag name + closing '}' */ - src = end + 1; - } - - e->text = formatted.s; + e->text = tags_expand_template(p->text, tags); e->font = p->font; e->foreground = p->foreground; diff --git a/tag.c b/tag.c index 70dbdcf..80fd00c 100644 --- a/tag.c +++ b/tag.c @@ -365,3 +365,85 @@ tag_set_destroy(struct tag_set *set) set->tags = NULL; set->count = 0; } + +struct sbuf { + char *s; + size_t size; + size_t len; +}; + +static void +sbuf_strncat(struct sbuf *s1, const char *s2, size_t n) +{ + size_t s2_actual_len = strlen(s2); + size_t s2_len = s2_actual_len < n ? s2_actual_len : n; + + if (s1->len + s2_len >= s1->size) { + size_t required_size = s1->len + s2_len + 1; + s1->size = 2 * required_size; + + s1->s = realloc(s1->s, s1->size); + s1->s[s1->len] = '\0'; + } + + strncat(s1->s, s2, s2_len); + s1->len += s2_len; +} + +static void +sbuf_strcat(struct sbuf *s1, const char *s2) +{ + sbuf_strncat(s1, s2, strlen(s2)); +} + +char * +tags_expand_template(const char *template, const struct tag_set *tags) +{ + struct sbuf formatted = {0}; + + while (true) { + /* Find next tag opening '{' */ + const char *begin = strchr(template, '{'); + + if (begin == NULL) { + /* No more tags, copy remaining characters */ + sbuf_strcat(&formatted, template); + break; + } + + /* Find closing '}' */ + const char *end = strchr(begin, '}'); + if (end == NULL) { + /* Wasn't actually a tag, copy as-is instead */ + sbuf_strncat(&formatted, template, begin - template + 1); + template = begin + 1; + continue; + } + + /* Extract tag name */ + char tag_name[end - begin]; + strncpy(tag_name, begin + 1, end - begin - 1); + tag_name[end - begin - 1] = '\0'; + + /* Lookup tag */ + const struct tag *tag = tag_for_name(tags, tag_name); + if (tag == NULL) { + /* No such tag, copy as-is instead */ + sbuf_strncat(&formatted, template, begin - template + 1); + template = begin + 1; + continue; + } + + /* Copy characters preceeding the tag (name) */ + sbuf_strncat(&formatted, template, begin - template); + + /* Copy tag value */ + const char *value = tag->as_string(tag); + sbuf_strcat(&formatted, value); + + /* Skip past tag name + closing '}' */ + template = end + 1; + } + + return formatted.s; +} diff --git a/tag.h b/tag.h index 8b4a1f9..254ee4a 100644 --- a/tag.h +++ b/tag.h @@ -48,3 +48,6 @@ struct tag *tag_new_string( const struct tag *tag_for_name(const struct tag_set *set, const char *name); void tag_set_destroy(struct tag_set *set); + +/* Utility functions */ +char *tags_expand_template(const char *template, const struct tag_set *tags);