diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index ef27012d..ad942242 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -70,6 +70,8 @@ struct swaybar_output { struct pool_buffer *current_buffer; bool dirty; bool frame_scheduled; + + uint32_t output_height, output_width, output_x, output_y; }; struct swaybar_workspace { diff --git a/swaybar/bar.c b/swaybar/bar.c index 668168eb..ebb9bc12 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -215,12 +215,16 @@ struct wl_output_listener output_listener = { static void xdg_output_handle_logical_position(void *data, struct zxdg_output_v1 *xdg_output, int32_t x, int32_t y) { - // Who cares + struct swaybar_output *output = data; + output->output_x = x; + output->output_y = y; } static void xdg_output_handle_logical_size(void *data, struct zxdg_output_v1 *xdg_output, int32_t width, int32_t height) { - // Who cares + struct swaybar_output *output = data; + output->output_height = height; + output->output_width = width; } static void xdg_output_handle_done(void *data, diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 019e8ed0..450b6882 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -5,6 +5,7 @@ #include #include "swaybar/bar.h" #include "swaybar/config.h" +#include "swaybar/input.h" #include "swaybar/tray/host.h" #include "swaybar/tray/icon.h" #include "swaybar/tray/item.h" @@ -13,6 +14,7 @@ #include "cairo.h" #include "list.h" #include "log.h" +#include "wlr-layer-shell-unstable-v1-client-protocol.h" // TODO menu @@ -248,6 +250,83 @@ void destroy_sni(struct swaybar_sni *sni) { free(sni); } +static void handle_click(struct swaybar_sni *sni, int x, int y, + enum x11_button button, int delta) { + const char *method = sni->tray->bar->config->tray_bindings[button]; + if (!method) { + static const char *default_bindings[10] = { + "nop", + "Activate", + "SecondaryActivate", + "ContextMenu", + "ScrollUp", + "ScrollDown", + "ScrollLeft", + "ScrollRight", + "nop", + "nop" + }; + method = default_bindings[button]; + } + if (strcmp(method, "nop") == 0) { + return; + } + if (sni->item_is_menu && strcmp(method, "Activate") == 0) { + method = "ContextMenu"; + } + + if (strncmp(method, "Scroll", strlen("Scroll")) == 0) { + char dir = method[strlen("Scroll")]; + char *orientation = (dir = 'U' || dir == 'D') ? "vertical" : "horizontal"; + int sign = (dir == 'U' || dir == 'L') ? -1 : 1; + + int ret = sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, + sni->path, sni->interface, "Scroll", NULL, NULL, "is", + delta*sign, orientation); + if (ret < 0) { + wlr_log(WLR_DEBUG, "Failed to scroll on SNI: %s", strerror(-ret)); + } + } else { + int ret = sd_bus_call_method_async(sni->tray->bus, NULL, sni->service, + sni->path, sni->interface, method, NULL, NULL, "ii", x, y); + if (ret < 0) { + wlr_log(WLR_DEBUG, "Failed to click on SNI: %s", strerror(-ret)); + } + } +} + +static int cmp_sni_id(const void *item, const void *cmp_to) { + const struct swaybar_sni *sni = item; + return strcmp(sni->watcher_id, cmp_to); +} + +static enum hotspot_event_handling icon_hotspot_callback( + struct swaybar_output *output, struct swaybar_hotspot *hotspot, + int x, int y, enum x11_button button, void *data) { + wlr_log(WLR_DEBUG, "Clicked on Status Notifier Item '%s'", (char *)data); + + struct swaybar_tray *tray = output->bar->tray; + int idx = list_seq_find(tray->items, cmp_sni_id, data); + + if (idx != -1) { + struct swaybar_sni *sni = tray->items->items[idx]; + // guess global position since wayland doesn't expose it + struct swaybar_config *config = tray->bar->config; + int global_x = output->output_x + config->gaps.left + x; + bool top_bar = config->position & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + int global_y = output->output_y + (top_bar ? config->gaps.top + y: + (int) output->output_height - config->gaps.bottom - y); + + wlr_log(WLR_DEBUG, "Guessing click at (%d, %d)", global_x, global_y); + handle_click(sni, global_x, global_y, button, 1); // TODO get delta from event + return HOTSPOT_IGNORE; + } else { + wlr_log(WLR_DEBUG, "but it doesn't exist"); + } + + return HOTSPOT_PROCESS; +} + uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, struct swaybar_sni *sni) { uint32_t height = output->height * output->scale; @@ -316,5 +395,15 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x, cairo_surface_destroy(icon); + struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); + hotspot->x = *x; + hotspot->y = 0; + hotspot->width = height; + hotspot->height = height; + hotspot->callback = icon_hotspot_callback; + hotspot->destroy = free; + hotspot->data = strdup(sni->watcher_id); + wl_list_insert(&output->hotspots, &hotspot->link); + return output->height; }