Merge pull request 'main' (#1) from dwl/dwl-patches:main into main

Reviewed-on: https://codeberg.org/MayOrMayNotBeACat/dwl-patches/pulls/1
This commit is contained in:
MayOrMayNotBeACat 2025-06-07 04:45:19 +02:00
commit 71afcd34fb
14 changed files with 822 additions and 379 deletions

View File

@ -18,6 +18,9 @@ Reloading the compositor will replace all functionality except for `main`, `setu
Note that you're responsible yourself for reloading ressources like fonts, which may only get acquired once.
A lot of components of dwl will also only get run on a trigger (the tiling for example).
So not every change will be immediate.
Furthermore, any patch adding more global state to dwl cannot currently be reloaded properly since
we keep state in the cold part. These patches will still work and their functionality will (hopefully) be
reloadable but you will need to restart the compositor once.
#### Notes
##### reduce compile errors
@ -28,12 +31,79 @@ So you may want to disable this compile option in order to get readable compiler
This does depend on you having a notification daemon like `dunst` or `mako` running as well as
having `notify-send` installed in order for the compositor to inform you of the reload.
#### How?
Most of all dwl functionality is moved into a shared object file `dwl.so`, which can be reloaded at runtime.
#### How do I make this work with other patches?
Most patches should already put everything in more or less the correct place but if they don't, then here is
where you learn how to fix it.
The concept itself is quite simple. We compile dwl.c twice once normally and once with the `HOT` macro defined.
The first run will yield the executable and the second will yield a shared object file to be reloaded at runtime.
From the cold part there are some newly available macros:
> symbol names are written as-is, never as string literals
* `TSYM(T, s)` dynamically loads the symbol `s` with type `T` from the shared object file use this if you need to call functions in the cold part (i.e. the `setup` function).
* `CSYM(T, v)` dynamically accesses the value of the symbol `v` of type `T` from the shared object. Use this to query values from config.h for example.
* `LISTEN_GLOBAL(E, L)` is similar to the `LISTEN` macro. `E` is an event and `L` the name of a global
listener. Current implementation is a bit messy and I may fix it if someone bothers me about it.
* `UNLISTEN(L)` takes a listener and unregisteres it. This is important for reloading.
When adding new code there are some considerations to be made. Since dwl decorates all symbols with `static` by default, we cannot access them as-is.
C's macro system is a bit too powerful though and we use this to our advantage. We will repeatedly define and
undefine a macro called `static` in order to replace the `static` keyword inside some sections.
This allows us to do less refactoring and preserve a lot of the original patch compatability since we're only
strategically adding lines. We're tring to be as minimally invasive as we can.
As a general guide:
* global state should be global for the cold part and `extern` in the cold part meaning it should be inside a block like this:
```C
#ifdef HOT
#define static extern
#else
#define static
#endif
... // your global variables go here
#undef static
```
* function declarations should be visible in the hot part but not included in the cold part meaning they should be enclosed like this:
```C
#ifdef HOT
#define static
... // your function declarations go here
#undef static
#endif
```
* static data like the event handler structs in the current `main` branch are a bit more difficult but we will let them reside inside the hot part.
Thus, we enclose them the same way we do functions:
```C
#ifdef HOT
#define static
... // your struct wl_listener event handlers go here
#undef static
#endif
```
* function definitions should go in the hot part, so they need to be inside a big block like this:
```C
#ifdef HOT
... // function definitions here
#endif
* enfore use of the `LISTEN_GLOBAL` and `UNLISTEN` macros (I know this sucks but what can I do, I need to get
access to the callbacks somehow). So you want
* `wl_list_remove(listener.link)` to become `UNLISTEN(listener)` and
* `wl_signal_add(event, global_listener)` to become `LISTEN_GLOBAL(event, global_listener)`.
* Make sure that any patch you're using also uses static everywhere.
* If a patch adds any config variables that are accessed in the cold part (i.e. probably `setup`),
then you'll have to manually remove the `static` keyword from them.
Note that usually you do not have to create the big `#ifdef` blocks yourself.
There is for example already a huge `#ifdef HOT`-delimited codeblock at the bottom
of dwl.c where all the function definitions go.
If you have any troubles, feel free to reach out.
### Download
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/hot-reload/hot-reload-0.7.patch)
- [main 2025-02-14](/dwl/dwl-patches/raw/branch/main/patches/hot-reload/hot-reload.patch)
- [main 2025-05-30](/dwl/dwl-patches/raw/branch/main/patches/hot-reload/hot-reload.patch)
- find the repo for the patch [here](/Sivecano/dwl/src/branch/hot-reload)
### Authors
- [Sivecano](https://codeberg.org/Sivecano)

View File

@ -1,4 +1,4 @@
From caa1adaf02ab4f9a326761ade5d1346149bc7c59 Mon Sep 17 00:00:00 2001
From 559c635056f23d55df3f83c12d1201a7328f648f Mon Sep 17 00:00:00 2001
From: Sivecano <sivecano@gmail.com>
Date: Sun, 26 Jan 2025 18:30:02 +0100
Subject: [PATCH] redo hot-reloading in one file
@ -12,7 +12,7 @@ Subject: [PATCH] redo hot-reloading in one file
5 files changed, 351 insertions(+), 50 deletions(-)
diff --git a/Makefile b/Makefile
index 3358bae..70d3d0f 100644
index 3358bae..e7ee9ff 100644
--- a/Makefile
+++ b/Makefile
@@ -13,13 +13,16 @@ DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \
@ -28,7 +28,7 @@ index 3358bae..70d3d0f 100644
dwl: dwl.o util.o
$(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
-dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
+dwl.o: dwl.c cursor-shape-v1-protocol.h \
+dwl.o: dwl.c 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
+dwl.so: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
@ -99,7 +99,7 @@ index 22d2171..6e3dda1 100644
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
diff --git a/dwl.c b/dwl.c
index def2562..7e059ad 100644
index def2562..1c9ab67 100644
--- a/dwl.c
+++ b/dwl.c
@@ -1,6 +1,15 @@
@ -652,7 +652,7 @@ index def2562..7e059ad 100644
+ wlr_log(WLR_ERROR, "couldn't load new dwl module from %s", get_module_path());
+
+ if (fork() == 0)
+ execl("/bin/env", "--", "Notify-send", "-u", "low", "failed to reload dwl", NULL);
+ execl("/bin/env", "--", "notify-send", "-u", "low", "failed to reload dwl", NULL);
+ return;
+ }
+
@ -766,5 +766,5 @@ index 226980d..11aab34 100644
+struct listens* append_listener(struct wl_listener* l, struct listens* ls);
+struct listens* remove_listener(struct wl_listener* l, struct listens* ls);
--
2.48.1
2.49.0

View File

@ -1,18 +1,18 @@
From 79fbc2405919a049a35dd58e860b6519ebb7943b Mon Sep 17 00:00:00 2001
From 44ce31430dd7d2c0a6c1dc29534f22fb33b25bca Mon Sep 17 00:00:00 2001
From: Sivecano <sivecano@gmail.com>
Date: Sun, 26 Jan 2025 18:30:02 +0100
Subject: [PATCH] redo hot-reloading in one file
---
Makefile | 19 ++-
Makefile | 19 +-
config.def.h | 5 +-
dwl.c | 475 +++++++++++++++++++++++++++++++++++++++------------
dwl.c | 484 +++++++++++++++++++++++++++++++++++++++------------
util.c | 34 ++++
util.h | 6 +
5 files changed, 421 insertions(+), 118 deletions(-)
5 files changed, 433 insertions(+), 115 deletions(-)
diff --git a/Makefile b/Makefile
index 578194f..0714ed1 100644
index 578194f..69c1b54 100644
--- a/Makefile
+++ b/Makefile
@@ -13,13 +13,16 @@ DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
@ -28,7 +28,7 @@ index 578194f..0714ed1 100644
dwl: dwl.o util.o
$(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
-dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
+dwl.o: dwl.c cursor-shape-v1-protocol.h \
+dwl.o: dwl.c 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
+dwl.so: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
@ -99,7 +99,7 @@ index 22d2171..6e3dda1 100644
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
diff --git a/dwl.c b/dwl.c
index ec4ca86..8d1eceb 100644
index 4816159..70e99be 100644
--- a/dwl.c
+++ b/dwl.c
@@ -1,6 +1,15 @@
@ -265,14 +265,37 @@ index ec4ca86..8d1eceb 100644
static struct wl_listener request_set_psel = {.notify = setpsel};
static struct wl_listener request_set_sel = {.notify = setsel};
static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
@@ -449,8 +535,38 @@ static struct wl_listener xwayland_ready = {.notify = xwaylandready};
static struct wlr_xwayland *xwayland;
#endif
@@ -436,7 +522,15 @@ static struct wl_listener request_start_drag = {.notify = requeststartdrag};
static struct wl_listener start_drag = {.notify = startdrag};
static struct wl_listener new_session_lock = {.notify = locksession};
+/* undoes the shadowing of static from above */
+#endif
+#undef static
+
+
#ifdef XWAYLAND
+#ifdef HOT
+#define static
+
static void activatex11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data);
static void configurex11(struct wl_listener *listener, void *data);
@@ -446,11 +540,45 @@ static void sethints(struct wl_listener *listener, void *data);
static void xwaylandready(struct wl_listener *listener, void *data);
static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
static struct wl_listener xwayland_ready = {.notify = xwaylandready};
+
+#define static extern
+#else
+#define static
+#endif
+
static struct wlr_xwayland *xwayland;
+
+#undef static
+#endif
+
+/* this is where we put global hot-reload state */
+#ifdef HOT
+#define COLD extern
@ -292,8 +315,8 @@ index ec4ca86..8d1eceb 100644
+#ifndef HOT
+static char* runpath;
+
+#endif
+
#endif
+
+#ifdef HOT
+
@ -304,7 +327,7 @@ index ec4ca86..8d1eceb 100644
/* attempt to encapsulate suck into one file */
#include "client.h"
@@ -692,10 +808,12 @@ checkidleinhibitor(struct wlr_surface *exclude)
@@ -695,10 +823,12 @@ checkidleinhibitor(struct wlr_surface *exclude)
wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited);
}
@ -318,7 +341,7 @@ index ec4ca86..8d1eceb 100644
#ifdef XWAYLAND
wlr_xwayland_destroy(xwayland);
xwayland = NULL;
@@ -707,7 +825,7 @@ cleanup(void)
@@ -710,7 +840,7 @@ cleanup(void)
}
wlr_xcursor_manager_destroy(cursor_mgr);
@ -327,7 +350,7 @@ index ec4ca86..8d1eceb 100644
/* If it's not destroyed manually it will cause a use-after-free of wlr_seat.
* Destroy it until it's fixed in the wlroots side */
@@ -719,6 +837,8 @@ cleanup(void)
@@ -722,6 +852,8 @@ cleanup(void)
wlr_scene_node_destroy(&scene->tree.node);
}
@ -336,7 +359,7 @@ index ec4ca86..8d1eceb 100644
void
cleanupmon(struct wl_listener *listener, void *data)
{
@@ -732,10 +852,10 @@ cleanupmon(struct wl_listener *listener, void *data)
@@ -735,10 +867,10 @@ cleanupmon(struct wl_listener *listener, void *data)
wlr_layer_surface_v1_destroy(l->layer_surface);
}
@ -350,7 +373,7 @@ index ec4ca86..8d1eceb 100644
m->wlr_output->data = NULL;
wlr_output_layout_remove(output_layout, m->wlr_output);
wlr_scene_output_destroy(m->scene_output);
@@ -748,37 +868,37 @@ cleanupmon(struct wl_listener *listener, void *data)
@@ -751,37 +883,37 @@ cleanupmon(struct wl_listener *listener, void *data)
void
cleanuplisteners(void)
{
@ -418,17 +441,16 @@ index ec4ca86..8d1eceb 100644
#endif
}
@@ -905,8 +1025,7 @@ commitpopup(struct wl_listener *listener, void *data)
@@ -908,7 +1040,7 @@ commitpopup(struct wl_listener *listener, void *data)
box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x);
box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y);
wlr_xdg_popup_unconstrain_from_box(popup, &box);
- wl_list_remove(&listener->link);
- free(listener);
+ UNLISTEN(listener);
free(listener);
}
void
@@ -1236,8 +1355,8 @@ destroydecoration(struct wl_listener *listener, void *data)
@@ -1239,8 +1371,8 @@ destroydecoration(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, destroy_decoration);
@ -439,27 +461,25 @@ index ec4ca86..8d1eceb 100644
}
void
@@ -1246,8 +1365,7 @@ destroydragicon(struct wl_listener *listener, void *data)
@@ -1249,7 +1381,7 @@ destroydragicon(struct wl_listener *listener, void *data)
/* Focus enter isn't sent during drag, so refocus the focused node. */
focusclient(focustop(selmon), 1);
motionnotify(0, NULL, 0, 0, 0, 0);
- wl_list_remove(&listener->link);
- free(listener);
+ UNLISTEN(listener);
free(listener);
}
void
@@ -1256,8 +1374,7 @@ destroyidleinhibitor(struct wl_listener *listener, void *data)
@@ -1259,7 +1391,7 @@ destroyidleinhibitor(struct wl_listener *listener, void *data)
/* `data` is the wlr_surface of the idle inhibitor being destroyed,
* at this point the idle inhibitor is still in the list of the manager */
checkidleinhibitor(wlr_surface_get_root_surface(data));
- wl_list_remove(&listener->link);
- free(listener);
+ UNLISTEN(listener);
free(listener);
}
void
@@ -1266,9 +1383,9 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data)
@@ -1269,9 +1401,9 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data)
LayerSurface *l = wl_container_of(listener, l, destroy);
wl_list_remove(&l->link);
@ -472,7 +492,7 @@ index ec4ca86..8d1eceb 100644
wlr_scene_node_destroy(&l->scene->node);
wlr_scene_node_destroy(&l->popups->node);
free(l);
@@ -1287,9 +1404,9 @@ destroylock(SessionLock *lock, int unlock)
@@ -1290,9 +1422,9 @@ destroylock(SessionLock *lock, int unlock)
motionnotify(0, NULL, 0, 0, 0, 0);
destroy:
@ -485,7 +505,7 @@ index ec4ca86..8d1eceb 100644
wlr_scene_node_destroy(&lock->scene->node);
cur_lock = NULL;
@@ -1303,7 +1420,7 @@ destroylocksurface(struct wl_listener *listener, void *data)
@@ -1306,7 +1438,7 @@ destroylocksurface(struct wl_listener *listener, void *data)
struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface;
m->lock_surface = NULL;
@ -494,7 +514,7 @@ index ec4ca86..8d1eceb 100644
if (lock_surface->surface != seat->keyboard_state.focused_surface)
return;
@@ -1323,23 +1440,23 @@ destroynotify(struct wl_listener *listener, void *data)
@@ -1326,23 +1458,23 @@ destroynotify(struct wl_listener *listener, void *data)
{
/* Called when the xdg_toplevel is destroyed. */
Client *c = wl_container_of(listener, c, destroy);
@ -530,7 +550,7 @@ index ec4ca86..8d1eceb 100644
}
free(c);
}
@@ -1354,7 +1471,7 @@ destroypointerconstraint(struct wl_listener *listener, void *data)
@@ -1357,7 +1489,7 @@ destroypointerconstraint(struct wl_listener *listener, void *data)
active_constraint = NULL;
}
@ -539,7 +559,7 @@ index ec4ca86..8d1eceb 100644
free(pointer_constraint);
}
@@ -1370,9 +1487,9 @@ destroykeyboardgroup(struct wl_listener *listener, void *data)
@@ -1373,9 +1505,9 @@ destroykeyboardgroup(struct wl_listener *listener, void *data)
{
KeyboardGroup *group = wl_container_of(listener, group, destroy);
wl_event_source_remove(group->key_repeat_source);
@ -552,7 +572,7 @@ index ec4ca86..8d1eceb 100644
wlr_keyboard_group_destroy(group->wlr_group);
free(group);
}
@@ -1538,8 +1655,8 @@ gpureset(struct wl_listener *listener, void *data)
@@ -1541,8 +1673,8 @@ gpureset(struct wl_listener *listener, void *data)
if (!(alloc = wlr_allocator_autocreate(backend, drw)))
die("couldn't recreate allocator");
@ -563,7 +583,7 @@ index ec4ca86..8d1eceb 100644
wlr_compositor_set_renderer(compositor, drw);
@@ -2229,6 +2346,8 @@ resize(Client *c, struct wlr_box geo, int interact)
@@ -2232,6 +2364,8 @@ resize(Client *c, struct wlr_box geo, int interact)
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
}
@ -572,7 +592,7 @@ index ec4ca86..8d1eceb 100644
void
run(char *startup_cmd)
{
@@ -2268,11 +2387,11 @@ run(char *startup_cmd)
@@ -2271,11 +2405,11 @@ run(char *startup_cmd)
if (fd_set_nonblock(STDOUT_FILENO) < 0)
close(STDOUT_FILENO);
@ -586,7 +606,7 @@ index ec4ca86..8d1eceb 100644
/* TODO hack to get cursor to display in its initial location (100, 100)
* instead of (0, 0) and then jumping. still may not be fully
@@ -2288,6 +2407,9 @@ run(char *startup_cmd)
@@ -2291,6 +2425,9 @@ run(char *startup_cmd)
wl_display_run(dpy);
}
@ -596,7 +616,7 @@ index ec4ca86..8d1eceb 100644
void
setcursor(struct wl_listener *listener, void *data)
{
@@ -2434,17 +2556,19 @@ setsel(struct wl_listener *listener, void *data)
@@ -2437,17 +2574,19 @@ setsel(struct wl_listener *listener, void *data)
wlr_seat_set_selection(seat, event->source, event->serial);
}
@ -618,7 +638,7 @@ index ec4ca86..8d1eceb 100644
/* The Wayland display is managed by libwayland. It handles accepting
* clients from the Unix socket, manging Wayland globals, and so on. */
@@ -2460,7 +2584,7 @@ setup(void)
@@ -2463,7 +2602,7 @@ setup(void)
/* Initialize the scene graph used to lay out windows */
scene = wlr_scene_create();
@ -627,7 +647,7 @@ index ec4ca86..8d1eceb 100644
for (i = 0; i < NUM_LAYERS; i++)
layers[i] = wlr_scene_tree_create(&scene->tree);
drag_icon = wlr_scene_tree_create(&scene->tree);
@@ -2472,7 +2596,7 @@ setup(void)
@@ -2475,7 +2614,7 @@ setup(void)
* supports for shared memory, this configures that for clients. */
if (!(drw = wlr_renderer_autocreate(backend)))
die("couldn't create renderer");
@ -636,7 +656,7 @@ index ec4ca86..8d1eceb 100644
/* Create shm, drm and linux_dmabuf interfaces by ourselves.
* The simplest way is call:
@@ -2519,24 +2643,24 @@ setup(void)
@@ -2522,24 +2661,24 @@ setup(void)
/* Initializes the interface used to implement urgency hints */
activation = wlr_xdg_activation_v1_create(dpy);
@ -665,7 +685,7 @@ index ec4ca86..8d1eceb 100644
/* Set up our client lists, the xdg-shell and the layer-shell. The xdg-shell is a
* Wayland protocol which is used for application windows. For more
@@ -2548,19 +2672,19 @@ setup(void)
@@ -2551,19 +2690,19 @@ setup(void)
wl_list_init(&fstack);
xdg_shell = wlr_xdg_shell_create(dpy, 6);
@ -690,7 +710,7 @@ index ec4ca86..8d1eceb 100644
locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
(float [4]){0.1f, 0.1f, 0.1f, 1.0f});
wlr_scene_node_set_enabled(&locked_bg->node, 0);
@@ -2570,10 +2694,10 @@ setup(void)
@@ -2573,10 +2712,10 @@ setup(void)
wlr_server_decoration_manager_create(dpy),
WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(dpy);
@ -703,7 +723,7 @@ index ec4ca86..8d1eceb 100644
relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
@@ -2601,14 +2725,14 @@ setup(void)
@@ -2604,14 +2743,14 @@ setup(void)
*
* And more comments are sprinkled throughout the notify functions above.
*/
@ -724,7 +744,7 @@ index ec4ca86..8d1eceb 100644
/*
* Configures a seat, which is a single "seat" at which a user sits and
@@ -2616,27 +2740,27 @@ setup(void)
@@ -2619,27 +2758,27 @@ setup(void)
* pointer, touch, and drawing tablet device. We also rig up a listener to
* let us know when new input devices are available on the backend.
*/
@ -765,7 +785,7 @@ index ec4ca86..8d1eceb 100644
/* 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
@@ -2648,8 +2772,8 @@ setup(void)
@@ -2651,8 +2790,8 @@ setup(void)
* It will be started when the first X client is started.
*/
if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) {
@ -776,7 +796,7 @@ index ec4ca86..8d1eceb 100644
setenv("DISPLAY", xwayland->display_name, 1);
} else {
@@ -2658,6 +2782,9 @@ setup(void)
@@ -2661,6 +2800,9 @@ setup(void)
#endif
}
@ -786,7 +806,7 @@ index ec4ca86..8d1eceb 100644
void
spawn(const Arg *arg)
{
@@ -3139,8 +3266,8 @@ void
@@ -3142,8 +3284,8 @@ void
dissociatex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, dissociate);
@ -797,7 +817,7 @@ index ec4ca86..8d1eceb 100644
}
void
@@ -3175,17 +3302,141 @@ xwaylandready(struct wl_listener *listener, void *data)
@@ -3178,17 +3320,141 @@ xwaylandready(struct wl_listener *listener, void *data)
}
#endif
@ -891,7 +911,7 @@ index ec4ca86..8d1eceb 100644
+ wlr_log(WLR_ERROR, "couldn't load new dwl module from %s", get_module_path());
+
+ if (fork() == 0)
+ execl("/bin/env", "--", "Notify-send", "-u", "low", "failed to reload dwl", NULL);
+ execl("/bin/env", "--", "notify-send", "-u", "low", "failed to reload dwl", NULL);
+ return;
+ }
+
@ -940,7 +960,7 @@ index ec4ca86..8d1eceb 100644
else if (c == 'v')
die("dwl " VERSION);
else
@@ -3205,3 +3456,5 @@ main(int argc, char *argv[])
@@ -3208,3 +3474,5 @@ main(int argc, char *argv[])
usage:
die("Usage: %s [-v] [-d] [-s startup command]", argv[0]);
}
@ -1005,5 +1025,5 @@ index 226980d..11aab34 100644
+struct listens* append_listener(struct wl_listener* l, struct listens* ls);
+struct listens* remove_listener(struct wl_listener* l, struct listens* ls);
--
2.48.1
2.49.0

View File

@ -0,0 +1,14 @@
### Description
Rotate clients on current monitor.
Example Configuration:
```c
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_J, rotate_clients, {.i = +1} },
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, rotate_clients, {.i = -1} },
```
### Download
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/rotate-clients/rotate-clients.patch)
### Authors
- [folk](https://codeberg.org/folk)

View File

@ -0,0 +1,56 @@
diff --git a/config.def.h b/config.def.h
index 22d2171..6029666 100644
--- a/config.def.h
+++ b/config.def.h
@@ -129,6 +129,8 @@ static const Key keys[] = {
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_J, rotate_clients, {.i = +1} },
+ { MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_K, rotate_clients, {.i = -1} },
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
diff --git a/dwl.c b/dwl.c
index a2711f6..6dfd87d 100644
--- a/dwl.c
+++ b/dwl.c
@@ -355,6 +355,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 rotate_clients(const Arg *arg);
/* variables */
static const char broken[] = "broken";
@@ -3054,6 +3055,30 @@ zoom(const Arg *arg)
arrange(selmon);
}
+static void rotate_clients(const Arg *arg) {
+ Monitor* m = selmon;
+ Client *c;
+ Client *first = NULL;
+ Client *last = NULL;
+
+ if (arg->i == 0)
+ return;
+
+ wl_list_for_each(c, &clients, link) {
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen) {
+ if (first == NULL) first = c;
+ last = c;
+ }
+ }
+ if (first != last) {
+ struct wl_list *append_to = (arg->i > 0) ? &last->link : first->link.prev;
+ struct wl_list *elem = (arg->i > 0) ? &first->link : &last->link;
+ wl_list_remove(elem);
+ wl_list_insert(append_to, elem);
+ arrange(selmon);
+ }
+}
+
#ifdef XWAYLAND
void
activatex11(struct wl_listener *listener, void *data)

View File

@ -16,7 +16,7 @@ There was discussion of this matter in [Issue #141](https://codeberg.org/dwl/dwl
### Download
- [git branch](https://codeberg.org/fauxmight/dwl/src/branch/tablet-input)
- [main 2025-01-01](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-input/tablet-input.patch)
- [main 2025-05-18](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-input/tablet-input.patch)
- [0.7](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/tablet-input/tablet-input-0.7.patch)
### Authors

View File

@ -1,16 +1,16 @@
From e504dc0fccfc3994962f03dc824d8907c6afc64f Mon Sep 17 00:00:00 2001
From: choc <notchoc@proton.me>
Date: Sat, 4 May 2024 01:16:12 +0800
Subject: [PATCH] implement wlr-tablet-v2
From 0659663b7eb9cafbd4f86779084765aa838e29cd Mon Sep 17 00:00:00 2001
From: A Frederick Christensen <dwl@ivories.org>
Date: Sat, 17 May 2025 23:26:15 -0500
Subject: [PATCH] Add tablet input
---
Makefile | 6 +-
config.def.h | 1 +
dwl.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 230 insertions(+), 1 deletion(-)
dwl.c | 231 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 237 insertions(+), 1 deletion(-)
diff --git a/Makefile b/Makefile
index f955e7b..ce1b556 100644
index 578194f..e0d1835 100644
--- a/Makefile
+++ b/Makefile
@@ -21,7 +21,8 @@ dwl: dwl.o util.o
@ -46,10 +46,10 @@ index 22d2171..3ad98ef 100644
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 */
diff --git a/dwl.c b/dwl.c
index ac9c36b..b8d129f 100644
index 4816159..e8d36ac 100644
--- a/dwl.c
+++ b/dwl.c
@@ -50,6 +50,9 @@
@@ -51,6 +51,9 @@
#include <wlr/types/wlr_session_lock_v1.h>
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_subcompositor.h>
@ -59,7 +59,7 @@ index ac9c36b..b8d129f 100644
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
@@ -270,6 +273,7 @@ static void createnotify(struct wl_listener *listener, void *data);
@@ -268,6 +271,7 @@ static void createnotify(struct wl_listener *listener, void *data);
static void createpointer(struct wlr_pointer *pointer);
static void createpointerconstraint(struct wl_listener *listener, void *data);
static void createpopup(struct wl_listener *listener, void *data);
@ -67,9 +67,9 @@ index ac9c36b..b8d129f 100644
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
static void cursorframe(struct wl_listener *listener, void *data);
static void cursorwarptohint(void);
@@ -284,6 +288,9 @@ static void destroypointerconstraint(struct wl_listener *listener, void *data);
@@ -281,6 +285,9 @@ static void destroynotify(struct wl_listener *listener, void *data);
static void destroypointerconstraint(struct wl_listener *listener, void *data);
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 void destroytablet(struct wl_listener *listener, void *data);
+static void destroytabletsurfacenotify(struct wl_listener *listener, void *data);
@ -77,7 +77,7 @@ index ac9c36b..b8d129f 100644
static Monitor *dirtomon(enum wlr_direction dir);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
@@ -337,6 +344,11 @@ static void spawn(const Arg *arg);
@@ -333,6 +340,11 @@ static void spawn(const Arg *arg);
static void startdrag(struct wl_listener *listener, void *data);
static void tag(const Arg *arg);
static void tagmon(const Arg *arg);
@ -89,7 +89,7 @@ index ac9c36b..b8d129f 100644
static void tile(Monitor *m);
static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
@@ -396,6 +408,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint;
@@ -390,6 +402,13 @@ static struct wlr_pointer_constraint_v1 *active_constraint;
static struct wlr_cursor *cursor;
static struct wlr_xcursor_manager *cursor_mgr;
@ -103,7 +103,20 @@ index ac9c36b..b8d129f 100644
static struct wlr_scene_rect *root_bg;
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
static struct wlr_scene_rect *locked_bg;
@@ -1133,6 +1152,28 @@ createpopup(struct wl_listener *listener, void *data)
@@ -412,6 +431,12 @@ static struct wl_listener cursor_button = {.notify = buttonpress};
static struct wl_listener cursor_frame = {.notify = cursorframe};
static struct wl_listener cursor_motion = {.notify = motionrelative};
static struct wl_listener cursor_motion_absolute = {.notify = motionabsolute};
+static struct wl_listener tablet_device_destroy = {.notify = destroytablet};
+static struct wl_listener tablet_tool_axis = {.notify = tablettoolaxis};
+static struct wl_listener tablet_tool_button = {.notify = tablettoolbutton};
+static struct wl_listener tablet_tool_destroy = {.notify = destroytablettool};
+static struct wl_listener tablet_tool_proximity = {.notify = tablettoolproximity};
+static struct wl_listener tablet_tool_tip = {.notify = tablettooltip};
static struct wl_listener gpu_reset = {.notify = gpureset};
static struct wl_listener layout_change = {.notify = updatemons};
static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor};
@@ -1196,6 +1221,28 @@ createpopup(struct wl_listener *listener, void *data)
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
}
@ -117,7 +130,7 @@ index ac9c36b..b8d129f 100644
+ return;
+
+ tablet = wlr_tablet_create(tablet_mgr, seat, device);
+ LISTEN_STATIC(&tablet->wlr_device->events.destroy, destroytablet);
+ wl_signal_add(&tablet->wlr_device->events.destroy, &tablet_device_destroy);
+ if (libinput_device_config_send_events_get_modes(device_handle)) {
+ libinput_device_config_send_events_set_mode(device_handle, send_events_mode);
+ wlr_cursor_attach_input_device(cursor, device);
@ -132,7 +145,7 @@ index ac9c36b..b8d129f 100644
void
cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
{
@@ -1321,6 +1362,27 @@ destroykeyboardgroup(struct wl_listener *listener, void *data)
@@ -1380,6 +1427,27 @@ destroykeyboardgroup(struct wl_listener *listener, void *data)
free(group);
}
@ -160,7 +173,7 @@ index ac9c36b..b8d129f 100644
Monitor *
dirtomon(enum wlr_direction dir)
{
@@ -1540,6 +1602,12 @@ inputdevice(struct wl_listener *listener, void *data)
@@ -1587,6 +1655,12 @@ inputdevice(struct wl_listener *listener, void *data)
case WLR_INPUT_DEVICE_POINTER:
createpointer(wlr_pointer_from_input_device(device));
break;
@ -173,7 +186,7 @@ index ac9c36b..b8d129f 100644
default:
/* TODO handle other input device types */
break;
@@ -2567,6 +2635,8 @@ setup(void)
@@ -2580,6 +2654,8 @@ setup(void)
relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
@ -182,18 +195,19 @@ index ac9c36b..b8d129f 100644
/*
* Creates a cursor, which is a wlroots utility for tracking the cursor
* image shown on screen.
@@ -2596,6 +2666,10 @@ setup(void)
LISTEN_STATIC(&cursor->events.button, buttonpress);
LISTEN_STATIC(&cursor->events.axis, axisnotify);
LISTEN_STATIC(&cursor->events.frame, cursorframe);
+ LISTEN_STATIC(&cursor->events.tablet_tool_proximity, tablettoolproximity);
+ LISTEN_STATIC(&cursor->events.tablet_tool_axis, tablettoolaxis);
+ LISTEN_STATIC(&cursor->events.tablet_tool_button, tablettoolbutton);
+ LISTEN_STATIC(&cursor->events.tablet_tool_tip, tablettooltip);
@@ -2609,6 +2685,11 @@ setup(void)
wl_signal_add(&cursor->events.button, &cursor_button);
wl_signal_add(&cursor->events.axis, &cursor_axis);
wl_signal_add(&cursor->events.frame, &cursor_frame);
+ wl_signal_add(&cursor->events.tablet_tool_proximity, &tablet_tool_proximity);
+ wl_signal_add(&cursor->events.tablet_tool_axis, &tablet_tool_axis);
+ wl_signal_add(&cursor->events.tablet_tool_button, &tablet_tool_button);
+ wl_signal_add(&cursor->events.tablet_tool_tip, &tablet_tool_tip);
+
cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape);
@@ -2689,6 +2763,156 @@ tagmon(const Arg *arg)
wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
@@ -2704,6 +2785,159 @@ tagmon(const Arg *arg)
setmon(sel, dirtomon(arg->i), 0);
}
@ -276,8 +290,8 @@ index ac9c36b..b8d129f 100644
+
+ if (!tablet_tool) {
+ tablet_tool = wlr_tablet_tool_create(tablet_mgr, seat, tool);
+ LISTEN_STATIC(&tablet_tool->wlr_tool->events.destroy, destroytablettool);
+ LISTEN_STATIC(&tablet_tool->events.set_cursor, setcursor);
+ wl_signal_add(&tablet_tool->wlr_tool->events.destroy, &tablet_tool_destroy);
+ wl_signal_add(&tablet_tool->events.set_cursor, &request_cursor);
+ }
+
+ switch (event->state) {
@ -306,7 +320,10 @@ index ac9c36b..b8d129f 100644
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_DISTANCE)
+ wlr_tablet_v2_tablet_tool_notify_distance(tablet_tool, event->distance);
+ if (event->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y))
+ {
+ printf("DEBUGGING: In axis event handling\n");
+ wlr_tablet_v2_tablet_tool_notify_tilt(tablet_tool, event->tilt_x, event->tilt_y);
+ }
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_ROTATION)
+ wlr_tablet_v2_tablet_tool_notify_rotation(tablet_tool, event->rotation);
+ if (event->updated_axes & WLR_TABLET_TOOL_AXIS_SLIDER)
@ -351,5 +368,5 @@ index ac9c36b..b8d129f 100644
tile(Monitor *m)
{
--
2.43.0
2.49.0

View File

@ -0,0 +1,15 @@
### Description
This patch replaces the window borders of tiled windows with borders that are similar to those found in tmux. The result is that there are no more unnecessary borders along the monitor edges in tiled mode. Borders of floating windows are not affected.
### Preview
![two clients](screenshot1.png)
![three clients](screenshot2.png)
### Download
- [git branch](/kerberoge/dwl/src/branch/tmux-borders)
- [0.7](/dwl/dwl-patches/raw/branch/main/patches/tmux-borders/tmux-borders-0.7.patch)
### Authors
- [kerberoge](https://codeberg.org/kerberoge)\
kerberoge at [dwl Discord](https://discord.gg/jJxZnrGPWN)

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 481 KiB

View File

@ -0,0 +1,489 @@
From 464259603cb3b7346670cc33fd9afa0f8fe0cd49 Mon Sep 17 00:00:00 2001
From: kerberoge <sjoerdenjh@gmail.com>
Date: Sun, 1 Jun 2025 17:03:09 +0200
Subject: [PATCH 1/1] Created tmux-borders patch for stock dwl
---
client.h | 6 ++
dwl.c | 298 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 280 insertions(+), 24 deletions(-)
diff --git a/client.h b/client.h
index 42f225f..007ab7d 100644
--- a/client.h
+++ b/client.h
@@ -291,6 +291,12 @@ client_is_unmanaged(Client *c)
return 0;
}
+static inline int
+client_needs_borders(Client *c)
+{
+ return c->isfloating || !c->mon->lt[c->mon->sellt]->arrange;
+}
+
static inline void
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
{
diff --git a/dwl.c b/dwl.c
index a2711f6..c092c0e 100644
--- a/dwl.c
+++ b/dwl.c
@@ -191,6 +191,7 @@ struct Monitor {
struct wlr_output *wlr_output;
struct wlr_scene_output *scene_output;
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
+ struct wlr_scene_tree *borders, *fborders, *uborders;
struct wl_listener frame;
struct wl_listener destroy;
struct wl_listener request_state;
@@ -255,10 +256,12 @@ static void chvt(const Arg *arg);
static void checkidleinhibitor(struct wlr_surface *exclude);
static void cleanup(void);
static void cleanupmon(struct wl_listener *listener, void *data);
+static int clientindex(Monitor *m, Client *c);
static void closemon(Monitor *m);
static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
static void commitnotify(struct wl_listener *listener, void *data);
static void commitpopup(struct wl_listener *listener, void *data);
+static int countclients(Monitor *m);
static void createdecoration(struct wl_listener *listener, void *data);
static void createidleinhibitor(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_keyboard *keyboard);
@@ -273,6 +276,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 destroyborders(struct wlr_scene_tree *t);
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);
@@ -285,6 +289,13 @@ 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 drawclientborders(struct wlr_scene_tree *t, Client *c,
+ int cidx, int n, const float color[static 4]);
+static void drawrect(struct wlr_scene_tree *t,
+ int x, int y, int w, int h, const float color[static 4]);
+static void drawborders(Monitor *m);
+static void drawfborders(Monitor *m);
+static void drawuborders(Monitor *m);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
static void focusstack(const Arg *arg);
@@ -517,6 +528,11 @@ arrange(Monitor *m)
if (m->lt[m->sellt]->arrange)
m->lt[m->sellt]->arrange(m);
+
+ drawborders(m);
+ drawuborders(m);
+ drawfborders(m);
+
motionnotify(0, NULL, 0, 0, 0, 0);
checkidleinhibitor(NULL);
}
@@ -721,10 +737,34 @@ cleanupmon(struct wl_listener *listener, void *data)
wlr_scene_output_destroy(m->scene_output);
closemon(m);
+ wlr_scene_node_destroy(&m->borders->node);
+ wlr_scene_node_destroy(&m->fborders->node);
+ wlr_scene_node_destroy(&m->uborders->node);
wlr_scene_node_destroy(&m->fullscreen_bg->node);
free(m);
}
+int
+clientindex(Monitor *m, Client *c)
+{
+ unsigned int i = 0;
+ Client *ci;
+
+ if (!c || m->lt[m->sellt]->arrange != tile)
+ return -1;
+
+ wl_list_for_each(ci, &clients, link) {
+ if (VISIBLEON(ci, m) && !ci->isfloating && !ci->isfullscreen) {
+ if (ci == c)
+ return i;
+ else
+ i++;
+ }
+ }
+
+ return -1;
+}
+
void
closemon(Monitor *m)
{
@@ -743,6 +783,10 @@ closemon(Monitor *m)
selmon = NULL;
}
+ destroyborders(m->borders);
+ destroyborders(m->fborders);
+ destroyborders(m->uborders);
+
wl_list_for_each(c, &clients, link) {
if (c->isfloating && c->geom.x > m->m.width)
resize(c, (struct wlr_box){.x = c->geom.x - m->w.width, .y = c->geom.y,
@@ -849,6 +893,19 @@ commitpopup(struct wl_listener *listener, void *data)
wl_list_remove(&listener->link);
}
+int
+countclients(Monitor *m)
+{
+ unsigned int n = 0;
+ Client *c;
+
+ wl_list_for_each(c, &clients, link)
+ if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
+ n++;
+
+ return n;
+}
+
void
createdecoration(struct wl_listener *listener, void *data)
{
@@ -985,6 +1042,9 @@ createmon(struct wl_listener *listener, void *data)
m = wlr_output->data = ecalloc(1, sizeof(*m));
m->wlr_output = wlr_output;
+ m->borders = wlr_scene_tree_create(layers[LyrTile]);
+ m->fborders = wlr_scene_tree_create(layers[LyrTile]);
+ m->uborders = wlr_scene_tree_create(layers[LyrTile]);
for (i = 0; i < LENGTH(m->layers); i++)
wl_list_init(&m->layers[i]);
@@ -1171,6 +1231,15 @@ cursorwarptohint(void)
}
}
+void
+destroyborders(struct wlr_scene_tree *t)
+{
+ struct wlr_scene_node *node, *tmp;
+
+ wl_list_for_each_safe(node, tmp, &t->children, link)
+ wlr_scene_node_destroy(node);
+}
+
void
destroydecoration(struct wl_listener *listener, void *data)
{
@@ -1336,6 +1405,154 @@ dirtomon(enum wlr_direction dir)
return selmon;
}
+void
+drawclientborders(struct wlr_scene_tree *t, Client *c, int cidx, int n, const float color[static 4])
+{
+ Monitor *m;
+ int mw, x, y, w, h;
+
+ m = c->mon;
+ mw = (int)round(m->w.width * m->mfact - 0.5 * borderpx);
+
+ if (m->nmaster == 1 && n == 2) {
+ /* Half vertical center line */
+ y = m->w.y + (cidx == 1 ? m->w.height / 2 : 0);
+ h = (int)round(0.5 * m->w.height);
+ drawrect(t, m->w.x + mw, y, borderpx, h, color);
+ } else if (m->nmaster != 1 && n == 2) {
+ /* Half horizontal center line */
+ x = m->w.x + (cidx == 1 ? m->w.width / 2 : 0);
+ y = m->w.y + (int)round(0.5 * m->w.height - 0.5 * borderpx);
+ w = (int)round(0.5 * m->w.width);
+ drawrect(t, x, y, w, borderpx, color);
+ } else {
+ if (m->nmaster && n > m->nmaster)
+ /* Vertical line next to client */
+ drawrect(t, m->w.x + mw, c->geom.y, borderpx, c->geom.height, color);
+
+ if (n > m->nmaster && cidx < m->nmaster) {
+ /* Left half */
+ x = m->w.x;
+ w = mw + borderpx;
+ } else if (m->nmaster && cidx >= m->nmaster) {
+ /* Right half */
+ x = m->w.x + mw;
+ w = m->w.width - mw;
+ } else {
+ /* Full width */
+ x = m->w.x;
+ w = m->w.width;
+ }
+
+ if ((cidx > 0 && cidx < m->nmaster) || (cidx > m->nmaster))
+ /* Line above client */
+ drawrect(t, x, c->geom.y - borderpx, w, borderpx, color);
+
+ if ((cidx < m->nmaster - 1) || (cidx >= m->nmaster && cidx < n - 1))
+ /* Line below client */
+ drawrect(t, x, c->geom.y + c->geom.height, w, borderpx, color);
+ }
+}
+
+void
+drawrect(struct wlr_scene_tree *t, int x, int y, int w, int h, const float color[static 4])
+{
+ struct wlr_scene_rect *r;
+
+ r = wlr_scene_rect_create(t, w, h, color);
+ wlr_scene_node_set_position(&r->node, x, y);
+}
+
+void
+drawborders(Monitor *m)
+{
+ int n, i;
+ int mw, tw, my = 0, ty = 0;
+
+ if (!m)
+ return;
+
+ destroyborders(m->borders);
+ n = countclients(m);
+
+ if (n <= 1 || m->lt[m->sellt]->arrange != tile)
+ return;
+
+ if (m->nmaster > 0 && n > m->nmaster)
+ mw = (int)round(m->w.width * m->mfact - 0.5 * borderpx);
+ else if (n <= m->nmaster)
+ mw = m->w.width;
+ else
+ mw = 0;
+
+ if (mw > 0)
+ tw = m->w.width - mw - borderpx;
+ else
+ tw = m->w.width;
+
+ /* Vertical center line */
+ if (mw > 0 && mw < m->w.width)
+ drawrect(m->borders, m->w.x + mw, m->w.y, borderpx, m->w.height, bordercolor);
+
+ /* Lines between master clients */
+ for (i = 0; i < MIN(n, m->nmaster) - 1; i++) {
+ my += (m->w.height - my - borderpx * (MIN(n, m->nmaster) - i - 1))
+ / (MIN(n, m->nmaster) - i);
+ drawrect(m->borders, m->w.x, m->w.y + my, mw, borderpx, bordercolor);
+ my += borderpx;
+ }
+
+ /* Lines between clients on the stack */
+ for (i = m->nmaster; i < n - 1; i++) {
+ ty += (m->w.height - ty - borderpx * (n - i - 1)) / (n - i);
+ drawrect(m->borders, m->m.x + (mw ? mw + borderpx : 0), m->w.y + ty,
+ tw, borderpx, bordercolor);
+ ty += borderpx;
+ }
+}
+
+void
+drawfborders(Monitor *m)
+{
+ Client *fc;
+ int n, cidx;
+
+ if (!m)
+ return;
+
+ destroyborders(m->fborders);
+ n = countclients(m);
+ fc = focustop(m);
+ cidx = clientindex(m, fc);
+
+ if (n <= 1 || cidx == -1)
+ return;
+
+ drawclientborders(m->fborders, fc, cidx, n, focuscolor);
+}
+
+void
+drawuborders(Monitor *m)
+{
+ Client *c;
+ int n, cidx;
+
+ if (!m)
+ return;
+
+ destroyborders(m->uborders);
+ n = countclients(m);
+
+ if (n <= 1)
+ return;
+
+ wl_list_for_each(c, &clients, link) {
+ cidx = clientindex(m, c);
+ if (cidx != -1 && c->isurgent)
+ drawclientborders(m->uborders, c, cidx, n, urgentcolor);
+ }
+}
+
void
focusclient(Client *c, int lift)
{
@@ -1366,12 +1583,15 @@ focusclient(Client *c, int lift)
wl_list_insert(&fstack, &c->flink);
selmon = c->mon;
c->isurgent = 0;
+ drawuborders(c->mon);
client_restack_surface(c);
/* Don't change border color if there is an exclusive focus or we are
* handling a drag operation */
- if (!exclusive_focus && !seat->drag)
+ if (!exclusive_focus && !seat->drag) {
client_set_border_color(c, focuscolor);
+ drawfborders(c->mon);
+ }
}
/* Deactivate old client if focus is changing */
@@ -1389,7 +1609,8 @@ focusclient(Client *c, int lift)
* and probably other clients */
} else if (old_c && !client_is_unmanaged(old_c) && (!c || !client_wants_focus(c))) {
client_set_border_color(old_c, bordercolor);
-
+ if (old_c->mon && (!c || c->mon != old_c->mon))
+ destroyborders(old_c->mon->fborders);
client_activate_surface(old, 0);
}
}
@@ -2193,15 +2414,20 @@ resize(Client *c, struct wlr_box geo, int interact)
applybounds(c, bbox);
/* Update scene-graph, including borders */
+ c->bw = client_needs_borders(c) ? borderpx : 0;
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);
+ for (int i = 0; i < 4; i++)
+ wlr_scene_node_set_enabled(&c->border[i]->node, c->bw);
+ if (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);
+ }
/* this is a no-op if size hasn't changed */
c->resize = client_set_size(c, c->geom.width - 2 * c->bw,
@@ -2359,8 +2585,13 @@ setlayout(const Arg *arg)
return;
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
selmon->sellt ^= 1;
+ else
+ return;
if (arg && arg->v)
selmon->lt[selmon->sellt] = (Layout *)arg->v;
+ if (selmon->lt[selmon->sellt ^ 1]->arrange == tile && !selmon->lt[selmon->sellt]->arrange)
+ /* Tiled -> floating, remove monitor borders and enable client borders */
+ tile(selmon);
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, LENGTH(selmon->ltsymbol));
arrange(selmon);
printstatus();
@@ -2692,31 +2923,46 @@ void
tile(Monitor *m)
{
unsigned int mw, my, ty;
- int i, n = 0;
+ int i, n;
Client *c;
+ struct wlr_box wb;
+ int borders = m->lt[m->sellt]->arrange == tile ? 1 : 0;
- wl_list_for_each(c, &clients, link)
- if (VISIBLEON(c, m) && !c->isfloating && !c->isfullscreen)
- n++;
+ n = countclients(m);
if (n == 0)
return;
- if (n > m->nmaster)
- mw = m->nmaster ? (int)roundf(m->w.width * m->mfact) : 0;
- else
+ if (n > m->nmaster && m->nmaster) {
+ mw = (int)round(m->w.width * m->mfact - (borders ? 0.5 * borderpx : 0));
+ } else if (m->nmaster)
mw = m->w.width;
+ else
+ mw = 0;
i = my = ty = 0;
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;
+ wb.x = m->w.x;
+ wb.y = m->w.y + my;
+ wb.width = mw;
+ if (borders)
+ wb.height = (m->w.height - my - borderpx * (MIN(n, m->nmaster) - i - 1))
+ / (MIN(n, m->nmaster) - i);
+ else
+ wb.height = (m->w.height - my) / (MIN(n, m->nmaster) - i);
+ resize(c, wb, 0);
+ my += wb.height + (borders ? borderpx : 0);
} 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;
+ wb.x = m->w.x + mw + (mw && borders ? borderpx : 0);
+ wb.y = m->w.y + ty;
+ wb.width = m->w.width - mw - (mw && borders ? borderpx : 0);
+ if (borders)
+ wb.height = (m->w.height - ty - borderpx * (n - i - 1)) / (n - i);
+ else
+ wb.height = (m->w.height - ty) / (n - i);
+ resize(c, wb, 0);
+ ty += wb.height + (borders ? borderpx : 0);
}
i++;
}
@@ -2941,8 +3187,10 @@ urgent(struct wl_listener *listener, void *data)
c->isurgent = 1;
printstatus();
- if (client_surface(c)->mapped)
+ if (client_surface(c)->mapped) {
client_set_border_color(c, urgentcolor);
+ drawuborders(c->mon);
+ }
}
void
@@ -3147,8 +3395,10 @@ sethints(struct wl_listener *listener, void *data)
c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
printstatus();
- if (c->isurgent && surface && surface->mapped)
+ if (c->isurgent && surface && surface->mapped) {
client_set_border_color(c, urgentcolor);
+ drawuborders(c->mon);
+ }
}
void
--
2.49.0

View File

@ -6,7 +6,7 @@ KNOWN BUGS:
### Download
- [git branch](https://codeberg.org/fauxmight/dwl/src/branch/touch-input)
- [2025-01-01](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input.patch)
- [2025-05-17](https://codeberg.org/dwl/dwl-patches/raw/branch/main/patches/touch-input/touch-input.patch)
### Authors
- [fauxmight](https://codeberg.org/fauxmight)

View File

@ -1,260 +0,0 @@
From 49503be07eea1b4422288323aa87a9ba7ebdefc3 Mon Sep 17 00:00:00 2001
From: Micah N Gorrell <m@minego.net>
Date: Fri, 9 Feb 2024 17:08:20 -0700
Subject: [PATCH] Add support for touch screen input devices, and send the
appropriate events to clients
---
dwl.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
diff --git a/dwl.c b/dwl.c
index ad21e1b..73fbd0d 100644
--- a/dwl.c
+++ b/dwl.c
@@ -51,6 +51,7 @@
#include <wlr/types/wlr_session_lock_v1.h>
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_subcompositor.h>
+#include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
@@ -161,6 +162,12 @@ typedef struct {
struct wl_listener destroy;
} KeyboardGroup;
+typedef struct TouchGroup {
+ struct wl_list link;
+ struct wlr_touch *touch;
+ Monitor *m;
+} TouchGroup;
+
typedef struct {
/* Must keep this field first */
unsigned int type; /* LayerShell */
@@ -268,7 +275,9 @@ static void createnotify(struct wl_listener *listener, void *data);
static void createpointer(struct wlr_pointer *pointer);
static void createpointerconstraint(struct wl_listener *listener, void *data);
static void createpopup(struct wl_listener *listener, void *data);
+static void createtouch(struct wlr_touch *touch);
static void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint);
+static void createtouch(struct wlr_touch *touch);
static void cursorframe(struct wl_listener *listener, void *data);
static void cursorwarptohint(void);
static void destroydecoration(struct wl_listener *listener, void *data);
@@ -338,6 +347,10 @@ static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
+static void touchdown(struct wl_listener *listener, void *data);
+static void touchup(struct wl_listener *listener, void *data);
+static void touchframe(struct wl_listener *listener, void *data);
+static void touchmotion(struct wl_listener *listener, void *data);
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);
@@ -405,6 +418,7 @@ static struct wlr_output_layout *output_layout;
static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static struct wl_list touches;
/* global event handlers */
static struct wl_listener cursor_axis = {.notify = axisnotify};
@@ -434,6 +448,10 @@ static struct wl_listener request_set_sel = {.notify = setsel};
static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
static struct wl_listener start_drag = {.notify = startdrag};
+static struct wl_listener touch_down = {.notify = touchdown};
+static struct wl_listener touch_frame = {.notify = touchframe};
+static struct wl_listener touch_motion = {.notify = touchmotion};
+static struct wl_listener touch_up = {.notify = touchup};
static struct wl_listener new_session_lock = {.notify = locksession};
#ifdef XWAYLAND
@@ -775,6 +793,10 @@ cleanuplisteners(void)
wl_list_remove(&request_set_cursor_shape.link);
wl_list_remove(&request_start_drag.link);
wl_list_remove(&start_drag.link);
+ wl_list_remove(&touch_down.link);
+ wl_list_remove(&touch_frame.link);
+ wl_list_remove(&touch_motion.link);
+ wl_list_remove(&touch_up.link);
wl_list_remove(&new_session_lock.link);
#ifdef XWAYLAND
wl_list_remove(&new_xwayland_surface.link);
@@ -1192,6 +1214,16 @@ createpopup(struct wl_listener *listener, void *data)
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
}
+void
+createtouch(struct wlr_touch *wlr_touch)
+{
+ TouchGroup *touch = ecalloc(1, sizeof(TouchGroup));
+
+ touch->touch = wlr_touch;
+ wl_list_insert(&touches, &touch->link);
+ wlr_cursor_attach_input_device(cursor, &wlr_touch->base);
+}
+
void
cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
{
@@ -1581,6 +1613,9 @@ inputdevice(struct wl_listener *listener, void *data)
case WLR_INPUT_DEVICE_POINTER:
createpointer(wlr_pointer_from_input_device(device));
break;
+ case WLR_INPUT_DEVICE_TOUCH:
+ createtouch(wlr_touch_from_input_device(device));
+ break;
default:
/* TODO handle other input device types */
break;
@@ -1593,6 +1628,8 @@ inputdevice(struct wl_listener *listener, void *data)
caps = WL_SEAT_CAPABILITY_POINTER;
if (!wl_list_empty(&kb_group->wlr_group->devices))
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
+ if (!wl_list_empty(&touches))
+ caps |= WL_SEAT_CAPABILITY_TOUCH;
wlr_seat_set_capabilities(seat, caps);
}
@@ -2604,6 +2641,13 @@ setup(void)
wl_signal_add(&cursor->events.axis, &cursor_axis);
wl_signal_add(&cursor->events.frame, &cursor_frame);
+ wl_list_init(&touches);
+
+ wl_signal_add(&cursor->events.touch_down, &touch_down);
+ wl_signal_add(&cursor->events.touch_frame, &touch_frame);
+ wl_signal_add(&cursor->events.touch_motion, &touch_motion);
+ wl_signal_add(&cursor->events.touch_up, &touch_up);
+
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);
@@ -2776,6 +2820,120 @@ toggleview(const Arg *arg)
printstatus();
}
+void
+touchdown(struct wl_listener *listener, void *data)
+{
+ struct wlr_touch_down_event *event = data;
+ double lx, ly;
+ double sx, sy;
+ struct wlr_surface *surface;
+ Client *c = NULL;
+ uint32_t serial = 0;
+ Monitor *m;
+
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+
+ // Map the input to the appropriate output, to ensure that rotation is
+ // handled.
+ wl_list_for_each(m, &mons, link) {
+ if (m == NULL || m->wlr_output == NULL) {
+ continue;
+ }
+ if (event->touch->output_name != NULL && 0 != strcmp(event->touch->output_name, m->wlr_output->name)) {
+ continue;
+ }
+
+ wlr_cursor_map_input_to_output(cursor, &event->touch->base, m->wlr_output);
+ }
+
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
+
+ /* Find the client under the pointer and send the event along. */
+ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
+ if (sloppyfocus)
+ focusclient(c, 0);
+
+ if (surface != NULL) {
+ serial = wlr_seat_touch_notify_down(seat, surface, event->time_msec, event->touch_id, sx, sy);
+ }
+
+ if (serial && wlr_seat_touch_num_points(seat) == 1) {
+ /* Emulate a mouse click if the touch event wasn't handled */
+ struct wlr_pointer_button_event *button_event = data;
+ struct wlr_pointer_motion_absolute_event *motion_event = data;
+ double dx, dy;
+
+ wlr_cursor_absolute_to_layout_coords(cursor, &motion_event->pointer->base, motion_event->x, motion_event->y, &lx, &ly);
+ wlr_cursor_warp_closest(cursor, &motion_event->pointer->base, lx, ly);
+ dx = lx - cursor->x;
+ dy = ly - cursor->y;
+ motionnotify(motion_event->time_msec, &motion_event->pointer->base, dx, dy, dx, dy);
+
+ button_event->button = BTN_LEFT;
+ button_event->state = WL_POINTER_BUTTON_STATE_PRESSED;
+ buttonpress(listener, button_event);
+ }
+}
+
+void
+touchup(struct wl_listener *listener, void *data)
+{
+ struct wlr_touch_up_event *event = data;
+
+ if (!wlr_seat_touch_get_point(seat, event->touch_id)) {
+ return;
+ }
+
+ if (wlr_seat_touch_num_points(seat) == 1) {
+ struct wlr_pointer_button_event *button_event = data;
+
+ button_event->button = BTN_LEFT;
+ button_event->state = WL_POINTER_BUTTON_STATE_RELEASED;
+ buttonpress(listener, button_event);
+ }
+
+ wlr_seat_touch_notify_up(seat, event->time_msec, event->touch_id);
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+}
+
+void
+touchframe(struct wl_listener *listener, void *data)
+{
+ wlr_seat_touch_notify_frame(seat);
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+}
+
+void
+touchmotion(struct wl_listener *listener, void *data)
+{
+ struct wlr_touch_motion_event *event = data;
+ double lx, ly;
+ double sx, sy;
+ struct wlr_surface *surface;
+ Client *c = NULL;
+
+ if (!wlr_seat_touch_get_point(seat, event->touch_id)) {
+ return;
+ }
+
+ wlr_cursor_absolute_to_layout_coords(cursor, &event->touch->base, event->x, event->y, &lx, &ly);
+ xytonode(lx, ly, &surface, &c, NULL, &sx, &sy);
+
+ if (c != NULL && surface != NULL) {
+ if (sloppyfocus)
+ focusclient(c, 0);
+ wlr_seat_touch_point_focus(seat, surface, event->time_msec, event->touch_id, sx, sy);
+ } else {
+ if (sloppyfocus)
+ focusclient(NULL, 0);
+ wlr_seat_touch_point_clear_focus(seat, event->time_msec, event->touch_id);
+ }
+ wlr_seat_touch_notify_motion(seat, event->time_msec, event->touch_id, sx, sy);
+
+ wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
+}
+
+
void
unlocksession(struct wl_listener *listener, void *data)
{
--
2.47.0

View File

@ -1,15 +1,15 @@
From 0eda173488e6ef3b0c7744e8cef0b3e0dfc81605 Mon Sep 17 00:00:00 2001
From: Micah N Gorrell <m@minego.net>
Date: Fri, 9 Feb 2024 17:08:20 -0700
Subject: [PATCH] Add support for touch screen input devices, and send the
appropriate events to clients
From f133af7120e28f3d8bda4d4e14b3bfd477b46426 Mon Sep 17 00:00:00 2001
From: A Frederick Christensen <dwl@ivories.org>
Date: Sat, 17 May 2025 21:59:37 -0500
Subject: [PATCH] Add support for touchscreen input devices
and send the appropriate events to clients
---
dwl.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 150 insertions(+)
dwl.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
diff --git a/dwl.c b/dwl.c
index 0eba3e9..c9eb7fb 100644
index 4816159..3a378f9 100644
--- a/dwl.c
+++ b/dwl.c
@@ -51,6 +51,7 @@
@ -20,7 +20,7 @@ index 0eba3e9..c9eb7fb 100644
#include <wlr/types/wlr_viewporter.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
@@ -165,6 +166,12 @@ typedef struct {
@@ -161,6 +162,12 @@ typedef struct {
struct wl_listener destroy;
} KeyboardGroup;
@ -33,7 +33,7 @@ index 0eba3e9..c9eb7fb 100644
typedef struct {
/* Must keep this field first */
unsigned int type; /* LayerShell */
@@ -271,7 +278,9 @@ static void createnotify(struct wl_listener *listener, void *data);
@@ -268,7 +275,9 @@ static void createnotify(struct wl_listener *listener, void *data);
static void createpointer(struct wlr_pointer *pointer);
static void createpointerconstraint(struct wl_listener *listener, void *data);
static void createpopup(struct wl_listener *listener, void *data);
@ -43,7 +43,7 @@ index 0eba3e9..c9eb7fb 100644
static void cursorframe(struct wl_listener *listener, void *data);
static void cursorwarptohint(void);
static void destroydecoration(struct wl_listener *listener, void *data);
@@ -342,6 +351,10 @@ static void togglefloating(const Arg *arg);
@@ -338,6 +347,10 @@ static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
@ -54,15 +54,37 @@ index 0eba3e9..c9eb7fb 100644
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);
@@ -410,6 +423,7 @@ static struct wlr_output_layout *output_layout;
@@ -405,6 +418,7 @@ static struct wlr_output_layout *output_layout;
static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
+static struct wl_list touches;
/* global event handlers */
static struct wl_listener cursor_axis = {.notify = axisnotify};
@@ -434,6 +448,10 @@ static struct wl_listener request_set_sel = {.notify = setsel};
static struct wl_listener request_set_cursor_shape = {.notify = setcursorshape};
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
static struct wl_listener start_drag = {.notify = startdrag};
+static struct wl_listener touch_down = {.notify = touchdown};
+static struct wl_listener touch_frame = {.notify = touchframe};
+static struct wl_listener touch_motion = {.notify = touchmotion};
+static struct wl_listener touch_up = {.notify = touchup};
static struct wl_listener new_session_lock = {.notify = locksession};
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
@@ -1129,6 +1143,16 @@ createpopup(struct wl_listener *listener, void *data)
@@ -778,6 +796,10 @@ cleanuplisteners(void)
wl_list_remove(&request_set_cursor_shape.link);
wl_list_remove(&request_start_drag.link);
wl_list_remove(&start_drag.link);
+ wl_list_remove(&touch_down.link);
+ wl_list_remove(&touch_frame.link);
+ wl_list_remove(&touch_motion.link);
+ wl_list_remove(&touch_up.link);
wl_list_remove(&new_session_lock.link);
#ifdef XWAYLAND
wl_list_remove(&new_xwayland_surface.link);
@@ -1196,6 +1218,16 @@ createpopup(struct wl_listener *listener, void *data)
LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup);
}
@ -79,7 +101,7 @@ index 0eba3e9..c9eb7fb 100644
void
cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
{
@@ -1534,6 +1558,9 @@ inputdevice(struct wl_listener *listener, void *data)
@@ -1587,6 +1619,9 @@ inputdevice(struct wl_listener *listener, void *data)
case WLR_INPUT_DEVICE_POINTER:
createpointer(wlr_pointer_from_input_device(device));
break;
@ -89,7 +111,7 @@ index 0eba3e9..c9eb7fb 100644
default:
/* TODO handle other input device types */
break;
@@ -1546,6 +1573,8 @@ inputdevice(struct wl_listener *listener, void *data)
@@ -1599,6 +1634,8 @@ inputdevice(struct wl_listener *listener, void *data)
caps = WL_SEAT_CAPABILITY_POINTER;
if (!wl_list_empty(&kb_group->wlr_group->devices))
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
@ -98,21 +120,21 @@ index 0eba3e9..c9eb7fb 100644
wlr_seat_set_capabilities(seat, caps);
}
@@ -2557,6 +2586,13 @@ setup(void)
LISTEN_STATIC(&cursor->events.axis, axisnotify);
LISTEN_STATIC(&cursor->events.frame, cursorframe);
@@ -2610,6 +2647,13 @@ setup(void)
wl_signal_add(&cursor->events.axis, &cursor_axis);
wl_signal_add(&cursor->events.frame, &cursor_frame);
+ wl_list_init(&touches);
+
+ LISTEN_STATIC(&cursor->events.touch_down, touchdown);
+ LISTEN_STATIC(&cursor->events.touch_frame, touchframe);
+ LISTEN_STATIC(&cursor->events.touch_motion, touchmotion);
+ LISTEN_STATIC(&cursor->events.touch_up, touchup);
+ wl_signal_add(&cursor->events.touch_down, &touch_down);
+ wl_signal_add(&cursor->events.touch_frame, &touch_frame);
+ wl_signal_add(&cursor->events.touch_motion, &touch_motion);
+ wl_signal_add(&cursor->events.touch_up, &touch_up);
+
cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1);
LISTEN_STATIC(&cursor_shape_mgr->events.request_set_shape, setcursorshape);
wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape);
@@ -2727,6 +2763,120 @@ toggleview(const Arg *arg)
@@ -2782,6 +2826,120 @@ toggleview(const Arg *arg)
printstatus();
}
@ -234,5 +256,5 @@ index 0eba3e9..c9eb7fb 100644
unlocksession(struct wl_listener *listener, void *data)
{
--
2.47.0
2.49.0