mirror of
https://git.savannah.gnu.org/git/guix.git
synced 2025-01-19 05:57:04 +01:00
b64f7984a5
* gnu/home/services/sway.scm: New file. (home-sway-service-type): New variable. (sway-configuration->file): New procedure. (sway-configuration): New configuration record. (sway-bar): New configuration record. (sway-output): New configuration record. (sway-input): New configuration record. (point): New configuration record. (sway-color): New configuration record. (sway-border-color): New configuration record. (sway-mode): New configuration record. (flatmap): New procedure. * gnu/local.mk: Add gnu/home/services/sway.scm. * doc/guix.texi (Sway window manager): New node to document the above changes. Signed-off-by: Florian Pelz <pelzflorian@pelzflorian.de> Change-Id: I880261570c5afdb795f2ce18bac2b9a5c898677f
870 lines
28 KiB
Scheme
870 lines
28 KiB
Scheme
;;; GNU Guix --- Functional package management for GNU
|
||
;;; Copyright © 2024 Arnaud Daby-Seesaram <ds-ac@nanein.fr>
|
||
;;;
|
||
;;; This file is part of GNU Guix.
|
||
;;;
|
||
;;; GNU Guix is free software; you can redistribute it and/or modify it
|
||
;;; under the terms of the GNU General Public License as published by
|
||
;;; the Free Software Foundation; either version 3 of the License, or (at
|
||
;;; your option) any later version.
|
||
;;;
|
||
;;; GNU Guix is distributed in the hope that it will be useful, but
|
||
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
;;; GNU General Public License for more details.
|
||
;;;
|
||
;;; You should have received a copy of the GNU General Public License
|
||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||
|
||
(define-module (gnu home services sway)
|
||
#:use-module (guix modules)
|
||
#:use-module (guix gexp)
|
||
#:use-module (srfi srfi-1)
|
||
#:use-module (ice-9 match)
|
||
#:use-module (guix packages)
|
||
#:use-module (gnu system keyboard)
|
||
#:use-module (gnu services configuration)
|
||
#:use-module (gnu home services)
|
||
#:use-module (gnu packages wm)
|
||
#:use-module (gnu packages terminals)
|
||
#:export (;; Event codes
|
||
%ev-code-mouse-left
|
||
%ev-code-mouse-right
|
||
%ev-code-mouse-scroll-click
|
||
|
||
;; Configuration records.
|
||
sway-configuration
|
||
sway-bar
|
||
sway-output
|
||
sway-input
|
||
point
|
||
sway-color
|
||
sway-border-color
|
||
home-sway-service-type
|
||
sway-configuration->file
|
||
sway-mode
|
||
|
||
;; Default values.
|
||
%sway-default-variables
|
||
%sway-default-gestures
|
||
%sway-default-modes
|
||
%sway-default-keybindings
|
||
%sway-default-startup-programs
|
||
%sway-default-packages))
|
||
|
||
;; Helper function.
|
||
(define (flatmap f l)
|
||
(let loop ((lst (reverse l)) (acc '()))
|
||
(match lst
|
||
(() acc)
|
||
((head . tail)
|
||
(let* ((h (f head))
|
||
(acc (append h acc)))
|
||
(loop tail acc))))))
|
||
|
||
|
||
;;;
|
||
;;; Definition of configurations.
|
||
;;;
|
||
|
||
(define (string-ish? s)
|
||
(or (gexp? s)
|
||
(file-like? s)
|
||
(string? s)))
|
||
|
||
(define (string-or-gexp? s)
|
||
(or (gexp? s)
|
||
(string? s)))
|
||
|
||
(define (list-of-string-ish? lst)
|
||
(every string-ish? lst))
|
||
|
||
(define (list-of-packages? lst)
|
||
(every package? lst))
|
||
|
||
(define (bar-position? p)
|
||
(member p '(top bottom)))
|
||
|
||
(define (hidden-state? st)
|
||
(member st '(hide show)))
|
||
|
||
(define (string-or-symbol? s)
|
||
(or (string? s)
|
||
(symbol? s)))
|
||
|
||
(define (strings? lst)
|
||
(every string? lst))
|
||
|
||
(define (extra-content? extra)
|
||
(every string-or-gexp? extra))
|
||
|
||
(define (make-alist-predicate key? val?)
|
||
(lambda (lst)
|
||
(every
|
||
(lambda (item)
|
||
(match item
|
||
((k . v)
|
||
(and (key? k)
|
||
(val? v)))
|
||
(_ #f)))
|
||
lst)))
|
||
|
||
(define bindings?
|
||
(make-alist-predicate symbol? string-or-gexp?))
|
||
|
||
(define mouse-bindings?
|
||
(make-alist-predicate integer? string-or-gexp?))
|
||
|
||
(define (variables? lst)
|
||
(make-alist-predicate symbol? string-ish?))
|
||
|
||
(define-maybe string (no-serialization))
|
||
(define-maybe strings (no-serialization))
|
||
(define-maybe boolean (no-serialization))
|
||
(define-maybe keyboard-layout (no-serialization))
|
||
|
||
(define-configuration/no-serialization sway-input
|
||
(identifier
|
||
(string-or-symbol '*)
|
||
"Identifier of the input.")
|
||
(layout
|
||
maybe-keyboard-layout
|
||
"Keyboard layout of the input.")
|
||
(disable-while-typing
|
||
maybe-boolean
|
||
"If `#t', disable the input while typing; if `#f' do not.")
|
||
(disable-while-trackpointing
|
||
maybe-boolean
|
||
"If `#t', disable the input while using a trackpoint; if `#f' do not.")
|
||
(tap
|
||
maybe-boolean
|
||
"Enable or disable tap.")
|
||
(extra-content
|
||
(extra-content '())
|
||
"Lines to add at the end of the configuration file."))
|
||
|
||
(define (sway-inputs? lst)
|
||
(every sway-input? lst))
|
||
|
||
(define-configuration/no-serialization sway-border-color
|
||
(border
|
||
string
|
||
"Border color.")
|
||
(background
|
||
string
|
||
"Background color.")
|
||
(text
|
||
string
|
||
"Text color."))
|
||
|
||
(define-maybe sway-border-color (no-serialization))
|
||
|
||
(define-configuration/no-serialization sway-color
|
||
(background
|
||
maybe-string
|
||
"Background color of the bar.")
|
||
(statusline
|
||
maybe-string
|
||
"Text color of the status line.")
|
||
(focused-background
|
||
maybe-string
|
||
"Background color of the bar on the currently focused monitor.")
|
||
(focused-statusline
|
||
maybe-string
|
||
"Text color of the statusline on the currently focused monitor.")
|
||
(focused-workspace
|
||
maybe-sway-border-color
|
||
"Color scheme for focused workspaces.")
|
||
(active-workspace
|
||
maybe-sway-border-color
|
||
"Color scheme for active workspaces.")
|
||
(inactive-workspace
|
||
maybe-sway-border-color
|
||
"Color scheme for inactive workspaces.")
|
||
(urgent-workspace
|
||
maybe-sway-border-color
|
||
"Color scheme for workspaces containing `urgent' windows.")
|
||
(binding-mode
|
||
maybe-sway-border-color
|
||
"Color scheme for the binding mode indicator."))
|
||
|
||
(define-maybe sway-color (no-serialization))
|
||
|
||
(define (status-command? c)
|
||
(or (string? c)
|
||
(file-like? c)
|
||
(gexp? c)))
|
||
|
||
(define-maybe bar-position (no-serialization))
|
||
(define-maybe hidden-state (no-serialization))
|
||
(define-maybe status-command (no-serialization))
|
||
|
||
(define-configuration/no-serialization sway-bar
|
||
(identifier
|
||
(symbol 'bar0)
|
||
"Identifier of the bar.")
|
||
(position
|
||
maybe-bar-position
|
||
"Position of the bar.")
|
||
(hidden-state
|
||
maybe-hidden-state
|
||
"Hidden state.")
|
||
(binding-mode-indicator
|
||
maybe-boolean
|
||
"Binding indicator.")
|
||
(colors
|
||
maybe-sway-color
|
||
"Color palette of the bar.")
|
||
(status-command
|
||
maybe-status-command
|
||
"Status command.")
|
||
(mouse-bindings
|
||
(mouse-bindings '())
|
||
"Actions triggered by mouse events.")
|
||
(extra-content
|
||
(extra-content '())
|
||
"Extra configuration lines."))
|
||
|
||
(define-maybe sway-bar (no-serialization))
|
||
|
||
(define-configuration/no-serialization point
|
||
(x integer "X coordinate.")
|
||
(y integer "Y coordinate."))
|
||
|
||
(define-maybe point (no-serialization))
|
||
|
||
(define (background? bg)
|
||
(or (string-ish? bg)
|
||
(and (pair? bg)
|
||
(string-ish? (car bg))
|
||
(member (cdr bg) '(stretch fill fit center tile)))))
|
||
|
||
(define-maybe background (no-serialization))
|
||
|
||
(define-configuration/no-serialization sway-output
|
||
(identifier
|
||
(string-or-symbol '*)
|
||
"Identifier of the output.")
|
||
(resolution
|
||
maybe-string
|
||
"Mode of the monitor.")
|
||
(position
|
||
maybe-point
|
||
"Position of the monitor.")
|
||
(background
|
||
maybe-background
|
||
"Background image.")
|
||
(extra-content
|
||
(extra-content '())
|
||
"Extra lines."))
|
||
|
||
(define (sway-outputs? lst)
|
||
(every sway-output? lst))
|
||
|
||
(define-configuration/no-serialization sway-mode
|
||
(mode-name
|
||
(string "default")
|
||
"Name of the mode.")
|
||
(keybindings
|
||
(bindings '())
|
||
"Keybindings.")
|
||
(mouse-bindings
|
||
(mouse-bindings '())
|
||
"Mouse bindings."))
|
||
|
||
(define (sway-modes? lst)
|
||
(every sway-mode? lst))
|
||
|
||
(define-configuration/no-serialization sway-configuration
|
||
(keybindings
|
||
(bindings %sway-default-keybindings)
|
||
"Keybindings.")
|
||
(gestures
|
||
(bindings %sway-default-gestures)
|
||
"Gestures.")
|
||
(packages
|
||
(list-of-packages
|
||
%sway-default-packages)
|
||
"List of packages to add to the profile.")
|
||
(variables
|
||
(variables %sway-default-variables)
|
||
"Variables declared at the beginning of the file.")
|
||
(inputs
|
||
(sway-inputs '())
|
||
"Inputs.")
|
||
(outputs
|
||
(sway-outputs '())
|
||
"Outputs.")
|
||
(bar
|
||
maybe-sway-bar
|
||
"Bar configuration.")
|
||
(modes
|
||
(sway-modes %sway-default-modes)
|
||
"Additional modes.")
|
||
(startup+reload-programs
|
||
(list-of-string-ish '())
|
||
"Programs to execute at startup time.")
|
||
(startup-programs
|
||
(list-of-string-ish %sway-default-startup-programs)
|
||
"Programs to execute at startup time.")
|
||
(extra-content
|
||
(extra-content '())
|
||
"Lines to add at the end of the configuration file."))
|
||
|
||
|
||
;;;
|
||
;;; Default settings and useful constants.
|
||
;;;
|
||
|
||
(define sway-menu
|
||
(program-file
|
||
"sway-menu.scm"
|
||
(with-imported-modules
|
||
(source-module-closure '((guix build utils)))
|
||
#~(begin
|
||
(use-modules (ice-9 ftw)
|
||
(ice-9 popen)
|
||
(ice-9 receive)
|
||
(ice-9 rdelim)
|
||
(guix build utils)
|
||
(srfi srfi-1))
|
||
|
||
(define (directory->files dir)
|
||
(define (executable-file? f)
|
||
;; Cf. `(@ (guix build utils) executable-file?)' for an
|
||
;; explanation of `(zero? ...)'.
|
||
(and=> (and (not (eq? (string-ref f 0) #\.))
|
||
(stat f))
|
||
(lambda (s)
|
||
(not (or
|
||
(zero? (logand (stat:mode s) #o100))
|
||
(eq? (stat:type s) 'directory))))))
|
||
(with-directory-excursion dir
|
||
(scandir "." executable-file?)))
|
||
|
||
(let ((path (string-append (getenv "HOME")
|
||
"/.guix-home/profile/bin"))
|
||
(wmenu #$(file-append wmenu "/bin/wmenu"))
|
||
(swaymsg #$(file-append sway "/bin/swaymsg")))
|
||
(receive (from to pids)
|
||
(pipeline `((,wmenu)))
|
||
(for-each
|
||
(lambda (c) (format to "~a~%" c))
|
||
(directory->files path))
|
||
(close to)
|
||
(let ((choice (read-line from)))
|
||
(close from)
|
||
(waitpid (first pids))
|
||
(when (string? choice) ;do not attempt to launch if no choice
|
||
;was given (e.g. if Escape is pressed in
|
||
;wmenu).
|
||
(execl swaymsg swaymsg "exec" "--"
|
||
choice)))))))))
|
||
|
||
(define %ev-code-mouse-left 272)
|
||
(define %ev-code-mouse-right 273)
|
||
(define %ev-code-mouse-scroll-click 274)
|
||
|
||
(define %sway-default-modes
|
||
(list (sway-mode
|
||
(mode-name "resize")
|
||
(keybindings
|
||
'(($left . "resize shrink width 10px")
|
||
($down . "resize grow height 10px")
|
||
($up . "resize shrink height 10px")
|
||
($right . "resize grow width 10px")
|
||
(Left . "resize shrink width 10px")
|
||
(Down . "resize grow height 10px")
|
||
(Up . "resize shrink height 10px")
|
||
(Right . "resize grow width 10px")
|
||
(Return . "mode \"default\"")
|
||
(Escape . "mode \"default\""))))))
|
||
|
||
(define %sway-default-packages
|
||
(list sway))
|
||
|
||
(define %sway-default-variables
|
||
`((mod . "Mod4")
|
||
(left . "h")
|
||
(down . "j")
|
||
(up . "k")
|
||
(right . "l")
|
||
(term . ,(file-append foot "/bin/foot"))
|
||
(menu . ,sway-menu)))
|
||
|
||
(define %sway-default-gestures
|
||
'((swipe:3:right . "workspace next_on_output")
|
||
(swipe:3:left . "workspace prev_on_output")
|
||
(swipe:3:down . "move to scratchpad")
|
||
(swipe:3:up . "scratchpad show")))
|
||
|
||
(define %sway-default-keybindings
|
||
`(($mod+Return . "exec $term")
|
||
($mod+Shift+q . "kill")
|
||
($mod+d . "exec $menu")
|
||
($mod+Shift+c . "reload")
|
||
($mod+Shift+e
|
||
. ,#~(string-append
|
||
"exec " #$sway "/bin/swaynag -t warning -m \\\n "
|
||
"'You pressed the exit shortcut. Do you really want to exit sway?"
|
||
" This will end your Wayland session.' \\\n "
|
||
"-B 'Yes, exit sway' \\\n '"
|
||
#$sway "/bin/swaymsg exit'"))
|
||
($mod+$left . "focus left")
|
||
($mod+$down . "focus down")
|
||
($mod+$up . "focus up")
|
||
($mod+$right . "focus right")
|
||
($mod+Left . "focus left")
|
||
($mod+Down . "focus down")
|
||
($mod+Up . "focus up")
|
||
($mod+Right . "focus right")
|
||
($mod+Shift+$left . "move left")
|
||
($mod+Shift+$down . "move down")
|
||
($mod+Shift+$up . "move up")
|
||
($mod+Shift+$right . "move right")
|
||
($mod+Shift+Left . "move left")
|
||
($mod+Shift+Down . "move down")
|
||
($mod+Shift+Up . "move up")
|
||
($mod+Shift+Right . "move right")
|
||
($mod+1 . "workspace number 1")
|
||
($mod+2 . "workspace number 2")
|
||
($mod+3 . "workspace number 3")
|
||
($mod+4 . "workspace number 4")
|
||
($mod+5 . "workspace number 5")
|
||
($mod+6 . "workspace number 6")
|
||
($mod+7 . "workspace number 7")
|
||
($mod+8 . "workspace number 8")
|
||
($mod+9 . "workspace number 9")
|
||
($mod+0 . "workspace number 10")
|
||
($mod+Shift+1 . "move container to workspace number 1")
|
||
($mod+Shift+2 . "move container to workspace number 2")
|
||
($mod+Shift+3 . "move container to workspace number 3")
|
||
($mod+Shift+4 . "move container to workspace number 4")
|
||
($mod+Shift+5 . "move container to workspace number 5")
|
||
($mod+Shift+6 . "move container to workspace number 6")
|
||
($mod+Shift+7 . "move container to workspace number 7")
|
||
($mod+Shift+8 . "move container to workspace number 8")
|
||
($mod+Shift+9 . "move container to workspace number 9")
|
||
($mod+Shift+0 . "move container to workspace number 10")
|
||
($mod+b . "splith")
|
||
($mod+v . "splitv")
|
||
($mod+s . "layout stacking")
|
||
($mod+w . "layout tabbed")
|
||
($mod+e . "layout toggle split")
|
||
($mod+f . "fullscreen")
|
||
($mod+Shift+space . "floating toggle")
|
||
($mod+space . "focus mode_toggle")
|
||
($mod+a . "focus parent")
|
||
($mod+Shift+minus . "move scratchpad")
|
||
($mod+minus . "scratchpad show")
|
||
($mod+r . "mode \"resize\"")))
|
||
|
||
(define %sway-default-startup-programs
|
||
(list
|
||
#~(string-append
|
||
#$swayidle "/bin/swayidle -w \\\n "
|
||
;; 300: lock screen.
|
||
"timeout 300 '" #$swaylock "/bin/swaylock "
|
||
"--indicator-radius 75 \\\n "
|
||
"-i " #$sway
|
||
"/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png \\\n "
|
||
"-f -c 000000' \\\n "
|
||
;; 600: lock + screen off.
|
||
"timeout 600 '" #$sway "/bin/swaymsg \"output * power off\"' \\\n "
|
||
;; Resume + sleep.
|
||
"resume '" #$sway "/bin/swaymsg \"output * power on\"' \\\n "
|
||
"before-sleep '" #$swaylock "/bin/swaylock -f -c 000000'")))
|
||
|
||
|
||
;;;
|
||
;;; Serialization functions.
|
||
;;;
|
||
|
||
;; The main serialization code is defined in `sway-configuration->file' below.
|
||
;; In this function, the configuration is seen as a list of lines and blocks.
|
||
;;
|
||
;; The other serialization functions of this files are helpers that will build
|
||
;; the above list. Each function either returns a list, or elements that will
|
||
;; be put in one. The elements of these lists will either be:
|
||
;; - strings,
|
||
;; In this case, the string is seen as a line to add to the configuraiton
|
||
;; file.
|
||
;; - a pair (cons 'begin-block string),
|
||
;; In this case, a line "string {" is added to the configuration file, and
|
||
;; the indentation level is increased by four.
|
||
;; - the symbol 'end-block.
|
||
;; In which case the indentation level is decreased by four, and the current
|
||
;; configuration block is closed (with the line "}").
|
||
|
||
;; A few helper functions:
|
||
|
||
(define* (add-line-if field value
|
||
#:key (serializer %unset-value)
|
||
(suffix %unset-value))
|
||
(if (eq? %unset-value value)
|
||
%unset-value
|
||
#~(string-append #$field " "
|
||
#$(if (eq? serializer %unset-value)
|
||
value
|
||
(serializer value))
|
||
#$(if (eq? suffix %unset-value)
|
||
""
|
||
suffix))))
|
||
|
||
(define (add-block name content)
|
||
(let ((content (filter
|
||
(lambda (elt) (not (eq? elt %unset-value)))
|
||
content)))
|
||
(if (equal? content '())
|
||
'()
|
||
(append
|
||
(list #~(cons 'begin-block #$name))
|
||
content
|
||
(list #~'end-block)))))
|
||
|
||
(define-syntax add-block*
|
||
(syntax-rules ()
|
||
((add-block* name elt ...)
|
||
(add-block name (append elt ...)))))
|
||
|
||
;; Serialization functions:
|
||
|
||
(define (box str)
|
||
(let* ((len (string-length str))
|
||
(line (make-string (+ 8 len) #\#)))
|
||
(list
|
||
line
|
||
(string-append "### " str " ###")
|
||
line)))
|
||
|
||
(define (with-heading str lst)
|
||
(define (heading str)
|
||
(let* ((len (string-length str))
|
||
(line (make-string (+ 2 len) #\#)))
|
||
(list
|
||
"" ;add an empty line before the configuration section.
|
||
(string-append "# " str)
|
||
line)))
|
||
(if (equal? lst '())
|
||
'() ;if the configuration block is empty, do not add the heading.
|
||
(append (heading str) lst)))
|
||
|
||
(define-inlinable (serialize-boolean-yn b)
|
||
(if b "yes" "no"))
|
||
(define-inlinable (serialize-boolean-ed b)
|
||
(if b "enable" "disable"))
|
||
|
||
(define-inlinable (serialize-binding binder key value)
|
||
#~(string-append #$binder #$key " " #$value))
|
||
|
||
(define (serialize-mouse-binding var)
|
||
(let* ((ev (car var))
|
||
(ev-code (number->string ev))
|
||
(command (cdr var)))
|
||
(serialize-binding "bindcode " ev-code command)))
|
||
|
||
(define (serialize-keybinding var)
|
||
(let ((name (symbol->string (car var)))
|
||
(value (cdr var)))
|
||
(serialize-binding "bindsym " name value)))
|
||
|
||
(define (serialize-gesture var)
|
||
(let ((name (symbol->string (car var)))
|
||
(value (cdr var)))
|
||
(serialize-binding "bindgesture " name value)))
|
||
|
||
(define (serialize-variable var)
|
||
(let ((name (symbol->string (car var)))
|
||
(value (cdr var)))
|
||
(serialize-binding "set $" name value)))
|
||
|
||
(define (serialize-exec b)
|
||
(if b
|
||
(lambda (exe)
|
||
#~(string-append "exec_always " #$exe))
|
||
(lambda (exe)
|
||
#~(string-append "exec " #$exe))))
|
||
|
||
(define (serialize-output out)
|
||
(let* ((pre-ident (sway-output-identifier out))
|
||
(ident (if (symbol? pre-ident)
|
||
(symbol->string pre-ident)
|
||
(string-append "\"" pre-ident "\"")))
|
||
(background (let ((bg (sway-output-background out)))
|
||
(if (pair? bg)
|
||
bg
|
||
(cons bg 'fill))))
|
||
(resolution (sway-output-resolution out))
|
||
(position (sway-output-position out))
|
||
(extra-content (sway-output-extra-content out)))
|
||
(add-block
|
||
(string-append "output " ident)
|
||
(cons*
|
||
;; Optional elements.
|
||
(add-line-if "bg" (car background)
|
||
#:suffix
|
||
(string-append " " (symbol->string (cdr background))))
|
||
(add-line-if "resolution" resolution)
|
||
(add-line-if "position" position
|
||
#:serializer
|
||
(lambda (p)
|
||
(string-append (number->string (point-x p))
|
||
" "
|
||
(number->string (point-y p)))))
|
||
;; Extra-content: inlined as-is.
|
||
extra-content))))
|
||
|
||
(define (serialize-input input)
|
||
(define-inlinable (fetch-arg layout acc)
|
||
(if (eq? layout %unset-value)
|
||
%unset-value
|
||
(acc layout)))
|
||
|
||
(define-inlinable (unfalse f)
|
||
(lambda (arg)
|
||
(let ((res (f arg)))
|
||
(if res res %unset-value))))
|
||
|
||
(define-inlinable (unnil f)
|
||
(lambda (arg)
|
||
(let ((res (f arg)))
|
||
(if (nil? res) %unset-value res))))
|
||
|
||
(let* ((pre-ident (sway-input-identifier input))
|
||
(ident (if (symbol? pre-ident)
|
||
(symbol->string pre-ident)
|
||
(string-append "\"" pre-ident "\"")))
|
||
|
||
;; unpack the `layout' field.
|
||
(layout (sway-input-layout input))
|
||
(xkb-layout (fetch-arg layout keyboard-layout-name))
|
||
(xkb-variant (fetch-arg layout (unfalse keyboard-layout-variant)))
|
||
(xkb-model (fetch-arg layout (unfalse keyboard-layout-model)))
|
||
(xkb-options (fetch-arg layout (unnil keyboard-layout-options)))
|
||
|
||
(tap (sway-input-tap input))
|
||
(dwt (sway-input-disable-while-typing input))
|
||
(dwtp (sway-input-disable-while-trackpointing input))
|
||
(extra-content (sway-input-extra-content input)))
|
||
(add-block
|
||
(string-append "input " ident)
|
||
(cons*
|
||
;; Optional.
|
||
(add-line-if "xkb_layout" xkb-layout)
|
||
(add-line-if "xkb_model" xkb-model)
|
||
(add-line-if "xkb_variant" xkb-variant)
|
||
(add-line-if "xkb_options" xkb-options
|
||
#:serializer (lambda (l) (string-join l ",")))
|
||
(add-line-if "dwt" dwt
|
||
#:serializer serialize-boolean-ed)
|
||
(add-line-if "dwtp" dwtp
|
||
#:serializer serialize-boolean-ed)
|
||
(add-line-if "tap" tap
|
||
#:serializer serialize-boolean-ed)
|
||
;; extra-content inlined as-is.
|
||
extra-content))))
|
||
|
||
(define (serialize-colors colors)
|
||
(define (border-serializer val)
|
||
(string-append (sway-border-color-border val)
|
||
" " (sway-border-color-background val)
|
||
" " (sway-border-color-text val)))
|
||
(if (eq? %unset-value colors)
|
||
'()
|
||
(let ((background (sway-color-background colors))
|
||
(statusline (sway-color-statusline colors))
|
||
(focused-background (sway-color-focused-background colors))
|
||
(focused-statusline (sway-color-focused-statusline colors))
|
||
(focused-workspace (sway-color-focused-workspace colors))
|
||
(active-workspace (sway-color-active-workspace colors))
|
||
(inactive-workspace (sway-color-inactive-workspace colors))
|
||
(urgent-workspace (sway-color-urgent-workspace colors))
|
||
(binding-mode (sway-color-binding-mode colors)))
|
||
(add-block
|
||
"colors"
|
||
(list
|
||
(add-line-if "background" background)
|
||
(add-line-if "statusline" statusline)
|
||
(add-line-if "focused_background" focused-background)
|
||
(add-line-if "focused_statusline" focused-statusline)
|
||
(add-line-if "focused_workspace" focused-workspace
|
||
#:serializer border-serializer)
|
||
(add-line-if "active_workspace" active-workspace
|
||
#:serializer border-serializer)
|
||
(add-line-if "inactive_workspace" inactive-workspace
|
||
#:serializer border-serializer)
|
||
(add-line-if "urgent_workspace" urgent-workspace
|
||
#:serializer border-serializer)
|
||
(add-line-if "binding_mode" binding-mode
|
||
#:serializer border-serializer))))))
|
||
|
||
(define (serialize-mode mode)
|
||
(let ((name (sway-mode-mode-name mode))
|
||
(keys (sway-mode-keybindings mode))
|
||
(clicks (sway-mode-mouse-bindings mode)))
|
||
(add-block*
|
||
(string-append "mode \"" name "\"")
|
||
(map serialize-keybinding keys)
|
||
(map serialize-mouse-binding clicks))))
|
||
|
||
(define (serialize-bar bar)
|
||
(define serialize-symbol
|
||
symbol->string)
|
||
|
||
(let ((identifier (symbol->string (sway-bar-identifier bar)))
|
||
(position (sway-bar-position bar))
|
||
(hidden-state (sway-bar-hidden-state bar))
|
||
(status-command (sway-bar-status-command bar))
|
||
(binding-mode-indicator (sway-bar-binding-mode-indicator bar))
|
||
(mouse-bindings (sway-bar-mouse-bindings bar))
|
||
(extra-content (sway-bar-extra-content bar))
|
||
(colors (sway-bar-colors bar)))
|
||
(add-block*
|
||
(string-append "bar " identifier)
|
||
|
||
(if (eq? colors %unset-value)
|
||
'()
|
||
(serialize-colors colors))
|
||
(list
|
||
(add-line-if "position" position
|
||
#:serializer serialize-symbol)
|
||
(add-line-if "hidden_state" hidden-state
|
||
#:serializer serialize-symbol)
|
||
(add-line-if "status_command" status-command)
|
||
(add-line-if "binding_mode_indicator" binding-mode-indicator
|
||
#:serializer serialize-boolean-yn))
|
||
;; Mouse-bindings and extra-content
|
||
(map serialize-mouse-binding mouse-bindings)
|
||
extra-content)))
|
||
|
||
(define (sway-configuration->file conf)
|
||
(let* ((extra (sway-configuration-extra-content conf))
|
||
(bar (sway-configuration-bar conf)))
|
||
(computed-file
|
||
"sway-config"
|
||
#~(begin
|
||
(use-modules (ice-9 format) (ice-9 match)
|
||
(srfi srfi-1))
|
||
|
||
(call-with-output-file #$output
|
||
(lambda (port)
|
||
|
||
;; Add the (indented) line "s" to the output file.
|
||
(define (line s)
|
||
(lambda (i)
|
||
(format port "~a~a~%" i s)
|
||
i))
|
||
|
||
;; Begin a block "name" and adjust the indentation.
|
||
(define (begin-block name)
|
||
(lambda (i)
|
||
(format port "~a~a {~%" i name)
|
||
(string-append " " i)))
|
||
|
||
;; Ends an open block and adjust the indentation.
|
||
;; Note: we must currently be in a configuration block.
|
||
;; Otherwise, `string-drop' might fail.
|
||
(define (end-block)
|
||
(lambda (i)
|
||
(let ((i (string-drop i 4)))
|
||
(format port "~a}~%" i)
|
||
i)))
|
||
|
||
;; Helper function. The configuration is represented as a list
|
||
;; of actions (alter the indentation level, add a line, ...).
|
||
;; This function recognises the action and calls the right
|
||
;; function among those defined above.
|
||
(define (serializer-dispatch-m arg)
|
||
(match arg
|
||
;; Special cases:
|
||
(('begin-block . str) (begin-block str))
|
||
('end-block (end-block))
|
||
;; Default case: `arg' is assumed to be a string.
|
||
(_ (line arg))))
|
||
|
||
(define (serializer-dispatch elt i)
|
||
((serializer-dispatch-m elt) i))
|
||
|
||
(fold
|
||
;; Dispatch function: depending on its argument, it will change
|
||
;; the indentation level or add a line to the output file.
|
||
serializer-dispatch
|
||
|
||
;; Initial indentation string. This string is prepended to
|
||
;; lines before their serialization.
|
||
""
|
||
;; List of lines or indentation modifiers.
|
||
(list
|
||
;; Header.
|
||
#$@(box "Auto-generated configuration")
|
||
"# DO NOT EDIT MANUALLY."
|
||
|
||
;; Variables.
|
||
#$@(with-heading "Variables."
|
||
(map serialize-variable
|
||
(sway-configuration-variables conf)))
|
||
|
||
;; Outputs.
|
||
#$@(with-heading "Outputs."
|
||
(flatmap serialize-output
|
||
(sway-configuration-outputs conf)))
|
||
|
||
;; Inputs.
|
||
#$@(with-heading "Inputs."
|
||
(flatmap serialize-input
|
||
(sway-configuration-inputs conf)))
|
||
|
||
;; Bar configuration:
|
||
;; If the bar is unset, do not include anything.
|
||
#$@(if (eq? bar %unset-value)
|
||
'()
|
||
(with-heading "Bar configuration."
|
||
(serialize-bar bar)))
|
||
|
||
;; Keybindings.
|
||
#$@(with-heading "Keybindings."
|
||
(map serialize-keybinding
|
||
(sway-configuration-keybindings conf)))
|
||
;; Gestures.
|
||
#$@(with-heading "Gestures."
|
||
(map serialize-gesture
|
||
(sway-configuration-gestures conf)))
|
||
|
||
;; Modes.
|
||
#$@(with-heading "Modes."
|
||
(flatmap serialize-mode
|
||
(sway-configuration-modes conf)))
|
||
|
||
;; Startup-Programs.
|
||
#$@(with-heading
|
||
"Programs to execute (at startup)."
|
||
(map (serialize-exec #f)
|
||
(sway-configuration-startup-programs conf)))
|
||
;; startup+reload-programs.
|
||
#$@(with-heading
|
||
"Programs to execute (at startup & after reload)."
|
||
(map (serialize-exec #t)
|
||
(sway-configuration-startup+reload-programs conf)))
|
||
|
||
;; Extra-content.
|
||
#$@(with-heading "Extra-content" extra)))))))))
|
||
|
||
|
||
;;;
|
||
;;; Definition of the Home Service.
|
||
;;;
|
||
|
||
(define (sway-configuration->files sway-conf)
|
||
`((".config/sway/config" ,(sway-configuration->file sway-conf))))
|
||
|
||
(define home-sway-service-type
|
||
(service-type
|
||
(name 'home-sway-config)
|
||
(extensions
|
||
(list (service-extension home-files-service-type
|
||
sway-configuration->files)
|
||
(service-extension home-profile-service-type
|
||
sway-configuration-packages)))
|
||
(description "Configure Sway by providing a file
|
||
@file{~/.config/sway/config}.")
|
||
(default-value (sway-configuration))))
|