Compare commits

...

75 commits

Author SHA1 Message Date
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 b28674e0ca.

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 71f11e6cf6 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 7d2415bfe8.

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
DreamMaoMao
4456f4536a fix: shouldn't configure uninitialized layer_surface 2025-03-13 20:36:18 +00:00
DreamMaoMao
e0f531d508 fix: crash when open some x11 app 2025-03-12 16:27:47 +08:00
korei999
aa69ed81b5
allocate with LISTEN_STATIC
Fixes: https://codeberg.org/dwl/dwl/issues/723
Supersedes: https://codeberg.org/dwl/dwl/pulls/724
2025-02-01 22:34:58 -06:00
Leonardo Hernández Hernández
d1c2f43498
rename some listeners
To keep consistency with the rest of listeners
2025-01-19 17:27:16 -06:00
Leonardo Hernández Hernández
da13a95683
destroy keyboard group after unlinking listeners
Last commit addressing the issue mentioned in
0925fe956a
2025-01-19 17:26:28 -06:00
Leonardo Hernández Hernández
9a9f67db1c
unlink global listeners on destroy
Continuation of 0925fe956a
2025-01-19 17:26:02 -06:00
Leonardo Hernández Hernández
4e7e2999d4
Partially revert "Line saver: LISTEN_STATIC macro"
This reverts commit 33bcd2e4ca.

We keep LISTEN_STATIC for three instances where we use it. We use
simple listeners for the rest of signals.

This is the continuation of 0925fe956a
2025-01-19 17:24:54 -06:00
Leonardo Hernández Hernández
0925fe956a
unlink some destroy listeners
Recently wlroots was updated to assert that signals do not have listeners
attached on destroy.

This is just a preliminar work to fix dwl. At the moment dwl will trigger the
assertions at exit.

References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4918
2025-01-17 21:03:28 -06:00
Leonardo Hernández Hernández
26504f9a6f
do not call waitid(2) in the signal handler when Xwayland is enabled
waitid(2) is not a async-signal-safe function acording to signal-safety(7)

We can stop doing this because wlroots!4926 allows compositors to install
signal handlers for SIGCHLD.

References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4926
2025-01-14 12:23:55 -06:00
Leonardo Hernández Hernández
6f34a6d3a6
use wlr_xwayland_surface_has_window_type() (wlroots!4553)
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4553
2025-01-14 12:23:55 -06:00
Leonardo Hernández Hernández
30f5063474
manually call updatemons in powermgrsetmode()
Fixes: https://codeberg.org/dwl/dwl/issues/713
2024-12-10 22:49:09 -06:00
Leonardo Hernández Hernández
1d08ade132
remove binary before copying to destination
Since Linux 6.11 is possible overwrite a running executable, possibly making it
crash.

Thanks to: movq42rax
Fixes: https://codeberg.org/dwl/dwl/issues/709
References: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2a010c412853
References: https://lore.kernel.org/stable/CACKH++YAtEMYu2nTLUyfmxZoGO37fqogKMDkBpddmNaz5HE6ng@mail.gmail.com/T/#u
2024-11-15 00:26:51 -06:00
Leonardo Hernández Hernández
84245764e2
specify version for presentation-time (wlroots!4858)
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4858
2024-10-27 20:37:15 -06:00
Leonardo Hernández Hernández
6ca87210d4
check if the backend supports explicit sync before creating the object (wlroots!4848)
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4848
2024-10-27 20:37:15 -06:00
Leonardo Hernández Hernández
002c7d2204
tell xwayland clients they're maximized
like we do to xdg clients when tiled state is not supported.
2024-09-21 21:00:47 -06:00
Guido Cella
8206cc8889 fix a use after free
This line makes dwl crash after closing mpv with the switchtotag patch.
2024-09-12 04:33:19 +00:00
Guido Cella
54f207839f reorder config.mk variables
By placing the default WLR_INCS and WLR_LIBS before the ones for an
alternative wlroots, they don't need to be commented to enable the
alternative ones.
2024-09-08 20:51:41 +02:00
Leonardo Hernández Hernández
9c05b9622c
fix style for client_set_scale() 2024-08-30 22:29:08 -06:00
choc
d34be5d545
remove unused link member from KeyboardGroup
unnecessary since grouping Keyboard wl_list to use wlr_keyboard_group in 023efce

ΔSLOC: -1
2024-08-27 23:12:00 -06:00
Leonardo Hernández Hernández
c49312f084
disable scene node unless it is unmanaged 2024-08-27 23:09:46 -06:00
Leonardo Hernández Hernández
f899060965
send a configure to unmanaged clients when mapping 2024-08-27 23:09:46 -06:00
Leonardo Hernández Hernández
cc72df11d6
configure xdg_toplevels after configuring it's decoration 2024-08-27 23:09:46 -06:00
Leonardo Hernández Hernández
0312720ae8
remove a space before parenthesis in function calls 2024-08-27 23:09:46 -06:00
Leonardo Hernández Hernández
6de87121e2
destroy popups when we can't get it's parent or they don't have monitor 2024-08-27 23:09:46 -06:00
Leonardo Hernández Hernández
bbc00d88a4
remove a redundant check
resize() now does the same check
2024-08-27 23:09:46 -06:00
Leonardo Hernández Hernández
54b546121b
avoid using a else block 2024-08-27 23:09:46 -06:00
Leonardo Hernández Hernández
43016bdad8
introduce client_set_scale() 2024-08-27 23:09:41 -06:00
Leonardo Hernández Hernández
b616476c85
remove unnecessary LayerShell.geom
We only used geom.x and geom.y. We can access those variables directly from the
scene node.
2024-08-27 23:09:08 -06:00
Leonardo Hernández Hernández
d4ad37354e
update comment about first fields of Client and LayerSurface order 2024-08-27 23:09:08 -06:00
Leonardo Hernández Hernández
5db05e82bd
fix style in configurex11() 2024-08-27 23:09:08 -06:00
Leonardo Hernández Hernández
8ec5e52e06
fix crash when a client is created while all outputs are disabled 2024-08-26 21:56:10 -06:00
Leonardo Hernández Hernández
c5275ca571
state that the Discord server is community-maintained
Previously I regularly checked the server but it has been quite a long time
since I was able to do it.
2024-08-18 19:24:04 -06:00
A Frederick Christensen
2c0b889f86
Update CHANGELOG.md 2024-08-18 19:23:56 -06:00
Leonardo Hernández Hernández
554754c9a2
chase xdg_surface geometry changes (wlroots!4788)
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4788
2024-08-14 13:37:14 -06:00
Leonardo Hernández Hernández
0caa658276
use wlr_scene_set_gamma_control_manager_v1() (wlroots!4192)
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4192
2024-08-14 12:21:27 -06:00
Leonardo Hernández Hernández
07aeef1f7e
guarantee client_get_{title,appid} never return NULL
ΔSLOC: -6
2024-08-14 12:19:37 -06:00
Leonardo Hernández Hernández
e454f7ae81
allow the use of non-system wlroots library
References: https://codeberg.org/dwl/dwl/issues/646#issuecomment-2032644
2024-08-14 12:00:52 -06:00
Leonardo Hernández Hernández
334bbe6f0f
fix potential crash in configurex11()
We can't call resize() on unmanaged clients because they don't have borders and
resize() requires them.

Fixes: 94f4ead7da
2024-08-10 10:47:48 -06:00
Leonardo Hernández Hernández
1b805ddd38
account border width in configurex11()
Fixes: 13925eb1da
2024-08-08 14:46:25 -06:00
Leonardo Hernández Hernández
94f4ead7da
actually move unmanaged clients in configurex11()
only calling wlr_xwayland_surface_configure() may be not enough because we also
need to move the scene node in order to make effective the configure
2024-08-08 14:46:08 -06:00
Leonardo Hernández Hernández
bb21ecda30
improve checking in configurex11()
this avoids a client resizing itself when the user is interactively resizing
the client
2024-08-08 14:33:03 -06:00
Leonardo Hernández Hernández
b25717c939
drop a useless check in configurex11() 2024-08-08 14:19:39 -06:00
Leonardo Hernández Hernández
a4fa954616
do not restack xwayland surfaces (wlroots!4756)
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4756
2024-08-07 16:58:16 -06:00
Leonardo Hernández Hernández
35951a8d7e
add support for linux-drm-syncobj-v1 (wlroots!4715)
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4262
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4715
2024-08-06 12:20:25 -06:00
Leonardo Hernández Hernández
a634e3f527
fix crash when a virtual pointer is destroyed
Fixes: https://codeberg.org/dwl/dwl/issues/680
2024-08-06 12:01:22 -06:00
Leonardo Hernández Hernández
d136dadf45
-pedantic -> -Wpedantic
Bug: https://codeberg.org/dwl/dwl/issues/584
2024-08-01 22:41:00 -06:00
Sivecano
672b4c405d
fix maximize callback not getting deregisterd 2024-07-27 22:05:53 -06:00
Leonardo Hernández Hernández
b5abbc37d8
fix crash when re-mapping a client
Fixes: ab5c554d09
2024-07-27 21:59:27 -06:00
Leonardo Hernández Hernández
986beef5be
replace spaces with tabs
Fixes: 71f11e6cf6
2024-07-27 00:41:39 -06:00
Leonardo Hernández Hernández
487abc28ba
add myself to .mailmap 2024-07-24 15:51:49 -06:00
Leonardo Hernández Hernández
cd216908a7
send scale on initial commit to layer surfaces
Signed-off-by: Leonardo Hernández Hernández <leohdz172@proton.me>
2024-07-24 06:25:54 -05:00
Lennart Jablonka
f2c5023a3a dwl(1): use correct special characters for - and '
The hyphen-minus <-> and apostrophe-quote <'> are interpreted by troff
as hyphen and right single quotation mark.  See groff_char(7).

Fixes: 0db6f3c5b5 ("add dwl(1)")
2024-07-23 23:32:15 +00:00
Lennart Jablonka
4bbbb4907e add myself to .mailmap 2024-07-23 23:32:15 +00:00
A Frederick Christensen
ea6a450121
README.md Fix links formatting issue after re-flow text to 80 columns 2024-07-21 14:34:45 -05:00
A Frederick Christensen
ad30ca910b
Documentation restructuring
Modified documentation to make clear the change in development (main) branch versus releases.
2024-07-21 14:21:43 -05:00
Leonardo Hernández Hernández
452a314faa
update README.md to mention the main branch now requires wlroots-git
Closes: https://codeberg.org/dwl/dwl/issues/646
2024-07-14 21:55:58 -06:00
Leonardo Hernández Hernández
da6de7c4d7
update wlr_xwayland_surface names (wlroots!2434)
References: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/2434
2024-07-14 21:37:03 -06:00
Leonardo Hernández Hernández
2553111aa3
bump wlroots version 2024-07-14 21:34:44 -06:00
10 changed files with 525 additions and 363 deletions

3
.mailmap Normal file
View file

@ -0,0 +1,3 @@
Lennart Jablonka <humm@ljabl.com> <hummsmith42@gmail.com>
Leonardo Hernández Hernández <leohdz172@proton.me> <leohdz172@outlook.com>
Leonardo Hernández Hernández <leohdz172@proton.me> <leohdz172@protonmail.com>

View file

@ -8,10 +8,22 @@
## Unreleased
### Added
* Support for the linux-drm-syncobj-v1 protocol ([wlroots!4715][wlroots!4715], [#685][685])
* Allow the use of non-system wlroots library ([#646][646])
[wlroots!4715]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4715
[685]: https://codeberg.org/dwl/dwl/pulls/685
[646]: https://codeberg.org/dwl/dwl/pulls/646
### Changed
### Deprecated
### Removed
### Fixed
* Crash when a client is created while all outputs are disabled.
### Security
### Contributors

View file

@ -6,15 +6,15 @@ include config.mk
# flags for compiling
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
-DVERSION=\"$(VERSION)\" $(XWAYLAND)
DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement \
DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
-Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
-Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types \
-Wfloat-conversion
# CFLAGS / LDFLAGS
PKGS = wlroots-0.18 wayland-server xkbcommon libinput $(XLIBS)
DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` -lm $(LIBS)
PKGS = wayland-server xkbcommon libinput $(XLIBS)
DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
all: dwl
dwl: dwl.o util.o
@ -61,6 +61,7 @@ dist: clean
install: dwl
mkdir -p $(DESTDIR)$(PREFIX)/bin
rm -f $(DESTDIR)$(PREFIX)/bin/dwl
cp -f dwl $(DESTDIR)$(PREFIX)/bin
chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl
mkdir -p $(DESTDIR)$(MANDIR)/man1

219
README.md
View file

@ -1,108 +1,82 @@
# dwl - dwm for Wayland
Join us on our IRC channel: [#dwl on Libera Chat]
Or on our [Discord server].
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,
primarily in terms of functionality, and secondarily in terms of philosophy.
Like dwm, dwl is:
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:
- Easy to understand, hack on, and extend with patches
- One C source file (or a very small number) configurable via `config.h`
- Tied to as few external dependencies as possible
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:
## Getting Started:
- 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.
- Configurable multi-monitor layout support, including position and rotation
- Configurable HiDPI/multi-DPI support
- Idle-inhibit protocol which lets applications such as mpv disable idle
monitoring
- Provide information to external status bars via stdout/stdin
- Urgency hints via xdg-activate protocol
- Support screen lockers via ext-session-lock-v1 protocol
- Various Wayland protocols
- XWayland support as provided by wlroots (can be enabled in `config.mk`)
- Zero flickering - Wayland users naturally expect that "every frame is perfect"
- Layer shell popups (used by Waybar)
- Damage tracking provided by scenegraph API
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
indiscriminately. We will try to keep the code as small as possible.
Features under consideration (possibly as patches) are:
- Protocols made trivial by wlroots
- Implement the text-input and input-method protocols to support IME once ibus
implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and
https://codeberg.org/dwl/dwl/pulls/235)
Feature *non-goals* for the main codebase include:
- Client-side decoration (any more than is necessary to tell the clients not to)
- Client-initiated window management, such as move, resize, and close, which can
be done through the compositor
- Animations and visual effects
## Building dwl
### Latest semi-stable [release]
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
against a late (and often changing) git commit of wlroots. While the adventurous
are welcome to use `main`, it is a rocky road. Using `main` requires that the
user be willing to chase git commits of wlroots. Testing development pull
requests may involve merging unmerged pull requests in [wlroots]' git repository
and/or git commits of wayland.
### Building dwl
dwl has the following dependencies:
```
libinput
wayland
wlroots (compiled with the libinput backend)
xkbcommon
wayland-protocols (compile-time only)
pkg-config (compile-time only)
```
If you enable X11 support:
```
libxcb
libxcb-wm
wlroots (compiled with X11 support)
Xwayland (runtime only)
```
- libinput
- wayland
- wlroots (compiled with the libinput backend)
- xkbcommon
- wayland-protocols (compile-time only)
- pkg-config (compile-time only)
Simply install these (and their `-devel` versions if your distro has separate
development packages) and run `make`. If you wish to build against a Git
version of wlroots, check out the [wlroots-next branch].
dwl has the following additional dependencies if XWayland support is enabled:
- libxcb
- libxcb-wm
- wlroots (compiled with X11 support)
- Xwayland (runtime only)
Install these (and their `-devel` versions if your distro has separate
development packages) and run `make`. If you wish to build against a released
version of wlroots (*you probably do*), use a [release] or a [0.x branch]. If
you want to use the unstable development `main` branch, you need to use the git
version of [wlroots].
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 created.
Check out the dwl [patches repository]!
As in the [dwm] community, we encourage users to share patches they have
created. Check out the [dwl-patches] repository!
## Running dwl
dwl can be run on any of the backends supported by wlroots. This means you can
run it as a separate window inside either an X11 or Wayland session, as well
as directly from a VT console. Depending on your distro's setup, you may need
to add your user to the `video` and `input` groups before you can run dwl on
a VT. If you are using `elogind` or `systemd-logind` you need to install
polkit; otherwise you need to add yourself in the `seat` group and
enable/start the seatd daemon.
run it as a separate window inside either an X11 or Wayland session, as well as
directly from a VT console. Depending on your distro's setup, you may need to
add your user to the `video` and `input` groups before you can run dwl on a
VT. If you are using `elogind` or `systemd-logind` you need to install polkit;
otherwise you need to add yourself in the `seat` group and enable/start the
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 background color is black.
decoration initially; these are instead clients that can be run within the
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
specify the command using the `-s` option. This command will be executed as a
@ -110,7 +84,8 @@ shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`,
but differs in that the display server will not shut down when this process
terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait
for it to terminate (if it hasn't already). This makes it ideal for execing into
a user service manager like [s6], [anopa], [runit], [dinit], or [`systemd --user`].
a user service manager like [s6], [anopa], [runit], [dinit], or [`systemd
--user`].
Note: The `-s` command is run as a *child process* of dwl, which means that it
does not have the ability to affect the environment of dwl or of any processes
@ -128,11 +103,11 @@ 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
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, you can
close standard input with the `<&-` shell redirection, for example:
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,
you can close standard input with the `<&-` shell redirection, for example:
dwl -s 'foot --server <&-'
@ -143,10 +118,62 @@ 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
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,
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.
- Configurable multi-monitor layout support, including position and rotation
- Configurable HiDPI/multi-DPI support
- Idle-inhibit protocol which lets applications such as mpv disable idle
monitoring
- Provide information to external status bars via stdout/stdin
- Urgency hints via xdg-activate protocol
- Support screen lockers via ext-session-lock-v1 protocol
- Various Wayland protocols
- XWayland support as provided by wlroots (can be enabled in `config.mk`)
- Zero flickering - Wayland users naturally expect that "every frame is perfect"
- Layer shell popups (used by Waybar)
- Damage tracking provided by scenegraph API
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
indiscriminately. We will try to keep the code as small as possible.
Features under consideration (possibly as patches) are:
- Protocols made trivial by wlroots
- Implement the text-input and input-method protocols to support IME once ibus
implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and
https://codeberg.org/dwl/dwl/pulls/235)
Feature *non-goals* for the main codebase include:
- Client-side decoration (any more than is necessary to tell the clients not to)
- Client-initiated window management, such as move, resize, and close, which can
be done through the compositor
- Animations and visual effects
## Acknowledgements
dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots
@ -154,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**
@ -164,17 +191,21 @@ inspiration, and to the various contributors to the project, including:
- Stivvo for output management and fullscreen support, and patch maintenance
[Discord server]: https://discord.gg/jJxZnrGPWN
[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl
[Wayland]: https://wayland.freedesktop.org/
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/
[wlroots-next branch]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next
[patches repository]: https://codeberg.org/dwl/dwl-patches
[s6]: https://skarnet.org/software/s6/
[anopa]: https://jjacky.com/anopa/
[runit]: http://smarden.org/runit/faq.html#userservices
[dinit]: https://davmac.org/projects/dinit/
[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
[0.x branch]: https://codeberg.org/dwl/dwl/branches
[anopa]: https://jjacky.com/anopa/
[dinit]: https://davmac.org/projects/dinit/
[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
[main]: https://codeberg.org/dwl/dwl/src/branch/main
[release]: https://codeberg.org/dwl/dwl/releases
[runit]: http://smarden.org/runit/faq.html#userservices
[s6]: https://skarnet.org/software/s6/
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/
[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars
[list of useful resources on our wiki]:
https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x
[Discord server]: https://discord.gg/jJxZnrGPWN
[Wayland]: https://wayland.freedesktop.org/

View file

@ -126,15 +126,14 @@ client_get_appid(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->class;
return c->surface.xwayland->class ? c->surface.xwayland->class : "broken";
#endif
return c->surface.xdg->toplevel->app_id;
return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id : "broken";
}
static inline void
client_get_clip(Client *c, struct wlr_box *clip)
{
struct wlr_box xdg_geom = {0};
*clip = (struct wlr_box){
.x = 0,
.y = 0,
@ -147,9 +146,8 @@ client_get_clip(Client *c, struct wlr_box *clip)
return;
#endif
wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom);
clip->x = xdg_geom.x;
clip->y = xdg_geom.y;
clip->x = c->surface.xdg->geometry.x;
clip->y = c->surface.xdg->geometry.y;
}
static inline void
@ -164,7 +162,7 @@ client_get_geometry(Client *c, struct wlr_box *geom)
return;
}
#endif
wlr_xdg_surface_get_geometry(c->surface.xdg, geom);
*geom = c->surface.xdg->geometry;
}
static inline Client *
@ -200,9 +198,9 @@ client_get_title(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
return c->surface.xwayland->title;
return c->surface.xwayland->title ? c->surface.xwayland->title : "broken";
#endif
return c->surface.xdg->toplevel->title;
return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title : "broken";
}
static inline int
@ -215,16 +213,15 @@ client_is_float_type(Client *c)
if (client_is_x11(c)) {
struct wlr_xwayland_surface *surface = c->surface.xwayland;
xcb_size_hints_t *size_hints = surface->size_hints;
size_t i;
if (surface->modal)
return 1;
for (i = 0; i < surface->window_type_len; i++)
if (surface->window_type[i] == netatom[NetWMWindowTypeDialog]
|| surface->window_type[i] == netatom[NetWMWindowTypeSplash]
|| surface->window_type[i] == netatom[NetWMWindowTypeToolbar]
|| surface->window_type[i] == netatom[NetWMWindowTypeUtility])
return 1;
if (wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG)
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH)
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR)
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
return 1;
}
return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
&& (size_hints->max_width == size_hints->min_width
@ -267,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) {
@ -301,17 +298,6 @@ client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
}
static inline void
client_restack_surface(Client *c)
{
#ifdef XWAYLAND
if (client_is_x11(c))
wlr_xwayland_surface_restack(c->surface.xwayland, NULL,
XCB_STACK_MODE_ABOVE);
#endif
return;
}
static inline void
client_send_close(Client *c)
{
@ -344,6 +330,13 @@ client_set_fullscreen(Client *c, int fullscreen)
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
}
static inline void
client_set_scale(struct wlr_surface *s, float scale)
{
wlr_fractional_scale_v1_notify_scale(s, scale);
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
}
static inline uint32_t
client_set_size(Client *c, uint32_t width, uint32_t height)
{
@ -364,8 +357,11 @@ static inline void
client_set_tiled(Client *c, uint32_t edges)
{
#ifdef XWAYLAND
if (client_is_x11(c))
if (client_is_x11(c)) {
wlr_xwayland_surface_set_maximized(c->surface.xwayland,
edges != WLR_EDGE_NONE, edges != WLR_EDGE_NONE);
return;
}
#endif
if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
@ -391,8 +387,8 @@ client_wants_focus(Client *c)
{
#ifdef XWAYLAND
return client_is_unmanaged(c)
&& wlr_xwayland_or_surface_wants_focus(c->surface.xwayland)
&& wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
&& wlr_xwayland_surface_override_redirect_wants_focus(c->surface.xwayland)
&& wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
#endif
return 0;
}

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

@ -8,10 +8,29 @@ PREFIX = /usr/local
MANDIR = $(PREFIX)/share/man
DATADIR = $(PREFIX)/share
WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19`
WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19`
# 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 \
# -I$(PWD)/wlroots/include
# Set -rpath to avoid using the wrong library.
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/build -L$(PWD)/wlroots/build -lwlroots-0.19
# Assuming you ran "meson setup --prefix ${PWD}/0.19 build && ninja -C build install"
#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
# -I$(PWD)/wlroots/0.19/include/wlroots-0.19
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.19/lib64 -L$(PWD)/wlroots/0.19/lib64 -lwlroots-0.19
XWAYLAND =
XLIBS =
# Uncomment to build XWayland support
#XWAYLAND = -DXWAYLAND
#XLIBS = xcb xcb-icccm
CC = gcc
# dwl itself only uses C99 features, but wlroots' headers use anonymous unions (C11).
# To avoid warnings about them, we do not use -std=c99 and instead of using the
# gmake default 'CC=c99', we use cc.
CC = cc

126
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 :
@ -140,19 +248,11 @@ server.
Start
.Nm
with s6 in the background:
.Dl dwl -s 's6-svscan <&-'
.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.

426
dwl.c
View file

@ -33,6 +33,7 @@
#include <wlr/types/wlr_keyboard_group.h>
#include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_linux_drm_syncobj_v1.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output_management_v1.h>
@ -78,16 +79,12 @@
#define END(A) ((A) + LENGTH(A))
#define TAGMASK ((1u << TAGCOUNT) - 1)
#define LISTEN(E, L, H) wl_signal_add((E), ((L)->notify = (H), (L)))
#define LISTEN_STATIC(E, H) do { static struct wl_listener _l = {.notify = (H)}; wl_signal_add((E), &_l); } while (0)
#define LISTEN_STATIC(E, H) do { struct wl_listener *_l = ecalloc(1, sizeof(*_l)); _l->notify = (H); wl_signal_add((E), _l); } while (0)
/* enums */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11 }; /* client types */
enum { LyrBg, LyrBottom, LyrTile, LyrFloat, LyrTop, LyrFS, LyrOverlay, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
#endif
typedef union {
int i;
@ -105,15 +102,18 @@ typedef struct {
typedef struct Monitor Monitor;
typedef struct {
/* Must keep these three elements in this order */
/* Must keep this field first */
unsigned int type; /* XDGShell or X11* */
struct wlr_box geom; /* layout-relative, includes border */
Monitor *mon;
struct wlr_scene_tree *scene;
struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
struct wlr_scene_tree *scene_surface;
struct wl_list link;
struct wl_list flink;
struct wlr_box geom; /* layout-relative, includes border */
struct wlr_box prev; /* layout-relative, includes border */
struct wlr_box bounds; /* only width and height are used */
union {
struct wlr_xdg_surface *xdg;
struct wlr_xwayland_surface *xwayland;
@ -128,8 +128,6 @@ typedef struct {
struct wl_listener fullscreen;
struct wl_listener set_decoration_mode;
struct wl_listener destroy_decoration;
struct wlr_box prev; /* layout-relative, includes border */
struct wlr_box bounds;
#ifdef XWAYLAND
struct wl_listener activate;
struct wl_listener associate;
@ -151,7 +149,6 @@ typedef struct {
} Key;
typedef struct {
struct wl_list link;
struct wlr_keyboard_group *wlr_group;
int nsyms;
@ -165,9 +162,9 @@ typedef struct {
} KeyboardGroup;
typedef struct {
/* Must keep these three elements in this order */
/* Must keep this field first */
unsigned int type; /* LayerShell */
struct wlr_box geom;
Monitor *mon;
struct wlr_scene_tree *scene;
struct wlr_scene_tree *popups;
@ -255,6 +252,7 @@ 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 void cleanuplisteners(void);
static void closemon(Monitor *m);
static void commitlayersurfacenotify(struct wl_listener *listener, void *data);
static void commitnotify(struct wl_listener *listener, void *data);
@ -282,7 +280,6 @@ static void destroylocksurface(struct wl_listener *listener, void *data);
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 Monitor *dirtomon(enum wlr_direction dir);
static void focusclient(Client *c, int lift);
@ -326,7 +323,6 @@ static void setcursor(struct wl_listener *listener, void *data);
static void setcursorshape(struct wl_listener *listener, void *data);
static void setfloating(Client *c, int floating);
static void setfullscreen(Client *c, int fullscreen);
static void setgamma(struct wl_listener *listener, void *data);
static void setlayout(const Arg *arg);
static void setmfact(const Arg *arg);
static void setmon(Client *c, Monitor *m, uint32_t newtags);
@ -357,7 +353,6 @@ static void xytonode(double x, double y, struct wlr_surface **psurface,
static void zoom(const Arg *arg);
/* variables */
static const char broken[] = "broken";
static pid_t child_pid = -1;
static int locked;
static void *exclusive_focus;
@ -383,7 +378,6 @@ static struct wlr_idle_notifier_v1 *idle_notifier;
static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
static struct wlr_layer_shell_v1 *layer_shell;
static struct wlr_output_manager_v1 *output_mgr;
static struct wlr_gamma_control_manager_v1 *gamma_control_mgr;
static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
static struct wlr_virtual_pointer_manager_v1 *virtual_pointer_mgr;
static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr;
@ -400,7 +394,6 @@ static struct wlr_scene_rect *root_bg;
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
static struct wlr_scene_rect *locked_bg;
static struct wlr_session_lock_v1 *cur_lock;
static struct wl_listener lock_listener = {.notify = locksession};
static struct wlr_seat *seat;
static KeyboardGroup *kb_group;
@ -413,17 +406,47 @@ static struct wlr_box sgeom;
static struct wl_list mons;
static Monitor *selmon;
/* global event handlers */
static struct wl_listener cursor_axis = {.notify = axisnotify};
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 gpu_reset = {.notify = gpureset};
static struct wl_listener layout_change = {.notify = updatemons};
static struct wl_listener new_idle_inhibitor = {.notify = createidleinhibitor};
static struct wl_listener new_input_device = {.notify = inputdevice};
static struct wl_listener new_virtual_keyboard = {.notify = virtualkeyboard};
static struct wl_listener new_virtual_pointer = {.notify = virtualpointer};
static struct wl_listener new_pointer_constraint = {.notify = createpointerconstraint};
static struct wl_listener new_output = {.notify = createmon};
static struct wl_listener new_xdg_toplevel = {.notify = createnotify};
static struct wl_listener new_xdg_popup = {.notify = createpopup};
static struct wl_listener new_xdg_decoration = {.notify = createdecoration};
static struct wl_listener new_layer_surface = {.notify = createlayersurface};
static struct wl_listener output_mgr_apply = {.notify = outputmgrapply};
static struct wl_listener output_mgr_test = {.notify = outputmgrtest};
static struct wl_listener output_power_mgr_set_mode = {.notify = powermgrsetmode};
static struct wl_listener request_activate = {.notify = urgent};
static struct wl_listener request_cursor = {.notify = setcursor};
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};
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};
#ifdef XWAYLAND
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);
static void createnotifyx11(struct wl_listener *listener, void *data);
static void dissociatex11(struct wl_listener *listener, void *data);
static xcb_atom_t getatom(xcb_connection_t *xc, const char *name);
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};
static struct wlr_xwayland *xwayland;
static xcb_atom_t netatom[NetLast];
#endif
/* configuration, allows nested code to access above variables */
@ -460,11 +483,8 @@ applyrules(Client *c)
const Rule *r;
Monitor *mon = selmon, *m;
c->isfloating = client_is_float_type(c);
if (!(appid = client_get_appid(c)))
appid = broken;
if (!(title = client_get_title(c)))
title = broken;
appid = client_get_appid(c);
title = client_get_title(c);
for (r = rules; r < END(rules); r++) {
if ((!r->title || strstr(title, r->title))
@ -478,6 +498,8 @@ applyrules(Client *c)
}
}
}
c->isfloating |= client_is_float_type(c);
setmon(c, mon, newtags);
}
@ -530,13 +552,14 @@ arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, int
wl_list_for_each(l, list, link) {
struct wlr_layer_surface_v1 *layer_surface = l->layer_surface;
if (!layer_surface->initialized)
continue;
if (exclusive != (layer_surface->current.exclusive_zone > 0))
continue;
wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area);
wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, l->scene->node.y);
l->geom.x = l->scene->node.x;
l->geom.y = l->scene->node.y;
}
}
@ -587,8 +610,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,
@ -630,17 +653,17 @@ buttonpress(struct wl_listener *listener, void *data)
break;
case WL_POINTER_BUTTON_STATE_RELEASED:
/* If you released any buttons, we exit interactive move/resize mode. */
/* TODO should reset to the pointer focus's current setcursor */
/* TODO: should reset to the pointer focus's current setcursor */
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
cursor_mode = CurNormal;
/* Drop the window off on its new monitor */
selmon = xytomon(cursor->x, cursor->y);
setmon(grabc, selmon, 0);
grabc = NULL;
return;
} else {
cursor_mode = CurNormal;
}
cursor_mode = CurNormal;
break;
}
/* If the event wasn't handled by the compositor, notify the client with
@ -676,6 +699,7 @@ checkidleinhibitor(struct wlr_surface *exclude)
void
cleanup(void)
{
cleanuplisteners();
#ifdef XWAYLAND
wlr_xwayland_destroy(xwayland);
xwayland = NULL;
@ -689,8 +713,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);
@ -716,6 +740,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);
@ -725,6 +751,43 @@ cleanupmon(struct wl_listener *listener, void *data)
free(m);
}
void
cleanuplisteners(void)
{
wl_list_remove(&cursor_axis.link);
wl_list_remove(&cursor_button.link);
wl_list_remove(&cursor_frame.link);
wl_list_remove(&cursor_motion.link);
wl_list_remove(&cursor_motion_absolute.link);
wl_list_remove(&gpu_reset.link);
wl_list_remove(&new_idle_inhibitor.link);
wl_list_remove(&layout_change.link);
wl_list_remove(&new_input_device.link);
wl_list_remove(&new_virtual_keyboard.link);
wl_list_remove(&new_virtual_pointer.link);
wl_list_remove(&new_pointer_constraint.link);
wl_list_remove(&new_output.link);
wl_list_remove(&new_xdg_toplevel.link);
wl_list_remove(&new_xdg_decoration.link);
wl_list_remove(&new_xdg_popup.link);
wl_list_remove(&new_layer_surface.link);
wl_list_remove(&output_mgr_apply.link);
wl_list_remove(&output_mgr_test.link);
wl_list_remove(&output_power_mgr_set_mode.link);
wl_list_remove(&request_activate.link);
wl_list_remove(&request_cursor.link);
wl_list_remove(&request_set_psel.link);
wl_list_remove(&request_set_sel.link);
wl_list_remove(&request_set_cursor_shape.link);
wl_list_remove(&request_start_drag.link);
wl_list_remove(&start_drag.link);
wl_list_remove(&new_session_lock.link);
#ifdef XWAYLAND
wl_list_remove(&new_xwayland_surface.link);
wl_list_remove(&xwayland_ready.link);
#endif
}
void
closemon(Monitor *m)
{
@ -763,6 +826,8 @@ commitlayersurfacenotify(struct wl_listener *listener, void *data)
struct wlr_layer_surface_v1_state old_state;
if (l->layer_surface->initial_commit) {
client_set_scale(layer_surface->surface, l->mon->wlr_output->scale);
/* Temporarily set the layer's current state to pending
* so that we can easily arrange it */
old_state = l->layer_surface->current;
@ -796,23 +861,24 @@ 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);
wlr_surface_set_preferred_buffer_scale(client_surface(c), (int)ceilf(c->mon->wlr_output->scale));
wlr_fractional_scale_v1_notify_scale(client_surface(c), c->mon->wlr_output->scale);
if (c->mon) {
client_set_scale(client_surface(c), c->mon->wlr_output->scale);
}
setmon(c, NULL, 0); /* Make sure to reapply rules in mapnotify() */
wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel, WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0);
wlr_xdg_toplevel_set_wm_capabilities(c->surface.xdg->toplevel,
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN);
if (c->decoration)
requestdecorationmode(&c->set_decoration_mode, c->decoration);
wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, 0, 0);
return;
}
if (client_surface(c)->mapped && c->mon)
resize(c, c->geom, (c->isfloating && !c->isfullscreen));
resize(c, c->geom, (c->isfloating && !c->isfullscreen));
/* mark a pending resize as completed */
if (c->resize && c->resize <= c->surface.xdg->current.configure_serial)
@ -837,13 +903,16 @@ commitpopup(struct wl_listener *listener, void *data)
return;
popup->base->surface->data = wlr_scene_xdg_surface_create(
popup->parent->data, popup->base);
if ((l && !l->mon) || (c && !c->mon))
if ((l && !l->mon) || (c && !c->mon)) {
wlr_xdg_popup_destroy(popup);
return;
}
box = type == LayerShell ? l->mon->m : c->mon->w;
box.x -= (type == LayerShell ? l->geom.x : c->geom.x);
box.y -= (type == LayerShell ? l->geom.y : c->geom.y);
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);
}
void
@ -945,8 +1014,6 @@ createlayersurface(struct wl_listener *listener, void *data)
wl_list_insert(&l->mon->layers[layer_surface->pending.layer],&l->link);
wlr_surface_send_enter(surface, layer_surface->output);
wlr_fractional_scale_v1_notify_scale(surface, l->mon->wlr_output->scale);
wlr_surface_set_preferred_buffer_scale(surface, (int32_t)ceilf(l->mon->wlr_output->scale));
}
void
@ -1097,10 +1164,10 @@ createpointer(struct wlr_pointer *pointer)
libinput_device_config_middle_emulation_set_enabled(device, middle_button_emulation);
if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL)
libinput_device_config_scroll_set_method (device, scroll_method);
libinput_device_config_scroll_set_method(device, scroll_method);
if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE)
libinput_device_config_click_set_method (device, click_method);
libinput_device_config_click_set_method(device, click_method);
if (libinput_device_config_send_events_get_modes(device))
libinput_device_config_send_events_set_mode(device, send_events_mode);
@ -1148,7 +1215,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. */
@ -1174,7 +1241,6 @@ void
destroydecoration(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, destroy_decoration);
c->decoration = NULL;
wl_list_remove(&c->destroy_decoration.link);
wl_list_remove(&c->set_decoration_mode.link);
@ -1186,6 +1252,8 @@ 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);
}
void
@ -1194,6 +1262,8 @@ 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);
}
void
@ -1275,6 +1345,7 @@ destroynotify(struct wl_listener *listener, void *data)
wl_list_remove(&c->commit.link);
wl_list_remove(&c->map.link);
wl_list_remove(&c->unmap.link);
wl_list_remove(&c->maximize.link);
}
free(c);
}
@ -1300,22 +1371,15 @@ destroysessionlock(struct wl_listener *listener, void *data)
destroylock(lock, 0);
}
void
destroysessionmgr(struct wl_listener *listener, void *data)
{
wl_list_remove(&lock_listener.link);
wl_list_remove(&listener->link);
}
void
destroykeyboardgroup(struct wl_listener *listener, void *data)
{
KeyboardGroup *group = wl_container_of(listener, group, destroy);
wl_event_source_remove(group->key_repeat_source);
wlr_keyboard_group_destroy(group->wlr_group);
wl_list_remove(&group->key.link);
wl_list_remove(&group->modifiers.link);
wl_list_remove(&group->destroy.link);
wlr_keyboard_group_destroy(group->wlr_group);
free(group);
}
@ -1365,7 +1429,6 @@ focusclient(Client *c, int lift)
wl_list_insert(&fstack, &c->flink);
selmon = c->mon;
c->isurgent = 0;
client_restack_surface(c);
/* Don't change border color if there is an exclusive focus or we are
* handling a drag operation */
@ -1448,7 +1511,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 *
@ -1481,7 +1544,8 @@ gpureset(struct wl_listener *listener, void *data)
if (!(alloc = wlr_allocator_autocreate(backend, drw)))
die("couldn't recreate allocator");
LISTEN_STATIC(&drw->events.lost, gpureset);
wl_list_remove(&gpu_reset.link);
wl_signal_add(&drw->events.lost, &gpu_reset);
wlr_compositor_set_renderer(compositor, drw);
@ -1496,22 +1560,10 @@ gpureset(struct wl_listener *listener, void *data)
void
handlesig(int signo)
{
if (signo == SIGCHLD) {
#ifdef XWAYLAND
siginfo_t in;
/* wlroots expects to reap the XWayland process itself, so we
* use WNOWAIT to keep the child waitable until we know it's not
* XWayland.
*/
while (!waitid(P_ALL, 0, &in, WEXITED|WNOHANG|WNOWAIT) && in.si_pid
&& (!xwayland || in.si_pid != xwayland->server->pid))
waitpid(in.si_pid, NULL, 0);
#else
if (signo == SIGCHLD)
while (waitpid(-1, NULL, WNOHANG) > 0);
#endif
} else if (signo == SIGINT || signo == SIGTERM) {
else if (signo == SIGINT || signo == SIGTERM)
quit(NULL);
}
}
void
@ -1692,7 +1744,8 @@ mapnotify(struct wl_listener *listener, void *data)
/* Create scene tree for this client and its border */
c->scene = client_surface(c)->data = wlr_scene_tree_create(layers[LyrTile]);
wlr_scene_node_set_enabled(&c->scene->node, c->type != XDGShell);
/* Enabled later by a call to arrange() */
wlr_scene_node_set_enabled(&c->scene->node, client_is_unmanaged(c));
c->scene_surface = c->type == XDGShell
? wlr_scene_xdg_surface_create(c->scene, c->surface.xdg)
: wlr_scene_subsurface_tree_create(c->scene, client_surface(c));
@ -1705,6 +1758,7 @@ mapnotify(struct wl_listener *listener, void *data)
/* Unmanaged clients always are floating */
wlr_scene_node_reparent(&c->scene->node, layers[LyrFloat]);
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
client_set_size(c, c->geom.width, c->geom.height);
if (client_wants_focus(c)) {
focusclient(c, 1);
exclusive_focus = c;
@ -1729,8 +1783,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);
@ -1790,8 +1844,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;
@ -1822,8 +1875,8 @@ motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double d
&& toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, &l) >= 0) {
c = w;
surface = seat->pointer_state.focused_surface;
sx = cursor->x - (l ? l->geom.x : w->geom.x);
sy = cursor->y - (l ? l->geom.y : w->geom.y);
sx = cursor->x - (l ? l->scene->node.x : w->geom.x);
sy = cursor->y - (l ? l->scene->node.y : w->geom.y);
}
/* time is 0 in internal calls meant to restore pointer focus. */
@ -1913,7 +1966,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
@ -1976,9 +2029,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);
@ -2037,7 +2090,6 @@ printstatus(void)
Monitor *m = NULL;
Client *c;
uint32_t occ, urg, sel;
const char *appid, *title;
wl_list_for_each(m, &mons, link) {
occ = urg = 0;
@ -2049,10 +2101,8 @@ printstatus(void)
urg |= c->tags;
}
if ((c = focustop(m))) {
title = client_get_title(c);
appid = client_get_appid(c);
printf("%s title %s\n", m->wlr_output->name, title ? title : broken);
printf("%s appid %s\n", m->wlr_output->name, appid ? appid : broken);
printf("%s title %s\n", m->wlr_output->name, client_get_title(c));
printf("%s appid %s\n", m->wlr_output->name, client_get_appid(c));
printf("%s fullscreen %d\n", m->wlr_output->name, c->isfullscreen);
printf("%s floating %d\n", m->wlr_output->name, c->isfloating);
sel = c->tags;
@ -2087,6 +2137,7 @@ powermgrsetmode(struct wl_listener *listener, void *data)
wlr_output_commit_state(m->wlr_output, &state);
m->asleep = !event->mode;
updatemons(NULL, NULL);
}
void
@ -2103,7 +2154,6 @@ rendermon(struct wl_listener *listener, void *data)
Monitor *m = wl_container_of(listener, m, frame);
Client *c;
struct wlr_output_state pending = {0};
struct wlr_gamma_control_v1 *gamma_control;
struct timespec now;
/* Render if no XDG clients have an outstanding resize and are visible on
@ -2113,32 +2163,7 @@ rendermon(struct wl_listener *listener, void *data)
goto skip;
}
/*
* HACK: The "correct" way to set the gamma is to commit it together with
* the rest of the state in one go, but to do that we would need to rewrite
* wlr_scene_output_commit() in order to add the gamma to the pending
* state before committing, instead try to commit the gamma in one frame,
* and commit the rest of the state in the next one (or in the same frame if
* the gamma can not be committed).
*/
if (m->gamma_lut_changed) {
gamma_control
= wlr_gamma_control_manager_v1_get_control(gamma_control_mgr, m->wlr_output);
m->gamma_lut_changed = 0;
if (!wlr_gamma_control_v1_apply(gamma_control, &pending))
goto commit;
if (!wlr_output_test_state(m->wlr_output, &pending)) {
wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
goto commit;
}
wlr_output_commit_state(m->wlr_output, &pending);
wlr_output_schedule_frame(m->wlr_output);
} else {
commit:
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 */
@ -2182,7 +2207,7 @@ resize(Client *c, struct wlr_box geo, int interact)
struct wlr_box *bbox;
struct wlr_box clip;
if (!c->mon || !c->scene)
if (!c->mon || !client_surface(c)->mapped)
return;
bbox = interact ? &sgeom : &c->mon->w;
@ -2243,8 +2268,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);
@ -2255,7 +2282,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);
@ -2278,7 +2305,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
@ -2294,7 +2321,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)
@ -2340,17 +2367,6 @@ setfullscreen(Client *c, int fullscreen)
printstatus();
}
void
setgamma(struct wl_listener *listener, void *data)
{
struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
Monitor *m = event->output->data;
if (!m)
return;
m->gamma_lut_changed = 1;
wlr_output_schedule_frame(m->wlr_output);
}
void
setlayout(const Arg *arg)
{
@ -2408,7 +2424,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);
@ -2419,7 +2435,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);
@ -2428,7 +2444,7 @@ setsel(struct wl_listener *listener, void *data)
void
setup(void)
{
int i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
int drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
sigemptyset(&sa.sa_mask);
@ -2463,12 +2479,12 @@ setup(void)
* supports for shared memory, this configures that for clients. */
if (!(drw = wlr_renderer_autocreate(backend)))
die("couldn't create renderer");
LISTEN_STATIC(&drw->events.lost, gpureset);
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);
@ -2478,6 +2494,10 @@ setup(void)
wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw));
}
if ((drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && drw->features.timeline
&& backend->features.timeline)
wlr_linux_drm_syncobj_manager_v1_create(dpy, 1, drm_fd);
/* Autocreates an allocator for us.
* The allocator is the bridge between the renderer and the backend. It
* handles the buffer creation, allowing wlroots to render onto the
@ -2501,29 +2521,29 @@ setup(void)
wlr_viewporter_create(dpy);
wlr_single_pixel_buffer_manager_v1_create(dpy);
wlr_fractional_scale_manager_v1_create(dpy, 1);
wlr_presentation_create(dpy, backend);
wlr_presentation_create(dpy, backend, 2);
wlr_alpha_modifier_v1_create(dpy);
/* Initializes the interface used to implement urgency hints */
activation = wlr_xdg_activation_v1_create(dpy);
LISTEN_STATIC(&activation->events.request_activate, urgent);
wl_signal_add(&activation->events.request_activate, &request_activate);
gamma_control_mgr = wlr_gamma_control_manager_v1_create(dpy);
LISTEN_STATIC(&gamma_control_mgr->events.set_gamma, setgamma);
wlr_scene_set_gamma_control_manager_v1(scene, wlr_gamma_control_manager_v1_create(dpy));
power_mgr = wlr_output_power_manager_v1_create(dpy);
LISTEN_STATIC(&power_mgr->events.set_mode, powermgrsetmode);
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);
LISTEN_STATIC(&output_layout->events.change, updatemons);
wlr_xdg_output_manager_v1_create(dpy, output_layout);
wl_signal_add(&output_layout->events.change, &layout_change);
wlr_xdg_output_manager_v1_create(dpy, output_layout);
/* Configure a listener to be notified when new outputs are available on the
* backend. */
wl_list_init(&mons);
LISTEN_STATIC(&backend->events.new_output, createmon);
wl_signal_add(&backend->events.new_output, &new_output);
/* 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
@ -2535,20 +2555,19 @@ setup(void)
wl_list_init(&fstack);
xdg_shell = wlr_xdg_shell_create(dpy, 6);
LISTEN_STATIC(&xdg_shell->events.new_toplevel, createnotify);
LISTEN_STATIC(&xdg_shell->events.new_popup, createpopup);
wl_signal_add(&xdg_shell->events.new_toplevel, &new_xdg_toplevel);
wl_signal_add(&xdg_shell->events.new_popup, &new_xdg_popup);
layer_shell = wlr_layer_shell_v1_create(dpy, 3);
LISTEN_STATIC(&layer_shell->events.new_surface, createlayersurface);
wl_signal_add(&layer_shell->events.new_surface, &new_layer_surface);
idle_notifier = wlr_idle_notifier_v1_create(dpy);
idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy);
LISTEN_STATIC(&idle_inhibit_mgr->events.new_inhibitor, createidleinhibitor);
wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &new_idle_inhibitor);
session_lock_mgr = wlr_session_lock_manager_v1_create(dpy);
wl_signal_add(&session_lock_mgr->events.new_lock, &lock_listener);
LISTEN_STATIC(&session_lock_mgr->events.destroy, destroysessionmgr);
wl_signal_add(&session_lock_mgr->events.new_lock, &new_session_lock);
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);
@ -2558,10 +2577,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);
LISTEN_STATIC(&xdg_decoration_mgr->events.new_toplevel_decoration, createdecoration);
wl_signal_add(&xdg_decoration_mgr->events.new_toplevel_decoration, &new_xdg_decoration);
pointer_constraints = wlr_pointer_constraints_v1_create(dpy);
LISTEN_STATIC(&pointer_constraints->events.new_constraint, createpointerconstraint);
wl_signal_add(&pointer_constraints->events.new_constraint, &new_pointer_constraint);
relative_pointer_mgr = wlr_relative_pointer_manager_v1_create(dpy);
@ -2589,14 +2608,14 @@ setup(void)
*
* And more comments are sprinkled throughout the notify functions above.
*/
LISTEN_STATIC(&cursor->events.motion, motionrelative);
LISTEN_STATIC(&cursor->events.motion_absolute, motionabsolute);
LISTEN_STATIC(&cursor->events.button, buttonpress);
LISTEN_STATIC(&cursor->events.axis, axisnotify);
LISTEN_STATIC(&cursor->events.frame, cursorframe);
wl_signal_add(&cursor->events.motion, &cursor_motion);
wl_signal_add(&cursor->events.motion_absolute, &cursor_motion_absolute);
wl_signal_add(&cursor->events.button, &cursor_button);
wl_signal_add(&cursor->events.axis, &cursor_axis);
wl_signal_add(&cursor->events.frame, &cursor_frame);
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);
/*
* Configures a seat, which is a single "seat" at which a user sits and
@ -2604,25 +2623,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.
*/
LISTEN_STATIC(&backend->events.new_input, inputdevice);
wl_signal_add(&backend->events.new_input, &new_input_device);
virtual_keyboard_mgr = wlr_virtual_keyboard_manager_v1_create(dpy);
LISTEN_STATIC(&virtual_keyboard_mgr->events.new_virtual_keyboard, virtualkeyboard);
wl_signal_add(&virtual_keyboard_mgr->events.new_virtual_keyboard,
&new_virtual_keyboard);
virtual_pointer_mgr = wlr_virtual_pointer_manager_v1_create(dpy);
LISTEN_STATIC(&virtual_pointer_mgr->events.new_virtual_pointer, virtualpointer);
wl_signal_add(&virtual_pointer_mgr->events.new_virtual_pointer,
&new_virtual_pointer);
seat = wlr_seat_create(dpy, "seat0");
LISTEN_STATIC(&seat->events.request_set_cursor, setcursor);
LISTEN_STATIC(&seat->events.request_set_selection, setsel);
LISTEN_STATIC(&seat->events.request_set_primary_selection, setpsel);
LISTEN_STATIC(&seat->events.request_start_drag, requeststartdrag);
LISTEN_STATIC(&seat->events.start_drag, startdrag);
wl_signal_add(&seat->events.request_set_cursor, &request_cursor);
wl_signal_add(&seat->events.request_set_selection, &request_set_sel);
wl_signal_add(&seat->events.request_set_primary_selection, &request_set_psel);
wl_signal_add(&seat->events.request_start_drag, &request_start_drag);
wl_signal_add(&seat->events.start_drag, &start_drag);
kb_group = createkeyboardgroup();
wl_list_init(&kb_group->destroy.link);
output_mgr = wlr_output_manager_v1_create(dpy);
LISTEN_STATIC(&output_mgr->events.apply, outputmgrapply);
LISTEN_STATIC(&output_mgr->events.test, outputmgrtest);
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
wl_signal_add(&output_mgr->events.test, &output_mgr_test);
/* 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
@ -2634,8 +2655,8 @@ setup(void)
* It will be started when the first X client is started.
*/
if ((xwayland = wlr_xwayland_create(dpy, compositor, 1))) {
LISTEN_STATIC(&xwayland->events.ready, xwaylandready);
LISTEN_STATIC(&xwayland->events.new_surface, createnotifyx11);
wl_signal_add(&xwayland->events.ready, &xwayland_ready);
wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface);
setenv("DISPLAY", xwayland->display_name, 1);
} else {
@ -2975,11 +2996,11 @@ void
virtualpointer(struct wl_listener *listener, void *data)
{
struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
struct wlr_pointer pointer = event->new_pointer->pointer;
struct wlr_input_device *device = &event->new_pointer->pointer.base;
wlr_cursor_attach_input_device(cursor, &pointer.base);
wlr_cursor_attach_input_device(cursor, device);
if (event->suggested_output)
wlr_cursor_map_input_to_output(cursor, &pointer.base, event->suggested_output);
wlr_cursor_map_input_to_output(cursor, device, event->suggested_output);
}
Monitor *
@ -3078,17 +3099,24 @@ configurex11(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, configure);
struct wlr_xwayland_surface_configure_event *event = data;
/* TODO: figure out if there is another way to do this */
if (!c->mon) {
if (!client_surface(c) || !client_surface(c)->mapped) {
wlr_xwayland_surface_configure(c->surface.xwayland,
event->x, event->y, event->width, event->height);
return;
}
if (c->isfloating || client_is_unmanaged(c))
resize(c, (struct wlr_box){.x = event->x, .y = event->y,
.width = event->width + c->bw * 2, .height = event->height + c->bw * 2}, 0);
else
if (client_is_unmanaged(c)) {
wlr_scene_node_set_position(&c->scene->node, event->x, event->y);
wlr_xwayland_surface_configure(c->surface.xwayland,
event->x, event->y, event->width, event->height);
return;
}
if ((c->isfloating && c != grabc) || !c->mon->lt[c->mon->sellt]->arrange) {
resize(c, (struct wlr_box){.x = event->x - c->bw,
.y = event->y - c->bw, .width = event->width + c->bw * 2,
.height = event->height + c->bw * 2}, 0);
} else {
arrange(c->mon);
}
}
void
@ -3122,25 +3150,12 @@ dissociatex11(struct wl_listener *listener, void *data)
wl_list_remove(&c->unmap.link);
}
xcb_atom_t
getatom(xcb_connection_t *xc, const char *name)
{
xcb_atom_t atom = 0;
xcb_intern_atom_reply_t *reply;
xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xc, 0, strlen(name), name);
if ((reply = xcb_intern_atom_reply(xc, cookie, NULL)))
atom = reply->atom;
free(reply);
return atom;
}
void
sethints(struct wl_listener *listener, void *data)
{
Client *c = wl_container_of(listener, c, set_hints);
struct wlr_surface *surface = client_surface(c);
if (c == focustop(selmon))
if (c == focustop(selmon) || !c->surface.xwayland->hints)
return;
c->isurgent = xcb_icccm_wm_hints_get_urgency(c->surface.xwayland->hints);
@ -3154,19 +3169,6 @@ void
xwaylandready(struct wl_listener *listener, void *data)
{
struct wlr_xcursor *xcursor;
xcb_connection_t *xc = xcb_connect(xwayland->display_name, NULL);
int err = xcb_connection_has_error(xc);
if (err) {
fprintf(stderr, "xcb_connect to X server failed with code %d\n. Continuing with degraded functionality.\n", err);
return;
}
/* Collect atoms we are interested in. If getatom returns 0, we will
* not detect that window type. */
netatom[NetWMWindowTypeDialog] = getatom(xc, "_NET_WM_WINDOW_TYPE_DIALOG");
netatom[NetWMWindowTypeSplash] = getatom(xc, "_NET_WM_WINDOW_TYPE_SPLASH");
netatom[NetWMWindowTypeToolbar] = getatom(xc, "_NET_WM_WINDOW_TYPE_TOOLBAR");
netatom[NetWMWindowTypeUtility] = getatom(xc, "_NET_WM_WINDOW_TYPE_UTILITY");
/* assign the one and only seat */
wlr_xwayland_set_seat(xwayland, seat);
@ -3177,8 +3179,6 @@ xwaylandready(struct wl_listener *listener, void *data)
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);
xcb_disconnect(xc);
}
#endif

10
util.c
View file

@ -38,14 +38,14 @@ ecalloc(size_t nmemb, size_t size)
int
fd_set_nonblock(int fd) {
int flags = fcntl(fd, F_GETFL);
if (flags < 0) {
if (flags < 0) {
perror("fcntl(F_GETFL):");
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
perror("fcntl(F_SETFL):");
return -1;
}
}
return 0;
}