How my Guix performed in Mexico (or not)
Published on
I am back from my trip, or rather, I am writing this on the plane returning home. And I can say that ... Guix sort of let me down in the first half, and I had no rescue plan mid-flight.
So let's talk about what went wrong, and what I had to do to get operational.
We departed Thursday night, and I am 100% not a plane person. Everything about it rubbed me the wrong way; turbulence, take-off, landing, anytime the plane shook even the slightest, I started panicking. I am so not excited about flying or traveling this way.
About an hour into the flight after my worries started easing, the plane went pitch black, and I had a massive problem - the backlight was not something easily manipulated. My partner instantly noticed and I did my best to adjust the viewing angle so it wouldn't be obnoxious, but alas, I had a major problem on my hand.
Normally, I would control backlight with xbacklight
, a simple script process that would do what it does to adjust the current backlight value, which lives somewhere in an obscure location like /sys/class/backlight/intel_backlight
. This is a folder that interacts with a device-specific driver and maps an integer value to a real-world lighting value.
However, xbacklight
was not allowing me to modify the backlight, and I believe it had something to do with Xorg getting in the way. The Xorg output file is defined by a Guix package that lives somewhere in my definitions, and I couldn't figure out how to add a "backlight"
property to the Xorg output device. Because of that, xbacklight
would see zero devices with a backlight modifier, and thus wouldn't be able to do anything.
I did my best digging I could and found read-only xorg.conf
files descibing my output, but obviously I couldn't manipulate it. I don't have the on-hand Guix knowledge to know how to work around this, other than locating the exact package that makes up my Xorg layout, which, for someone with no internet, my chances were slim to none.
The airplane had free Wi-Fi, which did little good, because it was designed to block applications that basically weren't WhatsApp or iMessage. Can't even do web browsing, not that I blame them for preventing that. So without any expertise on Guix, without any internet to allow me to download a new package, and with inherent fear that without a manual I would brick my system, I closed my laptop and put it away.
I proceeded to watch about half of Goodfellas, but then we started hitting turbulence over the Gulf and I developed a panick anxiety and watched our on-flight GPS flight path for the rest of the flight. Landing was less than pleasant, but I survived.
Mexico was a trip, while it might not be entirely up my alley, it was nice seeing family for the first time. The roads were very... Under-developed, but food and sights were aplenty. I don't speak fluent Spanish in any capacity, but my partner does and that got me far enough.
We had a big party, which I am still trying to recover from, and not before long the trip would be over. But not before I decided to do my emergency Guix repairs.
I figured the best approach I could posibly go down, without having to re-configure my entire system, would be to download a different desktop environment. As good i3wm
is to me, I figured I should try something stable as a baseline comparison. I downloaded the entirety of Gnome.
guix install gnome
guix install gnome-desktop
By default, Guix should be using gdm
, the Gnome display manager, to do all of the display management boring work, but however, just by installing gnome
or gnome-desktop
, that wasn't enough to make my default login prompt show Gnome as a session type. Now maybe it could be my sheer stupidity and I didn't regenerate a certain file for gdm
to read from to know I have Gnome, but the frustration grew on me and I decided to go rogue.
I know Gnome supports Wayland, and it was clearly Xorg giving me a damn issue, so what if I went crazy and installed Wayland, a Wayland compositor like wlroots
, and a window manager like Sway? Well as it turns out, that's what I needed.
guix install sway
I won't lie, I have past experience with Sway and Wayland. I found the problems between Xorg compatibility and Wayland compatibility to be so off-putting that I steered clear of Wayland. Some applications would be utterly broken and non-functioning under Wayland, whlie others might be fine because of Xwayland
.
This time around, I needed a quick fix, and a way to control brightness. Reading some forums, I saw some hacks for echoing brightness values to the driver directly, but I opted for using something called brightnessctl
to do the exact thing that xbacklight
would do instead.
guix install xbacklight
This functions the exact same way, and require smaking a minor modification to the Sway config. If you're like me, and you're coming from i3wm
, it might help if you make a "clean" configuration file for Sway underneath ~/.sway/config
by coping the default Sway config as a starter kit. There are some things that Sway cannot handle from i3's end, despite it trying it's best.
(Note: I don't really know how to locate things easily in Guix store, so bear with me for this bit)
The default Sway config lives in the Sway package's /gnu/store
folder respectively. You will have to figure out the hash or folder exactly, but for me the default config file was something along these lines, which you might be able to use a glob for.
mkdir -p ~/.sway
cat /gnu/store/*sway*/etc/sway/config > ~/.sway/config
The *sway*
part is a regex to find a folder pattern that matches on that sway
string, while also trying to locate the additional /etc/sway/config
attached at the end. This again can be something fixed by proper Guixing, but alas, I am not quite there yet. I would definitely consider doing this as part of your overall Guix system definition, still.
Now after all is said and done and Sway isn't complaining about your config, let's add some brightnessctl
controls in where our F-keys would be used.
bindsym XF86MonBrightnessUp exec brightnessctl set +5%
bindsym XF86MonBrightnessDown exec brightnessctl set 5%-
Why are the plus and minus backwards? I dunno, that's just how it is I guess. This increments the brightness value by +5%/-5% respectively, which... is probably like what all other laptops do by default.
Another fix to make Sway more usable is to switch the default status command. By default, it's a while loop that executes practically every second, but it doesn't really provide the comforts of i3status
, so I simply use i3status
until I can figure out something else.
bar {
position top
status_command i3status
colors {
statusline #ffffff
background #323232
inactive_workspace #323232 #32323200 #5c5c5c
}
}
You can also change the default wallpaper if you like, but frankly I have given that zero thought as to what I would want on my background.
Now, for the flight home, I can actually modify my backlight. I also ran some further guix pull
stuff just to update my Guix in some pre-party downtime I found myself with.
Sway's benefits have largely been a positive so far for my laptop. Noticeably, on a full charge of battery, I started out with well over 6 hours of battery life just using Emacs and some terminals. Using stuff will reduce the battery life by a bit, but that's a tradeoff with Wayland that you get. Your programs will only render when you actually need them to render new state.
Recently, Fedora decided to drop future endeavours related to Xorg, and I think this could not have come any sooner. I think Xorg is a broken, archaeic pile of crap that I still continue to use, and I think we'd all be way better off with Wayland moving forward.
I can't say I've used Wayland for a long enough period of time to become truly proficient with it, but Wayland is getting more attraction due to new and upcoming window managers, like Hyprland, although much to my dismay, that project has some ... issues to say the least with it's community.
Hyprland probably wouldn't be possible on Xorg, and I think them approaching Wayland was the right call. Maybe I'll try it out one day? I'm not sure. I think at best, my laptop is a great place to try out Sway and see what Wayland is capable of in it's current shape. I would consider moving my desktop from i3wm
to sway
if I can convince myself it's the right thing to do, although I have some applications I fear may be weird for compatibility reasons.
ncmpcpp
I mentioned my use of mpd
and ncmpcpp
, and I use it every day without a second thought about the underpinnings of the two. However, with Guix, I discovered a weird issue I didn't expect to see at all.
In order for ncmpcpp
to read FIFO data for Fourier spectrum visuals, it needs to be compiled with a specific library called libfftw
. My configuration file for this spectrum waveform graphic, however, did not work, and it was because my Guix-installed ncmpcpp
did not have libfftw
compiled with it. I checked the ncmpcpp
definition, and yep, it certainly did not have libfftw
(also a lack of a Brotli library).
(define-public ncmpcpp
(package
(name "ncmpcpp")
(version "0.9.2")
(source (origin
(method url-fetch)
(uri
(string-append "https://ncmpcpp.rybczak.net/stable/ncmpcpp-"
version ".tar.bz2"))
(sha256
(base32
"06rs734n120jp51hr0fkkhxrm7zscbhpdwls0m5b5cccghazdazs"))))
(build-system gnu-build-system)
(inputs (list libmpdclient
boost
readline
ncurses
taglib
icu4c
curl))
(native-inputs
(list pkg-config))
(arguments
'(#:configure-flags
'("BOOST_LIB_SUFFIX=" "--with-taglib" "--enable-clock")))
(synopsis "Featureful ncurses based MPD client inspired by ncmpc")
(description "Ncmpcpp is an mpd client with a UI very similar to ncmpc,
but it provides new useful features such as support for regular expressions
for library searches, extended song format, items filtering, the ability to
sort playlists, and a local file system browser.")
(home-page "https://ncmpcpp.rybczak.net/")
(license license:gpl2+)))
Note the strong lack of both compiler flags to indicate a presence of libfftw
, and also the inherent lack of a package definition for libfftw
at all. It's just not there, and wasn't designed with that in mind. On purpose maybe? I'll have to look this up later on in life if I want to have proper ncmpcpp
functionality to mirror my Archlinux installation.
After doing all my Sway change-overs and making sure I could actually adjust backlight, turns out the flight back was much easier to use my computer with, minus the really small space and amount of arm room to maneuver and type.
Emulators worked, Steam worked, and of course, Emacs worked. However, the flight was pretty short, so I didn't feel like plugging in my laptop and complicating my leg space. I turned off my laptop after about 2 hours and hung out with my partner instead seeing her play Final Fantasy Tactics on her phone.
After arriving home after a very bumpy and scary ride, I am here editing this post, making the corrections, and reviewing my next possible Guix steps to take.
Coming home I had to do as much research as possible on how I can rectify a lot of my issues. My running list of problems was starting to get pretty high, such that:
I think a lot of these problems would be solved if I could somehow create a Guix configuration that would create my desirable home environment, and that's exactly what I am going to seek to fix starting today (two days after my return).
First goal is first: modifying my old system configuration to prefer something that supports Wayland right out of the box.
First thing's first; we need to strip xorg
out of our system entirely. Normally, xorg
is defined as a service in Guix, and we can cut that middle-man by simply dropping it entirely. To get gdm
to support Wayland, we have to flag the gdm
service type to do that by supplying a new configuration. Since gdm
exists as a baseline configuration in %desktop-services
, we'll have to cut the old gdm
and add a new one.
# inside config.scm
(operating-system
; ...
(services
(cons*
(service openssh-service-type)
(service cups-service-type)
(service gdm-service-type
(gdm-configuration
(wayland? #t)))
(modify-services %desktop-services
(delete-service gdm-service-type))))
; ...
)
Since gdm
can be overridden with other session management software like lightdm
, sddm
or slimdm
, it's important that we remove gdm
first via the delete-service
curried function. modify-services
acts like a linear function specifically targeting service type lists, so by passing it a delete-service
function, we can strip gdm
from the base %desktop-services
list and build our own. Then, our custom gdm
gets appended and becomes the new default session manager.
I rebuilt the system using this new setup, and just like that, gdm
would let me log into Sway instead of i3. You can make more modifications like removing hard xorg
oriented programs at this point, but xwayland
might add some deps for compatibility purposes.
guix home
Guix has the capabilities to define a user environment, which solves a good chunk of my issues I was just talking about. The idea is that one can pin their software dependencies, like Emacs or GIMP, and bind it to their local configuration so that it's always there and tightly bound.
In principle, if say, a GTK theme updates, the Guix derivation path will change, and hard paths to that theme will break when the derivation moves to a new location. You might not notice a breakage right away by hard-linking to a derivation, but running guix gc
will clean old, un-linked, unneeded packages off the disk entirely, which will break configurations.
guix home
introduces the idea of pinning your specifications to a profile you can swap in and out of, which will keep your home environment, configs and software consistent and able to work in a way that suits your needs. First step is to initiate a file we can play with, and to do so we can run the following:
guix home import ~/guix-config
This command pulls all packages currently in your environment into a file for editing. Meaning anything we've done guix install <thing>
for up to this point will be pulled in. For me, I had to trim some fat, so I cut out some things I wasn't using just to get the system nice and tidy.
We can edit the file inside ~/guix-config
to look at what is inside our home-configuration.scm
file now.
(home-environment
(packages (specifications->packages (list "emacs"
"htop"
"chocolate-doom"
;...
)))
(services
(list
(service home-bash-service-type
(home-bash-configuration
(aliases '())
(bashrc (list (local-file "/home/steve/.bashrc" "bashrc")))
(bash-profile (list (local-file "/home/steve/.bash_profile" "bash_profile")))
)))))
If that seems a little strange, well it's because it's not exactly straight-forward what's going on. Here, a service
is a little bit different than the ones we were just invoking a moment ago in operating-system
- a service type here means something that the guix home
system will enable for the home setting, and this basic service type refers to the Bash shell definitions it will be using to define our new home.
At this stage, it would be wise for you to run guix home container ~/guix-config/home-configuration.scm
so Guix can build the packages (yes... again) and create a new isolated environment for you to test it out within. Should everything work to your tastes, then move on.
(I should note, under your packages, comment out anything that might make your build cost hours of build time, like Firefox, Steam or whatever)
This solves one problem; software packages are now pinned, and should not get cleaned up accidentally while they live and are used in this home environment. This acknowledgement is just as important as system-level dependencies now. However, now we need to figure out how to incorporate these packages into configuration files, so that our config files never go stale.
Environment variables are needed for a lot of packages, and so many of them get created automatically by typical Linux software we take for granted. In this, I'll be showcasing how to get Firefox to work on Wayland, because right now, it doesn't without a flag.
For Firefox to function with Wayland, we need to set an environment variable before running it, namely MOZ_ENABLE_WAYLAND
, which is sort of annoying to have to put in front of a Firefox open command. I personally would prefer not having to type this out each time into rofi
, and to avoid having to create desktop shortcuts or aliases, I'd prefer this variable just be set at startup.
First, double-check that Firefox isn't using Wayland already. Go to about:support"
, Ctrl+F
for "Window Protocol", and see what it says. If it's using xwayland
, then it's using an X11-compatible Wayland program, and not actually directly speaking to the Wayland compositor. This will be remedied soon by creating the environment variable.
(simple-service 'env-vars
home-environment-variables-service-type
`(("MOZ_ENABLE_WAYLAND" . "1")))
Inserting this into your services, rebuilding the home configuration, then re-loading the shell or even window session, you should soon see MOZ_ENABLE_WAYLAND
appear in your environment variables (do echo $MOZ_ENABLE_WAYLAND
to confirm). For this to take effect in your window (in my case Sway), reboot the session by quitting and re-entering Sway for this to take effect. Then check out about:support
and see if the "Window Protocol" has changed to Wayland. If that works, hooray, you have Wayland support!
It is here that I got an idea, that instead of trying to dynamically link Guix hash paths into my config files, I should instead seek out the use of environment variables instead. I don't really want to have to hand-craft a future-proof Sway configuration, so maybe using environment variables will help me better.
By using a combination of something called G-expressions, probably short for "Guix expressions", I can get the calculated path of a package by doing #$package
, where package
is a pre-defined package variable, which you can get by doing specificiation->package
on a string with the text of your target package.
(define s->p specifications->package)
(let ([arc-theme (s->p "arc-theme")]
[sway (s->p "sway")]
[plasma-wp (s->p "plasma-workspace-wallpapers")])
(simple-service 'env-vars home-environment-variables-service-type
`(("MOZ_ENABLE_WAYLAND" . "1")
("GTK_THEME" . "Arc-Dark")
("SWAY_ROOT" . ,#~(string-append #$sway ""))
("PLASMA_WP" . ,#~(string-append #$plasma-wp "")
("GTK2_RC_FILES . ,#~(string-append #$arc-theme
"/share/themes/Arc-Dark"/gtk-2.0/gtkrc"))
))))
For something like including $SWAY_ROOT
in my Sway config, I can now do this when I want to execute or include other files.
include $SWAY_ROOT/etc/sway/config.d/*
Same applies for anything else, like loading wallpapers from the KDE Plasma wallpaper package that I conveniently added for some cool wallpapers.
(Thing of note: GTK theming is weird, and I wouldn't say this is 100% solved. I'm not sure if Guix has the capabilities to allow the system to search for themes)
Once finalized, you can test it with guix home container
to see if all your dotfiles get linked appropriately, as Guix will store them in the Guix store as with all other packages, then you can do guix home reconfigure
to switch yourself over to the new environment. Then it's all set!
That went on for a little longer than I would have cared for, but I decided to dedicate myself to this until I figured it out. I wanted to be sure I had a usable Guix system and home environment I could build off before closing this post out.
I returned from Mexico on Sunday, and it is currently Wednesday, so this did take me some time to wrap up. I set a pretty ambitious goal of trying to get this all done as quickly as possible, and now I feel a little more confident with Guix and using it as a daily driver. For whatever reason, this feels more comfortable to me than my time using NixOS.
More importantly, I'm home, I'm feeling more recovered from all the sleepless nights I was having, and I'm ready to start working on some projects that are stuck in my pipeline.
Thanks for reading!