Modified copies of DMS built-in widgets. The code is copied from DankMaterialShell's default widgets with specific customizations applied.
Last synced: 2026-09-19
Base commit: b5415caa (bar: stop hidden pills from catching clicks (#3488)) — upstream/master tip
Repository: https://github.com/AvengeMedia/DankMaterialShell
Local clone lives at
~/code/_forks/DankMaterialShell(branchfeature/ddc-controls, HEAD48402bba=upstream/master+ fork DDC commits;upstream/masterverified as an ancestor). The running build is current:dms runresolves through~/.local/bin/dmsto adms-shell-1.7-beta+date=2026-09-19_dirtystore path built from that HEAD, andgit diff upstream/master HEAD -- quickshell/Modules/DankBar/Widgets/ quickshell/Modules/Plugins/is empty, so every file we fork is byte-identical toupstream/master(verified this sync).dms-debug-srv.serviceruns its owndms-shell-1.7-beta+date=2026-09-19_b5415castore path. The Nix profile (/etc/profiles/per-user/srb/bin/dms) still ships only the Go CLI —~/.local/binhas to stay ahead of the profile onPATH.
93 upstream commits. One of them — the 8e9cd3f4 squash — rewrote the whole bar widget
layer, so this sync is much larger than usual: BasePill became a one-line alias for the new
qs.Modules.SurfaceWidgets.BarPill, per-compositor logic moved into CompositorService +
Common/WorkspaceModel.js, tray and running-apps menus moved onto DankPopout /
DankContextMenu, and config version 18 moved 17 global settings into per-widget options.
First, a breakage fix. Config v18 migration deletes the old globals from settings.json,
so four widgets were silently reading undefined: CustomWorkspaceSwitcher lost its app icons
(showWorkspaceApps falsy, maxWorkspaceIcons undefined makes slice(0, undefined) return [])
plus drag reorder, the focused border, and a NaN appIconSize via
-6 + workspaceAppIconSizeOffset; CustomRunningApps lost compact mode; CustomMedia's scroll
handling went dead; CustomFocusedApp lost compact mode. Everything now goes through
SettingsData.widgetOption(<widgetType>, widgetData, key). The user's migrated values are
unrecoverable, and DMS defaults turn the workspace app icons off, so CustomWorkspaceSwitcher
carries an optionDefaults map (showWorkspaceApps, showWorkspaceIndex,
showWorkspacePadding all true) consulted by its opt() helper.
- CustomNetworkMonitor —
Ref-basedDgopServicerefcount (released when the widget or its window is hidden, instead of held for the shell's lifetime),contentThickness,contentColor. - CustomFocusedApp (672 → 529 lines) —
resolveSortedWindow,resolveActiveWindowPid,isWindowAlive,getNiriFocusedWindowand the per-compositor bodies ofupdateActiveWindow/hasWindowsOnCurrentWorkspaceall collapse intoCompositorService.activeWindowForScreen,windowPidandwindowOnActiveWorkspace, which also brings Aqueous support (b9365610).minTooltipYandisAutoHideBarnow come fromBasePill. - CustomMedia —
surfaceContext/contentScale,BarMetrics.mediaControlSizesizing, upstream'sPlayButton(DankIconButton, filled + checkable),StateLayerprev/next,surfaceLivegating on the visualiser and the scrolling title. The inlinesetTriggerPositioncalls stay: upstream could drop them becauseSurfaceWidgetFactorypositions the dash popout in its ownonClicked, which plugin widgets never reach. - CustomSystemTrayBar — taken wholesale from
upstream/masterand re-customised, since65fb97d2(menus →DankPopout, -837/+440) and the squash'sBarPillSurface/TrayItemIcondelegates left no common structure. Also picks up1bf35426and2bf2754a, and upstream fixes the fork never had: theDismissZoneoverflow mask, the window-localmapToItempopup placement fix for non-primary monitors,WlrLayershell.Overlay,StyledTextinstead of a rawText, and popup drag reordering. Auto-overflow / "Keep in Bar" is kept out by pinninguseAutomaticOverflow: falserather than by surgery — that emptiesautoOverflowBarItemsand makesisAutoOverflowTrayItem()always false, so every branch that would introduce it is dead while the file stays diff-friendly. - CustomRunningApps (2074 → 1862 lines) — patched rather than taken wholesale, because
upstream's 1600 → 545 rewrite drops the dynamic title width, the per-state colour system and
the full-height pills this fork exists for. Ported: the 230-line hand-rolled
PanelWindowcontext menu →DankContextMenupositioned throughBasePill.contextMenuAnchor(), witha3a9fe13's scratchpad entries;windowModelKeyper compositor (the fork keyed ungrouped windows by"address", which only Hyprland sets, so on niri every row shared an undefined key);skipSwitcherfiltering in scroll switching. - CustomWorkspaceSwitcher (2222 → 1572 lines) — data layer moved onto
CompositorService.currentWorkspaceKey/workspacesForScreen/isCurrentWorkspace/workspaceOccupied/workspaceUrgent/windowsOnWorkspace/switchToWorkspace/stepWorkspace/workspaceSecondaryAction/focusWindow. Ext-workspace data now comes fromQuickshell.WindowManagerscreen projections. BringsworkspacePaddingCount(e5d8d031), special-workspace hyprland slot keys (72326ec5), special workspaces with theinboxicon (a3a9fe13) and Aqueous (b9365610).
Not applicable: f6c53993 (selectedContainer instead of primaryContainer in
RunningApps) — our focused/unfocused colours come from the PluginService colour modes.
014c69b0 (workspace tile colour restyle) — same reason.
PluginService.pluginDataChangedonly ever carried the plugin id, but all four plugins declaredonPluginDataChanged(pluginId, key)and branched onkey. No plugin setting has ever applied without adms restart. All four handlers now match on the id and reload every value.Theme.onSecondaryhas not existed for some time; the five no-icon first-letter fallbacks across CustomFocusedApp, CustomRunningApps and CustomWorkspaceSwitcher now useTheme.widgetTextColor, like upstream.- CustomMedia's
SettingsData.audioScrollEnabledfallback was already dead at the previous base, soscrollModeresolved to"nothing"regardless. - CustomWorkspaceSwitcher's
paddingmirroredBarPill's old formula (default 12, plusremoveWidgetPadding).BarPillnow defaults to 8 and has droppedremoveWidgetPadding.
Exactly one of the 37 upstream commits touched our six widgets. No changes to CustomFocusedApp,
CustomMedia, CustomNetworkMonitor, CustomRunningApps, CustomSystemTrayBar,
Modules/Plugins/BasePill.qml or AudioVisualization.qml.
-
CustomWorkspaceSwitcher —
3d6e45f4"bar: focus workspace icons on any workspace and wire island overview loader", adapted. Both per-iconMouseAreas (rowAppMouseArea,colAppMouseArea) were gated onenabled: isActive, so an app icon on a non-active workspace could not be clicked to focus its window; worse, on the active workspace they swallowed the press that the outermouseAreaneeds. Upstream deletes both and hit-tests from the workspace delegate instead: newwindowIdAt(x, y)maps the press into the icon layout and readschildAt(...)?.windowId, andfocusWindowAt(x, y)focuses that window and returnstrue, which the delegate's left-buttononReleasedchecks before falling through to the workspace switch. Each icon delegate now exposesreadonly property var windowId: modelData.windowId.Adaptation: upstream aliases
iconsLayout: contentRow.item, which works because its icons are direct children of the row/column. Ours are not — the custom column layout nests them one level deeper insidecolIconsLayout(theColumnLayoutthat does the negative-margin overlap for the active icon), sochildAton theColumnwould return the wrapperItemand never find awindowId. Instead each layout component names its own container: theRowgetsid: rowIconsRow+iconsContainer: rowIconsRow, theColumngetsiconsContainer: colIconsLayout, andcontentRootreadsiconsLayout: contentRow.item?.iconsContainer ?? null.Our Hyprland branch keeps
Hyprland.dispatch(\focuswindow address:${winId}`)rather than upstream'sHyprlandService.focusWindow. Upstream also swapped its iconMouseAreas forHoverHandlers to preserve hover opacity; we need no replacement, because our icon opacity comes from the PluginService per-state colour system and never readcontainsMouse. Dropping the icons'cursorShape: Qt.PointingHandCursoris a no-op — the outermouseAreaalready sets it for every non-placeholder workspace. Drag-reorder is unaffected:wasDraggingstill returns early before the left-button branch. The// Custom:no-grouping,wsAppIconActive/wsAppIconNormalsizing, per-state colours and spacing preset are untouched.qmllinterror count is unchanged at 0, with two fewer each ofimport,unqualifiedandunresolved-type` warnings from the removed code. -
Not applicable —
fbffa410"clock: align the horizontal time block to whole pixels" touchesClock.qml, which we do not fork. The other 35 commits went to the launcher, Dank Island, dock, greeter, services, the Go core and translations.
Two of the 42 upstream commits touched our six widgets; both were ported. No changes to
CustomMedia, CustomNetworkMonitor, CustomSystemTrayBar, CustomWorkspaceSwitcher or
AudioVisualization.qml.
- CustomFocusedApp —
9a7177f9"fix(bar): prevent focused app widget from blanking and live-sync (#3258)". The widget used to blank on niri wheneverToplevelManager.activeToplevelwent null (workspace switch, popout grabbing focus). AddsisWindowAlive()andgetNiriFocusedWindow()helpers; when there is no active toplevel on niri it now falls back toNiriService.windows.find(w => w.is_focused)— orNiriService.lastFocusedWindowIdwhile the details popout is open — and maps that back to a toplevel throughCompositorService.sortedToplevels[].sourceToplevel, with anappId/titlematch as backup. Theif (!CompositorService.isNiri)guard ononActiveToplevelChangedis gone (niri needs the signal too),onAllWorkspacesChangedwas added, and the null-active branch now clears only when the window is dead or the screen's active workspace is genuinely empty. The popout trigger-position code was extracted intosyncPopoutState()soonActiveWindowChangedcan live-update an open popout (double-called viaQt.callLaterto catch post-layout geometry) orclose()it when the window goes away; a newConnectionsonfocusedWindowPopoutLoader.itemre-runsupdateActiveWindow()onshouldBeVisibleChanged/popoutClosed.hasWindowsOnCurrentWorkspaceuses the same helper and, with no focused window, now reports whether the screen's active workspace holds any window at all. Icon + title layout,maxNormalWidth: 99999,stripAppName/appIconSize/iconTitleSpacingare untouched. - CustomRunningApps —
5142d576"fix(bar): centre widget content on whole pixels (#3263)". Both copies of the ad-hocMath.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding))bar-thickness math replaced by upstream's newTheme.barThickness(innerPadding, dpr), which rounds to whole device pixels; the DPR comes fromCompositorService.getScreenScale(parentScreen)for the widget's owneffectiveBarThicknessand fromCompositorService.getScreenScale(contextMenuWindow.screen)inside the window context menu. Fixes half-pixel blur on fractional-scale outputs. Spacing presets, the PluginService colour system,appIconSizeand the title-width debounce cache are untouched.
Nothing to port. Twenty-nine upstream commits landed, but none touched any of the six widgets we
fork (FocusedApp, Media, NetworkMonitor, RunningApps, SystemTrayBar, WorkspaceSwitcher)
or Modules/Plugins/BasePill.qml. Upstream work went to the Dock, Dank Island, Greeter, Changelog,
services (IconThemeService, PolkitService, BluetoothService, ClipboardService), the Go core
and translations. Modules/Plugins/DesktopPluginWrapper.qml changed, but it wraps desktop-placed
plugins — ours are bar widgets plus one daemon — so it does not apply.
Five upstream commits touched our widgets. CustomNetworkMonitor had no upstream changes.
- CustomFocusedApp / CustomRunningApps / CustomSystemTrayBar —
ea0b158e"bar/island: fix click targets on satellites".MouseArea { anchors.fill: parent }replaced by an explicit rect grown byBasePill'sleftMargin/rightMargin/topMargin/bottomMargin, so clicks landing in the inter-widget gap or at the bar edge still hit the pill. Single-pillCustomFocusedAppextends on all four sides (upstream form); the multi-delegateCustomRunningApps(2MouseAreas) andCustomSystemTrayBar(3MouseAreas) extend on the cross axis only —x/widthwhen vertical,y/heightwhen horizontal — because side-by-side delegates would otherwise steal each other's clicks. - CustomSystemTrayBar —
3b527f1f"SystemTrayBar: add configurable icon spacing (#3183)". The spacing feature itself was already implemented here and is ahead of upstream: ouriconSpacingpreset comes fromPluginServiceunder the"SortedSystemTray"key, and both drag-shift call sites already usetrayItemSize + iconSpacing. Only the incidental fix was taken: the inline tray toggle spacer'svisible: width > 0 || height > 0→&&(with||a collapsed 0×N spacer stayed visible). - CustomSystemTrayBar —
5b8f083f"fix(tray): prefer tooltip title in menu (#3181)". Context-menu header now readstrayItem?.tooltipTitle || trayItem?.id || I18n.tr("Unknown")instead of the raw D-Bus id. Upstream'sisAutoOverflowTrayItem/ "Keep in Bar" branch is still absent here and was not introduced. - CustomRunningApps —
4447d77b"feat(Dank Island): add new island bar instance". Only the API change taken:SettingsData.barConfigs[0]?.position→SettingsData.getPrimaryBarConfig()?.positionfor the window-context-menutriggerBarPosition. Indexing[0]is wrong once more than one bar instance exists. - CustomWorkspaceSwitcher —
ea0b158e. Addedproperty real crossEdgeExtension: 0(bound automatically byWidgetHostonce the property exists) and used it in_topMargin/_bottomMarginfor horizontal bars. Inert on a normal bar; correct if the Island bar is ever enabled. - CustomWorkspaceSwitcher —
195ec3bf"feat(motion): spring-based physics & shell hybrid material animations". The drag-reorder shift'sBehavior on x/Behavior on y(NumberAnimation, 150 ms,OutCubic) replaced by twoSpringMotioninstances driven fromTheme.springPreset("fast", 150), retargeted inonShiftOffsetChanged. AlsoTheme.isLightColor(bgColor, 0.4)in place of the inline0.299r + 0.587g + 0.114b > 0.4ingetContrastingIconColor/getContrastingTextColor— mathematically identical (Theme.luminanceuses the same coefficients), and our extrabgOpacity < 0.1 → Theme.widgetTextColorguard is kept. - CustomMedia —
44e82c6e"island: break out more stuff into commonality helpers…". The ~118-line inline scrollingStyledText(hold/step/cava-tick/text-change animation) replaced by upstream'sScrollingTextfromqs.Widgets, which carries byte-identical logic.textContainer.widthnow readsmediaText.implicitTextWidthinstead ofmediaText.implicitWidth, because the component is anItemwrapper whose ownimplicitWidthis 0 (this is the samecontentWidth→implicitTextWidthcorrection upstream made inc580aa26). Behaviour difference: withscrollTitleEnabledoff, overflowing text now elides with…instead of hard-clipping.mediaSize/reverseOrder/hideIconand the unlimited-width path (textWidth === -1) are untouched. - CustomMedia / AudioVisualization —
44e82c6e, adapted. Our copy is still the pre-shaderRectangle+Repeaterfork, so only two things carry over:livegains&& enabled, and the fakeMath.random()cava fallbackTimeris gone (upstream deleted it;CustomMediaalready shows amusic_noteicon whenever cava is unavailable). Drive-by: theBehavior on heightguarded on!CavaService.cavaAvailablewent with it — nothing mutatesCavaService.valueswhile cava is down, so it could no longer fire. Upstream'sidleIconName/barColor/showBarsproperties are not needed, sinceCustomMediaowns its own idle icon. - CustomFocusedApp —
b7034fca"fix(bar): prevent focused app overlap (#3190)" and2c471e1c"clip title overflow horizontally only" not ported. Both clamp the pill toavailableWidth, butDankBarContent.qmlwiresavailableWidthonly for its own built-inFocusedAppinstance —WidgetHost/PluginComponentnever pass it to plugin widgets. Our property would sit at its stale default of400, capping the deliberately unlimited (maxNormalWidth: 99999) pill. - CustomMedia —
c580aa26"fix media text collapse" not applicable. The fix targets upstream'smeasuredTextWidth/adaptiveWidthEnabledpath, which our fork does not have (we size fromtextWidthdirectly).
Two upstream commits touched our six widgets; both were ported.
- CustomFocusedApp —
a669253c"feat(bar): add focused window details popout (#3139)". Left-click on the pill now opens upstream'sFocusedWindowContextMenupopout (window details + PID) via a newfocusedWindowPopoutLoader;cursorShape: Qt.PointingHandCursor; addedresolveSortedWindow()/resolveActiveWindowPid()(niri PID comes fromNiriService.windows[].pid, added to the service in the same upstream commit). Plugin importsqs.Modules.DankBar.Widgetsto reach the popout type. Icon + title layout, unlimited width and the strip-app-name setting are untouched. Requires a DMS build containinga669253c(quickshell/Modules/DankBar/Widgets/FocusedWindowContextMenu.qml+NiriServicepid): on the currentc1894a3store path the plugin fails to load untildmsis rebuilt from the fork branch. - CustomWorkspaceSwitcher —
90c5f65b"fix(workspaces/hyprland): recover workspace mapping on monitor hotplug". The hardcoded{id: 1, name: "1"}fallback for the per-monitor Hyprland filter replaced byhyprlandMonitorWorkspaces(), which falls back toHyprland.monitors[].activeWorkspace(#3133). Hyprland-only path — inert on niri, ported for diff-parity. Individual-icon (// Custom:) code,PluginServicecolours and spacing presets untouched. - No changes to CustomMedia, CustomNetworkMonitor, CustomRunningApps, CustomSystemTrayBar, or
AudioVisualization.qml.
Three upstream commits touched our six widgets; all three were ported.
- CustomSystemTrayBar —
34626070"fix(tray): don't dismiss click-opened tray menus from hover controller (#2979)". Real bug fix here, not just diff-parity: the running build'sTrayMenuManager.closeHoverMenus()skips any menu whoseopenedByHover !== true, and our fork had no such property, soDankBarHoverControllercould never dismiss a hover-opened tray menu. AddedopenedByHoverto the tray-menu component and threaded abyHoverargument through bothshowForTrayItem()overloads;openHoverAtGlobalPoint()passestrue, every click path leaves itundefined. - CustomSystemTrayBar —
2baf0482"feat(tray): add IPC action to open tray menus (#2701)". Added theConnections { target: TrayMenuManager }block withonOpenTrayMenuRequested.claimMenuRequest()/findTrayItem()both exist in the running build. Independent of our drag-and-drop reordering and ofSessionData.trayItemOrder; upstream's auto-overflow / "Keep in Bar" is still absent here, as intended. - CustomRunningApps —
b0b9b615"dock/apps: support minimize". Ported in full across both delegate branches:isMinimizedreadonly property +opacity: 0.4on the icon, Steam fallback icon and letter fallback..activate()→CompositorService.activateToplevel()(scroll switching, group cycling) andCompositorService.toggleToplevel()(single-window click).- Window context menu rewritten from a fixed 100×32 close-only rect into a 120-wide
Columnwith a conditional Minimize/Restore row plus Close. - Context-menu
yPosfor bottom bars stopped using the hardcoded32and now readswindowContextMenuLoader.item.menuHeight. This is the part that actually changes behaviour on this machine — minimize itself is inert on niri, sinceDankCommon/Common/Compositor.qmlreturnssupportsMinimize: falsewheneverNIRI_SOCKETis set, which makescanMinimize()false and hides the Minimize row. - Our customizations were untouched:
appIconSize, thePluginServicecolour modes viaroot.getTextColor(isFocused), the debug overlays, the root-level title debounce cache.
- No changes to CustomFocusedApp, CustomMedia, CustomNetworkMonitor, CustomWorkspaceSwitcher, or
AudioVisualization.qml.
Only one upstream commit touched our six widgets: c67b1850 "qs: large sweep of dead code removals".
- CustomWorkspaceSwitcher —
c67b1850: localescapeSwayWorkspaceName()/dispatchSwayWorkspace()(15 lines) deleted in favour ofCompositorService.dispatchSwayWorkspace(); 3 call sites redirected. Body is byte-identical to the service's, which is present in the running build (CompositorService.qml:1094). Sway/scroll/miracle paths only — inert on niri, taken for diff-parity.I3import still needed elsewhere in the file. - CustomNetworkMonitor —
c67b1850not applicable. Upstream swappedformatNetworkSpeed()forFormat.formatRate(), but (a) our formatter is the customization (figure spaces\u2007,"0 KB/s"/"<1 KB/s", 3-char right-aligned rounding), and (b) the newimport "../../../Common/Format.js"is relative toquickshell/Modules/DankBar/Widgets/and cannot resolve from the plugins directory. - Plugins setting components —
c67b1850also refactoredquickshell/Modules/Plugins/*Setting.qml(findSettings()→QmlUtils.findSettings()). No public API change, and all 11 local slider forks (SteppedSliderSetting/RealSliderSetting/LabeledSliderSetting) carry their ownfindSettings()— unaffected. Same relative-import blocker applies, so not ported. - No changes to CustomFocusedApp, CustomMedia, CustomRunningApps, CustomSystemTrayBar.
- CustomMedia —
fe1a783e/dc924618stable-metadata centralisation: the local_stableTitle/_stableArtist/_syncMeta()block (26 lines) deleted in favour ofMprisController.stableTitle/.stableArtist; all fouractivePlayer.next()call sites routed throughMprisController.next(). OurcanGoNext/canGoPreviousscroll guards are unaffected.2986e354/cdaedad9/c3fa7b2etitle-scroll rewrite (#2863): the infiniteSequentialAnimationreplaced byTimer-drivenstepScroll()that ridesCavaService.valuesChangedticks when the visualizer is live. A runningNumberAnimationcommits a frame every vsync, so two unsynchronized tick sources nearly doubled the surface commit rate. Also gated on window visibility +_isPlaying, andxrounded to whole pixels.- AudioVisualization — adapted, not ported. Our copy predates upstream's shader rewrite (
bandsA/bandsBvectors), so only the two ideas carry over: alivegate (visible && Window.window?.visible && isPlaying) on theRefloader, fallback timer andCavaServiceconnection; and levels quantized to 1/32 with identical frames dropped before assigningbarHeights.
- CustomSystemTrayBar —
fb2dbcedmenu overflow:rawHeightcapped atmaskHeight - 20andmenuColumnwrapped in aDankFlickable(interactive: contentHeight > height), so long tray menus scroll instead of running off-screen. OurTheme.primaryHoverhover colours andSessionData.isHiddenTrayIdvisibility logic preserved; upstream's auto-overflow / "Keep in Bar" branch is absent from our copy and was not introduced.1402d231vbar menu positioning: vertical-orientation branches clamp against windowwidth/heightinstead ofmaskX/maskYbounds (4 blocks — overflow menu x/y, tray menu x/y).- Icon-size token sweep: hardcoded
16/14/10→Theme.iconSizeSmalland derivations; checkboxradius: … ? 8 : 2→width / 2.
- CustomWorkspaceSwitcher —
4fb69957Hyprland re-focus fix (#2830):ConnectionsonHyprlandrawEventcallingupdateAllData()foractivewindow/activewindowv2. Inert on niri (enabled: CompositorService.isHyprland) — taken for diff-parity with upstream.296b3a3d(mango dispatch socket) not applicable — our copy has nommsg/overview-toggle button.
- CustomMedia —
52ed7194fix: missinganchors.verticalCenteron themediaInfoRow. - CustomNetworkMonitor —
093acdbfspacing-token sweep: hardcoded2/4→Theme.spacingXXS/Theme.spacingXS. - CustomRunningApps — close-button simplification:
BlurService.borderWidth/.borderColorused directly (enabled-check moved inside the service);"transparent"→Theme.withAlpha(..., 0)for smoother hover animation. - CustomSystemTrayBar —
- Cosmetic sweep:
Theme.outlineHeavyreplacing hardcodedQt.rgba(Theme.outline, 0.2),Theme.spacingXXS,closeWithAction()indirection removed, hover"transparent"→Theme.withAlpha(Theme.primaryHover, 0). fefc0afamenu boundary clamping: overflow/context menus now clamp againstmaskX/Y/Width/Heightinstead of raw screen bounds, plusRegionmasks so menu content areas are included in the popup hit region.HyprlandFocusGrab→DankFocusGrabmigration (fixes Hyprland focus-stealing bug #2577), wired through theKeyboardFocussingleton (KeyboardFocus.keyboardFocus()/.wantsGrab()/.barWindows) — this also closes a pre-existing gap where the file had hand-rolled focus logic bypassing that singleton entirely.6bee1b2cHoverMode hook functions added (hoverTriggerAtGlobalPoint,openHoverAtGlobalPoint) — purely additive.
- Cosmetic sweep:
- CustomWorkspaceSwitcher —
effectiveScreenNamesimplified toBarWidgetService.getFocusedScreenName(), replacing the manual per-compositor switch (incidentally fixes focus-follow for Mango, which the old switch never had a case for).- Sway/Hyprland named-workspace correctness: stripped
<num>:<name>prefix, stable ordering (numbered first, named after by name), safe dispatch for named workspaces (workspace "name"/workspace name:x), Hyprland special-workspace filtering. - Stable placeholder/slot pooling (
_placeholderPool,_hyprSlotPool) so ScriptModel reuses delegate identity across workspace churn instead of recreating pills (reduces animation jitter);onCompositorChangedresets both pools. DankColorAnimationswap for the pill's background-color transition (premultiplied-alpha tween instead of plainColorAnimation), applied on top of our own PluginService-based color system —SettingsData.workspace*ColorModeis unrelated to us and was not touched.
- Per-monitor "unfocused monitor appearance" color refactor (
effectiveColorMode/effectiveCustomColor/workspaceUnfocusedMonitor*) — CustomWorkspaceSwitcher has its own PluginService-based color system;SettingsData.workspace*ColorModeisn't used here at all. - CustomFocusedApp's new
showIconsetting + horizontal-icon width recalculation — superseded by our existing "icon + title, unlimited width" customization, which predates and already covers this. - CustomMedia's prev/next hover-color fix — doesn't apply; we already use a different color scheme (
Theme.primaryHover) there.
- CustomWorkspaceSwitcher: dwl/mango dead code — fixed in the 2026-09-19 sync. The
CompositorService.isDwl/DwlServicebranches are gone; mango now goes throughCompositorService's workspace API like every other compositor. - CustomWorkspaceSwitcher: named sway workspaces + app icons — fixed in the 2026-09-19
sync.
getWorkspaceIconsno longer keys off.num; it asksCompositorService.windowsOnWorkspace(record).
Shows icon + window title instead of app name + separator + title.
Changes:
- App name text hidden (
visible: false) - Separator dot hidden
- Icon displayed alongside title only
- Left-click opens upstream's
FocusedWindowContextMenupopout (window details + PID), as in upstream sincea669253c - Settings panel with:
- "Strip App Name from Title" - Smart removal of app name, version numbers, instance markers, and brand words from titles
Configurable media widget with settings panel.
Changes:
- Configurable text width (none/small/medium/unlimited)
- Reverse layout order option
- Hide icon option
- Mouse wheel volume control (when player supports it)
- Mouse wheel: 5% volume increments
- Touchpad: smooth 1% increments with accumulator
- Per-widget or global settings via
PluginService.loadPluginData
Network speed monitor with fixed-width formatting.
Changes:
- Uses figure spaces (
\u2007) for consistent width alignment - Shows
0 KB/sor<1 KB/sfor low values - Color-coded: download (Theme.info/blue), upload (Theme.error/red)
- Padded numbers to 3 digits for stable layout
Enhanced running apps taskbar.
Changes:
- Scroll wheel switches between windows
- Middle-click closes window
- Right-click context menu (
DankContextMenu) with Minimize/Restore, scratchpad moves and Close - Grouped windows show badge with count
- Click cycles through grouped windows
- Hover tooltips active via
tooltipLoader(an earlier revision had them commented out) - Smart dynamic title width - Non-linear algorithm shrinks longer titles proportionally more when space is constrained
- Niri column indicators - Visual frame around windows in the same Niri column
- Detects stacked vs tabbed columns (different colors)
- Frame opacity increases when group has focused window
- Niri floating indicator - Line indicator on floating windows
- Custom background colors - Separate settings for focused and unfocused pills
- Color selection from Theme palette (Primary, Secondary, Surface variants, etc.)
- Individual opacity sliders (0-100%) for each state
- Custom text colors - Auto-contrast or manual selection for focused/unfocused states
- Flat outer edge - Option to remove rounded corners on the edge facing screen border
- Settings panel with:
- "Strip App Name from Title" - Removes app name, version numbers, instance markers from window titles
- "Title Compression" - Configurable ratio for how aggressively longer titles shrink (1=equal, 2=normal, up to 10=extreme)
System tray with custom icon sizes, spacing, and hover colors. Uses upstream drag-and-drop reordering.
Changes:
- Custom icon size: Configurable via
PluginService.loadPluginData("SortedSystemTray", "iconSize", 18) - Custom icon spacing: Configurable via
PluginService.loadPluginData("SortedSystemTray", "iconSpacing", "M")(presets: 0, XS, S, M, L, XL) - Custom hover color:
Theme.primaryHoveron the four bar-visible hover surfaces (both carets, the main delegate, the inline expanded delegate) instead of upstream'sTheme.onSurfacestate-layer alpha. Menu chrome keeps upstream's styling. - Item size is the icon:
trayItemSizeisconfiguredIconSizewith no padding; upstream pads it byspacingXS + spacingXXS, which would double up with the spacing preset. - Drag-and-drop reordering: Uses upstream's drag-and-drop with spacing-aware slot calculations
- No auto-overflow:
useAutomaticOverflowis pinnedfalse, which emptiesautoOverflowBarItemsand makesisAutoOverflowTrayItem()always false — every upstream branch that would add auto-overflow or "Keep in Bar" is dead, with no surgery on the file.
Enhanced workspace indicator with app icons.
Changes:
- Shows individual app icons per workspace (no grouping)
- Patched:
const key = w.aqueousKey || \${moddedId}_${i}`(unique key per window), andstableIconCountreturnsCompositorService.windowsOnWorkspace(record).length` rather than upstream's per-app grouped count
- Patched:
- Active window icons enlarged (36px vs 24px)
- Click on app icon focuses that window, via
windowIdAt/focusWindowAthit-testing andCompositorService.focusWindow - Workspace index always shown alongside icons
- Steam games show gamepad icon, Quickshell shows themed icon
-
Custom background colors - Settings for all 4 states (active, unfocused, occupied, urgent)
- Color selection from Theme palette
- Individual opacity sliders (0-100%) for each state
- Custom text/icon colors - Auto-contrast or manual selection for each state
- Flat outer edge - Option to remove rounded corners on the screen-edge side
OLED burn-in protection daemon using DDC/I2C hardware brightness control.
Changes:
- Multi-stage dimming: active → dimming → holding → blacking → black → DPMS
- DDC hardware brightness: Uses I2C/DDC (independent of gamma/night light)
- Smooth fades: Ease-out cubic transitions at ~2.5 FPS (within DDC limits)
- Auto-detect DDC device: Falls back gracefully if no DDC device found
- Configurable stages: All timeouts, brightness levels, and fade durations adjustable
- Settings panel with:
- Enable/disable toggle
- Dim timeout (1-10 min)
- Dim brightness level (5-80%)
- Hold duration at dim (1-10 min)
- DPMS delay after black (1-30 min)
- Fade speed (3-20 sec)
Third-party plugin for Docker/Podman container management. See dockerManager/README.md.