|
| 1 | +;; Sets a list of options and their corresponding values, |
| 2 | +;; automatically quoting each option, transforming it into a symbol. |
| 3 | +;; In other words, this can be used just like @code{set}, but without |
| 4 | +;; needing to quote each option manually. |
| 5 | + |
| 6 | +;; @example |
| 7 | +;; (setq border-px 10 |
| 8 | +;; border-color \"#00FF00\") |
| 9 | +;; @end example |
| 10 | +(define-syntax setq-args |
| 11 | + (syntax-rules () |
| 12 | + ((setq-args) |
| 13 | + (syntax-error "Missing arguments to setq")) |
| 14 | + ((setq-args option) |
| 15 | + (syntax-error "Missing value to option in setq")) |
| 16 | + ((setq-args option exp) |
| 17 | + `(option ,exp)) |
| 18 | + ((setq-args option exp rest ...) |
| 19 | + (append `(option ,exp) (setq-args rest ...))))) |
| 20 | + |
| 21 | +(define-syntax setq |
| 22 | + (syntax-rules () |
| 23 | + ((setq) |
| 24 | + (syntax-error "Missing arguments to setq")) |
| 25 | + ((setq option) |
| 26 | + (syntax-error "Missing value to option in setq")) |
| 27 | + ((setq rest ...) |
| 28 | + (apply set (setq-args rest ...))))) |
| 29 | + |
| 30 | +(define* (dwl:run-async fn #:optional (callback #f)) |
| 31 | + "Evalutes FN asynchronously, without blocking the main thread. |
| 32 | +CALLBACK will be executed once FN has finished its execution, being |
| 33 | +passed the potential return value from FN. If no callback is provided, |
| 34 | +the return value will be ignored. |
| 35 | +
|
| 36 | +For thread safety, FN should not make use of dwl-guile bindings, although |
| 37 | +some bindings can be used without issue, such as @code{dwl:spawn}. Instead, |
| 38 | +try to move dwl-guile calls to the callback." |
| 39 | + ((@ (ice-9 futures) make-future) |
| 40 | + (lambda () |
| 41 | + ;; This is a really hacky (but easy) solution for ensuring thread safety |
| 42 | + ;; while still allowing for dwl-guile bindings to be called asynchronously. |
| 43 | + ;; Essentially, we are executing a shell command from the Guile context |
| 44 | + ;; in order to send a command to the main thread Guile context, via |
| 45 | + ;; the Wayland socket. A lot of overhead, but speed is not of great concern |
| 46 | + ;; when doing async calls (it is still quite fast). |
| 47 | + (dwl:spawn dwl:%binary-path "-e" (object->string (callback (fn))))))) |
| 48 | + |
| 49 | +(define* (dwl:start-repl-server) |
| 50 | + "Starts a local Guile REPL server, listening on a UNIX socket at path |
| 51 | +@path{/tmp/dwl-guile.socket}. This REPL allows you to execute expressions |
| 52 | +in the dwl-guile context, just like @code{dwl-guile -e \"<exp\"}, but with |
| 53 | +a more user-friendly interface. |
| 54 | +
|
| 55 | +The preferred way of connecting to the REPL server is using Geiser in Emacs. |
| 56 | +You can connect to the server by calling @code{geiser-connect-local}, and |
| 57 | +specifying the UNIX-socket path. |
| 58 | +
|
| 59 | +Note that this needs to be explicitly called in order for the REPL server to |
| 60 | +be started! |
| 61 | +" |
| 62 | + (use-modules (system repl server)) |
| 63 | + |
| 64 | + ;; REPL socket path is dependent on the type of build, i.e. stable or devel. |
| 65 | + ;; Therefore, this variable is set during the initial configuration load in C. |
| 66 | + (define (kill-server) |
| 67 | + (when (file-exists? dwl:%repl-socket-path) |
| 68 | + (delete-file dwl:%repl-socket-path) |
| 69 | + (stop-server-and-clients!))) |
| 70 | + |
| 71 | + (unless (file-exists? dwl:%repl-socket-path) |
| 72 | + (begin |
| 73 | + (spawn-server (make-unix-domain-server-socket #:path dwl:%repl-socket-path)) |
| 74 | + (add-hook! dwl:hook-quit kill-server)))) |
| 75 | + |
| 76 | +(define* (dwl:list-options) |
| 77 | + "Lists all available options that can be configured using the @code{set} |
| 78 | +procedure." |
| 79 | + (hash-fold |
| 80 | + (lambda (key value acc) |
| 81 | + ;; Discard value since it just contains C-related metadata |
| 82 | + (cons key acc)) |
| 83 | + '() |
| 84 | + dwl:%metadata)) |
| 85 | + |
| 86 | +(define* (dwl:list-keysyms) |
| 87 | + "Lists all available keysyms and their respective keycode that can be used |
| 88 | +when binding keys and buttons using the @code{bind} procedure." |
| 89 | + (define (iterator key value acc) |
| 90 | + (cons `(,key ,value) acc)) |
| 91 | + |
| 92 | + (hash-fold iterator |
| 93 | + (hash-fold iterator '() dwl:%keycodes) |
| 94 | + dwl:%keycodes-mouse)) |
| 95 | + |
| 96 | +(define* (dwl:show-options) |
| 97 | + "Same as @code{dwl:list-options}, but the list of options are printed |
| 98 | +in a readable format." |
| 99 | + (for-each |
| 100 | + (lambda (option) (display (string-append (symbol->string option) "\n"))) |
| 101 | + (sort-list (dwl:list-options) |
| 102 | + (lambda (x y) (string< (symbol->string x) |
| 103 | + (symbol->string y)))))) |
| 104 | + |
| 105 | +(define* (dwl:show-keysyms) |
| 106 | + "Same as @code{dwl:list-keysyms}, but the list of keysyms are printed |
| 107 | +in a readable format." |
| 108 | + (for-each |
| 109 | + (lambda (pair) |
| 110 | + (display (string-append (car pair) " = " (number->string (cadr pair)) "\n"))) |
| 111 | + (sort-list (dwl:list-keysyms) |
| 112 | + (lambda (x y) (< (cadr x) (cadr y)))))) |
| 113 | + |
| 114 | +(define* (dwl:set-tty-keys modifiers #:optional (ttys 12)) |
| 115 | + "Helper procedure for binding all ttys to MODIFIERS + F[1-TTYS]." |
| 116 | + (for-each |
| 117 | + (lambda (v) |
| 118 | + (set-keys (string-append modifiers "-<F" (number->string v) ">") `(dwl:chvt ,v))) |
| 119 | + (iota ttys 1))) |
| 120 | + |
| 121 | +(define* (dwl:set-tag-keys view-modifiers move-modifiers #:optional (tags 9)) |
| 122 | + "Helper procedure for adding bindings for viewing and moving clients to |
| 123 | +tags 1-TAGS. The key modifiers used for viewing and moving can be set by |
| 124 | +VIEW-MODIFIERS, and MOVE-MODIFIERS, respectively." |
| 125 | + (for-each |
| 126 | + (lambda (t) |
| 127 | + (set-keys (string-append view-modifiers "-" (number->string t)) `(dwl:view ,t) |
| 128 | + (string-append move-modifiers "-" (number->string t)) `(dwl:tag ,t))) |
| 129 | + (iota tags 1))) |
| 130 | + |
| 131 | +;; Set required options. |
| 132 | +;; These can not be inhibited, but they can easily be overridden if needed. |
| 133 | +(setq tags (map number->string (iota 9 1))) |
| 134 | + |
| 135 | +;; Define layouts before monitor rules to make sure layout is available. |
| 136 | +(set-layouts 'default "[]=" 'dwl:tile) |
| 137 | + |
| 138 | +;; There must be a default monitor rule (i.e. with name == NULL) |
| 139 | +(set-monitor-rules '((masters . 1) |
| 140 | + (master-factor . 0.55) |
| 141 | + (scale . 2) |
| 142 | + (transform . TRANSFORM-NORMAL) |
| 143 | + (layout . default))) |
| 144 | + |
| 145 | +(set-xkb-rules '((options . "compose:prsc,caps:hyper"))) |
| 146 | +(load "./keys.scm") |
0 commit comments