desktop.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2022 Ludovic Courtès <ludo@gnu.org>
  3. ;;; Copyright © 2022 ( <paren@disroot.org>
  4. ;;; Copyright © 2023 conses <contact@conses.eu>
  5. ;;; Copyright © 2023 Janneke Nieuwenhuizen <janneke@gnu.org>
  6. ;;;
  7. ;;; This file is part of GNU Guix.
  8. ;;;
  9. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  10. ;;; under the terms of the GNU General Public License as published by
  11. ;;; the Free Software Foundation; either version 3 of the License, or (at
  12. ;;; your option) any later version.
  13. ;;;
  14. ;;; GNU Guix is distributed in the hope that it will be useful, but
  15. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ;;; GNU General Public License for more details.
  18. ;;;
  19. ;;; You should have received a copy of the GNU General Public License
  20. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  21. (define-module (gnu home services desktop)
  22. #:use-module (gnu home services)
  23. #:use-module (gnu home services shepherd)
  24. #:use-module (gnu services configuration)
  25. #:autoload (gnu packages glib) (dbus)
  26. #:autoload (gnu packages xdisorg) (redshift unclutter)
  27. #:autoload (gnu packages xorg) (setxkbmap xmodmap)
  28. #:use-module (guix records)
  29. #:use-module (guix gexp)
  30. #:use-module (srfi srfi-1)
  31. #:use-module (ice-9 match)
  32. #:export (home-redshift-configuration
  33. home-redshift-configuration?
  34. home-redshift-service-type
  35. home-dbus-configuration
  36. home-dbus-service-type
  37. home-unclutter-configuration
  38. home-unclutter-service-type
  39. home-xmodmap-configuration
  40. home-xmodmap-service-type))
  41. ;;;
  42. ;;; Redshift.
  43. ;;;
  44. (define (serialize-integer field value)
  45. (string-append (match field
  46. ('daytime-temperature "temp-day")
  47. ('nighttime-temperature "temp-night")
  48. ('daytime-brightness "brightness-day")
  49. ('nighttime-brightness "brightness-night")
  50. ('latitude "lat")
  51. ('longitude "lon")
  52. (_ (symbol->string field)))
  53. "=" (number->string value) "\n"))
  54. (define (serialize-symbol field value)
  55. (string-append (symbol->string field)
  56. "=" (symbol->string value) "\n"))
  57. (define (serialize-string field value)
  58. (string-append (symbol->string field)
  59. "=" value "\n"))
  60. (define serialize-inexact-number serialize-integer)
  61. (define (inexact-number? n)
  62. (and (number? n) (inexact? n)))
  63. (define-maybe inexact-number)
  64. (define-maybe string)
  65. (define (serialize-raw-configuration-string field value)
  66. value)
  67. (define raw-configuration-string? string?)
  68. (define-configuration home-redshift-configuration
  69. (redshift
  70. (file-like redshift)
  71. "Redshift package to use.")
  72. (location-provider
  73. (symbol 'geoclue2)
  74. "Geolocation provider---@code{'manual} or @code{'geoclue2}.
  75. In the former case, you must also specify the @code{latitude} and
  76. @code{longitude} fields so Redshift can determine daytime at your place. In
  77. the latter case, the Geoclue system service must be running; it will be
  78. queried for location information.")
  79. (adjustment-method
  80. (symbol 'randr)
  81. "Color adjustment method.")
  82. ;; Default values from redshift(1).
  83. (daytime-temperature
  84. (integer 6500)
  85. "Daytime color temperature (kelvins).")
  86. (nighttime-temperature
  87. (integer 4500)
  88. "Nighttime color temperature (kelvins).")
  89. (daytime-brightness
  90. maybe-inexact-number
  91. "Daytime screen brightness, between 0.1 and 1.0.")
  92. (nighttime-brightness
  93. maybe-inexact-number
  94. "Nighttime screen brightness, between 0.1 and 1.0.")
  95. (latitude
  96. maybe-inexact-number
  97. "Latitude, when @code{location-provider} is @code{'manual}.")
  98. (longitude
  99. maybe-inexact-number
  100. "Longitude, when @code{location-provider} is @code{'manual}.")
  101. (dawn-time
  102. maybe-string
  103. "Custom time for the transition from night to day in the
  104. morning---@code{\"HH:MM\"} format. When specified, solar elevation is not
  105. used to determine the daytime/nighttime period.")
  106. (dusk-time
  107. maybe-string
  108. "Likewise, custom time for the transition from day to night in the
  109. evening.")
  110. (extra-content
  111. (raw-configuration-string "")
  112. "Extra content appended as-is to the Redshift configuration file. Run
  113. @command{man redshift} for more information about the configuration file
  114. format."))
  115. (define (serialize-redshift-configuration config)
  116. (define location-fields
  117. '(latitude longitude))
  118. (define (location-field? field)
  119. (memq (configuration-field-name field) location-fields))
  120. (define (secondary-field? field)
  121. (or (location-field? field)
  122. (memq (configuration-field-name field)
  123. '(redshift extra-content))))
  124. #~(string-append
  125. "[redshift]\n"
  126. #$(serialize-configuration config
  127. (remove secondary-field?
  128. home-redshift-configuration-fields))
  129. #$(home-redshift-configuration-extra-content config)
  130. "\n[manual]\n"
  131. #$(serialize-configuration config
  132. (filter location-field?
  133. home-redshift-configuration-fields))))
  134. (define (redshift-shepherd-service config)
  135. (define config-file
  136. (computed-file "redshift.conf"
  137. #~(call-with-output-file #$output
  138. (lambda (port)
  139. (display #$(serialize-redshift-configuration config)
  140. port)))))
  141. (list (shepherd-service
  142. (documentation "Redshift program.")
  143. (provision '(redshift))
  144. ;; FIXME: This fails to start if Home is first activated from a
  145. ;; non-X11 session.
  146. (start #~(make-forkexec-constructor
  147. (list #$(file-append redshift "/bin/redshift")
  148. "-c" #$config-file)))
  149. (stop #~(make-kill-destructor))
  150. (actions (list (shepherd-configuration-action config-file))))))
  151. (define home-redshift-service-type
  152. (service-type
  153. (name 'home-redshift)
  154. (extensions (list (service-extension home-shepherd-service-type
  155. redshift-shepherd-service)))
  156. (default-value (home-redshift-configuration))
  157. (description
  158. "Run Redshift, a program that adjusts the color temperature of display
  159. according to time of day.")))
  160. ;;;
  161. ;;; D-Bus.
  162. ;;;
  163. (define-record-type* <home-dbus-configuration>
  164. home-dbus-configuration make-home-dbus-configuration
  165. home-dbus-configuration?
  166. (dbus home-dbus-dbus ;file-like
  167. (default dbus)))
  168. (define (home-dbus-shepherd-services config)
  169. (list (shepherd-service
  170. (documentation "Run the D-Bus daemon in session-specific mode.")
  171. (provision '(dbus))
  172. (start #~(make-forkexec-constructor
  173. (list #$(file-append (home-dbus-dbus config)
  174. "/bin/dbus-daemon")
  175. "--nofork" "--session"
  176. (format #f "--address=unix:path=~a/bus"
  177. (or (getenv "XDG_RUNTIME_DIR")
  178. (format #f "/run/user/~a"
  179. (getuid)))))
  180. #:environment-variables
  181. (cons "DBUS_VERBOSE=1"
  182. (default-environment-variables))
  183. #:log-file
  184. (format #f "~a/dbus.log"
  185. (or (getenv "XDG_LOG_HOME")
  186. (format #f "~a/.local/var/log"
  187. (getenv "HOME"))))))
  188. (stop #~(make-kill-destructor)))))
  189. (define (home-dbus-environment-variables config)
  190. '(("DBUS_SESSION_BUS_ADDRESS"
  191. . "unix:path=${XDG_RUNTIME_DIR:-/run/user/$UID}/bus")))
  192. (define home-dbus-service-type
  193. (service-type
  194. (name 'home-dbus)
  195. (extensions
  196. (list (service-extension home-shepherd-service-type
  197. home-dbus-shepherd-services)
  198. (service-extension home-environment-variables-service-type
  199. home-dbus-environment-variables)))
  200. (default-value (home-dbus-configuration))
  201. (description
  202. "Run the session-specific D-Bus inter-process message bus.")))
  203. ;;;
  204. ;;; Unclutter.
  205. ;;;
  206. (define-configuration/no-serialization home-unclutter-configuration
  207. (unclutter
  208. (file-like unclutter)
  209. "The @code{unclutter} package to use.")
  210. (idle-timeout
  211. (integer 5)
  212. "Timeout in seconds after which to hide the cursor."))
  213. (define (home-unclutter-shepherd-service config)
  214. (list
  215. (shepherd-service
  216. (provision '(unclutter))
  217. (requirement '())
  218. (one-shot? #t)
  219. (start #~(make-forkexec-constructor
  220. (list
  221. #$(file-append
  222. (home-unclutter-configuration-unclutter config)
  223. "/bin/unclutter")
  224. "-idle"
  225. (number->string
  226. #$(home-unclutter-configuration-idle-timeout config)))
  227. #:log-file (string-append
  228. (or (getenv "XDG_LOG_HOME")
  229. (format #f "~a/.local/var/log"
  230. (getenv "HOME")))
  231. "/unclutter.log"))))))
  232. (define home-unclutter-service-type
  233. (service-type
  234. (name 'home-unclutter)
  235. (extensions
  236. (list
  237. (service-extension home-shepherd-service-type
  238. home-unclutter-shepherd-service)))
  239. (default-value (home-unclutter-configuration))
  240. (description "Run the @code{unclutter} daemon, which, on systems using the
  241. Xorg graphical display server, automatically hides the cursor after a
  242. user-defined timeout has expired.")))
  243. ;;;
  244. ;;; Xmodmap.
  245. ;;;
  246. (define-configuration/no-serialization home-xmodmap-configuration
  247. (xmodmap
  248. (file-like xmodmap)
  249. "The @code{xmodmap} package to use.")
  250. (key-map
  251. (list '())
  252. "List of expressions to be read by @code{xmodmap} on service startup."))
  253. (define (serialize-xmodmap-configuration field-name val)
  254. (define serialize-field
  255. (match-lambda
  256. ((key . value)
  257. (format #f "~a = ~a" key value))
  258. (e e)))
  259. #~(string-append
  260. #$@(interpose (map serialize-field val) "\n" 'suffix)))
  261. (define (xmodmap-shepherd-service config)
  262. (define config-file
  263. (mixed-text-file
  264. "config"
  265. (serialize-xmodmap-configuration
  266. #f (home-xmodmap-configuration-key-map config))))
  267. (list
  268. (shepherd-service
  269. (provision '(xmodmap))
  270. (start #~(make-system-constructor
  271. (string-join
  272. (list #$(file-append
  273. (home-xmodmap-configuration-xmodmap config)
  274. "/bin/xmodmap")
  275. #$config-file))))
  276. (stop #~(make-system-constructor
  277. #$(file-append setxkbmap "/bin/setxkbmap")))
  278. (documentation "On startup, run @code{xmodmap} and read the expressions in
  279. the configuration file. On stop, reset all the mappings back to the
  280. defaults."))))
  281. (define home-xmodmap-service-type
  282. (service-type
  283. (name 'home-xmodmap)
  284. (extensions
  285. (list
  286. (service-extension home-shepherd-service-type
  287. xmodmap-shepherd-service)))
  288. (default-value (home-xmodmap-configuration))
  289. (description "Run the @code{xmodmap} utility to modify keymaps and pointer
  290. buttons under the Xorg display server via user-defined expressions.")))