Support xdg_activation_v1 protocol - wmenu - 🔧 fork of wmenu
 (HTM) git clone git@git.drkhsh.at/wmenu.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit cf6f5b9d06d72ded0b077d6770854d0003c1b4aa
 (DIR) parent 41b2e8b1e1d1415a43baa6393b7237e7e77468eb
 (HTM) Author: adnano <me@adnano.co>
       Date:   Sun,  7 Apr 2024 08:51:57 -0400
       
       Support xdg_activation_v1 protocol
       
       Diffstat:
         M README.md                           |       2 +-
         M docs/wmenu.1.scd                    |       5 ++++-
         M main.c                              |       4 ++++
         M menu.c                              |      58 +++++++++++++++++++++++++++++--
         M menu.h                              |       4 ++++
         M protocols/meson.build               |       1 +
         M wmenu_run                           |       2 +-
       
       7 files changed, 71 insertions(+), 5 deletions(-)
       ---
 (DIR) diff --git a/README.md b/README.md
       @@ -27,7 +27,7 @@ See wmenu(1)
        To use wmenu with Sway, you can add the following to your configuration file:
        
        ```
       -set $menu dmenu_path | wmenu | xargs swaymsg exec --
       +set $menu wmenu_run
        bindsym $mod+d exec $menu
        ```
        
 (DIR) diff --git a/docs/wmenu.1.scd b/docs/wmenu.1.scd
       @@ -6,7 +6,7 @@ wmenu - dynamic menu for Wayland
        
        # SYNOPSIS
        
       -*wmenu* [-biPv] \
       +*wmenu* [-biPvx] \
          [-f _font_] \
          [-l _lines_] \
          [-o _output_] \
       @@ -37,6 +37,9 @@ to those matching the tokens in the input.
        *-v*
                prints version information to stdout, then exits.
        
       +*-x*
       +        wmenu will execute the selected item.
       +
        *-f* _font_
                defines the font used. For more information, see
                https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html
 (DIR) diff --git a/main.c b/main.c
       @@ -18,6 +18,7 @@
        
        #include "menu.h"
        #include "render.h"
       +#include "xdg-activation-v1-client-protocol.h"
        #include "wlr-layer-shell-unstable-v1-client-protocol.h"
        
        static void noop() {
       @@ -203,6 +204,8 @@ static void handle_global(void *data, struct wl_registry *registry,
                        wl_output_set_user_data(wl_output, output);
                        wl_output_add_listener(wl_output, &output_listener, output);
                        menu_add_output(menu, output);
       +        } else if (strcmp(interface, xdg_activation_v1_interface.name) == 0) {
       +                menu->activation = wl_registry_bind(registry, name, &xdg_activation_v1_interface, 1);
                }
        }
        
       @@ -227,6 +230,7 @@ static void menu_connect(struct menu *menu) {
                assert(menu->seat != NULL);
                assert(menu->data_device_manager != NULL);
                assert(menu->layer_shell != NULL);
       +        assert(menu->activation != NULL);
                menu->registry = registry;
        
                // Get data device for seat
 (DIR) diff --git a/menu.c b/menu.c
       @@ -21,6 +21,7 @@
        #include "pango.h"
        #include "pool-buffer.h"
        #include "render.h"
       +#include "xdg-activation-v1-client-protocol.h"
        #include "wlr-layer-shell-unstable-v1-client-protocol.h"
        
        // Creates and returns a new menu.
       @@ -89,11 +90,11 @@ static bool parse_color(const char *color, uint32_t *result) {
        // Parse menu options from command line arguments.
        void menu_getopts(struct menu *menu, int argc, char *argv[]) {
                const char *usage =
       -                "Usage: wmenu [-biPv] [-f font] [-l lines] [-o output] [-p prompt]\n"
       +                "Usage: wmenu [-biPvx] [-f font] [-l lines] [-o output] [-p prompt]\n"
                        "\t[-N color] [-n color] [-M color] [-m color] [-S color] [-s color]\n";
        
                int opt;
       -        while ((opt = getopt(argc, argv, "bhiPvf:l:o:p:N:n:M:m:S:s:")) != -1) {
       +        while ((opt = getopt(argc, argv, "bhiPvxf:l:o:p:N:n:M:m:S:s:")) != -1) {
                        switch (opt) {
                        case 'b':
                                menu->bottom = true;
       @@ -107,6 +108,9 @@ void menu_getopts(struct menu *menu, int argc, char *argv[]) {
                        case 'v':
                                puts("wmenu " VERSION);
                                exit(EXIT_SUCCESS);
       +                case 'x':
       +                        menu->exec = true;
       +                        break;
                        case 'f':
                                menu->font = optarg;
                                break;
       @@ -409,6 +413,53 @@ static void movewordedge(struct menu *menu, int dir) {
                }
        }
        
       +// Information needed to execute an item.
       +struct executable {
       +        struct menu *menu;
       +        char *name;
       +};
       +
       +// Executes an item with an activation token.
       +static void execute(struct executable *exe, const char *token) {
       +        menu_destroy(exe->menu);
       +
       +        setenv("XDG_ACTIVATION_TOKEN", token, true);
       +        execlp(exe->name, exe->name, NULL);
       +
       +        // Handle execution failure
       +        fprintf(stderr, "Failed to execute selection: %s\n", strerror(errno));
       +        free(exe->name);
       +        free(exe);
       +        exit(EXIT_FAILURE);
       +}
       +
       +static void activation_token_done(void *data, struct xdg_activation_token_v1 *activation_token,
       +        const char *token) {
       +        struct executable *exe = data;
       +        xdg_activation_token_v1_destroy(activation_token);
       +        execute(exe, token);
       +}
       +
       +static const struct xdg_activation_token_v1_listener activation_token_listener = {
       +        .done = activation_token_done,
       +};
       +
       +// Executes the selected item.
       +static void menu_exec(struct menu *menu) {
       +        if (!menu->sel) {
       +                return;
       +        }
       +
       +        struct executable *exe = calloc(1, sizeof(struct executable));
       +        exe->menu = menu;
       +        exe->name = strdup(menu->sel->text);
       +
       +        struct xdg_activation_token_v1 *activation_token = xdg_activation_v1_get_activation_token(menu->activation);
       +        xdg_activation_token_v1_set_surface(activation_token, menu->surface);
       +        xdg_activation_token_v1_add_listener(activation_token, &activation_token_listener, exe);
       +        xdg_activation_token_v1_commit(activation_token);
       +}
       +
        // Handle a keypress.
        void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                        xkb_keysym_t sym) {
       @@ -588,6 +639,8 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                                puts(menu->input);
                                fflush(stdout);
                                menu->exit = true;
       +                } else if (menu->exec) {
       +                        menu_exec(menu);
                        } else {
                                char *text = menu->sel ? menu->sel->text : menu->input;
                                puts(text);
       @@ -750,6 +803,7 @@ void menu_destroy(struct menu *menu) {
                wl_data_device_destroy(menu->data_device);
                wl_surface_destroy(menu->surface);
                zwlr_layer_surface_v1_destroy(menu->layer_surface);
       +        xdg_activation_v1_destroy(menu->activation);
        
                free_pages(menu);
                free_items(menu);
 (DIR) diff --git a/menu.h b/menu.h
       @@ -4,6 +4,7 @@
        #include <xkbcommon/xkbcommon.h>
        
        #include "pool-buffer.h"
       +#include "xdg-activation-v1-client-protocol.h"
        
        // A menu item.
        struct item {
       @@ -55,6 +56,8 @@ struct menu {
                int (*strncmp)(const char *, const char *, size_t);
                // Whether the input is a password
                bool passwd;
       +        // Whether to execute the selected item
       +        bool exec;
                // The font used to display the menu
                char *font;
                // The number of lines to list items vertically
       @@ -78,6 +81,7 @@ struct menu {
                struct wl_data_device_manager *data_device_manager;
                struct zwlr_layer_shell_v1 *layer_shell;
                struct output *output_list;
       +        struct xdg_activation_v1 *activation;
        
                struct keyboard *keyboard;
                struct wl_data_device *data_device;
 (DIR) diff --git a/protocols/meson.build b/protocols/meson.build
       @@ -12,6 +12,7 @@ endif
        
        protocols = [
                [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
       +        [wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'],
                ['wlr-layer-shell-unstable-v1.xml'],
        ]
        
 (DIR) diff --git a/wmenu_run b/wmenu_run
       @@ -32,4 +32,4 @@ path() {
                fi
        }
        
       -path | wmenu "$@" | ${SHELL:-"/bin/sh"} &
       +path | wmenu -x "$@"