diff options
| author | nic <ra@afu.re> | 2025-08-17 22:21:02 -0400 |
|---|---|---|
| committer | nic <ra@afu.re> | 2025-08-17 22:21:02 -0400 |
| commit | 12720eaf8606bf38d40e7474462e794f20897436 (patch) | |
| tree | 60d0fb159e7d480cf7698449bbe9d34703287932 | |
| parent | f63c33a40fe0aaa92ace3e267192167e011eb6d6 (diff) | |
border red ++, bindings...
| -rw-r--r-- | config.def.h | 14 | ||||
| -rw-r--r-- | patches/ipc.patch | 597 | ||||
| -rw-r--r-- | patches/regions.patch | 71 | ||||
| -rw-r--r-- | patches/swallow.patch | 351 | ||||
| -rw-r--r-- | patches/unclutter.patch | 192 | ||||
| -rw-r--r-- | patches/vanitygaps.patch | 357 |
6 files changed, 1576 insertions, 6 deletions
diff --git a/config.def.h b/config.def.h index 4aebfca..5a93b00 100644 --- a/config.def.h +++ b/config.def.h @@ -9,13 +9,13 @@ 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 int smartgaps = 0; /* 1 means no outer gap when there is only one window */ static const int monoclegaps = 0; /* 1 means outer gaps in monocle layout */ -static const unsigned int borderpx = 1; /* border pixel of windows */ -static const unsigned int gappih = 10; /* horiz inner gap between windows */ +static const unsigned int borderpx = 3; /* border pixel of windows */ +static const unsigned int gappih = 20; /* horiz inner gap between windows */ static const unsigned int gappiv = 10; /* vert inner gap between windows */ static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ -static const unsigned int gappov = 10; /* vert outer gap between windows and screen edge */ +static const unsigned int gappov = 30; /* vert outer gap between windows and screen edge */ static const float rootcolor[] = COLOR(0x222222ff); -static const float bordercolor[] = COLOR(0x444444ff); +static const float bordercolor[] = COLOR(0x770000ff); static const float focuscolor[] = COLOR(0x005577ff); static const float urgentcolor[] = COLOR(0xff0000ff); /* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */ @@ -140,13 +140,15 @@ static const Key keys[] = { /* SEPARE SPAWN FROM OTHER FUNCTION + LAYOUT FUNCTION */ /* modifier key function argument */ - { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, + { MODKEY, XKB_KEY_Return, spawn, {.v = termcmd} }, { MODKEY, XKB_KEY_a, spawn, {.v = menucmd} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_A, spawn, SHCMD(TERMINAL " -e abook -C ~/.config/abook/abookrc --datafile ~/.config/abook/addressbook") }, { MODKEY, XKB_KEY_w, spawn, {.v = (const char*[]){ "firefox", NULL }} }, { MODKEY, XKB_KEY_t, spawn, {.v = (const char*[]){ TERMINAL, "-e", "htop-vim", NULL }} }, - { MODKEY, XKB_KEY_n, spawn, SHCMD(TERMINAL "-e nvim -c VimwikiIndex") }, + { MODKEY, XKB_KEY_n, spawn, SHCMD("foot -e nvim -c VimwikiIndex") }, { MODKEY, XKB_KEY_m, spawn, SHCMD(TERMINAL " -e neomutt ") }, + { MODKEY, XKB_KEY_grave, spawn, {.v = (const char *[]) { "menuunicode", NULL } } }, + { MODKEY, XKB_KEY_q, killclient, {0} }, { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, spawn, {.v = (const char*[]){ "sysact", NULL }} }, diff --git a/patches/ipc.patch b/patches/ipc.patch new file mode 100644 index 0000000..9f989e7 --- /dev/null +++ b/patches/ipc.patch @@ -0,0 +1,597 @@ +From 6c6d655b68770ce82a24fde9b58c4d97b672553a Mon Sep 17 00:00:00 2001 +From: choc <notchoc@proton.me> +Date: Mon, 23 Oct 2023 10:35:17 +0800 +Subject: [PATCH] implement dwl-ipc-unstable-v2 + https://codeberg.org/dwl/dwl-patches/wiki/ipc + +--- + Makefile | 14 +- + config.def.h | 1 + + dwl.c | 257 ++++++++++++++++++++++++++---- + protocols/dwl-ipc-unstable-v2.xml | 181 +++++++++++++++++++++ + 4 files changed, 419 insertions(+), 34 deletions(-) + create mode 100644 protocols/dwl-ipc-unstable-v2.xml + +diff --git a/Makefile b/Makefile +index 8db7409..a79a080 100644 +--- a/Makefile ++++ b/Makefile +@@ -17,12 +17,14 @@ DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEV + LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS) + + all: dwl +-dwl: dwl.o util.o +- $(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ ++dwl: dwl.o util.o dwl-ipc-unstable-v2-protocol.o ++ $(CC) dwl.o util.o dwl-ipc-unstable-v2-protocol.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@ + dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \ + pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \ +- wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h ++ wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h \ ++ dwl-ipc-unstable-v2-protocol.h + util.o: util.c util.h ++dwl-ipc-unstable-v2-protocol.o: dwl-ipc-unstable-v2-protocol.c dwl-ipc-unstable-v2-protocol.h + + # wayland-scanner is a tool which generates C headers and rigging for Wayland + # protocols, which are specified in XML. wlroots requires you to rig these up +@@ -45,6 +47,12 @@ wlr-output-power-management-unstable-v1-protocol.h: + xdg-shell-protocol.h: + $(WAYLAND_SCANNER) server-header \ + $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@ ++dwl-ipc-unstable-v2-protocol.h: ++ $(WAYLAND_SCANNER) server-header \ ++ protocols/dwl-ipc-unstable-v2.xml $@ ++dwl-ipc-unstable-v2-protocol.c: ++ $(WAYLAND_SCANNER) private-code \ ++ protocols/dwl-ipc-unstable-v2.xml $@ + + config.h: + cp config.def.h $@ +diff --git a/config.def.h b/config.def.h +index 22d2171..1593033 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -127,6 +127,7 @@ static const Key keys[] = { + /* modifier key function argument */ + { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, ++ { MODKEY, XKB_KEY_b, togglebar, {0} }, + { 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 8a587d1..7a4949b 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -68,6 +68,7 @@ + #include <xcb/xcb_icccm.h> + #endif + ++#include "dwl-ipc-unstable-v2-protocol.h" + #include "util.h" + + /* macros */ +@@ -144,6 +145,12 @@ typedef struct { + uint32_t resize; /* configure serial of a pending resize */ + } Client; + ++typedef struct { ++ struct wl_list link; ++ struct wl_resource *resource; ++ Monitor *mon; ++} DwlIpcOutput; ++ + typedef struct { + uint32_t mod; + xkb_keysym_t keysym; +@@ -189,6 +196,7 @@ typedef struct { + + struct Monitor { + struct wl_list link; ++ struct wl_list dwl_ipc_outputs; + struct wlr_output *wlr_output; + struct wlr_scene_output *scene_output; + struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */ +@@ -286,6 +294,17 @@ static void destroysessionlock(struct wl_listener *listener, void *data); + static void destroysessionmgr(struct wl_listener *listener, void *data); + static void destroykeyboardgroup(struct wl_listener *listener, void *data); + static Monitor *dirtomon(enum wlr_direction dir); ++static void dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id); ++static void dwl_ipc_manager_destroy(struct wl_resource *resource); ++static void dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output); ++static void dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource); ++static void dwl_ipc_output_destroy(struct wl_resource *resource); ++static void dwl_ipc_output_printstatus(Monitor *monitor); ++static void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output); ++static void dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags); ++static void dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index); ++static void dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset); ++static void dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource); + static void focusclient(Client *c, int lift); + static void focusmon(const Arg *arg); + static void focusstack(const Arg *arg); +@@ -338,6 +357,7 @@ 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 togglebar(const Arg *arg); + static void togglefloating(const Arg *arg); + static void togglefullscreen(const Arg *arg); + static void toggletag(const Arg *arg); +@@ -411,6 +431,9 @@ static struct wlr_box sgeom; + static struct wl_list mons; + static Monitor *selmon; + ++static struct zdwl_ipc_manager_v2_interface dwl_manager_implementation = {.release = dwl_ipc_manager_release, .get_output = dwl_ipc_manager_get_output}; ++static struct zdwl_ipc_output_v2_interface dwl_output_implementation = {.release = dwl_ipc_output_release, .set_tags = dwl_ipc_output_set_tags, .set_layout = dwl_ipc_output_set_layout, .set_client_tags = dwl_ipc_output_set_client_tags}; ++ + #ifdef XWAYLAND + static void activatex11(struct wl_listener *listener, void *data); + static void associatex11(struct wl_listener *listener, void *data); +@@ -703,6 +726,10 @@ cleanupmon(struct wl_listener *listener, void *data) + LayerSurface *l, *tmp; + size_t i; + ++ DwlIpcOutput *ipc_output, *ipc_output_tmp; ++ wl_list_for_each_safe(ipc_output, ipc_output_tmp, &m->dwl_ipc_outputs, link) ++ wl_resource_destroy(ipc_output->resource); ++ + /* m->layers[i] are intentionally not unlinked */ + for (i = 0; i < LENGTH(m->layers); i++) { + wl_list_for_each_safe(l, tmp, &m->layers[i], link) +@@ -983,6 +1010,8 @@ createmon(struct wl_listener *listener, void *data) + m = wlr_output->data = ecalloc(1, sizeof(*m)); + m->wlr_output = wlr_output; + ++ wl_list_init(&m->dwl_ipc_outputs); ++ + for (i = 0; i < LENGTH(m->layers); i++) + wl_list_init(&m->layers[i]); + +@@ -1334,6 +1363,192 @@ dirtomon(enum wlr_direction dir) + return selmon; + } + ++void ++dwl_ipc_manager_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) ++{ ++ struct wl_resource *manager_resource = wl_resource_create(client, &zdwl_ipc_manager_v2_interface, version, id); ++ if (!manager_resource) { ++ wl_client_post_no_memory(client); ++ return; ++ } ++ wl_resource_set_implementation(manager_resource, &dwl_manager_implementation, NULL, dwl_ipc_manager_destroy); ++ ++ zdwl_ipc_manager_v2_send_tags(manager_resource, TAGCOUNT); ++ ++ for (unsigned int i = 0; i < LENGTH(layouts); i++) ++ zdwl_ipc_manager_v2_send_layout(manager_resource, layouts[i].symbol); ++} ++ ++void ++dwl_ipc_manager_destroy(struct wl_resource *resource) ++{ ++ /* No state to destroy */ ++} ++ ++void ++dwl_ipc_manager_get_output(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *output) ++{ ++ DwlIpcOutput *ipc_output; ++ Monitor *monitor = wlr_output_from_resource(output)->data; ++ struct wl_resource *output_resource = wl_resource_create(client, &zdwl_ipc_output_v2_interface, wl_resource_get_version(resource), id); ++ if (!output_resource) ++ return; ++ ++ ipc_output = ecalloc(1, sizeof(*ipc_output)); ++ ipc_output->resource = output_resource; ++ ipc_output->mon = monitor; ++ wl_resource_set_implementation(output_resource, &dwl_output_implementation, ipc_output, dwl_ipc_output_destroy); ++ wl_list_insert(&monitor->dwl_ipc_outputs, &ipc_output->link); ++ dwl_ipc_output_printstatus_to(ipc_output); ++} ++ ++void ++dwl_ipc_manager_release(struct wl_client *client, struct wl_resource *resource) ++{ ++ wl_resource_destroy(resource); ++} ++ ++static void ++dwl_ipc_output_destroy(struct wl_resource *resource) ++{ ++ DwlIpcOutput *ipc_output = wl_resource_get_user_data(resource); ++ wl_list_remove(&ipc_output->link); ++ free(ipc_output); ++} ++ ++void ++dwl_ipc_output_printstatus(Monitor *monitor) ++{ ++ DwlIpcOutput *ipc_output; ++ wl_list_for_each(ipc_output, &monitor->dwl_ipc_outputs, link) ++ dwl_ipc_output_printstatus_to(ipc_output); ++} ++ ++void ++dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) ++{ ++ Monitor *monitor = ipc_output->mon; ++ Client *c, *focused; ++ int tagmask, state, numclients, focused_client, tag; ++ const char *title, *appid; ++ focused = focustop(monitor); ++ zdwl_ipc_output_v2_send_active(ipc_output->resource, monitor == selmon); ++ ++ for (tag = 0 ; tag < TAGCOUNT; tag++) { ++ numclients = state = focused_client = 0; ++ tagmask = 1 << tag; ++ if ((tagmask & monitor->tagset[monitor->seltags]) != 0) ++ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE; ++ ++ wl_list_for_each(c, &clients, link) { ++ if (c->mon != monitor) ++ continue; ++ if (!(c->tags & tagmask)) ++ continue; ++ if (c == focused) ++ focused_client = 1; ++ if (c->isurgent) ++ state |= ZDWL_IPC_OUTPUT_V2_TAG_STATE_URGENT; ++ ++ numclients++; ++ } ++ zdwl_ipc_output_v2_send_tag(ipc_output->resource, tag, state, numclients, focused_client); ++ } ++ title = focused ? client_get_title(focused) : ""; ++ appid = focused ? client_get_appid(focused) : ""; ++ ++ zdwl_ipc_output_v2_send_layout(ipc_output->resource, monitor->lt[monitor->sellt] - layouts); ++ zdwl_ipc_output_v2_send_title(ipc_output->resource, title); ++ zdwl_ipc_output_v2_send_appid(ipc_output->resource, appid); ++ zdwl_ipc_output_v2_send_layout_symbol(ipc_output->resource, monitor->ltsymbol); ++ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FULLSCREEN_SINCE_VERSION) { ++ zdwl_ipc_output_v2_send_fullscreen(ipc_output->resource, focused ? focused->isfullscreen : 0); ++ } ++ if (wl_resource_get_version(ipc_output->resource) >= ZDWL_IPC_OUTPUT_V2_FLOATING_SINCE_VERSION) { ++ zdwl_ipc_output_v2_send_floating(ipc_output->resource, focused ? focused->isfloating : 0); ++ } ++ zdwl_ipc_output_v2_send_frame(ipc_output->resource); ++} ++ ++void ++dwl_ipc_output_set_client_tags(struct wl_client *client, struct wl_resource *resource, uint32_t and_tags, uint32_t xor_tags) ++{ ++ DwlIpcOutput *ipc_output; ++ Monitor *monitor; ++ Client *selected_client; ++ unsigned int newtags = 0; ++ ++ ipc_output = wl_resource_get_user_data(resource); ++ if (!ipc_output) ++ return; ++ ++ monitor = ipc_output->mon; ++ selected_client = focustop(monitor); ++ if (!selected_client) ++ return; ++ ++ newtags = (selected_client->tags & and_tags) ^ xor_tags; ++ if (!newtags) ++ return; ++ ++ selected_client->tags = newtags; ++ if (selmon == monitor) ++ focusclient(focustop(monitor), 1); ++ arrange(selmon); ++ printstatus(); ++} ++ ++void ++dwl_ipc_output_set_layout(struct wl_client *client, struct wl_resource *resource, uint32_t index) ++{ ++ DwlIpcOutput *ipc_output; ++ Monitor *monitor; ++ ++ ipc_output = wl_resource_get_user_data(resource); ++ if (!ipc_output) ++ return; ++ ++ monitor = ipc_output->mon; ++ if (index >= LENGTH(layouts)) ++ return; ++ if (index != monitor->lt[monitor->sellt] - layouts) ++ monitor->sellt ^= 1; ++ ++ monitor->lt[monitor->sellt] = &layouts[index]; ++ arrange(monitor); ++ printstatus(); ++} ++ ++void ++dwl_ipc_output_set_tags(struct wl_client *client, struct wl_resource *resource, uint32_t tagmask, uint32_t toggle_tagset) ++{ ++ DwlIpcOutput *ipc_output; ++ Monitor *monitor; ++ unsigned int newtags = tagmask & TAGMASK; ++ ++ ipc_output = wl_resource_get_user_data(resource); ++ if (!ipc_output) ++ return; ++ monitor = ipc_output->mon; ++ ++ if (!newtags || newtags == monitor->tagset[monitor->seltags]) ++ return; ++ if (toggle_tagset) ++ monitor->seltags ^= 1; ++ ++ monitor->tagset[monitor->seltags] = newtags; ++ if (selmon == monitor) ++ focusclient(focustop(monitor), 1); ++ arrange(monitor); ++ printstatus(); ++} ++ ++void ++dwl_ipc_output_release(struct wl_client *client, struct wl_resource *resource) ++{ ++ wl_resource_destroy(resource); ++} ++ + void + focusclient(Client *c, int lift) + { +@@ -2033,38 +2248,9 @@ void + printstatus(void) + { + Monitor *m = NULL; +- Client *c; +- uint32_t occ, urg, sel; + +- wl_list_for_each(m, &mons, link) { +- occ = urg = 0; +- wl_list_for_each(c, &clients, link) { +- if (c->mon != m) +- continue; +- occ |= c->tags; +- if (c->isurgent) +- urg |= c->tags; +- } +- if ((c = focustop(m))) { +- printf("%s title %s\n", m->wlr_output->name, client_get_title(c)); +- printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c)); +- printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen); +- printf("%s floating %d\n", m->wlr_output->name, c->isfloating); +- sel = c->tags; +- } else { +- printf("%s title \n", m->wlr_output->name); +- printf("%s appid \n", m->wlr_output->name); +- printf("%s fullscreen \n", m->wlr_output->name); +- printf("%s floating \n", m->wlr_output->name); +- sel = 0; +- } +- +- printf("%s selmon %u\n", m->wlr_output->name, m == selmon); +- printf("%s tags %"PRIu32" %"PRIu32" %"PRIu32" %"PRIu32"\n", +- m->wlr_output->name, occ, m->tagset[m->seltags], sel, urg); +- printf("%s layout %s\n", m->wlr_output->name, m->ltsymbol); +- } +- fflush(stdout); ++ wl_list_for_each(m, &mons, link) ++ dwl_ipc_output_printstatus(m); + } + + void +@@ -2584,6 +2770,8 @@ setup(void) + LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply); + LISTEN_STATIC(&output_mgr->events.test, outputmgrtest); + ++ wl_global_create(dpy, &zdwl_ipc_manager_v2_interface, 2, NULL, dwl_ipc_manager_bind); ++ + /* 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 */ +@@ -2681,6 +2869,13 @@ tile(Monitor *m) + } + } + ++void ++togglebar(const Arg *arg) { ++ DwlIpcOutput *ipc_output; ++ wl_list_for_each(ipc_output, &selmon->dwl_ipc_outputs, link) ++ zdwl_ipc_output_v2_send_toggle_visibility(ipc_output->resource); ++} ++ + void + togglefloating(const Arg *arg) + { +diff --git a/protocols/dwl-ipc-unstable-v2.xml b/protocols/dwl-ipc-unstable-v2.xml +new file mode 100644 +index 0000000..0a6e7e5 +--- /dev/null ++++ b/protocols/dwl-ipc-unstable-v2.xml +@@ -0,0 +1,181 @@ ++<?xml version="1.0" encoding="utf-8"?> ++<!-- ++This is largely ripped from somebar's ipc patchset; just with some personal modifications. ++I would probably just submit raphi's patchset but I don't think that would be polite. ++--> ++<protocol name="dwl_ipc_unstable_v2"> ++ <description summary="inter-proccess-communication about dwl's state"> ++ This protocol allows clients to update and get updates from dwl. ++ ++ Warning! The protocol described in this file is experimental and ++ backward incompatible changes may be made. Backward compatible ++ changes may be added together with the corresponding interface ++ version bump. ++ Backward incompatible changes are done by bumping the version ++ number in the protocol and interface names and resetting the ++ interface version. Once the protocol is to be declared stable, ++ the 'z' prefix and the version number in the protocol and ++ interface names are removed and the interface version number is ++ reset. ++ </description> ++ ++ <interface name="zdwl_ipc_manager_v2" version="2"> ++ <description summary="manage dwl state"> ++ This interface is exposed as a global in wl_registry. ++ ++ Clients can use this interface to get a dwl_ipc_output. ++ After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events. ++ The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client. ++ </description> ++ ++ <request name="release" type="destructor"> ++ <description summary="release dwl_ipc_manager"> ++ Indicates that the client will not the dwl_ipc_manager object anymore. ++ Objects created through this instance are not affected. ++ </description> ++ </request> ++ ++ <request name="get_output"> ++ <description summary="get a dwl_ipc_outout for a wl_output"> ++ Get a dwl_ipc_outout for the specified wl_output. ++ </description> ++ <arg name="id" type="new_id" interface="zdwl_ipc_output_v2"/> ++ <arg name="output" type="object" interface="wl_output"/> ++ </request> ++ ++ <event name="tags"> ++ <description summary="Announces tag amount"> ++ This event is sent after binding. ++ A roundtrip after binding guarantees the client recieved all tags. ++ </description> ++ <arg name="amount" type="uint"/> ++ </event> ++ ++ <event name="layout"> ++ <description summary="Announces a layout"> ++ This event is sent after binding. ++ A roundtrip after binding guarantees the client recieved all layouts. ++ </description> ++ <arg name="name" type="string"/> ++ </event> ++ </interface> ++ ++ <interface name="zdwl_ipc_output_v2" version="2"> ++ <description summary="control dwl output"> ++ Observe and control a dwl output. ++ ++ Events are double-buffered: ++ Clients should cache events and redraw when a dwl_ipc_output.frame event is sent. ++ ++ Request are not double-buffered: ++ The compositor will update immediately upon request. ++ </description> ++ ++ <enum name="tag_state"> ++ <entry name="none" value="0" summary="no state"/> ++ <entry name="active" value="1" summary="tag is active"/> ++ <entry name="urgent" value="2" summary="tag has at least one urgent client"/> ++ </enum> ++ ++ <request name="release" type="destructor"> ++ <description summary="release dwl_ipc_outout"> ++ Indicates to that the client no longer needs this dwl_ipc_output. ++ </description> ++ </request> ++ ++ <event name="toggle_visibility"> ++ <description summary="Toggle client visibilty"> ++ Indicates the client should hide or show themselves. ++ If the client is visible then hide, if hidden then show. ++ </description> ++ </event> ++ ++ <event name="active"> ++ <description summary="Update the selected output."> ++ Indicates if the output is active. Zero is invalid, nonzero is valid. ++ </description> ++ <arg name="active" type="uint"/> ++ </event> ++ ++ <event name="tag"> ++ <description summary="Update the state of a tag."> ++ Indicates that a tag has been updated. ++ </description> ++ <arg name="tag" type="uint" summary="Index of the tag"/> ++ <arg name="state" type="uint" enum="tag_state" summary="The state of the tag."/> ++ <arg name="clients" type="uint" summary="The number of clients in the tag."/> ++ <arg name="focused" type="uint" summary="If there is a focused client. Nonzero being valid, zero being invalid."/> ++ </event> ++ ++ <event name="layout"> ++ <description summary="Update the layout."> ++ Indicates a new layout is selected. ++ </description> ++ <arg name="layout" type="uint" summary="Index of the layout."/> ++ </event> ++ ++ <event name="title"> ++ <description summary="Update the title."> ++ Indicates the title has changed. ++ </description> ++ <arg name="title" type="string" summary="The new title name."/> ++ </event> ++ ++ <event name="appid" since="1"> ++ <description summary="Update the appid."> ++ Indicates the appid has changed. ++ </description> ++ <arg name="appid" type="string" summary="The new appid."/> ++ </event> ++ ++ <event name="layout_symbol" since="1"> ++ <description summary="Update the current layout symbol"> ++ Indicates the layout has changed. Since layout symbols are dynamic. ++ As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying. ++ You can ignore the zdwl_ipc_output.layout event. ++ </description> ++ <arg name="layout" type="string" summary="The new layout"/> ++ </event> ++ ++ <event name="frame"> ++ <description summary="The update sequence is done."> ++ Indicates that a sequence of status updates have finished and the client should redraw. ++ </description> ++ </event> ++ ++ <request name="set_tags"> ++ <description summary="Set the active tags of this output"/> ++ <arg name="tagmask" type="uint" summary="bitmask of the tags that should be set."/> ++ <arg name="toggle_tagset" type="uint" summary="toggle the selected tagset, zero for invalid, nonzero for valid."/> ++ </request> ++ ++ <request name="set_client_tags"> ++ <description summary="Set the tags of the focused client."> ++ The tags are updated as follows: ++ new_tags = (current_tags AND and_tags) XOR xor_tags ++ </description> ++ <arg name="and_tags" type="uint"/> ++ <arg name="xor_tags" type="uint"/> ++ </request> ++ ++ <request name="set_layout"> ++ <description summary="Set the layout of this output"/> ++ <arg name="index" type="uint" summary="index of a layout recieved by dwl_ipc_manager.layout"/> ++ </request> ++ ++ <!-- Version 2 --> ++ <event name="fullscreen" since="2"> ++ <description summary="Update fullscreen status"> ++ Indicates if the selected client on this output is fullscreen. ++ </description> ++ <arg name="is_fullscreen" type="uint" summary="If the selected client is fullscreen. Nonzero is valid, zero invalid"/> ++ </event> ++ ++ <event name="floating" since="2"> ++ <description summary="Update the floating status"> ++ Indicates if the selected client on this output is floating. ++ </description> ++ <arg name="is_floating" type="uint" summary="If the selected client is floating. Nonzero is valid, zero invalid"/> ++ </event> ++ </interface> ++</protocol> +-- +2.43.0 + diff --git a/patches/regions.patch b/patches/regions.patch new file mode 100644 index 0000000..207c0bd --- /dev/null +++ b/patches/regions.patch @@ -0,0 +1,71 @@ +From 9991f8bbf2e379dfca8eb356c03d3d20085255a8 Mon Sep 17 00:00:00 2001 +From: sewn <sewn@disroot.org> +Date: Sun, 23 Jul 2023 08:13:52 +0300 +Subject: [PATCH] pass window regions to given program as stdin + +--- + config.def.h | 1 + + dwl.c | 28 ++++++++++++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/config.def.h b/config.def.h +index 9009517..79d0236 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -122,6 +122,7 @@ static const Key keys[] = { + /* modifier key function argument */ + { MODKEY, XKB_KEY_p, spawn, {.v = menucmd} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} }, ++ { MODKEY, XKB_KEY_r, regions, SHCMD("grim -g \"$(slurp)\"") }, + { 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 fa76db2..9588e36 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -334,6 +334,7 @@ static Monitor *xytomon(double x, double y); + static void xytonode(double x, double y, struct wlr_surface **psurface, + Client **pc, LayerSurface **pl, double *nx, double *ny); + static void zoom(const Arg *arg); ++static void regions(const Arg *arg); + + /* variables */ + static const char broken[] = "broken"; +@@ -2823,6 +2824,33 @@ zoom(const Arg *arg) + arrange(selmon); + } + ++void ++regions(const Arg *arg) ++{ ++ int pipefd[2]; ++ Client *c; ++ Monitor *m; ++ ++ if (pipe(pipefd) == -1) ++ return; ++ if (fork() == 0) { ++ close(pipefd[1]); ++ dup2(pipefd[0], STDIN_FILENO); ++ close(pipefd[0]); ++ setsid(); ++ execvp(((char **)arg->v)[0], (char **)arg->v); ++ die("dwl: execvp %s failed:", ((char **)arg->v)[0]); ++ } ++ ++ close(pipefd[0]); ++ wl_list_for_each(m, &mons, link) ++ wl_list_for_each(c, &clients, link) ++ if (VISIBLEON(c, m)) ++ dprintf(pipefd[1], "%d,%d %dx%d\n", ++ c->geom.x, c->geom.y, c->geom.width, c->geom.height); ++ close(pipefd[1]); ++} ++ + #ifdef XWAYLAND + void + activatex11(struct wl_listener *listener, void *data) +-- +2.43.1 + diff --git a/patches/swallow.patch b/patches/swallow.patch new file mode 100644 index 0000000..ee1a1c1 --- /dev/null +++ b/patches/swallow.patch @@ -0,0 +1,351 @@ +From a220e1ed4b04a66c837dfc8e3363d3e696cbf541 Mon Sep 17 00:00:00 2001 +From: Nikita Ivanov <nikita.vyach.ivanov@gmail.com> +Date: Wed, 5 Feb 2025 02:34:39 +0100 +Subject: [PATCH] Swallow: hide the terminal when it spawns a client + +--- + client.h | 12 ++++ + config.def.h | 11 +++- + dwl.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++-- + 3 files changed, 168 insertions(+), 7 deletions(-) + +diff --git a/client.h b/client.h +index 42f225f..bc9cad2 100644 +--- a/client.h ++++ b/client.h +@@ -131,6 +131,18 @@ client_get_appid(Client *c) + return c->surface.xdg->toplevel->app_id; + } + ++static inline int ++client_get_pid(Client *c) ++{ ++ pid_t pid; ++#ifdef XWAYLAND ++ if (client_is_x11(c)) ++ return c->surface.xwayland->pid; ++#endif ++ wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); ++ return pid; ++} ++ + static inline void + client_get_clip(Client *c, struct wlr_box *clip) + { +diff --git a/config.def.h b/config.def.h +index 22d2171..42342f1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -13,6 +13,8 @@ static const float focuscolor[] = COLOR(0x005577ff); + static const float urgentcolor[] = COLOR(0xff0000ff); + /* 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 int enableautoswallow = 1; /* enables autoswallowing newly spawned clients */ ++static float swallowborder = 1.0f; /* add this multiplied by borderpx to border when a client is swallowed */ + + /* tagging - TAGCOUNT must be no greater than 31 */ + #define TAGCOUNT (9) +@@ -22,10 +24,11 @@ static int log_level = WLR_ERROR; + + /* 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 */ ++ /* app_id title tags mask isfloating isterm noswallow monitor */ + /* examples: */ +- { "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */ +- { "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */ ++ { "foot", NULL, 0, 0, 1, 1, -1 }, ++ { "Gimp_EXAMPLE", NULL, 0, 1, 0, 0, -1 }, /* Start on currently visible tags floating, not tiled */ ++ { "firefox_EXAMPLE", NULL, 1 << 8, 0, 0, 0, -1 }, /* Start on ONLY tag "9" */ + }; + + /* layout(s) */ +@@ -142,6 +145,8 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_space, setlayout, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} }, + { MODKEY, XKB_KEY_e, togglefullscreen, {0} }, ++ { MODKEY, XKB_KEY_a, toggleswallow, {0} }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_A, toggleautoswallow,{0} }, + { MODKEY, XKB_KEY_0, view, {.ui = ~0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} }, + { MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} }, +diff --git a/dwl.c b/dwl.c +index def2562..71d500a 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -73,12 +73,13 @@ + #define MAX(A, B) ((A) > (B) ? (A) : (B)) + #define MIN(A, B) ((A) < (B) ? (A) : (B)) + #define CLEANMASK(mask) (mask & ~WLR_MODIFIER_CAPS) +-#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags])) ++#define VISIBLEON(C, M) ((M) && (C)->mon == (M) && ((C)->tags & (M)->tagset[(M)->seltags]) && !(C)->swallowedby) + #define LENGTH(X) (sizeof X / sizeof X[0]) + #define END(A) ((A) + LENGTH(A)) + #define TAGMASK ((1u << TAGCOUNT) - 1) + #define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L))) + #define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0) ++#define BORDERPX(C) (borderpx + ((C)->swallowing ? (int)ceilf(swallowborder * (C)->swallowing->bw) : 0)) + + /* enums */ + enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ +@@ -104,7 +105,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 */ +@@ -140,8 +142,12 @@ typedef struct { + unsigned int bw; + uint32_t tags; + int isfloating, isurgent, isfullscreen; ++ int isterm, noswallow; + uint32_t resize; /* configure serial of a pending resize */ +-} Client; ++ pid_t pid; ++ Client *swallowing; /* client being hidden */ ++ Client *swallowedby; ++}; + + typedef struct { + uint32_t mod; +@@ -230,6 +236,8 @@ typedef struct { + const char *title; + uint32_t tags; + int isfloating; ++ int isterm; ++ int noswallow; + int monitor; + } Rule; + +@@ -311,6 +319,7 @@ static void moveresize(const Arg *arg); + static void outputmgrapply(struct wl_listener *listener, void *data); + static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test); + static void outputmgrtest(struct wl_listener *listener, void *data); ++static pid_t parentpid(pid_t pid); + static void pointerfocus(Client *c, struct wlr_surface *surface, + double sx, double sy, uint32_t time); + static void printstatus(void); +@@ -335,11 +344,15 @@ static void setsel(struct wl_listener *listener, void *data); + static void setup(void); + static void spawn(const Arg *arg); + static void startdrag(struct wl_listener *listener, void *data); ++static void swallow(Client *c, Client *toswallow); + static void tag(const Arg *arg); + static void tagmon(const Arg *arg); ++static Client *termforwin(Client *c); + static void tile(Monitor *m); + static void togglefloating(const Arg *arg); + static void togglefullscreen(const Arg *arg); ++static void toggleswallow(const Arg *arg); ++static void toggleautoswallow(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unlocksession(struct wl_listener *listener, void *data); +@@ -466,11 +479,15 @@ applyrules(Client *c) + if (!(title = client_get_title(c))) + title = broken; + ++ c->pid = client_get_pid(c); ++ + for (r = rules; r < END(rules); r++) { + if ((!r->title || strstr(title, r->title)) + && (!r->id || strstr(appid, r->id))) { + c->isfloating = r->isfloating; + newtags |= r->tags; ++ c->isterm = r->isterm; ++ c->noswallow = r->noswallow; + i = 0; + wl_list_for_each(m, &mons, link) { + if (r->monitor == i++) +@@ -478,6 +495,12 @@ applyrules(Client *c) + } + } + } ++ if (enableautoswallow && !c->noswallow && !c->isfloating && ++ !c->surface.xdg->initial_commit) { ++ Client *p = termforwin(c); ++ if (p) ++ swallow(c, p); ++ } + setmon(c, mon, newtags); + } + +@@ -2006,6 +2029,20 @@ outputmgrtest(struct wl_listener *listener, void *data) + outputmgrapplyortest(config, 1); + } + ++pid_t ++parentpid(pid_t pid) ++{ ++ unsigned int v = 0; ++ FILE *f; ++ char buf[256]; ++ snprintf(buf, sizeof(buf) - 1, "/proc/%u/stat", (unsigned)pid); ++ if (!(f = fopen(buf, "r"))) ++ return 0; ++ fscanf(f, "%*u %*s %*c %u", &v); ++ fclose(f); ++ return (pid_t)v; ++} ++ + void + pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, + uint32_t time) +@@ -2326,7 +2363,7 @@ setfullscreen(Client *c, int fullscreen) + c->isfullscreen = fullscreen; + if (!c->mon || !client_surface(c)->mapped) + return; +- c->bw = fullscreen ? 0 : borderpx; ++ c->bw = fullscreen ? 0 : BORDERPX(c); + client_set_fullscreen(c, fullscreen); + wlr_scene_node_reparent(&c->scene->node, layers[c->isfullscreen + ? LyrFS : c->isfloating ? LyrFloat : LyrTile]); +@@ -2404,6 +2441,9 @@ setmon(Client *c, Monitor *m, uint32_t newtags) + setfloating(c, c->isfloating); + } + focusclient(focustop(selmon), 1); ++ ++ if (c->swallowing) ++ setmon(c->swallowing, m, newtags); + } + + void +@@ -2669,6 +2709,44 @@ startdrag(struct wl_listener *listener, void *data) + LISTEN_STATIC(&drag->icon->events.destroy, destroydragicon); + } + ++void ++swallow(Client *c, Client *toswallow) ++{ ++ /* Do not allow a client to swallow itself */ ++ if (c == toswallow) ++ return; ++ ++ /* Swallow */ ++ if (toswallow && !c->swallowing) { ++ c->swallowing = toswallow; ++ toswallow->swallowedby = c; ++ toswallow->mon = c->mon; ++ toswallow->mon = c->mon; ++ wl_list_remove(&c->link); ++ wl_list_insert(&c->swallowing->link, &c->link); ++ wl_list_remove(&c->flink); ++ wl_list_insert(&c->swallowing->flink, &c->flink); ++ c->bw = BORDERPX(c); ++ c->tags = toswallow->tags; ++ c->isfloating = toswallow->isfloating; ++ c->geom = toswallow->geom; ++ setfullscreen(toswallow, 0); ++ } ++ ++ /* Unswallow */ ++ else if (c->swallowing) { ++ wl_list_remove(&c->swallowing->link); ++ wl_list_insert(&c->link, &c->swallowing->link); ++ wl_list_remove(&c->swallowing->flink); ++ wl_list_insert(&c->flink, &c->swallowing->flink); ++ c->swallowing->tags = c->tags; ++ c->swallowing->swallowedby = NULL; ++ c->swallowing = NULL; ++ c->bw = BORDERPX(c); ++ setfullscreen(c, 0); ++ } ++} ++ + void + tag(const Arg *arg) + { +@@ -2690,6 +2768,40 @@ tagmon(const Arg *arg) + setmon(sel, dirtomon(arg->i), 0); + } + ++Client * ++termforwin(Client *c) ++{ ++ Client *p; ++ pid_t pid; ++ pid_t pids[32]; ++ size_t i, pids_len; ++ ++ if (!c->pid || c->isterm) ++ return NULL; ++ ++ /* Get all parent pids */ ++ pids_len = 0; ++ pid = c->pid; ++ while (pids_len < LENGTH(pids)) { ++ pid = parentpid(pid); ++ if (!pid) ++ break; ++ pids[pids_len++] = pid; ++ } ++ ++ /* Find closest parent */ ++ for (i = 0; i < pids_len; i++) { ++ wl_list_for_each(p, &clients, link) { ++ if (!p->pid || !p->isterm || p->swallowedby) ++ continue; ++ if (pids[i] == p->pid) ++ return p; ++ } ++ } ++ ++ return NULL; ++} ++ + void + tile(Monitor *m) + { +@@ -2741,6 +2853,32 @@ togglefullscreen(const Arg *arg) + setfullscreen(sel, !sel->isfullscreen); + } + ++void ++toggleswallow(const Arg *arg) ++{ ++ Client *c, *sel = focustop(selmon); ++ if (!sel) ++ return; ++ ++ if (sel->swallowing) { ++ swallow(sel, NULL); ++ } else { ++ wl_list_for_each(c, &sel->flink, flink) { ++ if (&c->flink == &fstack) ++ continue; /* wrap past the sentinel node */ ++ if (VISIBLEON(c, selmon)) ++ break; /* found it */ ++ } ++ swallow(sel, c); ++ } ++} ++ ++void ++toggleautoswallow(const Arg *arg) ++{ ++ enableautoswallow = !enableautoswallow; ++} ++ + void + toggletag(const Arg *arg) + { +@@ -2801,6 +2939,12 @@ unmapnotify(struct wl_listener *listener, void *data) + grabc = NULL; + } + ++ if (c->swallowing) { ++ swallow(c, NULL); ++ } else if (c->swallowedby) { ++ swallow(c->swallowedby, NULL); ++ } ++ + if (client_is_unmanaged(c)) { + if (c == exclusive_focus) { + exclusive_focus = NULL; +-- +2.49.0 + diff --git a/patches/unclutter.patch b/patches/unclutter.patch new file mode 100644 index 0000000..4c9aede --- /dev/null +++ b/patches/unclutter.patch @@ -0,0 +1,192 @@ +From 68914f40359ebccc7b684a1f74d82419b1796cdf Mon Sep 17 00:00:00 2001 +From: Guido Cella <guido@guidocella.xyz> +Date: Thu, 25 Jul 2024 17:59:05 +0200 +Subject: [PATCH] =?UTF-8?q?hide=20the=20mouse=20cursor=20if=20it=20isn?= + =?UTF-8?q?=E2=80=99t=20being=20used?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +--- + config.def.h | 2 ++ + dwl.c | 74 +++++++++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 67 insertions(+), 9 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 22d2171..790c73d 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -106,6 +106,8 @@ LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right + */ + static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM; + ++static const int cursor_timeout = 5; ++ + /* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */ + #define MODKEY WLR_MODIFIER_ALT + +diff --git a/dwl.c b/dwl.c +index 775dadf..621779e 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -288,6 +288,8 @@ 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 handlecursoractivity(void); ++static int hidecursor(void *data); + static void handlesig(int signo); + static void incnmaster(const Arg *arg); + static void inputdevice(struct wl_listener *listener, void *data); +@@ -389,6 +391,14 @@ static struct wlr_pointer_constraint_v1 *active_constraint; + + static struct wlr_cursor *cursor; + static struct wlr_xcursor_manager *cursor_mgr; ++static struct wl_event_source *hide_source; ++static bool cursor_hidden = false; ++static struct { ++ enum wp_cursor_shape_device_v1_shape shape; ++ struct wlr_surface *surface; ++ int hotspot_x; ++ int hotspot_y; ++} last_cursor; + + static struct wlr_scene_rect *root_bg; + static struct wlr_session_lock_manager_v1 *session_lock_mgr; +@@ -609,8 +619,9 @@ axisnotify(struct wl_listener *listener, void *data) + * for example when you move the scroll wheel. */ + struct wlr_pointer_axis_event *event = data; + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); +- /* TODO: allow usage of scroll wheel for mousebindings, it can be implemented +- * by checking the event's orientation and the delta of the event */ ++ handlecursoractivity(); ++ /* TODO: allow usage of scroll whell for mousebindings, it can be implemented ++ * checking the event's orientation and the delta of the event */ + /* Notify the client with pointer focus of the axis event. */ + wlr_seat_pointer_notify_axis(seat, + event->time_msec, event->orientation, event->delta, +@@ -627,6 +638,7 @@ buttonpress(struct wl_listener *listener, void *data) + const Button *b; + + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++ handlecursoractivity(); + + switch (event->state) { + case WL_POINTER_BUTTON_STATE_PRESSED: +@@ -1563,6 +1575,32 @@ handlesig(int signo) + quit(NULL); + } + ++void ++handlecursoractivity(void) ++{ ++ wl_event_source_timer_update(hide_source, cursor_timeout * 1000); ++ ++ if (!cursor_hidden) ++ return; ++ ++ cursor_hidden = false; ++ ++ if (last_cursor.shape) ++ wlr_cursor_set_xcursor(cursor, cursor_mgr, ++ wlr_cursor_shape_v1_name(last_cursor.shape)); ++ else ++ wlr_cursor_set_surface(cursor, last_cursor.surface, ++ last_cursor.hotspot_x, last_cursor.hotspot_y); ++} ++ ++int ++hidecursor(void *data) ++{ ++ wlr_cursor_unset_image(cursor); ++ cursor_hidden = true; ++ return 1; ++} ++ + void + incnmaster(const Arg *arg) + { +@@ -1903,6 +1941,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d + + wlr_cursor_move(cursor, device, dx, dy); + wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); ++ handlecursoractivity(); + + /* Update selmon (even while dragging a window) */ + if (sloppyfocus) +@@ -1927,7 +1966,7 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d + /* If there's no client surface under the cursor, set the cursor image to a + * default. This is what makes the cursor image appear when you move it + * off of a client or over its border. */ +- if (!surface && !seat->drag) ++ if (!surface && !seat->drag && !cursor_hidden) + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); + + pointerfocus(c, surface, sx, sy, time); +@@ -2284,6 +2323,7 @@ run(char *startup_cmd) + * monitor when displayed here */ + wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "default"); ++ handlecursoractivity(); + + /* Run the Wayland event loop. This does not return until you exit the + * compositor. Starting the backend rigged up all of the necessary event +@@ -2307,9 +2347,16 @@ setcursor(struct wl_listener *listener, void *data) + * use the provided surface as the cursor image. It will set the + * hardware cursor on the output that it's currently on and continue to + * do so as the cursor moves between outputs. */ +- if (event->seat_client == seat->pointer_state.focused_client) +- wlr_cursor_set_surface(cursor, event->surface, +- event->hotspot_x, event->hotspot_y); ++ if (event->seat_client == seat->pointer_state.focused_client) { ++ last_cursor.shape = 0; ++ last_cursor.surface = event->surface; ++ last_cursor.hotspot_x = event->hotspot_x; ++ last_cursor.hotspot_y = event->hotspot_y; ++ ++ if (!cursor_hidden) ++ wlr_cursor_set_surface(cursor, event->surface, ++ event->hotspot_x, event->hotspot_y); ++ } + } + + void +@@ -2321,9 +2368,14 @@ setcursorshape(struct wl_listener *listener, void *data) + /* This can be sent by any client, so we check to make sure this one + * actually has pointer focus first. If so, we can tell the cursor to + * use the provided cursor shape. */ +- if (event->seat_client == seat->pointer_state.focused_client) +- wlr_cursor_set_xcursor(cursor, cursor_mgr, +- wlr_cursor_shape_v1_name(event->shape)); ++ if (event->seat_client == seat->pointer_state.focused_client) { ++ last_cursor.shape = event->shape; ++ last_cursor.surface = NULL; ++ ++ if (!cursor_hidden) ++ wlr_cursor_set_xcursor(cursor, cursor_mgr, ++ wlr_cursor_shape_v1_name(event->shape)); ++ } + } + + void +@@ -2614,6 +2666,9 @@ setup(void) + cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); + wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape); + ++ hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), ++ hidecursor, cursor); ++ + /* + * Configures a seat, which is a single "seat" at which a user sits and + * operates the computer. This conceptually includes up to one keyboard, +@@ -2998,6 +3053,7 @@ virtualpointer(struct wl_listener *listener, void *data) + wlr_cursor_attach_input_device(cursor, device); + if (event->suggested_output) + wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); ++ handlecursoractivity(); + } + + Monitor * +-- +2.49.0 + diff --git a/patches/vanitygaps.patch b/patches/vanitygaps.patch new file mode 100644 index 0000000..db1ddf4 --- /dev/null +++ b/patches/vanitygaps.patch @@ -0,0 +1,357 @@ +From 8d29d5cace06c97917fbc26c673fd37731ac4984 Mon Sep 17 00:00:00 2001 +From: Bonicgamer <44382222+Bonicgamer@users.noreply.github.com> +Date: Mon, 17 Aug 2020 14:48:24 -0400 +Subject: [PATCH 1/2] Implement vanitygaps +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> +--- + config.def.h | 21 ++++++++ + dwl.c | 149 +++++++++++++++++++++++++++++++++++++++++++++++---- + 2 files changed, 160 insertions(+), 10 deletions(-) + +diff --git a/config.def.h b/config.def.h +index 22d2171d..39e528b1 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -6,7 +6,12 @@ + /* appearance */ + 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 int smartgaps = 0; /* 1 means no outer gap when there is only one window */ + static const unsigned int borderpx = 1; /* border pixel of windows */ ++static const unsigned int gappih = 10; /* horiz inner gap between windows */ ++static const unsigned int gappiv = 10; /* vert inner gap between windows */ ++static const unsigned int gappoh = 10; /* horiz outer gap between windows and screen edge */ ++static const unsigned int gappov = 10; /* vert outer gap between windows and screen edge */ + static const float rootcolor[] = COLOR(0x222222ff); + static const float bordercolor[] = COLOR(0x444444ff); + static const float focuscolor[] = COLOR(0x005577ff); +@@ -133,6 +138,22 @@ static const Key keys[] = { + { MODKEY, XKB_KEY_d, incnmaster, {.i = -1} }, + { MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} }, + { MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_h, incgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_l, incgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_H, incogaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_L, incogaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_h, incigaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_CTRL, XKB_KEY_l, incigaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_0, togglegaps, {0} }, ++ { MODKEY|WLR_MODIFIER_LOGO|WLR_MODIFIER_SHIFT, XKB_KEY_parenright,defaultgaps, {0} }, ++ { MODKEY, XKB_KEY_y, incihgaps, {.i = +1 } }, ++ { MODKEY, XKB_KEY_o, incihgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_y, incivgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_CTRL, XKB_KEY_o, incivgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_y, incohgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_LOGO, XKB_KEY_o, incohgaps, {.i = -1 } }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Y, incovgaps, {.i = +1 } }, ++ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_O, incovgaps, {.i = -1 } }, + { MODKEY, XKB_KEY_Return, zoom, {0} }, + { MODKEY, XKB_KEY_Tab, view, {0} }, + { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} }, +diff --git a/dwl.c b/dwl.c +index ad21e1ba..fa823957 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -197,6 +197,10 @@ struct Monitor { + struct wlr_box w; /* window area, layout-relative */ + struct wl_list layers[4]; /* LayerSurface.link */ + const Layout *lt[2]; ++ int gappih; /* horizontal gap between windows */ ++ int gappiv; /* vertical gap between windows */ ++ int gappoh; /* horizontal outer gaps */ ++ int gappov; /* vertical outer gaps */ + unsigned int seltags; + unsigned int sellt; + uint32_t tagset[2]; +@@ -271,6 +275,7 @@ static void createpopup(struct wl_listener *listener, void *data); + static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint); + static void cursorframe(struct wl_listener *listener, void *data); + static void cursorwarptohint(void); ++static void defaultgaps(const Arg *arg); + static void destroydecoration(struct wl_listener *listener, void *data); + static void destroydragicon(struct wl_listener *listener, void *data); + static void destroyidleinhibitor(struct wl_listener *listener, void *data); +@@ -290,6 +295,13 @@ static void fullscreennotify(struct wl_listener *listener, void *data); + static void gpureset(struct wl_listener *listener, void *data); + static void handlesig(int signo); + static void incnmaster(const Arg *arg); ++static void incgaps(const Arg *arg); ++static void incigaps(const Arg *arg); ++static void incihgaps(const Arg *arg); ++static void incivgaps(const Arg *arg); ++static void incogaps(const Arg *arg); ++static void incohgaps(const Arg *arg); ++static void incovgaps(const Arg *arg); + static void inputdevice(struct wl_listener *listener, void *data); + static int keybinding(uint32_t mods, xkb_keysym_t sym); + static void keypress(struct wl_listener *listener, void *data); +@@ -323,6 +335,7 @@ static void setcursor(struct wl_listener *listener, void *data); + static void setcursorshape(struct wl_listener *listener, void *data); + static void setfloating(Client *c, int floating); + static void setfullscreen(Client *c, int fullscreen); ++static void setgaps(int oh, int ov, int ih, int iv); + static void setlayout(const Arg *arg); + static void setmfact(const Arg *arg); + static void setmon(Client *c, Monitor *m, uint32_t newtags); +@@ -336,6 +349,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 togglegaps(const Arg *arg); + static void toggletag(const Arg *arg); + static void toggleview(const Arg *arg); + static void unlocksession(struct wl_listener *listener, void *data); +@@ -405,6 +419,7 @@ static struct wlr_output_layout *output_layout; + static struct wlr_box sgeom; + static struct wl_list mons; + static Monitor *selmon; ++static int enablegaps = 1; /* enables gaps, used by togglegaps */ + + /* global event handlers */ + static struct wl_listener cursor_axis = {.notify = axisnotify}; +@@ -1048,6 +1063,11 @@ createmon(struct wl_listener *listener, void *data) + for (i = 0; i < LENGTH(m->layers); i++) + wl_list_init(&m->layers[i]); + ++ m->gappih = gappih; ++ m->gappiv = gappiv; ++ m->gappoh = gappoh; ++ m->gappov = gappov; ++ + wlr_output_state_init(&state); + /* Initialize monitor state using configured rules */ + m->tagset[0] = m->tagset[1] = 1; +@@ -1230,6 +1250,12 @@ cursorwarptohint(void) + } + } + ++void ++defaultgaps(const Arg *arg) ++{ ++ setgaps(gappoh, gappov, gappih, gappiv); ++} ++ + void + destroydecoration(struct wl_listener *listener, void *data) + { +@@ -1566,6 +1592,83 @@ incnmaster(const Arg *arg) + arrange(selmon); + } + ++void ++incgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh + arg->i, ++ selmon->gappov + arg->i, ++ selmon->gappih + arg->i, ++ selmon->gappiv + arg->i ++ ); ++} ++ ++void ++incigaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov, ++ selmon->gappih + arg->i, ++ selmon->gappiv + arg->i ++ ); ++} ++ ++void ++incihgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov, ++ selmon->gappih + arg->i, ++ selmon->gappiv ++ ); ++} ++ ++void ++incivgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov, ++ selmon->gappih, ++ selmon->gappiv + arg->i ++ ); ++} ++ ++void ++incogaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh + arg->i, ++ selmon->gappov + arg->i, ++ selmon->gappih, ++ selmon->gappiv ++ ); ++} ++ ++void ++incohgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh + arg->i, ++ selmon->gappov, ++ selmon->gappih, ++ selmon->gappiv ++ ); ++} ++ ++void ++incovgaps(const Arg *arg) ++{ ++ setgaps( ++ selmon->gappoh, ++ selmon->gappov + arg->i, ++ selmon->gappih, ++ selmon->gappiv ++ ); ++} ++ + void + inputdevice(struct wl_listener *listener, void *data) + { +@@ -2357,6 +2460,16 @@ setfullscreen(Client *c, int fullscreen) + printstatus(); + } + ++void ++setgaps(int oh, int ov, int ih, int iv) ++{ ++ selmon->gappoh = MAX(oh, 0); ++ selmon->gappov = MAX(ov, 0); ++ selmon->gappih = MAX(ih, 0); ++ selmon->gappiv = MAX(iv, 0); ++ arrange(selmon); ++} ++ + void + setlayout(const Arg *arg) + { +@@ -2701,7 +2814,7 @@ tagmon(const Arg *arg) + void + tile(Monitor *m) + { +- unsigned int mw, my, ty; ++ unsigned int mw, my, ty, h, r, oe = enablegaps, ie = enablegaps; + int i, n = 0; + Client *c; + +@@ -2711,22 +2824,31 @@ tile(Monitor *m) + if (n == 0) + return; + ++ if (smartgaps == n) { ++ oe = 0; // outer gaps disabled ++ } ++ + if (n > m->nmaster) +- mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0; ++ mw = m->nmaster ? (int)roundf((m->w.width + m->gappiv*ie) * m->mfact) : 0; + else +- mw = m->w.width; +- i = my = ty = 0; ++ mw = m->w.width - 2*m->gappov*oe + m->gappiv*ie; ++ i = 0; ++ my = ty = m->gappoh*oe; + wl_list_for_each(c, &clients, link) { + 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, +- .height = (m->w.height - my) / (MIN(n, m->nmaster) - i)}, 0); +- my += c->geom.height; ++ r = MIN(n, m->nmaster) - i; ++ h = (m->w.height - my - m->gappoh*oe - m->gappih*ie * (r - 1)) / r; ++ resize(c, (struct wlr_box){.x = m->w.x + m->gappov*oe, .y = m->w.y + my, ++ .width = mw - m->gappiv*ie, .height = h}, 0); ++ my += c->geom.height + m->gappih*ie; + } 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); +- ty += c->geom.height; ++ r = n - i; ++ h = (m->w.height - ty - m->gappoh*oe - m->gappih*ie * (r - 1)) / r; ++ resize(c, (struct wlr_box){.x = m->w.x + mw + m->gappov*oe, .y = m->w.y + ty, ++ .width = m->w.width - mw - 2*m->gappov*oe, .height = h}, 0); ++ ty += c->geom.height + m->gappih*ie; + } + i++; + } +@@ -2749,6 +2871,13 @@ togglefullscreen(const Arg *arg) + setfullscreen(sel, !sel->isfullscreen); + } + ++void ++togglegaps(const Arg *arg) ++{ ++ enablegaps = !enablegaps; ++ arrange(selmon); ++} ++ + void + toggletag(const Arg *arg) + { +-- +2.48.0 + + +From e3d10f01df9b7d6735ce9e43ebfdca35b8639f0e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Leonardo=20Hern=C3=A1ndez=20Hern=C3=A1ndez?= + <leohdz172@protonmail.com> +Date: Wed, 20 Jul 2022 00:15:32 -0500 +Subject: [PATCH 2/2] allow gaps in monocle layout if requested +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> +--- + config.def.h | 1 + + dwl.c | 6 +++++- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/config.def.h b/config.def.h +index 39e528b1..f4d4095d 100644 +--- a/config.def.h ++++ b/config.def.h +@@ -7,6 +7,7 @@ + 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 int smartgaps = 0; /* 1 means no outer gap when there is only one window */ ++static const int monoclegaps = 0; /* 1 means outer gaps in monocle layout */ + static const unsigned int borderpx = 1; /* border pixel of windows */ + static const unsigned int gappih = 10; /* horiz inner gap between windows */ + static const unsigned int gappiv = 10; /* vert inner gap between windows */ +diff --git a/dwl.c b/dwl.c +index fa823957..59eabb54 100644 +--- a/dwl.c ++++ b/dwl.c +@@ -1922,8 +1922,12 @@ monocle(Monitor *m) + wl_list_for_each(c, &clients, link) { + if (!VISIBLEON(c, m) || c->isfloating || c->isfullscreen) + continue; +- resize(c, m->w, 0); + n++; ++ if (!monoclegaps) ++ resize(c, m->w, 0); ++ else ++ resize(c, (struct wlr_box){.x = m->w.x + gappoh, .y = m->w.y + gappov, ++ .width = m->w.width - 2 * gappoh, .height = m->w.height - 2 * gappov}, 0); + } + if (n) + snprintf(m->ltsymbol, LENGTH(m->ltsymbol), "[%d]", n); +-- +2.48.0 + |
