diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h index 1aec6d6c..dced2a6c 100644 --- a/include/swaybar/i3bar.h +++ b/include/swaybar/i3bar.h @@ -30,6 +30,6 @@ void i3bar_block_unref(struct i3bar_block *block); bool i3bar_handle_readable(struct status_line *status); enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, struct i3bar_block *block, double x, double y, double rx, double ry, - double w, double h, int scale, uint32_t button); + double w, double h, int scale, uint32_t button, bool released); #endif diff --git a/include/swaybar/input.h b/include/swaybar/input.h index e8735d88..8ea88a69 100644 --- a/include/swaybar/input.h +++ b/include/swaybar/input.h @@ -49,7 +49,7 @@ struct swaybar_hotspot { int x, y, width, height; enum hotspot_event_handling (*callback)(struct swaybar_output *output, struct swaybar_hotspot *hotspot, double x, double y, uint32_t button, - void *data); + bool released, void *data); void (*destroy)(void *data); void *data; }; diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 6d00befb..ccd5a076 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c @@ -269,11 +269,16 @@ bool i3bar_handle_readable(struct status_line *status) { enum hotspot_event_handling i3bar_block_send_click(struct status_line *status, struct i3bar_block *block, double x, double y, double rx, double ry, - double w, double h, int scale, uint32_t button) { + double w, double h, int scale, uint32_t button, bool released) { sway_log(SWAY_DEBUG, "block %s clicked", block->name); if (!block->name || !status->click_events) { return HOTSPOT_PROCESS; } + if (released) { + // Since we handle the pressed event, also handle the released event + // to block it from falling through to a binding in the bar + return HOTSPOT_IGNORE; + } struct json_object *event_json = json_object_new_object(); json_object_object_add(event_json, "name", diff --git a/swaybar/input.c b/swaybar/input.c index f12eed79..8eccf542 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -141,14 +141,15 @@ static bool check_bindings(struct swaybar *bar, uint32_t button, } static bool process_hotspots(struct swaybar_output *output, - double x, double y, uint32_t button) { + double x, double y, uint32_t button, uint32_t state) { + bool released = state == WL_POINTER_BUTTON_STATE_RELEASED; struct swaybar_hotspot *hotspot; wl_list_for_each(hotspot, &output->hotspots, link) { if (x >= hotspot->x && y >= hotspot->y && x < hotspot->x + hotspot->width && y < hotspot->y + hotspot->height) { if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, x, y, - button, hotspot->data)) { + button, released, hotspot->data)) { return true; } } @@ -166,10 +167,8 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, return; } - if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - if (process_hotspots(output, pointer->x, pointer->y, button)) { - return; - } + if (process_hotspots(output, pointer->x, pointer->y, button, state)) { + return; } check_bindings(seat->bar, button, state); @@ -222,7 +221,8 @@ static void process_discrete_scroll(struct swaybar_seat *seat, struct swaybar_output *output, struct swaybar_pointer *pointer, uint32_t axis, wl_fixed_t value) { uint32_t button = wl_axis_to_button(axis, value); - if (process_hotspots(output, pointer->x, pointer->y, button)) { + if (process_hotspots(output, pointer->x, pointer->y, button, WL_POINTER_BUTTON_STATE_PRESSED)) { + // (Currently hotspots don't do anything on release events, so no need to emit one) return; } @@ -401,7 +401,8 @@ static void wl_touch_up(void *data, struct wl_touch *wl_touch, } if (time - slot->time < 500) { // Tap, treat it like a pointer click - process_hotspots(slot->output, slot->x, slot->y, BTN_LEFT); + process_hotspots(slot->output, slot->x, slot->y, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED); + // (Currently hotspots don't do anything on release events, so no need to emit one) } slot->output = NULL; } diff --git a/swaybar/render.c b/swaybar/render.c index a878805e..95f6e5be 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -160,7 +160,7 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color, static enum hotspot_event_handling block_hotspot_callback( struct swaybar_output *output, struct swaybar_hotspot *hotspot, - double x, double y, uint32_t button, void *data) { + double x, double y, uint32_t button, bool released, void *data) { struct i3bar_block *block = data; struct status_line *status = output->bar->status; return i3bar_block_send_click(status, block, x, y, @@ -168,7 +168,7 @@ static enum hotspot_event_handling block_hotspot_callback( y - (double)hotspot->y, (double)hotspot->width, (double)hotspot->height, - output->scale, button); + output->scale, button, released); } static void i3bar_block_unref_callback(void *data) { @@ -599,10 +599,15 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx, static enum hotspot_event_handling workspace_hotspot_callback( struct swaybar_output *output, struct swaybar_hotspot *hotspot, - double x, double y, uint32_t button, void *data) { + double x, double y, uint32_t button, bool released, void *data) { if (button != BTN_LEFT) { return HOTSPOT_PROCESS; } + if (released) { + // Since we handle the pressed event, also handle the released event + // to block it from falling through to a binding in the bar + return HOTSPOT_IGNORE; + } ipc_send_workspace_command(output->bar, (const char *)data); return HOTSPOT_IGNORE; } diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 0cb5ee9d..1f18b8bb 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -385,13 +385,18 @@ static int cmp_sni_id(const void *item, const void *cmp_to) { static enum hotspot_event_handling icon_hotspot_callback( struct swaybar_output *output, struct swaybar_hotspot *hotspot, - double x, double y, uint32_t button, void *data) { + double x, double y, uint32_t button, bool released, void *data) { sway_log(SWAY_DEBUG, "Clicked on %s", (char *)data); struct swaybar_tray *tray = output->bar->tray; int idx = list_seq_find(tray->items, cmp_sni_id, data); if (idx != -1) { + if (released) { + // Since we handle the pressed event, also handle the released event + // to block it from falling through to a binding in the bar + return HOTSPOT_IGNORE; + } struct swaybar_sni *sni = tray->items->items[idx]; // guess global position since wayland doesn't expose it struct swaybar_config *config = tray->bar->config;