diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 197d2190..d0b3dc81 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -33,6 +33,7 @@ struct swaybar { struct zxdg_output_manager_v1 *xdg_output_manager; struct wp_cursor_shape_manager_v1 *cursor_shape_manager; struct wl_shm *shm; + struct xdg_wm_base *wm_base; struct swaybar_config *config; struct status_line *status; diff --git a/include/swaybar/input.h b/include/swaybar/input.h index 8ea88a69..81ccaa98 100644 --- a/include/swaybar/input.h +++ b/include/swaybar/input.h @@ -15,6 +15,7 @@ struct swaybar; struct swaybar_output; +struct swaybar_seat; struct swaybar_pointer { struct wl_pointer *pointer; @@ -48,8 +49,8 @@ struct swaybar_hotspot { struct wl_list link; // swaybar_output::hotspots 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, - bool released, void *data); + struct swaybar_hotspot *hotspot, struct swaybar_seat *seat, uint32_t serial, + double x, double y, uint32_t button, bool released, void *data); void (*destroy)(void *data); void *data; }; diff --git a/include/swaybar/tray/item.h b/include/swaybar/tray/item.h index 73937a0c..9a4a00ff 100644 --- a/include/swaybar/tray/item.h +++ b/include/swaybar/tray/item.h @@ -18,6 +18,7 @@ struct swaybar_pixmap { struct swaybar_sni_slot { struct wl_list link; // swaybar_sni::slots struct swaybar_sni *sni; + int menu_id; const char *prop; const char *type; void *dest; @@ -48,6 +49,7 @@ struct swaybar_sni { char *icon_theme_path; // non-standard KDE property struct wl_list slots; // swaybar_sni_slot::link + char **menu_icon_theme_paths; }; struct swaybar_sni *create_sni(char *id, struct swaybar_tray *tray); diff --git a/include/swaybar/tray/tray.h b/include/swaybar/tray/tray.h index d2e80a6d..853f17cd 100644 --- a/include/swaybar/tray/tray.h +++ b/include/swaybar/tray/tray.h @@ -32,6 +32,9 @@ struct swaybar_tray { list_t *basedirs; // char * list_t *themes; // struct swaybar_theme * + + struct swaybar_dbusmenu *menu; + struct swaybar_dbusmenu_menu *menu_pointer_focus; }; struct swaybar_tray *create_tray(struct swaybar *bar); diff --git a/swaybar/bar.c b/swaybar/bar.c index 5b1213a8..b6ed284c 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -28,6 +28,7 @@ #include "pool-buffer.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h" +#include "xdg-shell-client-protocol.h" void free_workspaces(struct wl_list *list) { struct swaybar_workspace *ws, *tmp; @@ -364,6 +365,8 @@ static void handle_global(void *data, struct wl_registry *registry, } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) { bar->cursor_shape_manager = wl_registry_bind(registry, name, &wp_cursor_shape_manager_v1_interface, 1); + } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) { + bar->wm_base = wl_registry_bind(registry, name, &xdg_wm_base_interface, 1); } } @@ -538,6 +541,7 @@ void bar_teardown(struct swaybar *bar) { #if HAVE_TRAY destroy_tray(bar->tray); #endif + xdg_wm_base_destroy(bar->wm_base); free_outputs(&bar->outputs); free_outputs(&bar->unused_outputs); free_seats(&bar->seats); diff --git a/swaybar/input.c b/swaybar/input.c index ada4bc86..54e1d5cd 100644 --- a/swaybar/input.c +++ b/swaybar/input.c @@ -10,6 +10,10 @@ #include "swaybar/input.h" #include "swaybar/ipc.h" +#if HAVE_TRAY +#include "swaybar/tray/dbusmenu.h" +#endif + void free_hotspots(struct wl_list *list) { struct swaybar_hotspot *hotspot, *tmp; wl_list_for_each_safe(hotspot, tmp, list, link) { @@ -131,11 +135,27 @@ static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, pointer->serial = serial; update_cursor(seat); } + +#if HAVE_TRAY + struct swaybar_config *config = seat->bar->config; + if (!config->tray_hidden && dbusmenu_pointer_enter(data, wl_pointer, serial, + surface, surface_x, surface_y)) { + return; + } +#endif } static void wl_pointer_leave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface) { +#if HAVE_TRAY struct swaybar_seat *seat = data; + struct swaybar_config *config = seat->bar->config; + if (!config->tray_hidden && dbusmenu_pointer_leave(data, wl_pointer, serial, + surface)) { + return; + } +#endif + seat->pointer.current = NULL; } @@ -144,6 +164,13 @@ static void wl_pointer_motion(void *data, struct wl_pointer *wl_pointer, struct swaybar_seat *seat = data; seat->pointer.x = wl_fixed_to_double(surface_x); seat->pointer.y = wl_fixed_to_double(surface_y); +#if HAVE_TRAY + struct swaybar_config *config = seat->bar->config; + if (!config->tray_hidden && dbusmenu_pointer_motion(data, wl_pointer, time, + surface_x, surface_y)) { + return; + } +#endif } static bool check_bindings(struct swaybar *bar, uint32_t button, @@ -160,6 +187,7 @@ static bool check_bindings(struct swaybar *bar, uint32_t button, } static bool process_hotspots(struct swaybar_output *output, + struct swaybar_seat *seat, uint32_t serial, double x, double y, uint32_t button, uint32_t state) { bool released = state == WL_POINTER_BUTTON_STATE_RELEASED; struct swaybar_hotspot *hotspot; @@ -167,7 +195,7 @@ static bool process_hotspots(struct swaybar_output *output, 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, + if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, seat, serial, x, y, button, released, hotspot->data)) { return true; } @@ -180,13 +208,20 @@ static bool process_hotspots(struct swaybar_output *output, static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state) { struct swaybar_seat *seat = data; +#if HAVE_TRAY + struct swaybar_config *config = seat->bar->config; + if (!config->tray_hidden && dbusmenu_pointer_button(seat, wl_pointer, serial, + time, button, state)) { + return; + } +#endif struct swaybar_pointer *pointer = &seat->pointer; struct swaybar_output *output = pointer->current; if (!sway_assert(output, "button with no active output")) { return; } - if (process_hotspots(output, pointer->x, pointer->y, button, state)) { + if (process_hotspots(output, seat, serial, pointer->x, pointer->y, button, state)) { return; } @@ -240,7 +275,7 @@ 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, WL_POINTER_BUTTON_STATE_PRESSED)) { + if (process_hotspots(output, seat, 0, 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; } @@ -297,6 +332,13 @@ static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, return; } +#if HAVE_TRAY + struct swaybar_config *config = seat->bar->config; + if (!config->tray_hidden && dbusmenu_pointer_axis(data, wl_pointer)) { + return; + } +#endif + // If there's a while since the last scroll event, // set 'value' to zero as if to reset the "virtual scroll wheel" if (seat->axis[axis].discrete_steps == 0 && @@ -313,6 +355,13 @@ static void wl_pointer_frame(void *data, struct wl_pointer *wl_pointer) { struct swaybar_pointer *pointer = &seat->pointer; struct swaybar_output *output = pointer->current; +#if HAVE_TRAY + struct swaybar_config *config = seat->bar->config; + if (!config->tray_hidden && dbusmenu_pointer_frame(data, wl_pointer)) { + return; + } +#endif + if (output == NULL) { return; } @@ -420,7 +469,7 @@ 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, WL_POINTER_BUTTON_STATE_PRESSED); + process_hotspots(slot->output, seat, serial, 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/meson.build b/swaybar/meson.build index 34bbdeea..baeb74c4 100644 --- a/swaybar/meson.build +++ b/swaybar/meson.build @@ -3,7 +3,8 @@ tray_files = have_tray ? [ 'tray/icon.c', 'tray/item.c', 'tray/tray.c', - 'tray/watcher.c' + 'tray/watcher.c', + 'tray/dbusmenu.c' ] : [] swaybar_deps = [ diff --git a/swaybar/render.c b/swaybar/render.c index 879a4e42..eea6b35d 100644 --- a/swaybar/render.c +++ b/swaybar/render.c @@ -159,6 +159,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, + struct swaybar_seat *seat, uint32_t serial, double x, double y, uint32_t button, bool released, void *data) { struct i3bar_block *block = data; struct status_line *status = output->bar->status; @@ -598,6 +599,7 @@ 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, + struct swaybar_seat *seat, uint32_t serial, double x, double y, uint32_t button, bool released, void *data) { if (button != BTN_LEFT) { return HOTSPOT_PROCESS; diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index ca6c03ad..29bc8436 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -8,6 +8,7 @@ #include "swaybar/config.h" #include "swaybar/image.h" #include "swaybar/input.h" +#include "swaybar/tray/dbusmenu.h" #include "swaybar/tray/host.h" #include "swaybar/tray/icon.h" #include "swaybar/tray/item.h" @@ -332,8 +333,9 @@ void destroy_sni(struct swaybar_sni *sni) { free(sni); } -static void handle_click(struct swaybar_sni *sni, int x, int y, - uint32_t button, int delta) { +static void handle_click(struct swaybar_sni *sni, struct swaybar_output *output, + struct swaybar_seat *seat, uint32_t serial, int x, int y, uint32_t button, + int delta) { const char *method = NULL; struct tray_binding *binding = NULL; wl_list_for_each(binding, &sni->tray->bar->config->tray_bindings, link) { @@ -364,7 +366,11 @@ static void handle_click(struct swaybar_sni *sni, int x, int y, method = "ContextMenu"; } - if (strncmp(method, "Scroll", strlen("Scroll")) == 0) { + if (strcmp(method, "ContextMenu") == 0) { + if (sni->menu && !sni->tray->menu) { + swaybar_dbusmenu_open(sni, output, seat, serial, x, y); + } + } else 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; @@ -384,6 +390,7 @@ 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, + struct swaybar_seat *seat, uint32_t serial, double x, double y, uint32_t button, bool released, void *data) { sway_log(SWAY_DEBUG, "Clicked on %s", (char *)data); @@ -405,7 +412,8 @@ static enum hotspot_event_handling icon_hotspot_callback( (int) output->output_height - config->gaps.bottom - y); sway_log(SWAY_DEBUG, "Guessing click position at (%d, %d)", global_x, global_y); - handle_click(sni, global_x, global_y, button, 1); // TODO get delta from event + // TODO get delta from event + handle_click(sni, output, seat, serial, global_x, global_y, button, 1); return HOTSPOT_IGNORE; } else { sway_log(SWAY_DEBUG, "but it doesn't exist"); diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c index b0545f4a..e4a68034 100644 --- a/swaybar/tray/tray.c +++ b/swaybar/tray/tray.c @@ -110,7 +110,7 @@ static int cmp_output(const void *item, const void *cmp_to) { uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) { struct swaybar_config *config = output->bar->config; - if (config->tray_outputs) { + if (config->tray_outputs && !config->tray_hidden) { if (list_seq_find(config->tray_outputs, cmp_output, output) == -1) { return 0; }