The battery popout already surfaces the UPower energy rate, but the bar
widget could only show percentage and remaining time, so telling how fast
the battery is charging or draining meant opening the popout (or running a
third-party plugin that polls /sys/class/power_supply).
Add two independent, opt-in toggles to the battery widget - "Show Charge
Rate" and "Show Discharge Rate" - that render the signed rate next to the
existing text, e.g. "+28W" while charging and "77% (2h 11m) -19W" while
draining. Both default to off, and follow the established pattern: a global
default in SettingsData plus a per-widget-instance override.
The value comes from BatteryService.changeRate, so there is no extra process
or polling. It hides itself when the rate is below 0.05W (idle, fully
charged, or sitting at a charge limit) so it costs no bar space unless it
has something to say. Precision adapts to keep the pill narrow: one decimal
below 10W, whole watts above; vertical bars get a whole-watt line.
* fix(dock): hide overlay dock over fullscreen
* fix(dock): track fullscreen state declaratively
* fix(dock): clear overlay mask during fullscreen
* feat(dock): add fullscreen visibility option
* fix(dock): preserve auto-hide fullscreen behavior
* fix(dock): keep fullscreen mask interactive in overview
* fix(frame): host dock on overview without show dock
* feat(mpris): pin preferred media source
Add a minimal "pin media source" option so the bar media widget and OSD
keep showing a preferred player (e.g. a music player) even when another
source (e.g. YouTube in the browser) starts playing.
- MprisController: new pinnedIdentity property + setPinned(identity);
_bestPlayingPlayer() prefers a playing pinned player (exact identity
match, then case-insensitive substring fallback). Existing behavior
is unchanged when no pin is set.
- Persistence via SessionData.pinnedPlayerIdentity (spec entry added so
SessionData.set() accepts the key); empty string clears the pin.
- MediaDropdownOverlay (Media Players panel): each player row gets a
theme-colored circle indicator on the right. Empty circle = no pin
(initial state). Right-click a row to make it the default source
(circle fills); right-click another row to move the pin; right-click
the pinned row again to clear (back to empty). Left-click behavior
unchanged (selects the player).
* Update quickshell/Services/MprisController.qml
Concur with Claude's suggestion.
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
* Update quickshell/Services/MprisController.qml
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
---------
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
* feat(theme): add support for matugen smart mode and type
* add another dry run to get smart type preview
* fix too much keywords in search index
* revert dont extract translations
* feat gate "Auto From Wallpaper" toggle row and the available matugen scheme for the pallete drop down
* re-extract settings search index
* make portal sync no longer disables matugen smart mode
* make sure cosmic theme mode also follow change from smart mode
* add translator context for Auto (Light Mode) / Auto (Dark Mode) / Auto From Wallpaper
* fix: gate matugen smart mode checks on the dynamic theme so stock themes keep portal sync and fix tile labels in control center
Adds a user-configurable spacing between system tray icons in the bar,
available per widget via the tray context menu in Settings > Widgets
("Icon Spacing" stepper, 0-20px), with a global default fallback.
- SettingsData/SettingsSpec: new trayIconSpacing setting (default 0)
- SystemTrayBar: apply configuredIconSpacing to the horizontal Row and
vertical Column layouts, and account for it in auto-overflow item
estimation and drag-and-drop slot math (shift offsets and target
index calculation)
- WidgetsTabSection: "Icon Spacing" stepper in the tray widget context
menu, following the existing "Max Visible" pattern
- WidgetsTab: keep trayIconSpacing when restoring per-widget data
* fix(processlist): stop polling when the popout is closed
The popout's content loader deliberately stays warm across close so
re-opening is instant, and PopoutService only defers the actual unload
until session lock or monitors-off. But both DgopService references were
bound to component lifetime rather than presentation, so after closing
the popout refCount stayed above zero: dgop kept sampling the full
process list every 3s until the shell restarted or the session was
locked and unlocked.
Gate both references on shouldBeVisible instead. Ref grows an `active`
property (defaulting to true, so every other call site is unchanged) and
ProcessesView grows an `active` property that hosts keeping it loaded
while hidden can drive. ProcessListModal is unaffected — its tab loaders
already destroy the view when the window hides.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01GTGf29PYTp1kpAv5HNHBzM
* Update quickshell/Modules/ProcessList/ProcessListPopout.qml
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <[email protected]>
Co-authored-by: BB <[email protected]>
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
The idle inhibitor ("Keep Awake") lives only in memory: SessionService holds it
as a plain `property bool idleInhibited: false` and nothing ever writes it out.
Every restart of the shell silently clears it — the user's explicit choice is
dropped with no message and no trace, and the pill just disappears from the bar.
Restarting is not an edge case. `dms restart` is a first-class CLI command, and
the unit shipped in this repo (assets/systemd/dms.service) sets
`Restart=on-failure` with `TimeoutStopSec=10`, so a shell that is slow to stop
is killed and brought back automatically. Each of those paths turns Keep Awake
off without saying so.
Every other Control Center toggle already survives a restart. Measured on
upstream master, over the state read by Modules/ControlCenter/Components/
DragDropGrid.qml and its neighbours:
doNotDisturb in SessionSpec: yes
isLightMode in SessionSpec: yes
nightModeEnabled in SessionSpec: yes
wallpaperCyclingEnabled in SessionSpec: yes
idleInhibited in SessionSpec: NO
So this follows the doNotDisturb idiom exactly rather than inventing a
mechanism: one spec entry, one property, one setter that saves.
Restore happens through two entry points because the singletons are lazily
created and their order is not fixed: `onLoaded` covers "service instantiated
before the session file is read", `Component.onCompleted` covers the opposite.
enableIdleInhibit() is idempotent, so whichever runs second is a no-op.
The default stays false and SessionStore.toJson omits defaults, so an untouched
session.json gains no new key.
Related: #1483 asks for a configurable timer. The field added here is the same
shape doNotDisturb uses with doNotDisturbUntil, so a later `idleInhibitedUntil`
slots in beside it without another migration.
Co-authored-by: Mark2Mac <[email protected]>
* feat(theme): support qtengine as a Qt platform theme
qtengine is a single platform theme plugin serving both Qt5 and Qt6 from one JSON config, so it needs neither the qt5ct/qt6ct split nor qt6ct-kde.
It reads a KDE .colors scheme by path, which the kcolorscheme template already generates, so no new matugen template is required.
DMS now merges theme.colorScheme and theme.iconTheme into $XDG_CONFIG_HOME/qtengine/config.json after each generate, on icon theme changes, and from Apply Qt Colors.
The merge preserves every other key,refuses to touch a config it cannot parse, and only names a color scheme that exists.
The write is atomic, and its mtime bump is what trips qtengine's watcher and repaints running apps.
QT_QPA_PLATFORMTHEME=qtengine is accepted without the missing-env-var toast, Apply Qt Colors no longer fails on a machine without qt5ct or qt6ct, and dms doctor reports whether the plugin is installed where Qt actually searches, per Qt major.
* fix(theme): resolve qtengine config via XDG, tighten doctor probing
---------
Co-authored-by: bbedward <[email protected]>
* feat(dock): attach bar to screen edge
* feat(dock): add bar length padding
* feat(dock): expand bar padding range
* refactor(dock): group bar corner settings
* fix(i18n): avoid attached term variant
* fix(settings): group corner style with goth corners
* fix(dankbar): attach flush bars to the screen edge
---------
Co-authored-by: bbedward <[email protected]>
* feat(settings): persist named location for theme & gamma auto modes
* chore: bump dank-qml-common for location search support
* fix(settings): keep weather location name when search fills coordinates
* style(settings): unify manual coordinates layout with weather
- settings.json/session.json now store only values that differ from
spec defaults
- Machine-specific state moves out of settings.json into session.json
- Add dms backup create/restore: tar.gz of ~/.config/DankMaterialShell
fixes#3027
* feat(theme): add extract current theme to JSON file
Adds an 'Extract' button in Settings > Theme Color that exports the
current theme (generic/dynamic/custom/registry) to a dual-mode dark+light
JSON file via the DMS file save dialog.
* refactor(theme): simplify extract button to single DankButton
* refactor(theme): move extract button inside dynamic theme section
* fix(theme): address review feedback on extract theme save
* refactor: utilize dankActionButton
---------