Allow having clickable areas inside another

Previously, if you started several areas, one inside another, only the
inermost one would get registered and eventually triggered. This patch
fixes that, allowing you to use multiple areas around text to respond to
several different buttons, for example, both scroll-up and scroll-down.

If you define two areas that respond to the same button, only the
innermost one would get triggered. I think this makes sense.
This commit is contained in:
Otto Modinos 2015-01-16 01:37:45 +02:00
parent e197a15c3a
commit 7d2c7ab438
1 changed files with 25 additions and 13 deletions

38
bar.c
View File

@ -34,6 +34,7 @@ typedef struct monitor_t {
} monitor_t;
typedef struct area_t {
bool active;
int begin, end, align, button;
xcb_window_t window;
char *cmd;
@ -219,11 +220,15 @@ set_attribute (const char modifier, const char attribute)
area_t *
area_get (xcb_window_t win, const int x)
area_get (xcb_window_t win, const int btn, const int x)
{
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];
/* Looping backwards ensures that we get the innermost area first */
for (int i = astack.pos; i >= 0; i--) {
area_t *a = &astack.slot[i];
if (a->window == win && a->button == btn
&& x >= a->begin && x < a->end)
return a;
}
return NULL;
}
@ -248,17 +253,18 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x
{
char *p = str;
char *trail;
area_t *a = &astack.slot[astack.pos];
if (astack.pos == N) {
fprintf(stderr, "astack overflow!\n");
return false;
}
area_t *a;
// A wild close area tag appeared!
if (*p != ':') {
*end = p;
/* Find most recent unclosed area. */
int i;
for (i = astack.pos - 1; i >= 0 && !astack.slot[i].active; i--)
;
a = &astack.slot[i];
// Basic safety checks
if (!a->cmd || a->align != align || a->window != mon->window)
return false;
@ -280,11 +286,16 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x
break;
}
astack.pos++;
a->active = false;
return true;
}
if (astack.pos >= N) {
fprintf(stderr, "astack overflow!\n");
return false;
}
a = &astack.slot[astack.pos++];
// Found the closing : and check if it's just an escaped one
for (trail = strchr(++p, ':'); trail && trail[-1] == '\\'; trail = strchr(trail + 1, ':'))
;
@ -308,6 +319,7 @@ area_add (char *str, const char *optend, char **end, monitor_t *mon, const int x
// This is a pointer to the string buffer allocated in the main
a->cmd = p;
a->active = true;
a->align = align;
a->begin = x;
a->window = mon->window;
@ -1191,7 +1203,7 @@ main (int argc, char **argv)
case XCB_BUTTON_PRESS:
press_ev = (xcb_button_press_event_t *)ev;
{
area_t *area = area_get(press_ev->event, press_ev->event_x);
area_t *area = area_get(press_ev->event, press_ev->detail, press_ev->event_x);
// Respond to the click
if (area && area->button == press_ev->detail) {
write(STDOUT_FILENO, area->cmd, strlen(area->cmd));