16 Commits
Author SHA1 Message Date
A Frederick Christensen 21be76ac80 Formally not lead developers in README
User @guidocella joins dwl as a lead developer
2026-09-08 11:33:59 -05:00
julmajustus 70c33c015a Remove rendermon pending resize frame skip
This is no longer needed as wlroots => 0.19 handles this internally via scene-level surface state tracking and
linux-drm-syncobj explicit sync.

The manual commit skip now causes the c->resize to be stuck on non-zero
state which leads to choppy resizing experience.
2026-09-08 17:28:19 +02:00
Guido Cella ee788f0149 update wlroots version in commented variables 2026-09-08 11:44:44 +02:00
A Frederick Christensen 132606e133 add support for ext-image-copy-capture-v1 and ext-image-capture-source-v1 (wlroots!4545) 2026-09-08 11:44:44 +02:00
Thanatos 49ca434514 Bumped to 0.9 for wlroots-0.20.0. Updated cursor image buffer handling for xwayland 2026-09-08 11:44:44 +02:00
save196 babccfe6dc Preserve asleep disabled outputs in output config 2026-09-08 11:39:37 +02:00
klim 4847f97678 Clear surface->data on unmap to fix idle-inhibitor use-after-free
mapnotify() stores the client's scene tree in client_surface(c)->data;
checkidleinhibitor() later reads it back as a wlr_scene_tree and calls
wlr_scene_node_coords() on it. unmapnotify() frees the scene tree with
wlr_scene_node_destroy() but leaves surface->data dangling, so the next
arrange() -> checkidleinhibitor() dereferences freed memory and crashes
(SIGSEGV) whenever an idle inhibitor outlives the unmap.

Reset the pointer to NULL on unmap so the existing !tree guard handles it.
2026-09-08 09:30:56 +02:00
Alex Denes 04279f28e0 Remove decoration event listeners on destroynotify
When destroynotify doesn't clean up these listeners it causes a crash once the cleanup of the decoration is triggered

Thanks to kennylevinsen - https://codeberg.org/dwl/dwl/issues/1205#issuecomment-22424401
2026-09-06 13:52:31 +00:00
Alex Denes f4dfdabd0b NULL out decoration on destroy 2026-09-06 13:52:31 +00:00
Diego Viola a2d03cf618 Remove trailing whitespace from README 2026-03-02 02:13:43 +01:00
Diego Viola cb4cc3ae8f Fix typos 2026-02-25 02:38:09 -03:00
thanatos 9b76ee8e90 Updated README to clarify branch roles
This change effectively reverts DWL to the prior development model, where development of DWL itself happens against the current wlroots release, and changes in anticipation of the next wlroots release are made on a separate branch.
2026-02-21 19:50:17 +01:00
thanatos 908a73da82 Corrected README 2026-02-21 16:53:19 +01:00
thanatos 227cdf0128 Added Matrix to README 2026-02-21 16:46:08 +01:00
Guido Cella ca4123072d add support for the data control protocol
Enables the protocol documented at
https://wayland.app/protocols/ext-data-control-v1

It is the upstreamed version of the old wlr_data_control.

It is used e.g. by mpv to read and write the clipboard.
2026-02-12 01:47:40 +01:00
fauxmight a8915224e8 Remove "unmaintained" notice from README
User @thanatos has offered to take on the lead developer role for dwl.
2026-02-09 08:06:25 +01:00
4 changed files with 51 additions and 41 deletions
+4
View File
@@ -20,6 +20,7 @@ all: dwl
dwl: dwl.o util.o dwl: dwl.o util.o
$(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -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 client.h config.h config.mk cursor-shape-v1-protocol.h \
ext-image-copy-capture-v1-protocol.h \
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-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
util.o: util.c util.h util.o: util.c util.h
@@ -33,6 +34,9 @@ WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols`
cursor-shape-v1-protocol.h: cursor-shape-v1-protocol.h:
$(WAYLAND_SCANNER) enum-header \ $(WAYLAND_SCANNER) enum-header \
$(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@ $(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
ext-image-copy-capture-v1-protocol.h:
$(WAYLAND_SCANNER) enum-header \
$(WAYLAND_PROTOCOLS)/staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml $@
pointer-constraints-unstable-v1-protocol.h: pointer-constraints-unstable-v1-protocol.h:
$(WAYLAND_SCANNER) enum-header \ $(WAYLAND_SCANNER) enum-header \
$(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@ $(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
+17 -16
View File
@@ -1,15 +1,8 @@
# dwl - dwm for Wayland # dwl - dwm for Wayland
2025-08-16: Join us on our [Discord server]
dwl IS CURRENTLY UN-MAINTAINED. Or Matrix: [#dwl-official:matrix.org]
AT THE PRESENT TIME, I (@fauxmight) DO NOT HAVE Or on our IRC channel: [#dwl on Libera Chat]
THE TIME OR CAPACITY TO KEEP UP WITH [wlroots] CHANGES.
IF YOU ARE INTERESTED IN TAKING ON LEAD DEVELOPER RESPONSIBILITIES,
SEE ISSUE [#1166](https://codeberg.org/dwl/dwl/issues/1166).
---
Join us on our IRC channel: [#dwl on Libera Chat]
Or on the community-maintained [Discord server].
dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is
intended to fill the same space in the Wayland world that [dwm] does in X11, intended to fill the same space in the Wayland world that [dwm] does in X11,
@@ -31,12 +24,14 @@ with each release on the [release] page
### Development branch [main] ### Development branch [main]
Active development progresses on the `main` branch. The `main` branch is built Active development progresses on the `main` branch. The `main` branch is built
against a late (and often changing) git commit of wlroots. While the adventurous against the latest release of [wlroots]. PRs should target this branch unless they
are welcome to use `main`, it is a rocky road. Using `main` requires that the depend on functionality that is not in the current release of `wlroots`.
user be willing to chase git commits of wlroots. Testing development pull
requests may involve merging unmerged pull requests in [wlroots]' git repository ### Preview branch [wlroots-next]
and/or git commits of wayland. The `wlroots-next` branch is built against the git version of [wlroots], which
is unstable and changes frequently. PRs requiring functionality from the git
version of `wlroots` should target this branch.
### Building dwl ### Building dwl
dwl has the following dependencies: dwl has the following dependencies:
- libinput - libinput
@@ -198,6 +193,10 @@ inspiration, and to the various contributors to the project, including:
and for helping to keep the project running and for helping to keep the project running
- Stivvo for output management and fullscreen support, and patch maintenance - Stivvo for output management and fullscreen support, and patch maintenance
Also, thanks to our current lead developers:
- @thanatos
- @guidocella
[wlroots]: https://gitlab.freedesktop.org/wlroots [wlroots]: https://gitlab.freedesktop.org/wlroots
[dwm]: https://dwm.suckless.org/ [dwm]: https://dwm.suckless.org/
@@ -210,6 +209,7 @@ inspiration, and to the various contributors to the project, including:
[dwl-patches]: https://codeberg.org/dwl/dwl-patches [dwl-patches]: https://codeberg.org/dwl/dwl-patches
[list of useful resources on our wiki]: https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x [list of useful resources on our wiki]: https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x
[main]: https://codeberg.org/dwl/dwl/src/branch/main [main]: https://codeberg.org/dwl/dwl/src/branch/main
[wlroots-next]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next
[release]: https://codeberg.org/dwl/dwl/releases [release]: https://codeberg.org/dwl/dwl/releases
[runit]: http://smarden.org/runit/faq.html#userservices [runit]: http://smarden.org/runit/faq.html#userservices
[s6]: https://skarnet.org/software/s6/ [s6]: https://skarnet.org/software/s6/
@@ -217,3 +217,4 @@ inspiration, and to the various contributors to the project, including:
[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars [wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars
[Discord server]: https://discord.gg/jJxZnrGPWN [Discord server]: https://discord.gg/jJxZnrGPWN
[Wayland]: https://wayland.freedesktop.org/ [Wayland]: https://wayland.freedesktop.org/
[#dwl-official:matrix.org]: https://matrix.to/#/#dwl-official:matrix.org
+7 -7
View File
@@ -1,4 +1,4 @@
_VERSION = 0.8-dev _VERSION = 0.9-dev
VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)` VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)`
PKG_CONFIG = pkg-config PKG_CONFIG = pkg-config
@@ -8,8 +8,8 @@ PREFIX = /usr/local
MANDIR = $(PREFIX)/share/man MANDIR = $(PREFIX)/share/man
DATADIR = $(PREFIX)/share DATADIR = $(PREFIX)/share
WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19` WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.20`
WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19` WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.20`
# Allow using an alternative wlroots installation # Allow using an alternative wlroots installation
# This has to have all the includes required by wlroots, e.g: # This has to have all the includes required by wlroots, e.g:
@@ -17,12 +17,12 @@ WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19`
#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \ #WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
# -I$(PWD)/wlroots/include # -I$(PWD)/wlroots/include
# Set -rpath to avoid using the wrong library. # Set -rpath to avoid using the wrong library.
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/build -L$(PWD)/wlroots/build -lwlroots-0.19 #WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/build -L$(PWD)/wlroots/build -lwlroots-0.20
# Assuming you ran "meson setup --prefix ${PWD}/0.19 build && ninja -C build install" # Assuming you ran "meson setup --prefix ${PWD}/0.20 build && ninja -C build install"
#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \ #WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
# -I$(PWD)/wlroots/0.19/include/wlroots-0.19 # -I$(PWD)/wlroots/0.20/include/wlroots-0.20
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.19/lib64 -L$(PWD)/wlroots/0.19/lib64 -lwlroots-0.19 #WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.20/lib64 -L$(PWD)/wlroots/0.20/lib64 -lwlroots-0.20
XWAYLAND = XWAYLAND =
XLIBS = XLIBS =
+23 -18
View File
@@ -24,6 +24,9 @@
#include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_data_device.h>
#include <wlr/types/wlr_drm.h> #include <wlr/types/wlr_drm.h>
#include <wlr/types/wlr_export_dmabuf_v1.h> #include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_ext_data_control_v1.h>
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
#include <wlr/types/wlr_fractional_scale_v1.h> #include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h> #include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle_inhibit_v1.h> #include <wlr/types/wlr_idle_inhibit_v1.h>
@@ -68,6 +71,7 @@
#include <xcb/xcb_icccm.h> #include <xcb/xcb_icccm.h>
#endif #endif
#include "xdg-shell-protocol.h"
#include "util.h" #include "util.h"
/* macros */ /* macros */
@@ -585,7 +589,7 @@ arrangelayers(Monitor *m)
arrange(m); arrange(m);
} }
/* Arrange non-exlusive surfaces from top->bottom */ /* Arrange non-exclusive surfaces from top->bottom */
for (i = 3; i >= 0; i--) for (i = 3; i >= 0; i--)
arrangelayer(m, &m->layers[i], &usable_area, 0); arrangelayer(m, &m->layers[i], &usable_area, 0);
@@ -1241,6 +1245,7 @@ void
destroydecoration(struct wl_listener *listener, void *data) destroydecoration(struct wl_listener *listener, void *data)
{ {
Client *c = wl_container_of(listener, c, destroy_decoration); Client *c = wl_container_of(listener, c, destroy_decoration);
c->decoration = NULL;
wl_list_remove(&c->destroy_decoration.link); wl_list_remove(&c->destroy_decoration.link);
wl_list_remove(&c->set_decoration_mode.link); wl_list_remove(&c->set_decoration_mode.link);
@@ -1346,6 +1351,10 @@ destroynotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->map.link); wl_list_remove(&c->map.link);
wl_list_remove(&c->unmap.link); wl_list_remove(&c->unmap.link);
wl_list_remove(&c->maximize.link); wl_list_remove(&c->maximize.link);
if (c->decoration) {
wl_list_remove(&c->set_decoration_mode.link);
wl_list_remove(&c->destroy_decoration.link);
}
} }
free(c); free(c);
} }
@@ -2133,7 +2142,7 @@ powermgrsetmode(struct wl_listener *listener, void *data)
if (!m) if (!m)
return; return;
m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the ouput */ m->gamma_lut_changed = 1; /* Reapply gamma LUT when re-enabling the output */
wlr_output_state_set_enabled(&state, event->mode); wlr_output_state_set_enabled(&state, event->mode);
wlr_output_commit_state(m->wlr_output, &state); wlr_output_commit_state(m->wlr_output, &state);
@@ -2153,24 +2162,15 @@ rendermon(struct wl_listener *listener, void *data)
/* This function is called every time an output is ready to display a frame, /* This function is called every time an output is ready to display a frame,
* generally at the output's refresh rate (e.g. 60Hz). */ * generally at the output's refresh rate (e.g. 60Hz). */
Monitor *m = wl_container_of(listener, m, frame); Monitor *m = wl_container_of(listener, m, frame);
Client *c;
struct wlr_output_state pending = {0};
struct timespec now; struct timespec now;
/* Render if no XDG clients have an outstanding resize and are visible on if (!wlr_scene_output_needs_frame(m->scene_output)) {
* this monitor. */ return;
wl_list_for_each(c, &clients, link) {
if (c->resize && !c->isfloating && client_is_rendered_on_mon(c, m) && !client_is_stopped(c))
goto skip;
} }
wlr_scene_output_commit(m->scene_output, NULL); wlr_scene_output_commit(m->scene_output, NULL);
skip:
/* Let clients know a frame has been rendered */
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
wlr_scene_output_send_frame_done(m->scene_output, &now); wlr_scene_output_send_frame_done(m->scene_output, &now);
wlr_output_state_finish(&pending);
} }
void void
@@ -2455,7 +2455,7 @@ setup(void)
wlr_log_init(log_level, NULL); wlr_log_init(log_level, NULL);
/* The Wayland display is managed by libwayland. It handles accepting /* The Wayland display is managed by libwayland. It handles accepting
* clients from the Unix socket, manging Wayland globals, and so on. */ * clients from the Unix socket, managing Wayland globals, and so on. */
dpy = wl_display_create(); dpy = wl_display_create();
event_loop = wl_display_get_event_loop(dpy); event_loop = wl_display_get_event_loop(dpy);
@@ -2517,7 +2517,10 @@ setup(void)
wlr_data_device_manager_create(dpy); wlr_data_device_manager_create(dpy);
wlr_export_dmabuf_manager_v1_create(dpy); wlr_export_dmabuf_manager_v1_create(dpy);
wlr_screencopy_manager_v1_create(dpy); wlr_screencopy_manager_v1_create(dpy);
wlr_ext_image_copy_capture_manager_v1_create(dpy, 1);
wlr_ext_output_image_capture_source_manager_v1_create(dpy, 1);
wlr_data_control_manager_v1_create(dpy); wlr_data_control_manager_v1_create(dpy);
wlr_ext_data_control_manager_v1_create(dpy, 1);
wlr_primary_selection_v1_device_manager_create(dpy); wlr_primary_selection_v1_device_manager_create(dpy);
wlr_viewporter_create(dpy); wlr_viewporter_create(dpy);
wlr_single_pixel_buffer_manager_v1_create(dpy); wlr_single_pixel_buffer_manager_v1_create(dpy);
@@ -2832,6 +2835,7 @@ unmapnotify(struct wl_listener *listener, void *data)
} }
wlr_scene_node_destroy(&c->scene->node); wlr_scene_node_destroy(&c->scene->node);
client_surface(c)->data = NULL;
printstatus(); printstatus();
motionnotify(0, NULL, 0, 0, 0, 0); motionnotify(0, NULL, 0, 0, 0, 0);
} }
@@ -2854,10 +2858,13 @@ updatemons(struct wl_listener *listener, void *data)
/* First remove from the layout the disabled monitors */ /* First remove from the layout the disabled monitors */
wl_list_for_each(m, &mons, link) { wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled || m->asleep) if (m->wlr_output->enabled)
continue; continue;
config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output); config_head = wlr_output_configuration_head_v1_create(config, m->wlr_output);
config_head->state.enabled = 0; config_head->state.enabled = 0;
if (m->asleep)
continue;
/* Remove this output from the layout to avoid cursor enter inside it */ /* Remove this output from the layout to avoid cursor enter inside it */
wlr_output_layout_remove(output_layout, m->wlr_output); wlr_output_layout_remove(output_layout, m->wlr_output);
closemon(m); closemon(m);
@@ -3176,9 +3183,7 @@ xwaylandready(struct wl_listener *listener, void *data)
/* Set the default XWayland cursor to match the rest of dwl. */ /* Set the default XWayland cursor to match the rest of dwl. */
if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1))) if ((xcursor = wlr_xcursor_manager_get_xcursor(cursor_mgr, "default", 1)))
wlr_xwayland_set_cursor(xwayland, wlr_xwayland_set_cursor(xwayland, wlr_xcursor_image_get_buffer(xcursor->images[0]),
xcursor->images[0]->buffer, xcursor->images[0]->width * 4,
xcursor->images[0]->width, xcursor->images[0]->height,
xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);
} }
#endif #endif