Replace KDE blue (#3DAEE9) with a glacial teal (#2EB8A8) accent.
Neutral surfaces and semantic status colors unchanged from Breeze.
Both dark and light variants install to ${KDE_INSTALL_DATADIR}/color-schemes.
interactive starts false at atYBeginning so HomeScreenState can
own the swipe-up gesture that opens the drawer on phones. No such
gesture exists in convergence mode, leaving the grid permanently
non-interactive. Short-circuit the condition when convergence
mode is active.
In mobile mode the status bar goes transparent when on the
homescreen so the wallpaper shows through. That is correct for
phone UX. In convergence/desktop mode it clashes with the always-
opaque dark dock: the top area looks light while the bottom is
dark. Return transparentBackground=false when convergence mode
is enabled so the panel stays consistently opaque.
Remove hardcoded Complementary override and white color literals
from AppDrawerHeader. In mobile mode the Plasma containment
framework already provides Complementary context; in convergence
mode the drawerOverlay Window starts a fresh Window context.
Both cases now propagate correctly without an explicit override.
Also set Kirigami.Theme.Window on the convergence dock
FavouritesBar so icon labels and hover highlights follow the
active system palette instead of the wallpaper context.
input-gaming is a full-color Breeze icon with hard-coded gradients;
it cannot be made monochrome by a delegate-level mask. Switch to
input-gamepad, which uses fill:currentColor and matches the line-art
style of every other quick-settings tile icon.
Drop the empty loadFlatpakGames() stub — desktop .desktop files
with the Game category are already covered by loadDesktopGames().
Remove InstalledRole: the field was always true and nothing in QML
consumed it.
gamepadAt() is an internal helper; drop Q_INVOKABLE so it isn't
part of the public QML surface.
A mapped LayerShell surface prevents KWin from using DRM direct
scanout for fullscreen windows. Setting showing=false fades out
the HUD then sets visible=false, unmapping the Wayland surface
and allowing KWin to bypass the compositor render loop entirely
for the game frame.
The HUD reappears when the game exits or is minimised. Error
toasts still work because a failed launch never produces a
fullscreen window, so showingWindow remains false.
Connect to gameLaunched and gameLaunchFailed signals. Launch
toasts dismiss after 3 s; error toasts after 5 s with a red
background. The window grows downward from the HUD pill to
accommodate the toast pill.
When recentGamesChanged fires, the most recently played game
is stored in quickResumeGame. While set, the HUD pill widens
leftward to show the game name and a play button that calls
launchByStorageId directly — no need to open Game Center.
Star badge on pinned tiles (passive Kirigami.Icon, no event
handlers to avoid pointer-feedback loops). Pin/Unpin action
and per-game FPS cap + overlay rows added to the details dialog.
Per-game FPS and overlay rows use ButtonGroup with a Global
option that deletes the per-game key and falls back to the
global quick-settings value.
Remove isCurrent from info button visibility; add Menu and I
key handlers on the grid for keyboard/gamepad access to details.
Inject MangoHud when launching desktop and command-line games.
MANGOHUD_CONFIG is built per-launch via a QProcess instance so
env vars are isolated to each child process — qputenv is not used.
Global overlay toggle and FPS cap (Off/30/40/60) are stored as
properties on GameLauncherProvider and reflected in the quick
settings panel. Per-game overrides stored in plasmamobilerc under
[GamingPerGame/<storageId>] take precedence over the globals at
launch time.
Games can be pinned to the top of the grid. The pinned set is
persisted in plasmamobilerc [GamingPinned] and restored on start.
applyFilter() uses stable_sort so pinned games float to the top
while alphabetical order is preserved within each group.
Read the Waydroid allowlist from plasmamobilerc and treat matching
Waydroid launchers as their own source in the gaming shell.
Surface that source in Game Center so Android titles get their own tab,
source chip, and empty-state guidance.
Record recent launches only after the launcher reports success instead of
optimistically on every attempt. For desktop entries, wait for the
ApplicationLauncherJob result; for detached commands, use startDetached's
return value and show an inline error when startup fails.
Parse Steam libraryfolders and app manifests as KeyValues instead of
matching individual lines. This makes Steam discovery less brittle when
the files contain comments, nested blocks, or different formatting.
Keep Continue Playing visible alongside Running and show a temporary
launching state so the overlay does not pretend a task already exists.
Rename the GameMode status text to say what the shell actually knows.
Use SDL button labels so shell prompts match the connected
controller instead of always using Xbox-style wording. Expose
trigger rumble, touchpad count, gyro, and accelerometer support
through the gamepad wrapper and surface the relevant capability
labels in the overlay.
Enable background gamepad events and add short rumble feedback
for major shell actions such as opening quick settings, opening
the exit prompt, and launching a game.
Expose missing gaming controls directly in the panel so they
remain reachable in convergence mode. Add toggles for DND,
Launch Hint, Night Color, and Perf Overlay with gamepad focus
order updates.
Restyle brightness and volume sliders with rounded Plasma-themed
tracks and handles to remove harsh bar visuals while keeping
existing behavior unchanged.
Add PowerProfileControl and GameModeControl singletons and wire
them into gaming mode lifecycle handling. When gaming mode turns
on, keep DND on, switch to the performance profile when available,
and request GameMode. Restore previous state when gaming mode
turns off.
Add an overlayEnabled property in GameLauncherProvider so the
launcher can toggle MangoHud environment variables from QML.
Slide-out panel with brightness, volume, Wi-Fi, Bluetooth,
and airplane mode. Fully gamepad-navigable; D-pad and stick
input routed to the panel while open. System status bar
(clock, battery, connectivity) added to game center header.
Lutris games discovered from ~/.local/share/lutris/pga.db,
Heroic from ~/.config/heroic/store_cache/ JSON files.
Deduplication extended to cover all launcher sources.
Desktop entries launched via KIO::ApplicationLauncherJob to
expand Exec field codes. Generic commands parsed with
KShell::splitArgs. SQLite uses RAII cleanup guard.
Clamped SDL axis, rumble, and LED values. Renamed rumble
params from frequency to intensity. GamepadManager uses
singleton factory. setPlayerIndex checks SDL return.
FavouritesBar popup uses screen virtualX/Y for multi-monitor.
Show a PlaceholderMessage in the grid when no games are found,
with context-aware text for empty library vs no search results.
Map gamepad A to activate and X to close in RunningGamesView.
Update the legend bar to show X: Close when running tasks are
visible.
Both launch() and launchByStorageId() duplicated the process
spawn, signal emission, and timestamp bookkeeping. Move it to
a single private launchEntry(GameEntry&) method.
LB/RB cycle through source filter tabs (All/Steam/Desktop).
Start toggles focus between the search field and the grid.
Right stick Y-axis smoothly scrolls the grid at 60 Hz with
speed proportional to deflection. Update the gamepad legend
to show the new bindings.
When a game appears as both a Steam manifest and an XDG
desktop entry, drop the desktop duplicate. Steam entries are
preferred because they carry cover artwork and route through
the Steam launcher for Proton compatibility.
Expose SDL_GamepadAxis as an Axis enum in GamepadManager so
QML can identify axis events by name.
Convert left-stick deflection into repeated grid navigation
events with a 150ms interval and 0.4 deadzone. First movement
fires immediately when the stick crosses the threshold.
Wrap game launches in a brief fade-to-black curtain (250ms)
before dismissing the overlay, giving visual feedback that the
launch is in progress.
The cover art tile used layer.effect with a plain Item instead
of a ShaderEffect, which broke the overlay rendering. Replace
with a clipped Rectangle wrapper.
Remove Behavior on color from the grid delegate background —
GridView currentIndex changes on hover caused the highlight
color to flash visibly between cells.
Fix dangling taskList reference in the gamepad ButtonA and
DPadDown handlers (taskList lives inside RunningGamesView).
Auto-reopen Game Center when the last window closes in gaming
mode so the user is never stranded on a bare wallpaper.
Grid tiles now show Steam library artwork when available,
falling back to icon+label for games without cover art.
Cell proportions adjusted to 2:3 for portrait covers.
Search bar filters the library by name. Source tabs filter
by All/Steam/Desktop. Both properties live in C++ so QML
just binds filterString and sourceFilter.
"Continue Playing" row shows the last 5 launched games
with artwork, persisted across sessions via plasmamobilerc.
Remove orphaned GameTile.qml (replaced by inline delegate).
SDL3-backed gamepad manager polls at 60Hz, handles hotplug,
exposes battery/rumble/LED per device. Game launcher aggregates
XDG desktop entries, Steam appmanifests, and Flatpak into a
single sorted model.
Game Center uses the new model instead of folio's search model.
D-pad/A/B/Y navigate and launch. Guide button toggles the
overlay. Battery and controller status shown in the HUD.
Strut windows committed zero height to layer-shell during
early init, causing a protocol error and session exit. Wrap
height and exclusionZone in Math.max(1, ...) for top bar
and dock.
Persisted gamingModeEnabled=true with hardcoded
gameCenterOpen=false hid panels with no overlay visible.
Initialize gameCenterOpen from the stored setting.
Fix HUD visibility regression from an emergency visible:true
override. Various null-guard and positioning fixes from
static analysis across the gaming shell QML.
LayerShell windows with non-spanning anchors (AnchorTop|AnchorRight)
crash the compositor when made invisible because Qt briefly resizes
the surface to 0 before unmapping it. Wrap GamingHUD in a Loader so
the window is destroyed rather than hidden.
Replace the generic 'Yes / Cancel' exit dialog with 'Keep Playing /
Leave' in both the Game Center header and the QS tile, matching the
mental model of a couch user.
The 'Launch Hint' QS tile is now hidden (available: false) when
gaming mode is off so it does not clutter the regular action drawer.
Full-screen layer-shell overlay containing a game library grid
(XDG Game category, filtered via ApplicationListSearchModel) and
a panel of running tasks built on TaskManager.TasksModel.
Keyboard-navigable with directional focus between the running
tasks row and the game grid. A persistent HUD button lets the
user return after launching a game. Exiting gaming mode requires
an explicit confirmation dialog.
The overlay is a Window with LayerShell.LayerTop so it sits above
running application windows without covering system notifications.
Hide the navigation panel, status bar, and app drawer while
gamingModeEnabled is active. The KWin convergent-windows script
skips its window policy so game windows are not forcibly tiled
or maximized.
The Home button in gaming mode re-opens the Game Center overlay
rather than the app drawer. A configurable hint nudges the user
toward the HUD button after launching a game.
Add a gamingModeEnabled bool and a gamingDismissHintEnabled bool to
the shell settings plugin, persisted in plasmamobilerc [General],
following the same pattern as convergenceModeEnabled.
Two new quick settings tiles:
- org.kde.plasma.quicksetting.gaming: toggles gaming mode on/off,
shows explicit on/off label matching the convergence tile style.
- org.kde.plasma.quicksetting.gaminghint: shown while gaming mode
is active; dismisses the Game Center hint.
Both tiles are added to the default group in quicksettings config.
Make the convergence dock fully usable from the keyboard.
Tab now reaches Home, favorites, running tasks, and Overview.
Left and right move across section boundaries, and Enter/Space
triggers the same actions as mouse clicks.
Also add accessible role/name/press actions for these controls
so screen readers expose meaningful button semantics.
The popup snapped to visible/hidden instantly while every other
surface in the shell uses animated transitions. Add an opacity
fade over shortDuration so it matches the rest of the motion
language. State cleanup waits for the fade-out to finish.
The dock background was a hardcoded dark fill because upstream
icon labels are white (for floating over wallpaper). Switching
to Theme.backgroundColor alone just made labels vanish on light
themes, so it kept getting reverted.
Fix the whole stack at once: background uses the Window color
set, hover highlights derive from Theme.textColor instead of
white, and delegate labels switch to Theme.textColor in
convergence mode (still white over wallpaper on mobile).
Use QByteArray::data() instead of constData() for the
udev_device_set_sysattr_value call — Alpine libudev declares the
value parameter as char*, not const char*. Fix the SPDX license
identifier in CategoryPanel.qml from "EUPL 1.2" to "EUPL-1.2".
Clamp FavouritesBar window indicator dots to at least 1 so a
running task with an empty WinIdList still shows a dot. Add
Accessible.onPressAction to CategoryPanel tiles. Remove dead
convergence-mode property bindings from NavigationPanelComponent
since it is hidden in that mode. Use HTML video tags for .webm
files in README so they render as playable video.
Use Kirigami.Theme.textColor for the status bar hover overlay
so it works on both light and dark themes instead of hardcoded
white. Remove convergence-mode branches from the navigation
panel left action since it is hidden in convergence mode and
the code paths were unreachable.
Remove duplicate KService include in favouritesmodel.cpp. Add
keyboard navigation and accessibility role to CategoryPanel
tiles. Clamp the FavouritesBar thumbnail popup position to
screen bounds so it does not overflow offscreen on edge items.
The input region Y was computed from the bottom of the screen
instead of from the top, causing the touch region to be offset
from the actual popup. Use openOffset directly since the popup
anchors to the top. Unify the popup margin into a single
property so the delegate x and the input-region regionX stay
consistent.
Check restrictedPermissions before opening the detail popup in
convergence mode. Guard against null output in the KWin script
window-setup handler to prevent TypeError when a window has no
assigned output yet.
loadPackage + setPath can produce an invalid package if the shell
package is missing. Guard with isValid() to avoid passing a bad
package to setKPackage. Add the QML_SINGLETON factory that the
QML engine requires for proper singleton instantiation.
navigationPanelThickness is explicitly 0 in convergence mode, so using
it as the layer-shell surface height triggered a Wayland protocol error
and crashed the shell. Use gridUnit * 3 directly, matching the dock bar
height set on FavouritesBar.
The two const char* variables were pointing into QByteArray
temporaries that were destroyed at the end of each declaration
statement. By the time they were passed to udev, the memory was
freed. Hold the QByteArrays in named locals so the data stays
alive for the duration of the function.
udev_device_new_from_syspath returns NULL if the syspath is
invalid or the device disappears between enumeration and the
privileged call. Add an early-return guard so the subsequent
udev_device_set_sysattr_value call is never reached with a null
device pointer.
Also drop the unnecessary const_cast: udev_device_set_sysattr_value
takes const char*, not char*.
CHANGELOG.md held a project overview, not versioned entries.
Also fix a typo in the screenshot filename (tilling → tiling)
and the matching README reference.