Compare commits
14 commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2be61ea3d1 | |||
| 9d18bb4439 | |||
| dc1260d3cf | |||
| 39f8e0a52c | |||
| f269667a35 | |||
| 821a5f382a | |||
| 77cbea57d8 | |||
| 42c5ca8e38 | |||
| e32b429c43 | |||
| 51e5de1c8b | |||
| 92167bff9e | |||
| 9b2fec0df1 | |||
| af68b5e63c | |||
| 5c056777d6 |
24 changed files with 3871 additions and 4196 deletions
|
|
@ -1,62 +0,0 @@
|
||||||
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
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
name: Enhancement idea
|
|
||||||
about: Suggest a feature or improvement
|
|
||||||
title:
|
|
||||||
labels:
|
|
||||||
- 'Kind/Feature'
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,3 +1,6 @@
|
||||||
|
build/
|
||||||
|
bin/
|
||||||
|
|
||||||
dwl
|
dwl
|
||||||
*.o
|
*.o
|
||||||
*-protocol.c
|
*-protocol.c
|
||||||
|
|
|
||||||
3
.mailmap
3
.mailmap
|
|
@ -1,3 +0,0 @@
|
||||||
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>
|
|
||||||
217
CHANGELOG.md
217
CHANGELOG.md
|
|
@ -1,217 +0,0 @@
|
||||||
# Changelog
|
|
||||||
|
|
||||||
* [Unreleased](#unreleased)
|
|
||||||
* [0.7](#0.7)
|
|
||||||
* [0.6](#0.6)
|
|
||||||
* [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
|
|
||||||
|
|
||||||
### Added
|
|
||||||
|
|
||||||
* Allow configure x and y position of outputs ([#301][301])
|
|
||||||
* Implement repeatable keybindings ([#368][368])
|
|
||||||
* Print app id in printstatus() output ([#381][381])
|
|
||||||
* Display client count in monocle symbol ([#387][387])
|
|
||||||
* Export XCURSOR_SIZE to fix apps using an older version of Qt ([#425][425])
|
|
||||||
* Support for wp-fractional-scale-v1 (through wlr_scene: [wlroots!3511][wlroots!3511])
|
|
||||||
* dwl now sends `wl_surface.preferred_buffer_scale` (through wlr_scene: [wlroots!4269][wlroots!4269])
|
|
||||||
* Add support for xdg-shell v6 ([#465][465])
|
|
||||||
* Add support for wp-cursor-shape-v1 ([#444][444])
|
|
||||||
* Add desktop file ([#484][484])
|
|
||||||
* Add macro to easily configure colors ([#466][466])
|
|
||||||
* Color of urgent clients are now red ([#494][494])
|
|
||||||
* New flag `-d` and option `log_level` to change the wlroots debug level
|
|
||||||
* Add CHANGELOG.md ([#501][501])
|
|
||||||
|
|
||||||
[301]: https://github.com/djpohly/dwl/pull/301
|
|
||||||
[368]: https://github.com/djpohly/dwl/pull/368
|
|
||||||
[381]: https://github.com/djpohly/dwl/pull/381
|
|
||||||
[387]: https://github.com/djpohly/dwl/issues/387
|
|
||||||
[425]: https://github.com/djpohly/dwl/pull/425
|
|
||||||
[wlroots!4269]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/4269
|
|
||||||
[wlroots!3511]: https://gitlab.freedesktop.org/wlroots/wlroots/-/merge_requests/3511
|
|
||||||
[465]: https://github.com/djpohly/dwl/pull/465
|
|
||||||
[444]: https://github.com/djpohly/dwl/pull/444
|
|
||||||
[484]: https://github.com/djpohly/dwl/pull/484
|
|
||||||
[466]: https://github.com/djpohly/dwl/issues/466
|
|
||||||
[494]: https://github.com/djpohly/dwl/pull/494
|
|
||||||
[501]: https://github.com/djpohly/dwl/pull/501
|
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
|
||||||
|
|
||||||
* Replace `tags` with `TAGCOUNT` in config.def.h ([#403][403])
|
|
||||||
* Pop ups are now destroyed when focusing another client ([#408][408])
|
|
||||||
* dwl does not longer respect size hints, instead clip windows if they are
|
|
||||||
larger than they should be ([#455][455])
|
|
||||||
* The version of wlr-layer-shell-unstable-v1 was lowered to 3 (from 4)
|
|
||||||
* Use the same border color as dwm ([#494][494])
|
|
||||||
|
|
||||||
[403]: https://github.com/djpohly/dwl/pull/403
|
|
||||||
[408]: https://github.com/djpohly/dwl/pull/409
|
|
||||||
[455]: https://github.com/djpohly/dwl/pull/455
|
|
||||||
[494]: https://github.com/djpohly/dwl/pull/494
|
|
||||||
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
|
|
||||||
* Remove unused `rootcolor` option ([#401][401])
|
|
||||||
* Remove support for wlr-input-inhibitor-unstable-v1 ([#430][430])
|
|
||||||
* Remove support for KDE idle protocol ([#431][431])
|
|
||||||
|
|
||||||
[401]: https://github.com/djpohly/dwl/pull/401
|
|
||||||
[430]: https://github.com/djpohly/dwl/pull/430
|
|
||||||
[431]: https://github.com/djpohly/dwl/pull/431
|
|
||||||
|
|
||||||
|
|
||||||
### Fixed
|
|
||||||
|
|
||||||
* Fix crash when creating a layer surface with all outputs disabled
|
|
||||||
([#421][421])
|
|
||||||
* Fix other clients being shown as focused if the focused client have pop ups
|
|
||||||
open ([#408][408])
|
|
||||||
* Resize fullscreen clients when updating monitor mode
|
|
||||||
* dwl no longer crash at exit like sometimes did
|
|
||||||
* Fullscreen background appearing above clients ([#487][487])
|
|
||||||
* Fix a segfault when user provides invalid xkb_rules ([#518][518])
|
|
||||||
|
|
||||||
[421]: https://github.com/djpohly/dwl/pull/421
|
|
||||||
[408]: https://github.com/djpohly/dwl/issues/408
|
|
||||||
[487]: https://github.com/djpohly/dwl/issues/487
|
|
||||||
[518]: https://github.com/djpohly/dwl/pull/518
|
|
||||||
|
|
||||||
|
|
||||||
### Contributors
|
|
||||||
|
|
||||||
* A Frederick Christensen
|
|
||||||
* Angelo Antony
|
|
||||||
* Ben Collerson
|
|
||||||
* Devin J. Pohly
|
|
||||||
* Forrest Bushstone
|
|
||||||
* gan-of-culture
|
|
||||||
* godalming123
|
|
||||||
* Job79
|
|
||||||
* link2xt
|
|
||||||
* Micah Gorrell
|
|
||||||
* Nikita Ivanov
|
|
||||||
* Palanix
|
|
||||||
* pino-desktop
|
|
||||||
* Weiseguy
|
|
||||||
* Yves Zoundi
|
|
||||||
87
Makefile
87
Makefile
|
|
@ -1,10 +1,11 @@
|
||||||
.POSIX:
|
.POSIX:
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
|
.DEFAULT_GOAL := all
|
||||||
|
|
||||||
include config.mk
|
include config.mk
|
||||||
|
|
||||||
# flags for compiling
|
# flags for compiling
|
||||||
DWLCPPFLAGS = -I. -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
|
DWLCPPFLAGS = -I$(INCLUDE) -DWLR_USE_UNSTABLE -D_POSIX_C_SOURCE=200809L \
|
||||||
-DVERSION=\"$(VERSION)\" $(XWAYLAND)
|
-DVERSION=\"$(VERSION)\" $(XWAYLAND)
|
||||||
DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
|
DWLDEVCFLAGS = -g -Wpedantic -Wall -Wextra -Wdeclaration-after-statement \
|
||||||
-Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
|
-Wno-unused-parameter -Wshadow -Wunused-macros -Werror=strict-prototypes \
|
||||||
|
|
@ -16,13 +17,31 @@ PKGS = wayland-server xkbcommon libinput $(XLIBS)
|
||||||
DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
|
DWLCFLAGS = `$(PKG_CONFIG) --cflags $(PKGS)` $(WLR_INCS) $(DWLCPPFLAGS) $(DWLDEVCFLAGS) $(CFLAGS)
|
||||||
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
|
LDLIBS = `$(PKG_CONFIG) --libs $(PKGS)` $(WLR_LIBS) -lm $(LIBS)
|
||||||
|
|
||||||
all: dwl
|
# macros to relevant path definitions
|
||||||
dwl: dwl.o util.o
|
define mkbin
|
||||||
$(CC) dwl.o util.o $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
$(addprefix $(BIN)/,$1)
|
||||||
dwl.o: dwl.c client.h config.h config.mk cursor-shape-v1-protocol.h \
|
endef
|
||||||
|
define mkobj
|
||||||
|
$(addprefix $(OBJ)/,$1)
|
||||||
|
endef
|
||||||
|
define mkinclude
|
||||||
|
$(addprefix $(INCLUDE)/,$1)
|
||||||
|
endef
|
||||||
|
define mksrc
|
||||||
|
$(addprefix $(SRC)/,$1)
|
||||||
|
endef
|
||||||
|
|
||||||
|
.PHONY: setup
|
||||||
|
setup:
|
||||||
|
mkdir -p $(BIN) $(BUILD) $(INCLUDE) $(OBJ)
|
||||||
|
|
||||||
|
all: setup $(BIN)/$(BINARY) $(BUILD)/$(BINARY).desktop
|
||||||
|
$(BIN)/$(BINARY): $(call mkobj,main.o util.o)
|
||||||
|
$(CC) $^ $(DWLCFLAGS) $(LDFLAGS) $(LDLIBS) -o $@
|
||||||
|
$(OBJ)/main.o: $(call mksrc,main.c client.h) config.mk $(call mkinclude,config.h cursor-shape-v1-protocol.h \
|
||||||
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
pointer-constraints-unstable-v1-protocol.h wlr-layer-shell-unstable-v1-protocol.h \
|
||||||
wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h
|
wlr-output-power-management-unstable-v1-protocol.h xdg-shell-protocol.h)
|
||||||
util.o: util.c util.h
|
$(OBJ)/util.o: $(call mksrc,util.c util.h)
|
||||||
|
|
||||||
# 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
|
||||||
|
|
@ -30,50 +49,54 @@ 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:
|
$(INCLUDE)/cursor-shape-v1-protocol.h:
|
||||||
$(WAYLAND_SCANNER) enum-header \
|
$(WAYLAND_SCANNER) enum-header \
|
||||||
$(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
|
$(WAYLAND_PROTOCOLS)/staging/cursor-shape/cursor-shape-v1.xml $@
|
||||||
pointer-constraints-unstable-v1-protocol.h:
|
$(INCLUDE)/pointer-constraints-unstable-v1-protocol.h:
|
||||||
$(WAYLAND_SCANNER) enum-header \
|
$(WAYLAND_SCANNER) enum-header \
|
||||||
$(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
|
$(WAYLAND_PROTOCOLS)/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml $@
|
||||||
wlr-layer-shell-unstable-v1-protocol.h:
|
$(INCLUDE)/wlr-layer-shell-unstable-v1-protocol.h:
|
||||||
$(WAYLAND_SCANNER) enum-header \
|
$(WAYLAND_SCANNER) enum-header \
|
||||||
protocols/wlr-layer-shell-unstable-v1.xml $@
|
protocols/wlr-layer-shell-unstable-v1.xml $@
|
||||||
wlr-output-power-management-unstable-v1-protocol.h:
|
$(INCLUDE)/wlr-output-power-management-unstable-v1-protocol.h:
|
||||||
$(WAYLAND_SCANNER) server-header \
|
$(WAYLAND_SCANNER) server-header \
|
||||||
protocols/wlr-output-power-management-unstable-v1.xml $@
|
protocols/wlr-output-power-management-unstable-v1.xml $@
|
||||||
xdg-shell-protocol.h:
|
$(INCLUDE)/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 $@
|
||||||
|
|
||||||
config.h:
|
$(INCLUDE)/config.h:
|
||||||
cp config.def.h $@
|
cp $(SRC)/config.def.h $@
|
||||||
|
|
||||||
|
$(BUILD)/$(BINARY).desktop:
|
||||||
|
mkdir -p $(BUILD)
|
||||||
|
echo -e "[Desktop Entry]\nName=$(BINARY)\nComment=$(DESCRIPTION)\nExec=$(BINARY)\nType=Application" > $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f dwl *.o *-protocol.h
|
rm -rf $(INCLUDE) $(OBJ) $(BUILD) $(BIN)
|
||||||
|
|
||||||
dist: clean
|
dist: clean $(BUILD)/$(BINARY).desktop
|
||||||
mkdir -p dwl-$(VERSION)
|
mkdir -p $(BINARY)-$(VERSION)
|
||||||
cp -R LICENSE* Makefile CHANGELOG.md README.md client.h config.def.h \
|
cp -R LICENSE Makefile CHANGELOG.md README.md src \
|
||||||
config.mk protocols dwl.1 dwl.c util.c util.h dwl.desktop \
|
config.mk protocols dwl.1 $(BUILD)/$(BINARY).desktop \
|
||||||
dwl-$(VERSION)
|
$(BINARY)-$(VERSION)
|
||||||
tar -caf dwl-$(VERSION).tar.gz dwl-$(VERSION)
|
tar -caf $(BINARY)-$(VERSION).tar.gz $(BINARY)-$(VERSION)
|
||||||
rm -rf dwl-$(VERSION)
|
rm -rf $(BINARY)-$(VERSION) $(BUILD)
|
||||||
|
|
||||||
install: dwl
|
install: $(BIN)/$(BINARY) $(BUILD)/$(BINARY).desktop
|
||||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||||
rm -f $(DESTDIR)$(PREFIX)/bin/dwl
|
rm -f $(DESTDIR)$(PREFIX)/bin/$(BINARY)
|
||||||
cp -f dwl $(DESTDIR)$(PREFIX)/bin
|
cp -f $(BIN)/$(BINARY) $(DESTDIR)$(PREFIX)/bin
|
||||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/dwl
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/$(BINARY)
|
||||||
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
mkdir -p $(DESTDIR)$(MANDIR)/man1
|
||||||
cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1
|
cp -f dwl.1 $(DESTDIR)$(MANDIR)/man1
|
||||||
chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1
|
chmod 644 $(DESTDIR)$(MANDIR)/man1/dwl.1
|
||||||
mkdir -p $(DESTDIR)$(DATADIR)/wayland-sessions
|
mkdir -p $(DESTDIR)$(DATADIR)/wayland-sessions
|
||||||
cp -f dwl.desktop $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
cp -f $(BUILD)/$(BINARY).desktop $(DESTDIR)$(DATADIR)/wayland-sessions/$(BINARY).desktop
|
||||||
chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
chmod 644 $(DESTDIR)$(DATADIR)/wayland-sessions/$(BINARY).desktop
|
||||||
uninstall:
|
uninstall:
|
||||||
rm -f $(DESTDIR)$(PREFIX)/bin/dwl $(DESTDIR)$(MANDIR)/man1/dwl.1 \
|
rm -f $(DESTDIR)$(PREFIX)/bin/$(BINARY) $(DESTDIR)$(MANDIR)/man1/dwl.1 \
|
||||||
$(DESTDIR)$(DATADIR)/wayland-sessions/dwl.desktop
|
$(DESTDIR)$(DATADIR)/wayland-sessions/$(BINARY).desktop
|
||||||
|
|
||||||
.SUFFIXES: .c .o
|
%.c %.o:
|
||||||
.c.o:
|
|
||||||
$(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -c $<
|
$(CC) $(CPPFLAGS) $(DWLCFLAGS) -o $@ -c $<
|
||||||
|
|
|
||||||
201
README.dwl
Normal file
201
README.dwl
Normal file
|
|
@ -0,0 +1,201 @@
|
||||||
|
# dwl - dwm for Wayland
|
||||||
|
|
||||||
|
Join us on our IRC channel: [#dwl on Libera Chat]
|
||||||
|
Or on the community-maintained [Discord server].
|
||||||
|
|
||||||
|
dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is
|
||||||
|
intended to fill the same space in the Wayland world that dwm does in X11,
|
||||||
|
primarily in terms of functionality, and secondarily in terms of
|
||||||
|
philosophy. Like dwm, dwl is:
|
||||||
|
|
||||||
|
- Easy to understand, hack on, and extend with patches
|
||||||
|
- One C source file (or a very small number) configurable via `config.h`
|
||||||
|
- Tied to as few external dependencies as possible
|
||||||
|
|
||||||
|
## Getting Started:
|
||||||
|
|
||||||
|
### Latest semi-stable [release]
|
||||||
|
This is probably where you want to start. This builds against the [wlroots]
|
||||||
|
versions currently shipping in major distributions. If your
|
||||||
|
distribution's `wlroots` version is older, use an earlier dwl [release].
|
||||||
|
The `wlroots` version against which a given `dwl` release builds is specified
|
||||||
|
with each release on the [release] page
|
||||||
|
|
||||||
|
### Development branch [main]
|
||||||
|
Active development progresses on the `main` branch. The `main` branch is built
|
||||||
|
against a late (and often changing) git commit of wlroots. While the adventurous
|
||||||
|
are welcome to use `main`, it is a rocky road. Using `main` requires that the
|
||||||
|
user be willing to chase git commits of wlroots. Testing development pull
|
||||||
|
requests may involve merging unmerged pull requests in [wlroots]' git repository
|
||||||
|
and/or git commits of wayland.
|
||||||
|
|
||||||
|
### Building dwl
|
||||||
|
dwl has the following dependencies:
|
||||||
|
- libinput
|
||||||
|
- wayland
|
||||||
|
- wlroots (compiled with the libinput backend)
|
||||||
|
- xkbcommon
|
||||||
|
- wayland-protocols (compile-time only)
|
||||||
|
- pkg-config (compile-time only)
|
||||||
|
|
||||||
|
dwl has the following additional dependencies if XWayland support is enabled:
|
||||||
|
- libxcb
|
||||||
|
- libxcb-wm
|
||||||
|
- wlroots (compiled with X11 support)
|
||||||
|
- Xwayland (runtime only)
|
||||||
|
|
||||||
|
Install these (and their `-devel` versions if your distro has separate
|
||||||
|
development packages) and run `make`. If you wish to build against a released
|
||||||
|
version of wlroots (*you probably do*), use a [release] or a [0.x branch]. If
|
||||||
|
you want to use the unstable development `main` branch, you need to use the git
|
||||||
|
version of [wlroots].
|
||||||
|
|
||||||
|
To enable XWayland, you should uncomment its flags in `config.mk`.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
All configuration is done by editing `config.h` and recompiling, in the same
|
||||||
|
manner as dwm. There is no way to separately restart the window manager in
|
||||||
|
Wayland without restarting the entire display server, so any changes will take
|
||||||
|
effect the next time dwl is executed.
|
||||||
|
|
||||||
|
As in the dwm community, we encourage users to share patches they have
|
||||||
|
created. Check out the [dwl-patches] repository!
|
||||||
|
|
||||||
|
## Running dwl
|
||||||
|
|
||||||
|
dwl can be run on any of the backends supported by wlroots. This means you can
|
||||||
|
run it as a separate window inside either an X11 or Wayland session, as well as
|
||||||
|
directly from a VT console. Depending on your distro's setup, you may need to
|
||||||
|
add your user to the `video` and `input` groups before you can run dwl on a
|
||||||
|
VT. If you are using `elogind` or `systemd-logind` you need to install polkit;
|
||||||
|
otherwise you need to add yourself in the `seat` group and enable/start the
|
||||||
|
seatd daemon.
|
||||||
|
|
||||||
|
When dwl is run with no arguments, it will launch the server and begin handling
|
||||||
|
any shortcuts configured in `config.h`. There is no status bar or other
|
||||||
|
decoration initially; these are instead clients that can be run within the
|
||||||
|
Wayland session. Do note that the default background color is grey. This can be
|
||||||
|
modified in `config.h`.
|
||||||
|
|
||||||
|
If you would like to run a script or command automatically at startup, you can
|
||||||
|
specify the command using the `-s` option. This command will be executed as a
|
||||||
|
shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`,
|
||||||
|
but differs in that the display server will not shut down when this process
|
||||||
|
terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait
|
||||||
|
for it to terminate (if it hasn't already). This makes it ideal for execing into
|
||||||
|
a user service manager like [s6], [anopa], [runit], [dinit], or [`systemd
|
||||||
|
--user`].
|
||||||
|
|
||||||
|
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
|
||||||
|
that it spawns. If you need to set environment variables that affect the entire
|
||||||
|
dwl session, these must be set prior to running dwl. For example, Wayland
|
||||||
|
requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager
|
||||||
|
such as `elogind` or `systemd-logind`. If your system doesn't do this
|
||||||
|
automatically, you will need to configure it prior to launching `dwl`, e.g.:
|
||||||
|
|
||||||
|
export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u)
|
||||||
|
mkdir -p $XDG_RUNTIME_DIR
|
||||||
|
dwl
|
||||||
|
|
||||||
|
### Status information
|
||||||
|
|
||||||
|
Information about selected layouts, current window title, app-id, and
|
||||||
|
selected/occupied/urgent tags is written to the stdin of the `-s` command (see
|
||||||
|
the `STATUS INFORMATION` section in `_dwl_(1)`). This information can be used to
|
||||||
|
populate an external status bar with a script that parses the
|
||||||
|
information. Failing to read this information will cause dwl to block, so if you
|
||||||
|
do want to run a startup command that does not consume the status information,
|
||||||
|
you can close standard input with the `<&-` shell redirection, for example:
|
||||||
|
|
||||||
|
dwl -s 'foot --server <&-'
|
||||||
|
|
||||||
|
If your startup command is a shell script, you can achieve the same inside the
|
||||||
|
script with the line
|
||||||
|
|
||||||
|
exec <&-
|
||||||
|
|
||||||
|
To get a list of status bars that work with dwl consult our [wiki].
|
||||||
|
|
||||||
|
## Replacements for X applications
|
||||||
|
|
||||||
|
You can find a [list of useful resources on our wiki].
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
dwl is not meant to provide every feature under the sun. Instead, like dwm, it
|
||||||
|
sticks to features which are necessary, simple, and straightforward to implement
|
||||||
|
given the base on which it is built. Implemented default features are:
|
||||||
|
|
||||||
|
- Any features provided by dwm/Xlib: simple window borders, tags, keybindings,
|
||||||
|
client rules, mouse move/resize. Providing a built-in status bar is an
|
||||||
|
exception to this goal, to avoid dependencies on font rendering and/or drawing
|
||||||
|
libraries when an external bar could work well.
|
||||||
|
- Configurable multi-monitor layout support, including position and rotation
|
||||||
|
- Configurable HiDPI/multi-DPI support
|
||||||
|
- Idle-inhibit protocol which lets applications such as mpv disable idle
|
||||||
|
monitoring
|
||||||
|
- Provide information to external status bars via stdout/stdin
|
||||||
|
- Urgency hints via xdg-activate protocol
|
||||||
|
- Support screen lockers via ext-session-lock-v1 protocol
|
||||||
|
- Various Wayland protocols
|
||||||
|
- XWayland support as provided by wlroots (can be enabled in `config.mk`)
|
||||||
|
- Zero flickering - Wayland users naturally expect that "every frame is perfect"
|
||||||
|
- Layer shell popups (used by Waybar)
|
||||||
|
- Damage tracking provided by scenegraph API
|
||||||
|
|
||||||
|
Given the Wayland architecture, dwl has to implement features from dwm **and**
|
||||||
|
the xorg-server. Because of this, it is impossible to maintain the original
|
||||||
|
project goal of 2000 SLOC and have a reasonably complete compositor with
|
||||||
|
features comparable to dwm. However, this does not mean that the code will grow
|
||||||
|
indiscriminately. We will try to keep the code as small as possible.
|
||||||
|
|
||||||
|
Features under consideration (possibly as patches) are:
|
||||||
|
|
||||||
|
- Protocols made trivial by wlroots
|
||||||
|
- Implement the text-input and input-method protocols to support IME once ibus
|
||||||
|
implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and
|
||||||
|
https://codeberg.org/dwl/dwl/pulls/235)
|
||||||
|
|
||||||
|
Feature *non-goals* for the main codebase include:
|
||||||
|
|
||||||
|
- Client-side decoration (any more than is necessary to tell the clients not to)
|
||||||
|
- Client-initiated window management, such as move, resize, and close, which can
|
||||||
|
be done through the compositor
|
||||||
|
- Animations and visual effects
|
||||||
|
|
||||||
|
## Acknowledgements
|
||||||
|
|
||||||
|
dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots
|
||||||
|
developers. This was made possible in many cases by looking at how sway
|
||||||
|
accomplished something, then trying to do the same in as suckless a way as
|
||||||
|
possible.
|
||||||
|
|
||||||
|
Many thanks to suckless.org and the dwm developers and community for the
|
||||||
|
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
|
||||||
|
- Guido Cella for the layer-shell protocol implementation, patch maintenance,
|
||||||
|
and for helping to keep the project running
|
||||||
|
- Stivvo for output management and fullscreen support, and patch maintenance
|
||||||
|
|
||||||
|
|
||||||
|
[wlroots]: https://gitlab.freedesktop.org/wlroots
|
||||||
|
[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User
|
||||||
|
[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl
|
||||||
|
[0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1
|
||||||
|
[0.x branch]: https://codeberg.org/dwl/dwl/branches
|
||||||
|
[anopa]: https://jjacky.com/anopa/
|
||||||
|
[dinit]: https://davmac.org/projects/dinit/
|
||||||
|
[dwl-patches]: https://codeberg.org/dwl/dwl-patches
|
||||||
|
[list of useful resources on our wiki]: https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x
|
||||||
|
[main]: https://codeberg.org/dwl/dwl/src/branch/main
|
||||||
|
[release]: https://codeberg.org/dwl/dwl/releases
|
||||||
|
[runit]: http://smarden.org/runit/faq.html#userservices
|
||||||
|
[s6]: https://skarnet.org/software/s6/
|
||||||
|
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/
|
||||||
|
[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars
|
||||||
|
[Discord server]: https://discord.gg/jJxZnrGPWN
|
||||||
|
[Wayland]: https://wayland.freedesktop.org/
|
||||||
207
README.md
207
README.md
|
|
@ -1,201 +1,10 @@
|
||||||
# dwl - dwm for Wayland
|
### CryWL
|
||||||
|
|
||||||
Join us on our IRC channel: [#dwl on Libera Chat]
|
|
||||||
Or on the community-maintained [Discord server].
|
|
||||||
|
|
||||||
dwl is a compact, hackable compositor for [Wayland] based on [wlroots]. It is
|
|
||||||
intended to fill the same space in the Wayland world that dwm does in X11,
|
|
||||||
primarily in terms of functionality, and secondarily in terms of
|
|
||||||
philosophy. Like dwm, dwl is:
|
|
||||||
|
|
||||||
- Easy to understand, hack on, and extend with patches
|
|
||||||
- One C source file (or a very small number) configurable via `config.h`
|
|
||||||
- Tied to as few external dependencies as possible
|
|
||||||
|
|
||||||
## Getting Started:
|
|
||||||
|
|
||||||
### Latest semi-stable [release]
|
|
||||||
This is probably where you want to start. This builds against the [wlroots]
|
|
||||||
versions currently shipping in major distributions. If your
|
|
||||||
distribution's `wlroots` version is older, use an earlier dwl [release].
|
|
||||||
The `wlroots` version against which a given `dwl` release builds is specified
|
|
||||||
with each release on the [release] page
|
|
||||||
|
|
||||||
### Development branch [main]
|
|
||||||
Active development progresses on the `main` branch. The `main` branch is built
|
|
||||||
against a late (and often changing) git commit of wlroots. While the adventurous
|
|
||||||
are welcome to use `main`, it is a rocky road. Using `main` requires that the
|
|
||||||
user be willing to chase git commits of wlroots. Testing development pull
|
|
||||||
requests may involve merging unmerged pull requests in [wlroots]' git repository
|
|
||||||
and/or git commits of wayland.
|
|
||||||
|
|
||||||
### Building dwl
|
|
||||||
dwl has the following dependencies:
|
|
||||||
- libinput
|
|
||||||
- wayland
|
|
||||||
- wlroots (compiled with the libinput backend)
|
|
||||||
- xkbcommon
|
|
||||||
- wayland-protocols (compile-time only)
|
|
||||||
- pkg-config (compile-time only)
|
|
||||||
|
|
||||||
dwl has the following additional dependencies if XWayland support is enabled:
|
|
||||||
- libxcb
|
|
||||||
- libxcb-wm
|
|
||||||
- wlroots (compiled with X11 support)
|
|
||||||
- Xwayland (runtime only)
|
|
||||||
|
|
||||||
Install these (and their `-devel` versions if your distro has separate
|
|
||||||
development packages) and run `make`. If you wish to build against a released
|
|
||||||
version of wlroots (*you probably do*), use a [release] or a [0.x branch]. If
|
|
||||||
you want to use the unstable development `main` branch, you need to use the git
|
|
||||||
version of [wlroots].
|
|
||||||
|
|
||||||
To enable XWayland, you should uncomment its flags in `config.mk`.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
All configuration is done by editing `config.h` and recompiling, in the same
|
|
||||||
manner as dwm. There is no way to separately restart the window manager in
|
|
||||||
Wayland without restarting the entire display server, so any changes will take
|
|
||||||
effect the next time dwl is executed.
|
|
||||||
|
|
||||||
As in the dwm community, we encourage users to share patches they have
|
|
||||||
created. Check out the [dwl-patches] repository!
|
|
||||||
|
|
||||||
## Running dwl
|
|
||||||
|
|
||||||
dwl can be run on any of the backends supported by wlroots. This means you can
|
|
||||||
run it as a separate window inside either an X11 or Wayland session, as well as
|
|
||||||
directly from a VT console. Depending on your distro's setup, you may need to
|
|
||||||
add your user to the `video` and `input` groups before you can run dwl on a
|
|
||||||
VT. If you are using `elogind` or `systemd-logind` you need to install polkit;
|
|
||||||
otherwise you need to add yourself in the `seat` group and enable/start the
|
|
||||||
seatd daemon.
|
|
||||||
|
|
||||||
When dwl is run with no arguments, it will launch the server and begin handling
|
|
||||||
any shortcuts configured in `config.h`. There is no status bar or other
|
|
||||||
decoration initially; these are instead clients that can be run within the
|
|
||||||
Wayland session. Do note that the default background color is grey. This can be
|
|
||||||
modified in `config.h`.
|
|
||||||
|
|
||||||
If you would like to run a script or command automatically at startup, you can
|
|
||||||
specify the command using the `-s` option. This command will be executed as a
|
|
||||||
shell command using `/bin/sh -c`. It serves a similar function to `.xinitrc`,
|
|
||||||
but differs in that the display server will not shut down when this process
|
|
||||||
terminates. Instead, dwl will send this process a SIGTERM at shutdown and wait
|
|
||||||
for it to terminate (if it hasn't already). This makes it ideal for execing into
|
|
||||||
a user service manager like [s6], [anopa], [runit], [dinit], or [`systemd
|
|
||||||
--user`].
|
|
||||||
|
|
||||||
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
|
|
||||||
that it spawns. If you need to set environment variables that affect the entire
|
|
||||||
dwl session, these must be set prior to running dwl. For example, Wayland
|
|
||||||
requires a valid `XDG_RUNTIME_DIR`, which is usually set up by a session manager
|
|
||||||
such as `elogind` or `systemd-logind`. If your system doesn't do this
|
|
||||||
automatically, you will need to configure it prior to launching `dwl`, e.g.:
|
|
||||||
|
|
||||||
export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$(id -u)
|
|
||||||
mkdir -p $XDG_RUNTIME_DIR
|
|
||||||
dwl
|
|
||||||
|
|
||||||
### Status information
|
|
||||||
|
|
||||||
Information about selected layouts, current window title, app-id, and
|
|
||||||
selected/occupied/urgent tags is written to the stdin of the `-s` command (see
|
|
||||||
the `STATUS INFORMATION` section in `_dwl_(1)`). This information can be used to
|
|
||||||
populate an external status bar with a script that parses the
|
|
||||||
information. Failing to read this information will cause dwl to block, so if you
|
|
||||||
do want to run a startup command that does not consume the status information,
|
|
||||||
you can close standard input with the `<&-` shell redirection, for example:
|
|
||||||
|
|
||||||
dwl -s 'foot --server <&-'
|
|
||||||
|
|
||||||
If your startup command is a shell script, you can achieve the same inside the
|
|
||||||
script with the line
|
|
||||||
|
|
||||||
exec <&-
|
|
||||||
|
|
||||||
To get a list of status bars that work with dwl consult our [wiki].
|
|
||||||
|
|
||||||
## Replacements for X applications
|
|
||||||
|
|
||||||
You can find a [list of useful resources on our wiki].
|
|
||||||
|
|
||||||
## Background
|
|
||||||
|
|
||||||
dwl is not meant to provide every feature under the sun. Instead, like dwm, it
|
|
||||||
sticks to features which are necessary, simple, and straightforward to implement
|
|
||||||
given the base on which it is built. Implemented default features are:
|
|
||||||
|
|
||||||
- Any features provided by dwm/Xlib: simple window borders, tags, keybindings,
|
|
||||||
client rules, mouse move/resize. Providing a built-in status bar is an
|
|
||||||
exception to this goal, to avoid dependencies on font rendering and/or drawing
|
|
||||||
libraries when an external bar could work well.
|
|
||||||
- Configurable multi-monitor layout support, including position and rotation
|
|
||||||
- Configurable HiDPI/multi-DPI support
|
|
||||||
- Idle-inhibit protocol which lets applications such as mpv disable idle
|
|
||||||
monitoring
|
|
||||||
- Provide information to external status bars via stdout/stdin
|
|
||||||
- Urgency hints via xdg-activate protocol
|
|
||||||
- Support screen lockers via ext-session-lock-v1 protocol
|
|
||||||
- Various Wayland protocols
|
|
||||||
- XWayland support as provided by wlroots (can be enabled in `config.mk`)
|
|
||||||
- Zero flickering - Wayland users naturally expect that "every frame is perfect"
|
|
||||||
- Layer shell popups (used by Waybar)
|
|
||||||
- Damage tracking provided by scenegraph API
|
|
||||||
|
|
||||||
Given the Wayland architecture, dwl has to implement features from dwm **and**
|
|
||||||
the xorg-server. Because of this, it is impossible to maintain the original
|
|
||||||
project goal of 2000 SLOC and have a reasonably complete compositor with
|
|
||||||
features comparable to dwm. However, this does not mean that the code will grow
|
|
||||||
indiscriminately. We will try to keep the code as small as possible.
|
|
||||||
|
|
||||||
Features under consideration (possibly as patches) are:
|
|
||||||
|
|
||||||
- Protocols made trivial by wlroots
|
|
||||||
- Implement the text-input and input-method protocols to support IME once ibus
|
|
||||||
implements input-method v2 (see https://github.com/ibus/ibus/pull/2256 and
|
|
||||||
https://codeberg.org/dwl/dwl/pulls/235)
|
|
||||||
|
|
||||||
Feature *non-goals* for the main codebase include:
|
|
||||||
|
|
||||||
- Client-side decoration (any more than is necessary to tell the clients not to)
|
|
||||||
- Client-initiated window management, such as move, resize, and close, which can
|
|
||||||
be done through the compositor
|
|
||||||
- Animations and visual effects
|
|
||||||
|
|
||||||
## Acknowledgements
|
|
||||||
|
|
||||||
dwl began by extending the TinyWL example provided (CC0) by the sway/wlroots
|
|
||||||
developers. This was made possible in many cases by looking at how sway
|
|
||||||
accomplished something, then trying to do the same in as suckless a way as
|
|
||||||
possible.
|
|
||||||
|
|
||||||
Many thanks to suckless.org and the dwm developers and community for the
|
|
||||||
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
|
|
||||||
- Guido Cella for the layer-shell protocol implementation, patch maintenance,
|
|
||||||
and for helping to keep the project running
|
|
||||||
- Stivvo for output management and fullscreen support, and patch maintenance
|
|
||||||
|
|
||||||
|
|
||||||
[wlroots]: https://gitlab.freedesktop.org/wlroots
|
#### Hacking
|
||||||
[`systemd --user`]: https://wiki.archlinux.org/title/Systemd/User
|
```bash
|
||||||
[#dwl on Libera Chat]: https://web.libera.chat/?channels=#dwl
|
# Instantiate *pure* devshell
|
||||||
[0.7-rc1]: https://codeberg.org/dwl/dwl/releases/tag/v0.7-rc1
|
# provides: `mk` alias for preconfigured gmake
|
||||||
[0.x branch]: https://codeberg.org/dwl/dwl/branches
|
nix develop -i
|
||||||
[anopa]: https://jjacky.com/anopa/
|
mk
|
||||||
[dinit]: https://davmac.org/projects/dinit/
|
```
|
||||||
[dwl-patches]: https://codeberg.org/dwl/dwl-patches
|
|
||||||
[list of useful resources on our wiki]: https://codeberg.org/dwl/dwl/wiki/Home#migrating-from-x
|
|
||||||
[main]: https://codeberg.org/dwl/dwl/src/branch/main
|
|
||||||
[release]: https://codeberg.org/dwl/dwl/releases
|
|
||||||
[runit]: http://smarden.org/runit/faq.html#userservices
|
|
||||||
[s6]: https://skarnet.org/software/s6/
|
|
||||||
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots/
|
|
||||||
[wiki]: https://codeberg.org/dwl/dwl/wiki/Home#compatible-status-bars
|
|
||||||
[Discord server]: https://discord.gg/jJxZnrGPWN
|
|
||||||
[Wayland]: https://wayland.freedesktop.org/
|
|
||||||
|
|
|
||||||
404
client.h
404
client.h
|
|
@ -1,404 +0,0 @@
|
||||||
/*
|
|
||||||
* Attempt to consolidate unavoidable suck into one file, away from dwl.c. This
|
|
||||||
* file is not meant to be pretty. We use a .h file with static inline
|
|
||||||
* functions instead of a separate .c module, or function pointers like sway, so
|
|
||||||
* that they will simply compile out if the chosen #defines leave them unused.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Leave these functions first; they're used in the others */
|
|
||||||
static inline int
|
|
||||||
client_is_x11(Client *c)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
return c->type == X11;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct wlr_surface *
|
|
||||||
client_surface(Client *c)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c))
|
|
||||||
return c->surface.xwayland->surface;
|
|
||||||
#endif
|
|
||||||
return c->surface.xdg->surface;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
|
|
||||||
{
|
|
||||||
struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
|
|
||||||
struct wlr_surface *root_surface;
|
|
||||||
struct wlr_layer_surface_v1 *layer_surface;
|
|
||||||
Client *c = NULL;
|
|
||||||
LayerSurface *l = NULL;
|
|
||||||
int type = -1;
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
struct wlr_xwayland_surface *xsurface;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!s)
|
|
||||||
return -1;
|
|
||||||
root_surface = wlr_surface_get_root_surface(s);
|
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
|
|
||||||
c = xsurface->data;
|
|
||||||
type = c->type;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
|
|
||||||
l = layer_surface->data;
|
|
||||||
type = LayerShell;
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
|
|
||||||
while (xdg_surface) {
|
|
||||||
tmp_xdg_surface = NULL;
|
|
||||||
switch (xdg_surface->role) {
|
|
||||||
case WLR_XDG_SURFACE_ROLE_POPUP:
|
|
||||||
if (!xdg_surface->popup || !xdg_surface->popup->parent)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
|
|
||||||
|
|
||||||
if (!tmp_xdg_surface)
|
|
||||||
return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
|
|
||||||
|
|
||||||
xdg_surface = tmp_xdg_surface;
|
|
||||||
break;
|
|
||||||
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
|
|
||||||
c = xdg_surface->data;
|
|
||||||
type = c->type;
|
|
||||||
goto end;
|
|
||||||
case WLR_XDG_SURFACE_ROLE_NONE:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end:
|
|
||||||
if (pl)
|
|
||||||
*pl = l;
|
|
||||||
if (pc)
|
|
||||||
*pc = c;
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The others */
|
|
||||||
static inline void
|
|
||||||
client_activate_surface(struct wlr_surface *s, int activated)
|
|
||||||
{
|
|
||||||
struct wlr_xdg_toplevel *toplevel;
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
struct wlr_xwayland_surface *xsurface;
|
|
||||||
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
|
|
||||||
wlr_xwayland_surface_activate(xsurface, activated);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
|
|
||||||
wlr_xdg_toplevel_set_activated(toplevel, activated);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t
|
|
||||||
client_set_bounds(Client *c, int32_t width, int32_t height)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c))
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
|
|
||||||
XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0
|
|
||||||
&& (c->bounds.width != width || c->bounds.height != height)) {
|
|
||||||
c->bounds.width = width;
|
|
||||||
c->bounds.height = height;
|
|
||||||
return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline const char *
|
|
||||||
client_get_appid(Client *c)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c))
|
|
||||||
return c->surface.xwayland->class ? c->surface.xwayland->class : "broken";
|
|
||||||
#endif
|
|
||||||
return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id : "broken";
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_get_clip(Client *c, struct wlr_box *clip)
|
|
||||||
{
|
|
||||||
*clip = (struct wlr_box){
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
.width = c->geom.width - c->bw,
|
|
||||||
.height = c->geom.height - c->bw,
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c))
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
clip->x = c->surface.xdg->geometry.x;
|
|
||||||
clip->y = c->surface.xdg->geometry.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_get_geometry(Client *c, struct wlr_box *geom)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c)) {
|
|
||||||
geom->x = c->surface.xwayland->x;
|
|
||||||
geom->y = c->surface.xwayland->y;
|
|
||||||
geom->width = c->surface.xwayland->width;
|
|
||||||
geom->height = c->surface.xwayland->height;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
*geom = c->surface.xdg->geometry;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline Client *
|
|
||||||
client_get_parent(Client *c)
|
|
||||||
{
|
|
||||||
Client *p = NULL;
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c)) {
|
|
||||||
if (c->surface.xwayland->parent)
|
|
||||||
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (c->surface.xdg->toplevel->parent)
|
|
||||||
toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
|
|
||||||
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 *
|
|
||||||
client_get_title(Client *c)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c))
|
|
||||||
return c->surface.xwayland->title ? c->surface.xwayland->title : "broken";
|
|
||||||
#endif
|
|
||||||
return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title : "broken";
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
client_is_float_type(Client *c)
|
|
||||||
{
|
|
||||||
struct wlr_xdg_toplevel *toplevel;
|
|
||||||
struct wlr_xdg_toplevel_state state;
|
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c)) {
|
|
||||||
struct wlr_xwayland_surface *surface = c->surface.xwayland;
|
|
||||||
xcb_size_hints_t *size_hints = surface->size_hints;
|
|
||||||
if (surface->modal)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG)
|
|
||||||
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH)
|
|
||||||
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR)
|
|
||||||
|| wlr_xwayland_surface_has_window_type(surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
|
|
||||||
&& (size_hints->max_width == size_hints->min_width
|
|
||||||
|| size_hints->max_height == size_hints->min_height);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
toplevel = c->surface.xdg->toplevel;
|
|
||||||
state = toplevel->current;
|
|
||||||
return toplevel->parent || (state.min_width != 0 && state.min_height != 0
|
|
||||||
&& (state.min_width == state.max_width
|
|
||||||
|| state.min_height == state.max_height));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
client_is_rendered_on_mon(Client *c, Monitor *m)
|
|
||||||
{
|
|
||||||
/* This is needed for when you don't want to check formal assignment,
|
|
||||||
* but rather actual displaying of the pixels.
|
|
||||||
* Usually VISIBLEON suffices and is also faster. */
|
|
||||||
struct wlr_surface_output *s;
|
|
||||||
int unused_lx, unused_ly;
|
|
||||||
if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
|
|
||||||
return 0;
|
|
||||||
wl_list_for_each(s, &client_surface(c)->current_outputs, link)
|
|
||||||
if (s->output == m->wlr_output)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
client_is_stopped(Client *c)
|
|
||||||
{
|
|
||||||
int pid;
|
|
||||||
siginfo_t in = {0};
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c))
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
|
|
||||||
if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
|
|
||||||
/* This process is not our child process, while is very unlikely that
|
|
||||||
* it is stopped, in order to do not skip frames, assume that it is. */
|
|
||||||
if (errno == ECHILD)
|
|
||||||
return 1;
|
|
||||||
} else if (in.si_pid) {
|
|
||||||
if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
|
|
||||||
return 1;
|
|
||||||
if (in.si_code == CLD_CONTINUED)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
client_is_unmanaged(Client *c)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c))
|
|
||||||
return c->surface.xwayland->override_redirect;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
|
|
||||||
{
|
|
||||||
if (kb)
|
|
||||||
wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
|
|
||||||
kb->num_keycodes, &kb->modifiers);
|
|
||||||
else
|
|
||||||
wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_send_close(Client *c)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c)) {
|
|
||||||
wlr_xwayland_surface_close(c->surface.xwayland);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_set_border_color(Client *c, const float color[static 4])
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i < 4; i++)
|
|
||||||
wlr_scene_rect_set_color(c->border[i], color);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_set_fullscreen(Client *c, int fullscreen)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c)) {
|
|
||||||
wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_set_scale(struct wlr_surface *s, float scale)
|
|
||||||
{
|
|
||||||
wlr_fractional_scale_v1_notify_scale(s, scale);
|
|
||||||
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t
|
|
||||||
client_set_size(Client *c, uint32_t width, uint32_t height)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c)) {
|
|
||||||
wlr_xwayland_surface_configure(c->surface.xwayland,
|
|
||||||
c->geom.x + c->bw, c->geom.y + c->bw, width, height);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if ((int32_t)width == c->surface.xdg->toplevel->current.width
|
|
||||||
&& (int32_t)height == c->surface.xdg->toplevel->current.height)
|
|
||||||
return 0;
|
|
||||||
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_set_tiled(Client *c, uint32_t edges)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c)) {
|
|
||||||
wlr_xwayland_surface_set_maximized(c->surface.xwayland,
|
|
||||||
edges != WLR_EDGE_NONE, edges != WLR_EDGE_NONE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
|
|
||||||
>= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
|
|
||||||
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
|
|
||||||
} else {
|
|
||||||
wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
client_set_suspended(Client *c, int suspended)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c))
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
client_wants_focus(Client *c)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
return client_is_unmanaged(c)
|
|
||||||
&& wlr_xwayland_surface_override_redirect_wants_focus(c->surface.xwayland)
|
|
||||||
&& wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
client_wants_fullscreen(Client *c)
|
|
||||||
{
|
|
||||||
#ifdef XWAYLAND
|
|
||||||
if (client_is_x11(c))
|
|
||||||
return c->surface.xwayland->fullscreen;
|
|
||||||
#endif
|
|
||||||
return c->surface.xdg->toplevel->requested.fullscreen;
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
_VERSION = 0.8-dev
|
_VERSION = 0.8-dev
|
||||||
VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)`
|
VERSION = `git describe --tags --dirty 2>/dev/null || echo $(_VERSION)`
|
||||||
|
BINARY = crywl
|
||||||
|
DESCRIPTION = "dwm for Wayland"
|
||||||
|
|
||||||
PKG_CONFIG = pkg-config
|
PKG_CONFIG = pkg-config
|
||||||
|
|
||||||
|
|
@ -8,6 +10,12 @@ PREFIX = /usr/local
|
||||||
MANDIR = $(PREFIX)/share/man
|
MANDIR = $(PREFIX)/share/man
|
||||||
DATADIR = $(PREFIX)/share
|
DATADIR = $(PREFIX)/share
|
||||||
|
|
||||||
|
SRC = src
|
||||||
|
BUILD = build
|
||||||
|
OBJ = $(BUILD)/obj
|
||||||
|
INCLUDE = $(BUILD)/include
|
||||||
|
BIN = bin
|
||||||
|
|
||||||
WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19`
|
WLR_INCS = `$(PKG_CONFIG) --cflags wlroots-0.19`
|
||||||
WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19`
|
WLR_LIBS = `$(PKG_CONFIG) --libs wlroots-0.19`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
[Desktop Entry]
|
|
||||||
Name=dwl
|
|
||||||
Comment=dwm for Wayland
|
|
||||||
Exec=dwl
|
|
||||||
Type=Application
|
|
||||||
27
flake.lock
generated
Normal file
27
flake.lock
generated
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1755922037,
|
||||||
|
"narHash": "sha256-wY1+2JPH0ZZC4BQefoZw/k+3+DowFyfOxv17CN/idKs=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "b1b3291469652d5a2edb0becc4ef0246fff97a7c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-25.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
63
flake.nix
Normal file
63
flake.nix
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
description = "DWL Development Shell";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = {nixpkgs, ...}: let
|
||||||
|
system = "x86_64-linux";
|
||||||
|
enableXWayland = false;
|
||||||
|
in {
|
||||||
|
devShells."${system}".default = let
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
};
|
||||||
|
lib = nixpkgs.lib;
|
||||||
|
stdenv = pkgs.stdenv;
|
||||||
|
in
|
||||||
|
pkgs.mkShell {
|
||||||
|
packages = with pkgs;
|
||||||
|
[
|
||||||
|
# NativeBuildInputs
|
||||||
|
installShellFiles
|
||||||
|
pkg-config
|
||||||
|
wayland-scanner
|
||||||
|
|
||||||
|
# BuildInputs
|
||||||
|
libinput
|
||||||
|
xorg.libxcb
|
||||||
|
libxkbcommon
|
||||||
|
pixman
|
||||||
|
wayland
|
||||||
|
wayland-protocols
|
||||||
|
wlroots_0_19
|
||||||
|
]
|
||||||
|
++ lib.optionals enableXWayland
|
||||||
|
[
|
||||||
|
# XWayland
|
||||||
|
xorg.libX11
|
||||||
|
xorg.xcbutilwm
|
||||||
|
xwayland
|
||||||
|
];
|
||||||
|
|
||||||
|
shellHook = let
|
||||||
|
makeFlags =
|
||||||
|
lib.strings.concatStringsSep " "
|
||||||
|
([
|
||||||
|
"PKG_CONFIG=${stdenv.cc.targetPrefix}pkg-config"
|
||||||
|
"WAYLAND_SCANNER=wayland-scanner"
|
||||||
|
# "PREFIX=$(out)"
|
||||||
|
# "MANDIR=$(man)/share/man"
|
||||||
|
]
|
||||||
|
++ lib.optionals enableXWayland [
|
||||||
|
''XWAYLAND="-DXWAYLAND"''
|
||||||
|
''XLIBS="xcb xcb-icccm"''
|
||||||
|
]);
|
||||||
|
in ''
|
||||||
|
TERM=xterm-256color
|
||||||
|
alias mk='${makeFlags} make'
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
374
src/client.h
Normal file
374
src/client.h
Normal file
|
|
@ -0,0 +1,374 @@
|
||||||
|
/*
|
||||||
|
* Attempt to consolidate unavoidable suck into one file, away from dwl.c. This
|
||||||
|
* file is not meant to be pretty. We use a .h file with static inline
|
||||||
|
* functions instead of a separate .c module, or function pointers like sway, so
|
||||||
|
* that they will simply compile out if the chosen #defines leave them unused.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Leave these functions first; they're used in the others */
|
||||||
|
static inline int client_is_x11(Client *c) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
return c->type == X11;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct wlr_surface *client_surface(Client *c) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return c->surface.xwayland->surface;
|
||||||
|
#endif
|
||||||
|
return c->surface.xdg->surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc,
|
||||||
|
LayerSurface **pl) {
|
||||||
|
struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
|
||||||
|
struct wlr_surface *root_surface;
|
||||||
|
struct wlr_layer_surface_v1 *layer_surface;
|
||||||
|
Client *c = NULL;
|
||||||
|
LayerSurface *l = NULL;
|
||||||
|
int type = -1;
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
struct wlr_xwayland_surface *xsurface;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!s)
|
||||||
|
return -1;
|
||||||
|
root_surface = wlr_surface_get_root_surface(s);
|
||||||
|
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
|
||||||
|
c = xsurface->data;
|
||||||
|
type = c->type;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((layer_surface =
|
||||||
|
wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
|
||||||
|
l = layer_surface->data;
|
||||||
|
type = LayerShell;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
|
||||||
|
while (xdg_surface) {
|
||||||
|
tmp_xdg_surface = NULL;
|
||||||
|
switch (xdg_surface->role) {
|
||||||
|
case WLR_XDG_SURFACE_ROLE_POPUP:
|
||||||
|
if (!xdg_surface->popup || !xdg_surface->popup->parent)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
tmp_xdg_surface =
|
||||||
|
wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
|
||||||
|
|
||||||
|
if (!tmp_xdg_surface)
|
||||||
|
return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
|
||||||
|
|
||||||
|
xdg_surface = tmp_xdg_surface;
|
||||||
|
break;
|
||||||
|
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
|
||||||
|
c = xdg_surface->data;
|
||||||
|
type = c->type;
|
||||||
|
goto end;
|
||||||
|
case WLR_XDG_SURFACE_ROLE_NONE:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (pl)
|
||||||
|
*pl = l;
|
||||||
|
if (pc)
|
||||||
|
*pc = c;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The others */
|
||||||
|
static inline void client_activate_surface(struct wlr_surface *s,
|
||||||
|
int activated) {
|
||||||
|
struct wlr_xdg_toplevel *toplevel;
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
struct wlr_xwayland_surface *xsurface;
|
||||||
|
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
|
||||||
|
wlr_xwayland_surface_activate(xsurface, activated);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
|
||||||
|
wlr_xdg_toplevel_set_activated(toplevel, activated);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t client_set_bounds(Client *c, int32_t width,
|
||||||
|
int32_t height) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
|
||||||
|
XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION &&
|
||||||
|
width >= 0 && height >= 0 &&
|
||||||
|
(c->bounds.width != width || c->bounds.height != height)) {
|
||||||
|
c->bounds.width = width;
|
||||||
|
c->bounds.height = height;
|
||||||
|
return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *client_get_appid(Client *c) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return c->surface.xwayland->class ? c->surface.xwayland->class : "broken";
|
||||||
|
#endif
|
||||||
|
return c->surface.xdg->toplevel->app_id ? c->surface.xdg->toplevel->app_id
|
||||||
|
: "broken";
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_get_clip(Client *c, struct wlr_box *clip) {
|
||||||
|
*clip = (struct wlr_box){
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.width = c->geom.width - c->bw,
|
||||||
|
.height = c->geom.height - c->bw,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
clip->x = c->surface.xdg->geometry.x;
|
||||||
|
clip->y = c->surface.xdg->geometry.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_get_geometry(Client *c, struct wlr_box *geom) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c)) {
|
||||||
|
geom->x = c->surface.xwayland->x;
|
||||||
|
geom->y = c->surface.xwayland->y;
|
||||||
|
geom->width = c->surface.xwayland->width;
|
||||||
|
geom->height = c->surface.xwayland->height;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
*geom = c->surface.xdg->geometry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Client *client_get_parent(Client *c) {
|
||||||
|
Client *p = NULL;
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c)) {
|
||||||
|
if (c->surface.xwayland->parent)
|
||||||
|
toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (c->surface.xdg->toplevel->parent)
|
||||||
|
toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface,
|
||||||
|
&p, NULL);
|
||||||
|
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 *client_get_title(Client *c) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return c->surface.xwayland->title ? c->surface.xwayland->title : "broken";
|
||||||
|
#endif
|
||||||
|
return c->surface.xdg->toplevel->title ? c->surface.xdg->toplevel->title
|
||||||
|
: "broken";
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int client_is_float_type(Client *c) {
|
||||||
|
struct wlr_xdg_toplevel *toplevel;
|
||||||
|
struct wlr_xdg_toplevel_state state;
|
||||||
|
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c)) {
|
||||||
|
struct wlr_xwayland_surface *surface = c->surface.xwayland;
|
||||||
|
xcb_size_hints_t *size_hints = surface->size_hints;
|
||||||
|
if (surface->modal)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (wlr_xwayland_surface_has_window_type(
|
||||||
|
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_DIALOG) ||
|
||||||
|
wlr_xwayland_surface_has_window_type(
|
||||||
|
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_SPLASH) ||
|
||||||
|
wlr_xwayland_surface_has_window_type(
|
||||||
|
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_TOOLBAR) ||
|
||||||
|
wlr_xwayland_surface_has_window_type(
|
||||||
|
surface, WLR_XWAYLAND_NET_WM_WINDOW_TYPE_UTILITY)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size_hints && size_hints->min_width > 0 &&
|
||||||
|
size_hints->min_height > 0 &&
|
||||||
|
(size_hints->max_width == size_hints->min_width ||
|
||||||
|
size_hints->max_height == size_hints->min_height);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
toplevel = c->surface.xdg->toplevel;
|
||||||
|
state = toplevel->current;
|
||||||
|
return toplevel->parent || (state.min_width != 0 && state.min_height != 0 &&
|
||||||
|
(state.min_width == state.max_width ||
|
||||||
|
state.min_height == state.max_height));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int client_is_rendered_on_mon(Client *c, Monitor *m) {
|
||||||
|
/* This is needed for when you don't want to check formal assignment,
|
||||||
|
* but rather actual displaying of the pixels.
|
||||||
|
* Usually VISIBLEON suffices and is also faster. */
|
||||||
|
struct wlr_surface_output *s;
|
||||||
|
int unused_lx, unused_ly;
|
||||||
|
if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
|
||||||
|
return 0;
|
||||||
|
wl_list_for_each(s, &client_surface(c)->current_outputs,
|
||||||
|
link) if (s->output == m->wlr_output) return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int client_is_stopped(Client *c) {
|
||||||
|
int pid;
|
||||||
|
siginfo_t in = {0};
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
|
||||||
|
if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) < 0) {
|
||||||
|
/* This process is not our child process, while is very unlikely that
|
||||||
|
* it is stopped, in order to do not skip frames, assume that it is. */
|
||||||
|
if (errno == ECHILD)
|
||||||
|
return 1;
|
||||||
|
} else if (in.si_pid) {
|
||||||
|
if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
|
||||||
|
return 1;
|
||||||
|
if (in.si_code == CLD_CONTINUED)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int client_is_unmanaged(Client *c) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return c->surface.xwayland->override_redirect;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_notify_enter(struct wlr_surface *s,
|
||||||
|
struct wlr_keyboard *kb) {
|
||||||
|
if (kb)
|
||||||
|
wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes, kb->num_keycodes,
|
||||||
|
&kb->modifiers);
|
||||||
|
else
|
||||||
|
wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_send_close(Client *c) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c)) {
|
||||||
|
wlr_xwayland_surface_close(c->surface.xwayland);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_set_border_color(Client *c,
|
||||||
|
const float color[static 4]) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
wlr_scene_rect_set_color(c->border[i], color);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_set_fullscreen(Client *c, int fullscreen) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c)) {
|
||||||
|
wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_set_scale(struct wlr_surface *s, float scale) {
|
||||||
|
wlr_fractional_scale_v1_notify_scale(s, scale);
|
||||||
|
wlr_surface_set_preferred_buffer_scale(s, (int32_t)ceilf(scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t client_set_size(Client *c, uint32_t width,
|
||||||
|
uint32_t height) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c)) {
|
||||||
|
wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x + c->bw,
|
||||||
|
c->geom.y + c->bw, width, height);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if ((int32_t)width == c->surface.xdg->toplevel->current.width &&
|
||||||
|
(int32_t)height == c->surface.xdg->toplevel->current.height)
|
||||||
|
return 0;
|
||||||
|
return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width,
|
||||||
|
(int32_t)height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_set_tiled(Client *c, uint32_t edges) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c)) {
|
||||||
|
wlr_xwayland_surface_set_maximized(
|
||||||
|
c->surface.xwayland, edges != WLR_EDGE_NONE, edges != WLR_EDGE_NONE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
|
||||||
|
XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
|
||||||
|
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
|
||||||
|
} else {
|
||||||
|
wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel,
|
||||||
|
edges != WLR_EDGE_NONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void client_set_suspended(Client *c, int suspended) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int client_wants_focus(Client *c) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
return client_is_unmanaged(c) &&
|
||||||
|
wlr_xwayland_surface_override_redirect_wants_focus(
|
||||||
|
c->surface.xwayland) &&
|
||||||
|
wlr_xwayland_surface_icccm_input_model(c->surface.xwayland) !=
|
||||||
|
WLR_ICCCM_INPUT_MODEL_NONE;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int client_wants_fullscreen(Client *c) {
|
||||||
|
#ifdef XWAYLAND
|
||||||
|
if (client_is_x11(c))
|
||||||
|
return c->surface.xwayland->fullscreen;
|
||||||
|
#endif
|
||||||
|
return c->surface.xdg->toplevel->requested.fullscreen;
|
||||||
|
}
|
||||||
3085
src/main.c
Normal file
3085
src/main.c
Normal file
File diff suppressed because it is too large
Load diff
47
src/util.c
Normal file
47
src/util.c
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
/* See LICENSE.dwm file for copyright and license details. */
|
||||||
|
#include <fcntl.h>
|
||||||
|
#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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
51
util.c
51
util.c
|
|
@ -1,51 +0,0 @@
|
||||||
/* See LICENSE.dwm file for copyright and license details. */
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <fcntl.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue