summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZachIR <zachir@librem.one>2022-08-31 17:50:25 -0500
committerZachIR <zachir@librem.one>2022-08-31 17:50:25 -0500
commit7e96775d12cd982725cec146529b212f8fe94bad (patch)
treee1233ddb742fbce0dc47176d07300ad1540b29bb
parent226051974060746d02d787ac1ef70b6267ee51b4 (diff)
add patches I have applied
-rw-r--r--patches/dwl-alwayscenter.diff23
-rw-r--r--patches/dwl-autostart.diff132
-rw-r--r--patches/dwl-cursorwarp.diff145
-rw-r--r--patches/dwl-namedscratchpads.diff176
-rw-r--r--patches/dwl-push.diff129
-rw-r--r--patches/dwl-smartborders.diff164
-rw-r--r--patches/dwl-swallow.diff194
7 files changed, 963 insertions, 0 deletions
diff --git a/patches/dwl-alwayscenter.diff b/patches/dwl-alwayscenter.diff
new file mode 100644
index 0000000..24e52ba
--- /dev/null
+++ b/patches/dwl-alwayscenter.diff
@@ -0,0 +1,23 @@
+From 9173fdaf0d1eb853ff194ea11767ac15a0d13560 Mon Sep 17 00:00:00 2001
+From: Guido Cella <guido@guidocella.xyz>
+Date: Sat, 17 Apr 2021 08:59:55 +0200
+Subject: [PATCH] Center floating windows
+
+Credits to Benjamin Chausse for fixing this with multiple monitors.
+---
+ dwl.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/dwl.c b/dwl.c
+index 22287fb3..80c16459 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -467,6 +467,8 @@ applyrules(Client *c)
+ mon = m;
+ }
+ }
++ c->geom.x = (mon->w.width - c->geom.width) / 2 + mon->m.x;
++ c->geom.y = (mon->w.height - c->geom.height) / 2 + mon->m.y;
+ wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]);
+ setmon(c, mon, newtags);
+ }
diff --git a/patches/dwl-autostart.diff b/patches/dwl-autostart.diff
new file mode 100644
index 0000000..1bccc40
--- /dev/null
+++ b/patches/dwl-autostart.diff
@@ -0,0 +1,132 @@
+From 744a6ce137f30b4b4ab9271bfb5ea5b1ccf4423c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?=
+ <leohdz172@protonmail.com>
+Date: Wed, 9 Feb 2022 07:02:47 -0600
+Subject: [PATCH] apply autostart patch from dwm
+
+https://dwm.suckless.org/patches/cool_autostart/
+---
+ config.def.h | 6 ++++++
+ dwl.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 2 files changed, 58 insertions(+), 1 deletion(-)
+
+diff --git a/config.def.h b/config.def.h
+index 29c6dbf8..35372a68 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -86,6 +86,12 @@ LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
+ static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
+ static const double accel_speed = 0.0;
+
++/* Autostart */
++static const char *const autostart[] = {
++ "sh", "-c", "swaybg --image /xap/local/background", NULL,
++ NULL /* terminate */
++};
++
+ /* If you want to use the windows key change this to WLR_MODIFIER_LOGO */
+ #define MODKEY WLR_MODIFIER_ALT
+ #define TAGKEYS(KEY,SKEY,TAG) \
+diff --git a/dwl.c b/dwl.c
+index 40ea05a6..514ec4b0 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -213,6 +213,7 @@ static void arrange(Monitor *m);
+ static void arrangelayer(Monitor *m, struct wl_list *list,
+ struct wlr_box *usable_area, int exclusive);
+ static void arrangelayers(Monitor *m);
++static void autostartexec(void);
+ static void axisnotify(struct wl_listener *listener, void *data);
+ static void buttonpress(struct wl_listener *listener, void *data);
+ static void chvt(const Arg *arg);
+@@ -379,6 +380,9 @@ static Atom netatom[NetLast];
+ /* compile-time check if all tags fit into an unsigned int bit array. */
+ struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
+
++static pid_t *autostart_pids;
++static size_t autostart_len;
++
+ /* function implementations */
+ void
+ applybounds(Client *c, struct wlr_box *bbox)
+@@ -403,6 +407,29 @@ applybounds(Client *c, struct wlr_box *bbox)
+ c->geom.y = bbox->y;
+ }
+
++void
++autostartexec(void) {
++ const char *const *p;
++ size_t i = 0;
++
++ /* count entries */
++ for (p = autostart; *p; autostart_len++, p++)
++ while (*++p);
++
++ autostart_pids = calloc(autostart_len, sizeof(pid_t));
++ for (p = autostart; *p; i++, p++) {
++ if ((autostart_pids[i] = fork()) == 0) {
++ setsid();
++ execvp(*p, (char *const *)p);
++ fprintf(stderr, "dwl: execvp %s\n", *p);
++ perror(" failed");
++ _exit(EXIT_FAILURE);
++ }
++ /* skip arguments */
++ while (*++p);
++ }
++}
++
+ void
+ applyexclusive(struct wlr_box *usable_area,
+ uint32_t anchor, int32_t exclusive,
+@@ -1721,6 +1748,16 @@ printstatus(void)
+ void
+ quit(const Arg *arg)
+ {
++ size_t i;
++
++ /* kill child processes */
++ for (i = 0; i < autostart_len; i++) {
++ if (0 < autostart_pids[i]) {
++ kill(autostart_pids[i], SIGTERM);
++ waitpid(autostart_pids[i], NULL, 0);
++ }
++ }
++
+ wl_display_terminate(dpy);
+ }
+
+@@ -1808,6 +1845,7 @@ run(char *startup_cmd)
+ setenv("WAYLAND_DISPLAY", socket, 1);
+
+ /* Now that the socket exists, run the startup command */
++ autostartexec();
+ if (startup_cmd) {
+ int piperw[2];
+ if (pipe(piperw) < 0)
+@@ -2183,11 +2221,24 @@ sigchld(int unused)
+ * setting our own disposition for SIGCHLD.
+ */
+ pid_t pid;
++
+ if (signal(SIGCHLD, sigchld) == SIG_ERR)
+ die("can't install SIGCHLD handler:");
+- while (0 < (pid = waitpid(-1, NULL, WNOHANG)))
++ while (0 < (pid = waitpid(-1, NULL, WNOHANG))) {
++ pid_t *p, *lim;
+ if (pid == child_pid)
+ child_pid = -1;
++ if (!(p = autostart_pids))
++ continue;
++ lim = &p[autostart_len];
++
++ for (; p < lim; p++) {
++ if (*p == pid) {
++ *p = -1;
++ break;
++ }
++ }
++ }
+ }
+
+ void
diff --git a/patches/dwl-cursorwarp.diff b/patches/dwl-cursorwarp.diff
new file mode 100644
index 0000000..0c4b320
--- /dev/null
+++ b/patches/dwl-cursorwarp.diff
@@ -0,0 +1,145 @@
+From 8703fcdeac789425fbea768c3efa30884518e72e Mon Sep 17 00:00:00 2001
+From: Faerryn <alexandre.liao@gmail.com>
+Date: Thu, 26 May 2022 23:18:59 -0400
+Subject: [PATCH 1/3] cursor wrap
+
+---
+ dwl.c | 10 ++++++++++
+ 1 file changed, 10 insertions(+)
+
+diff --git a/dwl.c b/dwl.c
+index d0f5afc8..7427fa06 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -1107,6 +1107,16 @@ focusclient(Client *c, int lift)
+ struct wlr_keyboard *kb;
+ int i;
+
++ /* Warp cursor to center of client if it is outside */
++ if (c && (cursor->x < c->geom.x ||
++ cursor->x > c->geom.x + c->geom.width ||
++ cursor->y < c->geom.y ||
++ cursor->y > c->geom.y + c->geom.height))
++ wlr_cursor_warp_closest( cursor,
++ NULL,
++ c->geom.x + c->geom.width / 2.0,
++ c->geom.y + c->geom.height / 2.0);
++
+ /* Raise client in stacking order if requested */
+ if (c && lift)
+ wlr_scene_node_raise_to_top(c->scene);
+
+From 9cd5b806a96823fc10784a39c86d57156e749d11 Mon Sep 17 00:00:00 2001
+From: Faerryn <alexandre.liao@gmail.com>
+Date: Fri, 27 May 2022 14:51:09 -0400
+Subject: [PATCH 2/3] both focusclient and arrange will warp cursor
+
+---
+ dwl.c | 26 ++++++++++++++++++--------
+ 1 file changed, 18 insertions(+), 8 deletions(-)
+
+diff --git a/dwl.c b/dwl.c
+index 7427fa06..2bdcaa56 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -290,6 +290,7 @@ static void updatetitle(struct wl_listener *listener, void *data);
+ static void urgent(struct wl_listener *listener, void *data);
+ static void view(const Arg *arg);
+ static void virtualkeyboard(struct wl_listener *listener, void *data);
++static void warpcursor(const Client *c);
+ static Monitor *xytomon(double x, double y);
+ static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface,
+ Client **pc, LayerSurface **pl, double *nx, double *ny);
+@@ -489,6 +490,9 @@ arrange(Monitor *m)
+ if (m->lt[m->sellt]->arrange)
+ m->lt[m->sellt]->arrange(m);
+ /* TODO recheck pointer focus here... or in resize()? */
++ c = selclient();
++ if (c)
++ warpcursor(c);
+ }
+
+ void
+@@ -1108,14 +1112,8 @@ focusclient(Client *c, int lift)
+ int i;
+
+ /* Warp cursor to center of client if it is outside */
+- if (c && (cursor->x < c->geom.x ||
+- cursor->x > c->geom.x + c->geom.width ||
+- cursor->y < c->geom.y ||
+- cursor->y > c->geom.y + c->geom.height))
+- wlr_cursor_warp_closest( cursor,
+- NULL,
+- c->geom.x + c->geom.width / 2.0,
+- c->geom.y + c->geom.height / 2.0);
++ if (c)
++ warpcursor(c);
+
+ /* Raise client in stacking order if requested */
+ if (c && lift)
+@@ -2375,6 +2373,18 @@ virtualkeyboard(struct wl_listener *listener, void *data)
+ createkeyboard(device);
+ }
+
++void
++warpcursor(const Client *c) {
++ if (cursor->x < c->geom.x ||
++ cursor->x > c->geom.x + c->geom.width ||
++ cursor->y < c->geom.y ||
++ cursor->y > c->geom.y + c->geom.height)
++ wlr_cursor_warp_closest(cursor,
++ NULL,
++ c->geom.x + c->geom.width / 2.0,
++ c->geom.y + c->geom.height / 2.0);
++}
++
+ Monitor *
+ xytomon(double x, double y)
+ {
+
+From 95a8e2c3372b2dc245533001164b1e427751d394 Mon Sep 17 00:00:00 2001
+From: Faerryn <alexandre.liao@gmail.com>
+Date: Sat, 28 May 2022 12:35:32 -0400
+Subject: [PATCH 3/3] add an option to config.h for cursor_warp
+
+---
+ config.def.h | 3 +++
+ dwl.c | 4 ++--
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 4f131dda..f82dd582 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -6,6 +6,9 @@ static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0};
+ static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0};
+ static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0};
+
++/* cursor warping */
++static const bool cursor_warp = true;
++
+ /* tagging */
+ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+diff --git a/dwl.c b/dwl.c
+index 2bdcaa56..e593b152 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -491,7 +491,7 @@ arrange(Monitor *m)
+ m->lt[m->sellt]->arrange(m);
+ /* TODO recheck pointer focus here... or in resize()? */
+ c = selclient();
+- if (c)
++ if (cursor_warp && c)
+ warpcursor(c);
+ }
+
+@@ -1112,7 +1112,7 @@ focusclient(Client *c, int lift)
+ int i;
+
+ /* Warp cursor to center of client if it is outside */
+- if (c)
++ if (cursor_warp && c)
+ warpcursor(c);
+
+ /* Raise client in stacking order if requested */
diff --git a/patches/dwl-namedscratchpads.diff b/patches/dwl-namedscratchpads.diff
new file mode 100644
index 0000000..a83d322
--- /dev/null
+++ b/patches/dwl-namedscratchpads.diff
@@ -0,0 +1,176 @@
+From 13402c1ccead7a6775520bd1ceef31611583c965 Mon Sep 17 00:00:00 2001
+From: Louis-Michel Raynauld <louismichel@pweb.ca>
+Date: Fri, 29 Jul 2022 23:09:10 -0700
+Subject: [PATCH 1/2] port dwm "namedscratchpads" patch to dwl
+
+---
+ config.def.h | 9 +++++++--
+ dwl.c | 42 ++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 49 insertions(+), 2 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 190b0da4..b5f87336 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -10,11 +10,12 @@ static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0};
+ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+ static const Rule rules[] = {
+- /* app_id title tags mask isfloating monitor */
++ /* app_id title tags mask isfloating monitor scratchkey */
+ /* examples:
+ { "Gimp", NULL, 0, 1, -1 },
+ */
+- { "firefox", NULL, 1 << 8, 0, -1 },
++ { "firefox", NULL, 1 << 8, 0, -1, 0 },
++ { NULL, "scratchpad", 0, 1, -1, 's' },
+ };
+
+ /* layout(s) */
+@@ -66,11 +67,15 @@ static const int natural_scrolling = 0;
+ static const char *termcmd[] = { "alacritty", NULL };
+ static const char *menucmd[] = { "bemenu-run", NULL };
+
++/* named scratchpads - First arg only serves to match against key in rules*/
++static const char *scratchpadcmd[] = { "s", "alacritty", "-t", "scratchpad", NULL };
++
+ static const Key keys[] = {
+ /* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
+ /* modifier key function argument */
+ { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
++ { MODKEY, XKB_KEY_grave, togglescratch, {.v = scratchpadcmd } },
+ { MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
+ { MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
+ { MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
+diff --git a/dwl.c b/dwl.c
+index b09fc6f9..f21488c0 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -118,6 +118,7 @@ typedef struct {
+ int isfloating, isurgent;
+ uint32_t resize; /* configure serial of a pending resize */
+ int isfullscreen;
++ char scratchkey;
+ } Client;
+
+ typedef struct {
+@@ -198,6 +199,7 @@ typedef struct {
+ unsigned int tags;
+ int isfloating;
+ int monitor;
++ const char scratchkey;
+ } Rule;
+
+ /* function declarations */
+@@ -273,12 +275,14 @@ static void setsel(struct wl_listener *listener, void *data);
+ static void setup(void);
+ static void sigchld(int unused);
+ static void spawn(const Arg *arg);
++static void spawnscratch(const Arg *arg);
+ static void startdrag(struct wl_listener *listener, void *data);
+ static void tag(const Arg *arg);
+ static void tagmon(const Arg *arg);
+ static void tile(Monitor *m);
+ static void togglefloating(const Arg *arg);
+ static void togglefullscreen(const Arg *arg);
++static void togglescratch(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+ static void unmaplayersurface(LayerSurface *layersurface);
+@@ -457,6 +461,7 @@ applyrules(Client *c)
+ Monitor *mon = selmon, *m;
+
+ c->isfloating = client_is_float_type(c);
++ c->scratchkey = 0;
+ if (!(appid = client_get_appid(c)))
+ appid = broken;
+ if (!(title = client_get_title(c)))
+@@ -466,6 +471,7 @@ applyrules(Client *c)
+ if ((!r->title || strstr(title, r->title))
+ && (!r->id || strstr(appid, r->id))) {
+ c->isfloating = r->isfloating;
++ c->scratchkey = r->scratchkey;
+ newtags |= r->tags;
+ i = 0;
+ wl_list_for_each(m, &mons, link)
+@@ -2092,6 +2098,16 @@ spawn(const Arg *arg)
+ }
+ }
+
++void spawnscratch(const Arg *arg)
++{
++ if (fork() == 0) {
++ dup2(STDERR_FILENO, STDOUT_FILENO);
++ setsid();
++ execvp(((char **)arg->v)[1], ((char **)arg->v)+1);
++ die("dwl: execvp %s failed:", ((char **)arg->v)[1]);
++ }
++}
++
+ void
+ startdrag(struct wl_listener *listener, void *data)
+ {
+@@ -2176,6 +2192,32 @@ togglefullscreen(const Arg *arg)
+ setfullscreen(sel, !sel->isfullscreen);
+ }
+
++void
++togglescratch(const Arg *arg)
++{
++ Client *c;
++ unsigned int found = 0;
++
++ /* search for first window that matches the scratchkey */
++ wl_list_for_each(c, &clients, link)
++ if (c->scratchkey == ((char**)arg->v)[0][0]) {
++ found = 1;
++ break;
++ }
++
++ if (found) {
++ c->tags = VISIBLEON(c, selmon) ? 0 : selmon->tagset[selmon->seltags];
++ focusclient(NULL, 0);
++ if (VISIBLEON(c, selmon)) {
++ focusclient(c, 0);
++ }
++ arrange(selmon);
++
++ } else{
++ spawnscratch(arg);
++ }
++}
++
+ void
+ toggletag(const Arg *arg)
+ {
+
+From be5e75b1bad480a7eedd81ef68cc331687fbe7cd Mon Sep 17 00:00:00 2001
+From: Louis-Michel Raynauld <louismichel@pweb.ca>
+Date: Fri, 5 Aug 2022 22:20:59 -0700
+Subject: [PATCH 2/2] Fix focus after hiding and make sure toggle scratchpad
+ appears on top of others scratchpads if any.
+
+---
+ dwl.c | 7 ++-----
+ 1 file changed, 2 insertions(+), 5 deletions(-)
+
+diff --git a/dwl.c b/dwl.c
+index f21488c0..e0ecdb8e 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -2207,12 +2207,9 @@ togglescratch(const Arg *arg)
+
+ if (found) {
+ c->tags = VISIBLEON(c, selmon) ? 0 : selmon->tagset[selmon->seltags];
+- focusclient(NULL, 0);
+- if (VISIBLEON(c, selmon)) {
+- focusclient(c, 0);
+- }
+- arrange(selmon);
+
++ focusclient(c->tags == 0 ? focustop(selmon) : c, 1);
++ arrange(selmon);
+ } else{
+ spawnscratch(arg);
+ }
diff --git a/patches/dwl-push.diff b/patches/dwl-push.diff
new file mode 100644
index 0000000..06a1532
--- /dev/null
+++ b/patches/dwl-push.diff
@@ -0,0 +1,129 @@
+From dcb7a4d91075a9d918d082eb948c61d26eb0bc02 Mon Sep 17 00:00:00 2001
+From: "Devin J. Pohly" <djpohly@gmail.com>
+Date: Thu, 4 Mar 2021 00:45:50 -0600
+Subject: [PATCH 1/2] port dwm "push" patch to dwl
+
+---
+ Makefile | 2 ++
+ dwl.c | 2 ++
+ push.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 67 insertions(+)
+ create mode 100644 push.c
+
+diff --git a/Makefile b/Makefile
+index a0d1cc37..1701b63e 100644
+--- a/Makefile
++++ b/Makefile
+@@ -49,6 +49,8 @@ config.h: | config.def.h
+
+ dwl.o: config.h client.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h idle-protocol.h
+
++dwl.o: push.c
++
+ dwl: xdg-shell-protocol.o wlr-layer-shell-unstable-v1-protocol.o idle-protocol.o
+
+ clean:
+diff --git a/dwl.c b/dwl.c
+index 72f1046b..4cfd7d07 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -369,7 +369,9 @@ static Atom netatom[NetLast];
+ #endif
+
+ /* configuration, allows nested code to access above variables */
++#include "push.h"
+ #include "config.h"
++#include "push.c"
+
+ /* attempt to encapsulate suck into one file */
+ #include "client.h"
+diff --git a/push.c b/push.c
+new file mode 100644
+index 00000000..26ed462f
+--- /dev/null
++++ b/push.c
+@@ -0,0 +1,63 @@
++static Client *
++nexttiled(Client *sel) {
++ Client *c;
++ wl_list_for_each(c, &sel->link, link) {
++ if (&c->link == &clients)
++ break; /* don't wrap */
++ if (!c->isfloating && VISIBLEON(c, selmon))
++ return c;
++ }
++ return NULL;
++}
++
++static Client *
++prevtiled(Client *sel) {
++ Client *c;
++ wl_list_for_each_reverse(c, &sel->link, link) {
++ if (&c->link == &clients)
++ break; /* don't wrap */
++ if (!c->isfloating && VISIBLEON(c, selmon))
++ return c;
++ }
++ return NULL;
++}
++
++static void
++pushup(const Arg *arg) {
++ Client *sel = selclient();
++ Client *c;
++
++ if(!sel || sel->isfloating)
++ return;
++ if((c = prevtiled(sel))) {
++ /* attach before c */
++ wl_list_remove(&sel->link);
++ wl_list_insert(c->link.prev, &sel->link);
++ } else {
++ /* move to the end */
++ wl_list_remove(&sel->link);
++ wl_list_insert(clients.prev, &sel->link);
++ }
++ focusclient(sel, 1);
++ arrange(selmon);
++}
++
++static void
++pushdown(const Arg *arg) {
++ Client *sel = selclient();
++ Client *c;
++
++ if(!sel || sel->isfloating)
++ return;
++ if((c = nexttiled(sel))) {
++ /* attach after c */
++ wl_list_remove(&sel->link);
++ wl_list_insert(&c->link, &sel->link);
++ } else {
++ /* move to the front */
++ wl_list_remove(&sel->link);
++ wl_list_insert(&clients, &sel->link);
++ }
++ focusclient(sel, 1);
++ arrange(selmon);
++}
+
+From 156a13d9f9f9d8df16b184f5ec0c84e6e5b94df6 Mon Sep 17 00:00:00 2001
+From: "Devin J. Pohly" <djpohly@gmail.com>
+Date: Thu, 4 Mar 2021 13:52:58 -0600
+Subject: [PATCH 2/2] add missing header
+
+---
+ push.h | 4 ++++
+ 1 file changed, 4 insertions(+)
+ create mode 100644 push.h
+
+diff --git a/push.h b/push.h
+new file mode 100644
+index 00000000..59c0f80e
+--- /dev/null
++++ b/push.h
+@@ -0,0 +1,4 @@
++static Client *nexttiled(Client *sel);
++static Client *prevtiled(Client *sel);
++static void pushdown(const Arg *arg);
++static void pushup(const Arg *arg);
diff --git a/patches/dwl-smartborders.diff b/patches/dwl-smartborders.diff
new file mode 100644
index 0000000..9f21db9
--- /dev/null
+++ b/patches/dwl-smartborders.diff
@@ -0,0 +1,164 @@
+From 24d23869dc7c27feddf33753946aac02197fdb67 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?=
+ <leohdz172@protonmail.com>
+Date: Tue, 16 Aug 2022 15:28:00 -0500
+Subject: [PATCH] don't draw borders if there is only one window
+
+Co-authored-by: Andrey Proskurin <andreyproskurin@protonmail.com>
+---
+ config.def.h | 1 +
+ dwl.c | 36 ++++++++++++++++++++++++------------
+ 2 files changed, 25 insertions(+), 12 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 29c6dbf8..19632a50 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -2,6 +2,7 @@
+ static const int sloppyfocus = 1; /* focus follows mouse */
+ static const unsigned int borderpx = 1; /* border pixel of windows */
+ static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
++static const int smartborders = 1;
+ static const float rootcolor[] = {0.3, 0.3, 0.3, 1.0};
+ static const float bordercolor[] = {0.5, 0.5, 0.5, 1.0};
+ static const float focuscolor[] = {1.0, 0.0, 0.0, 1.0};
+diff --git a/dwl.c b/dwl.c
+index 40ea05a6..8f654f69 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -262,7 +262,7 @@ static void quit(const Arg *arg);
+ static void quitsignal(int signo);
+ static void rendermon(struct wl_listener *listener, void *data);
+ static void requeststartdrag(struct wl_listener *listener, void *data);
+-static void resize(Client *c, struct wlr_box geo, int interact);
++static void resize(Client *c, struct wlr_box geo, int interact, int draw_borders);
+ static void run(char *startup_cmd);
+ static Client *selclient(void);
+ static void setcursor(struct wl_listener *listener, void *data);
+@@ -754,7 +754,7 @@ closemon(Monitor *m)
+ wl_list_for_each(c, &clients, link) {
+ if (c->isfloating && c->geom.x > m->m.width)
+ resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y,
+- .width = c->geom.width, .height = c->geom.height}, 0);
++ .width = c->geom.width, .height = c->geom.height}, 0, 1);
+ if (c->mon == m)
+ setmon(c, selmon, c->tags);
+ }
+@@ -1456,7 +1456,7 @@ monocle(Monitor *m)
+ wl_list_for_each(c, &clients, link) {
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+- resize(c, m->w, 0);
++ resize(c, m->w, 0, !smartborders);
+ }
+ focusclient(focustop(m), 1);
+ }
+@@ -1499,11 +1499,11 @@ motionnotify(uint32_t time)
+ if (cursor_mode == CurMove) {
+ /* Move the grabbed client to the new position. */
+ resize(grabc, (struct wlr_box){.x = cursor->x - grabcx, .y = cursor->y - grabcy,
+- .width = grabc->geom.width, .height = grabc->geom.height}, 1);
++ .width = grabc->geom.width, .height = grabc->geom.height}, 1, 1);
+ return;
+ } else if (cursor_mode == CurResize) {
+ resize(grabc, (struct wlr_box){.x = grabc->geom.x, .y = grabc->geom.y,
+- .width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1);
++ .width = cursor->x - grabc->geom.x, .height = cursor->y - grabc->geom.y}, 1, 1);
+ return;
+ }
+
+@@ -1776,10 +1776,11 @@ requeststartdrag(struct wl_listener *listener, void *data)
+ }
+
+ void
+-resize(Client *c, struct wlr_box geo, int interact)
++resize(Client *c, struct wlr_box geo, int interact, int draw_borders)
+ {
+ struct wlr_box *bbox = interact ? &sgeom : &c->mon->w;
+ c->geom = geo;
++ c->bw = draw_borders ? borderpx : 0;
+ applybounds(c, bbox);
+
+ /* Update scene-graph, including borders */
+@@ -1885,6 +1886,8 @@ setfloating(Client *c, int floating)
+ {
+ c->isfloating = floating;
+ wlr_scene_node_reparent(c->scene, layers[c->isfloating ? LyrFloat : LyrTile]);
++ if (c->isfloating && !c->bw)
++ resize(c, c->mon->m, 0, 1);
+ arrange(c->mon);
+ printstatus();
+ }
+@@ -1898,7 +1901,7 @@ setfullscreen(Client *c, int fullscreen)
+
+ if (fullscreen) {
+ c->prev = c->geom;
+- resize(c, c->mon->m, 0);
++ resize(c, c->mon->m, 0, 0);
+ /* The xdg-protocol specifies:
+ *
+ * If the fullscreened surface is not opaque, the compositor must make
+@@ -1916,7 +1919,7 @@ setfullscreen(Client *c, int fullscreen)
+ } else {
+ /* restore previous size instead of arrange for floating windows since
+ * client positions are set by the user and cannot be recalculated */
+- resize(c, c->prev, 0);
++ resize(c, c->prev, 0, 1);
+ if (c->fullscreen_bg) {
+ wlr_scene_node_destroy(&c->fullscreen_bg->node);
+ c->fullscreen_bg = NULL;
+@@ -1933,6 +1936,12 @@ setlayout(const Arg *arg)
+ selmon->sellt ^= 1;
+ if (arg && arg->v)
+ selmon->lt[selmon->sellt] = (Layout *)arg->v;
++ if (!selmon->lt[selmon->sellt]->arrange) {
++ /* floating layout, draw borders around all clients */
++ Client *c;
++ wl_list_for_each(c, &clients, link)
++ resize(c, c->mon->m, 0, 1);
++ }
+ /* TODO change layout symbol? */
+ arrange(selmon);
+ printstatus();
+@@ -1969,7 +1978,7 @@ setmon(Client *c, Monitor *m, unsigned int newtags)
+ }
+ if (m) {
+ /* Make sure window actually overlaps with the monitor */
+- resize(c, c->geom, 0);
++ resize(c, c->geom, 0, 1);
+ wlr_surface_send_enter(client_surface(c), m->wlr_output);
+ c->tags = newtags ? newtags : m->tagset[m->seltags]; /* assign tags of target monitor */
+ arrange(m);
+@@ -2238,7 +2247,7 @@ tagmon(const Arg *arg)
+ void
+ tile(Monitor *m)
+ {
+- unsigned int i, n = 0, mw, my, ty;
++ unsigned int i, n = 0, mw, my, ty, draw_borders = 1;
+ Client *c;
+
+ wl_list_for_each(c, &clients, link)
+@@ -2247,6 +2256,9 @@ tile(Monitor *m)
+ if (n == 0)
+ return;
+
++ if (n == smartborders)
++ draw_borders = 0;
++
+ if (n > m->nmaster)
+ mw = m->nmaster ? m->w.width * m->mfact : 0;
+ else
+@@ -2257,11 +2269,11 @@ tile(Monitor *m)
+ continue;
+ if (i < m->nmaster) {
+ resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
+- .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
++ .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0, draw_borders);
+ my += c->geom.height;
+ } else {
+ resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
+- .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
++ .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0, draw_borders);
+ ty += c->geom.height;
+ }
+ i++;
diff --git a/patches/dwl-swallow.diff b/patches/dwl-swallow.diff
new file mode 100644
index 0000000..8240686
--- /dev/null
+++ b/patches/dwl-swallow.diff
@@ -0,0 +1,194 @@
+From 17585c99f57856d39fd0d4c489d8bafd103d53f4 Mon Sep 17 00:00:00 2001
+From: Dmitry Zakharchenko <dmitz@disroot.org>
+Date: Sun, 28 Aug 2022 11:38:08 +0300
+Subject: [PATCH] update swallow patch
+
+---
+ config.def.h | 6 ++--
+ dwl.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 97 insertions(+), 6 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 29c6dbf8..4aa6903b 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -12,11 +12,11 @@ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0};
+ static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+ static const Rule rules[] = {
+- /* app_id title tags mask isfloating monitor */
++ /* app_id title tags mask isfloating isterm noswallow monitor */
+ /* examples:
+- { "Gimp", NULL, 0, 1, -1 },
+++ { "Gimp", NULL, 0, 1, 0, 1, -1 },
+ */
+- { "firefox", NULL, 1 << 8, 0, -1 },
++ { "firefox", NULL, 1 << 8, 0, 0, 1, -1 },
+ };
+
+ /* layout(s) */
+diff --git a/dwl.c b/dwl.c
+index 66aea65c..e897a9ff 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -90,7 +90,8 @@ typedef struct {
+ } Button;
+
+ typedef struct Monitor Monitor;
+-typedef struct {
++typedef struct Client Client;
++struct Client{
+ /* Must keep these three elements in this order */
+ unsigned int type; /* XDGShell or X11* */
+ struct wlr_box geom; /* layout-relative, includes border */
+@@ -119,9 +120,11 @@ typedef struct {
+ #endif
+ unsigned int bw;
+ unsigned int tags;
+- int isfloating, isurgent, isfullscreen;
++ int isfloating, isurgent, isfullscreen, isterm, noswallow;
+ uint32_t resize; /* configure serial of a pending resize */
+-} Client;
++ pid_t pid;
++ Client *swallowing, *swallowedby;
++};
+
+ typedef struct {
+ uint32_t singular_anchor;
+@@ -200,6 +203,8 @@ typedef struct {
+ const char *title;
+ unsigned int tags;
+ int isfloating;
++ int isterm;
++ int noswallow;
+ int monitor;
+ } Rule;
+
+@@ -295,6 +300,10 @@ static Monitor *xytomon(double x, double y);
+ static struct wlr_scene_node *xytonode(double x, double y, struct wlr_surface **psurface,
+ Client **pc, LayerSurface **pl, double *nx, double *ny);
+ static void zoom(const Arg *arg);
++static pid_t getparentprocess(pid_t p);
++static int isdescprocess(pid_t p, pid_t c);
++static Client *termforwin(Client *w);
++static void swallow(Client *c, Client *w);
+
+ /* variables */
+ static const char broken[] = "broken";
+@@ -479,6 +488,8 @@ applyrules(Client *c)
+ if ((!r->title || strstr(title, r->title))
+ && (!r->id || strstr(appid, r->id))) {
+ c->isfloating = r->isfloating;
++ c->isterm = r->isterm;
++ c->noswallow = r->noswallow;
+ newtags |= r->tags;
+ i = 0;
+ wl_list_for_each(m, &mons, link)
+@@ -975,6 +986,8 @@ createnotify(struct wl_listener *listener, void *data)
+ c->surface.xdg = xdg_surface;
+ c->bw = borderpx;
+
++ wl_client_get_credentials(c->surface.xdg->client->client, &c->pid, NULL, NULL);
++
+ LISTEN(&xdg_surface->events.map, &c->map, mapnotify);
+ LISTEN(&xdg_surface->events.unmap, &c->unmap, unmapnotify);
+ LISTEN(&xdg_surface->events.destroy, &c->destroy, destroynotify);
+@@ -1239,6 +1252,61 @@ fullscreennotify(struct wl_listener *listener, void *data)
+ setfullscreen(c, fullscreen);
+ }
+
++pid_t
++getparentprocess(pid_t p)
++{
++ unsigned int v = 0;
++
++ FILE *f;
++ char buf[256];
++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)p);
++
++ if (!(f = fopen(buf, "r")))
++ return 0;
++
++ fscanf(f, "%*u %*s %*c %u", &v);
++ fclose(f);
++
++ return (pid_t)v;
++}
++
++int
++isdescprocess(pid_t p, pid_t c)
++{
++ while (p != c && c != 0)
++ c = getparentprocess(c);
++
++ return (int)c;
++}
++
++Client *
++termforwin(Client *w)
++{
++ Client *c;
++
++ if (!w->pid || w->isterm || w->noswallow)
++ return NULL;
++
++ wl_list_for_each(c, &clients, link)
++ if (c->isterm && !c->swallowing && c->pid && isdescprocess(c->pid, w->pid))
++ return c;
++
++ return NULL;
++}
++
++void
++swallow(Client *c, Client *w) {
++ c->bw = w->bw;
++ c->isfloating = w->isfloating;
++ c->isurgent = w->isurgent;
++ c->isfullscreen = w->isfullscreen;
++ resize(c, w->geom, 0);
++ wl_list_insert(&w->link, &c->link);
++ wl_list_insert(&w->flink, &c->flink);
++ wlr_scene_node_set_enabled(w->scene, 0);
++ wlr_scene_node_set_enabled(c->scene, 1);
++}
++
+ void
+ incnmaster(const Arg *arg)
+ {
+@@ -1430,6 +1498,19 @@ mapnotify(struct wl_listener *listener, void *data)
+ setfullscreen(c, 1);
+
+ c->mon->un_map = 1;
++ if (!c->noswallow) {
++ Client *p = termforwin(c);
++ if (p) {
++ c->swallowedby = p;
++ p->swallowing = c;
++ wl_list_remove(&c->link);
++ wl_list_remove(&c->flink);
++ swallow(c,p);
++ wl_list_remove(&p->link);
++ wl_list_remove(&p->flink);
++ }
++ arrange(c->mon);
++ }
+ }
+
+ void
+@@ -2322,6 +2403,16 @@ unmapnotify(struct wl_listener *listener, void *data)
+ cursor_mode = CurNormal;
+ grabc = NULL;
+ }
++ if (c->swallowing) {
++ c->swallowing->swallowedby = NULL;
++ c->swallowing = NULL;
++ }
++
++ if (c->swallowedby) {
++ swallow(c->swallowedby, c);
++ c->swallowedby->swallowing = NULL;
++ c->swallowedby = NULL;
++ }
+
+ if (c->mon)
+ c->mon->un_map = 1;