<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fvwm3 on dev@iostream.pl</title><link>https://lvajxi03.github.io/tags/fvwm3/</link><description>Recent content in Fvwm3 on dev@iostream.pl</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 05 Oct 2026 15:05:00 +0200</lastBuildDate><atom:link href="https://lvajxi03.github.io/tags/fvwm3/index.xml" rel="self" type="application/rss+xml"/><item><title>Escape from the Tropics</title><link>https://lvajxi03.github.io/posts/2026-10-05/</link><pubDate>Mon, 05 Oct 2026 15:05:00 +0200</pubDate><guid>https://lvajxi03.github.io/posts/2026-10-05/</guid><description>&lt;p&gt;&lt;strong&gt;KDE Plasma&lt;/strong&gt; is a remarkably pleasant environment for work — and for pretty much everything else — so there is very little to complain about.&lt;/p&gt;
&lt;p&gt;However, since I have already taken the first steps toward moving completely to &lt;strong&gt;FVWM3&lt;/strong&gt;, a little consistency seems appropriate.&lt;/p&gt;
&lt;p&gt;It is time to start replacing some of the applications from the KDE ecosystem as well.&lt;/p&gt;
&lt;p&gt;Not all at once.&lt;/p&gt;
&lt;p&gt;No need to panic.&lt;/p&gt;
&lt;p&gt;First, we need a survival kit.&lt;/p&gt;
&lt;h1 id="minimal-version"&gt;Minimal Version
&lt;/h1&gt;&lt;p&gt;The absolute minimum I would find difficult to live without is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;another terminal → &lt;strong&gt;Alacritty&lt;/strong&gt;, because why not,&lt;/li&gt;
&lt;li&gt;another file manager → &lt;strong&gt;PCManFM-Qt&lt;/strong&gt; — I used its GTK ancestor about twenty years ago, so now the Qt version gets a chance,&lt;/li&gt;
&lt;li&gt;Qt appearance configuration → &lt;strong&gt;qt6ct&lt;/strong&gt; — without it, surprises await,&lt;/li&gt;
&lt;li&gt;somewhat more deliberate wallpaper handling → &lt;strong&gt;feh&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;a launcher slightly more sophisticated than &lt;code&gt;dmenu&lt;/code&gt; → &lt;strong&gt;rofi&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;display configuration management → &lt;strong&gt;autorandr&lt;/strong&gt; and &lt;strong&gt;arandr&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There is one additional detail with &lt;code&gt;qt6ct&lt;/code&gt;: Qt applications need to know that they are supposed to use it.&lt;/p&gt;
&lt;p&gt;An FVWM session will therefore eventually need something along the lines of:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export QT_QPA_PLATFORMTHEME&lt;span style="color:#f92672"&gt;=&lt;/span&gt;qt6ct
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Simply installing &lt;code&gt;qt6ct&lt;/code&gt; does not magically make it take control of every Qt application.&lt;/p&gt;
&lt;p&gt;Unfortunately.&lt;/p&gt;
&lt;p&gt;The magic comes later.&lt;/p&gt;
&lt;h1 id="standard-version"&gt;Standard Version
&lt;/h1&gt;&lt;p&gt;The standard version contains everything from the minimal one, plus:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bluetooth device management → &lt;strong&gt;blueman&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;display brightness control → &lt;strong&gt;brightnessctl&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;notifications → &lt;strong&gt;dunst&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;a PolicyKit authentication agent → &lt;strong&gt;lxqt-policykit&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;screenshots → &lt;strong&gt;flameshot&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;NetworkManager connection management → &lt;strong&gt;network-manager-applet&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;an audio mixer → &lt;strong&gt;pavucontrol&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;an X11 compositor → &lt;strong&gt;picom&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;media-player control → &lt;strong&gt;playerctl&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;automatic removable-media mounting through UDisks → &lt;strong&gt;udiskie&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;a volume-control applet → &lt;strong&gt;volumeicon&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;a second terminal, for variety → &lt;strong&gt;qterminal&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;a system tray → &lt;strong&gt;stalonetray&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this point, an innocent little window manager starts looking suspiciously like a desktop environment.&lt;/p&gt;
&lt;p&gt;But that is fine.&lt;/p&gt;
&lt;p&gt;We still know exactly what it consists of.&lt;/p&gt;
&lt;h1 id="full-version"&gt;Full Version
&lt;/h1&gt;&lt;p&gt;Naturally, the &lt;em&gt;full&lt;/em&gt; version requires the standard version and all of its dependencies, and adds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;yet another terminal, just to prevent boredom → &lt;strong&gt;kitty&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;another file manager → &lt;strong&gt;Thunar&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Three terminals may sound excessive.&lt;/p&gt;
&lt;p&gt;They are not.&lt;/p&gt;
&lt;h1 id="rpm-packages"&gt;RPM Packages
&lt;/h1&gt;&lt;p&gt;Since &lt;strong&gt;Fedora&lt;/strong&gt; is now my main operating system, there is an obvious next step:&lt;/p&gt;
&lt;p&gt;package all of this as RPMs.&lt;/p&gt;
&lt;p&gt;Right?&lt;/p&gt;
&lt;p&gt;Right.&lt;/p&gt;
&lt;p&gt;The packages do not even need to contain any programs or configuration files of their own.&lt;/p&gt;
&lt;p&gt;What we need are &lt;strong&gt;metapackages&lt;/strong&gt; — almost empty RPM packages whose main purpose is to depend on other packages.&lt;/p&gt;
&lt;p&gt;Instead of remembering fifteen package names, I should eventually be able to type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo dnf install kde-refugee-pack-standard
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and be done with it.&lt;/p&gt;
&lt;h2 id="tools"&gt;Tools
&lt;/h2&gt;&lt;p&gt;First, install the basic RPM-building tools:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo dnf install rpm-build rpmdevtools rpmlint
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Create the standard build tree:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpmdev-setuptree
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and generate a fresh spec template:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpmdev-newspec my-package.spec
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;A typical spec template contains fields such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Name&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Version&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Release&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Summary&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;License&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;URL&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Source&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BuildRequires&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Requires&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It also contains sections such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;%description&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%prep&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%build&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%install&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%files&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;%changelog&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a package consisting entirely of dependencies, most of these are unnecessary.&lt;/p&gt;
&lt;p&gt;There are no sources.&lt;/p&gt;
&lt;p&gt;There is nothing to compile.&lt;/p&gt;
&lt;p&gt;There is not even anything to install into the filesystem.&lt;/p&gt;
&lt;h2 id="minimal"&gt;Minimal
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;kde-refugee-pack-minimal.spec&lt;/code&gt; file can therefore look like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-rpm" data-lang="rpm"&gt;Name: kde-refugee-pack-minimal
Version: 0.0.1
Release: 1%{?dist}
Summary: KDE refugee pack, minimal version

License: MIT
BuildArch: noarch

Requires: alacritty
Requires: qt6ct
Requires: pcmanfm-qt
Requires: feh
Requires: rofi
Requires: autorandr
Requires: arandr

%description
Mandatory metapackage for everyone who leaves KDE for fvwm3
(minimal version)

%files

%changelog
* Sat Oct 03 2026 Marcin Bielewicz &amp;lt;marcin.bielewicz@gmail.com&amp;gt;
- initial version
&lt;/code&gt;&lt;/pre&gt;
 &lt;blockquote&gt;
 &lt;p&gt;Important: keep the empty &lt;code&gt;%files&lt;/code&gt; section.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;The package does not contain any files, but we still want &lt;code&gt;rpmbuild&lt;/code&gt; to produce a binary RPM.&lt;/p&gt;
&lt;p&gt;That is its entire purpose:&lt;/p&gt;
&lt;p&gt;to exist and require other packages.&lt;/p&gt;
&lt;h2 id="standard"&gt;Standard
&lt;/h2&gt;&lt;p&gt;The next level depends on the first one:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-rpm" data-lang="rpm"&gt;Name: kde-refugee-pack-standard
Version: 0.0.1
Release: 1%{?dist}
Summary: KDE refugee pack, standard version

License: MIT
BuildArch: noarch

Requires: kde-refugee-pack-minimal = %{version}
Requires: blueman
Requires: brightnessctl
Requires: dunst
Requires: flameshot
Requires: lxqt-policykit
Requires: network-manager-applet
Requires: pavucontrol
Requires: picom
Requires: playerctl
Requires: udiskie
Requires: volumeicon
Requires: qterminal
Requires: stalonetray

%description
Mandatory metapackage for everyone who leaves KDE for fvwm3
(standard version)

%files

%changelog
* Sat Oct 03 2026 Marcin Bielewicz &amp;lt;marcin.bielewicz@gmail.com&amp;gt;
- initial version
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The important line is:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-rpm" data-lang="rpm"&gt;Requires: kde-refugee-pack-minimal = %{version}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;which means:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;I require &lt;code&gt;kde-refugee-pack-minimal&lt;/code&gt; in the same version as this package.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Of course, this could be written explicitly:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-rpm" data-lang="rpm"&gt;Requires: kde-refugee-pack-minimal = 0.0.1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;but &lt;code&gt;%{version}&lt;/code&gt; saves us from having to remember to change it in the next release.&lt;/p&gt;
&lt;p&gt;Laziness.&lt;/p&gt;
&lt;p&gt;Once again, the driving force behind computer science.&lt;/p&gt;
&lt;h2 id="full"&gt;Full
&lt;/h2&gt;&lt;p&gt;The final level:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code class="language-rpm" data-lang="rpm"&gt;Name: kde-refugee-pack-full
Version: 0.0.1
Release: 1%{?dist}
Summary: KDE refugee pack, full version

License: MIT
BuildArch: noarch

Requires: kde-refugee-pack-standard = %{version}
Requires: kitty
Requires: Thunar

%description
Mandatory metapackage for everyone who leaves KDE for fvwm3
(full version)

%files

%changelog
* Sat Oct 03 2026 Marcin Bielewicz &amp;lt;marcin.bielewicz@gmail.com&amp;gt;
- initial version
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This gives us a dependency chain:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;full
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── standard
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └── minimal
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;with each level adding its own collection of tools.&lt;/p&gt;
&lt;h1 id="building-the-packages"&gt;Building the Packages
&lt;/h1&gt;&lt;p&gt;A binary RPM can be built with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpmbuild -bb package.spec
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The result will normally appear under:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;~/rpmbuild/RPMS/noarch/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;-bb&lt;/code&gt; option builds the binary package only.&lt;/p&gt;
&lt;p&gt;If we also want an SRPM:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpmbuild -ba package.spec
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That is what I will use in CI.&lt;/p&gt;
&lt;p&gt;If the computer is doing the work anyway, there is little reason to stop it.&lt;/p&gt;
&lt;h1 id="installing-the-packages"&gt;Installing the Packages
&lt;/h1&gt;&lt;p&gt;A local RPM can be installed through DNF:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo dnf install ./package.rpm
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;./&lt;/code&gt; matters: it tells DNF that this is a local file rather than a package name to search for in configured repositories.&lt;/p&gt;
&lt;p&gt;DNF then resolves and installs the dependencies.&lt;/p&gt;
&lt;p&gt;Which was the whole point of this exercise.&lt;/p&gt;
&lt;h1 id="github-actions"&gt;GitHub Actions
&lt;/h1&gt;&lt;p&gt;Once the spec files live in a repository, rebuilding them manually every time starts looking suspiciously like a task that could be automated.&lt;/p&gt;
&lt;p&gt;Tasks like that are dangerous.&lt;/p&gt;
&lt;p&gt;They tend to produce CI pipelines.&lt;/p&gt;
&lt;p&gt;The workflow can look like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Build RPM packages&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;on&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;push&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;paths&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;specs/**&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;.github/workflows/rpm.yml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;pull_request&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;paths&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;specs/**&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;.github/workflows/rpm.yml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;permissions&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;contents&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;read&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;jobs&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;build&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Build ${{ matrix.package }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;strategy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;fail-fast&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;matrix&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;package&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;kde-refugee-pack-minimal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;kde-refugee-pack-standard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;kde-refugee-pack-full&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;fedora:44&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;steps&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Install build tools&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; dnf install -y \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; findutils \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; rpm-build \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; rpmdevtools \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; rpmlint&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Checkout repository&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/checkout@v7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Prepare rpmbuild tree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;rpmdev-setuptree&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Copy spec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; cp specs/${{ matrix.package }}.spec ~/rpmbuild/SPECS/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Lint spec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; rpmlint specs/${{ matrix.package }}.spec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Build RPM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; rpmbuild -ba ~/rpmbuild/SPECS/${{ matrix.package }}.spec&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Show result&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; find ~/rpmbuild/RPMS ~/rpmbuild/SRPMS -type f -print&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Collect build artifacts&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; mkdir -p artifacts
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; cp ~/rpmbuild/RPMS/noarch/*.rpm artifacts/
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; cp ~/rpmbuild/SRPMS/*.src.rpm artifacts/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Upload build bundle&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/upload-artifact@v7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;bundle-${{ matrix.package }}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;artifacts/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Upload binary RPM directly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/upload-artifact@v7&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;~/rpmbuild/RPMS/noarch/${{ matrix.package }}-*.noarch.rpm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;archive&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;install-test&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Test package installation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;needs&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;build&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;container&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;fedora:44&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;steps&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Download kde-refugee-pack-minimal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/download-artifact@v8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;bundle-kde-refugee-pack-minimal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;rpms/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Download kde-refugee-pack-standard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/download-artifact@v8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;bundle-kde-refugee-pack-standard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;rpms/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Download kde-refugee-pack-full&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;uses&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;actions/download-artifact@v8&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;with&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;bundle-kde-refugee-pack-full&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;rpms/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Install refugee pack&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;run&lt;/span&gt;: |&lt;span style="color:#e6db74"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; dnf install -y \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; rpms/kde-refugee-pack-minimal-*.noarch.rpm \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; rpms/kde-refugee-pack-standard-*.noarch.rpm \
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#e6db74"&gt; rpms/kde-refugee-pack-full-*.noarch.rpm&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;At first glance, this line may look odd:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;runs-on&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;ubuntu-latest&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We are building Fedora packages, after all.&lt;/p&gt;
&lt;p&gt;A few lines later, however:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;container&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;image&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;fedora:44&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;GitHub provides the runner, while the job itself executes in a Fedora 44 environment.&lt;/p&gt;
&lt;p&gt;There is no need for a separate Fedora runner.&lt;/p&gt;
&lt;p&gt;The matrix:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;matrix&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;package&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;kde-refugee-pack-minimal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;kde-refugee-pack-standard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#ae81ff"&gt;kde-refugee-pack-full&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;creates three independent builds.&lt;/p&gt;
&lt;p&gt;Each spec file is checked with &lt;code&gt;rpmlint&lt;/code&gt;, built, and stored as an artifact.&lt;/p&gt;
&lt;p&gt;And this is where things become pleasantly convenient.&lt;/p&gt;
&lt;p&gt;A normal artifact upload creates an archive containing the RPM and SRPM.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;actions/upload-artifact@v7&lt;/code&gt; also supports:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;archive&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;for a single file.&lt;/p&gt;
&lt;p&gt;So every binary RPM is additionally available directly as an &lt;code&gt;.rpm&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;No ZIP extraction required.&lt;/p&gt;
&lt;p&gt;Like civilized people.&lt;/p&gt;
&lt;p&gt;The second job downloads all three build bundles and tries to install the packages on a fresh Fedora environment.&lt;/p&gt;
&lt;p&gt;The workflow therefore verifies more than:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;the RPM builds.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;It also verifies:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;DNF can resolve the dependency chain and install all three levels.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;And because the workflow itself lives at:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;.github/workflows/rpm.yml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;while the path filter contains:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;paths&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;specs/**&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;.github/workflows/rpm.yml&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;changing the workflow itself triggers another run.&lt;/p&gt;
&lt;p&gt;The pipeline therefore tests, among other things, itself.&lt;/p&gt;
&lt;h1 id="summary"&gt;Summary
&lt;/h1&gt;&lt;p&gt;A small joke of a task somehow grew into:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a list of programs I will actually use,&lt;/li&gt;
&lt;li&gt;three levels of a KDE survival kit,&lt;/li&gt;
&lt;li&gt;three RPM metapackages,&lt;/li&gt;
&lt;li&gt;automated linting,&lt;/li&gt;
&lt;li&gt;automated builds,&lt;/li&gt;
&lt;li&gt;an installation test,&lt;/li&gt;
&lt;li&gt;artifacts available both as bundles and directly as RPM files,&lt;/li&gt;
&lt;li&gt;and a GitHub repository: &lt;a class="link" href="https://github.com/lvajxi03/specfiles/" target="_blank" rel="noopener"
 &gt;specfiles&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All because I did not want to type a dozen package names by hand.&lt;/p&gt;
&lt;p&gt;It was laziness, Your Honor.&lt;/p&gt;</description></item><item><title>A Window Manager Unlike Any Other</title><link>https://lvajxi03.github.io/posts/2026-09-28/</link><pubDate>Mon, 28 Sep 2026 19:10:00 +0200</pubDate><guid>https://lvajxi03.github.io/posts/2026-09-28/</guid><description>&lt;p&gt;Thirty-three years is a very long time in software.&lt;/p&gt;
&lt;p&gt;Trends change.&lt;/p&gt;
&lt;p&gt;Architectures come and go.&lt;/p&gt;
&lt;p&gt;Companies collapse, occasionally taking genuinely excellent projects to the grave with them.&lt;/p&gt;
&lt;p&gt;It is long enough that, back in 1993, I was considering moving from a Commodore 64 to an Amiga 500 — which never actually happened — while in 2026 I find myself interested in software from that same era which somehow still exists.&lt;/p&gt;
&lt;p&gt;And not merely exists.&lt;/p&gt;
&lt;p&gt;Some of it is doing remarkably well.&lt;/p&gt;
&lt;p&gt;In 1993, engineer &lt;strong&gt;Robert Nation&lt;/strong&gt; needed a lightweight window manager for a 33 MHz 486 laptop with just 4 MB of RAM.&lt;/p&gt;
&lt;p&gt;At the same time, his work involved analyzing enormous spectrograms, and he needed a virtual desktop larger than a single physical screen.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TWM&lt;/strong&gt; worked, but it consumed more memory than he liked and did not provide everything he needed.&lt;/p&gt;
&lt;p&gt;So he did what any reasonable programmer dissatisfied with an existing tool would do:&lt;/p&gt;
&lt;p&gt;he started taking it apart.&lt;/p&gt;
&lt;p&gt;The result was &lt;strong&gt;FVWM&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Its first public version was bundled with an &lt;code&gt;rxvt&lt;/code&gt; release on June 1, 1993. Soon afterward FVWM became an independent project, and it is still with us today.&lt;/p&gt;
&lt;p&gt;Despite more than three decades of development, it has retained much of its original character:&lt;/p&gt;
&lt;p&gt;it is lightweight, modular, extraordinarily configurable, and assumes that the user may actually know how their own desktop should behave.&lt;/p&gt;
&lt;h1 id="f-vwm"&gt;F? VWM
&lt;/h1&gt;&lt;p&gt;So what does the name mean?&lt;/p&gt;
&lt;p&gt;Today the official project calls it:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;F? Virtual Window Manager&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;where &lt;code&gt;F?&lt;/code&gt; can be expanded into almost anything beginning with the letter F.&lt;/p&gt;
&lt;p&gt;Preferably something printable.&lt;/p&gt;
&lt;p&gt;Originally, however, the &lt;code&gt;F&lt;/code&gt; had a very specific meaning:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Feeble Virtual Window Manager&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Robert Nation himself confirmed this, explaining that the earliest versions offered very few user-selectable features, so &lt;em&gt;feeble&lt;/em&gt; was a fairly accurate description.&lt;/p&gt;
&lt;p&gt;The software eventually stopped being feeble in any meaningful sense, while the interpretation of the letter F drifted into folklore.&lt;/p&gt;
&lt;p&gt;The modern project page suggests words such as:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;fantastic, fabulous, famous, flexible&amp;hellip;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;and wisely leaves the rest to the user&amp;rsquo;s imagination.&lt;/p&gt;
&lt;h2 id="what-exactly-is-a-window-manager"&gt;What Exactly Is a Window Manager?
&lt;/h2&gt;&lt;p&gt;That is a reasonable question.&lt;/p&gt;
&lt;p&gt;What sort of software is this?&lt;/p&gt;
&lt;p&gt;And why should anyone care?&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;window manager&lt;/strong&gt; manages application windows within a graphical session.&lt;/p&gt;
&lt;p&gt;In the X11 world it is responsible for things such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;window placement,&lt;/li&gt;
&lt;li&gt;size,&lt;/li&gt;
&lt;li&gt;stacking order,&lt;/li&gt;
&lt;li&gt;focus,&lt;/li&gt;
&lt;li&gt;decorations,&lt;/li&gt;
&lt;li&gt;minimization,&lt;/li&gt;
&lt;li&gt;maximization,&lt;/li&gt;
&lt;li&gt;switching between windows.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An application creates a window.&lt;/p&gt;
&lt;p&gt;The window manager decides what happens to it next.&lt;/p&gt;
&lt;p&gt;And that is all?&lt;/p&gt;
&lt;p&gt;More or less.&lt;/p&gt;
&lt;p&gt;Which is exactly what makes the idea interesting.&lt;/p&gt;
&lt;p&gt;GNOME, KDE Plasma, Xfce, and LXQt are complete &lt;strong&gt;desktop environments&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;They are collections of cooperating components that usually provide things such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;panels,&lt;/li&gt;
&lt;li&gt;menus,&lt;/li&gt;
&lt;li&gt;session management,&lt;/li&gt;
&lt;li&gt;display configuration,&lt;/li&gt;
&lt;li&gt;settings tools,&lt;/li&gt;
&lt;li&gt;notifications,&lt;/li&gt;
&lt;li&gt;desktop icons,&lt;/li&gt;
&lt;li&gt;wallpapers,&lt;/li&gt;
&lt;li&gt;device integration,&lt;/li&gt;
&lt;li&gt;often an entire set of applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A window manager is only one part of that puzzle.&lt;/p&gt;
&lt;p&gt;In the old days, an X11 desktop was often assembled gradually.&lt;/p&gt;
&lt;p&gt;Need a panel?&lt;/p&gt;
&lt;p&gt;Install one.&lt;/p&gt;
&lt;p&gt;Need a menu?&lt;/p&gt;
&lt;p&gt;Add one.&lt;/p&gt;
&lt;p&gt;Want a wallpaper?&lt;/p&gt;
&lt;p&gt;Run a wallpaper setter.&lt;/p&gt;
&lt;p&gt;Need desktop icons, a notification area, media controls, or animated penguins wandering around the screen?&lt;/p&gt;
&lt;p&gt;No problem.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;xpenguins&lt;/code&gt; is waiting.&lt;/p&gt;
&lt;p&gt;Today, we are much more likely to install an entire desktop environment and accept whatever came from the factory.&lt;/p&gt;
&lt;p&gt;And the factory keeps providing more.&lt;/p&gt;
&lt;p&gt;Increasingly tightly integrated.&lt;/p&gt;
&lt;p&gt;Eleven out of ten users never even change the wallpaper.&lt;/p&gt;
&lt;h2 id="what-does-fvwm-provide"&gt;What Does FVWM Provide?
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;FVWM&lt;/strong&gt; is a classic window manager in exactly that older tradition.&lt;/p&gt;
&lt;p&gt;Its primary concern is windows and how they behave.&lt;/p&gt;
&lt;p&gt;Want a panel?&lt;/p&gt;
&lt;p&gt;You can have one.&lt;/p&gt;
&lt;p&gt;Menus?&lt;/p&gt;
&lt;p&gt;Of course.&lt;/p&gt;
&lt;p&gt;A pager?&lt;/p&gt;
&lt;p&gt;Certainly.&lt;/p&gt;
&lt;p&gt;A window list?&lt;/p&gt;
&lt;p&gt;Also available.&lt;/p&gt;
&lt;p&gt;But FVWM does not assume that its developers know better than you how all of those things should look or behave.&lt;/p&gt;
&lt;p&gt;The default configuration provides enough to get started and then seems to say:&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Run me.&lt;br&gt;
Use me.&lt;br&gt;
Decide what is missing.&lt;br&gt;
Then configure it yourself.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;That is what its extensive configuration system is for.&lt;/p&gt;
&lt;p&gt;The official project describes FVWM3 as a lightweight floating window manager for X11 that can be configured as anything from a small minimal setup to something resembling a complete desktop environment.&lt;/p&gt;
&lt;h1 id="installation"&gt;Installation
&lt;/h1&gt;&lt;p&gt;I assume you already have &lt;em&gt;some&lt;/em&gt; graphical environment installed.&lt;/p&gt;
&lt;p&gt;Modern Linux distributions usually come with KDE, GNOME, Xfce, LXQt, or something similar.&lt;/p&gt;
&lt;p&gt;You therefore probably also have a display manager.&lt;/p&gt;
&lt;p&gt;In my case, this is &lt;strong&gt;Fedora with KDE Plasma and SDDM&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Installation is straightforward:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo dnf install fvwm3 dmenu
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first package contains &lt;strong&gt;FVWM3&lt;/strong&gt; itself.&lt;/p&gt;
&lt;p&gt;The second provides &lt;code&gt;dmenu&lt;/code&gt;, which the default FVWM configuration uses as a simple application launcher.&lt;/p&gt;
&lt;p&gt;It is worth checking that the package installed an X session definition:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rpm -ql fvwm3 | grep xsessions
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;On my system:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/share/xsessions/fvwm3.desktop
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Excellent.&lt;/p&gt;
&lt;p&gt;Log out.&lt;/p&gt;
&lt;p&gt;Select &lt;strong&gt;FVWM3&lt;/strong&gt; on the login screen.&lt;/p&gt;
&lt;p&gt;Enter the password.&lt;/p&gt;
&lt;p&gt;Press &lt;code&gt;Enter&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;And&amp;hellip;&lt;/p&gt;
&lt;h1 id="hello-darkness"&gt;Hello Darkness
&lt;/h1&gt;&lt;p&gt;&amp;hellip;enjoy the majestic sight of absolutely nothing.&lt;/p&gt;
&lt;p&gt;The session did not start.&lt;/p&gt;
&lt;p&gt;The reason turned out to be simple:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FVWM3 is an X11 window manager&lt;/strong&gt;, while my Fedora installation only had Wayland available.&lt;/p&gt;
&lt;p&gt;FVWM3 is still primarily built around Xlib and the X Window System.&lt;/p&gt;
&lt;p&gt;So Xorg needs to be installed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sudo dnf install xorg-x11-server-Xorg
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Fedora 44 still ships Xorg separately for X11 sessions and software that depends on it.&lt;/p&gt;
&lt;p&gt;Log in once more.&lt;/p&gt;
&lt;p&gt;Ah.&lt;/p&gt;
&lt;p&gt;Much better.&lt;/p&gt;
&lt;h2 id="configuring-x11"&gt;Configuring X11
&lt;/h2&gt;&lt;p&gt;The biggest surprise after all these years is that X11 no longer needs to be configured.&lt;/p&gt;
&lt;p&gt;It simply starts.&lt;/p&gt;
&lt;p&gt;And works.&lt;/p&gt;
&lt;p&gt;There is no need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;select graphics drivers manually,&lt;/li&gt;
&lt;li&gt;describe the monitor,&lt;/li&gt;
&lt;li&gt;write &lt;code&gt;Modeline&lt;/code&gt; entries,&lt;/li&gt;
&lt;li&gt;configure the mouse,&lt;/li&gt;
&lt;li&gt;configure the keyboard,&lt;/li&gt;
&lt;li&gt;specify font directories.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I remember a time when starting X11 and getting a black screen instead of smoke already counted as progress.&lt;/p&gt;
&lt;p&gt;Today it simply works.&lt;/p&gt;
&lt;p&gt;Thank you, 2026.&lt;/p&gt;
&lt;h1 id="first-start"&gt;First Start
&lt;/h1&gt;&lt;p&gt;The default &lt;strong&gt;FVWM3&lt;/strong&gt; session looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Default session" class="gallery-image" data-flex-basis="426px" data-flex-grow="177" height="1080" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-1.png" srcset="https://lvajxi03.github.io/posts/2026-09-28/fvwm-1_hu_ccb8a2f3b24802da.png 800w, https://lvajxi03.github.io/posts/2026-09-28/fvwm-1_hu_1d0e9028cb527683.png 1600w, https://lvajxi03.github.io/posts/2026-09-28/fvwm-1.png 1920w" width="1920"&gt;&lt;/p&gt;
&lt;p&gt;What exactly are we looking at?&lt;/p&gt;
&lt;p&gt;On the right is a panel constructed with the &lt;code&gt;FvwmButtons&lt;/code&gt; module.&lt;/p&gt;
&lt;p&gt;It contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the FVWM logo — still maintaining the cat theme,&lt;/li&gt;
&lt;li&gt;desktop buttons &lt;code&gt;0–3&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;a pager,&lt;/li&gt;
&lt;li&gt;an area for open windows managed by &lt;code&gt;FvwmIconMan&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;a clock and date display.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is essentially what the current upstream default configuration defines.&lt;/p&gt;
&lt;p&gt;As applications are opened, the panel gradually fills up:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Top of the default panel" class="gallery-image" data-flex-basis="159px" data-flex-grow="66" height="197" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-1a.png" width="131"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="The panel filling up" class="gallery-image" data-flex-basis="135px" data-flex-grow="56" height="230" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-1b.png" width="130"&gt;&lt;/p&gt;
&lt;p&gt;That is already quite a lot.&lt;/p&gt;
&lt;p&gt;We can even launch something.&lt;/p&gt;
&lt;p&gt;Press:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Alt+Space
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and &lt;code&gt;dmenu_run&lt;/code&gt; appears.&lt;/p&gt;
&lt;p&gt;The current default FVWM configuration binds exactly that command to &lt;code&gt;Alt+Space&lt;/code&gt;, provided &lt;code&gt;dmenu&lt;/code&gt; is installed.&lt;/p&gt;
&lt;p&gt;It displays executables found through &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Which means:&lt;/p&gt;
&lt;p&gt;a lot of things.&lt;/p&gt;
&lt;p&gt;Far too many things.&lt;/p&gt;
&lt;p&gt;Fortunately, the list is filtered as you type.&lt;/p&gt;
&lt;p&gt;&lt;img alt="dmenu" class="gallery-image" data-flex-basis="8276px" data-flex-grow="3448" height="35" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-7.png" srcset="https://lvajxi03.github.io/posts/2026-09-28/fvwm-7_hu_74944ae8d7d63df.png 800w, https://lvajxi03.github.io/posts/2026-09-28/fvwm-7.png 1207w" width="1207"&gt;&lt;/p&gt;
&lt;h2 id="windows"&gt;Windows
&lt;/h2&gt;&lt;p&gt;The first application window looks something like this:&lt;/p&gt;
&lt;p&gt;&lt;img alt="First window" class="gallery-image" data-flex-basis="426px" data-flex-grow="177" height="1080" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-2.png" srcset="https://lvajxi03.github.io/posts/2026-09-28/fvwm-2_hu_b33654003e070d1b.png 800w, https://lvajxi03.github.io/posts/2026-09-28/fvwm-2_hu_1138e42d428c8304.png 1600w, https://lvajxi03.github.io/posts/2026-09-28/fvwm-2.png 1920w" width="1920"&gt;&lt;/p&gt;
&lt;p&gt;There is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a title bar,&lt;/li&gt;
&lt;li&gt;buttons on both sides,&lt;/li&gt;
&lt;li&gt;a frame,&lt;/li&gt;
&lt;li&gt;borders,&lt;/li&gt;
&lt;li&gt;corners.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Window buttons" class="gallery-image" data-flex-basis="463px" data-flex-grow="193" height="268" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-2a.png" width="518"&gt;&lt;/p&gt;
&lt;p&gt;The button on the left opens the window operations menu.&lt;/p&gt;
&lt;p&gt;The ones on the right perform more obvious jobs such as closing, maximizing, and minimizing.&lt;/p&gt;
&lt;p&gt;Drag the title bar to move the window.&lt;/p&gt;
&lt;p&gt;Drag an edge to resize it.&lt;/p&gt;
&lt;p&gt;Drag a corner to resize it in two directions at once.&lt;/p&gt;
&lt;p&gt;The technology is clearly almost ready for worldwide adoption.&lt;/p&gt;
&lt;p&gt;Click the &lt;strong&gt;left mouse button&lt;/strong&gt; on the root window and the main FVWM menu appears:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Default menu" class="gallery-image" data-flex-basis="148px" data-flex-grow="62" height="261" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-3.png" width="162"&gt;&lt;/p&gt;
&lt;p&gt;Not bad.&lt;/p&gt;
&lt;p&gt;The important commands are already present.&lt;/p&gt;
&lt;p&gt;Including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Restart&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Quit&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Restart&lt;/code&gt; will become extremely useful in future episodes.&lt;/p&gt;
&lt;p&gt;Trust me.&lt;/p&gt;
&lt;h2 id="desks-and-pages"&gt;Desks and Pages
&lt;/h2&gt;&lt;p&gt;One of FVWM&amp;rsquo;s more interesting features is its enormous virtual workspace.&lt;/p&gt;
&lt;p&gt;The default configuration provides four &lt;strong&gt;desks&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;0 1 2 3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each desk can itself contain multiple &lt;strong&gt;pages&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;FVWM therefore distinguishes between two concepts:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Desk&lt;/strong&gt; — a separate desktop.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Page&lt;/strong&gt; — a position within the larger virtual space of that desktop.&lt;/p&gt;
&lt;p&gt;With the normal global multi-monitor configuration, all connected displays together form the visible area of one page.&lt;/p&gt;
&lt;p&gt;This means the virtual desktop can extend beyond the complete physical monitor arrangement.&lt;/p&gt;
&lt;p&gt;Then you can have several such virtual spaces.&lt;/p&gt;
&lt;p&gt;And several desks containing those.&lt;/p&gt;
&lt;p&gt;Sounds excessive?&lt;/p&gt;
&lt;p&gt;Give it a few days.&lt;/p&gt;
&lt;p&gt;You will run out of room.&lt;/p&gt;
&lt;p&gt;This becomes especially useful when many windows are open and you want to group them by purpose.&lt;/p&gt;
&lt;p&gt;One desk for code.&lt;/p&gt;
&lt;p&gt;One for documentation.&lt;/p&gt;
&lt;p&gt;One for communication.&lt;/p&gt;
&lt;p&gt;One for terminals that have been open for so long that nobody dares close them anymore.&lt;/p&gt;
&lt;p&gt;Open a window and try dragging it beyond the current visible workspace.&lt;/p&gt;
&lt;p&gt;Near the edge, you will feel a slight resistance.&lt;/p&gt;
&lt;p&gt;Keep going.&lt;/p&gt;
&lt;p&gt;The window crosses onto the neighboring page.&lt;/p&gt;
&lt;p&gt;At that moment the physical screen stops feeling like the desktop itself.&lt;/p&gt;
&lt;p&gt;It becomes merely a viewport onto something much larger.&lt;/p&gt;
&lt;h2 id="menus-and-window-information"&gt;Menus and Window Information
&lt;/h2&gt;&lt;p&gt;Clicking the &lt;strong&gt;right mouse button&lt;/strong&gt; on the root window opens the window operations menu.&lt;/p&gt;
&lt;p&gt;At this point no particular window has been selected.&lt;/p&gt;
&lt;p&gt;First choose the operation.&lt;/p&gt;
&lt;p&gt;Then choose the target window.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Window operations menu" class="gallery-image" data-flex-basis="161px" data-flex-grow="67" height="350" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-5.png" width="236"&gt;&lt;/p&gt;
&lt;p&gt;For example, choose:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Identify&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;and then:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GNU Emacs&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;FvwmIdent&lt;/code&gt; appears:&lt;/p&gt;
&lt;p&gt;&lt;img alt="FvwmIdent" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="fwvm-11.png"&gt;&lt;/p&gt;
&lt;p&gt;At first it looks like a collection of obscure X11 properties.&lt;/p&gt;
&lt;p&gt;Later, these values become extremely useful when writing configuration rules.&lt;/p&gt;
&lt;p&gt;That is precisely what &lt;code&gt;FvwmIdent&lt;/code&gt; is intended for: among other things, identifying a window&amp;rsquo;s name, resource, and class.&lt;/p&gt;
&lt;p&gt;Clicking the &lt;strong&gt;middle mouse button&lt;/strong&gt; on the root window displays a window list, including geometry information.&lt;/p&gt;
&lt;p&gt;Its main purpose is to activate another window quickly.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Alt+Tab&lt;/code&gt; produces a simpler window list without geometry.&lt;/p&gt;
&lt;p&gt;The default configuration binds this directly to FVWM&amp;rsquo;s &lt;code&gt;WindowList&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Clicking the &lt;strong&gt;right mouse button on a title bar&lt;/strong&gt; opens the current window&amp;rsquo;s operations menu:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Window menu" class="gallery-image" data-flex-basis="146px" data-flex-grow="61" height="190" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-4.png" width="116"&gt;&lt;/p&gt;
&lt;p&gt;Among the more interesting entries are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Stick / Unstick&lt;/strong&gt; — make the window appear across desks, or return it to normal behavior,&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Shade / Unshade&lt;/strong&gt; — collapse the window until only the title bar remains, then restore it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Shade" class="gallery-image" data-flex-basis="3328px" data-flex-grow="1386" height="69" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-6a.png" srcset="https://lvajxi03.github.io/posts/2026-09-28/fvwm-6a_hu_2dc9349d2e1dbe36.png 800w, https://lvajxi03.github.io/posts/2026-09-28/fvwm-6a.png 957w" width="957"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Stick" class="gallery-image" data-flex-basis="2172px" data-flex-grow="905" height="75" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://lvajxi03.github.io/posts/2026-09-28/fvwm-6b.png" width="679"&gt;&lt;/p&gt;
&lt;p&gt;And that is enough for the first encounter.&lt;/p&gt;
&lt;p&gt;Spend a while moving windows around, switching desks, exploring pages, and generally discovering how much space FVWM is prepared to give you.&lt;/p&gt;
&lt;p&gt;Then choose &lt;strong&gt;Quit&lt;/strong&gt; from the main menu.&lt;/p&gt;
&lt;p&gt;In the next episode, we will log in again.&lt;/p&gt;
&lt;p&gt;But this time, into &lt;strong&gt;our&lt;/strong&gt; FVWM.&lt;/p&gt;</description></item></channel></rss>