Skip to content

Latest commit

 

History

46 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Paddocks

Grouped desktop launcher panels for KDE Plasma 6, built out of stock Plasma widgets.

Windows has several tools that group desktop icons into titled, translucent panels; Linux has none. Plasma can already do most of it, but the pieces are undocumented and several fail silently. Paddocks is the working setup, plus — more usefully — the five things that otherwise cost an afternoon each.

Seven groups laid out across the top of a 3440x1440 desktop

Install

pipx install "paddocks[gui] @ git+https://github.com/SonicP3L1C4N/paddocks.git"
paddocks install-desktop        # optional: menu entry and icon

Or clone and symlink the entry point onto your PATH — no installer, and edits take effect immediately:

git clone https://github.com/SonicP3L1C4N/paddocks.git
ln -s "$PWD/paddocks/bin/paddocks" ~/.local/bin/paddocks

Requires KDE Plasma 6 (developed against 6.6), Python 3.11+ for tomllib, and qdbus6 / kwriteconfig6 / kquitapp6, all standard on a Plasma install. The command line has no third-party dependencies; only paddocks edit needs PySide6, which the [gui] extra pulls in. A distro package (sudo apt install python3-pyside6.qtwidgets) works too, and is what a checkout uses — drop the extra to avoid a second copy of Qt in a venv. PySide6 is the LGPL binding; PyQt6 is GPL-3.0-or-commercial, which does not suit an MIT project.

Use

Each group becomes a titled Quicklaunch widget, positioned and sized automatically from a small TOML file. Clicking launches; dragging an application onto a group adds it.

A single group close up: custom title, application names, and the wallpaper showing through the translucent background

paddocks discover > ~/.config/paddocks.toml   # every installed app, pre-grouped
$EDITOR ~/.config/paddocks.toml               # cut it down to what you use
paddocks apply --dry-run                      # check the computed layout
paddocks apply

discover buckets every installed .desktop file by its Categories= field — roughly the grouping the application menu already shows — and annotates each id with the application name, so it is a list to delete from rather than one to write:

[[group]]
name = "Graphics"
apps = [
    "org.blender.Blender",   # Blender
    "org.inkscape.Inkscape", # Inkscape
    "org.kde.krita",         # Krita
]

Folder groups

Give a group a path instead of apps and it shows that folder, live — drop a file in and it appears on the desktop, with no paddocks apply in between.

[[group]]
name = "Pictures"
path = "~/Pictures"

A folder group on the desktop: the Pictures folder shown live, with the wallpaper through its translucent background

~ and $VARS are expanded, and a path that does not exist yet is a warning rather than an error, so a folder on a drive you have not mounted fills in when it turns up. A folder's contents change under you, so there is no count to size it from: cells = 12 sets how many icon slots to size the box for, defaulting to 8, and the folder scrolls past that rather than growing.

It is a window onto a folder, not a file browser. Files open in their default application and subfolders open in Dolphin — you cannot drill down inside the widget. Folder View does have in-place navigation, with a back button, but it is reachable only from a panel popup: useListViewMode is isPopup && …, and a widget on the desktop is Floating, so the desktop always takes the other branch and hands the URL to KIO.

A group is one thing or the other — setting both apps and path is an error rather than a guess. Folder groups are Folder View widgets, which is the right widget for files and the wrong one for launchers, for the reasons in gotcha #1.

The editor

paddocks edit does the same job in a window: groups on the left, the selected group's applications in the middle, everything installed on the right.

The editor: groups, group contents, and the installed application list

Drag within either list to reorder, drag a group up or down to change where it lands on screen, double-click an application to add or remove it. Add folder makes a folder group instead — pick a directory and it is stored with ~ intact when it is under your home. Selecting one shows the folder it points at rather than an app list, since Plasma reads its contents live. Preview shows the computed layout without touching anything; Save & Apply writes the config and rebuilds the desktop. An id that no longer resolves is shown in red and kept rather than quietly dropped — the application may only be temporarily uninstalled.

Saving rewrites the file canonically: non-default settings, then the groups in order. Hand-written comments do not survive that. Python has no standard-library TOML writer, and the round-trip libraries that preserve comments are a dependency nothing else here needs.

App ids

Ids do not have to be the exact .desktop filename. The same application is firefox from a distro package, firefox_firefox from a snap and org.mozilla.firefox from a flatpak, so entries are also matched on the reverse-DNS tail, the snap-style suffix and the launcher's Name=. Anything inexact is reported so you can tighten the config, and a miss suggests the nearest ids instead of just failing:

~~ matched by name: Office and Web/firefox -> firefox_firefox
!! not installed: Dev Tools/vscode  (did you mean: code, discord?)

Commands

paddocks discover starter config from installed apps — --desktop-only, --all
paddocks apply build the groups — --dry-run, --strict, --no-strict
paddocks edit the editor window
paddocks status what is currently set up
paddocks remove take the groups away again
paddocks translucency 0.4 widget background opacity, lower is more transparent; reset to undo
paddocks install-desktop menu entry and icon — --remove, --variant dark|light

--strict turns an unresolved launcher into an error that changes nothing — for a settled config, or when driving apply from a script. Put strict = true under [settings] for every run; --no-strict gets past it once. It earns its keep on hand-written .desktop files, which stop resolving the moment their target moves and drop the app quietly out of its group.

install-desktop writes paddocks.desktop into ~/.local/share/applications and the icon into ~/.local/share/icons/hicolor. The entry is generated rather than checked in, because Exec= has to carry the absolute path of wherever you cloned this — move the clone and run it again.

What it does and does not cover

Capability Status
Grouped, titled launcher panels
Click to launch, drag to add
Translucent backgrounds ✅ see caveats
A group showing a folder, live path = "~/Downloads"
Files and launchers mixed in one group ❌ a group is one or the other
Multiple desktop pages ✅ use Plasma Activities (not managed here)
Roll-up / collapse a panel ❌ no equivalent in Plasma
Double-click desktop to hide icons ❌ no equivalent
Auto-sorting rules by file type ❌ groups are declared, not inferred

The five things that cost an afternoon

None of this is documented, and most of it fails without an error message.

1. Folder View looks like the right widget for launchers, and is a dead end

This is about launchers. For real files, Folder View is the right answer and is what folder groups use — every failure below is specific to .desktop files.

The obvious build is a Folder View per group, pointed at a folder of .desktop files. Both available URL schemes fail, in different ways:

  • file:///home/you/Desktop/Apps — renders org.kicad.pcbnew.desktop instead of PCB Editor. The icon resolves correctly, so it reads as a labelling bug rather than a URL problem. Only the desktop:/ KIO worker maps .desktop files to their Name=.
  • desktop:/Apps — labels are correct, and it looks like the answer. But kio_desktop only implements part of the protocol for subpaths: listing works, launching is a silent no-op, and new files are never noticed.

That second one costs a day to trust and then unpick. Verified with kioclient exec:

URL passed to KIO Result
/home/you/Desktop/Apps/kcalc.desktop launches
desktop:/Apps/kcalc.desktop exits 0, launches nothing
same, file made executable exits 0, launches nothing
desktop:/Apps (listing) works fine

Launching only works at the desktop root — any grouping folder breaks it. So the trade is correct labels or working launchers, never both.

Use Quicklaunch instead. org.kde.plasma.quicklaunch stores file:// URLs pointing straight at installed .desktop files, renders them by application name, launches them, and accepts drag-and-drop.

Two non-obvious keys. maxSectionCount sets the icon row count — without it Quicklaunch flows everything into one row and shrinks icons to fit, so icon size varies between groups. And it balances icons across the rows it is given, so six in two rows render 3+3, not 4+2: size the widget to that balanced column count, or it scales the icons up to fill the extra width and every group comes out slightly different.

2. Plasma's scripting API cannot position widgets

desktop.addWidget() works. Positioning it does not:

widget.geometry = Qt.rect(40, 40, 520, 420);   // ReferenceError: Qt is not defined
widget.geometry = {x: 40, y: 40, ...};         // no error, no effect

The object-literal form is the nasty one — it silently does nothing, and reading widget.geometry back reports the auto-placed position, so it looks like Plasma overrode your value rather than ignoring it.

Positions live in ItemGeometries-<W>x<H> under [Containments][<id>] in ~/.config/plasma-org.kde.plasma.desktop-appletsrc, formatted Applet-<id>:x,y,w,h,0;. plasmashell rewrites that file when it exits, so it must be stopped before the write, not after:

kquitapp6 plasmashell
kwriteconfig6 --file plasma-org.kde.plasma.desktop-appletsrc \
  --group Containments --group 1 --key ItemGeometries-3440x1440 "Applet-28:60,50,560,336,0;"
plasmashell &

Also note evaluateScript only reliably returns print() output — a bare trailing expression usually comes back empty.

3. plasma-apply-desktoptheme can be a silent no-op

On distros shipping AutomaticLookAndFeel=true in kdeglobals — Kubuntu among them — the look-and-feel package re-asserts its own desktop theme. The command reports success, plasmarc shows your theme, and Plasma renders something else. The only signal is a cache mtime:

$ ls -la --time-style=+%H:%M:%S ~/.cache/plasma_theme_*.kcache
... 08:38:36 plasma_theme_MyCustomTheme.kcache      # applied here
... 08:40:15 plasma_theme_kubuntu-light.kcache      # still being used

Fix: don't introduce a new theme id at all. Copy the active theme into ~/.local/share/plasma/desktoptheme/ under its original name — the user data dir shadows /usr/share — and patch the copy. Do it for the light and dark variants, or the styling vanishes when the day/night schedule flips.

4. Theme caches are keyed by theme name

Following from the above: keeping the name means the pixmap cache keeps serving the old artwork. Clear it while plasmashell is down.

rm -f ~/.cache/plasma_theme_*.kcache ~/.cache/ksvg-elements
5. widgets/background is the applet frame; translucent/ is dead

There is no opacity setting for widget backgrounds anywhere in Plasma. The frame is a theme SVG, selected in BasicAppletContainer.qml:

if (effectiveBackgroundHints & TranslucentBackground) return "widgets/translucentbackground";
else if (effectiveBackgroundHints & StandardBackground) return "widgets/background";

Desktop widgets take the StandardBackground path. translucent/widgets/background.svgz exists in every theme and is referenced by nothing — patching it, the obvious first guess, changes nothing.

To make the frame transparent, add an opacity attribute to the nine <g> elements center, top, bottom, left, right and the four corners. Ancestor opacity is not applied when Qt renders an SVG by element id, so setting it on the root <svg> does not work either. Leave the shadow-* elements alone so panels still read against a busy wallpaper. Most distro themes are sparse and fall back to default for artwork, so the file to copy and patch is usually /usr/share/plasma/desktoptheme/default/widgets/background.svgz.

Caveats

Tested on one machine. Plasma 6.6.6, Kubuntu 26.04, Wayland, a single 3440×1440 screen. Multi-monitor is unhandled — everything targets screenGeometry(0) and the containment from desktops()[0].

This leans on private API. ItemGeometries and the containment layout internals are not a stable interface. A Plasma point release can change the format; if panels land in the wrong place after an update, check that first.

A group is launchers or a folder, not both. Mixing them in one widget is not something Plasma offers — Quicklaunch holds launcher URLs, Folder View shows a directory. Use two groups.

translucency shadows system themes. While the shadow copies exist, distro updates to those themes stop reaching you. That is why it is a separate command from the groups — skip it if the trade is not worth it.

apply rewrites, it does not merge. It removes the widgets it made last time (tracked in ~/.local/state/paddocks/state.json) and rebuilds from the config. Hand-placed widgets are left alone, but not moved out of the way. Launchers added by dragging live in that widget's config, so apply discards them — add them to the TOML instead.

Every apply backs up your desktop layout first. plasma-org.kde.plasma.desktop-appletsrc holds every panel, widget and wallpaper setting you have, so it is copied into ~/.local/state/paddocks/backups/ before ItemGeometries is touched; the last five are kept. Restoring is a copy back, with plasmashell stopped for the same reason the write needs it:

kquitapp6 plasmashell
cp ~/.local/state/paddocks/backups/plasma-org.kde.plasma.desktop-appletsrc.<stamp> \
   ~/.config/plasma-org.kde.plasma.desktop-appletsrc
plasmashell &

Do not resolve() launcher paths. Flatpak's exports/share/applications is a symlink farm into content-addressed store paths. Following those symlinks bakes a commit hash into the URL, and every flatpak launcher breaks on the next update of that app. Use the export path as-is.

Contributing

Reports from other distros are the most useful thing — particularly whether AutomaticLookAndFeel behaves the same way, and whether the layout constants in paddocks/layout.py hold at other icon sizes and scale factors.

python3 -m unittest discover -s tests -t .

Standard library only, nothing to install. The tests never touch your real config, state file or a running plasmashell — the plasma module is replaced wholesale rather than patched function by function, so a missed attribute cannot take your desktop down. Editor tests skip themselves if PySide6 is absent.

Trademarks

Paddocks is an independent project, not affiliated with, endorsed by, or derived from any commercial desktop-organiser product. Any such products are named only for factual comparison, and remain the trademarks of their respective owners.

License

MIT

About

Grouped desktop launcher panels for KDE Plasma 6, plus the undocumented Plasma behaviour needed to build them

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages