aboutsummaryrefslogtreecommitdiff
path: root/tw/services/desktop.scm
diff options
context:
space:
mode:
Diffstat (limited to 'tw/services/desktop.scm')
-rw-r--r--tw/services/desktop.scm547
1 files changed, 471 insertions, 76 deletions
diff --git a/tw/services/desktop.scm b/tw/services/desktop.scm
index 6d9edfa8..a602fdf3 100644
--- a/tw/services/desktop.scm
+++ b/tw/services/desktop.scm
@@ -4,7 +4,8 @@
#:use-module (gnu home services mail)
#:use-module (gnu home services mcron)
#:use-module (gnu home services shepherd)
- #:use-module ((gnu packages admin) #:select (ansible))
+ #:use-module (gnu home services sound)
+ #:use-module ((gnu packages admin) #:select (ansible shepherd))
#:use-module ((gnu packages aidc) #:select (qrencode))
#:use-module ((gnu packages bittorrent) #:select (transmission-remote-gtk))
#:use-module ((gnu packages calendar) #:select (khal))
@@ -13,7 +14,7 @@
#:use-module ((gnu packages compton) #:select (picom))
#:use-module ((gnu packages dav) #:select (vdirsyncer))
#:use-module ((gnu packages fonts) #:select (font-fira-code font-fira-sans font-google-noto font-google-noto-emoji font-google-noto-sans-cjk font-google-noto-serif-cjk font-hermit font-inconsolata font-libertinus font-openmoji))
- #:use-module ((gnu packages freedesktop) #:select (xdg-utils))
+ #:use-module ((gnu packages freedesktop) #:select (elogind wev wtype xdg-utils xdg-desktop-portal xdg-desktop-portal-wlr))
#:use-module ((gnu packages games) #:select (bsd-games))
#:use-module ((gnu packages gimp) #:select (gimp))
#:use-module ((gnu packages gl) #:select (mesa))
@@ -21,10 +22,11 @@
#:use-module ((gnu packages gnome-xyz) #:select (papirus-icon-theme))
#:use-module ((gnu packages gnuzilla) #:select (icecat))
#:use-module ((gnu packages graphviz) #:select (xdot))
+ #:use-module ((gnu packages image) #:select (grim slurp))
#:use-module ((gnu packages image-viewers) #:select (imv))
#:use-module ((gnu packages inkscape) #:select (inkscape))
#:use-module ((gnu packages libreoffice) #:select (libreoffice))
- #:use-module ((gnu packages linux) #:select (acpilight powertop radeontop))
+ #:use-module ((gnu packages linux) #:select (acpilight procps powertop radeontop))
#:use-module ((gnu packages mail) #:select (aerc khard))
#:use-module ((gnu packages messaging) #:select (nheko))
#:use-module ((gnu packages networking) #:select (blueman))
@@ -37,25 +39,24 @@
#:use-module ((gnu packages ssh) #:select (pdsh))
#:use-module ((gnu packages syndication) #:select (newsboat))
#:use-module ((gnu packages tcl) #:select (tk))
- #:use-module ((gnu packages terminals) #:select (kitty))
+ #:use-module ((gnu packages terminals) #:select (foot kitty))
#:use-module ((gnu packages tex) #:select (texlive-scheme-small texlive-latexmk texlive-moderncv texlive-fontawesome5 texlive-multirow texlive-arydshln texlive-libertine texlive-inconsolata texlive-newtx texlive-babel texlive-csquotes texlive-siunitx texlive-minted texlive-svg texlive-hyperref texlive-capt-of texlive-ulem texlive-trimspaces texlive-transparent texlive-graphics texlive-tools texlive-wrapfig texlive-amsmath texlive-amsfonts texlive-txfonts))
#:use-module ((gnu packages version-control) #:select (git))
- #:use-module ((gnu packages video) #:select (mpv))
+ #:use-module ((gnu packages video) #:select (mpv obs obs-pipewire-audio-capture))
#:use-module ((gnu packages web-browsers) #:select (lynx))
- #:use-module ((gnu packages wm) #:select (dunst polybar))
- #:use-module ((gnu packages xdisorg) #:select (arandr numlockx hsetroot rofi rofi-calc xclip xdotool xsel))
+ #:use-module ((gnu packages wm) #:select (dunst polybar swaybg swayfx swayidle swaylock waybar))
+ #:use-module ((gnu packages xdisorg) #:select (arandr numlockx hsetroot rofi rofi-calc rofi-wayland wl-clipboard wob xclip xdotool xsel))
#:use-module ((gnu packages xfce) #:select (xfce4-screenshooter))
#:use-module ((gnu packages xorg) #:select (xdpyinfo xev xfd xfontsel xinput xkill xprop xrandr xset xrdb xwininfo setxkbmap))
#:use-module ((games packages minecraft) #:select (prismlauncher))
#:use-module ((nongnu packages nvidia) #:select (nvda))
- #:use-module ((nongnu packages messaging) #:select (zoom))
#:use-module ((nongnu packages nvidia) #:select (nvidia-system-monitor))
#:use-module (gnu services configuration)
#:use-module (guix gexp)
#:use-module (guix packages)
#:use-module ((guix records) #:select (match-record))
#:use-module ((nongnu packages game-client) #:select (steam steam-nvidia))
- #:use-module ((nongnu packages messaging) #:select (zoom signal-desktop))
+ #:use-module ((nongnu packages messaging) #:select (signal-desktop))
#:use-module ((nongnu packages nvidia) #:select (nvda nvidia-system-monitor))
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-26)
@@ -67,15 +68,76 @@
#:use-module ((tw packages mail) #:select (mutt_oauth2.py))
#:use-module ((tw packages scanner) #:select (simple-scan/airscan))
#:use-module ((tw packages xorg) #:select (xcwd))
+ #:use-module ((tw packages zoom) #:select (zoom/wayland))
#:use-module (tw theme)
#:export (home-desktop-configuration
home-monitor-configuration
home-desktop-service-type
+ home-wayland-desktop-configuration
+ home-wayland-desktop-service-type
home-gaming-configuration
home-gaming-service-type
home-pim-configuration
home-pim-service-type))
+(define common-desktop-packages
+ (list
+ ;; CLI tools
+ bsd-games powertop (list git "send-email") pdsh qrencode
+ texlive-scheme-small texlive-latexmk
+ ;; For CV:
+ texlive-moderncv texlive-fontawesome5 texlive-multirow texlive-arydshln
+ texlive-libertine texlive-inconsolata texlive-newtx texlive-babel
+ texlive-csquotes texlive-siunitx
+ ;; For org-mode export:
+ texlive-minted texlive-svg texlive-hyperref texlive-capt-of texlive-ulem
+ texlive-trimspaces texlive-transparent texlive-graphics texlive-tools
+ texlive-wrapfig texlive-amsmath texlive-amsfonts texlive-libertine
+ texlive-newtx texlive-txfonts texlive-inconsolata
+
+ ;; Work
+ s3cmd python-alibuild python-alidistlint actionlint modules
+ python-tox python-setuptools-scm python-mypy
+ hashicorp-levant-bin hashicorp-nomad-bin
+ hashicorp-consul-bin hashicorp-vault-bin hashicorp-packer-bin
+ ansible vinagre
+
+ ;; Fonts
+ font-hermit font-inconsolata font-fira-code font-fira-sans font-libertinus
+ ;; Base Noto doesn't include CJK, so install those separately.
+ font-google-noto font-google-noto-sans-cjk font-google-noto-serif-cjk
+ font-google-noto-emoji font-openmoji ; for polybar
+ ;; Theming
+ papirus-icon-theme catppuccin-gtk-theme catppuccin-mocha-dark-cursors
+ ;; Games (larger games installed in ~/.guix-profile to avoid frequent huge downloads).
+ szio-solitaire prismlauncher
+ ;; 0ad flightgear freeciv simutrans/pak128 warzone2100 widelands pioneer
+
+ ;; GUI applications common to X11 and Wayland
+ ;; acpilight is a drop-in xbacklight replacement, as xbacklight doesn't work on my system.
+ acpilight blueman gimp inkscape icecat imv libreoffice mpv pulsemixer
+ simple-scan/airscan transmission-remote-gtk tk xdg-utils xdot zoom/wayland
+ zathura zathura-ps zathura-pdf-poppler
+ ungoogled-chromium ; needed e.g. for Interrail site & DRM video
+ dconf dconf-editor)) ; required for config by blueman, cozy, ...
+
+(define common-xdg-configs
+ `(("alibuild/disable-analytics" ; All alibuild needs is an empty file.
+ ,(plain-file "alibuild-disable-analytics" ""))
+ ("gtk-2.0/gtkrc" ,(local-file "files/gtk2.ini"))
+ ("gtk-3.0/settings.ini" ,(local-file "files/gtk3.ini"))
+ ("kdeglobals" ,catppuccin-kdeglobals)
+ ("mimeapps.list" ,(local-file "files/mimeapps.list"))
+ ("zathura/zathurarc" ,(local-file "files/zathurarc"))
+ ("zathura/catppuccin" ,catppuccin-zathura)))
+
+(define common-home-files
+ `((".icons/default/index.theme" ,(local-file "files/cursors.ini"))
+ ;; With #:recursive? #t, Guix keeps the files' permission bits, i.e. makes them executable.
+ (".local/bin/sessionmenu" ,(local-file "files/sessionmenu" #:recursive? #t))
+ (".local/bin/passmenu" ,(local-file "files/passmenu" #:recursive? #t))
+ (".local/bin/volume" ,(local-file "files/volume" #:recursive? #t))))
+
;; Desktop services, including monitor layout
@@ -145,48 +207,13 @@ to list zones and their types.")
(define (home-packages config)
"Install packages I use frequently."
- (list
- ;; CLI tools
- bsd-games powertop (list git "send-email") pdsh qrencode
- texlive-scheme-small texlive-latexmk
- ;; For CV:
- texlive-moderncv texlive-fontawesome5 texlive-multirow texlive-arydshln
- texlive-libertine texlive-inconsolata texlive-newtx texlive-babel
- texlive-csquotes texlive-siunitx
- ;; For org-mode export:
- texlive-minted texlive-svg texlive-hyperref texlive-capt-of texlive-ulem
- texlive-trimspaces texlive-transparent texlive-graphics texlive-tools
- texlive-wrapfig texlive-amsmath texlive-amsfonts texlive-libertine
- texlive-newtx texlive-txfonts texlive-inconsolata
-
- ;; Work
- s3cmd python-alibuild python-alidistlint actionlint modules
- python-tox python-setuptools-scm python-mypy
- hashicorp-levant-bin hashicorp-nomad-bin
- hashicorp-consul-bin hashicorp-vault-bin hashicorp-packer-bin
- ansible vinagre
-
+ (cons*
;; i3 and Xorg. i3 itself must be installed system-wide for gdm to pick it up.
- ;; acpilight is a drop-in xbacklight replacement, as xbacklight doesn't work on my system.
- acpilight arandr dunst gimp hsetroot inkscape icecat imv kitty libreoffice
- mpv polybar pulsemixer rofi rofi-calc simple-scan/airscan
- transmission-remote-gtk tk xdg-utils xdot xclip xcwd xdotool
+ arandr dunst hsetroot kitty polybar rofi rofi-calc xclip xcwd xdotool
xdpyinfo xev xfd xfontsel xinput xkill xprop xrandr xrdb xsel xset xwininfo
- xfce4-screenshooter zoom zathura zathura-ps zathura-pdf-poppler
- ungoogled-chromium ; needed e.g. for Interrail site & DRM video
- dconf dconf-editor ; required for config by blueman, cozy, ...
- ;; gnome-keyring ; installed system-wide; see system-configuration.scm
- ;; geoclue ; for redshift -- installed system-wide
- ;; Fonts
- font-hermit font-inconsolata font-fira-code font-fira-sans font-libertinus
- ;; Base Noto doesn't include CJK, so install those separately.
- font-google-noto font-google-noto-sans-cjk font-google-noto-serif-cjk
- font-google-noto-emoji font-openmoji ; for polybar
- ;; Theming
- papirus-icon-theme catppuccin-gtk-theme catppuccin-mocha-dark-cursors
- ;; Games (larger games installed in ~/.guix-profile to avoid frequent huge downloads).
- ;; 0ad flightgear freeciv simutrans/pak128 warzone2100 widelands pioneer
- szio-solitaire prismlauncher))
+ xfce4-screenshooter ; only supports X11 for now: https://gitlab.xfce.org/apps/xfce4-screenshooter/-/merge_requests/52
+
+ common-desktop-packages))
(define xfce4-screenshooter.conf
(mixed-text-file "xfce4-screenshooter.conf" "\
@@ -206,20 +233,15 @@ show_border=1
(define (home-xdg-configs config)
"Configuration files that follow the XDG basedir spec."
- `(("alibuild/disable-analytics" ; All alibuild needs is an empty file.
- ,(plain-file "alibuild-disable-analytics" ""))
- ;; X11 environment configuration.
- ("X11/XCompose" ,(local-file "files/XCompose")) ; see also: $XCOMPOSEFILE variable
+ `(;; X11 environment configuration.
+ ("X11/XCompose" ,(local-file "files/XCompose")) ; see also: $XCOMPOSEFILE variable
;; Configuration files for GUI programs in $XDG_CONFIG_HOME. Some
;; of these may also work under Wayland, but some are X11-specific.
("dunst/dunstrc" ,(local-file "files/dunstrc"))
("dunst/dunstrc.d/50-catppuccin.conf" ,catppuccin-dunstrc)
- ("gtk-2.0/gtkrc" ,(local-file "files/gtk2.ini"))
- ("gtk-3.0/settings.ini" ,(local-file "files/gtk3.ini"))
("i3/config" ,(local-file "files/i3.conf"))
;; TODO: "kdeglobals" works for some programs (e.g. kdeconnect-app),
;; but not for others (e.g. nheko, kdeconnect-settings)...
- ("kdeglobals" ,catppuccin-kdeglobals)
("kitty/diff.conf"
,(combined-text-file "kitty-diff.conf"
(plain-file "kitty-diff-custom.conf"
@@ -229,19 +251,16 @@ show_border=1
,(combined-text-file "kitty.conf"
(local-file "files/kitty.conf")
catppuccin-kitty))
- ("mimeapps.list" ,(local-file "files/mimeapps.list"))
("polybar/config.ini" ,(local-file "files/polybar.ini"))
("polybar/catppuccin.ini" ,catppuccin-polybar)
("rofi/config.rasi" ,(local-file "files/rofi.rasi"))
("rofi/themes/catppuccin.rasi" ,catppuccin-rofi)
("xfce4/xfce4-screenshooter" ,xfce4-screenshooter.conf)
- ("zathura/zathurarc" ,(local-file "files/zathurarc"))
- ("zathura/catppuccin" ,catppuccin-zathura)))
+ ,@common-xdg-configs))
(define (home-files config)
"Extra configuration files and binaries that don't follow the XDG spec."
- `((".icons/default/index.theme" ,(local-file "files/cursors.ini"))
- ;; https://sw.kovidgoyal.net/kitty/kittens/diff/
+ `(;; https://sw.kovidgoyal.net/kitty/kittens/diff/
(".local/bin/kdiff" ; show a diff
,(program-file "kdiff"
#~(apply execl #$(file-append kitty "/bin/kitty") "kitty"
@@ -259,21 +278,7 @@ show_border=1
;; setuid binary for i3lock installed by the system config.
(system* "i3lock" "-nc" #$catppuccin-background-color)
(system* #$(file-append xset "/bin/xset") "dpms" "600" "600" "600")
- (system* #$(file-append dunst "/bin/dunstctl") "set-paused" "false"))))
- ;; With #:recursive? #t, Guix keeps the files' permission bits, i.e. makes them executable.
- (".local/bin/sessionmenu" ,(local-file "files/sessionmenu" #:recursive? #t))
- (".local/bin/passmenu" ,(local-file "files/passmenu" #:recursive? #t))
- (".local/bin/volume" ,(local-file "files/volume" #:recursive? #t))
- (".local/bin/alienv.guix"
- ,(program-file "alienv.guix"
- #~(begin
- (setenv "TERM" "xterm-256color") ; "modules" gets confused if this is unset
- (apply execlp "guix" "guix" "shell" "--pure" "--container" "--emulate-fhs" "--preserve=^TERM$"
- "bash" "util-linux" "coreutils" ; basic shell utilities (also needed by alienv)
- "which" "sed" "grep" "findutils" "procps" "gawk" "modules" ; alienv requirements
- "openssl@3" ; some packages need openssl
- "xz" ; XRootD needs liblzma
- "python-alibuild" "--" "alienv" (cdr (command-line))))))))
+ (system* #$(file-append dunst "/bin/dunstctl") "set-paused" "false"))))))
(define (home-environment config)
`(("TERMINAL" . "kitty")
@@ -303,6 +308,7 @@ show_border=1
,(shepherd-service
(documentation "Blueman applet; provides a GUI for connection to bluetooth devices.")
(provision '(blueman-applet))
+ (requirement '(x11-display))
(start #~(make-forkexec-constructor
(list #$(file-append blueman "/bin/blueman-applet"))))
(stop #~(make-kill-destructor)))
@@ -400,6 +406,395 @@ show_border=1
(service-extension home-shepherd-service-type home-shepherd-services)))))
+;;; Wayland-based desktop services
+
+(define-configuration/no-serialization home-wayland-desktop-configuration
+ (num-cores integer "Number of cores on the system. Used for waybar CPU
+display."))
+
+(define (home-wayland-packages config)
+ "Install packages I use frequently."
+ ;; Wayland-specific desktop tools
+ (cons* swayfx dunst foot grim rofi-wayland slurp swaybg wev wob wtype wl-clipboard
+ obs obs-pipewire-audio-capture ; to hack screen sharing
+ xdg-desktop-portal xdg-desktop-portal-wlr ; to set XDG_DESKTOP_PORTAL_DIR search path
+ common-desktop-packages))
+
+(define %waybar-dunst-signal 13)
+
+(define (waybar-configuration num-cores)
+ ;; For documentation, see:
+ ;; https://github.com/Alexays/Waybar/wiki/Configuration
+ (json-file "waybar.json"
+ `((reload_style_on_change . #t)
+ (layer . "top") ; put top bar above other windows' shadows
+
+ (modules-left . #("sway/mode" "sway/workspaces" "sway/window"))
+ (modules-center . #())
+ (modules-right . #("network" "memory" "cpu" "temperature"
+ "keyboard-state" "privacy" "pulseaudio" "battery"
+ "clock" "custom/dunst" "tray"))
+
+ (sway/workspaces (all-outputs . #t) (format . "{name}"))
+ (sway/window (max-length . 80) (icon . #t) (icon-size . 16))
+
+ (network
+ (interval . 10)
+ (icons . #("<span face='OpenMoji' fallback='false' color='#f38ba8'>📶</span>"
+ "<span face='OpenMoji' fallback='false' color='#f9e2af'>📶</span>"
+ "<span face='OpenMoji' fallback='false' color='#a6e3a1'>📶</span>"))
+ (format . "{ifname}")
+ (format-ethernet . "<span face='OpenMoji' fallback='false'>🌐</span> ↓ {bandwidthDownBytes} ↑ {bandwidthUpBytes}")
+ (format-wifi . "{icon} {essid} ↓ {bandwidthDownBytes} ↑ {bandwidthUpBytes}")
+ (tooltip-format . "{ifname}")
+ (tooltip-format-wifi . "{ifname}: {ipaddr} ({signalStrength}%, {frequency}GHz)")
+ (tooltip-format-ethernet . "{ifname}: {ipaddr} ({bandwidthTotalBytes}B/s)"))
+
+ (cpu
+ (interval . 2)
+ (format . ,(apply string-append (map (cut format #f "{icon~d}" <>)
+ (iota num-cores))))
+ (format-icons . #("<span color='#585b70'>▁</span>"
+ "<span color='#cdd6f4'>▂</span>"
+ "<span color='#cdd6f4'>▃</span>"
+ "<span color='#cdd6f4'>▄</span>"
+ "<span color='#cdd6f4'>▅</span>"
+ "<span color='#cdd6f4'>▆</span>"
+ "<span color='#f9e2af'>▇</span>"
+ "<span color='#f9e2af'>█</span>")))
+
+ (memory
+ (interval . 5)
+ (format . "<span color='#cdd6f4'>RAM</span> {used} GiB"))
+
+ (battery
+ (states (medium . 80) (critical . 20))
+ (format-discharging . "{icon} {capacity}% {power}W {time}")
+ (format-charging . "<span face='OpenMoji' fallback='false'>🔌</span> {capacity}% {power}W {time}")
+ (format-full . "")
+ (format-icons . #("<span face='OpenMoji' fallback='false' color='#f38ba8'>🔋</span>"
+ "<span face='OpenMoji' fallback='false' color='#f9e2af'>🔋</span>"
+ "<span face='OpenMoji' fallback='false' color='#f9e2af'>🔋</span>"
+ "<span face='OpenMoji' fallback='false' color='#f9e2af'>🔋</span>"
+ "<span face='OpenMoji' fallback='false' color='#a6e3a1'>🔋</span>")))
+
+ (pulseaudio
+ (scroll-step . 1)
+ (format . "{icon} {volume}%")
+ (format-muted . "<span face='OpenMoji' fallback='false'>🔇</span>")
+ (format-icons (default . #("<span face='OpenMoji' fallback='false'>🔈</span>"
+ "<span face='OpenMoji' fallback='false'>🔉</span>"
+ "<span face='OpenMoji' fallback='false'>🔊</span>")))
+ (tooltip-format . "{desc}: {volume}%")
+ (on-click . "volume toggle-mute")
+ (on-click-right . "foot pulsemixer"))
+
+ (keyboard-state (capslock . #t))
+
+ (custom/dunst
+ (exec . "echo '{\"alt\": \"'$(dunstctl is-paused)'\"}'")
+ (return-type . "json")
+ (interval . 10)
+ (signal . ,%waybar-dunst-signal) ; SIGRTMIN + %waybar-dunst-signal
+ (format-icons (true . "<span face='OpenMoji' fallback='false'>🔕</span>") (false . ""))
+ (format . "{icon}"))
+
+ (clock
+ (format . "{:%a, %e %b %H:%M}")
+ (tooltip-format . "<tt><small>{calendar}</small></tt>")
+ (calendar
+ (mode . "year")
+ (mode-mon-col . 3)
+ (on-scroll . 1)
+ (format (months . "<span color='#f9e2af'><b>{}</b></span>")
+ (days . "<span color='#cdd6f4'>{}</span>")
+ (weekdays . "<span color='#fab387'><b>{}</b></span>")
+ (today . "<span color='#f38ba8'><b><u>{}</u></b></span>"))))
+
+ (tray (icon-size . 16) (spacing . 4)))))
+
+(define-public %sway-common-configuration
+ (mixed-text-file "sway-greetd.conf" "\
+font pango:Fira Sans 10
+
+input type:keyboard {
+ xkb_layout \"gb\"
+ xkb_options \"caps:swapescape,parens:swap_brackets,terminate:ctrl_alt_bksp,compose:rctrl,keypad:oss,kpdl:kposs\"
+ xkb_numlock enabled
+}
+
+input type:touchpad {
+ # libinput configuration for touchpad
+ dwt enabled # 'disabled while typing'
+ middle_emulation enabled
+ natural_scroll enabled
+ click_method clickfinger
+ scroll_method two_finger
+ tap enabled
+ tap_button_map lrm
+ drag enabled
+ drag_lock disabled
+}
+
+output * background " tw-background "/share/backgrounds/tw/blobs.png fill
+
+# swayfx effects
+blur enable
+shadows enable
+corner_radius 6
+"))
+
+(define (home-wayland-xdg-configs config)
+ ;; Wayland also uses the XCompose file.
+ (match-record config <home-wayland-desktop-configuration> (num-cores)
+ `(("X11/XCompose" ,(local-file "files/XCompose")) ; see also: $XCOMPOSEFILE variable
+ ("dunst/dunstrc" ,(local-file "files/dunstrc"))
+ ("dunst/dunstrc.d/50-catppuccin.conf" ,catppuccin-dunstrc)
+ ("foot/foot.ini" ,(local-file "files/foot.ini"))
+ ("foot/catppuccin.ini" ,catppuccin-foot)
+ ("rofi/config.rasi" ,(local-file "files/rofi.rasi"))
+ ("rofi/themes/catppuccin.rasi" ,catppuccin-rofi)
+ ("sway/config"
+ ,(combined-text-file "sway.conf"
+ %sway-common-configuration
+ (local-file "files/sway.conf")))
+ ("swaylock/config"
+ ,(combined-text-file "swaylock.conf"
+ (mixed-text-file "swaylock-settings.conf"
+ "image=" tw-background "/share/backgrounds/tw/blobs.png\n"
+ "scaling=fill\n"
+ "font=Fira Sans\n"
+ "font-size=12\n"
+ "indicator-idle-visible\n"
+ "show-keyboard-layout\n"
+ "show-failed-attempts\n")
+ catppuccin-swaylock))
+ ("waybar/config.jsonc" ,(waybar-configuration num-cores))
+ ("waybar/style.css" ,(local-file "files/waybar.css"))
+ ("waybar/catppuccin.css" ,catppuccin-waybar)
+ ,@common-xdg-configs)))
+
+(define (home-wayland-files config)
+ common-home-files)
+
+(define (home-wayland-environment config)
+ `(;; Smooth trackpad scrolling in Firefox/Icecat.
+ ;; https://wiki.archlinux.org/index.php/Firefox/Tweaks#Pixel-perfect_trackpad_scrolling
+ ("MOZ_ENABLE_WAYLAND" . "1")
+ ("TERMINAL" . "foot") ; needed for rofi-sensible-terminal
+ ("QT_QPA_PLATFORM" . "wayland") ; needed for Qt apps, e.g. obs
+ ("XDG_CURRENT_DESKTOP" . "sway") ; not sure why this isn't set by default
+ ("_JAVA_OPTIONS" .
+ ,(string-append
+ "$_JAVA_OPTIONS${_JAVA_OPTIONS:+ }"
+ "-Dawt.useSystemAAFontSettings=on -Dswing.aatext=true "
+ "-Dswing.defaultlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel "
+ "-Dswing.crossplatformlaf=com.sun.java.swing.plaf.gtk.GTKLookAndFeel"))))
+
+(define wayland-screenlock-program
+ ;; Wrapper around swaylock to turn off the screen and pause notifications.
+ (program-file "wayland-screenlock"
+ ;; If swaylock is already running, don't lock again.
+ #~(unless (zero? (status:exit-val
+ (system* #$(file-append procps "/bin/pgrep")
+ "-xU" (number->string (getuid)) "swaylock")))
+ ;; Rely on swayidle to turn off the screen after a timeout.
+ (system* #$(file-append dunst "/bin/dunstctl") "set-paused" "true")
+ (system* #$(file-append shepherd "/bin/herd") "kick-dunst" "waybar")
+ (system* #$(file-append swaylock "/bin/swaylock"))
+ (system* #$(file-append dunst "/bin/dunstctl") "set-paused" "false")
+ (system* #$(file-append shepherd "/bin/herd") "kick-dunst" "waybar"))))
+
+(define (home-wayland-shepherd-services config)
+ (define wayland-environment-variables
+ (let ((vars '("XDG_RUNTIME_DIR" "WAYLAND_DISPLAY" "SWAYSOCK")))
+ #~(cons*
+ #$@(map (lambda (var) #~(string-append #$var "=" (getenv #$var))) vars)
+ (filter (lambda (assignment)
+ (not (or #$@(map (lambda (var)
+ #~(string-prefix? #$(string-append var "=") assignment))
+ vars))))
+ (default-environment-variables)))))
+
+ (list
+ (shepherd-service ; adjusted from Guix x11-display service
+ (provision '(wayland-display))
+ (modules '((ice-9 ftw)
+ (ice-9 match)
+ (ice-9 receive)
+ (srfi srfi-1)))
+ (start
+ #~(lambda* (#:optional
+ (display (getenv "WAYLAND_DISPLAY"))
+ (swaysock (getenv "SWAYSOCK")))
+ (define runtime-directory
+ (or (getenv "XDG_RUNTIME_DIR")
+ (format #f "/run/user/~d" (getuid))))
+
+ (define (correct-socket? prefix)
+ (lambda (name)
+ (let ((path (in-vicinity runtime-directory name)))
+ (and (string-prefix? prefix name)
+ (eq? 'socket (stat:type (stat path)))
+ (access? path O_RDWR)))))
+
+ (define (find-display delay)
+ ;; Wait for an accessible socket to show up in RUNTIME-DIRECTORY,
+ ;; up to DELAY seconds.
+ (let loop ((attempts delay))
+ (define wayland-socket
+ (find (correct-socket? "wayland-")
+ (or (scandir runtime-directory) '())))
+ (define sway-socket
+ (find (correct-socket? "sway-ipc.")
+ (or (scandir runtime-directory) '())))
+
+ (cond
+ ((and wayland-socket sway-socket)
+ (let ((swaysock (in-vicinity runtime-directory sway-socket)))
+ (format #t "Wayland server found at ~s. Sway socket found at ~s.~%"
+ wayland-socket swaysock)
+ (values wayland-socket swaysock)))
+ ((zero? attempts)
+ (format (current-error-port)
+ "Wayland server or Sway socket did not show up; giving up.~%")
+ (values #f #f))
+ (else (sleep 1) (loop (- attempts 1))))))
+
+ (receive (wayland-socket sway-socket) (find-display 10)
+ (let ((display (or display wayland-socket))
+ (swaysock (or swaysock sway-socket)))
+ (setenv "XDG_RUNTIME_DIR" runtime-directory)
+ (when display
+ (setenv "WAYLAND_DISPLAY" display))
+ (when swaysock
+ (setenv "SWAYSOCK" swaysock))
+ display))))
+ (stop #~(lambda _
+ (unsetenv "WAYLAND_DISPLAY")
+ (unsetenv "SWAYSOCK")
+ #f))
+ (respawn? #f))
+
+ ;; Using `make-forkexec-constructor' does not work because we need to
+ ;; inherit the variables from `wayland-display' at start time, not at
+ ;; definition time.
+ (shepherd-service
+ (documentation "NetworkManager applet; provides a GUI for network connections.")
+ (provision '(nm-applet))
+ (requirement '(wayland-display))
+ (start #~(lambda _
+ (fork+exec-command
+ (list #$(file-append network-manager-applet "/bin/nm-applet"))
+ #:environment-variables #$wayland-environment-variables)))
+ (stop #~(make-kill-destructor)))
+
+ (shepherd-service
+ (documentation "Blueman applet; provides a GUI for connection to bluetooth devices.")
+ (provision '(blueman-applet))
+ (requirement '(wayland-display))
+ (start #~(lambda _
+ (fork+exec-command
+ (list #$(file-append blueman "/bin/blueman-applet"))
+ #:environment-variables #$wayland-environment-variables)))
+ (stop #~(make-kill-destructor)))
+
+ (shepherd-service
+ (documentation "Dunst notification daemon; displays desktop notifications.")
+ (provision '(dunst))
+ (requirement '(wayland-display))
+ (start #~(lambda _
+ (fork+exec-command
+ (list #$(file-append dunst "/bin/dunst"))
+ #:environment-variables #$wayland-environment-variables)))
+ (stop #~(make-kill-destructor)))
+
+ (shepherd-service
+ (documentation "XDG desktop portal dispatcher.")
+ (provision '(xdg-desktop-portal))
+ (requirement '(wayland-display dbus))
+ (start #~(lambda _
+ (fork+exec-command
+ (list #$(file-append xdg-desktop-portal
+ "/libexec/xdg-desktop-portal") "-rv")
+ #:environment-variables
+ (cons* "XDG_CURRENT_DESKTOP=sway"
+ #;(string-append "XDG_DESKTOP_PORTAL_DIR=" #$xdg-desktop-portal-wlr
+ "/share/xdg-desktop-portal/portals")
+ #$wayland-environment-variables))))
+ (stop #~(make-kill-destructor)))
+
+ (shepherd-service
+ (documentation "Screen sharing support for wlroots-based compositors.")
+ (provision '(xdg-desktop-portal-wlr))
+ (requirement '(xdg-desktop-portal wayland-display dbus))
+ (start #~(lambda _
+ (fork+exec-command
+ (list #$(file-append xdg-desktop-portal-wlr
+ "/libexec/xdg-desktop-portal-wlr") "-rl" "DEBUG")
+ #:environment-variables
+ (cons* "XDG_CURRENT_DESKTOP=sway"
+ #$wayland-environment-variables))))
+ (stop #~(make-kill-destructor)))
+
+ (shepherd-service
+ (documentation "Waybar desktop status bar daemon.")
+ (provision '(waybar))
+ (requirement '(wayland-display))
+ (start #~(lambda _
+ (fork+exec-command
+ (list #$(file-append waybar "/bin/waybar"))
+ #:environment-variables #$wayland-environment-variables)))
+ (stop #~(make-kill-destructor))
+ (actions
+ (list (shepherd-action
+ (name 'kick-dunst)
+ (documentation "Tell waybar to update its Dunst status.")
+ (procedure #~(lambda (waybar-pid . args)
+ ;; See magic constant defined in waybar.jsonc.
+ (kill waybar-pid (+ SIGRTMIN #$%waybar-dunst-signal))
+ #t))))))
+
+ (let ((swayidle.conf
+ (mixed-text-file "swayidle.conf"
+ "lock '" wayland-screenlock-program "' \n"
+ "unlock '" procps "/bin/pkill -x -USR1 swaylock'\n"
+ "before-sleep '" elogind "/bin/loginctl lock-session'\n"
+ "timeout 300 '" elogind "/bin/loginctl lock-session && "
+ swayfx "/bin/swaymsg \"output * power off\"' " ; no newline!
+ "resume '" swayfx "/bin/swaymsg \"output * power on\"'\n"
+ "timeout 600 '" elogind "/bin/loginctl suspend'\n")))
+ (shepherd-service
+ (documentation "Manage the screen when idle or locked.")
+ (provision '(swayidle))
+ (requirement '(wayland-display))
+ (start #~(lambda _
+ (fork+exec-command
+ (list #$(file-append swayidle "/bin/swayidle") "-C" #$swayidle.conf)
+ #:environment-variables #$wayland-environment-variables)))
+ (stop #~(make-kill-destructor))
+ (actions
+ (list (shepherd-configuration-action swayidle.conf)
+ (shepherd-action
+ (name 'idle)
+ (documentation "Immediately enter idle state.")
+ (procedure #~(lambda (swayidle-pid . args)
+ (kill swayidle-pid SIGUSR1)
+ #t)))))))))
+
+(define home-wayland-desktop-service-type
+ (service-type
+ (name 'wayland-desktop)
+ (description "Configure a Wayland-based desktop environment.")
+ (extensions
+ (list (service-extension home-profile-service-type home-wayland-packages)
+ (service-extension home-xdg-configuration-files-service-type home-wayland-xdg-configs)
+ (service-extension home-files-service-type home-wayland-files)
+ (service-extension home-environment-variables-service-type home-wayland-environment)
+ (service-extension home-pipewire-service-type (const #t))
+ (service-extension home-shepherd-service-type home-wayland-shepherd-services)))))
+
+
;;; Gaming servicse
(define-configuration/no-serialization home-gaming-configuration