Add support for launching applications
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
#include <wayland-client.h>
|
||||
|
||||
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);
|
||||
|
||||
+32
@@ -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,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gdesktopappinfo.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
+2
-2
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user