Revive menu patch

This commit is contained in:
Nikita Ivanov 2024-05-18 23:29:20 +02:00
parent c29d2464da
commit 611c9f5744
No known key found for this signature in database
GPG Key ID: 6E656AC5B97B5133
2 changed files with 233 additions and 3 deletions

View File

@ -6,10 +6,10 @@ By default, two menus are available:
- focusing a window by its title by pressing `Alt+o`
- selecting a layout from a list by pressing `Alt+Shift+o`
Edit `menus` array and `MENU` macro in `config.h` to add/change menus and use a different dmenu program.
Edit `menus` array in `config.h` to add/change menus and use a different dmenu program.
### Download
- [2023-07-15](https://github.com/djpohly/dwl/compare/main...NikitaIvanovV:menu.patch)
- [2024-05-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/menu/menu.patch)
### Authors
- [Nikita Ivanov](https://github.com/NikitaIvanovV)
- [Nikita Ivanov](https://github.com/NikitaIvanovV)

230
patches/menu/menu.patch Normal file
View File

@ -0,0 +1,230 @@
commit 63bfca78aab30c6aed18bdbab86cee356b6292f0
Author: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
Date: Sat May 18 19:27:05 2024 +0200
Add menu command
diff --git a/config.def.h b/config.def.h
index 8f498d2..e7c7654 100644
--- a/config.def.h
+++ b/config.def.h
@@ -20,6 +20,12 @@ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You ca
/* logging */
static int log_level = WLR_ERROR;
+static const Menu menus[] = {
+ /* command feed function action function */
+ { "wmenu -i -l 5 -p Windows", menuwinfeed, menuwinaction },
+ { "wmenu -i -p Layouts", menulayoutfeed, menulayoutaction },
+};
+
static const Rule rules[] = {
/* app_id title tags mask isfloating monitor */
/* examples: */
@@ -135,6 +141,8 @@ static const Key keys[] = {
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
{ MODKEY, XKB_KEY_space, setlayout, {0} },
+ { MODKEY, XKB_KEY_o, menu, {.v = &menus[0]} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, menu, {.v = &menus[1]} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
diff --git a/dwl.c b/dwl.c
index bf763df..7adaccc 100644
--- a/dwl.c
+++ b/dwl.c
@@ -239,6 +239,12 @@ typedef struct {
struct wl_listener destroy;
} SessionLock;
+typedef struct {
+ const char *cmd; /* command to run a menu */
+ void (*feed)(FILE *f); /* feed input to menu */
+ void (*action)(char *line); /* do action based on menu output */
+} Menu;
+
/* function declarations */
static void applybounds(Client *c, struct wlr_box *bbox);
static void applyrules(Client *c);
@@ -295,6 +301,12 @@ static void locksession(struct wl_listener *listener, void *data);
static void maplayersurfacenotify(struct wl_listener *listener, void *data);
static void mapnotify(struct wl_listener *listener, void *data);
static void maximizenotify(struct wl_listener *listener, void *data);
+static void menu(const Arg *arg);
+static int menuloop(void *data);
+static void menuwinfeed(FILE *f);
+static void menuwinaction(char *line);
+static void menulayoutfeed(FILE *f);
+static void menulayoutaction(char *line);
static void monocle(Monitor *m);
static void motionabsolute(struct wl_listener *listener, void *data);
static void motionnotify(uint32_t time, struct wlr_input_device *device, double sx,
@@ -405,6 +417,11 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static struct wl_event_source *menu_source;
+static pid_t menu_pid;
+static int menu_fd;
+static const Menu *menu_current;
+
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
@@ -659,6 +676,7 @@ cleanup(void)
wlr_xwayland_destroy(xwayland);
xwayland = NULL;
#endif
+ wl_event_source_remove(menu_source);
wl_display_destroy_clients(dpy);
if (child_pid > 0) {
kill(child_pid, SIGTERM);
@@ -1645,6 +1663,136 @@ maximizenotify(struct wl_listener *listener, void *data)
wlr_xdg_surface_schedule_configure(c->surface.xdg);
}
+void
+menu(const Arg *arg)
+{
+ FILE *f;
+ pid_t pid;
+ int fd_right[2], fd_left[2];
+
+ if (!selmon || menu_pid != 0)
+ return;
+
+ menu_current = arg->v;
+
+ if (pipe(fd_right) == -1 || pipe(fd_left) == -1)
+ return;
+ if ((pid = fork()) == -1)
+ return;
+ if (pid == 0) {
+ close(fd_right[1]);
+ close(fd_left[0]);
+ dup2(fd_right[0], STDIN_FILENO);
+ close(fd_right[0]);
+ dup2(fd_left[1], STDOUT_FILENO);
+ close(fd_left[1]);
+
+ execl("/bin/sh", "/bin/sh", "-c", menu_current->cmd, NULL);
+ die("dwl: execl %s failed:", "/bin/sh");
+ }
+
+ close(fd_right[0]);
+ close(fd_left[1]);
+
+ if (!(f = fdopen(fd_right[1], "w")))
+ return;
+ menu_current->feed(f);
+ fclose(f);
+
+ menu_pid = pid;
+ menu_fd = fd_left[0];
+ wl_event_source_timer_update(menu_source, 10);
+}
+
+int
+menuloop(void *data)
+{
+ FILE *f;
+ pid_t pid;
+ char line[256], *s;
+
+ /* If process is still running, wait for another 50 ms */
+ if ((pid = waitpid(menu_pid, NULL, WNOHANG)) == 0) {
+ wl_event_source_timer_update(menu_source, 10);
+ return 0;
+ }
+
+ menu_pid = 0;
+
+ if (!(f = fdopen(menu_fd, "r")))
+ return 0;
+ if (fgets(line, sizeof(line), f)) {
+ if ((s = strchr(line, '\n')))
+ *s = '\0';
+ menu_current->action(line);
+ }
+ fclose(f);
+ return 0;
+}
+
+void
+menuwinfeed(FILE *f)
+{
+ Client *c;
+ const char *title;
+
+ wl_list_for_each(c, &fstack, flink) {
+ if (!(title = client_get_title(c)))
+ continue;
+ fprintf(f, "%s\n", title);
+ }
+}
+
+void
+menuwinaction(char *line)
+{
+ Client *c;
+ Monitor *prevm = selmon;
+ const char *title;
+
+ if (!selmon)
+ return;
+
+ wl_list_for_each(c, &fstack, flink) {
+ if (!(title = client_get_title(c)))
+ continue;
+ if (strcmp(line, title) == 0)
+ goto found;
+ }
+ return;
+
+found:
+ focusclient(c, 1);
+ wlr_cursor_move(cursor, NULL, selmon->m.x - prevm->m.x , 0);
+ selmon->seltags ^= 1; /* toggle sel tagset */
+ selmon->tagset[selmon->seltags] = c->tags;
+ arrange(selmon);
+ printstatus();
+}
+
+void
+menulayoutfeed(FILE *f)
+{
+ unsigned int i;
+ for (i = 0; i < LENGTH(layouts); i++)
+ fprintf(f, "%s\n", layouts[i].symbol);
+}
+
+void
+menulayoutaction(char *line)
+{
+ unsigned int i;
+ Arg a;
+ for (i = 0; i < LENGTH(layouts); i++)
+ if (strcmp(line, layouts[i].symbol) == 0)
+ goto found;
+ return;
+
+found:
+ a.v = &layouts[i];
+ setlayout(&a);
+}
+
void
monocle(Monitor *m)
{
@@ -2510,6 +2658,10 @@ setup(void)
* e.g when running in the x11 backend or the wayland backend and the
* compositor has Xwayland support */
unsetenv("DISPLAY");
+
+ menu_source = wl_event_loop_add_timer(
+ wl_display_get_event_loop(dpy), menuloop, NULL);
+
#ifdef XWAYLAND
/*
* Initialise the XWayland X server.