Compare commits

..

18 Commits

Author SHA1 Message Date
Andrea Chiavazza
7af0b45334 fix some key binding events being passed to clients 2026-01-16 13:23:16 +00:00
fauxmight
6cd26568d5 Update README.md
Document Java nonreparenting WM issue

Closes #722
2025-09-29 05:56:22 +02:00
fauxmight
ed2e1efda8 Update README.md
Make "dwl" references in README.md links to dwm main site.

Closes #1168
2025-09-29 05:39:54 +02:00
A Frederick Christensen
ab4cb6e283
Revert "add support for ext-image-copy-capture-v1 and ext-image-capture-source-v1 (wlroots!4545)"
This reverts commit b28674e0ca4a9ecc92cb0607498e3db2df3d4c00.

This PR is not yet finalized. (Screen freezes).
2025-08-04 16:27:34 -05:00
Leonardo Hernández Hernández
b28674e0ca add support for ext-image-copy-capture-v1 and ext-image-capture-source-v1 (wlroots!4545)
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4545
2025-08-04 23:08:53 +02:00
A Frederick Christensen
15bfffd87a
fullscreen_bg defaults to black
Per conversation at PR #1147 with @kilpilainen
2025-06-18 23:41:14 -05:00
fauxmight
90b8371707 Update README.md
Correct description of default background color
2025-06-18 14:52:15 +02:00
Guido Cella
ea263a0ed5 float sub-windows matching a rule
Currently when a rule that doesn't make windows floating matches, even
sub-windows of float type get tiled rather than just the main window.
This is inconsistent with dwm and other compositors. Fix this by making
these windows floating after applying rules.

Fixes #1142.
2025-06-14 22:27:25 +02:00
Leonardo Hernández Hernández
67ff29eb95
document status output 2025-06-09 13:55:38 -06:00
Leonardo Hernández Hernández
661e1ee38c
Use a subsection for mouse commands
also add missing ".El", s/Toggles/Toggle/ in second command and add newlines
after a full stop
2025-06-09 13:55:38 -06:00
Leonardo Hernández Hernández
9dbce43a69
document mouse button actions
[sevz: commit message is mine. The content was written by scottro11 and shared
in https://codeberg.org/dwl/dwl/issues/697]

Closes: https://codeberg.org/dwl/dwl/issues/697
2025-06-09 13:55:38 -06:00
Leonardo Hernández Hernández
59c99308b0
drop CAVEATS section from the man page
Since 71f11e6cf63289d51f152469a0da81a85fe2608c it is not longer the case
2025-06-09 13:55:37 -06:00
kilpilainen
02f8744a48
Use all-scroll instead of fleur xcursor shape for window dragging
When there are no xcursor themes available, Wayland uses its own built-in shapes [1].
Wayland (and thus to extend wlroots) is based on the XDG's cursor spec [2],
which itself is based on CSS' [3][4], neither of which define `fleur` shape. So dwl,
without any external themes, falls back to `default` shape when dragging a window.
There is `all-scroll` shape that is being symlinked to (or vice versa) by `move`,
`dnd-move`, `grabbed` and `fleur` shapes by various themes.

Since `all-scroll` is being symlinked to anyway, and has been part of all relevant
specs as the shape for this use case for a very long time now, use it instead.

[1] https://gitlab.freedesktop.org/wayland/wayland/-/blob/main/cursor/cursor-data.h#L559
[2] https://www.freedesktop.org/wiki/Specifications/cursor-spec
[3] https://drafts.csswg.org/css-ui/#cursor
[4] https://developer.mozilla.org/en-US/docs/Web/CSS/cursor
2025-06-09 13:39:40 -06:00
Nikita Ivanov
d1880b4422
Fix crash disabling monitor with locked surface 2025-06-09 13:33:02 -06:00
A Frederick Christensen
78e75a83a4
Revert "Update config.mk"
This reverts commit 7d2415bfe854cccc2bcf2709fecc1eaacddbe903.

Will stick with wlroots 0.19 for now.
2025-06-09 00:18:17 -05:00
mcsimw
7d2415bfe8 Update config.mk
compiles and works fine on wlroots-0.20
2025-06-09 06:54:02 +02:00
A Frederick Christensen
de57f6c315
Cleanup comments 2025-06-07 16:17:30 -05:00
fauxmight
faa56cc9b9 Update README.md 2025-04-24 04:28:44 +00:00
6 changed files with 173 additions and 57 deletions

View File

@ -4,9 +4,9 @@ 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
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,
primarily in terms of functionality, and secondarily in terms of
philosophy. Like dwm, dwl is:
philosophy. Like [dwm], dwl is:
- Easy to understand, hack on, and extend with patches
- One C source file (or a very small number) configurable via `config.h`
@ -15,10 +15,11 @@ philosophy. Like dwm, dwl is:
## Getting Started:
### Latest semi-stable [release]
This is probably where you want to start. This builds against the dependent
packages' versions currently shipping in major distributions. If your
distribution's wlroots version is older, use an earlier dwl [release] or [0.x
branch].
This is probably where you want to start. This builds against the [wlroots]
versions currently shipping in major distributions. If your
distribution's `wlroots` version is older, use an earlier dwl [release].
The `wlroots` version against which a given `dwl` release builds is specified
with each release on the [release] page
### Development branch [main]
Active development progresses on the `main` branch. The `main` branch is built
@ -54,11 +55,11 @@ To enable XWayland, you should uncomment its flags in `config.mk`.
## Configuration
All configuration is done by editing `config.h` and recompiling, in the same
manner as dwm. There is no way to separately restart the window manager in
manner as [dwm]. There is no way to separately restart the window manager in
Wayland without restarting the entire display server, so any changes will take
effect the next time dwl is executed.
As in the dwm community, we encourage users to share patches they have
As in the [dwm] community, we encourage users to share patches they have
created. Check out the [dwl-patches] repository!
## Running dwl
@ -74,7 +75,7 @@ seatd daemon.
When dwl is run with no arguments, it will launch the server and begin handling
any shortcuts configured in `config.h`. There is no status bar or other
decoration initially; these are instead clients that can be run within the
Wayland session. Do note that the default background color is black. This can be
Wayland session. Do note that the default background color is grey. This can be
modified in `config.h`.
If you would like to run a script or command automatically at startup, you can
@ -102,7 +103,7 @@ automatically, you will need to configure it prior to launching `dwl`, e.g.:
Information about selected layouts, current window title, app-id, and
selected/occupied/urgent tags is written to the stdin of the `-s` command (see
the `printstatus()` function for details). This information can be used to
the `STATUS INFORMATION` section in `_dwl_(1)`). This information can be used to
populate an external status bar with a script that parses the
information. Failing to read this information will cause dwl to block, so if you
do want to run a startup command that does not consume the status information,
@ -117,17 +118,26 @@ script with the line
To get a list of status bars that work with dwl consult our [wiki].
### (Known) Java nonreparenting WM issue
Certain IDEs don't display correctly unless an environmental variable for Java AWT
indicates that the WM is nonreparenting.
For some Java AWT-based IDEs, such as Xilinx Vivado and Microchip MPLAB X, the
following environment variable needs to be set before running the IDE or dwl:
export _JAVA_AWT_WM_NONREPARENTING=1
## Replacements for X applications
You can find a [list of useful resources on our wiki].
## Background
dwl is not meant to provide every feature under the sun. Instead, like dwm, it
dwl is not meant to provide every feature under the sun. Instead, like [dwm], it
sticks to features which are necessary, simple, and straightforward to implement
given the base on which it is built. Implemented default features are:
- Any features provided by dwm/Xlib: simple window borders, tags, keybindings,
- Any features provided by [dwm]/Xlib: simple window borders, tags, keybindings,
client rules, mouse move/resize. Providing a built-in status bar is an
exception to this goal, to avoid dependencies on font rendering and/or drawing
libraries when an external bar could work well.
@ -144,10 +154,10 @@ given the base on which it is built. Implemented default features are:
- Layer shell popups (used by Waybar)
- Damage tracking provided by scenegraph API
Given the Wayland architecture, dwl has to implement features from dwm **and**
Given the Wayland architecture, dwl has to implement features from [dwm] **and**
the xorg-server. Because of this, it is impossible to maintain the original
project goal of 2000 SLOC and have a reasonably complete compositor with
features comparable to dwm. However, this does not mean that the code will grow
features comparable to [dwm]. However, this does not mean that the code will grow
indiscriminately. We will try to keep the code as small as possible.
Features under consideration (possibly as patches) are:
@ -171,7 +181,7 @@ developers. This was made possible in many cases by looking at how sway
accomplished something, then trying to do the same in as suckless a way as
possible.
Many thanks to suckless.org and the dwm developers and community for the
Many thanks to suckless.org and the [dwm] developers and community for the
inspiration, and to the various contributors to the project, including:
- **Devin J. Pohly for creating and nurturing the fledgling project**
@ -181,6 +191,8 @@ inspiration, and to the various contributors to the project, including:
- Stivvo for output management and fullscreen support, and patch maintenance
[wlroots]: https://gitlab.freedesktop.org/wlroots
[dwm]: https://dwm.suckless.org/
[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User
[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl
[0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1

View File

@ -264,8 +264,8 @@ client_is_stopped(Client *c)
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
/* This process is not our child process, while is very unluckely that
* it is stopped, in order to do not skip frames assume that it is. */
/* This process is not our child process, while is very unlikely that
* it is stopped, in order to do not skip frames, assume that it is. */
if (errno == ECHILD)
return 1;
} else if (in.si_pid) {

View File

@ -12,7 +12,7 @@ static const float bordercolor[] = COLOR(0x444444ff);
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 const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
/* tagging - TAGCOUNT must be no greater than 31 */
#define TAGCOUNT (9)

View File

@ -11,7 +11,7 @@ DATADIR = $(PREFIX)/share
WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19`
WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19`
# Allow using an alternative wlroots installations
# Allow using an alternative wlroots installation
# This has to have all the includes required by wlroots, e.g:
# Assuming wlroots git repo is "${PWD}/wlroots" and you only ran "meson setup build && ninja -C build"
#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \

124
dwl.1
View File

@ -37,7 +37,7 @@ starts a shell process running
when starting.
When stopping, it sends
.Dv SIGTERM
to the child process and waits for it to exit.
to the child process group and waits for it to exit.
.Pp
Users are encouraged to customize
.Nm
@ -55,10 +55,10 @@ Move window to a single tag.
Toggle tag for window.
.It Mod-p
Spawn
.Nm wmenu-run .
.Xr wmenu-run 1 .
.It Mod-Shift-Return
Spawn
.Nm foot .
.Xr foot 1 .
.It Mod-[jk]
Move focus down/up the stack.
.It Mod-[id]
@ -100,6 +100,114 @@ Quit
.Nm .
.El
These might differ depending on your keyboard layout.
.Ss Mouse commands
.Bl -tag -width 20n -offset indent -compact
.It Mod-Button1
Move focused window while dragging.
Tiled windows will be toggled to the floating state.
.It Mod-Button2
Toggle focused window between floating and tiled state.
.It Mod-Button3
Resize focused window while dragging.
Tiled windows will be toggled to the floating state.
.El
.Sh STATUS INFORMATION
.Nm
writes its status information to standard output.
If the
.Fl s
option is given, the status information is written to the standard input of the
child process instead.
.Pp
Said information has the following format:
.Bd -ragged -offset indent
.Ar <monitor>
.Ar <component>
.Ar <data>
.Ed
.Pp
.Bl -tag -width 11n -offset 0 -compact
.It Ar <monitor>
is the name given to the output.
.It Ar <component>
is one of (in order)
.Em title ,
.Em appid ,
.Em fullscreen ,
.Em floating ,
.Em selmon ,
.Em tags ,
.Em layout .
.It Ar <data>
changes depending on
.Ar <component> .
.Bl -tag -width 10n -compact
.It Em title
The title of the focused window on
.Ar <monitor>
or nothing if there is no focused window.
.It Em appid
The app_id of the focused window on
.Ar <monitor>
or nothing if there is no focused window.
.It Em fullscreen
Prints 1 if the focused window on
.Ar <monitor>
is in fullscreen state, otherwise prints 0. If there is no focused
window it prints nothing.
.It Em floating
Prints 1 if the focused window on
.Ar <monitor>
is in floating state, otherwise prints 0. If there is no focused
window it prints nothing.
.It Em selmon
Prints 1 if
.Ar <monitor>
is the selected monitor, otherwise prints 0.
.It Em tags
Prints four bitmasks in the following order:
.Bl -bullet -width 2n -compact
.It
Occupied tags of
.Ar <monitor> .
.It
Selected tags of
.Ar <monitor> .
.It
Tags of the focused window on
.Ar <monitor> .
.It
Tags where a window on
.Ar <monitor>
requested activation or has urgency hints.
.El
The bitmasks are 32-bit unsigned decimal integers.
.It Em layout
Prints the symbol of the current layout.
.El
.El
.Ss Examples
When there is a selected window:
.Bd -literal -offset indent
HDMI\-A\-1 title \(ti/source/repos/dwl > man \-l dwl.1
HDMI\-A\-1 appid footclient
HDMI\-A\-1 fullscreen 0
HDMI\-A\-1 floating 0
HDMI\-A\-1 selmon 1
HDMI\-A\-1 tags 271 4 4 0
HDMI\-A\-1 layout [T]
.Ed
.Pp
When there is no selected window:
.Bd -literal -offset indent
HDMI\-A\-1 title
HDMI\-A\-1 appid
HDMI\-A\-1 fullscreen
HDMI\-A\-1 floating
HDMI\-A\-1 selmon 1
HDMI\-A\-1 tags 271 512 0 0
HDMI\-A\-1 layout [T]
.Ed
.Sh ENVIRONMENT
These environment variables are used by
.Nm :
@ -142,17 +250,9 @@ Start
with s6 in the background:
.Dl dwl \-s \(aqs6\-svscan <&\-\(aq
.Sh SEE ALSO
.Xr dwm 1 ,
.Xr foot 1 ,
.Xr wmenu 1 ,
.Xr dwm 1 ,
.Xr xkeyboard-config 7
.Sh CAVEATS
The child process's standard input is connected with a pipe to
.Nm .
If the child process neither reads from the pipe nor closes its
standard input,
.Nm
will freeze after a while due to it blocking when writing to the full
pipe buffer.
.Sh BUGS
All of them.

56
dwl.c
View File

@ -484,7 +484,6 @@ applyrules(Client *c)
const Rule *r;
Monitor *mon = selmon, *m;
c->isfloating = client_is_float_type(c);
appid = client_get_appid(c);
title = client_get_title(c);
@ -500,6 +499,8 @@ applyrules(Client *c)
}
}
}
c->isfloating |= client_is_float_type(c);
setmon(c, mon, newtags);
}
@ -610,8 +611,8 @@ 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 whell for mousebindings, it can be implemented
* checking the event's orientation and the delta of the event */
/* TODO: allow usage of scroll wheel for mousebindings, it can be implemented
* by 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,
@ -713,8 +714,8 @@ cleanup(void)
destroykeyboardgroup(&kb_group->destroy, NULL);
/* 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 */
/* If it's not destroyed manually, it will cause a use-after-free of wlr_seat.
* Destroy it until it's fixed on the wlroots side */
wlr_backend_destroy(backend);
wl_display_destroy(dpy);
@ -740,6 +741,8 @@ cleanupmon(struct wl_listener *listener, void *data)
wl_list_remove(&m->frame.link);
wl_list_remove(&m->link);
wl_list_remove(&m->request_state.link);
if (m->lock_surface)
destroylocksurface(&m->destroy_lock_surface, NULL);
m->wlr_output->data = NULL;
wlr_output_layout_remove(output_layout, m->wlr_output);
wlr_scene_output_destroy(m->scene_output);
@ -859,7 +862,7 @@ commitnotify(struct wl_listener *listener, void *data)
/*
* Get the monitor this client will be rendered on
* Note that if the user set a rule in which the client is placed on
* a different monitor based on its title this will likely select
* a different monitor based on its title, this will likely select
* a wrong monitor.
*/
applyrules(c);
@ -1213,7 +1216,7 @@ cursorconstrain(struct wlr_pointer_constraint_v1 *constraint)
void
cursorframe(struct wl_listener *listener, void *data)
{
/* This event is forwarded by the cursor when a pointer emits an frame
/* This event is forwarded by the cursor when a pointer emits a frame
* event. Frame events are sent after regular pointer events to group
* multiple events together. For instance, two axis events may happen at the
* same time, in which case a frame event won't be sent in between. */
@ -1509,7 +1512,7 @@ focusstack(const Arg *arg)
focusclient(c, 1);
}
/* We probably should change the name of this, it sounds like
/* We probably should change the name of this: it sounds like it
* will focus the topmost client of this mon, when actually will
* only return that client */
Client *
@ -1793,8 +1796,8 @@ mapnotify(struct wl_listener *listener, void *data)
/* Set initial monitor, tags, floating status, and focus:
* we always consider floating, clients that have parent and thus
* we set the same tags and monitor than its parent, if not
* try to apply rules for them */
* we set the same tags and monitor as its parent.
* If there is no parent, apply rules */
if ((p = client_get_parent(c))) {
c->isfloating = 1;
setmon(c, p->mon, p->tags);
@ -1854,8 +1857,7 @@ motionabsolute(struct wl_listener *listener, void *data)
* motion event, from 0..1 on each axis. This happens, for example, when
* wlroots is running under a Wayland window rather than KMS+DRM, and you
* move the mouse over the window. You could enter the window from any edge,
* so we have to warp the mouse there. There is also some hardware which
* emits these events. */
* so we have to warp the mouse there. Also, some hardware emits these events. */
struct wlr_pointer_motion_absolute_event *event = data;
double lx, ly, dx, dy;
@ -1977,7 +1979,7 @@ moveresize(const Arg *arg)
case CurMove:
grabcx = (int)round(cursor->x) - grabc->geom.x;
grabcy = (int)round(cursor->y) - grabc->geom.y;
wlr_cursor_set_xcursor(cursor, cursor_mgr, "fleur");
wlr_cursor_set_xcursor(cursor, cursor_mgr, "all-scroll");
break;
case CurResize:
/* Doesn't work for X11 output - the next absolute motion event
@ -2040,9 +2042,9 @@ apply_or_test:
ok &= test ? wlr_output_test_state(wlr_output, &state)
: wlr_output_commit_state(wlr_output, &state);
/* Don't move monitors if position wouldn't change, this to avoid
* wlroots marking the output as manually configured.
* wlr_output_layout_add does not like disabled outputs */
/* Don't move monitors if position wouldn't change. This avoids
* wlroots marking the output as manually configured.
* wlr_output_layout_add does not like disabled outputs */
if (!test && wlr_output->enabled && (m->m.x != config_head->state.x || m->m.y != config_head->state.y))
wlr_output_layout_add(output_layout, wlr_output,
config_head->state.x, config_head->state.y);
@ -2279,8 +2281,10 @@ run(char *startup_cmd)
close(piperw[0]);
}
/* Mark stdout as non-blocking to avoid people who does not close stdin
* nor consumes it in their startup script getting dwl frozen */
/* Mark stdout as non-blocking to avoid the startup script
* causing dwl to freeze when a user neither closes stdin
* nor consumes standard input in his startup script */
if (fd_set_nonblock(STDOUT_FILENO) < 0)
close(STDOUT_FILENO);
@ -2291,7 +2295,7 @@ run(char *startup_cmd)
selmon = xytomon(cursor->x, cursor->y);
/* 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
* instead of (0, 0) and then jumping. Still may not be fully
* initialized, as the image/coordinates are not transformed for the
* monitor when displayed here */
wlr_cursor_warp_closest(cursor, NULL, cursor->x, cursor->y);
@ -2314,7 +2318,7 @@ setcursor(struct wl_listener *listener, void *data)
* event, which will result in the client requesting set the cursor surface */
if (cursor_mode != CurNormal && cursor_mode != CurPressed)
return;
/* This can be sent by any client, so we check to make sure this one is
/* 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 surface as the cursor image. It will set the
* hardware cursor on the output that it's currently on and continue to
@ -2330,7 +2334,7 @@ setcursorshape(struct wl_listener *listener, void *data)
struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
if (cursor_mode != CurNormal && cursor_mode != CurPressed)
return;
/* This can be sent by any client, so we check to make sure this one is
/* 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)
@ -2433,7 +2437,7 @@ setpsel(struct wl_listener *listener, void *data)
{
/* This event is raised by the seat when a client wants to set the selection,
* usually when the user copies something. wlroots allows compositors to
* ignore such requests if they so choose, but in dwl we always honor
* ignore such requests if they so choose, but in dwl we always honor them
*/
struct wlr_seat_request_set_primary_selection_event *event = data;
wlr_seat_set_primary_selection(seat, event->source, event->serial);
@ -2444,7 +2448,7 @@ setsel(struct wl_listener *listener, void *data)
{
/* This event is raised by the seat when a client wants to set the selection,
* usually when the user copies something. wlroots allows compositors to
* ignore such requests if they so choose, but in dwl we always honor
* ignore such requests if they so choose, but in dwl we always honor them
*/
struct wlr_seat_request_set_selection_event *event = data;
wlr_seat_set_selection(seat, event->source, event->serial);
@ -2491,9 +2495,9 @@ setup(void)
wl_signal_add(&drw->events.lost, &gpu_reset);
/* Create shm, drm and linux_dmabuf interfaces by ourselves.
* The simplest way is call:
* The simplest way is to call:
* wlr_renderer_init_wl_display(drw);
* but we need to create manually the linux_dmabuf interface to integrate it
* but we need to create the linux_dmabuf interface manually to integrate it
* with wlr_scene. */
wlr_renderer_init_wl_shm(drw, dpy);
@ -2542,7 +2546,7 @@ setup(void)
power_mgr = wlr_output_power_manager_v1_create(dpy);
wl_signal_add(&power_mgr->events.set_mode, &output_power_mgr_set_mode);
/* Creates an output layout, which a wlroots utility for working with an
/* Creates an output layout, which is a wlroots utility for working with an
* arrangement of screens in a physical layout. */
output_layout = wlr_output_layout_create(dpy);
wl_signal_add(&output_layout->events.change, &layout_change);