mirror of
https://codeberg.org/adnano/wmenu.git
synced 2025-10-29 05:40:20 -04:00
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:
parent
fc69aa6e2b
commit
65f3093bb3
9 changed files with 47 additions and 118 deletions
|
|
@ -9,6 +9,8 @@ wmenu - dynamic menu for Wayland
|
||||||
*wmenu* [-biPv] \
|
*wmenu* [-biPv] \
|
||||||
[-f _font_] \
|
[-f _font_] \
|
||||||
[-l _lines_] \
|
[-l _lines_] \
|
||||||
|
[-g _height_] \
|
||||||
|
[-w _width_] \
|
||||||
[-o _output_] \
|
[-o _output_] \
|
||||||
[-p _prompt_] \
|
[-p _prompt_] \
|
||||||
[-N _color_] [-n _color_] \
|
[-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
|
is printed to stdout and wmenu terminates. Entering text will narrow the items
|
||||||
to those matching the tokens in the input.
|
to those matching the tokens in the input.
|
||||||
|
|
||||||
*wmenu-run* is a special invocation of wmenu which lists programs in the user's
|
*wmenu-run* is a special script which lists programs in the user's
|
||||||
$PATH and runs the result.
|
$PATH and runs the result with the main *wmenu* executable.
|
||||||
|
|
||||||
# OPTIONS
|
# OPTIONS
|
||||||
|
|
||||||
|
|
@ -49,6 +51,12 @@ $PATH and runs the result.
|
||||||
*-l* _lines_
|
*-l* _lines_
|
||||||
wmenu lists items vertically, with the given number of 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_
|
*-o* _output_
|
||||||
wmenu is displayed on the output with the given name.
|
wmenu is displayed on the output with the given name.
|
||||||
|
|
||||||
|
|
|
||||||
3
install-wmenu-run.sh
Executable file
3
install-wmenu-run.sh
Executable file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cp ../wmenu-run /usr/local/bin/
|
||||||
21
menu.c
21
menu.c
|
|
@ -27,6 +27,7 @@ struct menu *menu_create(menu_callback callback) {
|
||||||
struct menu *menu = calloc(1, sizeof(struct menu));
|
struct menu *menu = calloc(1, sizeof(struct menu));
|
||||||
menu->strncmp = strncmp;
|
menu->strncmp = strncmp;
|
||||||
menu->font = "monospace 10";
|
menu->font = "monospace 10";
|
||||||
|
menu->line_height = get_font_height(menu->font) + 2;
|
||||||
menu->normalbg = 0x222222ff;
|
menu->normalbg = 0x222222ff;
|
||||||
menu->normalfg = 0xbbbbbbff;
|
menu->normalfg = 0xbbbbbbff;
|
||||||
menu->promptbg = 0x005577ff;
|
menu->promptbg = 0x005577ff;
|
||||||
|
|
@ -85,11 +86,14 @@ static bool parse_color(const char *color, uint32_t *result) {
|
||||||
// Parse menu options from command line arguments.
|
// Parse menu options from command line arguments.
|
||||||
void menu_getopts(struct menu *menu, int argc, char *argv[]) {
|
void menu_getopts(struct menu *menu, int argc, char *argv[]) {
|
||||||
const char *usage =
|
const char *usage =
|
||||||
"Usage: wmenu [-biPv] [-f font] [-l lines] [-o output] [-p prompt]\n"
|
"Usage: wmenu [-biPv] [-f font] [-l lines] [-g height] [-w width] [-o output]\n"
|
||||||
"\t[-N color] [-n color] [-M color] [-m color] [-S color] [-s color]\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;
|
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) {
|
switch (opt) {
|
||||||
case 'b':
|
case 'b':
|
||||||
menu->bottom = true;
|
menu->bottom = true;
|
||||||
|
|
@ -109,6 +113,13 @@ void menu_getopts(struct menu *menu, int argc, char *argv[]) {
|
||||||
case 'l':
|
case 'l':
|
||||||
menu->lines = atoi(optarg);
|
menu->lines = atoi(optarg);
|
||||||
break;
|
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':
|
case 'o':
|
||||||
menu->output_name = optarg;
|
menu->output_name = optarg;
|
||||||
break;
|
break;
|
||||||
|
|
@ -156,13 +167,11 @@ void menu_getopts(struct menu *menu, int argc, char *argv[]) {
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int height = get_font_height(menu->font);
|
|
||||||
menu->line_height = height + 2;
|
|
||||||
menu->height = menu->line_height;
|
menu->height = menu->line_height;
|
||||||
if (menu->lines > 0) {
|
if (menu->lines > 0) {
|
||||||
menu->height += menu->height * menu->lines;
|
menu->height += menu->height * menu->lines;
|
||||||
}
|
}
|
||||||
menu->padding = height / 2;
|
menu->padding = get_font_height(menu->font) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add an item to the menu.
|
// Add an item to the menu.
|
||||||
|
|
|
||||||
2
menu.h
2
menu.h
|
|
@ -59,6 +59,8 @@ struct menu {
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int line_height;
|
int line_height;
|
||||||
|
int customwidth;
|
||||||
|
int customheight;
|
||||||
int padding;
|
int padding;
|
||||||
int inputw;
|
int inputw;
|
||||||
int promptw;
|
int promptw;
|
||||||
|
|
|
||||||
35
meson.build
35
meson.build
|
|
@ -21,12 +21,12 @@ add_project_arguments(cc.get_supported_arguments([
|
||||||
'-Wvla',
|
'-Wvla',
|
||||||
]), language : 'c')
|
]), language : 'c')
|
||||||
|
|
||||||
cairo = dependency('cairo')
|
cairo = dependency('cairo')
|
||||||
pango = dependency('pango')
|
pango = dependency('pango')
|
||||||
pangocairo = dependency('pangocairo')
|
pangocairo = dependency('pangocairo')
|
||||||
wayland_client = dependency('wayland-client')
|
wayland_client = dependency('wayland-client')
|
||||||
wayland_protos = dependency('wayland-protocols')
|
wayland_protos = dependency('wayland-protocols')
|
||||||
xkbcommon = dependency('xkbcommon')
|
xkbcommon = dependency('xkbcommon')
|
||||||
|
|
||||||
rt = cc.find_library('rt')
|
rt = cc.find_library('rt')
|
||||||
|
|
||||||
|
|
@ -56,25 +56,4 @@ executable(
|
||||||
install: true,
|
install: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
executable(
|
meson.add_install_script('install-wmenu-run.sh')
|
||||||
'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,
|
|
||||||
)
|
|
||||||
|
|
|
||||||
6
render.c
6
render.c
|
|
@ -106,7 +106,7 @@ static void render_input(struct menu *menu, cairo_t *cairo) {
|
||||||
// Renders a cursor for the input field.
|
// Renders a cursor for the input field.
|
||||||
static void render_cursor(struct menu *menu, cairo_t *cairo) {
|
static void render_cursor(struct menu *menu, cairo_t *cairo) {
|
||||||
const int cursor_width = 2;
|
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
|
int cursor_pos = menu->promptw + menu->padding
|
||||||
+ text_width(cairo, menu->font, menu->input)
|
+ text_width(cairo, menu->font, menu->input)
|
||||||
- text_width(cairo, menu->font, &menu->input[menu->cursor])
|
- 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
|
// Draw left and right scroll indicators if necessary
|
||||||
if (page->prev) {
|
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, "<");
|
pango_printf(cairo, menu->font, 1, "<");
|
||||||
}
|
}
|
||||||
if (page->next) {
|
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, ">");
|
pango_printf(cairo, menu->font, 1, ">");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,11 @@ static void layer_surface_configure(void *data,
|
||||||
struct zwlr_layer_surface_v1 *surface,
|
struct zwlr_layer_surface_v1 *surface,
|
||||||
uint32_t serial, uint32_t width, uint32_t height) {
|
uint32_t serial, uint32_t width, uint32_t height) {
|
||||||
struct wl_context *context = data;
|
struct wl_context *context = data;
|
||||||
context->menu->width = width;
|
if (context->menu->customwidth > 0) {
|
||||||
|
context->menu->width = context->menu->customwidth;
|
||||||
|
} else {
|
||||||
|
context->menu->width = width;
|
||||||
|
}
|
||||||
context->menu->height = height;
|
context->menu->height = height;
|
||||||
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
zwlr_layer_surface_v1_ack_configure(surface, serial);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
wmenu-run
Executable file
2
wmenu-run
Executable file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#!/bin/sh
|
||||||
|
compgen -c | sort | wmenu "$@" | sh
|
||||||
78
wmenu-run.c
78
wmenu-run.c
|
|
@ -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;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue