Docs
Everything beyond install — build, configure, internals, troubleshooting, contributing. Install and FAQ live on the home page.
Build from source
Standard CMake build. Install KDE Frameworks 6 + Qt 6 dev headers first (see Dependencies), then:
git clone https://github.com/xarbit/plasma6-applet-appgrid.git
cd plasma6-applet-appgrid
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
cmake --build build -j$(nproc)
sudo cmake --install build
kquitapp6 plasmashell && kstart plasmashell
Pass -DAPPGRID_UNIVERSAL_BUILD=ON to compile in the opt-in update checker (only used by the universal-tarball CI build). Pass -DAPPGRID_VERSION_OVERRIDE=<ver> to bake an explicit version string into the binary (see Versioning).
Arch users: a PKGBUILD ships at the repo root. Build a proper pacman package with makepkg -sf, install via sudo pacman -U.
Development builds
Every push to main is published to a separate -dev channel — bleeding-edge, rebuilt on every commit. Expect breakage; it’s for testing fixes before they land in a release, not for daily use.
Arch (AUR):
yay -S plasma6-applets-appgrid-git
A -git VCS package — it builds the latest main. Plain yay -Syu won’t detect new commits; rebuild with yay -Syu --devel to pull updates.
Fedora (Copr):
sudo dnf copr enable scujas/plasma-applet-appgrid-dev
sudo dnf install plasma-applet-appgrid
Ubuntu (Launchpad PPA):
sudo add-apt-repository ppa:xarbit/plasma-applet-appgrid-dev
sudo apt install plasma-applet-appgrid
There’s no -dev channel for the universal tarball — build from source for that. To leave the dev channel, remove the -dev repo (or the -git package) and switch to the stable Copr / PPA / AUR.
Dependencies (per distro)
Authoritative dep lists live alongside their packaging spec — keep these in sync with what you actually install.
- Arch: see PKGBUILD (
depends=+makedepends=) - Fedora: see packages/rpm/appgrid.spec.in (
BuildRequires:+Requires:) - Ubuntu: see packages/deb/debian/control (
Build-Depends:+Depends:) - Universal Package runtime: see packages/universal/distros.toml — per-distro runtime packages,
install.pyverifies vialddbefore placing any files
Core runtime: plasma-workspace, libplasma, kservice, ki18n, kio, kpackage, kcoreaddons, kconfig, kwindowsystem, krunner, kirigami, layer-shell-qt, plasma-activities, plasma-activities-stats, qt6-base, qt6-declarative.
CMake build options
Pass with -D<option>=<value> on the cmake -B build invocation.
| Option | Default | Effect |
|---|---|---|
APPGRID_VERSION_OVERRIDE | (empty — derived from git) | Bake an explicit version string into the binary. CI passes this for every release so the binary self-reports the exact release tag (see Versioning). |
APPGRID_UNIVERSAL_BUILD | OFF | Compile in the opt-in update checker. ON only for the universal-tarball CI job; distro packages leave this OFF so the package manager handles updates. |
ENABLE_X11 | ON | Compile X11-specific session support (frameless window flags + manual screen positioning for the Center variant on X11). Turn OFF for Wayland-only builds (Plasma 6.8+). |
BUILD_TESTING | OFF | Build the C++ + QML test suite. See Running the test suite. |
Standard CMake options also apply: CMAKE_BUILD_TYPE (Release / RelWithDebInfo / Debug / None), CMAKE_INSTALL_PREFIX (default /usr/local — set to /usr for system installs), KDE_INSTALL_QTPLUGINDIR (override the Qt plugin install path — the Universal Package CI pins this to lib/qt6/plugins).
Configuration reference
Right-click the AppGrid panel icon → Configure AppGrid. Settings marked (Center only) apply only to the AppGrid Center variant; the Panel variant uses Plasma’s native popup for those.
| Setting | Description | Default |
|---|---|---|
| Icon | Panel icon or custom image | dev.xarbit.appgrid (existing 1.7.x installs keep their prior icon) |
| Text label | Optional text next to the panel icon | (empty) |
| Icons per row (Center) | Columns in the grid | 5 |
| Visible rows (Center) | Rows visible before scrolling | 4 |
| Icon size | Small (32 px), medium (48 px), large (64 px) | Large |
| Sort order | Alphabetical, Most Used, By Category | Most Used |
| Open on active screen | Open on mouse focus screen or panel screen | On |
| Show category bar | Show or hide the category filter bar | On |
| Category tab style | Category bar tabs: Default (text), Icon and text, or Icon only | Default |
| Open categories on hover | Dwell on a category tab to select it without clicking | Off |
| Search all apps | Search across categories regardless of active tab | On |
| Start with favorites | Open showing favorites instead of all apps | Off |
| Show recently used | Recently launched apps row at the top of the grid | On |
| Use system categories | Use KDE Menu Editor categories | Off |
| Hide empty categories | Hide categories with no apps | On |
| KRunner plugins | Search bookmarks, files, websites via KRunner | On |
| Inline completion | Greyed completion of the best match in the search field, accepted with Tab | On |
| Prefer frequently-used apps | Bias ranking with KActivities frecency (frequency + recency) | On |
| Show Alt+1–9 badge | Launch-shortcut badge on each result (shortcuts still work when off) | On |
| Show hidden apps in search | Keep deliberately-hidden apps findable by name | Off |
| Terminal shell | Shell for t: commands | /bin/sh |
| Show divider lines | Dividers between UI sections | On |
| Show scrollbars | Scrollbars in grid and search | Off |
| Show tooltips on hover | App description + install source on hover | On |
| Show new app badge | Green badge on newly installed apps | On |
| Drop shadow behind app icons | Soft drop shadow under each app icon in the grid | On |
| Hide labels on favorites tab | Render the Favorites tab as icons only (no app names) | Off |
| Sort favorites alphabetically | Auto-sort favorites by name instead of manual order | Off |
| Reduce grid spacing (Center) | Narrower cells for a tighter layout (the pre-1.9 width) instead of square cells | Off |
| Apply Size to app icons only | Size changes only the icons; labels, secondary icons and spacing stay at the default | Off |
| Highlight icons on hover | Soft highlight behind an app icon on mouse hover | On |
| Open/close animation (Center) | None, Fade, Scale, Pop, Slide Up/Down, Glide, Buzz, Twist, Slam, Grow Up | Scale |
| Background blur (Center) | Blur behind the launcher | On |
| Background contrast (Center) | Plasma theme-tuned contrast filter behind the launcher | On |
| Use Plasma theme background (Center) | Draw the panel using the active Plasma theme’s dialog SVG (matches the Panel variant) | Off |
| Dim background (Center) | Darken the screen behind the launcher | Off |
| Compact mode (Center) | Hide the grid and category bar until you start typing (Down arrow reveals) | Off |
| Vertical position (Center) | Offset the centered launcher up or down within the free space (−100 % = top, 0 % = centered, +100 % = bottom) | 0 % |
| Icon animation | None, Shake, Grow, Bounce, Spin, Shuffle | Shake |
| Animate icons on open | Play icon animation when launcher opens | On |
| Power & session buttons | Per-button show / hide and drag-reorder for sleep, restart, shutdown, session, lock, logout, switch user | All shown in default order |
| Show button labels | Text labels on power / session buttons | Off |
| Background opacity (Center) | Launcher background opacity | 85 % |
| Corner radius (Center) | Custom corner radius | Off (uses Plasma theme) |
| Check for updates (Universal build only) | Opt-in once-per-day check against the AppGrid release feed | Off |
Favorites storage
AppGrid stores favorites in KDE’s activity-aware favorites backend (KAStatsFavoritesModel, backed by KActivitiesStats from KDE Frameworks). It uses a single stable client id, dev.xarbit.appgrid.favorites.
What that means in practice:
- Favorites are activity-aware and sync via standard KDE sync mechanisms if configured.
- The Center and Panel variants share one favorites list (same client id), and it survives removing and re-adding the widget.
- AppGrid does not share favorites with Kickoff or Kicker — those use their own client id (
org.kde.plasma.favorites). - AppGrid does not override or modify Kickoff / Kicker settings.
Upgrading from an earlier version? See the migration notes.
Plasmoid variants & IDs
AppGrid ships as two plasmoids sharing a common C++ codebase but with separate metadata + applet IDs so they can be installed and configured independently. As of 1.9 each variant is a single compiled .so with its QML interface and metadata compiled in (no loose QML package), so after an update Plasma must be restarted to drop the old .so (see Restart Plasma after updating).
- AppGrid (Center) — applet ID
dev.xarbit.appgrid. Standalone window with its own blur, opacity, corner radius, animations. - AppGrid (Panel) — applet ID
dev.xarbit.appgrid.panel. Native Plasma popup anchored to the panel icon (Kickoff-style).
Both share the same grid, search, categories, quick commands, and favorite storage backend. Settings that don’t make sense for the panel variant (window-level blur, opacity, corner radius, open/close animation, multi-monitor screen selection) are managed by Plasma’s native popup instead and don’t appear in its Configure dialog.
Universal package internals
The Universal Package (appgrid-universal-<version>-<arch>.tar.gz) is built once per release against Fedora 42 (oldest mainstream distro shipping Plasma libs at SONAME 7) and runs on any Plasma 6.4+ system with matching SONAMEs. Install layout:
~/.local/lib/qt6/plugins/plasma/applets/dev.xarbit.appgrid.so+…appgrid.panel.so— the compiled plasmoid plugins. As of 1.9 the QML interface and metadata are compiled into each.so; there is no looseplasmoids/QML directory anymore.~/.local/share/applications/+~/.local/share/icons/— desktop integration~/.local/share/locale/<lang>/LC_MESSAGES/dev.xarbit.appgrid.mo— translations~/.config/plasma-workspace/env/appgrid-user-local.sh— one-off env script that adds~/.local/lib/qt6/plugins/toQT_PLUGIN_PATHat session start (this is why first install needs one log-out / log-in)~/.local/share/appgrid/MANIFEST+VERSION— written byinstall.pyso upgrades + the bundleduninstall.pyknow what to touch
install.py preflight: refuses to run as root, validates $HOME, rejects existing system-wide installs (with the per-distro uninstall command), checks for plasmashell on PATH, runs ldd against the plugin to confirm every required library resolves (prints the per-distro install command for any missing deps), and mandatorily verifies SHA256SUMS over the payload before writing anything. Override --allow-coexist bypasses the system-wide-install refusal at your own risk.
Full guide bundled in every tarball: packages/universal/INSTALL.TXT.
Update checker — technical
The opt-in update checker (universal-tarball builds only — CMake flag APPGRID_UNIVERSAL_BUILD=ON) lives in src/updatechecker.cpp. Distro packages don’t link this in.
- Schedule: 24-hour interval with ±2 h jitter; one check on settings-enable.
- Transport: single
HTTPS GETtohttps://appgrid.xarbit.dev/api/latest.json; TLS 1.2+, generic user-agent (no version), no cookies (cookie jar overridden), proxy-auth disabled, 10 s timeout, 16 KiB response cap. - Rate-limit niceness: rotating
ETagstored locally and sent with each request so the CDN can respond304when nothing changed; the ETag rotates every 7 checks to avoid being usable as a long-term identifier. - State file:
~/.cache/plasmashell/dev.xarbit.appgrid.update-checker.json— last check timestamp, last seen version, current ETag. Written atomically via tmp + rename. - UI behaviour: if a newer version exists, a small indicator appears near the session buttons. Clicking opens the release notes in your browser. Never auto-installs.
- Comparison: semver-aware (pre-release tags rank older than their stable counterpart; build metadata ignored), validated against
VERSION_REbefore comparison so a malformed response can’t poison the UI.
Test coverage: 62 cases in tests/test_updatechecker.cpp (version comparison, URL scheme validation, response-size cap, ETag rotation, state persistence).
Versioning scheme
The binary’s self-reported version (shown in the i: system-info view) is computed at build time by CMakeLists.txt in three priority tiers:
- If
-DAPPGRID_VERSION_OVERRIDE=<ver>was passed, that wins. CI passes this for every release so the binary string matches the tarball filename + release tag exactly. - Otherwise, if
HEADis exactly a release tag, useCMAKE_PROJECT_VERSIONunchanged (e.g."1.9.0"). - Otherwise it’s a local dev build between releases — derive
{BASE}-dev.{N}+self.g{SHA}(whereNis commits since the last tag andSHAis the 7-char short hash). The+self.g…build-metadata suffix flags the binary as hand-built (not a CI artifact). Per semver, build metadata is ignored for ordering — so update behaviour matches the equivalent CI build of the same git state. Useful in bug reports for telling local vs CI binaries apart at a glance.
Translations
Translation files live in po/ as <lang>/dev.xarbit.appgrid.po. To add or update a translation:
- Fork the repo, branch from
main. - For a new language: copy
po/<closest-lang>/dev.xarbit.appgrid.pointo a newpo/<your-lang>/directory; edit themsgstrentries. - For an existing one: edit the
.pofile directly. Mark fuzzy entries with#, fuzzyuntil reviewed. - Open a PR — keep changes scoped to translation files only; CI runs gettext validation.
Strings to translate are extracted from QML i18nd("dev.xarbit.appgrid", …) calls and C++ i18n(…) macros. Don’t add new msgid entries by hand — they’ll be regenerated on the next string-extraction pass and lost.
State file locations
Where AppGrid stores things on disk. Useful when debugging, wiping state, or migrating a setup to a new machine.
- Plasmoid config (icon, grid size, sort mode, animations, all settings from Configuration reference): stored in your containment’s
plasma-org.kde.plasma.desktop-appletsrc(Plasma config dir, usually~/.config/). Per-applet — each AppGrid instance has its own. - Hidden apps list (managed via
h:): also in the per-applet plasmoid config ashiddenApps(StringList of.desktopstorage IDs). - Recent launches: per-applet plasmoid config as
recentApps. Cleared when “Show recently used” is turned off. - Favorites: KDE Frameworks’ KActivitiesStats backend (system-managed, see Favorites storage). One-time migration flag
favoritesPortedToKAstatsin the plasmoid config tracks whether the 1.7.x → 1.8.x port has run. - Update checker cache (universal builds, opt-in only):
~/.cache/plasmashell/dev.xarbit.appgrid.update-checker.json— last check timestamp, last seen version, current ETag. Atomic write via tmp + rename. - Universal install manifest:
~/.local/share/appgrid/MANIFEST+~/.local/share/appgrid/VERSION— written byinstall.py, read byuninstall.pyto remove only what was installed. - Universal env script:
~/.config/plasma-workspace/env/appgrid-user-local.sh— adds~/.local/lib/qt6/plugins/toQT_PLUGIN_PATHat session start.
To wipe everything AppGrid wrote: uninstall (system package or ./uninstall.sh for universal), then delete the cache file + remove the AppGrid widget from your panel (this clears the per-applet config). Favorites in KActivitiesStats can be cleared via System Settings → Activities or by removing every favorite manually from the launcher.
Running the test suite
C++ and QML tests live in tests/. Configure with -DBUILD_TESTING=ON and run via ctest:
cmake -B build -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON
cmake --build build -j$(nproc)
ctest --test-dir build --output-on-failure
Covered:
test_appfiltermodel.cpp— proxy filtering, category / search / favorites filterstest_appmodel_helpers.cpp— model helpers (storage ID normalization, app entry parsing)test_filter.cpp— filter predicates (hidden apps, recents exclusion)test_search_ranking.cpp— relevance tiers + most-used boost (see search ranking FAQ)test_frecency_scoring.cpp— KActivities frecency tiebreak in search rankingtest_sort.cpp— sort modes (alphabetical, most used, by category)test_category_mapping.cpp— built-in category groupingtest_pluginhelpers.cpp— KRunner plugin/favorites helperstest_discoverbackends.cpp— “Manage in Discover” backend resolutiontest_updatechecker.cpp— version comparison, URL scheme validation, response-size cap, ETag rotation, state persistence (62 cases)qml/— QML behaviour tests via QtQuickTest
Open a PR with new tests when you fix a bug — CI runs ctest on every push.
Help & troubleshooting
Restart Plasma after updating
AppGrid’s QML is compiled into its .so, so a running plasmashell keeps the old version loaded until it restarts. After updating (any install method), log out and back in, or run:
kquitapp6 plasmashell && kstart plasmashell
Upgrading from AppGrid 1.7.x
1.8.0 migrates favorites to KDE’s activity-aware backend (KAStatsFavoritesModel — see Favorites storage). On first launch, AppGrid reads your existing legacy favoriteApps list and ports those entries into the new backend. The legacy list is kept as a backup so the migration is non-destructive — the flag favoritesPortedToKAstats in the plasmoid config tracks whether it has run.
If favorites look wrong after upgrading (missing entries, empty, ordering off): type i: in the search bar to open the system-info view. It shows the current migration status — KAStats entry count plus the legacy backup count — and a Re-run migration button. Clicking it clears the migration flag; on next open AppGrid recomputes the favorites list as the union of the legacy backup and current KAStats entries. Nothing is lost — missing legacy items are re-added.
If the entry counts in the i: view themselves look wrong, restart plasmashell to force a fresh model load: kquitapp6 plasmashell && kstart plasmashell.
Switching from a distro package to the Universal Package
Plasma can’t reliably load two copies of the same applet ID — uninstall the system package first, then run the universal installer. The bundled install.py detects the conflict and prints the matching uninstall command for your distro before doing anything.
- Arch:
sudo pacman -R plasma6-applets-appgrid - Fedora:
sudo dnf remove plasma-applet-appgrid - Debian / Ubuntu:
sudo apt remove plasma-applet-appgrid - openSUSE:
sudo zypper remove plasma6-applet-appgrid - Gentoo:
sudo emerge -C kde-misc/plasma6-applet-appgrid
Override with ./install.sh --allow-coexist at your own risk — Plasma will still load whichever plasmoid wins discovery on next session start, usually the system one.
Switching from the Universal Package back to a distro package
Run the bundled ./uninstall.sh from the tarball directory first — it reads ~/.local/share/appgrid/MANIFEST and removes only the files it placed. Then install the distro package the normal way. The ~/.config/plasma-workspace/env/appgrid-user-local.sh env script is removed too, so you do need one log-out / log-in after the swap.
AppGrid doesn’t show up after installing
- Restart plasmashell:
kquitapp6 plasmashell && kstart plasmashell - For the Universal Package specifically: log out + back in once on first install (Plasma needs to re-read its session env to pick up the new
QT_PLUGIN_PATH). - Right-click your panel launcher → Show Alternatives — AppGrid should appear in the list.
- If it’s still missing: check the installer’s
lddprobe output for unresolved libraries (Universal Package), orjournalctl --user -b | grep -i plasmafor load errors.
Getting logs & debugging
AppGrid logs through Qt’s normal channels — there’s no separate log file. All messages surface in plasmashell’s journal. Every message AppGrid emits is prefixed with AppGrid: so it’s easy to filter.
Tail the plasmashell journal live:
journalctl --user -f -t plasmashell
Filter to AppGrid messages only:
journalctl --user -b -t plasmashell | grep AppGrid
Plugin loading problems (plasmoid doesn’t appear, “Couldn’t find plugin” errors): restart plasmashell with verbose Qt plugin logging attached to a terminal — this prints every plugin directory Qt scans and why each candidate is loaded or rejected.
kquitapp6 plasmashell
QT_DEBUG_PLUGINS=1 plasmashell --replace 2>&1 | tee plasmashell.log
For QML import errors specifically, add QML_IMPORT_TRACE=1 too. Both env vars are extremely noisy — only use for one-off debugging sessions.
Universal installer / uninstaller debugging: install.py and uninstall.py print every step to stdout; pass --dry-run to install.py to see what it would do without writing anything. Errors exit with non-zero status — pipe to a file with ./install.sh 2>&1 | tee install.log.
Update checker: inspect the cache file directly to see what the last check stored: cat ~/.cache/plasmashell/dev.xarbit.appgrid.update-checker.json. Force an immediate check by toggling the setting off and on (Configure AppGrid → Check the AppGrid website for new releases).
Iterating on the UI: because the QML is compiled into the .so, plasmoidviewer -a dev.xarbit.appgrid can’t load it from a loose package. Rebuild and restart plasmashell instead (cmake --build build && sudo cmake --install build && kquitapp6 plasmashell && kstart plasmashell). The QtQuickTest suite (see Running the test suite) is the fastest way to exercise QML logic without a full session.
Reporting a bug
Type i: in the search bar to open the system-info view, then click Copy — you’ll get a paste-ready report with your AppGrid version, install type (distro vs universal), Plasma version, Qt version, KF6 version, distro, and architecture. Attach it to the issue.
Real-time chat (Matrix)
Quick questions, install help, or “did anyone else hit this?” — easier in chat than an issue. AppGrid has a public Matrix space on matrix.org:
- Space:
#appgrid-plasma:matrix.org— joining the space adds you to both public rooms below. - #appgrid-general — help, install issues, feature ideas.
- #appgrid-random — off-topic, KDE setups, screenshots.
- #appgrid-development — invite-only; open a PR or active issue first, then ping in #appgrid-general for access.
Don’t have a Matrix account? Sign up free at element.io (web/desktop/mobile) or any homeserver — federation means you can join from anywhere.