Skip to content

feat(shell): wallpaper grid picker (Plasma-style)#5

Merged
manuacl merged 4 commits into
mainfrom
feat/wallpaper-grid-picker
May 26, 2026
Merged

feat(shell): wallpaper grid picker (Plasma-style)#5
manuacl merged 4 commits into
mainfrom
feat/wallpaper-grid-picker

Conversation

@manuacl

@manuacl manuacl commented May 26, 2026

Copy link
Copy Markdown
Owner

Summary

Addresses the UX feedback after PR #4: "on n'a plus d'aperçu des images, idéalement avec le bouton Pick image j'aurais aimé retrouver la vue qu'on a dans les réglages KDE".

Replaces the spartan QtQuick FileDialog with a Plasma System Settings-style grid:

  • New core class `WallpaperLibrary` (QAbstractListModel) scans `/usr/share/wallpapers/` and `~/.local/share/wallpapers/` for both package wallpapers (`/contents/images/*.`) and flat image files.
  • Same-name entries across paths deduplicated first-wins so user overrides shadow system packages.
  • New `WallpaperPicker.qml` (Kirigami.Dialog with GridView) bound to the model via a `wallpaperLibrary` context property. Each thumbnail is a clickable ItemDelegate, click emits `wallpaperPicked(url)` and closes the dialog.
  • `customFooterActions: ["Browse…"]` adds the FileDialog fallback for arbitrary files (same DontUseNativeDialog portal bypass as before).
  • Main.qml's header action renamed from "Pick image…" to "Choose wallpaper…"; opens the picker instead of the dialog directly.

`WallpaperLibrary` stays in src/core/ — QtCore + KConfig only, no GUI/Kirigami/DBus/KAuth. The layering guard still passes.

Test plan

  • CI "Build and test (Fedora 42 / Qt6 / KF6)" passes — 7/7 test suites (6 new tst_WallpaperLibrary assertions covering empty paths, package detection, flat-file fallback, role names, dedup, reload)
  • CI "REUSE compliance" passes
  • Flatpak SDK build (`./dev/build.sh -- --build-only`) finishes the bundle
  • Manual launch: "Choose wallpaper…" opens a grid with thumbnails of the runtime's bundled KDE wallpapers + any user wallpapers under ~/.local/share/wallpapers/. Click one → window.pickedImage updates → Apply flow works end-to-end
  • Manual launch: "Browse…" inside the picker still opens a FileDialog for arbitrary paths

manuacl and others added 4 commits May 26, 2026 12:03
Replaces the bare FileDialog from PR #4 with a Plasma System
Settings-style grid: thumbnails of every wallpaper found in
/usr/share/wallpapers/ and ~/.local/share/wallpapers/, plus a
"Browse…" fallback for arbitrary files. This is what the user
flagged after PR #4: bypassing the XDG portal lost the Plasma file
picker's thumbnail preview, leaving Qt's spartan QML dialog.

Core addition: WallpaperLibrary, a QAbstractListModel that scans
the search paths in a single pass and handles two layout
conventions:

  - Package wallpapers — <root>/<name>/contents/images/*.<ext>, the
    convention KPackage and /usr/share/wallpapers ship. Picks the
    alphabetically-first image inside contents/images/ for both
    thumbnail and apply target (Plasma's image renderer consumes any
    single resolution from a package).

  - Flat image files dropped directly under <root>, useful for the
    user's quick-drop spot at ~/.local/share/wallpapers/.

Same-name entries across multiple search paths are deduplicated
first-wins, so a user override at ~/.local/share/wallpapers/<Name>
shadows the same-name system package.

QML: WallpaperPicker.qml is a Kirigami.Dialog with a GridView bound
to the new wallpaperLibrary context property. Each tile is a
clickable ItemDelegate that emits wallpaperPicked(url) on click and
closes the dialog. customFooterActions adds the "Browse…" action,
which opens an embedded FileDialog (same DontUseNativeDialog flag
as before for the same portal-bypass reason).

Main.qml: the page header "Pick image…" action becomes "Choose
wallpaper…" and opens the new picker instead of the FileDialog
directly. The wallpaperPicked signal sets window.pickedImage, so the
rest of the apply flow is unchanged.

WallpaperLibrary stays in src/core/ — QtCore-only, no GUI/Kirigami
deps, no plasma-isolation breach. 6 new tst_WallpaperLibrary
assertions cover empty paths, package detection, flat-file fallback,
role-name strings (must match QML required-property names), dedup
across paths, and reload() picking up filesystem changes.

7/7 test suites pass (DesktopSurface, LockscreenSurface,
LoginSurface, SyncEngine, WallpaperLibrary, PlasmaReloader,
appstreamtest).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The picker came up empty on a real machine because neither pattern
the initial implementation supported matched what the user actually
has on disk:

  - ~/.local/share/wallpapers/Personal/{sunset.jpg, forest.png, …}
    is just a folder of flat images, not a KPackage structure with
    contents/images/. The package-detection pass returned nothing,
    and the flat-files pass only looked at the search root itself.

  - /usr/share/wallpapers/ is shipped on the Bazzite host (Altai,
    Autumn, BytheWater, …) but the org.kde.Platform//6.10 Flatpak
    runtime does not bundle them at the same path inside the
    sandbox — surprisingly enough — so the system-defaults default
    search path resolved to /run/build/... nothing.

Two fixes:

1. WallpaperLibrary gains a third scan pattern: for each subdir that
   isn't already classified as a package (no contents/images/), list
   its top-level image files and add each as its own entry. The
   subdir name itself doesn't surface — the user picks an image, not
   a folder. New tst_WallpaperLibrary case
   picksFlatImagesInsideOneLevelSubdir locks in the behavior.

2. Manifest grants --filesystem=/usr/share/wallpapers:ro so the
   sandbox can see the host's system wallpapers. Read-only — the
   sandbox-review checklist for Flathub (v3 evolution) considers
   read access to a system config dir routine.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ifact

Three follow-ups to PR #5 round 1:

1. System wallpapers were missing from the grid because Flatpak
   silently rejects --filesystem=/usr/share/wallpapers ("Path /usr
   is reserved"). The supported route is --filesystem=host:ro and
   reading through /run/host/. Manifest now grants host:ro and
   WallpaperLibrary's default search paths include
   /run/host/usr/share/wallpapers (non-existent on a native install,
   skipped silently).

2. Desktop apply only hit the first containment, so on dual-monitor
   setups the wallpaper synced on one screen but not the other.
   findAllDesktopContainmentIds() now returns every containment
   whose Wallpaper/org.kde.image/General subgroup carries an Image
   entry, and apply() writes to all of them — that's literally what
   "sync" should do here. New tst_DesktopSurface case
   applyWritesToEveryDesktopContainment locks the behavior in, with
   a sample-desktop-appletsrc-multi fixture that mirrors a real
   two-screen install.

3. Ultra-wide / panoramic wallpapers (the user's uwp5030806.png is
   5K-class) overflowed the tile bounds in the picker grid because
   ItemDelegate doesn't clip its contents by default. clip: true on
   the delegate root closes that off without touching the layout.

7/7 test suites still pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Kirigami.Dialog renders as a fixed-size modal panel inside the
parent window — it's designed for short-form prompts (confirm /
cancel), not for long-form content like a wallpaper grid. The user
flagged the inability to resize the picker, which has more entries
than the default size shows.

QtQuick.Window with transientParent: applicationWindow() and
modality: Qt.WindowModal gives a real top-level window the user can
resize freely via the OS-native decoration handle, while keeping
focus tied to the main app window — the WM treats it as a modal of
the parent rather than a peer.

Footer buttons replace customFooterActions: a plain RowLayout with a
spacer + Browse / Cancel buttons, since Window has no built-in
standardButtons API. Same FileDialog inside, same wallpaperPicked
signal contract, so Main.qml only needed s/wallpaperPicker.open/
.show/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@manuacl manuacl merged commit 828209d into main May 26, 2026
2 checks passed
@manuacl manuacl deleted the feat/wallpaper-grid-picker branch May 26, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant