From e6f26581bf22e266c5056eddfb264eca2efb6ef4 Mon Sep 17 00:00:00 2001 From: Timo Wilken Date: Thu, 11 Jul 2024 17:11:25 +0200 Subject: Wayland-based desktop support Add a separate home service to configure a Wayland-based desktop instead of an X11 one. Screensharing in Zoom doesn't work unfortunately, but it worked (at least for a while) through OBS. Waybar might need some work to bring it in line with the previous polybar configuration, especially in terms of aesthetics. --- tw/services/desktop.scm | 547 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 471 insertions(+), 76 deletions(-) (limited to 'tw/services/desktop.scm') 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))) @@ -399,6 +405,395 @@ show_border=1 (service-extension home-environment-variables-service-type home-environment) (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 . #("📶" + "📶" + "📶")) + (format . "{ifname}") + (format-ethernet . "🌐 ↓ {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 . #("" + "" + "" + "" + "" + "" + "" + ""))) + + (memory + (interval . 5) + (format . "RAM {used} GiB")) + + (battery + (states (medium . 80) (critical . 20)) + (format-discharging . "{icon} {capacity}% {power}W {time}") + (format-charging . "🔌 {capacity}% {power}W {time}") + (format-full . "") + (format-icons . #("🔋" + "🔋" + "🔋" + "🔋" + "🔋"))) + + (pulseaudio + (scroll-step . 1) + (format . "{icon} {volume}%") + (format-muted . "🔇") + (format-icons (default . #("🔈" + "🔉" + "🔊"))) + (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 . "🔕") (false . "")) + (format . "{icon}")) + + (clock + (format . "{:%a, %e %b %H:%M}") + (tooltip-format . "{calendar}") + (calendar + (mode . "year") + (mode-mon-col . 3) + (on-scroll . 1) + (format (months . "{}") + (days . "{}") + (weekdays . "{}") + (today . "{}")))) + + (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 (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 -- cgit v1.2.3