Main commit; add features, remove wmenu-run.c, create wmenu-run script and update all docs and build system files.

This commit is contained in:
moonsabre 2025-03-09 18:56:33 -07:00
parent fc69aa6e2b
commit 65f3093bb3
9 changed files with 47 additions and 118 deletions

View file

@ -9,6 +9,8 @@ wmenu - dynamic menu for Wayland
*wmenu* [-biPv] \
[-f _font_] \
[-l _lines_] \
[-g _height_] \
[-w _width_] \
[-o _output_] \
[-p _prompt_] \
[-N _color_] [-n _color_] \
@ -24,8 +26,8 @@ items from stdin. When the user selects an item and presses Return, their choice
is printed to stdout and wmenu terminates. Entering text will narrow the items
to those matching the tokens in the input.
*wmenu-run* is a special invocation of wmenu which lists programs in the user's
$PATH and runs the result.
*wmenu-run* is a special script which lists programs in the user's
$PATH and runs the result with the main *wmenu* executable.
# OPTIONS
@ -49,6 +51,12 @@ $PATH and runs the result.
*-l* _lines_
wmenu lists items vertically, with the given number of lines.
*-g* _height_
this value will be added to the height of each line.
*-w* _width_
the width of the window will be constrained to this value.
*-o* _output_
wmenu is displayed on the output with the given name.

3
install-wmenu-run.sh Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
cp ../wmenu-run /usr/local/bin/

21
menu.c
View file

@ -27,6 +27,7 @@ struct menu *menu_create(menu_callback callback) {
struct menu *menu = calloc(1, sizeof(struct menu));
menu->strncmp = strncmp;
menu->font = "monospace 10";
menu->line_height = get_font_height(menu->font) + 2;
menu->normalbg = 0x222222ff;
menu->normalfg = 0xbbbbbbff;
menu->promptbg = 0x005577ff;
@ -85,11 +86,14 @@ 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"
"\t[-N color] [-n color] [-M color] [-m color] [-S color] [-s color]\n";
"Usage: wmenu [-biPv] [-f font] [-l lines] [-g height] [-w width] [-o output]\n"
"\t[-p prompt] [-N color] [-n color] [-M color] [-m color] [-S color] [-s color]\n";
menu->customwidth = 0;
menu->customheight = 0;
int opt;
while ((opt = getopt(argc, argv, "bhiPvf:l:o:p:N:n:M:m:S:s:")) != -1) {
while ((opt = getopt(argc, argv, "bhiPvf:l:g:w:o:p:N:n:M:m:S:s:")) != -1) {
switch (opt) {
case 'b':
menu->bottom = true;
@ -109,6 +113,13 @@ void menu_getopts(struct menu *menu, int argc, char *argv[]) {
case 'l':
menu->lines = atoi(optarg);
break;
case 'g':
menu->customheight = atoi(optarg);
menu->line_height = get_font_height(menu->font) + menu->customheight;
break;
case 'w':
menu->customwidth = atoi(optarg);
break;
case 'o':
menu->output_name = optarg;
break;
@ -156,13 +167,11 @@ void menu_getopts(struct menu *menu, int argc, char *argv[]) {
exit(EXIT_FAILURE);
}
int height = get_font_height(menu->font);
menu->line_height = height + 2;
menu->height = menu->line_height;
if (menu->lines > 0) {
menu->height += menu->height * menu->lines;
}
menu->padding = height / 2;
menu->padding = get_font_height(menu->font) / 2;
}
// Add an item to the menu.

2
menu.h
View file

@ -59,6 +59,8 @@ struct menu {
int width;
int height;
int line_height;
int customwidth;
int customheight;
int padding;
int inputw;
int promptw;

View file

@ -56,25 +56,4 @@ executable(
install: true,
)
executable(
'wmenu-run',
files(
'menu.c',
'pango.c',
'pool-buffer.c',
'render.c',
'wayland.c',
'wmenu-run.c',
),
dependencies: [
cairo,
client_protos,
pango,
pangocairo,
rt,
wayland_client,
wayland_protos,
xkbcommon,
],
install: true,
)
meson.add_install_script('install-wmenu-run.sh')

View file

@ -106,7 +106,7 @@ static void render_input(struct menu *menu, cairo_t *cairo) {
// Renders a cursor for the input field.
static void render_cursor(struct menu *menu, cairo_t *cairo) {
const int cursor_width = 2;
const int cursor_margin = 2;
const int cursor_margin = menu->line_height / 5;
int cursor_pos = menu->promptw + menu->padding
+ text_width(cairo, menu->font, menu->input)
- text_width(cairo, menu->font, &menu->input[menu->cursor])
@ -144,11 +144,11 @@ static void render_horizontal_page(struct menu *menu, cairo_t *cairo, struct pag
// Draw left and right scroll indicators if necessary
if (page->prev) {
cairo_move_to(cairo, menu->promptw + menu->inputw + menu->padding, 0);
cairo_move_to(cairo, menu->promptw + menu->inputw + menu->padding, menu->customheight / 2);
pango_printf(cairo, menu->font, 1, "<");
}
if (page->next) {
cairo_move_to(cairo, menu->width - menu->right_arrow + menu->padding, 0);
cairo_move_to(cairo, menu->width - menu->right_arrow + menu->padding, menu->customheight / 2);
pango_printf(cairo, menu->font, 1, ">");
}
}

View file

@ -220,7 +220,11 @@ static void layer_surface_configure(void *data,
struct zwlr_layer_surface_v1 *surface,
uint32_t serial, uint32_t width, uint32_t height) {
struct wl_context *context = data;
if (context->menu->customwidth > 0) {
context->menu->width = context->menu->customwidth;
} else {
context->menu->width = width;
}
context->menu->height = height;
zwlr_layer_surface_v1_ack_configure(surface, serial);
}

2
wmenu-run Executable file
View file

@ -0,0 +1,2 @@
#!/bin/sh
compgen -c | sort | wmenu "$@" | sh

View file

@ -1,78 +0,0 @@
#define _POSIX_C_SOURCE 200809L
#include <dirent.h>
#include <stdio.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 *path = strdup(getenv("PATH"));
for (char *p = strtok(path, ":"); p != NULL; p = strtok(NULL, ":")) {
DIR *dir = opendir(p);
if (dir == NULL) {
continue;
}
for (struct dirent *ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
if (ent->d_name[0] == '.') {
continue;
}
menu_add_item(menu, strdup(ent->d_name));
}
closedir(dir);
}
menu_sort_and_deduplicate(menu);
free(path);
}
struct command {
struct menu *menu;
char *text;
bool exit;
};
static void activation_token_done(void *data, struct xdg_activation_token_v1 *activation_token,
const char *token) {
struct command *cmd = data;
xdg_activation_token_v1_destroy(activation_token);
int pid = fork();
if (pid == 0) {
setenv("XDG_ACTIVATION_TOKEN", token, true);
char *argv[] = {"/bin/sh", "-c", cmd->text, NULL};
execvp(argv[0], (char**)argv);
} else {
if (cmd->exit) {
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, bool exit) {
struct command *cmd = calloc(1, sizeof(struct command));
cmd->menu = menu;
cmd->text = strdup(text);
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_items(menu);
int status = menu_run(menu);
menu_destroy(menu);
return status;
}