- Update strategy
- Introduction
- Channels
- Systems
- mpd Configuration
- Home Configuration
- Profiles
- Dotfiles Management
- Notes
- The config for emacs is common to all systems
- A list of modules is generated as a manifest for guix installation
Review the approach by Andrew Tropin - either adopt or standardise with mu4e across all linux systems.
This file was originally created by David Wilson, and can be seen here: https://github.com/daviwil/dotfiles My modifications are made to configure the contents for my systems.
Guix supports the concept of channels which basically amount to Git
repositories which contain Guix package definitions that can be
installed on your machine. Aside from the %default-channels
list,
I also use the Nonguix channel to install packages that aren’t
included with Guix by default like the non-free Linux kernel.
;; -*- buffer-read-only: t; -*-
;; NOTE: This file is generated from ~/dotfiles/System.org. Please see commentary there.
(list (channel
(name 'pj-suckless)
(url "https://github.com/paul-jewell/pj-suckless.git"))
(channel
(name 'nonguix)
;;(commit "c34fa8bfacdce5fa45b2a684c2b27309c09a9056")
(url "https://gitlab.com/nonguix/nonguix")
;; enable signature verification
(introduction
(make-channel-introduction
"897c1a470da759236cc11798f4e0a5f7d4d59fbc"
(openpgp-fingerprint
"2A39 3FFF 68F4 EF7A 3D29 12AF 6F51 20A0 22FB B2D5"))))
(channel
(name 'guix)
;;(commit "190187326ad7516dd6728eed7bb6ef2d4f92897a")
(url "https://git.savannah.gnu.org/git/guix.git")
(introduction
(make-channel-introduction
"9edb3f66fd807b096b48283debdcddccfea34bad"
(openpgp-fingerprint
"BBB0 2DDF 2CEA F6A8 0D1D E643 A2A0 6DF2 A33A 54FA")))))
The following channel list can be used when testing patches to
packages and services from a local clone of the Guix repo. You’ll
have to create a branch and commit changes to it before guix pull
can pick them up, though. You can change the target branch using the
branch
field of the channel
.
;; (list (channel
;; (name 'nonguix)
;; (url "https://gitlab.com/nonguix/nonguix"))
;; (channel
;; (name 'guix)
;; (branch "fix-glu-pkg-config")
;; (url "file:///home/daviwil/Projects/Code/guix")
;; (introduction
;; (make-channel-introduction
;; "d06d5db885e4b8399e878708862fbe3a67f0592c"
;; (openpgp-fingerprint
;; "53C4 1E6E 41AA FE55 335A CA5E 446A 2ED4 D940 BF14")))))
This base configuration is shared between all of the machines I manage with Guix. Since all of my machines are Lenovo ThinkPad laptops, the same basic configuration applies pretty cleanly across all of them. This may change in the future.
Any configuration that derives from base-operating-system
must
invoke guix system
in a specific way to ensure it gets loaded
correctly:
sudo guix system -L ~/.config/guix/systems reconfigure ~/.config/guix/systems/davinci.scm
This is also executed by running Make $(system)-system in the dotfiles directory
;; -*- buffer-read-only: t; -*-
;; NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there.
(define-module (base-system)
#:use-module (gnu)
#:use-module (srfi srfi-1)
#:use-module (gnu system nss)
#:use-module (gnu system setuid)
#:use-module (gnu services pm)
#:use-module (gnu services cups)
#:use-module (gnu services desktop)
#:use-module (gnu services networking)
#:use-module (gnu packages wm)
#:use-module (gnu packages cups)
#:use-module (gnu packages vim)
#:use-module (gnu packages gtk)
#:use-module (gnu packages xorg)
#:use-module (gnu packages emacs)
#:use-module (gnu packages file-systems)
#:use-module (gnu packages gnome)
#:use-module (gnu packages mtools)
#:use-module (gnu packages linux)
#:use-module (gnu packages audio)
#:use-module (gnu packages gnuzilla)
#:use-module (gnu packages pulseaudio)
#:use-module (gnu packages web-browsers)
#:use-module (gnu packages version-control)
#:use-module (gnu packages package-management)
#:use-module (nongnu packages linux)
#:use-module (nongnu system linux-initrd)
#:use-module (paulj packages paulj-dwm)
#:use-module (paulj packages paulj-st)
#:use-module (paulj packages paulj-dmenu)
#:use-module (paulj packages paulj-slock))
(use-service-modules nix)
(use-service-modules desktop xorg)
(use-service-modules ssh)
(use-package-modules certs)
(use-package-modules shells)
Add a udev
rule to enable members of the video
group to control screen brightness.
;; Allow members of the "video" group to change the screen brightness.
(define %backlight-udev-rule
(udev-rule
"90-backlight.rules"
(string-append "ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"KERNEL==\"intel_backlight\", "
"RUN+=\"/run/current-system/profile/bin/chgrp video /sys/class/backlight/%k/brightness\""
"\n"
"ACTION==\"add\", SUBSYSTEM==\"backlight\", "
"KERNEL==\"intel_backlight\", "
"RUN+=\"/run/current-system/profile/bin/chmod g+w /sys/class/backlight/%k/brightness\"")))
(define %touchpad-udev-rule
(udev-rule
"10-trackpoint.rules"
(string-append "ACTION==\"add\", SUBSYSTEM==\"input\", "
"ATTR{name}==\"TPPS/2 IBM Trackpoint\", "
"ATTR{device/sensitivity}=\"240\", "
"ATTR{device/press_to_select}=\"1\"")))
Override the default %desktop-services
to add the udev
backlight
configuration and include OpenVPN in the list of NetworkManager
plugins.
(define %my-desktop-services
(modify-services
%desktop-services
(elogind-service-type config =>
(elogind-configuration
(inherit config)
(handle-lid-switch-external-power 'suspend)))
(udev-service-type config =>
(udev-configuration
(inherit config)
(rules (cons* %backlight-udev-rule
%touchpad-udev-rule
(udev-configuration-rules config)))))))
Use the libinput
driver for all input devices since it’s a bit more modern than the default.
(define %xorg-libinput-config
"Section \"InputClass\"
Identifier \"Touchpads\"
Driver \"libinput\"
MatchDevicePath \"/dev/input/event*\"
MatchIsTouchpad \"on\"
Option \"Tapping\" \"on\"
Option \"TappingDrag\" \"on\"
Option \"DisableWhileTyping\" \"on\"
Option \"MiddleEmulation\" \"on\"
Option \"ScrollMethod\" \"twofinger\"
EndSection
Section \"InputClass\"
Identifier \"Keyboards\"
Driver \"libinput\"
MatchDevicePath \"/dev/input/event*\"
MatchIsKeyboard \"on\"
EndSection")
Define the base-operating-system
which will be inherited by all machine configurations.
(define-public base-operating-system
(operating-system
(host-name "base")
(timezone "Europe/London")
(locale "en_GB.utf8")
;; Use non-free Linux and firmware
(kernel linux)
(firmware (list linux-firmware))
(initrd microcode-initrd)
;; Choose UK English keyboard layout, with the extd layout.
(keyboard-layout (keyboard-layout "gb" "extd"
#:model "thinkpad"
#:options '("ctrl:nocaps")))
;; Use the UEFI variant of GRUB with the EFI System
;; Partition mounted on /boot/efi.
(bootloader (bootloader-configuration
(bootloader grub-efi-bootloader)
(targets '("/boot/efi"))
(keyboard-layout keyboard-layout)))
;; Guix doesn't like it when there isn't a file-systems
;; entry, so add one that is meant to be overridden
(file-systems (cons*
(file-system
(mount-point "/tmp")
(device "none")
(type "tmpfs")
(check? #f))
%base-file-systems))
(users (cons (user-account
(name "paul")
(comment "Paul Jewell")
(group "users")
(home-directory "/home/paul")
(supplementary-groups '(
"wheel" ;; sudo
"netdev" ;; network devices
"kvm"
"tty"
"input"
"realtime" ;; Enable realtime scheduling
"lp" ;; control bluetooth devices
"audio" ;; control audio devices
"video"))) ;; control video devices
%base-user-accounts))
;; Add the 'realtime' group
(groups (cons (user-group (system? #t) (name "realtime"))
%base-groups))
;; Install bare-minimum system packages
(packages (append (list
git
ntfs-3g
exfat-utils
fuse-exfat
stow
neovim
bluez
bluez-alsa
pulseaudio
tlp
xf86-input-libinput
nss-certs ;; for HTTPS access
gvfs) ;; for user mounts
%base-packages))
;; Use the "desktop" services, which include the X11 log-in service,
;; networking with NetworkManager, and more
(services (cons* (service slim-service-type
(slim-configuration
(xorg-configuration
(xorg-configuration
(keyboard-layout keyboard-layout)
(extra-config (list %xorg-libinput-config))))))
(service openssh-service-type)
(service tlp-service-type
(tlp-configuration
(cpu-boost-on-ac? #t)
(wifi-pwr-on-bat? #t)))
(pam-limits-service ;; This enables JACK to enter realtime mode
(list
(pam-limits-entry "@realtime" 'both 'rtprio 99)
(pam-limits-entry "@realtime" 'both 'memlock 'unlimited)))
(service thermald-service-type)
(service cups-service-type
(cups-configuration
(web-interface? #t)
(extensions
(list cups-filters))))
(bluetooth-service #:auto-enable? #t)
(remove (lambda (service)
(eq? (service-kind service) gdm-service-type))
%my-desktop-services)))
;; Add nmtui to the setuid program list
(setuid-programs
(append (list (setuid-program
(program (file-append network-manager "/bin/nmtui"))))
%setuid-programs))))
Machines are named after opera stars and greek gods (during initial setup!).
Some settings need to be customized on a per-system basis without tweaking individual configuration files. Thanks to org-mode’s noweb
functionality, I can define a set of variables that can be tweaked for each system and applied across these configuration files when they get generated.
(require 'map) ;; Needed for map-merge
(setq pj/system-settings
(map-merge
'list
'()
<<system-settings>>))
zeus is a Lenovo X270 being used as a test bed for guix configuration.
;; -*- buffer-read-only: t; -*-
;; NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there.
;; Note - if you re-install, you need to review the uuid entries below.
(define-module (zeus)
#:use-module (base-system)
#:use-module (gnu))
(operating-system
(inherit base-operating-system)
(host-name "zeus")
;; TODO: Move from uuid to drive labels - makes it easier to install the system afresh
(swap-devices
(list (swap-space
(target (uuid "a0a103a5-cef2-446b-a2ff-8ffbee6890de")))))
(file-systems
(cons* (file-system
(mount-point "/boot/efi")
(device (uuid "F21D-F4AF" 'fat32))
(type "vfat"))
(file-system
(mount-point "/")
(device
(uuid "dbac54d4-4507-4205-bc72-8b1e7abc3c8f"
'btrfs))
(type "btrfs"))
%base-file-systems)))
tristan
is my main desktop AMD Ryzen 9 system, running gentoo linux
,
and dual booting into windows
.
Currently, there is no guix installation on this system, but there is emacs on both operating systems.
rodolfo
is a lenovo x270 laptop with gentoo linux installed.
shingo
is a small computer in the shed. Currently has gentoo, but will
be the next candidate for guix.
music_directory "~/music"
playlist_directory "~/.config/mpd/playlists"
auto_update "yes"
bind_to_address "127.0.0.1"
restore_paused "yes"
max_output_buffer_size "16384"
audio_output {
type "pulse"
name "pulse"
}
audio_output {
type "fifo"
name "visualiser feed"
path "/tmp/mpd.fifo"
format "44100:16:2"
}
(use-modules
(gnu home)
(gnu home services)
(gnu home services shells)
(gnu home services shepherd)
(gnu services)
(guix gexp)
(gnu packages)
(gnu packages emacs)
(gnu packages syncthing)
(gnu packages gnupg)
(gnu packages mpd)
(gnu packages pulseaudio)
(gnu packages admin))
(define %inputrc
(plain-file
"inputrc"
(string-append
"set input-meta on\n"
"set convert-meta off\n"
"set output-meta on\n\n"
"set editing-mode emacs\n\n"
"set enable-keypad on\n\n"
"$if mode=emacs\n"
"# Allow the use of the home/end keys\n"
"\"\\e[1~\": beginning-of-line\n"
"\"\\e[4~\": end-of-line\n\n"
"# Map 'page up' and 'page down' to search history based on current cmdline\n"
"\"\\e[5~\": history-search-backward\n"
"\"\\e[6~\": history-search-forward\n"
"$endif\n")))
;; emacs-packages
;; - emacs and packages required for the fully functioning emacs editor with my
;; configuration.
;; TODO: Link the configuration snippets with the package names and tangle the
;; result, either in emacs, or with guile
(define %emacs-packages
;; (map specification->package
(list
"emacs"
"emacs-use-package"
"emacs-no-littering"
"emacs-popup"
"emacs-ivy"
"emacs-ivy-hydra"
"emacs-ivy-rich"
"emacs-swiper"
"emacs-counsel-bbdb"
"emacs-counsel"
"emacs-which-key"
"ispell"
"hunspell"
"hunspell-dict-en-gb"
"emacs-ledger-mode"
"emacs-go-mode"
"emacs-multiple-cursors"
"emacs-org-bullets"
"emacs-org-roam"
;; "emacs-org-roam-dailies" ;; package not available under guix
"emacs-auctex"
;;"reftex" ;; included in emacs
"emacs-hydra"
;;"emacs-js2-mode"
;;"emacs-js2-reflector-el"
"emacs-company"
"emacs-company-irony"
"emacs-irony-mode"
"emacs-irony-eldoc"
"emacs-jedi"
"emacs-epc"
"emacs-company-jedi"
"emacs-magit"
"emacs-git-gutter"
"emacs-git-timemachine"
"emacs-flycheck"
"emacs-all-the-icons"
"emacs-all-the-icons-dired"
"emacs-gruvbox-theme"
"emacs-projectile"
"emacs-counsel-projectile"
"emacs-powerline"
"emacs-diminish"
"emacs-paredit"
;; "emacs-paredit-everywhere"
"emacs-rainbow-delimiters"
"emacs-clojure-mode"
"emacs-cider"
;; "emacs-cider-hydra"
"emacs-slime"
"emacs-macrostep"
"emacs-elisp-slime-nav"
"mu"
"emacs-mu4e-alert"
"isync"
"emacs-org-caldav"
"emacs-helpful"
"pinentry"
"emacs-pinentry"
;;"emacs-erc"
;;"emacs-erc-log"
;;"emacs-erc-notify"
;;"emacs-erc-spelling"
;;"emacs-erc-autoaway"
"emacs-toc-org"
"emacs-ox-hugo"
"emacs-flycheck-guile"
"emacs-guix"
"emacs-geiser"))
(define %programming-apps
(list
"gcc-toolchain"
"make"
"pkg-config"
"texinfo"
"sbcl"
"curl"))
;; Home-apps
;; - The applications I want to have installed even for the base case
(define %home-apps
(append
(list
"git"
"ntfs-3g"
"exfat-utils"
"fuse-exfat"
"bluez"
"bluez-alsa"
"pulseaudio"
"tlp"
"xf86-input-libinput"
"nss-certs"
"gvfs"
"htop"
"syncthing"
"nyxt"
"mpd")
%emacs-packages))
(home-environment
(packages (map specification->package+output
%home-apps))
(services
(list
(service home-bash-service-type
(home-bash-configuration
(guix-defaults? #t)
(environment-variables
'(("XDG_CACHE_HOME" . "~/.cache")
("INPUTRC" . "~/.inputrc")
("HISTFILE" . "$XDG_CACHE_HOME/.bash_history")
("EDITOR" . "emacs")
("PATH" . "~/.bin:~/.bin/statusbar:$PATH")
("BROWSER" . "nyxt")))))
(service home-shepherd-service-type
(home-shepherd-configuration
(shepherd shepherd)
(services
(list
(shepherd-service
(provision '(syncthing))
(documentation "Run 'syncthing' without calling the browser")
(start #~(make-forkexec-constructor
(list #$(file-append syncthing "/bin/syncthing")
"-no-browser"
"-logflags=3" ; prefix with date and time
"-logfile=/home/paul/log/syncthing.log")))
(stop #~(make-kill-destructor)))
(shepherd-service
(provision '(gpg-agent))
(documentation "Run 'gpg-agent'")
(start #~(make-system-constructor
#$(file-append gnupg "/bin/gpg-connect-agent /bye")))
(stop #~(make-system-destructor
#$(file-append gnupg "/bin/gpgconf --kill gpg-agent"))))
(shepherd-service
(provision '(pulseaudio))
(documentation "Run pulseaudio")
(start #~(make-forkexec-constructor
(list #$(file-append pulseaudio "/bin/pulseaudio"))))
(stop #~(make-kill-destructor)))
(shepherd-service
(provision '(mpd))
(documentation "Run 'mpd' server")
(start #~(make-forkexec-constructor
(list #$(file-append mpd "/bin/mpd ~/.config/mpd/mpd.conf"))))
(stop #~(make-kill-destructor)))))))
(simple-service 'inputrc-config
home-files-service-type
(list `("inputrc"
,%inputrc)))
(simple-service 'mpd-config
home-files-service-type
(list `("config/mpd/mpd.conf"
,(local-file "/home/paul/dotfiles/home/files/mpd/mpd.conf"))))
(simple-service 'emacs-config
home-files-service-type
(list `("emacs.d/early-init.el"
,(local-file "/home/paul/dotfiles/home/files/emacs/early-init.el"))
`("emacs.d/init.el"
,(local-file "/home/paul/dotfiles/home/files/emacs/init.el"))
`("emacs.d/lisp/my-org-mode.el"
,(local-file "/home/paul/dotfiles/home/files/emacs/lisp/my-org-mode.el")))))))
(define-module (home zeus core)
#:use-module (gnu home)
#:use-module ((home zeus gnupg) #:prefix gnupg:)
#:use-module ((home zeus version-control) #:prefix vc:)
#:use-module ((home zeus wm) #:prefix wm:)
#:use-module ((home zeus emacs) #:prefix emacs:)
#:use-module ((home zeus shell) #:prefix shell:)
#:use-module ((home zeus password-utils) #:prefix pass:)
#:use-module ((home zeus xdg) #:prefix xdg:)
#:use-module ((home zeus ssh) #:prefix ssh:)
#:use-module ((home zeus pipewire) #:prefix pw:)
#:use-module ((home zeus terminals) #:prefix term:)
#:use-module ((home zeus packages) #:select (packages)))
(home-environment
(packages packages)
(services
(append
wm:services
vc:services
gnupg:services
emacs:services
pass:services
shell:services
xdg:services
ssh:services
pw:services
term:services)))
Packages are installed into separate manifests that get installed as
profiles which can be updated independently. These profiles get
installed under the ~/.guix-extra-profiles
path and sourced by
~/.profile
when I log in.
Base installation includes the packages required for console based computer use, without xorg. This includes system admin tools etc, but not additional packages for specific tasks. Those are in the additional manifests below.
Guix packages
"system-config-printer"
"openssh"
"zip"
"unzip"
"htop"
"lf"
"gnupg"
"screen"
"stress"
"glances"
"syncthing"
"syncthing-gtk"
# Automatically adjust the document to full width
set adjust-open width
# Set the title to the filename
set window-title-basename true
# Larger scroll steps with j/k
set scroll-step 150
# Adjusting the document
map [normal] E adjust_window best-fit
map [fullscreen] E adjust_window best-fit
map [normal] e adjust_window width
map [fullscreen] e adjust_window width
# Toggling the inverted colours
map <C-i> recolor
map <C-g> abort
Guix packages
"zathura"
"zathura-pdf-mupdf"
Guix Packages
"alsa-utils"
"pavucontrol"
Guix Packages
"password-store"
"keepassxc"
pass git pull
pass git push
notify-send -i "emblem-synchronizing" "Passwords synced!"
I use GNU mcron for scheduling tasks to run periodically in the background.
Syncing Passwords
(job
'(next-hour (range 0 24 4))
"~/.bin/sync-passwords")
Guix Packages
"mcron"
Manager I am using dwm, installed in the user account. These are the packages required for that, and the other support packages for the Xorg desktop use. By not having window managers installed at system level, the .xsession code is run by the login manager, so configuration of the window manager and associated programs is done there.
(specifications->manifest
'("paulj-dwm"
"paulj-dmenu"
"dwmblocks"
"paulj-st"
"paulj-slock"
"xev"
"xset"
"xrdb"
"xhost"
"xmodmap"
"setxkbmap"
"xrandr"
"arandr"
"xss-lock"
"libinput"
"xinput"
"compton"
"redshift"
"gucharmap"
"fontmanager"
"brightnessctl"
"xdg-utils" ;; For xdg-open, etc
"shared-mime-info"
"dunst"
"libnotify"
"unclutter"
;; Settings Manager
"xsettingsd"
;; GTK Themes
"arc-icon-theme"
"matcha-theme"
"hicolor-icon-theme"
"gnome-icon-theme"
"gnome-backgrounds"
"papirus-icon-theme"
;; Fonts
"font-iosevka"
"font-fira-mono"
"font-fira-code"
"font-abattis-cantarell"
"font-dejavu"
"font-google-noto"
"font-gnu-freefont"
"font-liberation"
"font-awesome"
"font-google-material-design-icons"
"gs-fonts"
;; Packages for dwmblocks status bar
"bmon"
"xbacklight"
"pamixer"
"lm-sensors"
"mpd-mpc"
;; Packages for dwm
"bc"
"maim"
"calcurse"
))
.xsession
#if [ -z "$(pgrep -u paul shepherd)" ]; then
# shepherd &
#fi
#xsettingsd &
#compton &
# TODO: Make the background changeable, and saved between sessions
#feh --bg-fill ~/backgrounds/mountains-1412683.jpg &
#unclutter &
#exec dwm
I use xsettingsd as a minimal settings daemon for Xorg applications. It replaces similar daemons from desktop environments like GNOME and XFCE and enables me to use a simple configuration file like the following:
.config/xsettingsd/xsettingsd.conf:
Net/ThemeName "Matcha-dark-azul"
Net/IconThemeName "Papirus-Dark"
Gtk/DecorationLayout "menu:minimize,maximize,close"
Gtk/FontName "Cantarell 11"
Gtk/MonospaceFontName "Fira Mono 10"
Gtk/CursorThemeName "Adwaita"
Xft/Antialias 1
Xft/Hinting 0
Xft/HintStyle "hintnone"
Xft/DPI 96 # 1024 * DPI
I also have to do an extra step to make sure Emacs can find the font path from the “desktop” profile.
.config/fontconfig/fonts.conf:
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<dir>~/.dotfiles/fonts</dir>
<dir>~/.guix-extra-profiles/window-manager/window-manager/share/fonts</dir>
<alias>
<family>Apple Color Emoji</family>
<prefer>
<family>Noto Color Emoji</family>
</prefer>
</alias>
</fontconfig>
nyxt is the future!
(specifications->manifest
'("ungoogled-chromium"
"nyxt"
"lagrange"
"gsettings-desktop-schemas"
"gnome-icon-theme"
))
Languages and tools for programming.
;; Various developer tools that I use. These might be split out into
;; platform-specific manifests at some point.
(specifications->manifest
'(;; C/C++
"gcc-toolchain"
"make"
"pkg-config"
"texinfo"
"llvm"
"lld"
"clang"
;; Python (3 by default)
"python"
"python2" ;; needed by gimp tools?
;; Docker
;;"docker-cli"
;; Java
"icedtea"
;;lisp
"sbcl"
;;clojure
"clojure"
"leiningen"
;; SDL
"glu"
"glfw"
"sdl2"
"sdl2-image"
"sdl2-mixer"
"sdl2-gfx"
"sdl2-ttf"
"curl"
"virt-manager"))
;; "glibc" ;; For ldd
(specifications->manifest
'("feh"
"gimp"
"scrot"))
music_directory "~/music"
playlist_directory "~/.config/mpd/playlists"
auto_update "yes"
bind_to_address "127.0.0.1"
restore_paused "yes"
max_output_buffer_size "16384"
audio_output {
type "pulse"
name "pulse"
}
audio_output {
type "fifo"
name "visualiser feed"
path "/tmp/mpd.fifo"
format "44100:16:2"
}
Guix packages
"mpd"
"ncmpcpp"
(specifications->manifest
'("aisleriot"
"gnome-mahjongg"))
These packages are needed to enable many video formats to be played in browsers and video players. VAAPI drivers are also used to enable hardware-accelerated video decoding.
Guix Packages
"gstreamer"
"gst-plugins-base"
"gst-plugins-good"
"gst-plugins-bad"
"gst-plugins-ugly"
"gst-libav"
"intel-vaapi-driver"
"libva-utils"
An area of future investigation. This is currently as specified by David Wilson in his configuration.
;; Music creation tools
(specifications->manifest
'(;; JACK tools
"jack"
"jack2"
"jack-keyboard"
"qjackctl"
"patchage"
;; DAWs
"ardour"
"zrythm"
;; Guitar
;; "guitarix"
;; "guitarix-lv2"
;; Effects
"calf"
"g2reverb"
"dragonfly-reverb"
"wolf-shaper"
;; Synths
"helm"
"amsynth"
"avldrums-lv2"
"geonkick"
"fluidsynth"
"zynaddsubfx"
;; Mixing Tools
"wolf-spectrum"))
Also something for future exploration.
;; Video creation tools
(specifications->manifest
'(;; Screen Capture and Streaming
"obs"
"ffmpeg" ;; ffmpeg and ffplay
"v4l-utils" ;; Get details about webcams: v4l2-ctl --list-devices
;; Screen recording with pulseaudio source 0 (-i 0)
;; ffmpeg -y -f x11grab -video_size 2560x1440 -i :0.0+0,0 -f pulse -ac 2 -i 0 -c:v libx264 -pix_fmt yuv420p -crf 0 -preset ultrafast ~/output.mp4 -v 0
;; Scaling video down to 1080p
;; ffmpeg -i output2.mp4 -s 1920x1080 ~/output2-scaled.mp4
;; Show webcam with specific resolution
;; ffplay -f v4l2 -framerate 60 -video_size hd480 /dev/video2 -v 0
;; Video Editing
"blender"))
Dunst is a minimal interface for displaying desktop notifications. It is quite hackable but I’m not currently taking much advantage of its power. One useful feature is the ability to recall notification history; the keybinding is C-`
in my configuration (though I’d prefer if I could invoke it from an Emacs keybinding somehow).
.config/dunst/dunstrc:
[global]
### Display ###
monitor = 0
# The geometry of the window:
# [{width}]x{height}[+/-{x}+/-{y}]
geometry = "500x10-10+50"
# Show how many messages are currently hidden (because of geometry).
indicate_hidden = yes
# Shrink window if it's smaller than the width. Will be ignored if
# width is 0.
shrink = no
# The transparency of the window. Range: [0; 100].
transparency = 10
# The height of the entire notification. If the height is smaller
# than the font height and padding combined, it will be raised
# to the font height and padding.
notification_height = 0
# Draw a line of "separator_height" pixel height between two
# notifications.
# Set to 0 to disable.
separator_height = 1
separator_color = frame
# Padding between text and separator.
padding = 8
# Horizontal padding.
horizontal_padding = 8
# Defines width in pixels of frame around the notification window.
# Set to 0 to disable.
frame_width = 2
# Defines color of the frame around the notification window.
frame_color = "#89AAEB"
# Sort messages by urgency.
sort = yes
# Don't remove messages, if the user is idle (no mouse or keyboard input)
# for longer than idle_threshold seconds.
idle_threshold = 120
### Text ###
font = Cantarell 20
# The spacing between lines. If the height is smaller than the
# font height, it will get raised to the font height.
line_height = 0
markup = full
# The format of the message. Possible variables are:
# %a appname
# %s summary
# %b body
# %i iconname (including its path)
# %I iconname (without its path)
# %p progress value if set ([ 0%] to [100%]) or nothing
# %n progress value if set without any extra characters
# %% Literal %
# Markup is allowed
format = "<b>%s</b>\n%b"
# Alignment of message text.
# Possible values are "left", "center" and "right".
alignment = left
# Show age of message if message is older than show_age_threshold
# seconds.
# Set to -1 to disable.
show_age_threshold = 60
# Split notifications into multiple lines if they don't fit into
# geometry.
word_wrap = yes
# When word_wrap is set to no, specify where to make an ellipsis in long lines.
# Possible values are "start", "middle" and "end".
ellipsize = middle
# Ignore newlines '\n' in notifications.
ignore_newline = no
# Stack together notifications with the same content
stack_duplicates = true
# Hide the count of stacked notifications with the same content
hide_duplicate_count = false
# Display indicators for URLs (U) and actions (A).
show_indicators = yes
### Icons ###
# Align icons left/right/off
icon_position = left
# Scale larger icons down to this size, set to 0 to disable
max_icon_size = 88
# Paths to default icons.
# TODO: Check the icon path...
icon_path = /home/paul/.guix-extra-profiles/desktop/desktop/share/icons/gnome/256x256/status/:/home/daviwil/.guix-extra-profiles/desktop/desktop/share/icons/gnome/256x256/devices/:/home/daviwil/.guix-extra-profiles/desktop/desktop/share/icons/gnome/256x256/emblems/
### History ###
# Should a notification popped up from history be sticky or timeout
# as if it would normally do.
sticky_history = no
# Maximum amount of notifications kept in history
history_length = 20
### Misc/Advanced ###
# Browser for opening urls in context menu.
browser = nyxt
# Always run rule-defined scripts, even if the notification is suppressed
always_run_script = true
# Define the title of the windows spawned by dunst
title = Dunst
# Define the class of the windows spawned by dunst
class = Dunst
startup_notification = false
verbosity = mesg
# Define the corner radius of the notification window
# in pixel size. If the radius is 0, you have no rounded
# corners.
# The radius will be automatically lowered if it exceeds half of the
# notification height to avoid clipping text and/or icons.
corner_radius = 4
mouse_left_click = close_current
mouse_middle_click = do_action
mouse_right_click = close_all
# Experimental features that may or may not work correctly. Do not expect them
# to have a consistent behaviour across releases.
[experimental]
# Calculate the dpi to use on a per-monitor basis.
# If this setting is enabled the Xft.dpi value will be ignored and instead
# dunst will attempt to calculate an appropriate dpi value for each monitor
# using the resolution and physical size. This might be useful in setups
# where there are multiple screens with very different dpi values.
per_monitor_dpi = false
[shortcuts]
# Shortcuts are specified as [modifier+][modifier+]...key
# Available modifiers are "ctrl", "mod1" (the alt-key), "mod2",
# "mod3" and "mod4" (windows-key).
# Xev might be helpful to find names for keys.
# Close notification.
#close = ctrl+space
# Close all notifications.
#close_all = ctrl+shift+space
# Redisplay last message(s).
# On the US keyboard layout "grave" is normally above TAB and left
# of "1". Make sure this key actually exists on your keyboard layout,
# e.g. check output of 'xmodmap -pke'
history = ctrl+grave
# Context menu.
context = ctrl+shift+period
[urgency_low]
# IMPORTANT: colors have to be defined in quotation marks.
# Otherwise the "#" and following would be interpreted as a comment.
background = "#222222"
foreground = "#888888"
timeout = 10
# Icon for notifications with low urgency, uncomment to enable
#icon = /path/to/icon
[urgency_normal]
background = "#1c1f26"
foreground = "#ffffff"
timeout = 10
# Icon for notifications with normal urgency, uncomment to enable
#icon = /path/to/icon
[urgency_critical]
background = "#900000"
foreground = "#ffffff"
frame_color = "#ff0000"
timeout = 0
# Icon for notifications with critical urgency, uncomment to enable
#icon = /path/to/icon
The desktop.scm
manifest holds the list of packages that I use to configure my desktop environment. The package names are pulled from the relevant sections titled Guix Packages in this file (system.org
).
.config/guix/manifests/desktop.scm:
(specifications->manifest
'(
<<packages>>
))
mpv is a simple yet powerful video player. Paired with youtube-dl it can even stream YouTube videos. mpv-mpris allows playback control via playerctl.
.config/mpv/mpv.conf
# Configure playback quality
vo=gpu
hwdec=vaapi
profile=gpu-hq
scale=ewa_lanczossharp
cscale=ewa_lanczossharp
# Start the window in the upper right screen corner
geometry=22%-30+20
# Save video position on quit
save-position-on-quit
# Enable control by MPRIS
script=~/.guix-extra-profiles/desktop/desktop/lib/mpris.so
# Limit the resolution of YouTube videos
ytdl=yes
ytdl-format=bestvideo[height<=?720]+bestaudio/best
# When playing audio files, display the album art
audio-display=attachment
# Keep the player open after the file finishes
keep-open
Guix Packages
"mpv"
"mpv-mpris"
"youtube-dl"
"playerctl"
GNU Shepherd is used to manage services that run in the background after I log in. Documentation: https://guix.gnu.org/en/blog/2020/gnu-shepherd-user-services/
(use-modules (shepherd service)
((ice-9 ftw) #:select (scandir)))
;; Load all the files in the directory 'init.d' with a suffix '.scm'
(for-each
(lambda (file)
(load (string-append "init.d/" file)))
(scandir (string-append (dirname (current-filename)) "/init.d")
(lambda (file)
(string-suffix? ".scm" file))))
(action 'shepherd 'daemonize)
(define gpg-agent
(make <service>
#:provides '(gpg-agent)
#:respawn? #t
#:start (make-system-constructor "gpg-connect-agent /bye")
#:stop (make-system-destructor "gpgconf --kill gpg-agent")))
(register-services gpg-agent)
(start gpg-agent)
(define mcron
(make <service>
#:provides '(mcron)
#:respawn? #t
#:start (make-forkexec-constructor '("mcron"))
#:stop (make-kill-destructor)))
(register-services mcron)
(start mcron)
Currently this isn’t working as expected, so set to not tangle.
(define emacs
(make <service>
#:provides '(emacs)
#:requires '()
#:docstring "Start emacs daemon"
#:start (make-system-constructor "emacs --daemon")
#:stop (make-system-destructor "emacsclient --eval \"(kill-emacs)\"")))
(register-services emacs)
(start emacs)
(define syncthing
(make <service>
#:provides '(syncthing)
#:docstring "Run `syncthing' without calling the browser"
#:start (make-forkexec-constructor
'("syncthing" "-no-browser"
"-logflags=3" ; prefix with date and time
"-logfile=/home/paul/log/syncthing.log"))
#:stop (make-kill-destructor)
#:respawn #t))
(register-services syncthing)
(start syncthing)
(define pulseaudio
(make <service>
#:provides '(pulseaudio)
#:respawn? #t
#:start (make-forkexec-constructor '("pulseaudio"))
#:stop (make-kill-destructor)))
(register-services pulseaudio)
(start pulseaudio)
(define mpd
(make <service>
#:provides '(mpd)
#:respawn? #t
#:start (make-forkexec-constructor '("mpd"))
#:stop (make-kill-destructor)))
(register-services mpd)
(start mpd)
To make the management of multiple profiles easier, I’ve created a couple of shell scripts:
This script accepts a space-separated list of manifest file names (without extension) under the ~/.config/guix/manifests
folder and then installs those profiles for the first time. For example:
activate-profiles desktop emacs music
.bin/activate-profiles:
# -*- buffer-read-only: t; -*-
# NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there.
if [ $HOSTNAME = "zeus" ] # This will need modification when expanding number of guix systems.
# Currently zeus is the only one.
then
GREEN='\033[1;32m'
RED='\033[1;30m'
NC='\033[0m'
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
profiles=$*
if [[ $# -eq 0 ]]; then
profiles="$HOME/.config/guix/manifests/*.scm";
fi
for profile in $profiles; do
# Remove the path and file extension, if any
profileName=$(basename $profile)
profileName="${profileName%.*}"
profilePath="$GUIX_EXTRA_PROFILES/$profileName"
manifestPath=$HOME/.config/guix/manifests/$profileName.scm
if [ -f $manifestPath ]; then
echo
echo -e "${GREEN}Activating profile:" $manifestPath "${NC}"
echo
mkdir -p $profilePath
guix package --manifest=$manifestPath --profile="$profilePath/$profileName"
# Source the new profile
GUIX_PROFILE="$profilePath/$profileName"
if [ -f $GUIX_PROFILE/etc/profile ]; then
. "$GUIX_PROFILE"/etc/profile
else
echo -e "${RED}Couldn't find profile:" $GUIX_PROFILE/etc/profile "${NC}"
fi
else
echo "No profile found at path" $profilePath
fi
done
fi
This script accepts a space-separated list of manifest file names (without extension) under the ~/.config/guix/manifests
folder and then installs any updates to the packages contained within them. If no profile names are provided, it walks the list of profile directories under ~/.guix-extra-profiles
and updates each one of them.
update-profiles emacs
.bin/update-profiles:
# -*- buffer-read-only: t; -*-
# NOTE: This file is generated from ~/.dotfiles/System.org. Please see commentary there.
GREEN='\033[1;32m'
NC='\033[0m'
GUIX_EXTRA_PROFILES=$HOME/.guix-extra-profiles
profiles=$*
if [[ $# -eq 0 ]]; then
profiles="$GUIX_EXTRA_PROFILES/*";
fi
for profile in $profiles; do
profileName=$(basename $profile)
profilePath=$GUIX_EXTRA_PROFILES/$profileName
echo
echo -e "${GREEN}Updating profile:" $profilePath "${NC}"
echo
guix package --profile="$profilePath/$profileName" --manifest="$HOME/.config/guix/manifests/$profileName.scm"
done
Since I keep all of my important configuration files in Org Mode code blocks, I have to ensure that the real configuration files are kept up to date when I sync the latest changes to my dotfiles repo. I’ve written a couple of scripts to simplify that process:
When I want to sync my dotfiles repo into my local clone which likely has uncommitted changes, I run sync-dotfiles
. This script first makes sure that all Org files are saved in a running Emacs instance and then stashes everything before pulling the latest changes from origin
. After pulling, the stash is popped and then the script verifies there are no merge conflicts from the stash before proceeding. If there are no conflicts, update-dotfiles
is run, otherwise I’ll fix the merge conflicts manually and run update-dotfiles
myself.
.bin/sync-dotfiles
# -*- buffer-read-only: t; -*-
# Sync dotfiles repo and ensure that dotfiles are tangled correctly afterward
GREEN='\033[1;32m'
BLUE='\033[1;34m'
RED='\033[1;30m'
NC='\033[0m'
# Navigate to the directory of this script (generally ~/.dotfiles/.bin)
cd $(dirname $(readlink -f $0))
cd ..
echo
echo -e "${BLUE}Saving Org buffers if Emacs is running...${NC}"
emacsclient -u -e "(org-save-all-org-buffers)" -a "echo 'Emacs is not currently running'"
echo -e "${BLUE}Stashing existing changes...${NC}"
stash_result=$(git stash push -m "sync-dotfiles: Before syncing dotfiles")
needs_pop=1
if [ "$stash_result" = "No local changes to save" ]; then
needs_pop=0
fi
echo -e "${BLUE}Pulling updates from dotfiles repo...${NC}"
echo
git pull origin master
echo
if [[ $needs_pop -eq 1 ]]; then
echo -e "${BLUE}Popping stashed changes...${NC}"
echo
git stash pop
fi
unmerged_files=$(git diff --name-only --diff-filter=U)
if [[ ! -z $unmerged_files ]]; then
echo -e "${RED}The following files have merge conflicts after popping the stash:${NC}"
echo
printf %"s\n" $unmerged_files # Ensure newlines are printed
else
update-dotfiles
fi
Updating my dotfiles requires running a script in Emacs to loop over
all of my literate configuration .org
files and run
org-babel-tangle-file
to make sure all of my configuration files are
up to date.
.bin/update-dotfiles .emacs.d/tangle-dotfiles.el
These two files is already in the .bin and .emacs.d directory respectively. Otherwise it’s not straight forward to tangle all of the .org files.
Until I migrate its Markdown contents into Org syntax, consult .config/guix/systems/README.md for installation instructions.
If you need to manually connect to Bluetooth audio devices using bluetoothctl
,
as I currently do in Guix, you’ll need to enter these commands at the
bluetoothctl
prompt:
system-alias "my-hostname" # To configure your laptop's device name
default-agent
power on
scan on
# Wait for your device to appear
pair 04:52:C7:5E:5C:A8
trust 04:52:C7:5E:5C:A8 # To enable auto-connect
connect 04:52:C7:5E:5C:A8