summaryrefslogtreecommitdiffstats
path: root/dwl-patches/patches/menu/menu.patch
diff options
context:
space:
mode:
Diffstat (limited to 'dwl-patches/patches/menu/menu.patch')
-rw-r--r--dwl-patches/patches/menu/menu.patch227
1 files changed, 227 insertions, 0 deletions
diff --git a/dwl-patches/patches/menu/menu.patch b/dwl-patches/patches/menu/menu.patch
new file mode 100644
index 0000000..c1dea4d
--- /dev/null
+++ b/dwl-patches/patches/menu/menu.patch
@@ -0,0 +1,227 @@
+From da9861cf0448ca94011470634fd61c3ef2129a25 Mon Sep 17 00:00:00 2001
+From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com>
+Date: Fri, 21 Mar 2025 21:48:42 +0100
+Subject: [PATCH] Add menu command
+
+---
+ config.def.h | 8 +++
+ dwl.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 164 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index 22d2171..a5914ca 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 10 -p Windows", menuwinfeed, menuwinaction },
++ { "wmenu -i -p Layouts", menulayoutfeed, menulayoutaction },
++};
++
+ /* NOTE: ALWAYS keep a rule declared even if you don't use rules (e.g leave at least one example) */
+ static const Rule rules[] = {
+ /* app_id title tags mask isfloating monitor */
+@@ -140,6 +146,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 def2562..b0e8310 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -242,6 +242,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);
+@@ -302,6 +308,12 @@ static void killclient(const Arg *arg);
+ static void locksession(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 menuread(int fd, uint32_t mask, 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,
+@@ -413,6 +425,11 @@ static struct wlr_box sgeom;
+ static struct wl_list mons;
+ static Monitor *selmon;
+
++static const Menu *menu_current;
++static int menu_fd;
++static pid_t menu_pid;
++static struct wl_event_source *menu_source;
++
+ #ifdef XWAYLAND
+ static void activatex11(struct wl_listener *listener, void *data);
+ static void associatex11(struct wl_listener *listener, void *data);
+@@ -1768,6 +1785,145 @@ maximizenotify(struct wl_listener *listener, void *data)
+ wlr_xdg_surface_schedule_configure(c->surface.xdg);
+ }
+
++void
++menu(const Arg *arg)
++{
++ FILE *f;
++ int fd_right[2], fd_left[2];
++
++ if (menu_current != NULL) {
++ wl_event_source_remove(menu_source);
++ close(menu_fd);
++ kill(menu_pid, SIGTERM);
++ menu_current = NULL;
++ if (!arg->v)
++ return;
++ }
++
++ if (pipe(fd_right) == -1 || pipe(fd_left) == -1)
++ return;
++ if ((menu_pid = fork()) == -1)
++ return;
++ if (menu_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 *)(arg->v))->cmd, NULL);
++ die("dwl: execl %s failed:", "/bin/sh");
++ }
++
++ close(fd_right[0]);
++ close(fd_left[1]);
++ menu_fd = fd_left[0];
++ if (fd_set_nonblock(menu_fd) == -1)
++ return;
++ if (!(f = fdopen(fd_right[1], "w")))
++ return;
++ menu_current = arg->v;
++ menu_current->feed(f);
++ fclose(f);
++ menu_source = wl_event_loop_add_fd(event_loop,
++ menu_fd, WL_EVENT_READABLE, menuread, NULL);
++}
++
++int
++menuread(int fd, uint32_t mask, void *data)
++{
++ char *s;
++ int n;
++ static char line[512];
++ static int i = 0;
++
++ if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
++ i = 0;
++ menu(&(const Arg){ .v = NULL });
++ return 0;
++ }
++ if ((n = read(menu_fd, line + i, LENGTH(line) - 1 - i)) == -1) {
++ if (errno != EAGAIN) {
++ i = 0;
++ menu(&(const Arg){ .v = NULL });
++ }
++ return 0;
++ }
++ line[i + n] = '\0';
++ if (!(s = strchr(line + i, '\n'))) {
++ i += n;
++ return 0;
++ }
++ i = 0;
++ *s = '\0';
++ menu_current->action(line);
++ return 0;
++}
++
++void
++menuwinfeed(FILE *f)
++{
++ Client *c;
++ const char *title, *appid;
++
++ wl_list_for_each(c, &fstack, flink) {
++ if (!(title = client_get_title(c)))
++ continue;
++ fprintf(f, "%s", title);
++ if ((appid = client_get_appid(c)))
++ fprintf(f, " | %s", appid);
++ fputc('\n', f);
++ }
++}
++
++void
++menuwinaction(char *line)
++{
++ Client *c;
++ const char *appid, *title;
++ static char buf[512];
++
++ wl_list_for_each(c, &fstack, flink) {
++ if (!(title = client_get_title(c)))
++ continue;
++ appid = client_get_appid(c);
++ snprintf(buf, LENGTH(buf) - 1, "%s%s%s",
++ title, appid ? " | " : "", appid ? appid : "");
++ if (strcmp(line, buf) == 0)
++ goto found;
++ }
++ return;
++
++found:
++ if (!c->mon)
++ return;
++ wl_list_remove(&c->flink);
++ wl_list_insert(&fstack, &c->flink);
++ selmon = c->mon;
++ view(&(const Arg){ .ui = c->tags });
++}
++
++void
++menulayoutfeed(FILE *f)
++{
++ const Layout *l;
++ for (l = layouts; l < END(layouts); l++)
++ fprintf(f, "%s\n", l->symbol);
++}
++
++void
++menulayoutaction(char *line)
++{
++ const Layout *l;
++ for (l = layouts; l < END(layouts); l++)
++ if (strcmp(line, l->symbol) == 0)
++ goto found;
++ return;
++
++found:
++ setlayout(&(const Arg){ .v = l });
++}
++
+ void
+ monocle(Monitor *m)
+ {
+--
+2.49.0
+