Add wmenu-run executable - 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 41e8599392a543a537f15447e20fd7bc8d8f2297
 (DIR) parent 1f221a73cf290ff509ef6c066ff692bb48f8625e
 (HTM) Author: adnano <me@adnano.co>
       Date:   Thu,  2 May 2024 21:39:54 -0400
       
       Add wmenu-run executable
       
       Diffstat:
         M menu.c                              |       2 ++
         M menu.h                              |       1 +
         M meson.build                         |      25 ++++++++++++++++++++++++-
         M wayland.c                           |       5 +++++
         M wayland.h                           |       1 +
         A wmenu-run.c                         |      70 +++++++++++++++++++++++++++++++
         R main.c -> wmenu.c                   |       0 
       
       7 files changed, 103 insertions(+), 1 deletion(-)
       ---
 (DIR) diff --git a/menu.c b/menu.c
       @@ -529,6 +529,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->callback) {
       +                        menu->callback(menu);
                        } else {
                                char *text = menu->sel ? menu->sel->text : menu->input;
                                puts(text);
 (DIR) diff --git a/menu.h b/menu.h
       @@ -68,6 +68,7 @@ struct menu {
                struct item *sel;         // selected item
                struct page *pages;       // list of pages
        
       +        void (*callback)(struct menu *menu);
                bool exit;
                bool failure;
        };
 (DIR) diff --git a/meson.build b/meson.build
       @@ -38,12 +38,35 @@ install_data('wmenu_run', install_dir: get_option('bindir'))
        executable(
                'wmenu',
                files(
       -                'main.c',
                        'menu.c',
                        'pango.c',
                        'pool-buffer.c',
                        'render.c',
                        'wayland.c',
       +                'wmenu.c',
       +        ),
       +        dependencies: [
       +                cairo,
       +                client_protos,
       +                pango,
       +                pangocairo,
       +                rt,
       +                wayland_client,
       +                wayland_protos,
       +                xkbcommon,
       +        ],
       +        install: true,
       +)
       +
       +executable(
       +        'wmenu-run',
       +        files(
       +                'menu.c',
       +                'pango.c',
       +                'pool-buffer.c',
       +                'render.c',
       +                'wayland.c',
       +                'wmenu-run.c',
                ),
                dependencies: [
                        cairo,
 (DIR) diff --git a/wayland.c b/wayland.c
       @@ -128,6 +128,11 @@ struct xkb_state *context_get_xkb_state(struct wl_context *context) {
                return context->keyboard->state;
        }
        
       +// Returns the XDG activation object for the context.
       +struct xdg_activation_v1 *context_get_xdg_activation(struct wl_context *context) {
       +        return context->activation;
       +}
       +
        // Retrieves pasted text from a Wayland data offer.
        bool context_paste(struct wl_context *context) {
                if (!context->data_offer) {
 (DIR) diff --git a/wayland.h b/wayland.h
       @@ -13,6 +13,7 @@ struct pool_buffer *context_get_current_buffer(struct wl_context *context);
        struct pool_buffer *context_get_next_buffer(struct wl_context *context, int scale);
        struct wl_surface *context_get_surface(struct wl_context *context);
        struct xkb_state *context_get_xkb_state(struct wl_context *context);
       +struct xdg_activation_v1 *context_get_xdg_activation(struct wl_context *context);
        bool context_paste(struct wl_context *context);
        
        #endif
 (DIR) diff --git a/wmenu-run.c b/wmenu-run.c
       @@ -0,0 +1,70 @@
       +#define _POSIX_C_SOURCE 200809L
       +#include <errno.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <unistd.h>
       +
       +#include "menu.h"
       +#include "wayland.h"
       +#include "xdg-activation-v1-client-protocol.h"
       +
       +static void read_items(struct menu *menu) {
       +        char buf[sizeof menu->input];
       +        while (fgets(buf, sizeof buf, stdin)) {
       +                char *p = strchr(buf, '\n');
       +                if (p) {
       +                        *p = '\0';
       +                }
       +                menu_add_item(menu, strdup(buf));
       +        }
       +}
       +
       +struct executable {
       +        struct menu *menu;
       +        char *name;
       +};
       +
       +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);
       +        menu_destroy(exe->menu);
       +
       +        setenv("XDG_ACTIVATION_TOKEN", token, true);
       +        execlp(exe->name, exe->name, NULL);
       +
       +        fprintf(stderr, "Failed to execute selection: %s\n", strerror(errno));
       +        free(exe->name);
       +        free(exe);
       +        exit(EXIT_FAILURE);
       +}
       +
       +static const struct xdg_activation_token_v1_listener activation_token_listener = {
       +        .done = activation_token_done,
       +};
       +
       +static void 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_v1 *activation = context_get_xdg_activation(menu->context);
       +        struct xdg_activation_token_v1 *activation_token = xdg_activation_v1_get_activation_token(activation);
       +        xdg_activation_token_v1_set_surface(activation_token, context_get_surface(menu->context));
       +        xdg_activation_token_v1_add_listener(activation_token, &activation_token_listener, exe);
       +        xdg_activation_token_v1_commit(activation_token);
       +}
       +
       +int main(int argc, char *argv[]) {
       +        struct menu *menu = menu_create();
       +        menu->callback = exec;
       +        menu_getopts(menu, argc, argv);
       +        read_items(menu);
       +        int status = menu_run(menu);
       +        menu_destroy(menu);
       +        return status;
       +}
 (DIR) diff --git a/main.c b/wmenu.c