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