diff options
| author | Arnaud Daby-Seesaram <ds-ac@nanein.fr> | 2024-10-09 00:33:41 +0200 |
|---|---|---|
| committer | Florian Pelz <pelzflorian@pelzflorian.de> | 2024-10-12 14:26:01 +0200 |
| commit | b64f7984a5e2aba04df72a92f0044e423efe77c6 (patch) | |
| tree | 6f7dd897f6924757ec9663935e2913443ba91c86 /gnu | |
| parent | b9ec6251bee8e4e500eb9291087fbf2018aca113 (diff) | |
home: services: Add 'home-sway-service-type'.
* 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
Diffstat (limited to 'gnu')
| -rw-r--r-- | gnu/home/services/sway.scm | 870 | ||||
| -rw-r--r-- | gnu/local.mk | 1 |
2 files changed, 871 insertions, 0 deletions
diff --git a/gnu/home/services/sway.scm b/gnu/home/services/sway.scm new file mode 100644 index 00000000000..0e1a2d57b2a --- /dev/null +++ b/gnu/home/services/sway.scm | |||
| @@ -0,0 +1,870 @@ | |||
| 1 | ;;; GNU Guix --- Functional package management for GNU | ||
| 2 | ;;; Copyright © 2024 Arnaud Daby-Seesaram <ds-ac@nanein.fr> | ||
| 3 | ;;; | ||
| 4 | ;;; This file is part of GNU Guix. | ||
| 5 | ;;; | ||
| 6 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | ||
| 7 | ;;; under the terms of the GNU General Public License as published by | ||
| 8 | ;;; the Free Software Foundation; either version 3 of the License, or (at | ||
| 9 | ;;; your option) any later version. | ||
| 10 | ;;; | ||
| 11 | ;;; GNU Guix is distributed in the hope that it will be useful, but | ||
| 12 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | ;;; GNU General Public License for more details. | ||
| 15 | ;;; | ||
| 16 | ;;; You should have received a copy of the GNU General Public License | ||
| 17 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | ||
| 18 | |||
| 19 | (define-module (gnu home services sway) | ||
| 20 | #:use-module (guix modules) | ||
| 21 | #:use-module (guix gexp) | ||
| 22 | #:use-module (srfi srfi-1) | ||
| 23 | #:use-module (ice-9 match) | ||
| 24 | #:use-module (guix packages) | ||
| 25 | #:use-module (gnu system keyboard) | ||
| 26 | #:use-module (gnu services configuration) | ||
| 27 | #:use-module (gnu home services) | ||
| 28 | #:use-module (gnu packages wm) | ||
| 29 | #:use-module (gnu packages terminals) | ||
| 30 | #:export (;; Event codes | ||
| 31 | %ev-code-mouse-left | ||
| 32 | %ev-code-mouse-right | ||
| 33 | %ev-code-mouse-scroll-click | ||
| 34 | |||
| 35 | ;; Configuration records. | ||
| 36 | sway-configuration | ||
| 37 | sway-bar | ||
| 38 | sway-output | ||
| 39 | sway-input | ||
| 40 | point | ||
| 41 | sway-color | ||
| 42 | sway-border-color | ||
| 43 | home-sway-service-type | ||
| 44 | sway-configuration->file | ||
| 45 | sway-mode | ||
| 46 | |||
| 47 | ;; Default values. | ||
| 48 | %sway-default-variables | ||
| 49 | %sway-default-gestures | ||
| 50 | %sway-default-modes | ||
| 51 | %sway-default-keybindings | ||
| 52 | %sway-default-startup-programs | ||
| 53 | %sway-default-packages)) | ||
| 54 | |||
| 55 | ;; Helper function. | ||
| 56 | (define (flatmap f l) | ||
| 57 | (let loop ((lst (reverse l)) (acc '())) | ||
| 58 | (match lst | ||
| 59 | (() acc) | ||
| 60 | ((head . tail) | ||
| 61 | (let* ((h (f head)) | ||
| 62 | (acc (append h acc))) | ||
| 63 | (loop tail acc)))))) | ||
| 64 | |||
| 65 | |||
| 66 | ;;; | ||
| 67 | ;;; Definition of configurations. | ||
| 68 | ;;; | ||
| 69 | |||
| 70 | (define (string-ish? s) | ||
| 71 | (or (gexp? s) | ||
| 72 | (file-like? s) | ||
| 73 | (string? s))) | ||
| 74 | |||
| 75 | (define (string-or-gexp? s) | ||
| 76 | (or (gexp? s) | ||
| 77 | (string? s))) | ||
| 78 | |||
| 79 | (define (list-of-string-ish? lst) | ||
| 80 | (every string-ish? lst)) | ||
| 81 | |||
| 82 | (define (list-of-packages? lst) | ||
| 83 | (every package? lst)) | ||
| 84 | |||
| 85 | (define (bar-position? p) | ||
| 86 | (member p '(top bottom))) | ||
| 87 | |||
| 88 | (define (hidden-state? st) | ||
| 89 | (member st '(hide show))) | ||
| 90 | |||
| 91 | (define (string-or-symbol? s) | ||
| 92 | (or (string? s) | ||
| 93 | (symbol? s))) | ||
| 94 | |||
| 95 | (define (strings? lst) | ||
| 96 | (every string? lst)) | ||
| 97 | |||
| 98 | (define (extra-content? extra) | ||
| 99 | (every string-or-gexp? extra)) | ||
| 100 | |||
| 101 | (define (make-alist-predicate key? val?) | ||
| 102 | (lambda (lst) | ||
| 103 | (every | ||
| 104 | (lambda (item) | ||
| 105 | (match item | ||
| 106 | ((k . v) | ||
| 107 | (and (key? k) | ||
| 108 | (val? v))) | ||
| 109 | (_ #f))) | ||
| 110 | lst))) | ||
| 111 | |||
| 112 | (define bindings? | ||
| 113 | (make-alist-predicate symbol? string-or-gexp?)) | ||
| 114 | |||
| 115 | (define mouse-bindings? | ||
| 116 | (make-alist-predicate integer? string-or-gexp?)) | ||
| 117 | |||
| 118 | (define (variables? lst) | ||
| 119 | (make-alist-predicate symbol? string-ish?)) | ||
| 120 | |||
| 121 | (define-maybe string (no-serialization)) | ||
| 122 | (define-maybe strings (no-serialization)) | ||
| 123 | (define-maybe boolean (no-serialization)) | ||
| 124 | (define-maybe keyboard-layout (no-serialization)) | ||
| 125 | |||
| 126 | (define-configuration/no-serialization sway-input | ||
| 127 | (identifier | ||
| 128 | (string-or-symbol '*) | ||
| 129 | "Identifier of the input.") | ||
| 130 | (layout | ||
| 131 | maybe-keyboard-layout | ||
| 132 | "Keyboard layout of the input.") | ||
| 133 | (disable-while-typing | ||
| 134 | maybe-boolean | ||
| 135 | "If `#t', disable the input while typing; if `#f' do not.") | ||
| 136 | (disable-while-trackpointing | ||
| 137 | maybe-boolean | ||
| 138 | "If `#t', disable the input while using a trackpoint; if `#f' do not.") | ||
| 139 | (tap | ||
| 140 | maybe-boolean | ||
| 141 | "Enable or disable tap.") | ||
| 142 | (extra-content | ||
| 143 | (extra-content '()) | ||
| 144 | "Lines to add at the end of the configuration file.")) | ||
| 145 | |||
| 146 | (define (sway-inputs? lst) | ||
| 147 | (every sway-input? lst)) | ||
| 148 | |||
| 149 | (define-configuration/no-serialization sway-border-color | ||
| 150 | (border | ||
| 151 | string | ||
| 152 | "Border color.") | ||
| 153 | (background | ||
| 154 | string | ||
| 155 | "Background color.") | ||
| 156 | (text | ||
| 157 | string | ||
| 158 | "Text color.")) | ||
| 159 | |||
| 160 | (define-maybe sway-border-color (no-serialization)) | ||
| 161 | |||
| 162 | (define-configuration/no-serialization sway-color | ||
| 163 | (background | ||
| 164 | maybe-string | ||
| 165 | "Background color of the bar.") | ||
| 166 | (statusline | ||
| 167 | maybe-string | ||
| 168 | "Text color of the status line.") | ||
| 169 | (focused-background | ||
| 170 | maybe-string | ||
| 171 | "Background color of the bar on the currently focused monitor.") | ||
| 172 | (focused-statusline | ||
| 173 | maybe-string | ||
| 174 | "Text color of the statusline on the currently focused monitor.") | ||
| 175 | (focused-workspace | ||
| 176 | maybe-sway-border-color | ||
| 177 | "Color scheme for focused workspaces.") | ||
| 178 | (active-workspace | ||
| 179 | maybe-sway-border-color | ||
| 180 | "Color scheme for active workspaces.") | ||
| 181 | (inactive-workspace | ||
| 182 | maybe-sway-border-color | ||
| 183 | "Color scheme for inactive workspaces.") | ||
| 184 | (urgent-workspace | ||
| 185 | maybe-sway-border-color | ||
| 186 | "Color scheme for workspaces containing `urgent' windows.") | ||
| 187 | (binding-mode | ||
| 188 | maybe-sway-border-color | ||
| 189 | "Color scheme for the binding mode indicator.")) | ||
| 190 | |||
| 191 | (define-maybe sway-color (no-serialization)) | ||
| 192 | |||
| 193 | (define (status-command? c) | ||
| 194 | (or (string? c) | ||
| 195 | (file-like? c) | ||
| 196 | (gexp? c))) | ||
| 197 | |||
| 198 | (define-maybe bar-position (no-serialization)) | ||
| 199 | (define-maybe hidden-state (no-serialization)) | ||
| 200 | (define-maybe status-command (no-serialization)) | ||
| 201 | |||
| 202 | (define-configuration/no-serialization sway-bar | ||
| 203 | (identifier | ||
| 204 | (symbol 'bar0) | ||
| 205 | "Identifier of the bar.") | ||
| 206 | (position | ||
| 207 | maybe-bar-position | ||
| 208 | "Position of the bar.") | ||
| 209 | (hidden-state | ||
| 210 | maybe-hidden-state | ||
| 211 | "Hidden state.") | ||
| 212 | (binding-mode-indicator | ||
| 213 | maybe-boolean | ||
| 214 | "Binding indicator.") | ||
| 215 | (colors | ||
| 216 | maybe-sway-color | ||
| 217 | "Color palette of the bar.") | ||
| 218 | (status-command | ||
| 219 | maybe-status-command | ||
| 220 | "Status command.") | ||
| 221 | (mouse-bindings | ||
| 222 | (mouse-bindings '()) | ||
| 223 | "Actions triggered by mouse events.") | ||
| 224 | (extra-content | ||
| 225 | (extra-content '()) | ||
| 226 | "Extra configuration lines.")) | ||
| 227 | |||
| 228 | (define-maybe sway-bar (no-serialization)) | ||
| 229 | |||
| 230 | (define-configuration/no-serialization point | ||
| 231 | (x integer "X coordinate.") | ||
| 232 | (y integer "Y coordinate.")) | ||
| 233 | |||
| 234 | (define-maybe point (no-serialization)) | ||
| 235 | |||
| 236 | (define (background? bg) | ||
| 237 | (or (string-ish? bg) | ||
| 238 | (and (pair? bg) | ||
| 239 | (string-ish? (car bg)) | ||
| 240 | (member (cdr bg) '(stretch fill fit center tile))))) | ||
| 241 | |||
| 242 | (define-maybe background (no-serialization)) | ||
| 243 | |||
| 244 | (define-configuration/no-serialization sway-output | ||
| 245 | (identifier | ||
| 246 | (string-or-symbol '*) | ||
| 247 | "Identifier of the output.") | ||
| 248 | (resolution | ||
| 249 | maybe-string | ||
| 250 | "Mode of the monitor.") | ||
| 251 | (position | ||
| 252 | maybe-point | ||
| 253 | "Position of the monitor.") | ||
| 254 | (background | ||
| 255 | maybe-background | ||
| 256 | "Background image.") | ||
| 257 | (extra-content | ||
| 258 | (extra-content '()) | ||
| 259 | "Extra lines.")) | ||
| 260 | |||
| 261 | (define (sway-outputs? lst) | ||
| 262 | (every sway-output? lst)) | ||
| 263 | |||
| 264 | (define-configuration/no-serialization sway-mode | ||
| 265 | (mode-name | ||
| 266 | (string "default") | ||
| 267 | "Name of the mode.") | ||
| 268 | (keybindings | ||
| 269 | (bindings '()) | ||
| 270 | "Keybindings.") | ||
| 271 | (mouse-bindings | ||
| 272 | (mouse-bindings '()) | ||
| 273 | "Mouse bindings.")) | ||
| 274 | |||
| 275 | (define (sway-modes? lst) | ||
| 276 | (every sway-mode? lst)) | ||
| 277 | |||
| 278 | (define-configuration/no-serialization sway-configuration | ||
| 279 | (keybindings | ||
| 280 | (bindings %sway-default-keybindings) | ||
| 281 | "Keybindings.") | ||
| 282 | (gestures | ||
| 283 | (bindings %sway-default-gestures) | ||
| 284 | "Gestures.") | ||
| 285 | (packages | ||
| 286 | (list-of-packages | ||
| 287 | %sway-default-packages) | ||
| 288 | "List of packages to add to the profile.") | ||
| 289 | (variables | ||
| 290 | (variables %sway-default-variables) | ||
| 291 | "Variables declared at the beginning of the file.") | ||
| 292 | (inputs | ||
| 293 | (sway-inputs '()) | ||
| 294 | "Inputs.") | ||
| 295 | (outputs | ||
| 296 | (sway-outputs '()) | ||
| 297 | "Outputs.") | ||
| 298 | (bar | ||
| 299 | maybe-sway-bar | ||
| 300 | "Bar configuration.") | ||
| 301 | (modes | ||
| 302 | (sway-modes %sway-default-modes) | ||
| 303 | "Additional modes.") | ||
| 304 | (startup+reload-programs | ||
| 305 | (list-of-string-ish '()) | ||
| 306 | "Programs to execute at startup time.") | ||
| 307 | (startup-programs | ||
| 308 | (list-of-string-ish %sway-default-startup-programs) | ||
| 309 | "Programs to execute at startup time.") | ||
| 310 | (extra-content | ||
| 311 | (extra-content '()) | ||
| 312 | "Lines to add at the end of the configuration file.")) | ||
| 313 | |||
| 314 | |||
| 315 | ;;; | ||
| 316 | ;;; Default settings and useful constants. | ||
| 317 | ;;; | ||
| 318 | |||
| 319 | (define sway-menu | ||
| 320 | (program-file | ||
| 321 | "sway-menu.scm" | ||
| 322 | (with-imported-modules | ||
| 323 | (source-module-closure '((guix build utils))) | ||
| 324 | #~(begin | ||
| 325 | (use-modules (ice-9 ftw) | ||
| 326 | (ice-9 popen) | ||
| 327 | (ice-9 receive) | ||
| 328 | (ice-9 rdelim) | ||
| 329 | (guix build utils) | ||
| 330 | (srfi srfi-1)) | ||
| 331 | |||
| 332 | (define (directory->files dir) | ||
| 333 | (define (executable-file? f) | ||
| 334 | ;; Cf. `(@ (guix build utils) executable-file?)' for an | ||
| 335 | ;; explanation of `(zero? ...)'. | ||
| 336 | (and=> (and (not (eq? (string-ref f 0) #\.)) | ||
| 337 | (stat f)) | ||
| 338 | (lambda (s) | ||
| 339 | (not (or | ||
| 340 | (zero? (logand (stat:mode s) #o100)) | ||
| 341 | (eq? (stat:type s) 'directory)))))) | ||
| 342 | (with-directory-excursion dir | ||
| 343 | (scandir "." executable-file?))) | ||
| 344 | |||
| 345 | (let ((path (string-append (getenv "HOME") | ||
| 346 | "/.guix-home/profile/bin")) | ||
| 347 | (wmenu #$(file-append wmenu "/bin/wmenu")) | ||
| 348 | (swaymsg #$(file-append sway "/bin/swaymsg"))) | ||
| 349 | (receive (from to pids) | ||
| 350 | (pipeline `((,wmenu))) | ||
| 351 | (for-each | ||
| 352 | (lambda (c) (format to "~a~%" c)) | ||
| 353 | (directory->files path)) | ||
| 354 | (close to) | ||
| 355 | (let ((choice (read-line from))) | ||
| 356 | (close from) | ||
| 357 | (waitpid (first pids)) | ||
| 358 | (when (string? choice) ;do not attempt to launch if no choice | ||
| 359 | ;was given (e.g. if Escape is pressed in | ||
| 360 | ;wmenu). | ||
| 361 | (execl swaymsg swaymsg "exec" "--" | ||
| 362 | choice))))))))) | ||
| 363 | |||
| 364 | (define %ev-code-mouse-left 272) | ||
| 365 | (define %ev-code-mouse-right 273) | ||
| 366 | (define %ev-code-mouse-scroll-click 274) | ||
| 367 | |||
| 368 | (define %sway-default-modes | ||
| 369 | (list (sway-mode | ||
| 370 | (mode-name "resize") | ||
| 371 | (keybindings | ||
| 372 | '(($left . "resize shrink width 10px") | ||
| 373 | ($down . "resize grow height 10px") | ||
| 374 | ($up . "resize shrink height 10px") | ||
| 375 | ($right . "resize grow width 10px") | ||
| 376 | (Left . "resize shrink width 10px") | ||
| 377 | (Down . "resize grow height 10px") | ||
| 378 | (Up . "resize shrink height 10px") | ||
| 379 | (Right . "resize grow width 10px") | ||
| 380 | (Return . "mode \"default\"") | ||
| 381 | (Escape . "mode \"default\"")))))) | ||
| 382 | |||
| 383 | (define %sway-default-packages | ||
| 384 | (list sway)) | ||
| 385 | |||
| 386 | (define %sway-default-variables | ||
| 387 | `((mod . "Mod4") | ||
| 388 | (left . "h") | ||
| 389 | (down . "j") | ||
| 390 | (up . "k") | ||
| 391 | (right . "l") | ||
| 392 | (term . ,(file-append foot "/bin/foot")) | ||
| 393 | (menu . ,sway-menu))) | ||
| 394 | |||
| 395 | (define %sway-default-gestures | ||
| 396 | '((swipe:3:right . "workspace next_on_output") | ||
| 397 | (swipe:3:left . "workspace prev_on_output") | ||
| 398 | (swipe:3:down . "move to scratchpad") | ||
| 399 | (swipe:3:up . "scratchpad show"))) | ||
| 400 | |||
| 401 | (define %sway-default-keybindings | ||
| 402 | `(($mod+Return . "exec $term") | ||
| 403 | ($mod+Shift+q . "kill") | ||
| 404 | ($mod+d . "exec $menu") | ||
| 405 | ($mod+Shift+c . "reload") | ||
| 406 | ($mod+Shift+e | ||
| 407 | . ,#~(string-append | ||
| 408 | "exec " #$sway "/bin/swaynag -t warning -m \\\n " | ||
| 409 | "'You pressed the exit shortcut. Do you really want to exit sway?" | ||
| 410 | " This will end your Wayland session.' \\\n " | ||
| 411 | "-B 'Yes, exit sway' \\\n '" | ||
| 412 | #$sway "/bin/swaymsg exit'")) | ||
| 413 | ($mod+$left . "focus left") | ||
| 414 | ($mod+$down . "focus down") | ||
| 415 | ($mod+$up . "focus up") | ||
| 416 | ($mod+$right . "focus right") | ||
| 417 | ($mod+Left . "focus left") | ||
| 418 | ($mod+Down . "focus down") | ||
| 419 | ($mod+Up . "focus up") | ||
| 420 | ($mod+Right . "focus right") | ||
| 421 | ($mod+Shift+$left . "move left") | ||
| 422 | ($mod+Shift+$down . "move down") | ||
| 423 | ($mod+Shift+$up . "move up") | ||
| 424 | ($mod+Shift+$right . "move right") | ||
| 425 | ($mod+Shift+Left . "move left") | ||
| 426 | ($mod+Shift+Down . "move down") | ||
| 427 | ($mod+Shift+Up . "move up") | ||
| 428 | ($mod+Shift+Right . "move right") | ||
| 429 | ($mod+1 . "workspace number 1") | ||
| 430 | ($mod+2 . "workspace number 2") | ||
| 431 | ($mod+3 . "workspace number 3") | ||
| 432 | ($mod+4 . "workspace number 4") | ||
| 433 | ($mod+5 . "workspace number 5") | ||
| 434 | ($mod+6 . "workspace number 6") | ||
| 435 | ($mod+7 . "workspace number 7") | ||
| 436 | ($mod+8 . "workspace number 8") | ||
| 437 | ($mod+9 . "workspace number 9") | ||
| 438 | ($mod+0 . "workspace number 10") | ||
| 439 | ($mod+Shift+1 . "move container to workspace number 1") | ||
| 440 | ($mod+Shift+2 . "move container to workspace number 2") | ||
| 441 | ($mod+Shift+3 . "move container to workspace number 3") | ||
| 442 | ($mod+Shift+4 . "move container to workspace number 4") | ||
| 443 | ($mod+Shift+5 . "move container to workspace number 5") | ||
| 444 | ($mod+Shift+6 . "move container to workspace number 6") | ||
| 445 | ($mod+Shift+7 . "move container to workspace number 7") | ||
| 446 | ($mod+Shift+8 . "move container to workspace number 8") | ||
| 447 | ($mod+Shift+9 . "move container to workspace number 9") | ||
| 448 | ($mod+Shift+0 . "move container to workspace number 10") | ||
| 449 | ($mod+b . "splith") | ||
| 450 | ($mod+v . "splitv") | ||
| 451 | ($mod+s . "layout stacking") | ||
| 452 | ($mod+w . "layout tabbed") | ||
| 453 | ($mod+e . "layout toggle split") | ||
| 454 | ($mod+f . "fullscreen") | ||
| 455 | ($mod+Shift+space . "floating toggle") | ||
| 456 | ($mod+space . "focus mode_toggle") | ||
| 457 | ($mod+a . "focus parent") | ||
| 458 | ($mod+Shift+minus . "move scratchpad") | ||
| 459 | ($mod+minus . "scratchpad show") | ||
| 460 | ($mod+r . "mode \"resize\""))) | ||
| 461 | |||
| 462 | (define %sway-default-startup-programs | ||
| 463 | (list | ||
| 464 | #~(string-append | ||
| 465 | #$swayidle "/bin/swayidle -w \\\n " | ||
| 466 | ;; 300: lock screen. | ||
| 467 | "timeout 300 '" #$swaylock "/bin/swaylock " | ||
| 468 | "--indicator-radius 75 \\\n " | ||
| 469 | "-i " #$sway | ||
| 470 | "/share/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png \\\n " | ||
| 471 | "-f -c 000000' \\\n " | ||
| 472 | ;; 600: lock + screen off. | ||
| 473 | "timeout 600 '" #$sway "/bin/swaymsg \"output * power off\"' \\\n " | ||
| 474 | ;; Resume + sleep. | ||
| 475 | "resume '" #$sway "/bin/swaymsg \"output * power on\"' \\\n " | ||
| 476 | "before-sleep '" #$swaylock "/bin/swaylock -f -c 000000'"))) | ||
| 477 | |||
| 478 | |||
| 479 | ;;; | ||
| 480 | ;;; Serialization functions. | ||
| 481 | ;;; | ||
| 482 | |||
| 483 | ;; The main serialization code is defined in `sway-configuration->file' below. | ||
| 484 | ;; In this function, the configuration is seen as a list of lines and blocks. | ||
| 485 | ;; | ||
| 486 | ;; The other serialization functions of this files are helpers that will build | ||
| 487 | ;; the above list. Each function either returns a list, or elements that will | ||
| 488 | ;; be put in one. The elements of these lists will either be: | ||
| 489 | ;; - strings, | ||
| 490 | ;; In this case, the string is seen as a line to add to the configuraiton | ||
| 491 | ;; file. | ||
| 492 | ;; - a pair (cons 'begin-block string), | ||
| 493 | ;; In this case, a line "string {" is added to the configuration file, and | ||
| 494 | ;; the indentation level is increased by four. | ||
| 495 | ;; - the symbol 'end-block. | ||
| 496 | ;; In which case the indentation level is decreased by four, and the current | ||
| 497 | ;; configuration block is closed (with the line "}"). | ||
| 498 | |||
| 499 | ;; A few helper functions: | ||
| 500 | |||
| 501 | (define* (add-line-if field value | ||
| 502 | #:key (serializer %unset-value) | ||
| 503 | (suffix %unset-value)) | ||
| 504 | (if (eq? %unset-value value) | ||
| 505 | %unset-value | ||
| 506 | #~(string-append #$field " " | ||
| 507 | #$(if (eq? serializer %unset-value) | ||
| 508 | value | ||
| 509 | (serializer value)) | ||
| 510 | #$(if (eq? suffix %unset-value) | ||
| 511 | "" | ||
| 512 | suffix)))) | ||
| 513 | |||
| 514 | (define (add-block name content) | ||
| 515 | (let ((content (filter | ||
| 516 | (lambda (elt) (not (eq? elt %unset-value))) | ||
| 517 | content))) | ||
| 518 | (if (equal? content '()) | ||
| 519 | '() | ||
| 520 | (append | ||
| 521 | (list #~(cons 'begin-block #$name)) | ||
| 522 | content | ||
| 523 | (list #~'end-block))))) | ||
| 524 | |||
| 525 | (define-syntax add-block* | ||
| 526 | (syntax-rules () | ||
| 527 | ((add-block* name elt ...) | ||
| 528 | (add-block name (append elt ...))))) | ||
| 529 | |||
| 530 | ;; Serialization functions: | ||
| 531 | |||
| 532 | (define (box str) | ||
| 533 | (let* ((len (string-length str)) | ||
| 534 | (line (make-string (+ 8 len) #\#))) | ||
| 535 | (list | ||
| 536 | line | ||
| 537 | (string-append "### " str " ###") | ||
| 538 | line))) | ||
| 539 | |||
| 540 | (define (with-heading str lst) | ||
| 541 | (define (heading str) | ||
| 542 | (let* ((len (string-length str)) | ||
| 543 | (line (make-string (+ 2 len) #\#))) | ||
| 544 | (list | ||
| 545 | "" ;add an empty line before the configuration section. | ||
| 546 | (string-append "# " str) | ||
| 547 | line))) | ||
| 548 | (if (equal? lst '()) | ||
| 549 | '() ;if the configuration block is empty, do not add the heading. | ||
| 550 | (append (heading str) lst))) | ||
| 551 | |||
| 552 | (define-inlinable (serialize-boolean-yn b) | ||
| 553 | (if b "yes" "no")) | ||
| 554 | (define-inlinable (serialize-boolean-ed b) | ||
| 555 | (if b "enable" "disable")) | ||
| 556 | |||
| 557 | (define-inlinable (serialize-binding binder key value) | ||
| 558 | #~(string-append #$binder #$key " " #$value)) | ||
| 559 | |||
| 560 | (define (serialize-mouse-binding var) | ||
| 561 | (let* ((ev (car var)) | ||
| 562 | (ev-code (number->string ev)) | ||
| 563 | (command (cdr var))) | ||
| 564 | (serialize-binding "bindcode " ev-code command))) | ||
| 565 | |||
| 566 | (define (serialize-keybinding var) | ||
| 567 | (let ((name (symbol->string (car var))) | ||
| 568 | (value (cdr var))) | ||
| 569 | (serialize-binding "bindsym " name value))) | ||
| 570 | |||
| 571 | (define (serialize-gesture var) | ||
| 572 | (let ((name (symbol->string (car var))) | ||
| 573 | (value (cdr var))) | ||
| 574 | (serialize-binding "bindgesture " name value))) | ||
| 575 | |||
| 576 | (define (serialize-variable var) | ||
| 577 | (let ((name (symbol->string (car var))) | ||
| 578 | (value (cdr var))) | ||
| 579 | (serialize-binding "set $" name value))) | ||
| 580 | |||
| 581 | (define (serialize-exec b) | ||
| 582 | (if b | ||
| 583 | (lambda (exe) | ||
| 584 | #~(string-append "exec_always " #$exe)) | ||
| 585 | (lambda (exe) | ||
| 586 | #~(string-append "exec " #$exe)))) | ||
| 587 | |||
| 588 | (define (serialize-output out) | ||
| 589 | (let* ((pre-ident (sway-output-identifier out)) | ||
| 590 | (ident (if (symbol? pre-ident) | ||
| 591 | (symbol->string pre-ident) | ||
| 592 | (string-append "\"" pre-ident "\""))) | ||
| 593 | (background (let ((bg (sway-output-background out))) | ||
| 594 | (if (pair? bg) | ||
| 595 | bg | ||
| 596 | (cons bg 'fill)))) | ||
| 597 | (resolution (sway-output-resolution out)) | ||
| 598 | (position (sway-output-position out)) | ||
| 599 | (extra-content (sway-output-extra-content out))) | ||
| 600 | (add-block | ||
| 601 | (string-append "output " ident) | ||
| 602 | (cons* | ||
| 603 | ;; Optional elements. | ||
| 604 | (add-line-if "bg" (car background) | ||
| 605 | #:suffix | ||
| 606 | (string-append " " (symbol->string (cdr background)))) | ||
| 607 | (add-line-if "resolution" resolution) | ||
| 608 | (add-line-if "position" position | ||
| 609 | #:serializer | ||
| 610 | (lambda (p) | ||
| 611 | (string-append (number->string (point-x p)) | ||
| 612 | " " | ||
| 613 | (number->string (point-y p))))) | ||
| 614 | ;; Extra-content: inlined as-is. | ||
| 615 | extra-content)))) | ||
| 616 | |||
| 617 | (define (serialize-input input) | ||
| 618 | (define-inlinable (fetch-arg layout acc) | ||
| 619 | (if (eq? layout %unset-value) | ||
| 620 | %unset-value | ||
| 621 | (acc layout))) | ||
| 622 | |||
| 623 | (define-inlinable (unfalse f) | ||
| 624 | (lambda (arg) | ||
| 625 | (let ((res (f arg))) | ||
| 626 | (if res res %unset-value)))) | ||
| 627 | |||
| 628 | (define-inlinable (unnil f) | ||
| 629 | (lambda (arg) | ||
| 630 | (let ((res (f arg))) | ||
| 631 | (if (nil? res) %unset-value res)))) | ||
| 632 | |||
| 633 | (let* ((pre-ident (sway-input-identifier input)) | ||
| 634 | (ident (if (symbol? pre-ident) | ||
| 635 | (symbol->string pre-ident) | ||
| 636 | (string-append "\"" pre-ident "\""))) | ||
| 637 | |||
| 638 | ;; unpack the `layout' field. | ||
| 639 | (layout (sway-input-layout input)) | ||
| 640 | (xkb-layout (fetch-arg layout keyboard-layout-name)) | ||
| 641 | (xkb-variant (fetch-arg layout (unfalse keyboard-layout-variant))) | ||
| 642 | (xkb-model (fetch-arg layout (unfalse keyboard-layout-model))) | ||
| 643 | (xkb-options (fetch-arg layout (unnil keyboard-layout-options))) | ||
| 644 | |||
| 645 | (tap (sway-input-tap input)) | ||
| 646 | (dwt (sway-input-disable-while-typing input)) | ||
| 647 | (dwtp (sway-input-disable-while-trackpointing input)) | ||
| 648 | (extra-content (sway-input-extra-content input))) | ||
| 649 | (add-block | ||
| 650 | (string-append "input " ident) | ||
| 651 | (cons* | ||
| 652 | ;; Optional. | ||
| 653 | (add-line-if "xkb_layout" xkb-layout) | ||
| 654 | (add-line-if "xkb_model" xkb-model) | ||
| 655 | (add-line-if "xkb_variant" xkb-variant) | ||
| 656 | (add-line-if "xkb_options" xkb-options | ||
| 657 | #:serializer (lambda (l) (string-join l ","))) | ||
| 658 | (add-line-if "dwt" dwt | ||
| 659 | #:serializer serialize-boolean-ed) | ||
| 660 | (add-line-if "dwtp" dwtp | ||
| 661 | #:serializer serialize-boolean-ed) | ||
| 662 | (add-line-if "tap" tap | ||
| 663 | #:serializer serialize-boolean-ed) | ||
| 664 | ;; extra-content inlined as-is. | ||
| 665 | extra-content)))) | ||
| 666 | |||
| 667 | (define (serialize-colors colors) | ||
| 668 | (define (border-serializer val) | ||
| 669 | (string-append (sway-border-color-border val) | ||
| 670 | " " (sway-border-color-background val) | ||
| 671 | " " (sway-border-color-text val))) | ||
| 672 | (if (eq? %unset-value colors) | ||
| 673 | '() | ||
| 674 | (let ((background (sway-color-background colors)) | ||
| 675 | (statusline (sway-color-statusline colors)) | ||
| 676 | (focused-background (sway-color-focused-background colors)) | ||
| 677 | (focused-statusline (sway-color-focused-statusline colors)) | ||
| 678 | (focused-workspace (sway-color-focused-workspace colors)) | ||
| 679 | (active-workspace (sway-color-active-workspace colors)) | ||
| 680 | (inactive-workspace (sway-color-inactive-workspace colors)) | ||
| 681 | (urgent-workspace (sway-color-urgent-workspace colors)) | ||
| 682 | (binding-mode (sway-color-binding-mode colors))) | ||
| 683 | (add-block | ||
| 684 | "colors" | ||
| 685 | (list | ||
| 686 | (add-line-if "background" background) | ||
| 687 | (add-line-if "statusline" statusline) | ||
| 688 | (add-line-if "focused_background" focused-background) | ||
| 689 | (add-line-if "focused_statusline" focused-statusline) | ||
| 690 | (add-line-if "focused_workspace" focused-workspace | ||
| 691 | #:serializer border-serializer) | ||
| 692 | (add-line-if "active_workspace" active-workspace | ||
| 693 | #:serializer border-serializer) | ||
| 694 | (add-line-if "inactive_workspace" inactive-workspace | ||
| 695 | #:serializer border-serializer) | ||
| 696 | (add-line-if "urgent_workspace" urgent-workspace | ||
| 697 | #:serializer border-serializer) | ||
| 698 | (add-line-if "binding_mode" binding-mode | ||
| 699 | #:serializer border-serializer)))))) | ||
| 700 | |||
| 701 | (define (serialize-mode mode) | ||
| 702 | (let ((name (sway-mode-mode-name mode)) | ||
| 703 | (keys (sway-mode-keybindings mode)) | ||
| 704 | (clicks (sway-mode-mouse-bindings mode))) | ||
| 705 | (add-block* | ||
| 706 | (string-append "mode \"" name "\"") | ||
| 707 | (map serialize-keybinding keys) | ||
| 708 | (map serialize-mouse-binding clicks)))) | ||
| 709 | |||
| 710 | (define (serialize-bar bar) | ||
| 711 | (define serialize-symbol | ||
| 712 | symbol->string) | ||
| 713 | |||
| 714 | (let ((identifier (symbol->string (sway-bar-identifier bar))) | ||
| 715 | (position (sway-bar-position bar)) | ||
| 716 | (hidden-state (sway-bar-hidden-state bar)) | ||
| 717 | (status-command (sway-bar-status-command bar)) | ||
| 718 | (binding-mode-indicator (sway-bar-binding-mode-indicator bar)) | ||
| 719 | (mouse-bindings (sway-bar-mouse-bindings bar)) | ||
| 720 | (extra-content (sway-bar-extra-content bar)) | ||
| 721 | (colors (sway-bar-colors bar))) | ||
| 722 | (add-block* | ||
| 723 | (string-append "bar " identifier) | ||
| 724 | |||
| 725 | (if (eq? colors %unset-value) | ||
| 726 | '() | ||
| 727 | (serialize-colors colors)) | ||
| 728 | (list | ||
| 729 | (add-line-if "position" position | ||
| 730 | #:serializer serialize-symbol) | ||
| 731 | (add-line-if "hidden_state" hidden-state | ||
| 732 | #:serializer serialize-symbol) | ||
| 733 | (add-line-if "status_command" status-command) | ||
| 734 | (add-line-if "binding_mode_indicator" binding-mode-indicator | ||
| 735 | #:serializer serialize-boolean-yn)) | ||
| 736 | ;; Mouse-bindings and extra-content | ||
| 737 | (map serialize-mouse-binding mouse-bindings) | ||
| 738 | extra-content))) | ||
| 739 | |||
| 740 | (define (sway-configuration->file conf) | ||
| 741 | (let* ((extra (sway-configuration-extra-content conf)) | ||
| 742 | (bar (sway-configuration-bar conf))) | ||
| 743 | (computed-file | ||
| 744 | "sway-config" | ||
| 745 | #~(begin | ||
| 746 | (use-modules (ice-9 format) (ice-9 match) | ||
| 747 | (srfi srfi-1)) | ||
| 748 | |||
| 749 | (call-with-output-file #$output | ||
| 750 | (lambda (port) | ||
| 751 | |||
| 752 | ;; Add the (indented) line "s" to the output file. | ||
| 753 | (define (line s) | ||
| 754 | (lambda (i) | ||
| 755 | (format port "~a~a~%" i s) | ||
| 756 | i)) | ||
| 757 | |||
| 758 | ;; Begin a block "name" and adjust the indentation. | ||
| 759 | (define (begin-block name) | ||
| 760 | (lambda (i) | ||
| 761 | (format port "~a~a {~%" i name) | ||
| 762 | (string-append " " i))) | ||
| 763 | |||
| 764 | ;; Ends an open block and adjust the indentation. | ||
| 765 | ;; Note: we must currently be in a configuration block. | ||
| 766 | ;; Otherwise, `string-drop' might fail. | ||
| 767 | (define (end-block) | ||
| 768 | (lambda (i) | ||
| 769 | (let ((i (string-drop i 4))) | ||
| 770 | (format port "~a}~%" i) | ||
| 771 | i))) | ||
| 772 | |||
| 773 | ;; Helper function. The configuration is represented as a list | ||
| 774 | ;; of actions (alter the indentation level, add a line, ...). | ||
| 775 | ;; This function recognises the action and calls the right | ||
| 776 | ;; function among those defined above. | ||
| 777 | (define (serializer-dispatch-m arg) | ||
| 778 | (match arg | ||
| 779 | ;; Special cases: | ||
| 780 | (('begin-block . str) (begin-block str)) | ||
| 781 | ('end-block (end-block)) | ||
| 782 | ;; Default case: `arg' is assumed to be a string. | ||
| 783 | (_ (line arg)))) | ||
| 784 | |||
| 785 | (define (serializer-dispatch elt i) | ||
| 786 | ((serializer-dispatch-m elt) i)) | ||
| 787 | |||
| 788 | (fold | ||
| 789 | ;; Dispatch function: depending on its argument, it will change | ||
| 790 | ;; the indentation level or add a line to the output file. | ||
| 791 | serializer-dispatch | ||
| 792 | |||
| 793 | ;; Initial indentation string. This string is prepended to | ||
| 794 | ;; lines before their serialization. | ||
| 795 | "" | ||
| 796 | ;; List of lines or indentation modifiers. | ||
| 797 | (list | ||
| 798 | ;; Header. | ||
| 799 | #$@(box "Auto-generated configuration") | ||
| 800 | "# DO NOT EDIT MANUALLY." | ||
| 801 | |||
| 802 | ;; Variables. | ||
| 803 | #$@(with-heading "Variables." | ||
| 804 | (map serialize-variable | ||
| 805 | (sway-configuration-variables conf))) | ||
| 806 | |||
| 807 | ;; Outputs. | ||
| 808 | #$@(with-heading "Outputs." | ||
| 809 | (flatmap serialize-output | ||
| 810 | (sway-configuration-outputs conf))) | ||
| 811 | |||
| 812 | ;; Inputs. | ||
| 813 | #$@(with-heading "Inputs." | ||
| 814 | (flatmap serialize-input | ||
| 815 | (sway-configuration-inputs conf))) | ||
| 816 | |||
| 817 | ;; Bar configuration: | ||
| 818 | ;; If the bar is unset, do not include anything. | ||
| 819 | #$@(if (eq? bar %unset-value) | ||
| 820 | '() | ||
| 821 | (with-heading "Bar configuration." | ||
| 822 | (serialize-bar bar))) | ||
| 823 | |||
| 824 | ;; Keybindings. | ||
| 825 | #$@(with-heading "Keybindings." | ||
| 826 | (map serialize-keybinding | ||
| 827 | (sway-configuration-keybindings conf))) | ||
| 828 | ;; Gestures. | ||
| 829 | #$@(with-heading "Gestures." | ||
| 830 | (map serialize-gesture | ||
| 831 | (sway-configuration-gestures conf))) | ||
| 832 | |||
| 833 | ;; Modes. | ||
| 834 | #$@(with-heading "Modes." | ||
| 835 | (flatmap serialize-mode | ||
| 836 | (sway-configuration-modes conf))) | ||
| 837 | |||
| 838 | ;; Startup-Programs. | ||
| 839 | #$@(with-heading | ||
| 840 | "Programs to execute (at startup)." | ||
| 841 | (map (serialize-exec #f) | ||
| 842 | (sway-configuration-startup-programs conf))) | ||
| 843 | ;; startup+reload-programs. | ||
| 844 | #$@(with-heading | ||
| 845 | "Programs to execute (at startup & after reload)." | ||
| 846 | (map (serialize-exec #t) | ||
| 847 | (sway-configuration-startup+reload-programs conf))) | ||
| 848 | |||
| 849 | ;; Extra-content. | ||
| 850 | #$@(with-heading "Extra-content" extra))))))))) | ||
| 851 | |||
| 852 | |||
| 853 | ;;; | ||
| 854 | ;;; Definition of the Home Service. | ||
| 855 | ;;; | ||
| 856 | |||
| 857 | (define (sway-configuration->files sway-conf) | ||
| 858 | `((".config/sway/config" ,(sway-configuration->file sway-conf)))) | ||
| 859 | |||
| 860 | (define home-sway-service-type | ||
| 861 | (service-type | ||
| 862 | (name 'home-sway-config) | ||
| 863 | (extensions | ||
| 864 | (list (service-extension home-files-service-type | ||
| 865 | sway-configuration->files) | ||
| 866 | (service-extension home-profile-service-type | ||
| 867 | sway-configuration-packages))) | ||
| 868 | (description "Configure Sway by providing a file | ||
| 869 | @file{~/.config/sway/config}.") | ||
| 870 | (default-value (sway-configuration)))) | ||
diff --git a/gnu/local.mk b/gnu/local.mk index 46a687c28eb..90e22f15675 100644 --- a/gnu/local.mk +++ b/gnu/local.mk | |||
| @@ -114,6 +114,7 @@ GNU_SYSTEM_MODULES = \ | |||
| 114 | %D%/home/services/shepherd.scm \ | 114 | %D%/home/services/shepherd.scm \ |
| 115 | %D%/home/services/sound.scm \ | 115 | %D%/home/services/sound.scm \ |
| 116 | %D%/home/services/ssh.scm \ | 116 | %D%/home/services/ssh.scm \ |
| 117 | %D%/home/services/sway.scm \ | ||
| 117 | %D%/home/services/syncthing.scm \ | 118 | %D%/home/services/syncthing.scm \ |
| 118 | %D%/home/services/mcron.scm \ | 119 | %D%/home/services/mcron.scm \ |
| 119 | %D%/home/services/utils.scm \ | 120 | %D%/home/services/utils.scm \ |
