summaryrefslogtreecommitdiff
path: root/tw/services
diff options
context:
space:
mode:
authorTimo Wilken2023-09-12 21:16:20 +0200
committerTimo Wilken2023-09-12 21:20:19 +0200
commita082af65ad53e4703b9540647aff9a716fdda86b (patch)
tree4d18f2d547878caa4aec18e80fc7653a984338c7 /tw/services
parentd44b9efda2d387430e63c1d6cd426c88bcde2eda (diff)
Factor out common desktop services
Most of the code for setting desktop layouts is common between machines. Also, make the blueman-applet service reusable.
Diffstat (limited to 'tw/services')
-rw-r--r--tw/services/desktop.scm130
-rw-r--r--tw/services/files/polybar.ini239
2 files changed, 369 insertions, 0 deletions
diff --git a/tw/services/desktop.scm b/tw/services/desktop.scm
new file mode 100644
index 00000000..b0bb4e8a
--- /dev/null
+++ b/tw/services/desktop.scm
@@ -0,0 +1,130 @@
+(define-module (tw services desktop)
+ #:use-module (gnu)
+ #:use-module (gnu home services)
+ #:use-module (gnu home services shepherd)
+ #:use-module ((gnu packages networking) #:select (blueman))
+ #:use-module ((gnu packages wm) #:select (polybar))
+ #:use-module ((gnu packages xdisorg) #:select (numlockx hsetroot))
+ #:use-module ((gnu packages xorg) #:select (xrandr xset))
+ #:use-module (gnu services configuration)
+ #:use-module (guix gexp)
+ #:use-module (guix packages)
+ #:use-module ((guix records) #:select (match-record))
+ #:use-module (srfi srfi-1)
+ #:use-module ((tw theme) #:select (catppuccin-polybar))
+ #:export (home-desktop-layout-configuration
+ home-monitor-configuration
+ home-desktop-layout-service-type
+ home-blueman-service-type))
+
+
+;; Monitor layout and polybars
+
+(define (list-of-strings? thing)
+ (and (list? thing) (every string? thing)))
+
+(define-configuration/no-serialization home-monitor-configuration
+ (name string "The monitor's name in X11.")
+ (xrandr-options (list-of-strings '()) "Options to pass to xrandr to
+configure this monitor."))
+
+(define (list-of-monitors? thing)
+ (and (list? thing) (every home-monitor-configuration? thing)))
+
+(define-configuration/no-serialization home-desktop-layout-configuration
+ (desktop-background string "Path to an image that will be set as the desktop
+background. An initial @code{~/} is replaced with $HOME/.")
+ (monitors list-of-monitors "List of monitor declarations to apply."))
+
+(define (polybar-config monitors)
+ `(("polybar/config.ini" ,(local-file "files/polybar.ini"))
+ ("polybar/catppuccin.ini" ,catppuccin-polybar)))
+
+(define polybar-wrapper
+ (program-file "polybar-wrapper"
+ #~(begin
+ ;; This wrapper program checks that the monitor we want to start
+ ;; polybar on is actually connected.
+ (use-modules (ice-9 popen)
+ (ice-9 rdelim))
+ (let* ((connected-str (string-append (getenv "POLYBAR_MONITOR") " connected"))
+ (xrandr (open-pipe* OPEN_READ #$(file-append xrandr "/bin/xrandr") "-q"))
+ (monitor-connected?
+ (let loop ((line (read-line xrandr)))
+ (cond
+ ((eof-object? line) #f) ; we didn't find our monitor connected
+ ((string-prefix? connected-str line) #t) ; the monitor we want is connected
+ (else (loop (read-line xrandr))))))) ; keep looking
+ (close-pipe xrandr)
+ (when monitor-connected?
+ (execl #$(file-append polybar "/bin/polybar")))))))
+
+(define (polybar-service monitor)
+ (shepherd-service
+ (documentation (string-append "Polybar desktop bar for monitor " monitor "."))
+ (provision (list (symbol-append 'polybar- (string->symbol monitor))))
+ (requirement '(xorg-setup))
+ (start #~(make-forkexec-constructor
+ (list #$polybar-wrapper)
+ #:environment-variables
+ (cons #$(string-append "POLYBAR_MONITOR=" monitor)
+ (default-environment-variables))))
+ (stop #~(make-kill-destructor))))
+
+(define (desktop-layout-services config)
+ (match-record config <home-desktop-layout-configuration>
+ (desktop-background monitors)
+ (cons* (shepherd-service
+ (documentation "Set up X displays on login.")
+ (provision '(xorg-setup))
+ (one-shot? #t)
+ (start #~(lambda _
+ (define (replace-home path)
+ (if (string-prefix? "~/" path)
+ (string-replace path (getenv "HOME") 0 1)
+ path))
+ (system* #$(file-append numlockx "/bin/numlockx") "on")
+ ;; Turn off the monitors if there is no input for 10 minutes.
+ (system* #$(file-append xset "/bin/xset") "dpms" "600" "600" "600")
+ ;; TODO: may need one xrandr invocation per monitor; this is
+ ; ;what tw/home/cern.scm had before.
+ (system* #$(file-append xrandr "/bin/xrandr")
+ #$@(append-map (lambda (monitor)
+ (match-record monitor <home-monitor-configuration>
+ (name xrandr-options)
+ `("--output" ,name ,@xrandr-options)))
+ monitors))
+ ;; Set the desktop background picture. Hopefully doing this just after
+ ;; xrandr works and sets it for both screens.
+ (system* #$(file-append hsetroot "/bin/hsetroot")
+ "-cover" (replace-home #$desktop-background)))))
+ (map (compose polybar-service home-monitor-configuration-name) monitors))))
+
+(define home-desktop-layout-service-type
+ (service-type
+ (name 'desktop-layout)
+ (extensions
+ (list (service-extension home-shepherd-service-type desktop-layout-services)
+ (service-extension home-xdg-configuration-files-service-type polybar-config)))
+ (description
+ "Configure the desktop background, monitor layout and polybar.")))
+
+
+;; Blueman
+
+(define (blueman-services config)
+ (list (shepherd-service
+ (documentation "Blueman applet; provides a GUI for connection to bluetooth devices.")
+ (provision '(blueman-applet))
+ (start #~(make-forkexec-constructor
+ (list #$(file-append blueman "/bin/blueman-applet"))))
+ (stop #~(make-kill-destructor)))))
+
+(define home-blueman-service-type
+ (service-type
+ (name 'blueman)
+ (default-value #f)
+ (extensions
+ (list (service-extension home-shepherd-service-type blueman-services)))
+ (description
+ "Run the Blueman applet for graphical Bluetooth control.")))
diff --git a/tw/services/files/polybar.ini b/tw/services/files/polybar.ini
new file mode 100644
index 00000000..201c5131
--- /dev/null
+++ b/tw/services/files/polybar.ini
@@ -0,0 +1,239 @@
+; -*- mode: conf-windows; -*-
+
+[global/wm]
+include-file = catppuccin.ini
+
+[colors]
+background = ${colors.base}
+background-alt = ${colors.surface0}
+primary = ${colors.blue}
+alert = ${colors.yellow}
+disabled = ${colors.overlay2}
+empty-bar = ${colors.surface2}
+
+[settings]
+screenchange-reload = true
+
+[bar/primary]
+monitor = ${env:POLYBAR_MONITOR}
+width = 100%
+height = 24pt
+radius = 0
+line-size = 3pt
+line-color = ${colors.primary}
+border-size = 0
+padding-left = 0
+padding-right = 2
+module-margin = 2
+
+background = ${colors.background}
+foreground = ${colors.text}
+
+; font-N = <fontconfig pattern>;<vertical offset>
+font-0 = Fira Sans:size=11;2
+; Some workspace names have emojis in them.
+; Using Noto Emoji means emojis would be much too big and colourful.
+font-1 = OpenMoji:style=Black:size=11;3
+; Hermit is needed for Unicode block chars.
+font-2 = Hermit:size=10;1
+
+separator = ยท
+separator-foreground = ${colors.disabled}
+
+modules-left = i3 xwindow
+modules-right = wlan eth memory cpu temp xkeyboard pulseaudio dunst battery date
+tray-position = right
+
+enable-ipc = true
+
+cursor-click = pointer
+cursor-scroll = ns-resize
+
+[module/i3]
+type = internal/i3
+pin-workspaces = false
+show-urgent = true
+strip-wsnumbers = true
+index-sort = true
+label-mode-foreground = ${colors.alert}
+label-mode-background = ${colors.background-alt}
+label-mode-padding = 2
+label-focused-overline = ${colors.primary}
+label-focused-padding = 1
+label-urgent-foreground = ${colors.alert}
+label-urgent-background = ${colors.background-alt}
+label-urgent-padding = 1
+label-unfocused-padding = 1
+label-visible-padding = 1
+
+[module/xwindow]
+type = internal/xwindow
+label = %title%
+label-maxlen = 120
+
+[module/pulseaudio]
+type = internal/pulseaudio
+format-volume = <ramp-volume> <label-volume>
+label-volume = %percentage%%
+label-muted = ๐Ÿ”‡
+label-muted-foreground = ${colors.disabled}
+
+ramp-volume-0 = ๐Ÿ”ˆ
+ramp-volume-1 = ๐Ÿ”‰
+ramp-volume-2 = ๐Ÿ”Š
+ramp-volume-0-foreground = ${colors.primary}
+ramp-volume-1-foreground = ${colors.primary}
+ramp-volume-2-foreground = ${colors.primary}
+
+[module/xkeyboard]
+type = internal/xkeyboard
+blacklist-0 = num lock
+; hide xkeyboard module unless Caps Lock is pressed
+label-layout =
+label-indicator-padding = 1
+label-indicator-margin = 0
+label-indicator-foreground = ${colors.alert}
+label-indicator-background = ${colors.background-alt}
+
+[module/memory]
+type = internal/memory
+interval = 1
+format = <label> <ramp-used>
+format-prefix = "RAM "
+format-prefix-foreground = ${colors.primary}
+format-warn-prefix = "RAM "
+format-warn-prefix-foreground = ${colors.primary}
+label = %used%
+label-warn = %free% left
+label-warn-foreground = ${colors.alert}
+label-warn-background = ${colors.background-alt}
+
+ramp-used-0 = โ–
+ramp-used-1 = โ–‚
+ramp-used-2 = โ–ƒ
+ramp-used-3 = โ–„
+ramp-used-4 = โ–…
+ramp-used-5 = โ–†
+ramp-used-6 = โ–‡
+ramp-used-7 = โ–ˆ
+ramp-used-0-foreground = ${colors.empty-bar}
+ramp-used-1-foreground = ${colors.primary}
+ramp-used-2-foreground = ${colors.primary}
+ramp-used-3-foreground = ${colors.primary}
+ramp-used-4-foreground = ${colors.primary}
+ramp-used-5-foreground = ${colors.alert}
+ramp-used-6-foreground = ${colors.alert}
+ramp-used-7-foreground = ${colors.alert}
+
+[module/cpu]
+type = internal/cpu
+interval = 1
+format = <ramp-coreload>
+format-prefix = "CPU "
+format-prefix-foreground = ${colors.primary}
+
+; Spacing (number of spaces, pixels, points) between individual per-core ramps
+ramp-coreload-spacing = 1
+ramp-coreload-0 = โ–
+ramp-coreload-1 = โ–‚
+ramp-coreload-2 = โ–ƒ
+ramp-coreload-3 = โ–„
+ramp-coreload-4 = โ–…
+ramp-coreload-5 = โ–†
+ramp-coreload-6 = โ–‡
+ramp-coreload-7 = โ–ˆ
+ramp-coreload-0-foreground = ${colors.empty-bar}
+ramp-coreload-1-foreground = ${colors.primary}
+ramp-coreload-2-foreground = ${colors.primary}
+ramp-coreload-3-foreground = ${colors.primary}
+ramp-coreload-4-foreground = ${colors.primary}
+ramp-coreload-5-foreground = ${colors.primary}
+ramp-coreload-6-foreground = ${colors.alert}
+ramp-coreload-7-foreground = ${colors.alert}
+
+[module/temp]
+type = internal/temperature
+; head /sys/class/thermal/thermal_zone*/type
+thermal-zone = 1
+format-prefix = "๐ŸŒก "
+format-prefix-foreground = ${colors.primary}
+format-warn-prefix = "๐ŸŒก "
+format-warn-prefix-foreground = ${colors.primary}
+label-warn-foreground = ${colors.alert}
+label-warn-background = ${colors.background-alt}
+
+[network-base]
+type = internal/network
+interval = 5
+format-connected = <label-connected>
+format-packetloss = <animation-packetloss> <label-connected>
+; Hide completely if disconnected.
+format-disconnected =
+
+animation-packetloss-0 = โš 
+animation-packetloss-0-foreground = ${colors.alert}
+animation-packetloss-0-background = ${colors.background-alt}
+animation-packetloss-1 = ๐Ÿ“ถ
+animation-packetloss-1-foreground = ${colors.alert}
+animation-packetloss-1-background = ${colors.background-alt}
+; Framerate in milliseconds
+animation-packetloss-framerate = 500
+; Don't display "B/s" suffix, only e.g. "5 K" for compactness.
+speed-unit =
+
+[module/wlan]
+inherit = network-base
+interface-type = wireless
+format-connected = <ramp-signal> <label-connected>
+label-connected = %essid% โ†“ %downspeed% โ†‘ %upspeed%
+; label-connected-foreground = ${colors.green}
+
+ramp-signal-0 = ๐Ÿ“ถ
+ramp-signal-1 = ๐Ÿ“ถ
+ramp-signal-2 = ๐Ÿ“ถ
+ramp-signal-0-foreground = ${colors.red}
+ramp-signal-1-foreground = ${colors.green}
+ramp-signal-2-foreground = ${colors.green}
+
+[module/eth]
+inherit = network-base
+interface-type = wired
+label-connected = โ†“ %downspeed% โ†‘ %upspeed%
+format-connected-prefix = "๐ŸŒ "
+format-connected-prefix-foreground = ${colors.green}
+
+[module/battery]
+type = internal/battery
+low-at = 25
+time-format = %-Hh%Mm
+format-discharging = <ramp-capacity> <label-discharging>
+label-discharging = %percentage%% %time% %consumption%W
+format-charging = <label-charging>
+format-charging-prefix = "๐Ÿ”Œ "
+format-charging-prefix-foreground = ${colors.green}
+label-charging = %percentage%% %time%
+format-full =
+
+ramp-capacity-0 = ๐Ÿ”‹
+ramp-capacity-1 = ๐Ÿ”‹
+ramp-capacity-2 = ๐Ÿ”‹
+ramp-capacity-0-foreground = ${colors.red}
+ramp-capacity-1-foreground = ${colors.yellow}
+ramp-capacity-2-foreground = ${colors.green}
+
+[module/date]
+type = internal/date
+interval = 1
+date = %a %e %b
+time = %H:%M
+date-alt = %Y-%m-%d
+time-alt = %H:%M:%S
+label = %date%, %time%
+
+[module/dunst]
+type = custom/script
+; Only show a "slience" emoji when notifications are paused; nothing otherwise.
+exec = "case $(dunstctl is-paused) in false) echo;; true) echo '๐Ÿ”•';; esac"
+format = <label>
+format-foreground = ${colors.alert}
+format-background = ${colors.background-alt}