mirror of
https://codeberg.org/dwl/dwl.git
synced 2026-09-19 22:02:50 +00:00
Compare commits
256
Commits
v0.5
..
2f3fe0671d
@@ -0,0 +1,62 @@
|
|||||||
|
name: Bug Report
|
||||||
|
about: Something in dwl isn't working correctly
|
||||||
|
title:
|
||||||
|
labels:
|
||||||
|
- 'Kind/Bug'
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
- Only report bugs that can be reproduced on the main (or wlroots-next) branch without patches.
|
||||||
|
- Proprietary graphics drivers, including nvidia, are not supported. Please use the open source equivalents, such as nouveau, if you would like to use dwl.
|
||||||
|
- Report patch issues to their respective authors.
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: dwl_version
|
||||||
|
attributes:
|
||||||
|
label: 'dwl version:'
|
||||||
|
placeholder: '`dwl -v`'
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: wlroots_version
|
||||||
|
attributes:
|
||||||
|
label: 'wlroots version:'
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: distro
|
||||||
|
attributes:
|
||||||
|
label: What distro (and version) are you using?
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
value: |
|
||||||
|
The steps you took to reproduce the problem.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: debug_log
|
||||||
|
attributes:
|
||||||
|
label: Debug Log
|
||||||
|
value: |
|
||||||
|
Run `dwl -d 2> ~/dwl.log` from a TTY and attach the **full** (do not truncate it) file here, or upload it to a pastebin.
|
||||||
|
Please try to keep the reproduction as brief as possible and exit dwl.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: backtrace
|
||||||
|
attributes:
|
||||||
|
label: Stack Trace
|
||||||
|
value: |
|
||||||
|
- Only required if dwl crashes.
|
||||||
|
- If the lines mentioning dwl or wlroots have `??`. Please compile both dwl and wlroots from source (enabling debug symbols) and try to reproduce.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
name: Enhancement idea
|
||||||
|
about: Suggest a feature or improvement
|
||||||
|
title:
|
||||||
|
labels:
|
||||||
|
- 'Kind/Feature'
|
||||||
|
body:
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bug report
|
|
||||||
about: Something in dwl isn't working correctly
|
|
||||||
title: ''
|
|
||||||
labels: 'A: bug'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Info
|
|
||||||
dwl version:
|
|
||||||
wlroots version:
|
|
||||||
## Description
|
|
||||||
<!--
|
|
||||||
Only report bugs that can be reproduced on the main line
|
|
||||||
Report patch issues to their respective authors
|
|
||||||
-->
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
---
|
|
||||||
name: Enhancement idea
|
|
||||||
about: Suggest a feature or improvement
|
|
||||||
title: ''
|
|
||||||
labels: 'A: enhancement'
|
|
||||||
assignees: ''
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
|
|
||||||
@@ -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>
|
||||||
+119
@@ -1,7 +1,126 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
* [Unreleased](#unreleased)
|
||||||
|
* [0.7](#0.7)
|
||||||
|
* [0.6](#0.6)
|
||||||
* [0.5](#0.5)
|
* [0.5](#0.5)
|
||||||
|
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
||||||
|
|
||||||
|
## 0.7
|
||||||
|
|
||||||
|
This version is just 0.6 with wlroots 0.18 compatibility.
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Add support for the alpha-modifier-v1 protocol ([wlroots!4616][wlroots!4616]).
|
||||||
|
* dwl now will survive GPU resets ([#601][601]).
|
||||||
|
|
||||||
|
[wlroots!4616]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4616
|
||||||
|
[601]: https://codeberg.org/dwl/dwl/issues/601
|
||||||
|
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Guido Cella
|
||||||
|
|
||||||
|
|
||||||
|
## 0.6
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
* Add `rootcolor` to change the default background color ([#544][544]).
|
||||||
|
* Implement the wlr-virtual-pointer-unstable-v1 protocol ([#574][574]).
|
||||||
|
* Implement the pointer-constraints and relative-pointer protocols ([#317][317])
|
||||||
|
* Implement the wlr-output-power-management protocol ([#599][599])
|
||||||
|
|
||||||
|
[544]: https://codeberg.org/dwl/dwl/pulls/544
|
||||||
|
[574]: https://codeberg.org/dwl/dwl/pulls/574
|
||||||
|
[317]: https://codeberg.org/dwl/dwl/issues/317
|
||||||
|
[599]: https://codeberg.org/dwl/dwl/issues/559
|
||||||
|
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
* Keyboards are now managed through keyboard groups ([#549][549]).
|
||||||
|
* Only the first matched keybinding is executed.
|
||||||
|
* Allow toggling the layout before selecting a different one ([#570][570]).
|
||||||
|
* Fullscreen clients are now rendered above wlr_layer_surfaces in the top layer
|
||||||
|
([#609][609]).
|
||||||
|
* The default menu was changed from `bemenu-run` to `wmenu-run` ([#553][553]).
|
||||||
|
* The option `sloppyfocus` now replicates the dwm behavior ([#599][599]).
|
||||||
|
* Allow configure position of monitors with negative values. (-1, -1) is
|
||||||
|
used to auto-configure them ([#635][635]).
|
||||||
|
* dwl now kills the entire process group of `startup_cmd`
|
||||||
|
* The O_NONBLOCK flag is set for stdout.
|
||||||
|
|
||||||
|
[549]: https://codeberg.org/dwl/dwl/pulls/549
|
||||||
|
[570]: https://codeberg.org/dwl/dwl/pulls/570
|
||||||
|
[609]: https://codeberg.org/dwl/dwl/pulls/609
|
||||||
|
[553]: https://codeberg.org/dwl/dwl/issues/553
|
||||||
|
[599]: https://codeberg.org/dwl/dwl/pulls/599
|
||||||
|
[635]: https://codeberg.org/dwl/dwl/pulls/635
|
||||||
|
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
* The SLOC limit is now removed ([#497][497]).
|
||||||
|
|
||||||
|
[497]: https://codeberg.org/dwl/dwl/pulls/497
|
||||||
|
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
* Clients not having the correct border color when mapping.
|
||||||
|
* Compliance with the xdg-decoration-unstable-v1 ([#546][546]).
|
||||||
|
* dwl no longer sends negative values in xdg_toplevel.configure events.
|
||||||
|
* Crashes with disabled monitors ([#472][472]).
|
||||||
|
|
||||||
|
[546]: https://codeberg.org/dwl/dwl/pulls/546
|
||||||
|
[472]: https://codeberg.org/dwl/dwl/issues/472
|
||||||
|
|
||||||
|
|
||||||
|
### Contributors
|
||||||
|
|
||||||
|
Ben Jargowsky
|
||||||
|
Benjamin Chausse
|
||||||
|
David Donahue
|
||||||
|
Devin J. Pohly
|
||||||
|
Dima Krasner
|
||||||
|
Emil Miler
|
||||||
|
Forrest Bushstone
|
||||||
|
Guido Cella
|
||||||
|
Peter Hofmann
|
||||||
|
Rutherther
|
||||||
|
Squibid
|
||||||
|
choc
|
||||||
|
fictitiousexistence
|
||||||
|
korei999
|
||||||
|
sewn
|
||||||
|
thanatos
|
||||||
|
|
||||||
|
|
||||||
## 0.5
|
## 0.5
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -4,20 +4,24 @@
|
|||||||
include config.mk
|
include config.mk
|
||||||
|
|
||||||
# flags for compiling
|
# flags for compiling
|
||||||
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XWAYLAND)
|
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
|
||||||
DWLDEVCFLAGS = -g -pedantic -Wall -Wextra -Wdeclaration-after-statement -Wno-unused-parameter -Wno-sign-compare -Wshadow -Wunused-macros\
|
-DVERSION=\"$(VERSION)\" $(XWAYLAND) $(CPPFLAGS)
|
||||||
-Werror=strict-prototypes -Werror=implicit -Werror=return-type -Werror=incompatible-pointer-types
|
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
|
# CFLAGS / LDFLAGS
|
||||||
PKGS = wlroots wayland-server xkbcommon libinput $(XLIBS)
|
PKGS = wayland-server xkbcommon libinput $(XLIBS)
|
||||||
DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
|
DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
|
||||||
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(LIBS)
|
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
|
||||||
|
|
||||||
all: dwl
|
all: dwl
|
||||||
dwl: dwl.o util.o
|
dwl: dwl.c client.h config.h ime.h util.h config.mk cursor-shape-v1-protocol.h \
|
||||||
$(CC) dwl.o util.o $(LDLIBS) $(LDFLAGS) $(DWLCFLAGS) -o $@
|
ext-image-copy-capture-v1-protocol.h \
|
||||||
dwl.o: dwl.c config.mk config.h client.h cursor-shape-v1-protocol.h xdg-shell-protocol.h wlr-layer-shell-unstable-v1-protocol.h
|
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
||||||
util.o: util.c util.h
|
wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
||||||
|
$(CC) dwl.c $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
||||||
|
|
||||||
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
||||||
# protocols, which are specified in XML. wlroots requires you to rig these up
|
# protocols, which are specified in XML. wlroots requires you to rig these up
|
||||||
@@ -25,15 +29,24 @@ util.o: util.c util.h
|
|||||||
WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner`
|
WAYLAND_SCANNER = `$(PKG_CONFIG) --variable=wayland_scanner wayland-scanner`
|
||||||
WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols`
|
WAYLAND_PROTOCOLS = `$(PKG_CONFIG) --variable=pkgdatadir wayland-protocols`
|
||||||
|
|
||||||
|
cursor-shape-v1-protocol.h:
|
||||||
|
$(WAYLAND_SCANNER) enum-header \
|
||||||
|
$(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
|
||||||
|
ext-image-copy-capture-v1-protocol.h:
|
||||||
|
$(WAYLAND_SCANNER) enum-header \
|
||||||
|
$(WAYLAND_PROTOCOLS)/staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml $@
|
||||||
|
pointer-constraints-unstable-v1-protocol.h:
|
||||||
|
$(WAYLAND_SCANNER) enum-header \
|
||||||
|
$(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
|
||||||
|
wlr-layer-shell-unstable-v1-protocol.h:
|
||||||
|
$(WAYLAND_SCANNER) enum-header \
|
||||||
|
protocols/wlr-layer-shell-unstable-v1.xml $@
|
||||||
|
wlr-output-power-management-unstable-v1-protocol.h:
|
||||||
|
$(WAYLAND_SCANNER) server-header \
|
||||||
|
protocols/wlr-output-power-management-unstable-v1.xml $@
|
||||||
xdg-shell-protocol.h:
|
xdg-shell-protocol.h:
|
||||||
$(WAYLAND_SCANNER) server-header \
|
$(WAYLAND_SCANNER) server-header \
|
||||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
||||||
wlr-layer-shell-unstable-v1-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
protocols/wlr-layer-shell-unstable-v1.xml $@
|
|
||||||
cursor-shape-v1-protocol.h:
|
|
||||||
$(WAYLAND_SCANNER) server-header \
|
|
||||||
$(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
|
|
||||||
|
|
||||||
config.h:
|
config.h:
|
||||||
cp config.def.h $@
|
cp config.def.h $@
|
||||||
@@ -42,14 +55,15 @@ clean:
|
|||||||
|
|
||||||
dist: clean
|
dist: clean
|
||||||
mkdir -p dwl-$(VERSION)
|
mkdir -p dwl-$(VERSION)
|
||||||
cp -R LICENSE* Makefile README.md client.h config.def.h\
|
cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h \
|
||||||
config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop\
|
config.mk protocols dwl.1 dwl.c ime.h util.h dwl.desktop \
|
||||||
dwl-$(VERSION)
|
dwl-$(VERSION)
|
||||||
tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION)
|
tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION)
|
||||||
rm -rf dwl-$(VERSION)
|
rm -rf dwl-$(VERSION)
|
||||||
|
|
||||||
install: dwl
|
install: dwl
|
||||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||||
|
rm -f $(DESTDIR)$(PREFIX)/bin/dwl
|
||||||
cp -f dwl $(DESTDIR)$(PREFIX)/bin
|
cp -f dwl $(DESTDIR)$(PREFIX)/bin
|
||||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl
|
||||||
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||||
@@ -59,8 +73,5 @@ install: dwl
|
|||||||
cp -f dwl.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
cp -f dwl.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
||||||
chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 \
|
||||||
|
$(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
||||||
.SUFFIXES: .c .o
|
|
||||||
.c.o:
|
|
||||||
$(CC) $(CPPFLAGS) $(DWLCFLAGS) -c $<
|
|
||||||
|
|||||||
@@ -1,103 +1,85 @@
|
|||||||
# dwl - dwm for Wayland
|
# dwl - dwm for Wayland
|
||||||
|
|
||||||
Join us on our IRC channel: [#dwl on Libera Chat]
|
Join us on our [Discord server]
|
||||||
Or on our [Discord server].
|
Or Matrix: [#dwl-official:matrix.org]
|
||||||
|
Or on our IRC channel: [#dwl on Libera Chat]
|
||||||
|
|
||||||
dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is
|
dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is
|
||||||
intended to fill the same space in the Wayland world that dwm does in X11,
|
intended to fill the same space in the Wayland world that [dwm] does in X11,
|
||||||
primarily in terms of philosophy, and secondarily in terms of functionality.
|
primarily in terms of functionality, and secondarily in terms of
|
||||||
Like dwm, dwl is:
|
philosophy. Like [dwm], dwl is:
|
||||||
|
|
||||||
- Easy to understand, hack on, and extend with patches
|
- Easy to understand, hack on, and extend with patches
|
||||||
- One C source file (or a very small number) configurable via `config.h`
|
- One C source file configurable via `config.h`
|
||||||
- Limited to 2200 SLOC to promote hackability
|
|
||||||
- Tied to as few external dependencies as possible
|
- Tied to as few external dependencies as possible
|
||||||
|
|
||||||
dwl is not meant to provide every feature under the sun. Instead, like dwm, it
|
## Getting Started:
|
||||||
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,
|
### Latest semi-stable [release]
|
||||||
client rules, mouse move/resize. Providing a built-in status bar is an
|
This is probably where you want to start. This builds against the [wlroots]
|
||||||
exception to this goal, to avoid dependencies on font rendering and/or
|
versions currently shipping in major distributions. If your
|
||||||
drawing libraries when an external bar could work well.
|
distribution's `wlroots` version is older, use an earlier dwl [release].
|
||||||
- Configurable multi-monitor layout support, including position and rotation
|
The `wlroots` version against which a given `dwl` release builds is specified
|
||||||
- Configurable HiDPI/multi-DPI support
|
with each release on the [release] page
|
||||||
- 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
|
|
||||||
|
|
||||||
Features under consideration (possibly as patches) are:
|
### Development branch [main]
|
||||||
|
Active development progresses on the `main` branch. The `main` branch is built
|
||||||
|
against the latest release of [wlroots]. PRs should target this branch unless they
|
||||||
|
depend on functionality that is not in the current release of `wlroots`.
|
||||||
|
|
||||||
- Protocols made trivial by wlroots
|
### Preview branch [wlroots-next]
|
||||||
- Implement the text-input and input-method protocols to support IME once ibus
|
The `wlroots-next` branch is built against the git version of [wlroots], which
|
||||||
implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and
|
is unstable and changes frequently. PRs requiring functionality from the git
|
||||||
https://github.com/djpohly/dwl/pull/235)
|
version of `wlroots` should target this branch.
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
### Building dwl
|
||||||
dwl has the following dependencies:
|
dwl has the following dependencies:
|
||||||
```
|
- libinput
|
||||||
libinput
|
- wayland
|
||||||
wayland
|
- wlroots (compiled with the libinput backend)
|
||||||
wlroots (compiled with the libinput backend)
|
- xkbcommon
|
||||||
xkbcommon
|
- wayland-protocols (compile-time only)
|
||||||
wayland-protocols (compile-time only)
|
- pkg-config (compile-time only)
|
||||||
pkg-config (compile-time only)
|
|
||||||
```
|
|
||||||
If you enable X11 support:
|
|
||||||
```
|
|
||||||
libxcb
|
|
||||||
libxcb-wm
|
|
||||||
wlroots (compiled with X11 support)
|
|
||||||
Xwayland (runtime only)
|
|
||||||
```
|
|
||||||
|
|
||||||
Simply install these (and their `-devel` versions if your distro has separate
|
dwl has the following additional dependencies if XWayland support is enabled:
|
||||||
development packages) and run `make`. If you wish to build against a Git
|
- libxcb
|
||||||
version of wlroots, check out the [wlroots-next branch].
|
- 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`.
|
To enable XWayland, you should uncomment its flags in `config.mk`.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
All configuration is done by editing `config.h` and recompiling, in the same
|
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
|
Wayland without restarting the entire display server, so any changes will take
|
||||||
effect the next time dwl is executed.
|
effect the next time dwl is executed.
|
||||||
|
|
||||||
As in the dwm community, we encourage users to share patches they have created.
|
As in the [dwm] community, we encourage users to share patches they have
|
||||||
Check out the [patches page on our wiki]!
|
created. Check out the [dwl-patches] repository!
|
||||||
|
|
||||||
## Running dwl
|
## Running dwl
|
||||||
|
|
||||||
dwl can be run on any of the backends supported by wlroots. This means you can
|
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
|
run it as a separate window inside either an X11 or Wayland session, as well as
|
||||||
as directly from a VT console. Depending on your distro's setup, you may need
|
directly from a VT console. Depending on your distro's setup, you may need to
|
||||||
to add your user to the `video` and `input` groups before you can run dwl on
|
add your user to the `video` and `input` groups before you can run dwl on a
|
||||||
a VT. If you are using `elogind` or `systemd-logind` you need to install
|
VT. If you are using `elogind` or `systemd-logind` you need to install polkit;
|
||||||
polkit; otherwise you need to add yourself in the `seat` group and
|
otherwise you need to add yourself in the `seat` group and enable/start the
|
||||||
enable/start the seatd daemon.
|
seatd daemon.
|
||||||
|
|
||||||
When dwl is run with no arguments, it will launch the server and begin handling
|
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
|
any shortcuts configured in `config.h`. There is no status bar or other
|
||||||
decoration initially; these are instead clients that can be run within
|
decoration initially; these are instead clients that can be run within the
|
||||||
the Wayland session.
|
Wayland session. Do note that the default background color is grey. This can be
|
||||||
Do note that the background color is black.
|
modified in `config.h`.
|
||||||
|
|
||||||
If you would like to run a script or command automatically at startup, you can
|
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
|
specify the command using the `-s` option. This command will be executed as a
|
||||||
@@ -105,7 +87,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
|
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
|
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
|
for it to terminate (if it hasn't already). This makes it ideal for execing into
|
||||||
a user service manager like [s6], [anopa], [runit], 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
|
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
|
does not have the ability to affect the environment of dwl or of any processes
|
||||||
@@ -123,11 +106,11 @@ automatically, you will need to configure it prior to launching `dwl`, e.g.:
|
|||||||
|
|
||||||
Information about selected layouts, current window title, app-id, and
|
Information about selected layouts, current window title, app-id, and
|
||||||
selected/occupied/urgent tags is written to the stdin of the `-s` command (see
|
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.
|
populate an external status bar with a script that parses the
|
||||||
Failing to read this information will cause dwl to block, so if you do want to
|
information. Failing to read this information will cause dwl to block, so if you
|
||||||
run a startup command that does not consume the status information, you can
|
do want to run a startup command that does not consume the status information,
|
||||||
close standard input with the `<&-` shell redirection, for example:
|
you can close standard input with the `<&-` shell redirection, for example:
|
||||||
|
|
||||||
dwl -s 'foot --server <&-'
|
dwl -s 'foot --server <&-'
|
||||||
|
|
||||||
@@ -138,10 +121,59 @@ script with the line
|
|||||||
|
|
||||||
To get a list of status bars that work with dwl consult our [wiki].
|
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
|
## Replacements for X applications
|
||||||
|
|
||||||
You can find a [list of useful resources on our wiki].
|
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
|
||||||
|
|
||||||
|
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
|
## Acknowledgements
|
||||||
|
|
||||||
dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots
|
dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots
|
||||||
@@ -149,25 +181,37 @@ 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
|
accomplished something, then trying to do the same in as suckless a way as
|
||||||
possible.
|
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:
|
inspiration, and to the various contributors to the project, including:
|
||||||
|
|
||||||
|
- **Devin J. Pohly for creating and nurturing the fledgling project**
|
||||||
- Alexander Courtis for the XWayland implementation
|
- Alexander Courtis for the XWayland implementation
|
||||||
- Guido Cella for the layer-shell protocol implementation, patch maintenance,
|
- Guido Cella for the layer-shell protocol implementation, patch maintenance,
|
||||||
and for helping to keep the project running
|
and for helping to keep the project running
|
||||||
- Stivvo for output management and fullscreen support, and patch maintenance
|
- Stivvo for output management and fullscreen support, and patch maintenance
|
||||||
|
|
||||||
|
Also, thanks to our current lead developers:
|
||||||
|
|
||||||
[Discord server]: https://discord.gg/jJxZnrGPWN
|
- @thanatos
|
||||||
[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl
|
- @guidocella
|
||||||
[Wayland]: https://wayland.freedesktop.org/
|
|
||||||
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/
|
[wlroots]: https://gitlab.freedesktop.org/wlroots
|
||||||
[wlroots-next branch]: https://github.com/djpohly/dwl/tree/wlroots-next
|
[dwm]: https://dwm.suckless.org/
|
||||||
[patches page on our wiki]: https://github.com/djpohly/dwl/wiki/Patches
|
|
||||||
[s6]: https://skarnet.org/software/s6/
|
|
||||||
[anopa]: https://jjacky.com/anopa/
|
|
||||||
[runit]: http://smarden.org/runit/faq.html#userservices
|
|
||||||
[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User
|
[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User
|
||||||
[wiki]: https://github.com/djpohly/dwl/wiki#compatible-status-bars
|
[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl
|
||||||
[list of useful resources on our wiki]:
|
[0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1
|
||||||
https://github.com/djpohly/dwl/wiki#migrating-from-x
|
[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
|
||||||
|
[wlroots-next]: https://codeberg.org/dwl/dwl/src/branch/wlroots-next
|
||||||
|
[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
|
||||||
|
[Discord server]: https://discord.gg/jJxZnrGPWN
|
||||||
|
[Wayland]: https://wayland.freedesktop.org/
|
||||||
|
[#dwl-official:matrix.org]: https://matrix.to/#/#dwl-official:matrix.org
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ static inline int
|
|||||||
client_is_x11(Client *c)
|
client_is_x11(Client *c)
|
||||||
{
|
{
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
return c->type == X11Managed || c->type == X11Unmanaged;
|
return c->type == X11;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -126,15 +126,14 @@ client_get_appid(Client *c)
|
|||||||
{
|
{
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (client_is_x11(c))
|
if (client_is_x11(c))
|
||||||
return c->surface.xwayland->class;
|
return c->surface.xwayland->class ? c->surface.xwayland->class : "broken";
|
||||||
#endif
|
#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
|
static inline void
|
||||||
client_get_clip(Client *c, struct wlr_box *clip)
|
client_get_clip(Client *c, struct wlr_box *clip)
|
||||||
{
|
{
|
||||||
struct wlr_box xdg_geom = {0};
|
|
||||||
*clip = (struct wlr_box){
|
*clip = (struct wlr_box){
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
@@ -147,9 +146,8 @@ client_get_clip(Client *c, struct wlr_box *clip)
|
|||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom);
|
clip->x = c->surface.xdg->geometry.x;
|
||||||
clip->x = xdg_geom.x;
|
clip->y = c->surface.xdg->geometry.y;
|
||||||
clip->y = xdg_geom.y;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -164,7 +162,7 @@ client_get_geometry(Client *c, struct wlr_box *geom)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
wlr_xdg_surface_get_geometry(c->surface.xdg, geom);
|
*geom = c->surface.xdg->geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Client *
|
static inline Client *
|
||||||
@@ -172,22 +170,37 @@ client_get_parent(Client *c)
|
|||||||
{
|
{
|
||||||
Client *p = NULL;
|
Client *p = NULL;
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (client_is_x11(c) && c->surface.xwayland->parent)
|
if (client_is_x11(c)) {
|
||||||
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
|
if (c->surface.xwayland->parent)
|
||||||
|
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (c->surface.xdg->toplevel->parent)
|
if (c->surface.xdg->toplevel->parent)
|
||||||
toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
|
toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
client_has_children(Client *c)
|
||||||
|
{
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return !wl_list_empty(&c->surface.xwayland->children);
|
||||||
|
#endif
|
||||||
|
/* surface.xdg->link is never empty because it always contains at least the
|
||||||
|
* surface itself. */
|
||||||
|
return wl_list_length(&c->surface.xdg->link) > 1;
|
||||||
|
}
|
||||||
|
|
||||||
static inline const char *
|
static inline const char *
|
||||||
client_get_title(Client *c)
|
client_get_title(Client *c)
|
||||||
{
|
{
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (client_is_x11(c))
|
if (client_is_x11(c))
|
||||||
return c->surface.xwayland->title;
|
return c->surface.xwayland->title ? c->surface.xwayland->title : "broken";
|
||||||
#endif
|
#endif
|
||||||
return c->surface.xdg->toplevel->title;
|
return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title : "broken";
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
@@ -200,16 +213,15 @@ client_is_float_type(Client *c)
|
|||||||
if (client_is_x11(c)) {
|
if (client_is_x11(c)) {
|
||||||
struct wlr_xwayland_surface *surface = c->surface.xwayland;
|
struct wlr_xwayland_surface *surface = c->surface.xwayland;
|
||||||
xcb_size_hints_t *size_hints = surface->size_hints;
|
xcb_size_hints_t *size_hints = surface->size_hints;
|
||||||
size_t i;
|
|
||||||
if (surface->modal)
|
if (surface->modal)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
for (i = 0; i < surface->window_type_len; i++)
|
if (wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG)
|
||||||
if (surface->window_type[i] == netatom[NetWMWindowTypeDialog]
|
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH)
|
||||||
|| surface->window_type[i] == netatom[NetWMWindowTypeSplash]
|
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR)
|
||||||
|| surface->window_type[i] == netatom[NetWMWindowTypeToolbar]
|
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
|
||||||
|| surface->window_type[i] == netatom[NetWMWindowTypeUtility])
|
return 1;
|
||||||
return 1;
|
}
|
||||||
|
|
||||||
return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
|
return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
|
||||||
&& (size_hints->max_width == size_hints->min_width
|
&& (size_hints->max_width == size_hints->min_width
|
||||||
@@ -252,8 +264,8 @@ client_is_stopped(Client *c)
|
|||||||
|
|
||||||
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
|
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
|
||||||
if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
|
if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
|
||||||
/* This process is not our child process, while is very unluckely that
|
/* 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. */
|
* it is stopped, in order to do not skip frames, assume that it is. */
|
||||||
if (errno == ECHILD)
|
if (errno == ECHILD)
|
||||||
return 1;
|
return 1;
|
||||||
} else if (in.si_pid) {
|
} else if (in.si_pid) {
|
||||||
@@ -270,7 +282,8 @@ static inline int
|
|||||||
client_is_unmanaged(Client *c)
|
client_is_unmanaged(Client *c)
|
||||||
{
|
{
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
return c->type == X11Unmanaged;
|
if (client_is_x11(c))
|
||||||
|
return c->surface.xwayland->override_redirect;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -278,22 +291,18 @@ client_is_unmanaged(Client *c)
|
|||||||
static inline void
|
static inline void
|
||||||
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
|
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
|
||||||
{
|
{
|
||||||
if (kb)
|
uint32_t filtered[WLR_KEYBOARD_KEYS_CAP];
|
||||||
wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
|
size_t size = 0;
|
||||||
kb->num_keycodes, &kb->modifiers);
|
if (!kb) {
|
||||||
else
|
|
||||||
wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
|
wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
static inline void
|
for (size_t i = 0; i < kb->num_keycodes; i++) {
|
||||||
client_restack_surface(Client *c)
|
uint32_t key = kb->keycodes[i];
|
||||||
{
|
if (!consumed[key])
|
||||||
#ifdef XWAYLAND
|
filtered[size++] = key;
|
||||||
if (client_is_x11(c))
|
}
|
||||||
wlr_xwayland_surface_restack(c->surface.xwayland, NULL,
|
wlr_seat_keyboard_notify_enter(seat, s, filtered, size, &kb->modifiers);
|
||||||
XCB_STACK_MODE_ABOVE);
|
|
||||||
#endif
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@@ -328,30 +337,40 @@ client_set_fullscreen(Client *c, int fullscreen)
|
|||||||
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, 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
|
static inline uint32_t
|
||||||
client_set_size(Client *c, uint32_t width, uint32_t height)
|
client_set_size(Client *c, uint32_t width, uint32_t height)
|
||||||
{
|
{
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (client_is_x11(c)) {
|
if (client_is_x11(c)) {
|
||||||
wlr_xwayland_surface_configure(c->surface.xwayland,
|
wlr_xwayland_surface_configure(c->surface.xwayland,
|
||||||
c->geom.x, c->geom.y, width, height);
|
c->geom.x + c->bw, c->geom.y + c->bw, width, height);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (width == c->surface.xdg->toplevel->current.width
|
if ((int32_t)width == c->surface.xdg->toplevel->current.width
|
||||||
&& height ==c->surface.xdg->toplevel->current.height)
|
&& (int32_t)height == c->surface.xdg->toplevel->current.height)
|
||||||
return 0;
|
return 0;
|
||||||
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, width, height);
|
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
client_set_tiled(Client *c, uint32_t edges)
|
client_set_tiled(Client *c, uint32_t edges)
|
||||||
{
|
{
|
||||||
#ifdef XWAYLAND
|
#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;
|
return;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (wl_resource_get_version(c->surface.xdg->resource)
|
if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
|
||||||
>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
|
>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
|
||||||
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
|
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
|
||||||
} else {
|
} else {
|
||||||
@@ -363,10 +382,8 @@ static inline void
|
|||||||
client_set_suspended(Client *c, int suspended)
|
client_set_suspended(Client *c, int suspended)
|
||||||
{
|
{
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (client_is_x11(c)) {
|
if (client_is_x11(c))
|
||||||
wlr_xwayland_surface_set_withdrawn(c->surface.xwayland, suspended);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
|
wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
|
||||||
@@ -377,8 +394,8 @@ client_wants_focus(Client *c)
|
|||||||
{
|
{
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
return client_is_unmanaged(c)
|
return client_is_unmanaged(c)
|
||||||
&& wlr_xwayland_or_surface_wants_focus(c->surface.xwayland)
|
&& wlr_xwayland_surface_override_redirect_wants_focus(c->surface.xwayland)
|
||||||
&& wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
|
&& wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
+52
-49
@@ -7,11 +7,12 @@
|
|||||||
static const int sloppyfocus = 1; /* focus follows mouse */
|
static const int sloppyfocus = 1; /* focus follows mouse */
|
||||||
static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
|
static const int bypass_surface_visibility = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */
|
||||||
static const unsigned int borderpx = 1; /* border pixel of windows */
|
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||||
|
static const float rootcolor[] = COLOR(0x222222ff);
|
||||||
static const float bordercolor[] = COLOR(0x444444ff);
|
static const float bordercolor[] = COLOR(0x444444ff);
|
||||||
static const float focuscolor[] = COLOR(0x005577ff);
|
static const float focuscolor[] = COLOR(0x005577ff);
|
||||||
static const float urgentcolor[] = COLOR(0xff0000ff);
|
static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||||
/* To conform the xdg-protocol, set the alpha to zero to restore the old behavior */
|
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||||
static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* 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 */
|
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||||
#define TAGCOUNT (9)
|
#define TAGCOUNT (9)
|
||||||
@@ -20,11 +21,10 @@ static const float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; /* You can al
|
|||||||
static int log_level = WLR_ERROR;
|
static int log_level = WLR_ERROR;
|
||||||
|
|
||||||
static const Rule rules[] = {
|
static const Rule rules[] = {
|
||||||
/* app_id title tags mask isfloating monitor */
|
/* app_id title tags mask isfloating monitor */
|
||||||
/* examples:
|
{ "Gimp_EXAMPLE", NULL, 0, 1, -1 }, /* Start on currently visible tags floating, not tiled */
|
||||||
{ "Gimp", NULL, 0, 1, -1 },
|
{ "firefox_EXAMPLE", NULL, 1 << 8, 0, -1 }, /* Start on ONLY tag "9" */
|
||||||
*/
|
/* default/example rule: can be changed but cannot be eliminated; at least one rule must exist */
|
||||||
{ "firefox", NULL, 1 << 8, 0, -1 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* layout(s) */
|
/* layout(s) */
|
||||||
@@ -36,13 +36,15 @@ static const Layout layouts[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* monitors */
|
/* monitors */
|
||||||
|
/* (x=-1, y=-1) is reserved as an "autoconfigure" monitor position indicator
|
||||||
|
* WARNING: negative values other than (-1, -1) cause problems with Xwayland clients due to
|
||||||
|
* https://gitlab.freedesktop.org/xorg/xserver/-/issues/899 */
|
||||||
static const MonitorRule monrules[] = {
|
static const MonitorRule monrules[] = {
|
||||||
/* name mfact nmaster scale layout rotate/reflect x y */
|
/* name mfact nmaster scale layout rotate/reflect x y
|
||||||
/* example of a HiDPI laptop monitor:
|
* example of a HiDPI laptop monitor:
|
||||||
{ "eDP-1", 0.5, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
|
{ "eDP-1", 0.5f, 1, 2, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 }, */
|
||||||
*/
|
{ NULL, 0.55f, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
|
||||||
/* defaults */
|
/* default monitor rule: can be changed but cannot be eliminated; at least one monitor rule must exist */
|
||||||
{ NULL, 0.55, 1, 1, &layouts[0], WL_OUTPUT_TRANSFORM_NORMAL, -1, -1 },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* keyboard */
|
/* keyboard */
|
||||||
@@ -93,6 +95,7 @@ LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
|
|||||||
*/
|
*/
|
||||||
static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
|
static const enum libinput_config_accel_profile accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
|
||||||
static const double accel_speed = 0.0;
|
static const double accel_speed = 0.0;
|
||||||
|
|
||||||
/* You can choose between:
|
/* You can choose between:
|
||||||
LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
|
LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
|
||||||
LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
|
LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
|
||||||
@@ -113,44 +116,44 @@ static const enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TA
|
|||||||
|
|
||||||
/* commands */
|
/* commands */
|
||||||
static const char *termcmd[] = { "foot", NULL };
|
static const char *termcmd[] = { "foot", NULL };
|
||||||
static const char *menucmd[] = { "bemenu-run", NULL };
|
static const char *menucmd[] = { "wmenu-run", NULL };
|
||||||
|
|
||||||
static const Key keys[] = {
|
static const Key keys[] = {
|
||||||
/* Note that Shift changes certain key codes: c -> C, 2 -> at, etc. */
|
/* Note that Shift changes certain key codes: 2 -> at, etc. */
|
||||||
/* modifier key function argument */
|
/* modifier key function argument */
|
||||||
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
{ MODKEY, XKB_KEY_p, spawn, {.v = menucmd} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Return, spawn, {.v = termcmd} },
|
||||||
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
|
{ MODKEY, XKB_KEY_j, focusstack, {.i = +1} },
|
||||||
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
{ MODKEY, XKB_KEY_k, focusstack, {.i = -1} },
|
||||||
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
{ MODKEY, XKB_KEY_i, incnmaster, {.i = +1} },
|
||||||
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
|
{ MODKEY, XKB_KEY_d, incnmaster, {.i = -1} },
|
||||||
{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05} },
|
{ MODKEY, XKB_KEY_h, setmfact, {.f = -0.05f} },
|
||||||
{ MODKEY, XKB_KEY_l, setmfact, {.f = +0.05} },
|
{ MODKEY, XKB_KEY_l, setmfact, {.f = +0.05f} },
|
||||||
{ MODKEY, XKB_KEY_Return, zoom, {0} },
|
{ MODKEY, XKB_KEY_Return, zoom, {0} },
|
||||||
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
{ MODKEY, XKB_KEY_Tab, view, {0} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_C, killclient, {0} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_c, killclient, {0} },
|
||||||
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
{ MODKEY, XKB_KEY_t, setlayout, {.v = &layouts[0]} },
|
||||||
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
{ MODKEY, XKB_KEY_f, setlayout, {.v = &layouts[1]} },
|
||||||
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
{ MODKEY, XKB_KEY_m, setlayout, {.v = &layouts[2]} },
|
||||||
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
{ MODKEY, XKB_KEY_space, setlayout, {0} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_space, togglefloating, {0} },
|
||||||
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
{ MODKEY, XKB_KEY_e, togglefullscreen, {0} },
|
||||||
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
|
{ MODKEY, XKB_KEY_0, view, {.ui = ~0} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_parenright, tag, {.ui = ~0} },
|
||||||
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
{ MODKEY, XKB_KEY_comma, focusmon, {.i = WLR_DIRECTION_LEFT} },
|
||||||
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
{ MODKEY, XKB_KEY_period, focusmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_less, tagmon, {.i = WLR_DIRECTION_LEFT} },
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_greater, tagmon, {.i = WLR_DIRECTION_RIGHT} },
|
||||||
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
TAGKEYS( XKB_KEY_1, XKB_KEY_exclam, 0),
|
||||||
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
TAGKEYS( XKB_KEY_2, XKB_KEY_at, 1),
|
||||||
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
TAGKEYS( XKB_KEY_3, XKB_KEY_numbersign, 2),
|
||||||
TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3),
|
TAGKEYS( XKB_KEY_4, XKB_KEY_dollar, 3),
|
||||||
TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4),
|
TAGKEYS( XKB_KEY_5, XKB_KEY_percent, 4),
|
||||||
TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5),
|
TAGKEYS( XKB_KEY_6, XKB_KEY_asciicircum, 5),
|
||||||
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
|
TAGKEYS( XKB_KEY_7, XKB_KEY_ampersand, 6),
|
||||||
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
|
TAGKEYS( XKB_KEY_8, XKB_KEY_asterisk, 7),
|
||||||
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
|
TAGKEYS( XKB_KEY_9, XKB_KEY_parenleft, 8),
|
||||||
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_Q, quit, {0} },
|
{ MODKEY|WLR_MODIFIER_SHIFT, XKB_KEY_q, quit, {0} },
|
||||||
|
|
||||||
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
|
/* Ctrl-Alt-Backspace and Ctrl-Alt-Fx used to be handled by X server */
|
||||||
{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
|
{ WLR_MODIFIER_CTRL|WLR_MODIFIER_ALT,XKB_KEY_Terminate_Server, quit, {0} },
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
_VERSION = 0.5
|
_VERSION = 0.9-dev
|
||||||
VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)`
|
VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)`
|
||||||
|
|
||||||
PKG_CONFIG = pkg-config
|
PKG_CONFIG = pkg-config
|
||||||
@@ -8,8 +8,29 @@ PREFIX = /usr/local
|
|||||||
MANDIR = $(PREFIX)/share/man
|
MANDIR = $(PREFIX)/share/man
|
||||||
DATADIR = $(PREFIX)/share
|
DATADIR = $(PREFIX)/share
|
||||||
|
|
||||||
|
WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.20`
|
||||||
|
WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.20`
|
||||||
|
|
||||||
|
# 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.20
|
||||||
|
|
||||||
|
# Assuming you ran "meson setup --prefix ${PWD}/0.20 build && ninja -C build install"
|
||||||
|
#WLR_INCS = -I/usr/include/pixman-1 -I/usr/include/elogind -I/usr/include/libdrm \
|
||||||
|
# -I$(PWD)/wlroots/0.20/include/wlroots-0.20
|
||||||
|
#WLR_LIBS = -Wl,-rpath,$(PWD)/wlroots/0.20/lib64 -L$(PWD)/wlroots/0.20/lib64 -lwlroots-0.20
|
||||||
|
|
||||||
XWAYLAND =
|
XWAYLAND =
|
||||||
XLIBS =
|
XLIBS =
|
||||||
# Uncomment to build XWayland support
|
# Uncomment to build XWayland support
|
||||||
#XWAYLAND = -DXWAYLAND
|
#XWAYLAND = -DXWAYLAND
|
||||||
#XLIBS = xcb xcb-icccm
|
#XLIBS = xcb xcb-icccm
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ starts a shell process running
|
|||||||
when starting.
|
when starting.
|
||||||
When stopping, it sends
|
When stopping, it sends
|
||||||
.Dv SIGTERM
|
.Dv SIGTERM
|
||||||
to the child process and waits for it to exit.
|
to the child process group and waits for it to exit.
|
||||||
.Pp
|
.Pp
|
||||||
Users are encouraged to customize
|
Users are encouraged to customize
|
||||||
.Nm
|
.Nm
|
||||||
@@ -55,10 +55,10 @@ Move window to a single tag.
|
|||||||
Toggle tag for window.
|
Toggle tag for window.
|
||||||
.It Mod-p
|
.It Mod-p
|
||||||
Spawn
|
Spawn
|
||||||
.Nm bemenu-run .
|
.Xr wmenu-run 1 .
|
||||||
.It Mod-Shift-Return
|
.It Mod-Shift-Return
|
||||||
Spawn
|
Spawn
|
||||||
.Nm foot .
|
.Xr foot 1 .
|
||||||
.It Mod-[jk]
|
.It Mod-[jk]
|
||||||
Move focus down/up the stack.
|
Move focus down/up the stack.
|
||||||
.It Mod-[id]
|
.It Mod-[id]
|
||||||
@@ -100,6 +100,114 @@ Quit
|
|||||||
.Nm .
|
.Nm .
|
||||||
.El
|
.El
|
||||||
These might differ depending on your keyboard layout.
|
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
|
.Sh ENVIRONMENT
|
||||||
These environment variables are used by
|
These environment variables are used by
|
||||||
.Nm :
|
.Nm :
|
||||||
@@ -140,19 +248,11 @@ server.
|
|||||||
Start
|
Start
|
||||||
.Nm
|
.Nm
|
||||||
with s6 in the background:
|
with s6 in the background:
|
||||||
.Dl dwl -s 's6-svscan <&-'
|
.Dl dwl \-s \(aqs6\-svscan <&\-\(aq
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr foot 1 ,
|
|
||||||
.Xr bemenu 1 ,
|
|
||||||
.Xr dwm 1 ,
|
.Xr dwm 1 ,
|
||||||
|
.Xr foot 1 ,
|
||||||
|
.Xr wmenu 1 ,
|
||||||
.Xr xkeyboard-config 7
|
.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
|
.Sh BUGS
|
||||||
All of them.
|
All of them.
|
||||||
|
|||||||
@@ -0,0 +1,639 @@
|
|||||||
|
#include <wlr/types/wlr_input_method_v2.h>
|
||||||
|
#include <wlr/types/wlr_text_input_v3.h>
|
||||||
|
|
||||||
|
struct input_method_relay {
|
||||||
|
struct wl_list text_inputs; /* struct text_input.link */
|
||||||
|
struct wlr_input_method_v2 *input_method;
|
||||||
|
|
||||||
|
struct wlr_surface *focused_surface;
|
||||||
|
struct text_input *active_text_input;
|
||||||
|
|
||||||
|
struct wl_list popups; /* input_method_popup.link */
|
||||||
|
struct wlr_scene_tree *popup_tree;
|
||||||
|
|
||||||
|
struct wl_listener new_text_input;
|
||||||
|
struct wl_listener new_input_method;
|
||||||
|
|
||||||
|
struct wl_listener input_method_commit;
|
||||||
|
struct wl_listener input_method_grab_keyboard;
|
||||||
|
struct wl_listener input_method_destroy;
|
||||||
|
struct wl_listener input_method_new_popup_surface;
|
||||||
|
|
||||||
|
struct wl_listener keyboard_grab_destroy;
|
||||||
|
struct wl_listener focused_surface_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct input_method_popup {
|
||||||
|
struct wlr_input_popup_surface_v2 *popup_surface;
|
||||||
|
struct wlr_scene_tree *tree;
|
||||||
|
struct wlr_scene_tree *scene_surface;
|
||||||
|
struct input_method_relay *relay;
|
||||||
|
struct wl_list link; /* input_method_relay.popups */
|
||||||
|
|
||||||
|
struct wl_listener destroy;
|
||||||
|
struct wl_listener commit;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct text_input {
|
||||||
|
struct input_method_relay *relay;
|
||||||
|
struct wlr_text_input_v3 *input;
|
||||||
|
struct wl_list link;
|
||||||
|
|
||||||
|
struct wl_listener enable;
|
||||||
|
struct wl_listener commit;
|
||||||
|
struct wl_listener disable;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_method_manager_v2 *input_method_manager;
|
||||||
|
struct wlr_text_input_manager_v3 *text_input_manager;
|
||||||
|
struct input_method_relay *input_method_relay;
|
||||||
|
|
||||||
|
/* functions used in dwl.c */
|
||||||
|
static int input_method_keyboard_grab_forward_key(
|
||||||
|
KeyboardGroup *keyboard, struct wlr_keyboard_key_event *event);
|
||||||
|
static int input_method_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard);
|
||||||
|
static struct input_method_relay *input_method_relay_create(void);
|
||||||
|
static void input_method_relay_finish(struct input_method_relay *relay);
|
||||||
|
static void input_method_relay_set_focus(struct input_method_relay *relay,
|
||||||
|
struct wlr_surface *surface);
|
||||||
|
|
||||||
|
/* internal functions */
|
||||||
|
static struct text_input *get_active_text_input(struct input_method_relay *relay);
|
||||||
|
static struct wlr_input_method_keyboard_grab_v2 *get_keyboard_grab(KeyboardGroup *keyboard);
|
||||||
|
static int keyboard_is_emulated_by_input_method(struct wlr_keyboard *keyboard,
|
||||||
|
struct wlr_input_method_v2 *input_method);
|
||||||
|
static void handle_focused_surface_destroy(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_input_method_commit(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_input_method_destroy(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_input_method_grab_keyboard(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_input_method_new_popup_surface(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_keyboard_grab_destroy(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_new_input_method(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_new_text_input(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_popup_surface_commit(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_popup_surface_destroy(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_text_input_commit(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_text_input_destroy(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_text_input_disable(struct wl_listener *listener, void *data);
|
||||||
|
static void handle_text_input_enable(struct wl_listener *listener, void *data);
|
||||||
|
static Monitor *output_from_wlr_output(struct wlr_output *wlr_output);
|
||||||
|
static Monitor *output_nearest_to(int lx, int ly);
|
||||||
|
static void send_state_to_input_method(struct input_method_relay *relay);
|
||||||
|
static void update_active_text_input(struct input_method_relay *relay);
|
||||||
|
static void update_popup_position(struct input_method_popup *popup);
|
||||||
|
static void update_popups_position(struct input_method_relay *relay);
|
||||||
|
static void update_text_inputs_focused_surface(struct input_method_relay *relay);
|
||||||
|
|
||||||
|
Monitor *
|
||||||
|
output_from_wlr_output(struct wlr_output *wlr_output)
|
||||||
|
{
|
||||||
|
Monitor *m = NULL;
|
||||||
|
wl_list_for_each(m, &mons, link) {
|
||||||
|
if (m->wlr_output == wlr_output)
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Monitor *
|
||||||
|
output_nearest_to(int lx, int ly)
|
||||||
|
{
|
||||||
|
double closest_x, closest_y;
|
||||||
|
wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x,
|
||||||
|
&closest_y);
|
||||||
|
|
||||||
|
return output_from_wlr_output(
|
||||||
|
wlr_output_layout_output_at(output_layout, closest_x, closest_y));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
keyboard_is_emulated_by_input_method(struct wlr_keyboard *keyboard,
|
||||||
|
struct wlr_input_method_v2 *input_method)
|
||||||
|
{
|
||||||
|
struct wlr_virtual_keyboard_v1 *virtual_keyboard;
|
||||||
|
|
||||||
|
if (!keyboard || !input_method)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
virtual_keyboard = wlr_input_device_get_virtual_keyboard(&keyboard->base);
|
||||||
|
|
||||||
|
return virtual_keyboard &&
|
||||||
|
wl_resource_get_client(virtual_keyboard->resource) ==
|
||||||
|
wl_resource_get_client(input_method->resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_input_method_keyboard_grab_v2 *
|
||||||
|
get_keyboard_grab(KeyboardGroup *keyboard)
|
||||||
|
{
|
||||||
|
struct wlr_input_method_v2 *input_method = input_method_relay->input_method;
|
||||||
|
|
||||||
|
if (!input_method || !input_method->keyboard_grab || keyboard != kb_group ||
|
||||||
|
keyboard_is_emulated_by_input_method(keyboard->virtual_keyboard,
|
||||||
|
input_method))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return input_method->keyboard_grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
input_method_keyboard_grab_forward_modifiers(KeyboardGroup *keyboard)
|
||||||
|
{
|
||||||
|
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab =
|
||||||
|
get_keyboard_grab(keyboard);
|
||||||
|
|
||||||
|
struct wlr_keyboard_modifiers *modifiers =
|
||||||
|
&keyboard->wlr_group->keyboard.modifiers;
|
||||||
|
|
||||||
|
if (keyboard_grab) {
|
||||||
|
wlr_input_method_keyboard_grab_v2_set_keyboard(
|
||||||
|
keyboard_grab, &keyboard->wlr_group->keyboard);
|
||||||
|
wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, modifiers);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
input_method_keyboard_grab_forward_key(
|
||||||
|
KeyboardGroup *keyboard, struct wlr_keyboard_key_event *event)
|
||||||
|
{
|
||||||
|
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab =
|
||||||
|
get_keyboard_grab(keyboard);
|
||||||
|
if (keyboard_grab) {
|
||||||
|
wlr_input_method_keyboard_grab_v2_set_keyboard(
|
||||||
|
keyboard_grab, &keyboard->wlr_group->keyboard);
|
||||||
|
wlr_input_method_keyboard_grab_v2_send_key(keyboard_grab, event->time_msec,
|
||||||
|
event->keycode, event->state);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct text_input *
|
||||||
|
get_active_text_input(struct input_method_relay *relay)
|
||||||
|
{
|
||||||
|
struct text_input *text_input;
|
||||||
|
|
||||||
|
if (!relay->input_method)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
wl_list_for_each(text_input, &relay->text_inputs, link) {
|
||||||
|
if (text_input->input->focused_surface &&
|
||||||
|
text_input->input->current_enabled)
|
||||||
|
return text_input;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
update_active_text_input(struct input_method_relay *relay)
|
||||||
|
{
|
||||||
|
struct text_input *active_text_input = get_active_text_input(relay);
|
||||||
|
|
||||||
|
if (relay->input_method && relay->active_text_input != active_text_input) {
|
||||||
|
if (active_text_input)
|
||||||
|
wlr_input_method_v2_send_activate(relay->input_method);
|
||||||
|
else
|
||||||
|
wlr_input_method_v2_send_deactivate(relay->input_method);
|
||||||
|
wlr_input_method_v2_send_done(relay->input_method);
|
||||||
|
}
|
||||||
|
|
||||||
|
relay->active_text_input = active_text_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
update_text_inputs_focused_surface(struct input_method_relay *relay)
|
||||||
|
{
|
||||||
|
struct text_input *text_input;
|
||||||
|
wl_list_for_each(text_input, &relay->text_inputs, link) {
|
||||||
|
struct wlr_text_input_v3 *input = text_input->input;
|
||||||
|
|
||||||
|
struct wlr_surface *new_focused_surface;
|
||||||
|
if (relay->input_method && relay->focused_surface &&
|
||||||
|
wl_resource_get_client(input->resource) ==
|
||||||
|
wl_resource_get_client(relay->focused_surface->resource)) {
|
||||||
|
new_focused_surface = relay->focused_surface;
|
||||||
|
} else {
|
||||||
|
new_focused_surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input->focused_surface == new_focused_surface)
|
||||||
|
continue;
|
||||||
|
if (input->focused_surface)
|
||||||
|
wlr_text_input_v3_send_leave(input);
|
||||||
|
if (new_focused_surface)
|
||||||
|
wlr_text_input_v3_send_enter(input, new_focused_surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
update_popup_position(struct input_method_popup *popup)
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay = popup->relay;
|
||||||
|
struct text_input *text_input = relay->active_text_input;
|
||||||
|
struct wlr_box cursor_rect;
|
||||||
|
struct wlr_xdg_surface *xdg_surface;
|
||||||
|
struct wlr_layer_surface_v1 *layer_surface;
|
||||||
|
struct wlr_scene_tree *tree;
|
||||||
|
int lx, ly;
|
||||||
|
Monitor *output;
|
||||||
|
struct wlr_box output_box;
|
||||||
|
struct wlr_xdg_positioner_rules positioner_rules;
|
||||||
|
struct wlr_box popup_box;
|
||||||
|
|
||||||
|
if (!text_input || !relay->focused_surface ||
|
||||||
|
!popup->popup_surface->surface->mapped)
|
||||||
|
return;
|
||||||
|
|
||||||
|
xdg_surface = wlr_xdg_surface_try_from_wlr_surface(relay->focused_surface);
|
||||||
|
layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(relay->focused_surface);
|
||||||
|
|
||||||
|
if ((text_input->input->current.features &
|
||||||
|
WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE) &&
|
||||||
|
(xdg_surface || layer_surface)) {
|
||||||
|
cursor_rect = text_input->input->current.cursor_rectangle;
|
||||||
|
|
||||||
|
tree = relay->focused_surface->data;
|
||||||
|
wlr_scene_node_coords(&tree->node, &lx, &ly);
|
||||||
|
cursor_rect.x += lx;
|
||||||
|
cursor_rect.y += ly;
|
||||||
|
|
||||||
|
if (xdg_surface) {
|
||||||
|
cursor_rect.x -= xdg_surface->geometry.x;
|
||||||
|
cursor_rect.y -= xdg_surface->geometry.y;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cursor_rect = (struct wlr_box){0};
|
||||||
|
}
|
||||||
|
|
||||||
|
output = output_nearest_to(cursor_rect.x, cursor_rect.y);
|
||||||
|
if (!output || !output->wlr_output->enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wlr_output_layout_get_box(output_layout, output->wlr_output, &output_box);
|
||||||
|
|
||||||
|
positioner_rules = (struct wlr_xdg_positioner_rules) {
|
||||||
|
.anchor_rect = cursor_rect,
|
||||||
|
.anchor = XDG_POSITIONER_ANCHOR_BOTTOM_LEFT,
|
||||||
|
.gravity = XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT,
|
||||||
|
.size =
|
||||||
|
{
|
||||||
|
.width = popup->popup_surface->surface->current.width,
|
||||||
|
.height = popup->popup_surface->surface->current.height,
|
||||||
|
},
|
||||||
|
.constraint_adjustment = XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y |
|
||||||
|
XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X,
|
||||||
|
};
|
||||||
|
|
||||||
|
wlr_xdg_positioner_rules_get_geometry(&positioner_rules, &popup_box);
|
||||||
|
wlr_xdg_positioner_rules_unconstrain_box(&positioner_rules, &output_box, &popup_box);
|
||||||
|
|
||||||
|
wlr_scene_node_set_position(&popup->tree->node, popup_box.x, popup_box.y);
|
||||||
|
wlr_scene_node_raise_to_top(&relay->popup_tree->node);
|
||||||
|
|
||||||
|
wlr_input_popup_surface_v2_send_text_input_rectangle(
|
||||||
|
popup->popup_surface, &(struct wlr_box){
|
||||||
|
.x = cursor_rect.x - popup_box.x,
|
||||||
|
.y = cursor_rect.y - popup_box.y,
|
||||||
|
.width = cursor_rect.width,
|
||||||
|
.height = cursor_rect.height,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
update_popups_position(struct input_method_relay *relay)
|
||||||
|
{
|
||||||
|
struct input_method_popup *popup;
|
||||||
|
wl_list_for_each(popup, &relay->popups, link) {
|
||||||
|
update_popup_position(popup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_input_method_commit(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay =
|
||||||
|
wl_container_of(listener, relay, input_method_commit);
|
||||||
|
struct wlr_input_method_v2 *input_method = relay->input_method;
|
||||||
|
struct text_input *text_input = relay->active_text_input;
|
||||||
|
|
||||||
|
if (!text_input)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (input_method->current.preedit.text) {
|
||||||
|
wlr_text_input_v3_send_preedit_string(text_input->input,
|
||||||
|
input_method->current.preedit.text,
|
||||||
|
input_method->current.preedit.cursor_begin,
|
||||||
|
input_method->current.preedit.cursor_end);
|
||||||
|
}
|
||||||
|
if (input_method->current.commit_text) {
|
||||||
|
wlr_text_input_v3_send_commit_string(text_input->input,
|
||||||
|
input_method->current.commit_text);
|
||||||
|
}
|
||||||
|
if (input_method->current.delete.before_length ||
|
||||||
|
input_method->current.delete.after_length) {
|
||||||
|
wlr_text_input_v3_send_delete_surrounding_text(text_input->input,
|
||||||
|
input_method->current.delete.before_length,
|
||||||
|
input_method->current.delete.after_length);
|
||||||
|
}
|
||||||
|
wlr_text_input_v3_send_done(text_input->input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_keyboard_grab_destroy(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay =
|
||||||
|
wl_container_of(listener, relay, keyboard_grab_destroy);
|
||||||
|
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab =
|
||||||
|
relay->input_method->keyboard_grab;
|
||||||
|
wl_list_remove(&relay->keyboard_grab_destroy.link);
|
||||||
|
|
||||||
|
if (keyboard_grab->keyboard) {
|
||||||
|
/* Send modifier state to original client */
|
||||||
|
wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat,
|
||||||
|
&keyboard_grab->keyboard->modifiers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_input_method_grab_keyboard(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay =
|
||||||
|
wl_container_of(listener, relay, input_method_grab_keyboard);
|
||||||
|
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data;
|
||||||
|
|
||||||
|
struct wlr_keyboard *active_keyboard = &kb_group->wlr_group->keyboard;
|
||||||
|
|
||||||
|
if (!keyboard_is_emulated_by_input_method(active_keyboard,
|
||||||
|
relay->input_method)) {
|
||||||
|
/* Send modifier state to grab */
|
||||||
|
wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab,
|
||||||
|
active_keyboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
relay->keyboard_grab_destroy.notify = handle_keyboard_grab_destroy;
|
||||||
|
wl_signal_add(&keyboard_grab->events.destroy, &relay->keyboard_grab_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_input_method_destroy(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay =
|
||||||
|
wl_container_of(listener, relay, input_method_destroy);
|
||||||
|
wl_list_remove(&relay->input_method_commit.link);
|
||||||
|
wl_list_remove(&relay->input_method_grab_keyboard.link);
|
||||||
|
wl_list_remove(&relay->input_method_new_popup_surface.link);
|
||||||
|
wl_list_remove(&relay->input_method_destroy.link);
|
||||||
|
relay->input_method = NULL;
|
||||||
|
|
||||||
|
update_text_inputs_focused_surface(relay);
|
||||||
|
update_active_text_input(relay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_popup_surface_destroy(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct input_method_popup *popup = wl_container_of(listener, popup, destroy);
|
||||||
|
wlr_scene_node_destroy(&popup->tree->node);
|
||||||
|
wl_list_remove(&popup->destroy.link);
|
||||||
|
wl_list_remove(&popup->commit.link);
|
||||||
|
wl_list_remove(&popup->link);
|
||||||
|
free(popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_popup_surface_commit(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct input_method_popup *popup = wl_container_of(listener, popup, commit);
|
||||||
|
update_popup_position(popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_input_method_new_popup_surface(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay =
|
||||||
|
wl_container_of(listener, relay, input_method_new_popup_surface);
|
||||||
|
|
||||||
|
struct input_method_popup *popup = ecalloc(1, sizeof(*popup));
|
||||||
|
popup->popup_surface = data;
|
||||||
|
popup->relay = relay;
|
||||||
|
|
||||||
|
popup->destroy.notify = handle_popup_surface_destroy;
|
||||||
|
wl_signal_add(&popup->popup_surface->events.destroy, &popup->destroy);
|
||||||
|
|
||||||
|
popup->commit.notify = handle_popup_surface_commit;
|
||||||
|
wl_signal_add(&popup->popup_surface->surface->events.commit, &popup->commit);
|
||||||
|
|
||||||
|
popup->tree = wlr_scene_tree_create(layers[LyrIMPopup]);
|
||||||
|
popup->scene_surface = wlr_scene_subsurface_tree_create(
|
||||||
|
popup->tree, popup->popup_surface->surface);
|
||||||
|
popup->scene_surface->node.data = popup;
|
||||||
|
|
||||||
|
wl_list_insert(&relay->popups, &popup->link);
|
||||||
|
|
||||||
|
update_popup_position(popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_new_input_method(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay =
|
||||||
|
wl_container_of(listener, relay, new_input_method);
|
||||||
|
struct wlr_input_method_v2 *input_method = data;
|
||||||
|
if (seat != input_method->seat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (relay->input_method) {
|
||||||
|
wlr_input_method_v2_send_unavailable(input_method);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
relay->input_method = input_method;
|
||||||
|
|
||||||
|
relay->input_method_commit.notify = handle_input_method_commit;
|
||||||
|
wl_signal_add(&relay->input_method->events.commit,
|
||||||
|
&relay->input_method_commit);
|
||||||
|
|
||||||
|
relay->input_method_grab_keyboard.notify = handle_input_method_grab_keyboard;
|
||||||
|
wl_signal_add(&relay->input_method->events.grab_keyboard,
|
||||||
|
&relay->input_method_grab_keyboard);
|
||||||
|
|
||||||
|
relay->input_method_destroy.notify = handle_input_method_destroy;
|
||||||
|
wl_signal_add(&relay->input_method->events.destroy,
|
||||||
|
&relay->input_method_destroy);
|
||||||
|
|
||||||
|
relay->input_method_new_popup_surface.notify =
|
||||||
|
handle_input_method_new_popup_surface;
|
||||||
|
wl_signal_add(&relay->input_method->events.new_popup_surface,
|
||||||
|
&relay->input_method_new_popup_surface);
|
||||||
|
|
||||||
|
update_text_inputs_focused_surface(relay);
|
||||||
|
update_active_text_input(relay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
send_state_to_input_method(struct input_method_relay *relay)
|
||||||
|
{
|
||||||
|
struct wlr_input_method_v2 *input_method = relay->input_method;
|
||||||
|
struct wlr_text_input_v3 *input = relay->active_text_input->input;
|
||||||
|
|
||||||
|
if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT) {
|
||||||
|
wlr_input_method_v2_send_surrounding_text(input_method,
|
||||||
|
input->current.surrounding.text,
|
||||||
|
input->current.surrounding.cursor,
|
||||||
|
input->current.surrounding.anchor);
|
||||||
|
}
|
||||||
|
wlr_input_method_v2_send_text_change_cause(input_method,
|
||||||
|
input->current.text_change_cause);
|
||||||
|
if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE) {
|
||||||
|
wlr_input_method_v2_send_content_type(input_method,
|
||||||
|
input->current.content_type.hint,
|
||||||
|
input->current.content_type.purpose);
|
||||||
|
}
|
||||||
|
wlr_input_method_v2_send_done(input_method);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_text_input_enable(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct text_input *text_input = wl_container_of(listener, text_input, enable);
|
||||||
|
struct input_method_relay *relay = text_input->relay;
|
||||||
|
|
||||||
|
update_active_text_input(relay);
|
||||||
|
if (relay->active_text_input == text_input) {
|
||||||
|
update_popups_position(relay);
|
||||||
|
send_state_to_input_method(relay);
|
||||||
|
}
|
||||||
|
wlr_text_input_v3_send_done(text_input->input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_text_input_disable(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct text_input *text_input =
|
||||||
|
wl_container_of(listener, text_input, disable);
|
||||||
|
update_active_text_input(text_input->relay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_text_input_commit(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct text_input *text_input = wl_container_of(listener, text_input, commit);
|
||||||
|
struct input_method_relay *relay = text_input->relay;
|
||||||
|
|
||||||
|
if (relay->active_text_input == text_input) {
|
||||||
|
update_popups_position(relay);
|
||||||
|
send_state_to_input_method(relay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_text_input_destroy(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct text_input *text_input =
|
||||||
|
wl_container_of(listener, text_input, destroy);
|
||||||
|
wl_list_remove(&text_input->enable.link);
|
||||||
|
wl_list_remove(&text_input->disable.link);
|
||||||
|
wl_list_remove(&text_input->commit.link);
|
||||||
|
wl_list_remove(&text_input->destroy.link);
|
||||||
|
wl_list_remove(&text_input->link);
|
||||||
|
update_active_text_input(text_input->relay);
|
||||||
|
free(text_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_new_text_input(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay =
|
||||||
|
wl_container_of(listener, relay, new_text_input);
|
||||||
|
struct wlr_text_input_v3 *wlr_text_input = data;
|
||||||
|
struct text_input *text_input;
|
||||||
|
|
||||||
|
if (seat != wlr_text_input->seat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
text_input = ecalloc(1, sizeof(*text_input));
|
||||||
|
text_input->input = wlr_text_input;
|
||||||
|
text_input->relay = relay;
|
||||||
|
wl_list_insert(&relay->text_inputs, &text_input->link);
|
||||||
|
|
||||||
|
text_input->enable.notify = handle_text_input_enable;
|
||||||
|
wl_signal_add(&text_input->input->events.enable, &text_input->enable);
|
||||||
|
|
||||||
|
text_input->disable.notify = handle_text_input_disable;
|
||||||
|
wl_signal_add(&text_input->input->events.disable, &text_input->disable);
|
||||||
|
|
||||||
|
text_input->commit.notify = handle_text_input_commit;
|
||||||
|
wl_signal_add(&text_input->input->events.commit, &text_input->commit);
|
||||||
|
|
||||||
|
text_input->destroy.notify = handle_text_input_destroy;
|
||||||
|
wl_signal_add(&text_input->input->events.destroy, &text_input->destroy);
|
||||||
|
|
||||||
|
update_text_inputs_focused_surface(relay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
handle_focused_surface_destroy(struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay =
|
||||||
|
wl_container_of(listener, relay, focused_surface_destroy);
|
||||||
|
input_method_relay_set_focus(relay, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct input_method_relay *
|
||||||
|
input_method_relay_create()
|
||||||
|
{
|
||||||
|
struct input_method_relay *relay = ecalloc(1, sizeof(*relay));
|
||||||
|
wl_list_init(&relay->text_inputs);
|
||||||
|
wl_list_init(&relay->popups);
|
||||||
|
relay->popup_tree = wlr_scene_tree_create(&scene->tree);
|
||||||
|
|
||||||
|
relay->new_text_input.notify = handle_new_text_input;
|
||||||
|
wl_signal_add(&text_input_manager->events.new_text_input, &relay->new_text_input);
|
||||||
|
|
||||||
|
relay->new_input_method.notify = handle_new_input_method;
|
||||||
|
wl_signal_add(&input_method_manager->events.new_input_method,
|
||||||
|
&relay->new_input_method);
|
||||||
|
|
||||||
|
relay->focused_surface_destroy.notify = handle_focused_surface_destroy;
|
||||||
|
|
||||||
|
return relay;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
input_method_relay_finish(struct input_method_relay *relay)
|
||||||
|
{
|
||||||
|
wl_list_remove(&relay->new_text_input.link);
|
||||||
|
wl_list_remove(&relay->new_input_method.link);
|
||||||
|
free(relay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
input_method_relay_set_focus(struct input_method_relay *relay,
|
||||||
|
struct wlr_surface *surface)
|
||||||
|
{
|
||||||
|
if (relay->focused_surface == surface)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (relay->focused_surface)
|
||||||
|
wl_list_remove(&relay->focused_surface_destroy.link);
|
||||||
|
relay->focused_surface = surface;
|
||||||
|
if (surface)
|
||||||
|
wl_signal_add(&surface->events.destroy, &relay->focused_surface_destroy);
|
||||||
|
|
||||||
|
update_text_inputs_focused_surface(relay);
|
||||||
|
update_active_text_input(relay);
|
||||||
|
}
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="wlr_output_power_management_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2019 Purism SPC
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<description summary="Control power management modes of outputs">
|
||||||
|
This protocol allows clients to control power management modes
|
||||||
|
of outputs that are currently part of the compositor space. The
|
||||||
|
intent is to allow special clients like desktop shells to power
|
||||||
|
down outputs when the system is idle.
|
||||||
|
|
||||||
|
To modify outputs not currently part of the compositor space see
|
||||||
|
wlr-output-management.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is experimental and
|
||||||
|
backward incompatible changes may be made. Backward compatible changes
|
||||||
|
may be added together with the corresponding interface version bump.
|
||||||
|
Backward incompatible changes are done by bumping the version number in
|
||||||
|
the protocol and interface names and resetting the interface version.
|
||||||
|
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||||
|
version number in the protocol and interface names are removed and the
|
||||||
|
interface version number is reset.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_power_manager_v1" version="1">
|
||||||
|
<description summary="manager to create per-output power management">
|
||||||
|
This interface is a manager that allows creating per-output power
|
||||||
|
management mode controls.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="get_output_power">
|
||||||
|
<description summary="get a power management for an output">
|
||||||
|
Create a output power management mode control that can be used to
|
||||||
|
adjust the power management mode for a given output.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
|
||||||
|
<arg name="output" type="object" interface="wl_output"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the manager">
|
||||||
|
All objects created by the manager will still remain valid, until their
|
||||||
|
appropriate destroy request has been called.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwlr_output_power_v1" version="1">
|
||||||
|
<description summary="adjust power management mode for an output">
|
||||||
|
This object offers requests to set the power management mode of
|
||||||
|
an output.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="mode">
|
||||||
|
<entry name="off" value="0"
|
||||||
|
summary="Output is turned off."/>
|
||||||
|
<entry name="on" value="1"
|
||||||
|
summary="Output is turned on, no power saving"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="invalid_mode" value="1" summary="inexistent power save mode"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="set_mode">
|
||||||
|
<description summary="Set an outputs power save mode">
|
||||||
|
Set an output's power save mode to the given mode. The mode change
|
||||||
|
is effective immediately. If the output does not support the given
|
||||||
|
mode a failed event is sent.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="uint" enum="mode" summary="the power save mode to set"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="mode">
|
||||||
|
<description summary="Report a power management mode change">
|
||||||
|
Report the power management mode change of an output.
|
||||||
|
|
||||||
|
The mode event is sent after an output changed its power
|
||||||
|
management mode. The reason can be a client using set_mode or the
|
||||||
|
compositor deciding to change an output's mode.
|
||||||
|
This event is also sent immediately when the object is created
|
||||||
|
so the client is informed about the current power management mode.
|
||||||
|
</description>
|
||||||
|
<arg name="mode" type="uint" enum="mode"
|
||||||
|
summary="the output's new power management mode"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="failed">
|
||||||
|
<description summary="object no longer valid">
|
||||||
|
This event indicates that the output power management mode control
|
||||||
|
is no longer valid. This can happen for a number of reasons,
|
||||||
|
including:
|
||||||
|
- The output doesn't support power management
|
||||||
|
- Another client already has exclusive power management mode control
|
||||||
|
for this output
|
||||||
|
- The output disappeared
|
||||||
|
|
||||||
|
Upon receiving this event, the client should destroy this object.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy this power management">
|
||||||
|
Destroys the output power management mode control object.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
/* See LICENSE.dwm file for copyright and license details. */
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
die(const char *fmt, ...) {
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
vfprintf(stderr, fmt, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
|
|
||||||
fputc(' ', stderr);
|
|
||||||
perror(NULL);
|
|
||||||
} else {
|
|
||||||
fputc('\n', stderr);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
ecalloc(size_t nmemb, size_t size)
|
|
||||||
{
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
if (!(p = calloc(nmemb, size)))
|
|
||||||
die("calloc:");
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,58 @@
|
|||||||
/* See LICENSE.dwm file for copyright and license details. */
|
/* See LICENSE.dwm file for copyright and license details. */
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
void die(const char *fmt, ...);
|
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
||||||
void *ecalloc(size_t nmemb, size_t size);
|
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||||
|
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||||
|
#define END(A) ((A) + LENGTH(A))
|
||||||
|
|
||||||
|
static void die(const char *fmt, ...);
|
||||||
|
static void *ecalloc(size_t nmemb, size_t size);
|
||||||
|
static int fd_set_nonblock(int fd);
|
||||||
|
|
||||||
|
void
|
||||||
|
die(const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
|
||||||
|
fputc(' ', stderr);
|
||||||
|
perror(NULL);
|
||||||
|
} else {
|
||||||
|
fputc('\n', stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
ecalloc(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if (!(p = calloc(nmemb, size)))
|
||||||
|
die("calloc:");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fd_set_nonblock(int fd) {
|
||||||
|
int flags = fcntl(fd, F_GETFL);
|
||||||
|
if (flags < 0) {
|
||||||
|
perror("fcntl(F_GETFL):");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||||
|
perror("fcntl(F_SETFL):");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user