Add support binding on-click handlers to other buttons than LEFT

One can now bind the left/middle/right mouse buttons to on-click. In
fact, you can have all three buttons bound to different handlers for
the same particle. The new syntax is

    on-click:
        left: <command>
        middle: <command>
        right: <command>

Leaving one out is the same thing as not mapping it at
all. Furthermore,

    on-click: <command>

is still valid, and is a shorthand for

    on-click:
        left: <commsnd>
This commit is contained in:
Daniel Eklöf 2021-06-22 19:04:13 +02:00
parent af163d3f77
commit c79ffbe057
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
15 changed files with 163 additions and 90 deletions

View file

@ -272,26 +272,25 @@ static void
wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
{
if (state != WL_POINTER_BUTTON_STATE_PRESSED)
return;
struct seat *seat = data;
struct wayland_backend *backend = seat->backend;
backend->active_seat = seat;
if (state == WL_POINTER_BUTTON_STATE_PRESSED)
backend->active_seat = seat;
else {
enum mouse_button btn;
enum mouse_button btn;
switch (button) {
case BTN_LEFT: btn = MOUSE_BTN_LEFT; break;
case BTN_MIDDLE: btn = MOUSE_BTN_MIDDLE; break;
case BTN_RIGHT: btn = MOUSE_BTN_RIGHT; break;
default:
return;
}
switch (button) {
case BTN_LEFT: btn = MOUSE_BTN_LEFT; break;
case BTN_MIDDLE: btn = MOUSE_BTN_MIDDLE; break;
case BTN_RIGHT: btn = MOUSE_BTN_RIGHT; break;
default:
return;
backend->bar_on_mouse(
backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y);
}
backend->bar_on_mouse(
backend->bar, ON_MOUSE_CLICK, btn, seat->pointer.x, seat->pointer.y);
}
static void

View file

@ -152,6 +152,24 @@ conf_verify_dict(keychain_t *chain, const struct yml_node *node,
return true;
}
bool
conf_verify_on_click(keychain_t *chain, const struct yml_node *node)
{
/* on-click: <command> */
const char *s = yml_value_as_string(node);
if (s != NULL)
return true;
static const struct attr_info info[] = {
{"left", false, &conf_verify_string},
{"middle", false, &conf_verify_string},
{"right", false, &conf_verify_string},
{NULL, false, NULL},
};
return conf_verify_dict(chain, node, info);
}
bool
conf_verify_color(keychain_t *chain, const struct yml_node *node)
{

View file

@ -40,6 +40,7 @@ bool conf_verify_list(keychain_t *chain, const struct yml_node *node,
bool conf_verify_dict(keychain_t *chain, const struct yml_node *node,
const struct attr_info info[]); /* NULL-terminated list */
bool conf_verify_on_click(keychain_t *chain, const struct yml_node *node);
bool conf_verify_color(keychain_t *chain, const struct yml_node *node);
bool conf_verify_font(keychain_t *chain, const struct yml_node *node);

View file

@ -139,8 +139,33 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited)
int right = margin != NULL ? yml_value_as_int(margin) :
right_margin != NULL ? yml_value_as_int(right_margin) : 0;
const char *on_click_template
= on_click != NULL ? yml_value_as_string(on_click) : NULL;
const char *on_click_templates[MOUSE_BTN_COUNT] = {NULL};
if (on_click != NULL) {
const char *legacy = yml_value_as_string(on_click);
if (legacy != NULL)
on_click_templates[MOUSE_BTN_LEFT] = legacy;
if (yml_is_dict(on_click)) {
for (struct yml_dict_iter it = yml_dict_iter(on_click);
it.key != NULL;
yml_dict_next(&it))
{
const char *key = yml_value_as_string(it.key);
const char *template = yml_value_as_string(it.value);
if (strcmp(key, "left") == 0)
on_click_templates[MOUSE_BTN_LEFT] = template;
else if (strcmp(key, "middle") == 0)
on_click_templates[MOUSE_BTN_MIDDLE] = template;
else if (strcmp(key, "right") == 0)
on_click_templates[MOUSE_BTN_RIGHT] = template;
else
assert(false);
}
}
}
struct deco *deco = deco_node != NULL ? conf_to_deco(deco_node) : NULL;
/*
@ -159,7 +184,7 @@ conf_to_particle(const struct yml_node *node, struct conf_inherit inherited)
/* Instantiate base/common particle */
struct particle *common = particle_common_new(
left, right, on_click_template, font, foreground, deco);
left, right, on_click_templates, font, foreground, deco);
const struct particle_iface *iface = plugin_load_particle(type);

View file

@ -22,31 +22,41 @@ particle_default_destroy(struct particle *particle)
if (particle->deco != NULL)
particle->deco->destroy(particle->deco);
fcft_destroy(particle->font);
free(particle->on_click_template);
for (size_t i = 0; i < MOUSE_BTN_COUNT; i++)
free(particle->on_click_templates[i]);
free(particle);
}
struct particle *
particle_common_new(int left_margin, int right_margin,
const char *on_click_template,
const char **on_click_templates,
struct fcft_font *font, pixman_color_t foreground,
struct deco *deco)
{
struct particle *p = calloc(1, sizeof(*p));
p->left_margin = left_margin;
p->right_margin = right_margin;
p->on_click_template =
on_click_template != NULL ? strdup(on_click_template) : NULL;
p->foreground = foreground;
p->font = font;
p->deco = deco;
if (on_click_templates != NULL) {
for (size_t i = 0; i < MOUSE_BTN_COUNT; i++) {
if (on_click_templates[i] != NULL) {
p->have_on_click_template = true;
p->on_click_templates[i] = strdup(on_click_templates[i]);
}
}
}
return p;
}
void
exposable_default_destroy(struct exposable *exposable)
{
free(exposable->on_click);
for (size_t i = 0; i < MOUSE_BTN_COUNT; i++)
free(exposable->on_click[i]);
free(exposable);
}
@ -144,19 +154,32 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar,
enum mouse_event event, enum mouse_button btn,
int x, int y)
{
#if defined(LOG_ENABLE_DBG) && LOG_ENABLE_DBG
static const char *button_name[] = {
[MOUSE_BTN_NONE] = "none",
[MOUSE_BTN_LEFT] = "left",
[MOUSE_BTN_MIDDLE] = "middle",
[MOUSE_BTN_RIGHT] = "right",
[MOUSE_BTN_COUNT] = "count",
};
LOG_DBG("on_mouse: exposable=%p, event=%s, btn=%s, x=%d, y=%d (on-click=%s)",
exposable, event == ON_MOUSE_MOTION ? "motion" : "click",
btn == MOUSE_BTN_NONE ? "none" : btn == MOUSE_BTN_LEFT ? "left" : btn == MOUSE_BTN_MIDDLE ? "middle" : "right",
x, y, exposable->on_click);
button_name[btn], x, y, exposable->on_click[btn]);
#endif
/* If we have a handler, change cursor to a hand */
bar->set_cursor(bar, exposable->on_click == NULL ? "left_ptr" : "hand2");
const char *cursor =
(exposable->particle != NULL &&
exposable->particle->have_on_click_template)
? "hand2"
: "left_ptr";
bar->set_cursor(bar, cursor);
/* If this is a mouse click, and we have a handler, execute it */
if (exposable->on_click != NULL && event == ON_MOUSE_CLICK) {
if (exposable->on_click[btn] != NULL && event == ON_MOUSE_CLICK) {
/* Need a writeable copy, whose scope *we* control */
char *cmd = strdup(exposable->on_click);
LOG_DBG("cmd = \"%s\"", exposable->on_click);
char *cmd = strdup(exposable->on_click[btn]);
LOG_DBG("cmd = \"%s\"", exposable->on_click[btn]);
char **argv;
if (!tokenize_cmdline(cmd, &argv)) {
@ -174,15 +197,15 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar,
int wstatus;
if (waitpid(pid, &wstatus, 0) == -1)
LOG_ERRNO("%s: failed to wait for on_click handler", exposable->on_click);
LOG_ERRNO("%s: failed to wait for on_click handler", exposable->on_click[btn]);
if (WIFEXITED(wstatus)) {
if (WEXITSTATUS(wstatus) != 0)
LOG_ERRNO_P("%s: failed to execute", WEXITSTATUS(wstatus), exposable->on_click);
LOG_ERRNO_P("%s: failed to execute", WEXITSTATUS(wstatus), exposable->on_click[btn]);
} else
LOG_ERR("%s: did not exit normally", exposable->on_click);
LOG_ERR("%s: did not exit normally", exposable->on_click[btn]);
LOG_DBG("%s: launched", exposable->on_click);
LOG_DBG("%s: launched", exposable->on_click[btn]);
} else {
/*
* Use a pipe with O_CLOEXEC to communicate exec() failure
@ -283,11 +306,17 @@ exposable_default_on_mouse(struct exposable *exposable, struct bar *bar,
}
struct exposable *
exposable_common_new(const struct particle *particle, const char *on_click)
exposable_common_new(const struct particle *particle, const struct tag_set *tags)
{
struct exposable *exposable = calloc(1, sizeof(*exposable));
exposable->particle = particle;
exposable->on_click = on_click != NULL ? strdup(on_click) : NULL;
if (particle != NULL && particle->have_on_click_template) {
tags_expand_templates(
exposable->on_click,
(const char **)particle->on_click_templates,
MOUSE_BTN_COUNT, tags);
}
exposable->destroy = &exposable_default_destroy;
exposable->on_mouse = &exposable_default_on_mouse;
return exposable;

View file

@ -7,23 +7,6 @@
#include "decoration.h"
#include "tag.h"
struct bar;
struct particle {
void *private;
int left_margin, right_margin;
char *on_click_template;
pixman_color_t foreground;
struct fcft_font *font;
struct deco *deco;
void (*destroy)(struct particle *particle);
struct exposable *(*instantiate)(const struct particle *particle,
const struct tag_set *tags);
};
enum mouse_event {
ON_MOUSE_MOTION,
ON_MOUSE_CLICK,
@ -34,14 +17,36 @@ enum mouse_button {
MOUSE_BTN_LEFT,
MOUSE_BTN_MIDDLE,
MOUSE_BTN_RIGHT,
MOUSE_BTN_COUNT,
};
struct bar;
struct particle {
void *private;
int left_margin, right_margin;
bool have_on_click_template;
char *on_click_templates[MOUSE_BTN_COUNT];
pixman_color_t foreground;
struct fcft_font *font;
struct deco *deco;
void (*destroy)(struct particle *particle);
struct exposable *(*instantiate)(const struct particle *particle,
const struct tag_set *tags);
};
struct exposable {
const struct particle *particle;
void *private;
int width; /* Should be set by begin_expose(), at latest */
char *on_click;
char *on_click[MOUSE_BTN_COUNT];
void (*destroy)(struct exposable *exposable);
int (*begin_expose)(struct exposable *exposable);
@ -53,13 +58,13 @@ struct exposable {
};
struct particle *particle_common_new(
int left_margin, int right_margin, const char *on_click_template,
int left_margin, int right_margin, const char *on_click_templates[],
struct fcft_font *font, pixman_color_t foreground, struct deco *deco);
void particle_default_destroy(struct particle *particle);
struct exposable *exposable_common_new(
const struct particle *particle, const char *on_click);
const struct particle *particle, const struct tag_set *tags);
void exposable_default_destroy(struct exposable *exposable);
void exposable_render_deco(
const struct exposable *exposable, pixman_image_t *pix, int x, int y, int height);
@ -73,7 +78,7 @@ void exposable_default_on_mouse(
{"margin", false, &conf_verify_int}, \
{"left-margin", false, &conf_verify_int}, \
{"right-margin", false, &conf_verify_int}, \
{"on-click", false, &conf_verify_string}, \
{"on-click", false, &conf_verify_on_click}, \
{"font", false, &conf_verify_font}, \
{"foreground", false, &conf_verify_color}, \
{"deco", false, &conf_verify_decoration}, \

View file

@ -72,7 +72,7 @@ on_mouse(struct exposable *exposable, struct bar *bar,
//const struct particle *p = exposable->particle;
const struct private *e = exposable->private;
if (exposable->on_click != NULL) {
if (exposable->on_click[btn] != NULL) {
exposable_default_on_mouse(exposable, bar, event, btn, x, y);
return;
}

View file

@ -22,13 +22,9 @@ expose(const struct exposable *exposable, pixman_image_t *pix, int x, int y, int
static struct exposable *
instantiate(const struct particle *particle, const struct tag_set *tags)
{
char *on_click = tags_expand_template(particle->on_click_template, tags);
struct exposable *exposable = exposable_common_new(particle, on_click);
struct exposable *exposable = exposable_common_new(particle, tags);
exposable->begin_expose = &begin_expose;
exposable->expose = &expose;
free(on_click);
return exposable;
}

View file

@ -80,7 +80,7 @@ on_mouse(struct exposable *exposable, struct bar *bar,
const struct particle *p = exposable->particle;
const struct eprivate *e = exposable->private;
if (exposable->on_click != NULL) {
if (exposable->on_click[btn] != NULL) {
/* We have our own handler */
exposable_default_on_mouse(exposable, bar, event, btn, x, y);
return;
@ -121,16 +121,12 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
assert(e->exposables[i] != NULL);
}
char *on_click = tags_expand_template(particle->on_click_template, tags);
struct exposable *exposable = exposable_common_new(particle, on_click);
struct exposable *exposable = exposable_common_new(particle, tags);
exposable->private = e;
exposable->destroy = &exposable_destroy;
exposable->begin_expose = &begin_expose;
exposable->expose = &expose;
exposable->on_mouse = &on_mouse;
free(on_click);
return exposable;
}

View file

@ -66,7 +66,7 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
const struct particle *p = exposable->particle;
const struct eprivate *e = exposable->private;
if (exposable->on_click != NULL) {
if (exposable->on_click[btn] != NULL) {
/* We have our own handler */
exposable_default_on_mouse(exposable, bar, event, btn, x, y);
return;
@ -119,15 +119,12 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
assert(e->exposable != NULL);
char *on_click = tags_expand_template(particle->on_click_template, tags);
struct exposable *exposable = exposable_common_new(particle, on_click);
struct exposable *exposable = exposable_common_new(particle, tags);
exposable->private = e;
exposable->destroy = &exposable_destroy;
exposable->begin_expose = &begin_expose;
exposable->expose = &expose;
exposable->on_mouse = &on_mouse;
free(on_click);
return exposable;
}

View file

@ -148,7 +148,9 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
}
/* Remember the original handler, so that we can restore it */
char *original = exposable->on_click;
char *original[MOUSE_BTN_COUNT];
for (size_t i = 0; i < MOUSE_BTN_COUNT; i++)
original[i] = exposable->on_click[i];
if (event == ON_MOUSE_CLICK) {
long where = clickable_width > 0
@ -160,7 +162,9 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
.count = 1,
};
exposable->on_click = tags_expand_template(exposable->on_click, &tags);
tags_expand_templates(
exposable->on_click, (const char **)exposable->on_click,
MOUSE_BTN_COUNT, &tags);
tag_set_destroy(&tags);
}
@ -169,8 +173,10 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
if (event == ON_MOUSE_CLICK) {
/* Reset handler string */
free(exposable->on_click);
exposable->on_click = original;
for (size_t i = 0; i < MOUSE_BTN_COUNT; i++) {
free(exposable->on_click[i]);
exposable->on_click[i] = original[i];
}
}
}
@ -213,10 +219,7 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
for (size_t i = 0; i < epriv->count; i++)
assert(epriv->exposables[i] != NULL);
char *on_click = tags_expand_template(particle->on_click_template, tags);
struct exposable *exposable = exposable_common_new(particle, on_click);
free(on_click);
struct exposable *exposable = exposable_common_new(particle, tags);
exposable->private = epriv;
exposable->destroy = &exposable_destroy;

View file

@ -62,7 +62,7 @@ on_mouse(struct exposable *exposable, struct bar *bar, enum mouse_event event,
const struct particle *p = exposable->particle;
const struct eprivate *e = exposable->private;
if (exposable->on_click != NULL) {
if (exposable->on_click[btn] != NULL) {
/* We have our own handler */
exposable_default_on_mouse(exposable, bar, event, btn, x, y);
return;
@ -146,15 +146,12 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
e->exposable = pp->instantiate(pp, tags);
assert(e->exposable != NULL);
char *on_click = tags_expand_template(particle->on_click_template, tags);
struct exposable *exposable = exposable_common_new(particle, on_click);
struct exposable *exposable = exposable_common_new(particle, tags);
exposable->private = e;
exposable->destroy = &exposable_destroy;
exposable->begin_expose = &begin_expose;
exposable->expose = &expose;
exposable->on_mouse = &on_mouse;
free(on_click);
return exposable;
}

View file

@ -269,15 +269,11 @@ instantiate(const struct particle *particle, const struct tag_set *tags)
}
}
char *on_click = tags_expand_template(particle->on_click_template, tags);
struct exposable *exposable = exposable_common_new(particle, on_click);
struct exposable *exposable = exposable_common_new(particle, tags);
exposable->private = e;
exposable->destroy = &exposable_destroy;
exposable->begin_expose = &begin_expose;
exposable->expose = &expose;
free(on_click);
return exposable;
}

8
tag.c
View file

@ -533,3 +533,11 @@ tags_expand_template(const char *template, const struct tag_set *tags)
return formatted.s;
}
void
tags_expand_templates(char *expanded[], const char *template[], size_t nmemb,
const struct tag_set *tags)
{
for (size_t i = 0; i < nmemb; i++)
expanded[i] = tags_expand_template(template[i], tags);
}

3
tag.h
View file

@ -50,3 +50,6 @@ void tag_set_destroy(struct tag_set *set);
/* Utility functions */
char *tags_expand_template(const char *template, const struct tag_set *tags);
void tags_expand_templates(
char *expanded[], const char *template[], size_t nmemb,
const struct tag_set *tags);