From 0d603b179ccccbb4270fd202a14a2db18d0a5413 Mon Sep 17 00:00:00 2001
From: A Frederick Christensen <dwl@ivories.org>
Date: Thu, 26 Feb 2026 17:09:28 -0600
Subject: [PATCH] Apply simple_scratchpad patch

---
 config.def.h        |  3 ++
 dwl.c               | 34 +++++++++++++++++++++--
 simple_scratchpad.c | 68 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 103 insertions(+), 2 deletions(-)
 create mode 100644 simple_scratchpad.c

diff --git a/config.def.h b/config.def.h
index 8a6eda0..6254fc9 100644
--- a/config.def.h
+++ b/config.def.h
@@ -132,6 +132,9 @@ static const Key keys[] = {
 	{ MODKEY,                    XKB_KEY_Return,      zoom,             {0} },
 	{ MODKEY,                    XKB_KEY_Tab,         view,             {0} },
 	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c,           killclient,       {0} },
+	{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_z,           addscratchpad,    {0} },
+	{ MODKEY|WLR_MODIFIER_CTRL,  XKB_KEY_z,           togglescratchpad, {0} },
+	{ MODKEY,                    XKB_KEY_z,           removescratchpad, {0} },
 	{ MODKEY,                    XKB_KEY_t,           setlayout,        {.v = &layouts[0]} },
 	{ MODKEY,                    XKB_KEY_f,           setlayout,        {.v = &layouts[1]} },
 	{ MODKEY,                    XKB_KEY_m,           setlayout,        {.v = &layouts[2]} },
diff --git a/dwl.c b/dwl.c
index 44f3ad9..215f630 100644
--- a/dwl.c
+++ b/dwl.c
@@ -139,6 +139,7 @@ typedef struct {
 	uint32_t tags;
 	int isfloating, isurgent, isfullscreen;
 	uint32_t resize; /* configure serial of a pending resize */
+	struct wl_list link_temp;
 } Client;
 
 typedef struct {
@@ -240,6 +241,7 @@ typedef struct {
 } SessionLock;
 
 /* function declarations */
+static void addscratchpad(const Arg *arg);
 static void applybounds(Client *c, struct wlr_box *bbox);
 static void applyrules(Client *c);
 static void arrange(Monitor *m);
@@ -314,6 +316,7 @@ static void printstatus(void);
 static void powermgrsetmode(struct wl_listener *listener, void *data);
 static void quit(const Arg *arg);
 static void rendermon(struct wl_listener *listener, void *data);
+static void removescratchpad(const Arg *arg);
 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);
@@ -336,6 +339,7 @@ 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 togglescratchpad(const Arg *arg);
 static void toggletag(const Arg *arg);
 static void toggleview(const Arg *arg);
 static void unlocksession(struct wl_listener *listener, void *data);
@@ -406,6 +410,9 @@ static struct wlr_box sgeom;
 static struct wl_list mons;
 static Monitor *selmon;
 
+static struct wl_list scratchpad_clients;
+static int scratchpad_visible = 1;
+
 /* global event handlers */
 static struct wl_listener cursor_axis = {.notify = axisnotify};
 static struct wl_listener cursor_button = {.notify = buttonpress};
@@ -455,6 +462,8 @@ static struct wlr_xwayland *xwayland;
 /* attempt to encapsulate suck into one file */
 #include "client.h"
 
+#include "simple_scratchpad.c"
+
 /* function implementations */
 void
 applybounds(Client *c, struct wlr_box *bbox)
@@ -1328,10 +1337,20 @@ void
 destroynotify(struct wl_listener *listener, void *data)
 {
 	/* Called when the xdg_toplevel is destroyed. */
-	Client *c = wl_container_of(listener, c, destroy);
+	Client *sc, *c = wl_container_of(listener, c, destroy);
 	wl_list_remove(&c->destroy.link);
 	wl_list_remove(&c->set_title.link);
 	wl_list_remove(&c->fullscreen.link);
+	/* Check if destroyed client was part of scratchpad_clients
+	 * and clean it from the list if so. */
+	if (c && wl_list_length(&scratchpad_clients) > 0) {
+		wl_list_for_each(sc, &scratchpad_clients, link_temp) {
+			if (sc == c) {
+				wl_list_remove(&c->link_temp);
+				break;
+			}
+		}
+	}
 #ifdef XWAYLAND
 	if (c->type != XDGShell) {
 		wl_list_remove(&c->activate.link);
@@ -2333,11 +2352,21 @@ setcursorshape(struct wl_listener *listener, void *data)
 void
 setfloating(Client *c, int floating)
 {
-	Client *p = client_get_parent(c);
+	Client *sc, *p = client_get_parent(c);
 	c->isfloating = floating;
 	/* If in floating layout do not change the client's layer */
 	if (!c->mon || !client_surface(c)->mapped || !c->mon->lt[c->mon->sellt]->arrange)
 		return;
+	/* Check if unfloated client was part of scratchpad_clients
+	 * and remove it from scratchpad_clients list if so */
+	if (!floating && wl_list_length(&scratchpad_clients) > 0) {
+		wl_list_for_each(sc, &scratchpad_clients, link_temp) {
+			if (sc == c) {
+				wl_list_remove(&c->link_temp);
+				break;
+			}
+		}
+	}
 	wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen ||
 			(p && p->isfullscreen) ? LyrFS
 			: c->isfloating ? LyrFloat : LyrTile]);
@@ -2554,6 +2583,7 @@ setup(void)
 	 */
 	wl_list_init(&clients);
 	wl_list_init(&fstack);
+	wl_list_init(&scratchpad_clients);
 
 	xdg_shell = wlr_xdg_shell_create(dpy, 6);
 	wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
diff --git a/simple_scratchpad.c b/simple_scratchpad.c
new file mode 100644
index 0000000..26d6b66
--- /dev/null
+++ b/simple_scratchpad.c
@@ -0,0 +1,68 @@
+/* ************************************************************************** */
+/*                                                                            */
+/*                                                        :::      ::::::::   */
+/*   simple_scratchpad.c                                :+:      :+:    :+:   */
+/*                                                    +:+ +:+         +:+     */
+/*   By: jmakkone <jmakkone@student.hive.fi>        +#+  +:+       +#+        */
+/*                                                +#+#+#+#+#+   +#+           */
+/*   Created: 2024/12/19 19:35:02 by jmakkone          #+#    #+#             */
+/*   Updated: 2025/01/04 13:35:50 by jmakkone         ###   ########.fr       */
+/*                                                                            */
+/* ************************************************************************** */
+
+void
+addscratchpad(const Arg *arg)
+{
+	Client *cc, *c = focustop(selmon);
+
+	if (!c)
+		return;
+	/* Check if the added client is already a scratchpad client */
+	wl_list_for_each(cc, &scratchpad_clients, link_temp) {
+		if (cc == c)
+			return;
+	}
+	if (!c->isfloating) {
+		setfloating(c, 1);
+	}
+	wl_list_insert(&scratchpad_clients, &c->link_temp);
+}
+
+void
+togglescratchpad(const Arg *arg)
+{
+	Client *c;
+	Monitor *m = selmon;
+
+	scratchpad_visible = !scratchpad_visible;
+	if (scratchpad_visible) {
+		wl_list_for_each(c, &scratchpad_clients, link_temp) {
+			c->mon = m;
+			c->tags = m->tagset[m->seltags];
+			arrange(m);
+			focusclient(c, 1);
+		}
+	} else {
+		wl_list_for_each(c, &scratchpad_clients, link_temp) {
+			c->tags = 0;
+			focusclient(focustop(m), 1);
+			arrange(m);
+		}
+	}
+}
+
+void
+removescratchpad(const Arg *arg)
+{
+	Client *sc, *c = focustop(selmon);
+
+	if (c && wl_list_length(&scratchpad_clients) > 0) {
+		/* Check if c is in scratchpad_clients */
+		wl_list_for_each(sc, &scratchpad_clients, link_temp) {
+			if (sc == c) {
+				wl_list_remove(&c->link_temp);
+				break;
+			}
+		}
+	}
+}
-- 
2.52.0

