Developing for the KDE ecosystem is pretty fun, and sometimes it leads to interesting discoveries through experimentation. Today we're gonna try something cursed: installing KDE components through symlinking, and the implications that follow from doing so.
To clear out some common knowledge, it's well known that under the Linux desktop you can install components either locally or systemwide, such as icons, sounds, fonts, etc. This is done by dropping the appropriate stuff in either ~/.local/share
or /usr/share
for user and system installations respectively. This is standard practice, and KDE software follows this standard as well. So things like plasmoids, global themes, KWin effects and scripts end up being placed in the aforementioned directories when installed either manually or through kpackagetool6.
Nothing out of the ordinary so far, right? Now, here's where things get a little interesting.
When KDE software tries loading packages installed like this, it does so by prioritizing locally-installed packages first. So, if it can find the package within ~/.local/share
, it'll attempt to load that. If not, it'll go to /usr/share
instead.
What this means is that the user can effectively take systemwide packages, install them locally (by moving them from /usr/share
to ~/.local/share
) and make changes to them, which would then be loaded first upon reloading Plasma and/or KWin, depending on what packages have been moved.
The following question naturally arises from this: What are all the things that we can install locally and expect them to work? Well, almost pretty much everything found in /usr/share/plasma
and /usr/share/kwin
.
This has the interesting consequence of being able to locally install components that were never meant to be installed like that, much less modified afterwards. Things like the outline directory, which contains code that defines the window frame that appears when snapping windows to screen edges, and the shells directory, which has plenty of QML code for various aspects of the desktop shell.
Perhaps the earlier section was also common knowledge among KDE power users out there, so let's get to the point and take this to the next logical step, which is to replace these locally installed packages with symlinks, and see what happens.
There are two main ways of approaching this:
The first one is straightforward; we just create a symlink which points to any desired directory like this:
This just seems to work completely fine, as expected. KDE doesn't seem to think anything is out of the ordinary with this. This works best for directories that don't have anything interesting going on for the end-user (like shells). As of the release of KDE Plasma 6.4, where KWin got split into KWin and KWin-X11, this method has the legitimate use case (possibly the only legit use case, lol) of symlinking the kwin folder found in ~/.local/share
to kwin-x11 and kwin-wayland, since any code found there is limited to QML and JavaScript, and most of that code doesn't care about what display server you're using.
So this is cool and all, but this isn't particularly great for folders where things like plasmoids or KWin scripts are stored, since the user is likely to install a bunch of these over time. These packages shouldn't be installed in some arbitrary directory that could be located quite literally anywhere.
Let's say that we want to perform some kind of symlinking in those cases anyway (suspend your disbelief for a moment). Going by the same principle as provided above, we get this:
Assuming all of these have already been placed in some kind of containment (panel or desktop), upon restarting Plasmashell everything seems to work correctly. The plasmoids have been loaded correctly! That is, until you try adding a plasmoid that hasn't been loaded into a containment beforehand. Most of the symlinked plasmoids are nowhere to be found in the menu for adding widgets. Not even kpackagetool6 recognizes their existence.
The only exception to this seems to be plasmoids that already exist in /usr/share/plasma/plasmoids
, like built-in plasmoids. After loads of trial and error (more than what would be considered sane behavior by most), I ended up devising a workaround that would make the other invisible plasmoids show up again.
Let's take Simple Application Launcher as an example plasmoid:
The magic is shown on the bottom half of the image. Plasma requires there to be at least one true directory (as in, not a symlink) with the relevant plasmoid ID, and additionally a metadata.json file inside it, although that file can be a symlink as well. With this rather insane setup, the plasmoid can finally be viewed by the "Add widgets" menu and by kpackagetool6:
You can now unsuspend your disbelief, as it's easy to see how this only makes things more convoluted, with any hypothetical benefits not really justifying the weirdness of the setup required. This ended up being more of a mini-rabbit hole that was simply interesting to delve into to see how much you can "trick" Plasma.