summaryrefslogtreecommitdiffstats
path: root/dwl-patches/stale-patches
diff options
context:
space:
mode:
Diffstat (limited to 'dwl-patches/stale-patches')
-rw-r--r--dwl-patches/stale-patches/bar-systray-old/README.md33
-rw-r--r--dwl-patches/stale-patches/bar-systray-old/bar-systray-0.7.patch398
-rw-r--r--dwl-patches/stale-patches/bar-systray-old/systray.pngbin0 -> 22944 bytes
-rw-r--r--dwl-patches/stale-patches/master-right/README.md13
-rw-r--r--dwl-patches/stale-patches/master-right/master-right-0.7.patch35
-rw-r--r--dwl-patches/stale-patches/master-right/master-right.patch35
-rw-r--r--dwl-patches/stale-patches/press_repeat_release/README.md15
-rw-r--r--dwl-patches/stale-patches/press_repeat_release/press_repeat_release.patch108
-rw-r--r--dwl-patches/stale-patches/remembertags/README.md16
-rw-r--r--dwl-patches/stale-patches/remembertags/remembertags.patch105
-rw-r--r--dwl-patches/stale-patches/tab-pango/README.md10
-rw-r--r--dwl-patches/stale-patches/tab-pango/tab.patch461
-rw-r--r--dwl-patches/stale-patches/togglekblayout/README.md14
-rw-r--r--dwl-patches/stale-patches/togglekblayout/togglekblayout.patch107
14 files changed, 1350 insertions, 0 deletions
diff --git a/dwl-patches/stale-patches/bar-systray-old/README.md b/dwl-patches/stale-patches/bar-systray-old/README.md
new file mode 100644
index 0000000..9c8b94e
--- /dev/null
+++ b/dwl-patches/stale-patches/bar-systray-old/README.md
@@ -0,0 +1,33 @@
+### Description
+Add a system tray next to the [bar](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar). Heed the warning, this is far from suckless ^^
+
+![preview](systray.png)
+
+**Superseded by [bar-systray](/dwl/dwl-patches/src/branch/main/patches/bar-systray).**
+
+### Dependencies
+- GTK4
+- [bar.patch](https://codeberg.org/dwl/dwl-patches/src/branch/main/patches/bar) as mentioned.
+- [gtk4-layer-shell](https://github.com/wmww/gtk4-layer-shell)
+- [statusnotifier-systray-gtk4](https://codeberg.org/janetski/statusnotifier-systray-gtk4) built as a static library.
+
+### Applying the patch
+The patch applies on top of the bar patch. That needs to be applied first.
+
+The patch creates subdirectories `lib` and `include`. After patching, but before `make`, install
+`libstatusnotifier-systray-gtk4.a` and `snsystray.h` from statusnotifier-systray-gtk4 in the
+directories. One possible way to do that:
+
+1. Clone [https://codeberg.org/janetski/statusnotifier-systray-gtk4](https://codeberg.org/janetski/statusnotifier-systray-gtk4). Can clone to any location.
+2. From statusnotifier-systray-gtk4 root:
+ 1. `$ meson setup --default-library=static --prefix=/ -Dgir=false -Dvala=false -Ddocs=false build`
+ 2. `$ meson compile -C build`
+ 3. `$ DESTDIR=$DWLDIR meson install -C build`, where $DWLDIR is the path to dwl root.
+3. Finally, from dwl root, run `make`.
+
+### Download
+- [git branch](/janetski/dwl/src/branch/0.7-systray)
+- [0.7](/dwl/dwl-patches/raw/branch/main/patches/bar-systray/bar-systray-0.7.patch)
+
+### Authors
+- [janetski](https://codeberg.org/janetski) ([.vetu](https://discordapp.com/users/355488216469471242) on discord)
diff --git a/dwl-patches/stale-patches/bar-systray-old/bar-systray-0.7.patch b/dwl-patches/stale-patches/bar-systray-old/bar-systray-0.7.patch
new file mode 100644
index 0000000..eae4561
--- /dev/null
+++ b/dwl-patches/stale-patches/bar-systray-old/bar-systray-0.7.patch
@@ -0,0 +1,398 @@
+From 71f7b97dca2d781668e826aae7e06544958534f6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Janne=20Vetel=C3=A4inen?= <janne.vetelainen@elisanet.fi>
+Date: Fri, 23 Aug 2024 18:39:17 +0300
+Subject: [PATCH 1/1] Add a system tray next to the sewn's bar
+
+---
+ Makefile | 8 +-
+ config.def.h | 2 +
+ dwl.c | 222 ++++++++++++++++++++++++++++++++++++++++++++-
+ include/.gitignore | 1 +
+ lib/.gitignore | 1 +
+ 5 files changed, 225 insertions(+), 9 deletions(-)
+ create mode 100644 include/.gitignore
+ create mode 100644 lib/.gitignore
+
+diff --git a/Makefile b/Makefile
+index 9bc67db..853b04c 100644
+--- a/Makefile
++++ b/Makefile
+@@ -7,14 +7,14 @@ include config.mk
+ DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
+ -DVERSION=\"$(VERSION)\" $(XWAYLAND)
+ DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \
+- -Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
++ -Wno-unused-parameter -Wshadow -Wunused-macros \
+ -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \
+ -Wfloat-conversion
+
+ # CFLAGS / LDFLAGS
+-PKGS = wlroots-0.18 wayland-server xkbcommon libinput pixman-1 fcft $(XLIBS)
+-DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
+-LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS)
++PKGS = wlroots-0.18 wayland-server xkbcommon libinput pixman-1 fcft $(XLIBS) gtk4 gtk4-layer-shell-0
++DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS) -Iinclude
++LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS) -Llib -lstatusnotifier-systray-gtk4
+
+ all: dwl
+ dwl: dwl.o util.o
+diff --git a/config.def.h b/config.def.h
+index 5d1dc2b..bb9366f 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -11,6 +11,8 @@ static const int showbar = 1; /* 0 means no bar */
+ static const int topbar = 1; /* 0 means bottom bar */
+ static const char *fonts[] = {"monospace:size=10"};
+ static const float rootcolor[] = COLOR(0x000000ff);
++static const int trayspacing = 4; /* Spacing between icons in system tray */
++static const int traymargins = 4; /* System tray inner margins */
+ /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
+ static const float fullscreen_bg[] = {0.1f, 0.1f, 0.1f, 1.0f}; /* You can also use glsl colors */
+ static uint32_t colors[][3] = {
+diff --git a/dwl.c b/dwl.c
+index ece537a..24f550a 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -72,9 +72,22 @@
+ #include "util.h"
+ #include "drwl.h"
+
++#include <snsystray.h>
++#include <gdk/gdk.h>
++#include <gio/gio.h>
++#include <glib-object.h>
++#include <glib.h>
++#include <gtk/gtk.h>
++#include <gtk4-layer-shell.h>
++#include <pthread.h>
++
+ /* macros */
++#ifndef MAX
+ #define MAX(A, B) ((A) > (B) ? (A) : (B))
++#endif /* MAX */
++#ifndef MIN
+ #define MIN(A, B) ((A) < (B) ? (A) : (B))
++#endif /* MIN */
+ #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS)
+ #define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]))
+ #define LENGTH(X) (sizeof X / sizeof X[0])
+@@ -324,6 +337,15 @@ static void focusstack(const Arg *arg);
+ static Client *focustop(Monitor *m);
+ static void fullscreennotify(struct wl_listener *listener, void *data);
+ static void gpureset(struct wl_listener *listener, void *data);
++static void gtkactivate(GtkApplication *app, void *data);
++static void gtkclosewindows(void *data, void *udata);
++static void gtkhandletogglebarmsg(void *data);
++static void gtkhandlewidthnotify(SnSystray *systray, GParamSpec *pspec, void *data);
++static void* gtkinit(void *data);
++static void gtkspawnstray(Monitor *m, GtkApplication *app);
++static void gtkterminate(void *data);
++static void gtktoggletray(void *data, void *udata);
++static GdkMonitor* gtkwlrtogdkmon(Monitor *wlrmon);
+ static void handlesig(int signo);
+ static void incnmaster(const Arg *arg);
+ static void inputdevice(struct wl_listener *listener, void *data);
+@@ -380,7 +402,7 @@ static void unlocksession(struct wl_listener *listener, void *data);
+ static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
+ static void unmapnotify(struct wl_listener *listener, void *data);
+ static void updatemons(struct wl_listener *listener, void *data);
+-static void updatebar(Monitor *m);
++static void updatebar(Monitor *m, int traywidth);
+ static void updatetitle(struct wl_listener *listener, void *data);
+ static void urgent(struct wl_listener *listener, void *data);
+ static void view(const Arg *arg);
+@@ -394,6 +416,8 @@ static void zoom(const Arg *arg);
+ /* variables */
+ static const char broken[] = "broken";
+ static pid_t child_pid = -1;
++static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
++static pthread_t gtkthread; /* Gtk functions are only allowed to be called from this thread */
+ static int locked;
+ static void *exclusive_focus;
+ static struct wl_display *dpy;
+@@ -1187,7 +1211,7 @@ createmon(struct wl_listener *listener, void *data)
+
+ m->scene_buffer = wlr_scene_buffer_create(layers[LyrBottom], NULL);
+ m->scene_buffer->point_accepts_input = baracceptsinput;
+- updatebar(m);
++ updatebar(m, 0);
+
+ wl_list_insert(&mons, &m->link);
+ drawbars();
+@@ -1518,6 +1542,8 @@ drawbar(Monitor *m)
+ if (!(buf = bufmon(m)))
+ return;
+
++ pthread_mutex_lock(&mutex);
++
+ /* draw status first so it can be overdrawn by tags later */
+ if (m == selmon) { /* status is only drawn on selected monitor */
+ drwl_setscheme(m->drw, colors[SchemeNorm]);
+@@ -1566,6 +1592,7 @@ drawbar(Monitor *m)
+ m->m.y + (topbar ? 0 : m->m.height - m->b.real_height));
+ wlr_scene_buffer_set_buffer(m->scene_buffer, &buf->base);
+ wlr_buffer_unlock(&buf->base);
++ pthread_mutex_unlock(&mutex);
+ }
+
+ void
+@@ -1710,6 +1737,174 @@ fullscreennotify(struct wl_listener *listener, void *data)
+ setfullscreen(c, client_wants_fullscreen(c));
+ }
+
++void
++gtkactivate(GtkApplication *app, void *data)
++{
++ GdkDisplay *display;
++ GtkCssProvider *cssp;
++ char csss[64];
++ Monitor *m;
++ uint32_t bgcolor;
++
++ bgcolor = colors[SchemeNorm][1] >> 8;
++ display = gdk_display_get_default();
++ cssp = gtk_css_provider_new();
++ sprintf(csss, "window{background-color:#%06x;}", bgcolor);
++ gtk_css_provider_load_from_string(cssp, csss);
++ gtk_style_context_add_provider_for_display(display,
++ GTK_STYLE_PROVIDER(cssp),
++ GTK_STYLE_PROVIDER_PRIORITY_USER);
++
++ wl_list_for_each(m, &mons, link)
++ gtkspawnstray(m, app);
++
++ g_object_unref(cssp);
++}
++
++void
++gtkclosewindows(void *data, void *udata)
++{
++ GtkWindow *window = GTK_WINDOW(data);
++
++ gtk_window_close(window);
++}
++
++void
++gtkhandletogglebarmsg(void *data)
++{
++ GtkApplication *app;
++ GList *windows;
++
++ app = GTK_APPLICATION(g_application_get_default());
++ windows = gtk_application_get_windows(app);
++ g_list_foreach(windows, gtktoggletray, data);
++}
++
++void
++gtkhandlewidthnotify(SnSystray *systray, GParamSpec *pspec, void *data)
++{
++ Monitor *m = (Monitor *)data;
++ int traywidth;
++
++ traywidth = sn_systray_get_width(systray);
++
++ updatebar(m, traywidth);
++ drawbar(m);
++}
++
++void*
++gtkinit(void *data)
++{
++ GtkApplication *app = gtk_application_new("org.dwl.systray",
++ G_APPLICATION_NON_UNIQUE);
++ g_signal_connect(app, "activate", G_CALLBACK(gtkactivate), NULL);
++ g_application_run(G_APPLICATION(app), 0, NULL);
++
++ g_object_unref(app);
++
++ return NULL;
++}
++
++void
++gtkspawnstray(Monitor *m, GtkApplication *app)
++{
++ GdkMonitor *gdkmon;
++ GtkWindow *window;
++ SnSystray *systray;
++ const char *conn;
++ gboolean anchors[4];
++ int iconsize, tray_init_width, tray_height;
++
++ gdkmon = gtkwlrtogdkmon(m);
++ if (gdkmon == NULL)
++ die("Failed to get gdkmon");
++
++ conn = gdk_monitor_get_connector(gdkmon);
++ iconsize = m->b.real_height - 2 * traymargins;
++ tray_height = m->b.real_height;
++ tray_init_width = m->b.real_height;
++
++ if (topbar) {
++ anchors[GTK_LAYER_SHELL_EDGE_LEFT] = false;
++ anchors[GTK_LAYER_SHELL_EDGE_RIGHT] = true;
++ anchors[GTK_LAYER_SHELL_EDGE_TOP] = true;
++ anchors[GTK_LAYER_SHELL_EDGE_BOTTOM] = false;
++ } else {
++ anchors[GTK_LAYER_SHELL_EDGE_LEFT] = false;
++ anchors[GTK_LAYER_SHELL_EDGE_RIGHT] = true;
++ anchors[GTK_LAYER_SHELL_EDGE_TOP] = false;
++ anchors[GTK_LAYER_SHELL_EDGE_BOTTOM] = true;
++ }
++
++ systray = sn_systray_new(iconsize,
++ traymargins,
++ trayspacing,
++ conn);
++ window = GTK_WINDOW(gtk_window_new());
++
++ gtk_window_set_default_size(window, tray_init_width, tray_height);
++ gtk_window_set_child(window, GTK_WIDGET(systray));
++ gtk_window_set_application(window, app);
++ gtk_layer_init_for_window(window);
++ gtk_layer_set_layer(window, GTK_LAYER_SHELL_LAYER_BOTTOM);
++ gtk_layer_set_exclusive_zone(window, -1);
++ gtk_layer_set_monitor(window, gdkmon);
++
++ for (int j = 0; j < GTK_LAYER_SHELL_EDGE_ENTRY_NUMBER; j++) {
++ gtk_layer_set_anchor(window, j, anchors[j]);
++ }
++
++ updatebar(m, tray_init_width);
++ g_signal_connect(systray, "notify::curwidth", G_CALLBACK(gtkhandlewidthnotify), m);
++ gtk_window_present(window);
++}
++
++void
++gtkterminate(void *data)
++{
++ GtkApplication *app;
++ GList *windows;
++
++ app = GTK_APPLICATION(g_application_get_default());
++ windows = gtk_application_get_windows(app);
++ g_list_foreach(windows, gtkclosewindows, NULL);
++}
++
++GdkMonitor*
++gtkwlrtogdkmon(Monitor *wlrmon)
++{
++ GdkMonitor *gdkmon = NULL;
++
++ GListModel *gdkmons;
++ GdkDisplay *display;
++ const char *gdkname;
++ const char *wlrname;
++ unsigned int i;
++
++ wlrname = wlrmon->wlr_output->name;
++ display = gdk_display_get_default();
++ gdkmons = gdk_display_get_monitors(display);
++
++ for (i = 0; i < g_list_model_get_n_items(gdkmons); i++) {
++ GdkMonitor *mon = g_list_model_get_item(gdkmons, i);
++ gdkname = gdk_monitor_get_connector(mon);
++ if (strcmp(wlrname, gdkname) == 0)
++ gdkmon = mon;
++ }
++
++ return gdkmon;
++}
++
++void
++gtktoggletray(void *data, void *udata)
++{
++ GtkWidget *widget = GTK_WIDGET(data);
++ int *pbarvisible = (int *)udata;
++ int barvisible = GPOINTER_TO_INT(pbarvisible);
++
++ gtk_widget_set_visible(widget, barvisible);
++}
++
+ void
+ gpureset(struct wl_listener *listener, void *data)
+ {
+@@ -2293,6 +2488,8 @@ powermgrsetmode(struct wl_listener *listener, void *data)
+ void
+ quit(const Arg *arg)
+ {
++ g_idle_add_once(gtkterminate, NULL);
++ pthread_join(gtkthread, NULL);
+ wl_display_terminate(dpy);
+ }
+
+@@ -2836,6 +3033,9 @@ setup(void)
+ fprintf(stderr, "failed to setup XWayland X server, continuing without it\n");
+ }
+ #endif
++
++ // Gtk functions are only allowed to be called from this thread.
++ pthread_create(&gtkthread, NULL, &gtkinit, NULL);
+ }
+
+ void
+@@ -2943,9 +3143,21 @@ tile(Monitor *m)
+ void
+ togglebar(const Arg *arg)
+ {
++ int barvisible;
++ int *pbarvisible;
++
+ wlr_scene_node_set_enabled(&selmon->scene_buffer->node,
+ !selmon->scene_buffer->node.enabled);
+ arrangelayers(selmon);
++
++ // Notify gtkthread
++ if (selmon->scene_buffer->node.enabled)
++ barvisible = 1;
++ else
++ barvisible = 0;
++
++ pbarvisible = GINT_TO_POINTER(barvisible);
++ g_idle_add_once(gtkhandletogglebarmsg, pbarvisible);
+ }
+
+ void
+@@ -3140,7 +3352,7 @@ updatemons(struct wl_listener *listener, void *data)
+ if (stext[0] == '\0')
+ strncpy(stext, "dwl-"VERSION, sizeof(stext));
+ wl_list_for_each(m, &mons, link) {
+- updatebar(m);
++ updatebar(m, 0);
+ drawbar(m);
+ }
+
+@@ -3155,7 +3367,7 @@ updatemons(struct wl_listener *listener, void *data)
+ }
+
+ void
+-updatebar(Monitor *m)
++updatebar(Monitor *m, int traywidth)
+ {
+ size_t i;
+ int rw, rh;
+@@ -3163,7 +3375,7 @@ updatebar(Monitor *m)
+
+ wlr_output_transformed_resolution(m->wlr_output, &rw, &rh);
+ m->b.width = rw;
+- m->b.real_width = (int)((float)m->b.width / m->wlr_output->scale);
++ m->b.real_width = (int)((float)m->b.width / m->wlr_output->scale) - traywidth;
+
+ wlr_scene_node_set_enabled(&m->scene_buffer->node, m->wlr_output->enabled ? showbar : 0);
+
+diff --git a/include/.gitignore b/include/.gitignore
+new file mode 100644
+index 0000000..424c745
+--- /dev/null
++++ b/include/.gitignore
+@@ -0,0 +1 @@
++*.h
+diff --git a/lib/.gitignore b/lib/.gitignore
+new file mode 100644
+index 0000000..10301e2
+--- /dev/null
++++ b/lib/.gitignore
+@@ -0,0 +1 @@
++*.a
+--
+2.46.0
+
diff --git a/dwl-patches/stale-patches/bar-systray-old/systray.png b/dwl-patches/stale-patches/bar-systray-old/systray.png
new file mode 100644
index 0000000..54f9f98
--- /dev/null
+++ b/dwl-patches/stale-patches/bar-systray-old/systray.png
Binary files differ
diff --git a/dwl-patches/stale-patches/master-right/README.md b/dwl-patches/stale-patches/master-right/README.md
new file mode 100644
index 0000000..0f69bbc
--- /dev/null
+++ b/dwl-patches/stale-patches/master-right/README.md
@@ -0,0 +1,13 @@
+### Description
+Show the master area to the right.
+
+### Reason for deprecation
+I created this patch for a user on Discord and I have never used it.
+
+### Download
+- [git branch](https://codeberg.org/sevz/dwl/src/branch/master-right)
+- [main 2024-09-01](/dwl/dwl-patches/raw/branch/main/patches/master-right/master-right.patch)
+- [master-right-0.7.patch](/dwl/dwl-patches/raw/branch/main/patches/master-right/master-right-0.7.patch)
+
+### Authors
+- [sevz](https://codeberg.org/sevz)
diff --git a/dwl-patches/stale-patches/master-right/master-right-0.7.patch b/dwl-patches/stale-patches/master-right/master-right-0.7.patch
new file mode 100644
index 0000000..e4845f4
--- /dev/null
+++ b/dwl-patches/stale-patches/master-right/master-right-0.7.patch
@@ -0,0 +1,35 @@
+From f72236247e5e7cb23c3cac86b496cdd2c523f7ff Mon Sep 17 00:00:00 2001
+From: Sevz17 <leohdz172@outlook.com>
+Date: Fri, 25 Jun 2021 19:50:56 -0500
+Subject: [PATCH] show master area to the right
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Leonardo Hernández Hernández <leohdz172@proton.me>
+---
+ dwl.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/dwl.c b/dwl.c
+index a2711f67..50b057a7 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -2710,11 +2710,12 @@ tile(Monitor *m)
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ if (i < m->nmaster) {
+- resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
++ resize(c, (struct wlr_box){.x = m->w.x + m->w.width - mw,
++ .y = m->w.y + my, .width = mw,
+ .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
+ my += c->geom.height;
+ } else {
+- resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
++ resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + ty,
+ .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
+ ty += c->geom.height;
+ }
+--
+2.46.0
+
diff --git a/dwl-patches/stale-patches/master-right/master-right.patch b/dwl-patches/stale-patches/master-right/master-right.patch
new file mode 100644
index 0000000..70c80a1
--- /dev/null
+++ b/dwl-patches/stale-patches/master-right/master-right.patch
@@ -0,0 +1,35 @@
+From 0afd0a98998dda20e4fe4f4d2b5fcdec49c448c3 Mon Sep 17 00:00:00 2001
+From: Sevz17 <leohdz172@outlook.com>
+Date: Fri, 25 Jun 2021 19:50:56 -0500
+Subject: [PATCH] show master area to the right
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Leonardo Hernández Hernández <leohdz172@proton.me>
+---
+ dwl.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/dwl.c b/dwl.c
+index 9021e442..2bd354a3 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -2670,11 +2670,12 @@ tile(Monitor *m)
+ if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen)
+ continue;
+ if (i < m->nmaster) {
+- resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + my, .width = mw,
++ resize(c, (struct wlr_box){.x = m->w.x + m->w.width - mw,
++ .y = m->w.y + my, .width = mw,
+ .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0);
+ my += c->geom.height;
+ } else {
+- resize(c, (struct wlr_box){.x = m->w.x + mw, .y = m->w.y + ty,
++ resize(c, (struct wlr_box){.x = m->w.x, .y = m->w.y + ty,
+ .width = m->w.width - mw, .height = (m->w.height - ty) / (n - i)}, 0);
+ ty += c->geom.height;
+ }
+--
+2.46.0
+
diff --git a/dwl-patches/stale-patches/press_repeat_release/README.md b/dwl-patches/stale-patches/press_repeat_release/README.md
new file mode 100644
index 0000000..b9b4ff3
--- /dev/null
+++ b/dwl-patches/stale-patches/press_repeat_release/README.md
@@ -0,0 +1,15 @@
+### Description
+This patch adds 3 additional options to the `Key` struct, `on_press`, `on_repeat` and `on_release` which can be used to control which events a key binding should be triggered on.
+
+NOTE: Due to concerns about patching difficulties this patch does NOT include any changes to `config.def.h`. After applying you will need to add the 3 additional initializers to each key binding that you would like to modify. Any key binding that is not updated will cause a build warning but should function as it does in vanilla.
+
+2025-01-04 Moved to stale patches.
+Outstanding issues with this patch: https://codeberg.org/dwl/dwl-patches/issues/98
+Patch maintainer notes he is no longer maintaining dwl patches: https://codeberg.org/dwl/dwl-patches/pulls/102
+
+### Download
+- [git branch](https://codeberg.org/USERNAME/dwl/src/branch/press_repeat_release)
+- [2024-03-27](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/press_repeat_release/press_repeat_release.patch)
+
+### Authors
+- [minego](https://codeberg.org/minego)
diff --git a/dwl-patches/stale-patches/press_repeat_release/press_repeat_release.patch b/dwl-patches/stale-patches/press_repeat_release/press_repeat_release.patch
new file mode 100644
index 0000000..b86666d
--- /dev/null
+++ b/dwl-patches/stale-patches/press_repeat_release/press_repeat_release.patch
@@ -0,0 +1,108 @@
+From aee1dc3e9ca4d8deec5432d0c64921af6e301ecd Mon Sep 17 00:00:00 2001
+From: Micah N Gorrell <m@minego.net>
+Date: Wed, 27 Mar 2024 15:59:50 -0600
+Subject: [PATCH 1/2] onpress, onrepeat, onrelease
+
+---
+ dwl.c | 18 ++++++++++++------
+ 1 file changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/dwl.c b/dwl.c
+index 5867b0c..43bbf0c 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -146,6 +146,10 @@ typedef struct {
+ xkb_keysym_t keysym;
+ void (*func)(const Arg *);
+ const Arg arg;
++
++ int on_press;
++ int on_repeat;
++ int on_release;
+ } Key;
+
+ typedef struct {
+@@ -286,7 +290,7 @@ static void fullscreennotify(struct wl_listener *listener, void *data);
+ static void handlesig(int signo);
+ static void incnmaster(const Arg *arg);
+ static void inputdevice(struct wl_listener *listener, void *data);
+-static int keybinding(uint32_t mods, xkb_keysym_t sym);
++static int keybinding(uint32_t mods, xkb_keysym_t sym, int on_press, int on_repeat, int on_release);
+ static void keypress(struct wl_listener *listener, void *data);
+ static void keypressmod(struct wl_listener *listener, void *data);
+ static int keyrepeat(void *data);
+@@ -1428,7 +1432,7 @@ inputdevice(struct wl_listener *listener, void *data)
+ }
+
+ int
+-keybinding(uint32_t mods, xkb_keysym_t sym)
++keybinding(uint32_t mods, xkb_keysym_t sym, int on_press, int on_repeat, int on_release)
+ {
+ /*
+ * Here we handle compositor keybindings. This is when the compositor is
+@@ -1439,8 +1443,10 @@ keybinding(uint32_t mods, xkb_keysym_t sym)
+ for (k = keys; k < END(keys); k++) {
+ if (CLEANMASK(mods) == CLEANMASK(k->mod)
+ && sym == k->keysym && k->func) {
+- k->func(&k->arg);
+- return 1;
++ if ((on_press && k->on_press) || (on_repeat && k->on_repeat) || (on_release && k->on_release)) {
++ k->func(&k->arg);
++ return 1;
++ }
+ }
+ }
+ return 0;
+@@ -1470,7 +1476,7 @@ keypress(struct wl_listener *listener, void *data)
+ * attempt to process a compositor keybinding. */
+ if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ for (i = 0; i < nsyms; i++)
+- handled = keybinding(mods, syms[i]) || handled;
++ handled = keybinding(mods, syms[i], event->state == WL_KEYBOARD_KEY_STATE_PRESSED, 0, event->state == WL_KEYBOARD_KEY_STATE_RELEASED) || handled;
+ }
+
+ if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) {
+@@ -1518,7 +1524,7 @@ keyrepeat(void *data)
+ 1000 / group->wlr_group->keyboard.repeat_info.rate);
+
+ for (i = 0; i < group->nsyms; i++)
+- keybinding(group->mods, group->keysyms[i]);
++ keybinding(group->mods, group->keysyms[i], 0, 1, 0);
+
+ return 0;
+ }
+--
+2.44.0
+
+
+From 1875bb171c9b0cd2fb03bb7e6c3fb400e33eeaf1 Mon Sep 17 00:00:00 2001
+From: Micah N Gorrell <m@minego.net>
+Date: Wed, 27 Mar 2024 16:26:52 -0600
+Subject: [PATCH 2/2] Modified logic so that an unmodified keybinding with
+ default values for the new flags will behave as it does in vanilla, while
+ keybindings with customized flags will function as expected
+
+---
+ dwl.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/dwl.c b/dwl.c
+index 43bbf0c..55e7a40 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -1443,7 +1443,11 @@ keybinding(uint32_t mods, xkb_keysym_t sym, int on_press, int on_repeat, int on_
+ for (k = keys; k < END(keys); k++) {
+ if (CLEANMASK(mods) == CLEANMASK(k->mod)
+ && sym == k->keysym && k->func) {
+- if ((on_press && k->on_press) || (on_repeat && k->on_repeat) || (on_release && k->on_release)) {
++ if ((k->on_press == 0 && k->on_repeat == 0 && k->on_release == 0) ||
++ (on_press && k->on_press) ||
++ (on_repeat && k->on_repeat) ||
++ (on_release && k->on_release)
++ ) {
+ k->func(&k->arg);
+ return 1;
+ }
+--
+2.44.0
+
diff --git a/dwl-patches/stale-patches/remembertags/README.md b/dwl-patches/stale-patches/remembertags/README.md
new file mode 100644
index 0000000..b45e87c
--- /dev/null
+++ b/dwl-patches/stale-patches/remembertags/README.md
@@ -0,0 +1,16 @@
+### Description
+This patch modifies the behavior when selecting tags so that selecting a tag will also enable any other tags that were previously visible.
+
+For example:
+1. Select tag 5, with mod+5
+2. Toggle tag 8, with ctrl+mod+8
+3. Select tag 1, with mod+1. Tags 5 and 8 should no longer be visible.
+4. Select tag 5 again, with mod+5. Tag 8 should be visible since it was remembered.
+5. Select tag 5 again, with mod_5. Selecting the already selected tag resets any remembered tags, so now tag 5 should be the only one visible.
+
+### Download
+- [git branch](https://codeberg.org/minego/dwl/src/branch/remembertags)
+- [2024-03-27](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/remembertags/remembertags.patch)
+
+### Authors
+- [minego](https://codeberg.org/minego) \ No newline at end of file
diff --git a/dwl-patches/stale-patches/remembertags/remembertags.patch b/dwl-patches/stale-patches/remembertags/remembertags.patch
new file mode 100644
index 0000000..fd6135e
--- /dev/null
+++ b/dwl-patches/stale-patches/remembertags/remembertags.patch
@@ -0,0 +1,105 @@
+From fea6eb3cfc84ede8403c89a3230f5c658a6c7bd1 Mon Sep 17 00:00:00 2001
+From: Micah N Gorrell <m@minego.net>
+Date: Wed, 27 Mar 2024 13:05:09 -0600
+Subject: [PATCH] remembertags
+
+---
+ config.def.h | 8 ++++----
+ dwl.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 52 insertions(+), 4 deletions(-)
+
+diff --git a/config.def.h b/config.def.h
+index 9009517..2312802 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -105,10 +105,10 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
+ #define MODKEY WLR_MODIFIER_ALT
+
+ #define TAGKEYS(KEY,SKEY,TAG) \
+- { MODKEY, KEY, view, {.ui = 1 << TAG} }, \
+- { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
+- { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
+- { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT,SKEY,toggletag, {.ui = 1 << TAG} }
++ { MODKEY, KEY, remembertagsview, {.i = TAG} }, \
++ { MODKEY|WLR_MODIFIER_CTRL, KEY, toggleview, {.ui = 1 << TAG} }, \
++ { MODKEY|WLR_MODIFIER_SHIFT, SKEY, tag, {.ui = 1 << TAG} }, \
++ { MODKEY|WLR_MODIFIER_CTRL|WLR_MODIFIER_SHIFT, SKEY, toggletag, {.ui = 1 << TAG} }
+
+ /* helper for spawning shell commands in the pre dwm-5.0 fashion */
+ #define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+diff --git a/dwl.c b/dwl.c
+index 5867b0c..31a81aa 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -205,6 +205,11 @@ struct Monitor {
+ int gamma_lut_changed;
+ int nmaster;
+ char ltsymbol[16];
++ unsigned int createtag[2]; /* Create windows on the last tag directly selected, not all selected */
++ struct {
++ unsigned int tagset;
++ Client *zoomed;
++ } remembered[31];
+ };
+
+ typedef struct {
+@@ -308,6 +313,7 @@ static void pointerfocus(Client *c, struct wlr_surface *surface,
+ double sx, double sy, uint32_t time);
+ static void printstatus(void);
+ static void quit(const Arg *arg);
++static void remembertagsview(const Arg *arg);
+ static void rendermon(struct wl_listener *listener, void *data);
+ static void requestdecorationmode(struct wl_listener *listener, void *data);
+ static void requeststartdrag(struct wl_listener *listener, void *data);
+@@ -1951,6 +1957,48 @@ quit(const Arg *arg)
+ wl_display_terminate(dpy);
+ }
+
++void
++remembertagsview(const Arg *arg) {
++ unsigned newtags = (1 << arg->i) & TAGMASK;
++ int oldtag;
++ int active;
++ unsigned int newcreate;
++
++ if (selmon == NULL) {
++ return;
++ }
++
++ oldtag = selmon->createtag[selmon->seltags];
++ active = (oldtag == arg->i);
++
++ if (oldtag < TAGCOUNT) {
++ selmon->remembered[oldtag].tagset = selmon->tagset[selmon->seltags];
++ }
++
++ selmon->seltags ^= 1; /*toggle tagset*/
++
++ if (-1 == arg->i) {
++ /* A specific tag was not specified */
++ active = 0;
++ newcreate = selmon->createtag[selmon->seltags];
++ } else {
++ newcreate = arg->i;
++ }
++
++ if (active) {
++ /* Select twice to isolate the tag */
++ selmon->tagset[selmon->seltags] = newtags;
++ } else if (arg->i < TAGCOUNT) {
++ /* Restore whatever was previously on this tag */
++ selmon->tagset[selmon->seltags] = newtags | selmon->remembered[newcreate].tagset;
++ }
++
++ selmon->createtag[selmon->seltags] = newcreate;
++ focusclient(focustop(selmon), 1);
++ arrange(selmon);
++ printstatus();
++}
++
+ void
+ rendermon(struct wl_listener *listener, void *data)
+ {
+--
+2.44.0
+
diff --git a/dwl-patches/stale-patches/tab-pango/README.md b/dwl-patches/stale-patches/tab-pango/README.md
new file mode 100644
index 0000000..c7e4a1c
--- /dev/null
+++ b/dwl-patches/stale-patches/tab-pango/README.md
@@ -0,0 +1,10 @@
+### Description
+Add a tab bar or window title to the top or bottom of windows.
+
+**This is the old version of the `tab` patch. Deprecated because the [new version](https://codeberg.org/dwl/dwl-patches/raw/branch-main/patches/tab) is significantly more efficient and well-written than this, and it better adheres to the suckless philosophy.**
+
+### Download
+- [2024-03-15](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tab/tab.patch)
+
+### Authors
+- [dev-gm](https://codeberg.org/dev-gm)
diff --git a/dwl-patches/stale-patches/tab-pango/tab.patch b/dwl-patches/stale-patches/tab-pango/tab.patch
new file mode 100644
index 0000000..5b7b8a0
--- /dev/null
+++ b/dwl-patches/stale-patches/tab-pango/tab.patch
@@ -0,0 +1,461 @@
+From b624206781513cdff1b9609fc5ac4b848094e1b4 Mon Sep 17 00:00:00 2001
+From: Gavin M <github@gavinm.us>
+Date: Fri, 15 Mar 2024 16:37:23 -0500
+Subject: [PATCH] Tabbed patch
+
+---
+ Makefile | 2 +-
+ config.def.h | 18 +++-
+ dwl.c | 276 +++++++++++++++++++++++++++++++++++++++++++++++++--
+ 3 files changed, 281 insertions(+), 15 deletions(-)
+
+diff --git a/Makefile b/Makefile
+index a67fdd3..182eb87 100644
+--- a/Makefile
++++ b/Makefile
+@@ -9,7 +9,7 @@ DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unu
+ -Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types -Wfloat-conversion
+
+ # CFLAGS / LDFLAGS
+-PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS)
++PKGS = wlroots wayland-server xkbcommon libinput cairo pangocairo $(XLIBS)
+ DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
+ LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS)
+
+diff --git a/config.def.h b/config.def.h
+index 9009517..1ca270f 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -7,6 +7,16 @@
+ static const int sloppyfocus = 1; /* focus follows mouse */
+ static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
+ static const unsigned int borderpx = 1; /* border pixel of windows */
++static const double title_border_width = 0.75;
++static const unsigned int title_padding = 11;
++static const int title_top = 0;
++static const LayoutType floating_title_type = LAYOUT_TYPE_LABEL;
++static const char title_font[] = "Dejavu Sans Mono 10.5";
++static const float title_font_color[] = COLOR(0xffffffff);
++static const float title_focus_bg[] = COLOR(0x3b3b3bff);
++static const float title_root_bg[] = COLOR(0x131313ff);
++static const float title_urgent_bg[] = COLOR(0x00ff00ff);
++static const float title_border_color[] = COLOR(0x3b3b3bff);
+ static const float rootcolor[] = COLOR(0x222222ff);
+ static const float bordercolor[] = COLOR(0x444444ff);
+ static const float focuscolor[] = COLOR(0x005577ff);
+@@ -30,10 +40,10 @@ static const Rule rules[] = {
+
+ /* layout(s) */
+ static const Layout layouts[] = {
+- /* symbol arrange function */
+- { "[]=", tile },
+- { "><>", NULL }, /* no layout function means floating behavior */
+- { "[M]", monocle },
++ /* symbol type render_only_top arrange function */
++ { "[]=", LAYOUT_TYPE_NONE, 0, tile },
++ { "><>", LAYOUT_TYPE_LABEL, 0, NULL }, /* no layout function means floating behavior */
++ { "[M]", LAYOUT_TYPE_TABS_ONLY_MULTIPLE_CLIENTS, 1, monocle },
+ };
+
+ /* monitors */
+diff --git a/dwl.c b/dwl.c
+index 5867b0c..e613d17 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -2,6 +2,11 @@
+ * See LICENSE file for copyright and license details.
+ */
+ #include <getopt.h>
++#include <cairo/cairo.h>
++#include <pango/pangocairo.h>
++#include <pango/pango-font.h>
++#include <pango/pango-layout.h>
++#include <libdrm/drm_fourcc.h>
+ #include <libinput.h>
+ #include <linux/input-event-codes.h>
+ #include <signal.h>
+@@ -13,8 +18,10 @@
+ #include <wayland-server-core.h>
+ #include <wlr/backend.h>
+ #include <wlr/backend/libinput.h>
++#include <wlr/interfaces/wlr_buffer.h>
+ #include <wlr/render/allocator.h>
+ #include <wlr/render/wlr_renderer.h>
++#include <wlr/types/wlr_buffer.h>
+ #include <wlr/types/wlr_compositor.h>
+ #include <wlr/types/wlr_cursor.h>
+ #include <wlr/types/wlr_cursor_shape_v1.h>
+@@ -110,6 +117,7 @@ typedef struct {
+ struct wlr_scene_tree *scene;
+ struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
+ struct wlr_scene_tree *scene_surface;
++ struct wlr_scene_buffer *titlebar;
+ struct wl_list link;
+ struct wl_list flink;
+ union {
+@@ -137,7 +145,7 @@ typedef struct {
+ #endif
+ unsigned int bw;
+ uint32_t tags;
+- int isfloating, isurgent, isfullscreen;
++ int isfloating, isurgent, isfullscreen, titleisinit, istabbed;
+ uint32_t resize; /* configure serial of a pending resize */
+ } Client;
+
+@@ -179,8 +187,17 @@ typedef struct {
+ struct wl_listener surface_commit;
+ } LayerSurface;
+
++typedef enum {
++ LAYOUT_TYPE_NONE,
++ LAYOUT_TYPE_LABEL,
++ LAYOUT_TYPE_TABS_ONLY_MULTIPLE_CLIENTS,
++ LAYOUT_TYPE_TABS_ALWAYS
++} LayoutType;
++
+ typedef struct {
+ const char *symbol;
++ LayoutType type;
++ int render_top_only;
+ void (*arrange)(Monitor *);
+ } Layout;
+
+@@ -282,6 +299,7 @@ static void focusclient(Client *c, int lift);
+ static void focusmon(const Arg *arg);
+ static void focusstack(const Arg *arg);
+ static Client *focustop(Monitor *m);
++static Client *focustop_onlytiled(Monitor *m, int onlytiled);
+ static void fullscreennotify(struct wl_listener *listener, void *data);
+ static void handlesig(int signo);
+ static void incnmaster(const Arg *arg);
+@@ -309,6 +327,7 @@ static void pointerfocus(Client *c, struct wlr_surface *surface,
+ static void printstatus(void);
+ static void quit(const Arg *arg);
+ static void rendermon(struct wl_listener *listener, void *data);
++static void rendertitlebar(Client *client);
+ static void requestdecorationmode(struct wl_listener *listener, void *data);
+ static void requeststartdrag(struct wl_listener *listener, void *data);
+ static void requestmonstate(struct wl_listener *listener, void *data);
+@@ -349,6 +368,7 @@ static void xytonode(double x, double y, struct wlr_surface **psurface,
+ static void zoom(const Arg *arg);
+
+ /* variables */
++static int title_height;
+ static const char broken[] = "broken";
+ static pid_t child_pid = -1;
+ static int locked;
+@@ -973,6 +993,7 @@ createnotify(struct wl_listener *listener, void *data)
+ c = xdg_surface->data = ecalloc(1, sizeof(*c));
+ c->surface.xdg = xdg_surface;
+ c->bw = borderpx;
++ c->titleisinit = c->istabbed = 0;
+
+ wlr_xdg_toplevel_set_wm_capabilities(xdg_surface->toplevel,
+ WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
+@@ -1360,6 +1381,22 @@ focustop(Monitor *m)
+ return NULL;
+ }
+
++Client *
++focustop_onlytiled(Monitor *m, int onlytiled)
++{
++ Client *c;
++ if (!m)
++ return NULL;
++ wl_list_for_each(c, &fstack, flink) {
++ if (VISIBLEON(c, m)) {
++ if ((onlytiled == 1 && c->isfloating) || (onlytiled == 2 && (!c->isfloating || !m->lt[m->sellt]->arrange)))
++ continue;
++ return c;
++ }
++ }
++ return NULL;
++}
++
+ void
+ fullscreennotify(struct wl_listener *listener, void *data)
+ {
+@@ -2003,6 +2040,195 @@ skip:
+ wlr_output_state_finish(&pending);
+ }
+
++struct text_buffer {
++ struct wlr_buffer base;
++ void *data;
++ uint32_t format;
++ size_t stride;
++};
++
++static void text_buffer_destroy(struct wlr_buffer *wlr_buffer) {
++ struct text_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
++ free(buffer->data);
++ free(buffer);
++}
++
++static bool text_buffer_begin_data_ptr_access(struct wlr_buffer *wlr_buffer,
++ uint32_t flags, void **data, uint32_t *format, size_t *stride) {
++ struct text_buffer *buffer = wl_container_of(wlr_buffer, buffer, base);
++ if(data != NULL) {
++ *data = (void *)buffer->data;
++ }
++ if(format != NULL) {
++ *format = buffer->format;
++ }
++ if(stride != NULL) {
++ *stride = buffer->stride;
++ }
++ return true;
++}
++
++static void text_buffer_end_data_ptr_access(struct wlr_buffer *wlr_buffer) {
++ // This space is intentionally left blank
++}
++
++static const struct wlr_buffer_impl text_buffer_impl = {
++ .destroy = text_buffer_destroy,
++ .begin_data_ptr_access = text_buffer_begin_data_ptr_access,
++ .end_data_ptr_access = text_buffer_end_data_ptr_access,
++};
++
++static struct text_buffer *text_buffer_create(uint32_t width, uint32_t height, uint32_t stride) {
++ struct text_buffer *buffer = calloc(1, sizeof(*buffer));
++ if (buffer == NULL) {
++ return NULL;
++ }
++
++ wlr_buffer_init(&buffer->base, &text_buffer_impl, width, height);
++ buffer->format = DRM_FORMAT_ARGB8888;
++ buffer->stride = stride;
++
++ buffer->data = malloc(buffer->stride * height);
++ if (buffer->data == NULL) {
++ free(buffer);
++ return NULL;
++ }
++
++ return buffer;
++}
++
++void
++rendertitlebar(Client *c)
++{
++ struct wl_list *init_destroy, *cursor_destroy;
++ cairo_surface_t *surface;
++ cairo_status_t status;
++ cairo_t *cr;
++ PangoFontDescription *desc;
++ PangoLayout *layout;
++ LayoutType title_type;
++ Client *l, *sel;
++ unsigned int len, tabsize, i;
++ const char *title;
++ const float *color;
++ unsigned char *data;
++ int stride;
++ struct text_buffer *text_buffer;
++ void *data_ptr;
++
++ if (!c || !c->scene || !c->mon || !selmon || (!VISIBLEON(c, selmon) && c->mon == selmon))
++ return;
++
++ if (c->titleisinit) {
++ init_destroy = cursor_destroy = &c->titlebar->node.events.destroy.listener_list;
++ do {
++ cursor_destroy = cursor_destroy->next;
++ } while (cursor_destroy && cursor_destroy != init_destroy);
++ if (!cursor_destroy) {
++ return;
++ }
++ wlr_scene_node_destroy(&c->titlebar->node);
++ }
++ c->titleisinit = c->istabbed = 0;
++
++ sel = focustop_onlytiled(c->mon, c->isfloating + 1);
++
++ if (c->isfullscreen)
++ return;
++ title_type = c->isfloating ? floating_title_type : c->mon->lt[c->mon->sellt]->type;
++
++ if (title_type == LAYOUT_TYPE_TABS_ONLY_MULTIPLE_CLIENTS || title_type == LAYOUT_TYPE_TABS_ALWAYS) {
++ len = 0;
++ wl_list_for_each(l, &clients, link) {
++ if (VISIBLEON(l, c->mon) && l->isfloating == c->isfloating)
++ len++;
++ }
++ if (title_type == LAYOUT_TYPE_TABS_ONLY_MULTIPLE_CLIENTS && len <= 1)
++ return;
++ }
++
++ if (c->mon->lt[c->mon->sellt]->render_top_only == 1 && !c->isfloating && c != sel) {
++ c->istabbed = 1;
++ return;
++ } /*else if (c->mon->lt[c->mon->sellt]->render_top_only == 2 && c != sel) {
++ c->istabbed = 1;
++ return;
++ }*/
++
++ if (title_type == LAYOUT_TYPE_NONE)
++ return;
++
++ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, c->geom.width, title_height);
++ if ((status = cairo_surface_status(surface)) != CAIRO_STATUS_SUCCESS) {
++ wlr_log(WLR_ERROR, "cairo_image_surface_create failed: %s",
++ cairo_status_to_string(status));
++ return;
++ }
++ cr = cairo_create(surface);
++ desc = pango_font_description_from_string(title_font);
++ layout = pango_cairo_create_layout(cr);
++ pango_layout_set_font_description(layout, desc);
++ pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_NONE);
++
++ cairo_set_line_width(cr, title_border_width);
++
++ if (title_type == LAYOUT_TYPE_LABEL) {
++ cairo_rectangle(cr, 0, 0, c->geom.width, title_height);
++ cairo_set_source_rgba(cr, title_focus_bg[0], title_focus_bg[1], title_focus_bg[2], title_focus_bg[3]);
++ cairo_fill_preserve(cr);
++ cairo_set_source_rgba(cr, title_border_color[0], title_border_color[1], title_border_color[2], title_border_color[3]);
++ cairo_stroke(cr);
++ cairo_set_source_rgba(cr, title_font_color[0], title_font_color[1], title_font_color[2], title_font_color[3]);
++ title = client_get_title(c);
++ pango_layout_set_text(layout, title ? title : " ", (c->geom.width - title_padding) * PANGO_SCALE);
++ cairo_move_to(cr, title_padding, 0);
++ pango_cairo_show_layout(cr, layout);
++ } else {
++ tabsize = c->geom.width / len;
++ i = 0;
++ wl_list_for_each(l, &clients, link) {
++ if (VISIBLEON(l, c->mon) && l->isfloating == c->isfloating) {
++ cairo_rectangle(cr, i * tabsize, 0, (i + 1) * tabsize, title_height);
++ color = (l == sel) ? title_focus_bg
++ : (c->isurgent ? title_urgent_bg : title_root_bg);
++ cairo_set_source_rgba(cr, color[0], color[1], color[2], color[3]);
++ cairo_fill_preserve(cr);
++ cairo_set_source_rgba(cr, title_border_color[0], title_border_color[1], title_border_color[2], title_border_color[3]);
++ cairo_stroke(cr);
++ cairo_set_source_rgba(cr, title_font_color[0], title_font_color[1], title_font_color[2], title_font_color[3]);
++ title = client_get_title(l);
++ pango_layout_set_text(layout, title ? title : " ", (tabsize - title_padding) * PANGO_SCALE);
++ cairo_move_to(cr, (i * tabsize) + title_padding, 0);
++ pango_cairo_show_layout(cr, layout);
++ i++;
++ }
++ }
++ }
++
++ data = cairo_image_surface_get_data(surface);
++ stride = cairo_image_surface_get_stride(surface);
++ text_buffer = text_buffer_create(c->geom.width, title_height, stride);
++
++ if(!wlr_buffer_begin_data_ptr_access(&text_buffer->base,
++ WLR_BUFFER_DATA_PTR_ACCESS_WRITE, &data_ptr, NULL, NULL)) {
++ wlr_log(WLR_ERROR, "%s", "Failed to get pointer access to text buffer");
++ return;
++ }
++ memcpy(data_ptr, data, stride * title_height);
++ wlr_buffer_end_data_ptr_access(&text_buffer->base);
++ cairo_surface_destroy(surface);
++
++ c->titlebar = wlr_scene_buffer_create(c->scene, &text_buffer->base);
++ c->titleisinit = c->istabbed = 1;
++
++ wlr_scene_node_set_position(&c->titlebar->node, 0, !title_top ? c->geom.height - title_height : 0);
++ wlr_scene_node_raise_to_top(&c->titlebar->node);
++
++ pango_font_description_free(desc);
++ g_object_unref(layout);
++ cairo_destroy(cr);
++}
++
+ void
+ requestdecorationmode(struct wl_listener *listener, void *data)
+ {
+@@ -2036,24 +2262,30 @@ resize(Client *c, struct wlr_box geo, int interact)
+ {
+ struct wlr_box *bbox = interact ? &sgeom : &c->mon->w;
+ struct wlr_box clip;
++ unsigned int th;
++ int draw_borders = 1;
+ client_set_bounds(c, geo.width, geo.height);
+ c->geom = geo;
++ c->bw = draw_borders ? borderpx : 0;
+ applybounds(c, bbox);
+
++ rendertitlebar(c);
++ th = c->istabbed ? title_height : c->bw;
++
+ /* Update scene-graph, including borders */
+ wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
+- wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
+- wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
+- wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
+- wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
+- wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
+- wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
+- wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
+- wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
++ wlr_scene_node_set_position(&c->scene_surface->node, c->bw, title_top ? th : c->bw);
++ wlr_scene_rect_set_size(c->border[0], c->geom.width, (title_top && c->istabbed) ? 0 : c->bw);
++ wlr_scene_rect_set_size(c->border[1], c->geom.width, (!title_top && c->istabbed) ? 0 : c->bw);
++ wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - (c->bw + th));
++ wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - (c->bw + th));
++ wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - (title_top ? c->bw : th));
++ wlr_scene_node_set_position(&c->border[2]->node, 0, title_top ? th : c->bw);
++ wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, title_top ? th : c->bw);
+
+ /* this is a no-op if size hasn't changed */
+ c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
+- c->geom.height - 2 * c->bw);
++ c->geom.height - (c->bw + th));
+ client_get_clip(c, &clip);
+ wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
+ }
+@@ -2274,6 +2506,11 @@ setup(void)
+
+ int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
+ struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
++ cairo_surface_t *surface;
++ cairo_t *cr;
++ PangoFontDescription *desc;
++ PangoLayout *layout;
++
+ sigemptyset(&sa.sa_mask);
+
+ for (i = 0; i < (int)LENGTH(sig); i++)
+@@ -2506,6 +2743,24 @@ setup(void)
+
+ wlr_scene_set_presentation(scene, wlr_presentation_create(dpy, backend));
+
++ surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
++
++ cr = cairo_create(surface);
++
++ desc = pango_font_description_from_string(title_font);
++ /* Create Pango layout. */
++ layout = pango_cairo_create_layout(cr);
++ pango_layout_set_font_description(layout, desc);
++ pango_layout_set_text(layout, " ", -1);
++ /* Set width and height to text size */
++ pango_layout_get_pixel_size(layout, NULL, &title_height);
++
++ /* Cleanup */
++ pango_font_description_free (desc);
++ cairo_surface_destroy(surface);
++ g_object_unref (layout);
++ cairo_destroy(cr);
++
+ /* Make sure XWayland clients don't connect to the parent X server,
+ * e.g when running in the x11 backend or the wayland backend and the
+ * compositor has Xwayland support */
+@@ -2978,6 +3233,7 @@ createnotifyx11(struct wl_listener *listener, void *data)
+ c->surface.xwayland = xsurface;
+ c->type = X11;
+ c->bw = borderpx;
++ c->titleisinit = c->istabbed = 0;
+
+ /* Listen to the various events it can emit */
+ LISTEN(&xsurface->events.associate, &c->associate, associatex11);
+--
+2.44.0
+
diff --git a/dwl-patches/stale-patches/togglekblayout/README.md b/dwl-patches/stale-patches/togglekblayout/README.md
new file mode 100644
index 0000000..366a6d8
--- /dev/null
+++ b/dwl-patches/stale-patches/togglekblayout/README.md
@@ -0,0 +1,14 @@
+### Description
+
+> This patch is no longer being maintained by me [wochap](https://codeberg.org/wochap), since I'm now using a different patch specific to my use case: https://codeberg.org/wochap/dwl/src/branch/v0.6-b/xkb-rules-switcher/xkb-rules-switcher.patch
+
+Switch between multiple keyboard layouts at runtime.
+
+### Download
+- [git branch](https://codeberg.org/wochap/dwl/src/branch/v0.5/togglekblayout)
+- [v0.5](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/togglekblayout/togglekblayout.patch)
+
+### Authors
+- [wochap](https://codeberg.org/wochap)
+- [Stivvo](https://github.com/Stivvo)
+
diff --git a/dwl-patches/stale-patches/togglekblayout/togglekblayout.patch b/dwl-patches/stale-patches/togglekblayout/togglekblayout.patch
new file mode 100644
index 0000000..4ef802a
--- /dev/null
+++ b/dwl-patches/stale-patches/togglekblayout/togglekblayout.patch
@@ -0,0 +1,107 @@
+From 1bb99c78da484ce6036dc997962ed2f4c0d11208 Mon Sep 17 00:00:00 2001
+From: wochap <gean.marroquin@gmail.com>
+Date: Thu, 19 Oct 2023 23:21:49 -0500
+Subject: [PATCH 1/2] apply main...Stivvo:toggleKbLayout.patch
+
+---
+ config.def.h | 6 ++++++
+ dwl.c | 20 ++++++++++++++++++++
+ 2 files changed, 26 insertions(+)
+
+diff --git a/config.def.h b/config.def.h
+index db0babc..caa09ea 100644
+--- a/config.def.h
++++ b/config.def.h
+@@ -57,6 +57,11 @@ static const struct xkb_rule_names xkb_rules = {
+ static const int repeat_rate = 25;
+ static const int repeat_delay = 600;
+
++/* gb will be set the first time togglekblayout is called, then us.. it is
++ * recommended to set the same layout in position 0 of kblayouts and in
++ * xkb_rules */
++static const char *kblayouts[] = {"us", "gb"};
++
+ /* Trackpad */
+ static const int tap_to_click = 1;
+ static const int tap_and_drag = 1;
+@@ -141,6 +146,7 @@ static const Key keys[] = {
+ { MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
++ { MODKEY, XKB_KEY_w, togglekblayout, {0} },
+ TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
+ TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
+ TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
+diff --git a/dwl.c b/dwl.c
+index ef27a1d..25458e6 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -312,6 +312,7 @@ 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 togglekblayout(const Arg *arg);
+ static void togglefullscreen(const Arg *arg);
+ static void toggletag(const Arg *arg);
+ static void toggleview(const Arg *arg);
+@@ -368,6 +369,7 @@ static struct wl_listener lock_listener = {.notify = locksession};
+
+ static struct wlr_seat *seat;
+ static struct wl_list keyboards;
++static unsigned int kblayout = 0; /* index of kblayouts */
+ static unsigned int cursor_mode;
+ static Client *grabc;
+ static int grabcx, grabcy; /* client-relative */
+@@ -2454,6 +2456,24 @@ togglefullscreen(const Arg *arg)
+ setfullscreen(sel, !sel->isfullscreen);
+ }
+
++void
++togglekblayout(const Arg *arg)
++{
++ Keyboard *kb;
++ struct xkb_rule_names newrule = xkb_rules;
++
++ kblayout = (kblayout + 1) % LENGTH(kblayouts);
++ newrule.layout = kblayouts[kblayout];
++ wl_list_for_each(kb, &keyboards, link) {
++ struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
++ struct xkb_keymap *keymap = xkb_map_new_from_names(context, &newrule,
++ XKB_KEYMAP_COMPILE_NO_FLAGS);
++ wlr_keyboard_set_keymap(kb->device->keyboard, keymap);
++ xkb_keymap_unref(keymap);
++ xkb_context_unref(context);
++ }
++}
++
+ void
+ toggletag(const Arg *arg)
+ {
+--
+2.42.0
+
+
+From 3428168a686e2da8ba8a9dc1473350610afaef19 Mon Sep 17 00:00:00 2001
+From: wochap <gean.marroquin@gmail.com>
+Date: Thu, 19 Oct 2023 23:46:06 -0500
+Subject: [PATCH 2/2] fix build
+
+---
+ dwl.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/dwl.c b/dwl.c
+index 25458e6..090280f 100644
+--- a/dwl.c
++++ b/dwl.c
+@@ -2468,7 +2468,7 @@ togglekblayout(const Arg *arg)
+ struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
+ struct xkb_keymap *keymap = xkb_map_new_from_names(context, &newrule,
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
+- wlr_keyboard_set_keymap(kb->device->keyboard, keymap);
++ wlr_keyboard_set_keymap(kb->wlr_keyboard, keymap);
+ xkb_keymap_unref(keymap);
+ xkb_context_unref(context);
+ }
+--
+2.42.0