From c5fdd0b0b867e06f143023153d77f3574566957b Mon Sep 17 00:00:00 2001 From: Vegard Matthey Date: Sun, 12 Jan 2025 01:09:24 +0100 Subject: [PATCH] Add support for launching applications --- menu.c | 10 +++++--- menu.h | 5 ++-- meson.build | 32 ++++++++++++++++++++++++ wmenu-drun.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++ wmenu-run.c | 4 +-- wmenu.c | 4 +-- 6 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 wmenu-drun.c diff --git a/menu.c b/menu.c index 9bda76c..49254b3 100644 --- a/menu.c +++ b/menu.c @@ -166,7 +166,7 @@ void menu_getopts(struct menu *menu, int argc, char *argv[]) { } // Add an item to the menu. -void menu_add_item(struct menu *menu, char *text) { +void menu_add_item(struct menu *menu, char *text, void *app_info) { if ((menu->item_count & (menu->item_count - 1)) == 0) { size_t alloc_size = menu->item_count ? 2 * menu->item_count : 1; void *new_array = realloc(menu->items, sizeof(struct item) * alloc_size); @@ -179,6 +179,7 @@ void menu_add_item(struct menu *menu, char *text) { struct item *new = &menu->items[menu->item_count]; new->text = text; + new->app_info = app_info; menu->item_count++; } @@ -380,6 +381,9 @@ static void match_items(struct menu *menu) { void menu_render_items(struct menu *menu) { calc_widths(menu); match_items(menu); + if (!(menu->width) || !(menu->height)) { + return; + } render_menu(menu); } @@ -581,10 +585,10 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state, case XKB_KEY_Return: case XKB_KEY_KP_Enter: if (shift) { - menu->callback(menu, menu->input, true); + menu->callback(menu, menu->input, menu->sel->app_info, true); } else { char *text = menu->sel ? menu->sel->text : menu->input; - menu->callback(menu, text, !ctrl); + menu->callback(menu, text, menu->sel->app_info, !ctrl); } break; case XKB_KEY_Left: diff --git a/menu.h b/menu.h index 8dcd99c..966990e 100644 --- a/menu.h +++ b/menu.h @@ -8,11 +8,12 @@ #include struct menu; -typedef void (*menu_callback)(struct menu *menu, char *text, bool exit); +typedef void (*menu_callback)(struct menu *menu, char *text, void *cmd, bool exit); // A menu item. struct item { char *text; + void *app_info; int width; struct item *prev_match; // previous matching item struct item *next_match; // next matching item @@ -83,7 +84,7 @@ struct menu { struct menu *menu_create(menu_callback callback); void menu_destroy(struct menu *menu); void menu_getopts(struct menu *menu, int argc, char *argv[]); -void menu_add_item(struct menu *menu, char *text); +void menu_add_item(struct menu *menu, char *text, void *app_info); void menu_sort_and_deduplicate(struct menu *menu); void menu_render_items(struct menu *menu); void menu_paste(struct menu *menu, const char *text, ssize_t len); diff --git a/meson.build b/meson.build index a3b507d..fc39f37 100644 --- a/meson.build +++ b/meson.build @@ -19,6 +19,7 @@ add_project_arguments(cc.get_supported_arguments([ '-Wno-unused-parameter', '-Wundef', '-Wvla', + '-Wno-discarded-qualifiers' ]), language : 'c') cairo = dependency('cairo') @@ -27,6 +28,8 @@ pangocairo = dependency('pangocairo') wayland_client = dependency('wayland-client') wayland_protos = dependency('wayland-protocols') xkbcommon = dependency('xkbcommon') +glib = dependency('glib-2.0') +gio_unix = dependency('gio-unix-2.0') rt = cc.find_library('rt') @@ -52,6 +55,8 @@ executable( wayland_client, wayland_protos, xkbcommon, + glib, + gio_unix, ], install: true, ) @@ -75,6 +80,33 @@ executable( wayland_client, wayland_protos, xkbcommon, + glib, + gio_unix, + ], + install: true, +) + +executable( + 'wmenu-drun', + files( + 'menu.c', + 'pango.c', + 'pool-buffer.c', + 'render.c', + 'wayland.c', + 'wmenu-drun.c', + ), + dependencies: [ + cairo, + client_protos, + pango, + pangocairo, + rt, + wayland_client, + wayland_protos, + xkbcommon, + glib, + gio_unix, ], install: true, ) diff --git a/wmenu-drun.c b/wmenu-drun.c new file mode 100644 index 0000000..065ee4e --- /dev/null +++ b/wmenu-drun.c @@ -0,0 +1,70 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include + +#include "menu.h" +#include "wayland.h" +#include "xdg-activation-v1-client-protocol.h" + +static void read_desktop_items(struct menu *menu) { + GList* list = g_app_info_get_all(); + GList* item; + for(item = list; item; item = item->next) { + if (g_app_info_should_show(item->data) == FALSE) { + continue; + } + const char *name = g_app_info_get_name(item->data); + menu_add_item(menu, name, item->data); + } + menu_sort_and_deduplicate(menu); +} + +struct command { + struct menu *menu; + GAppInfo *app_info; + bool exit; +}; + +static void activation_token_done(void *data, struct xdg_activation_token_v1 *activation_token, + const char *token) { + struct command *cmd = data; + GAppLaunchContext *context = g_app_launch_context_new(); // Not strictly necessary. + g_app_info_launch(cmd->app_info, NULL, context, NULL); + setenv("XDG_ACTIVATION_TOKEN", token, true); + xdg_activation_token_v1_destroy(activation_token); + cmd->menu->exit = true; +} + +static const struct xdg_activation_token_v1_listener activation_token_listener = { + .done = activation_token_done, +}; + +static void exec_item(struct menu *menu, char *text, void *app_info, bool exit) { + struct command *cmd = calloc(1, sizeof(struct command)); + cmd->menu = menu; + cmd->app_info = (GAppInfo*)app_info; + if (cmd->app_info == NULL) { + printf("app info is nil\n"); + } + cmd->exit = exit; + + 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, cmd); + xdg_activation_token_v1_commit(activation_token); +} + +int main(int argc, char *argv[]) { + struct menu *menu = menu_create(exec_item); + menu_getopts(menu, argc, argv); + read_desktop_items(menu); + int status = menu_run(menu); + menu_destroy(menu); + return status; +} diff --git a/wmenu-run.c b/wmenu-run.c index 1b7b8c1..e088ab5 100644 --- a/wmenu-run.c +++ b/wmenu-run.c @@ -20,7 +20,7 @@ static void read_items(struct menu *menu) { if (ent->d_name[0] == '.') { continue; } - menu_add_item(menu, strdup(ent->d_name)); + menu_add_item(menu, strdup(ent->d_name), NULL); } closedir(dir); } @@ -55,7 +55,7 @@ static const struct xdg_activation_token_v1_listener activation_token_listener = .done = activation_token_done, }; -static void exec_item(struct menu *menu, char *text, bool exit) { +static void exec_item(struct menu *menu, char *text, void *app_info, bool exit) { struct command *cmd = calloc(1, sizeof(struct command)); cmd->menu = menu; cmd->text = strdup(text); diff --git a/wmenu.c b/wmenu.c index 38e78b9..04d07a9 100644 --- a/wmenu.c +++ b/wmenu.c @@ -13,11 +13,11 @@ static void read_items(struct menu *menu) { if (p) { *p = '\0'; } - menu_add_item(menu, strdup(buf)); + menu_add_item(menu, strdup(buf), NULL); } } -static void print_item(struct menu *menu, char *text, bool exit) { +static void print_item(struct menu *menu, char *text, void *app_info, bool exit) { puts(text); fflush(stdout); if (exit) {