1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-06-16 08:05:19 -04:00

Compare commits

...

6 Commits

Author SHA1 Message Date
purian23 fc72b6d779 feat(popouts): implement hover popout functionality 2026-06-12 23:19:29 -04:00
bbedward 3701b3d7a3 wallpaper: re-introduce updatesEnabled 2026-06-12 20:00:53 -04:00
purian23 bae98daa5c fix(wallpaper): simplify wallpaper rendering logic & reliability
- Keep wallpaper surfaces persistent and remove `updatesEnabled` throttling that could leave wallpapers grey or frozen after DPMS, suspend, fullscreen, or output changes

Fixes #2612
Fixes #2299
Fixes #2272
Fixes #2028
2026-06-12 17:30:54 -04:00
jbwfu b34a04f723 fix(clipboard): hide pin action while keeping saved indicator (#2626) 2026-06-12 15:39:23 -04:00
purian23 1c0245f2db fix(translations): add newline at end of JSON file and output file 2026-06-12 15:06:36 -04:00
purian23 7777e87dc8 refactor(settings): reorg to break out sections and verbiage 2026-06-12 14:57:25 -04:00
22 changed files with 1815 additions and 799 deletions
+164 -9
View File
@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
import Quickshell import Quickshell
import QtQuick import QtQuick
import qs.Common
Singleton { Singleton {
id: root id: root
@@ -16,8 +17,76 @@ Singleton {
signal popoutOpening signal popoutOpening
signal popoutChanged signal popoutChanged
property real hoverCursorGlobalX: 0
property real hoverCursorGlobalY: 0
function updateHoverCursor(gx, gy) {
hoverCursorGlobalX = gx;
hoverCursorGlobalY = gy;
}
function cursorOverBar(gx, gy, padding) {
const pad = padding !== undefined ? padding : 16;
const bars = KeyboardFocus.barWindows || [];
for (let i = 0; i < bars.length; i++) {
const w = bars[i];
if (!w?.visible)
continue;
if (typeof w.containsGlobalPoint === "function") {
if (w.containsGlobalPoint(gx, gy, pad))
return true;
continue;
}
const item = w.contentItem;
if (!item || typeof item.mapToItem !== "function")
continue;
const topLeft = item.mapToItem(null, 0, 0);
if (!topLeft)
continue;
if (gx >= topLeft.x - pad && gx < topLeft.x + item.width + pad && gy >= topLeft.y - pad && gy < topLeft.y + item.height + pad)
return true;
}
return false;
}
function _isPopoutPresented(popout) {
if (!popout)
return false;
try {
if (popout.dashVisible !== undefined)
return !!popout.dashVisible;
if (popout.notificationHistoryVisible !== undefined)
return !!popout.notificationHistoryVisible;
return !!(popout.shouldBeVisible || popout.isClosing);
} catch (e) {
return false;
}
}
function _openPopout(popout) {
if (popout.dashVisible !== undefined) {
if (popout.dashVisible && !popout.shouldBeVisible && !popout.isClosing)
popout.dashVisible = false;
popout.dashVisible = true;
return;
}
if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = true;
return;
}
popout.open();
}
function _closePopout(popout) { function _closePopout(popout) {
try { try {
if (popout?.hoverDismissEnabled) {
if (typeof popout.closeFromHoverDismiss === "function") {
popout.closeFromHoverDismiss();
return;
}
}
if (popout.hoverDismissEnabled !== undefined)
popout.hoverDismissEnabled = false;
switch (true) { switch (true) {
case popout.dashVisible !== undefined: case popout.dashVisible !== undefined:
popout.dashVisible = false; popout.dashVisible = false;
@@ -89,7 +158,26 @@ Singleton {
continue; continue;
_closePopout(popout); _closePopout(popout);
} }
currentPopoutsByScreen = {}; // Keep map entries until each popout's close animation finishes (hidePopout).
}
function closePopoutForScreen(screen) {
if (!screen)
return;
const screenName = screen.name;
const popout = currentPopoutsByScreen[screenName];
if (!popout || _isStale(popout)) {
currentPopoutsByScreen[screenName] = null;
currentPopoutTriggers[screenName] = null;
return;
}
_closePopout(popout);
}
function cancelHoverDismiss(screen) {
const popout = getActivePopout(screen);
if (popout?.cancelHoverDismiss)
popout.cancelHoverDismiss();
} }
function getActivePopout(screen) { function getActivePopout(screen) {
@@ -106,6 +194,8 @@ Singleton {
function requestPopout(popout, tabIndex, triggerSource) { function requestPopout(popout, tabIndex, triggerSource) {
if (!popout || !popout.screen) if (!popout || !popout.screen)
return; return;
if (popout.hoverDismissEnabled !== undefined)
popout.hoverDismissEnabled = false;
screenshotActive = false; screenshotActive = false;
const screenName = popout.screen.name; const screenName = popout.screen.name;
const currentPopout = currentPopoutsByScreen[screenName]; const currentPopout = currentPopoutsByScreen[screenName];
@@ -181,16 +271,81 @@ Singleton {
ModalManager.closeAllModalsExcept(null); ModalManager.closeAllModalsExcept(null);
} }
if (movedFromOtherScreen) { _openPopout(popout);
popout.open(); }
function requestHoverPopout(popout, tabIndex, triggerSource) {
if (!popout || !popout.screen)
return;
screenshotActive = false;
const screenName = popout.screen.name;
const currentPopout = currentPopoutsByScreen[screenName];
const triggerId = triggerSource !== undefined ? triggerSource : tabIndex;
const willOpen = !(currentPopout === popout && _isPopoutPresented(popout) && triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId);
if (willOpen)
popoutOpening();
let movedFromOtherScreen = false;
for (const otherScreenName in currentPopoutsByScreen) {
if (otherScreenName === screenName)
continue;
const otherPopout = currentPopoutsByScreen[otherScreenName];
if (!otherPopout)
continue;
if (_isStale(otherPopout)) {
currentPopoutsByScreen[otherScreenName] = null;
currentPopoutTriggers[otherScreenName] = null;
continue;
}
if (otherPopout === popout) {
movedFromOtherScreen = true;
currentPopoutsByScreen[otherScreenName] = null;
currentPopoutTriggers[otherScreenName] = null;
continue;
}
_closePopout(otherPopout);
}
if (currentPopout && currentPopout !== popout) {
if (_isStale(currentPopout)) {
currentPopoutsByScreen[screenName] = null;
currentPopoutTriggers[screenName] = null;
} else { } else {
if (popout.dashVisible !== undefined) { _closePopout(currentPopout);
popout.dashVisible = true;
} else if (popout.notificationHistoryVisible !== undefined) {
popout.notificationHistoryVisible = true;
} else {
popout.open();
} }
} }
if (currentPopout === popout && _isPopoutPresented(popout) && !movedFromOtherScreen) {
if (triggerId !== undefined && currentPopoutTriggers[screenName] === triggerId)
return;
if (tabIndex !== undefined && popout.currentTabIndex !== undefined)
popout.currentTabIndex = tabIndex;
if (popout.updateSurfacePosition)
popout.updateSurfacePosition();
currentPopoutTriggers[screenName] = triggerId;
if (popout.hoverDismissEnabled !== undefined)
popout.hoverDismissEnabled = true;
return;
}
currentPopoutTriggers[screenName] = triggerId;
currentPopoutsByScreen[screenName] = popout;
popoutChanged();
if (tabIndex !== undefined && popout.currentTabIndex !== undefined)
popout.currentTabIndex = tabIndex;
if (currentPopout !== popout)
ModalManager.closeAllModalsExcept(null);
if (popout.hoverDismissEnabled !== undefined)
popout.hoverDismissEnabled = true;
_openPopout(popout);
} }
} }
+2 -1
View File
@@ -810,7 +810,8 @@ Singleton {
"shadowOpacity": 60, "shadowOpacity": 60,
"shadowColorMode": "default", "shadowColorMode": "default",
"shadowCustomColor": "#000000", "shadowCustomColor": "#000000",
"clickThrough": false "clickThrough": false,
"hoverPopouts": false
} }
] ]
+2 -19
View File
@@ -64,27 +64,15 @@ Item {
} }
} }
property bool wallpaperSurfacesLoaded: true
Loader { Loader {
id: blurredWallpaperBackgroundLoader id: blurredWallpaperBackgroundLoader
active: root.wallpaperSurfacesLoaded && SettingsData.blurredWallpaperLayer && CompositorService.isNiri active: SettingsData.blurredWallpaperLayer && CompositorService.isNiri
asynchronous: false asynchronous: false
sourceComponent: BlurredWallpaperBackground {} sourceComponent: BlurredWallpaperBackground {}
} }
DeferredAction { WallpaperBackground {}
id: wallpaperSurfaceReloadAction
onTriggered: root.wallpaperSurfacesLoaded = true
}
Loader {
id: wallpaperBackgroundLoader
active: root.wallpaperSurfacesLoaded
asynchronous: false
sourceComponent: WallpaperBackground {}
}
DesktopWidgetLayer {} DesktopWidgetLayer {}
@@ -398,11 +386,6 @@ Item {
frameSurfaceReloadAction.schedule(); frameSurfaceReloadAction.schedule();
} }
if (root.wallpaperSurfacesLoaded) {
root.wallpaperSurfacesLoaded = false;
wallpaperSurfaceReloadAction.schedule();
}
root.dockEnabled = false; root.dockEnabled = false;
Qt.callLater(() => { Qt.callLater(() => {
root.dockEnabled = true; root.dockEnabled = true;
+11 -14
View File
@@ -28,7 +28,7 @@ Rectangle {
readonly property bool showPinAction: visibleEntryActions.includes("pin") readonly property bool showPinAction: visibleEntryActions.includes("pin")
readonly property bool showEditAction: visibleEntryActions.includes("edit") readonly property bool showEditAction: visibleEntryActions.includes("edit")
readonly property bool showDeleteAction: visibleEntryActions.includes("delete") readonly property bool showDeleteAction: visibleEntryActions.includes("delete")
readonly property bool showPinnedIndicator: !showPinAction && effectivePinned readonly property bool showPinnedIndicator: hasPinnedDuplicate && !showPinAction
readonly property bool showAnyAction: showPinAction || showEditAction || showDeleteAction || showPinnedIndicator readonly property bool showAnyAction: showPinAction || showEditAction || showDeleteAction || showPinnedIndicator
radius: Theme.cornerRadius radius: Theme.cornerRadius
@@ -72,20 +72,17 @@ Rectangle {
spacing: Theme.spacingXS spacing: Theme.spacingXS
visible: root.showAnyAction visible: root.showAnyAction
DankActionButton { Item {
iconName: "push_pin" width: 40
iconSize: Theme.iconSize - 6 height: 40
iconColor: Theme.primary
backgroundColor: Theme.primarySelected
visible: root.showPinnedIndicator visible: root.showPinnedIndicator
onClicked: {
if (entry.pinned) { // Status indicator only; the Pin action remains hidden.
unpinRequested(entry); DankIcon {
return; anchors.centerIn: parent
} name: "push_pin"
if (pinnedDuplicateEntry) { size: Theme.iconSize - 6
unpinRequested(pinnedDuplicateEntry); color: Theme.primary
}
} }
} }
@@ -105,8 +105,8 @@ Rectangle {
}, },
{ {
"id": "compositor_layout", "id": "compositor_layout",
"text": CompositorService.isNiri ? "niri" : (CompositorService.isHyprland ? "Hyprland" : "MangoWC"), "text": CompositorService.isNiri ? "Niri" : (CompositorService.isHyprland ? "Hyprland" : "MangoWC"),
"icon": "crop_square", "icon": "layers",
"tabIndex": 37, "tabIndex": 37,
"layoutCapable": true "layoutCapable": true
} }
@@ -117,18 +117,18 @@ Rectangle {
"text": I18n.tr("Dank Bar"), "text": I18n.tr("Dank Bar"),
"icon": "toolbar", "icon": "toolbar",
"children": [ "children": [
{
"id": "dankbar_settings",
"text": I18n.tr("Settings"),
"icon": "tune",
"tabIndex": 3
},
{ {
"id": "dankbar_appearance", "id": "dankbar_appearance",
"text": I18n.tr("Appearance"), "text": I18n.tr("Appearance"),
"icon": "palette", "icon": "palette",
"tabIndex": 6 "tabIndex": 6
}, },
{
"id": "dankbar_settings",
"text": I18n.tr("Settings"),
"icon": "tune",
"tabIndex": 3
},
{ {
"id": "dankbar_widgets", "id": "dankbar_widgets",
"text": I18n.tr("Widgets"), "text": I18n.tr("Widgets"),
@@ -7,6 +7,7 @@ import qs.Widgets
import qs.Services import qs.Services
Variants { Variants {
readonly property var log: Log.scoped("BlurredWallpaperBackground")
model: { model: {
if (SessionData.isGreeterMode) { if (SessionData.isGreeterMode) {
return Quickshell.screens; return Quickshell.screens;
@@ -32,6 +33,8 @@ Variants {
color: "transparent" color: "transparent"
updatesEnabled: root.renderActive || root._settleFrames > 0
mask: Region { mask: Region {
item: Item {} item: Item {}
} }
@@ -85,7 +88,6 @@ Variants {
} }
Component.onCompleted: { Component.onCompleted: {
blurWallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading);
isInitialized = true; isInitialized = true;
} }
@@ -93,51 +95,67 @@ Variants {
property real transitionProgress: 0 property real transitionProgress: 0
readonly property bool transitioning: transitionAnimation.running readonly property bool transitioning: transitionAnimation.running
property bool effectActive: false property bool effectActive: false
property bool _renderSettling: true
property bool useNextForEffect: false property bool useNextForEffect: false
readonly property var backingWindow: Window.window
readonly property bool renderActive: !source || effectActive || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading
property int _settleFrames: 3
Connections { function invalidate() {
target: currentWallpaper _settleFrames = 3;
function onStatusChanged() { backingWindow?.update();
if (currentWallpaper.status !== Image.Ready && currentWallpaper.status !== Image.Error)
return;
root._renderSettling = true;
renderSettleTimer.restart();
}
} }
onRenderActiveChanged: invalidate()
onBackingWindowChanged: invalidate()
Connections { Connections {
target: blurWallpaperWindow target: root.backingWindow
function onFrameSwapped() {
if (root._settleFrames > 0)
root._settleFrames--;
}
function onVisibleChanged() {
root.invalidate();
}
function onWidthChanged() { function onWidthChanged() {
root._renderSettling = true; root.invalidate();
renderSettleTimer.restart();
} }
function onHeightChanged() { function onHeightChanged() {
root._renderSettling = true; root.invalidate();
renderSettleTimer.restart();
} }
} }
Connections { Connections {
target: Quickshell target: Quickshell
function onScreensChanged() { function onScreensChanged() {
root._renderSettling = true; root.invalidate();
renderSettleTimer.restart();
} }
} }
Connections { Connections {
target: SettingsData target: SettingsData
function onWallpaperFillModeChanged() { function onWallpaperFillModeChanged() {
root._renderSettling = true; root.invalidate();
renderSettleTimer.restart();
} }
} }
Timer { Connections {
id: renderSettleTimer target: IdleService
interval: 1000 function onIsShellLockedChanged() {
onTriggered: root._renderSettling = false if (IdleService.isShellLocked)
return;
root.invalidate();
}
}
function handleTransitionLoadError(failedSource) {
log.warn("failed to load candidate wallpaper for", modelData.name + ":", failedSource);
transitionDelayTimer.stop();
transitionAnimation.stop();
root.useNextForEffect = false;
root.effectActive = false;
root.transitionProgress = 0.0;
nextWallpaper.source = "";
} }
onSourceChanged: { onSourceChanged: {
@@ -164,8 +182,6 @@ Variants {
transitionAnimation.stop(); transitionAnimation.stop();
root.transitionProgress = 0.0; root.transitionProgress = 0.0;
root.effectActive = false; root.effectActive = false;
root._renderSettling = true;
renderSettleTimer.restart();
currentWallpaper.source = newSource; currentWallpaper.source = newSource;
nextWallpaper.source = ""; nextWallpaper.source = "";
} }
@@ -194,8 +210,6 @@ Variants {
transitionAnimation.stop(); transitionAnimation.stop();
root.transitionProgress = 0; root.transitionProgress = 0;
root.effectActive = false; root.effectActive = false;
root._renderSettling = true;
renderSettleTimer.restart();
currentWallpaper.source = nextWallpaper.source; currentWallpaper.source = nextWallpaper.source;
nextWallpaper.source = ""; nextWallpaper.source = "";
} }
@@ -204,9 +218,6 @@ Variants {
return; return;
} }
root._renderSettling = true;
renderSettleTimer.restart();
nextWallpaper.source = newPath; nextWallpaper.source = newPath;
if (nextWallpaper.status === Image.Ready) if (nextWallpaper.status === Image.Ready)
@@ -215,7 +226,7 @@ Variants {
Loader { Loader {
anchors.fill: parent anchors.fill: parent
active: !root.source || root.isColorSource active: !root.source || root.isColorSource || currentWallpaper.status === Image.Error
asynchronous: true asynchronous: true
sourceComponent: DankBackdrop { sourceComponent: DankBackdrop {
@@ -238,6 +249,12 @@ Variants {
cache: true cache: true
sourceSize: Qt.size(root.textureWidth, root.textureHeight) sourceSize: Qt.size(root.textureWidth, root.textureHeight)
fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name))
onStatusChanged: {
if (status === Image.Error) {
log.warn("failed to load active wallpaper for", modelData.name + ":", source);
}
}
} }
Image { Image {
@@ -253,6 +270,10 @@ Variants {
fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name))
onStatusChanged: { onStatusChanged: {
if (status === Image.Error) {
root.handleTransitionLoadError(source);
return;
}
if (status !== Image.Ready) if (status !== Image.Ready)
return; return;
if (!root.transitioning) { if (!root.transitioning) {
@@ -329,8 +350,6 @@ Variants {
root.useNextForEffect = false; root.useNextForEffect = false;
nextWallpaper.source = ""; nextWallpaper.source = "";
root.transitionProgress = 0.0; root.transitionProgress = 0.0;
root._renderSettling = true;
renderSettleTimer.restart();
root.effectActive = false; root.effectActive = false;
} }
} }
File diff suppressed because it is too large Load Diff
+41 -1
View File
@@ -709,6 +709,14 @@ PanelWindow {
readonly property var _rightSection: topBarContent ? (barWindow.isVertical ? topBarContent.vRightSection : topBarContent.hRightSection) : null readonly property var _rightSection: topBarContent ? (barWindow.isVertical ? topBarContent.vRightSection : topBarContent.hRightSection) : null
readonly property real _revealProgress: topBarSlide.x + topBarSlide.y readonly property real _revealProgress: topBarSlide.x + topBarSlide.y
function containsGlobalPoint(gx, gy, padding) {
const pad = padding !== undefined ? padding : 16;
if (!inputMask.showing)
return false;
const topLeft = inputMask.mapToItem(null, 0, 0);
return gx >= topLeft.x - pad && gx < topLeft.x + inputMask.width + pad && gy >= topLeft.y - pad && gy < topLeft.y + inputMask.height + pad;
}
function sectionRect(section, isCenter, _dep) { function sectionRect(section, isCenter, _dep) {
if (!section) if (!section)
return { return {
@@ -1010,7 +1018,7 @@ PanelWindow {
} }
} }
onWheel: wheel => { function processWheel(wheel) {
if (!(barConfig?.scrollEnabled ?? true) || actionInProgress) { if (!(barConfig?.scrollEnabled ?? true) || actionInProgress) {
wheel.accepted = false; wheel.accepted = false;
return; return;
@@ -1079,6 +1087,8 @@ PanelWindow {
wheel.accepted = false; wheel.accepted = false;
} }
onWheel: wheel => processWheel(wheel)
} }
DankBarContent { DankBarContent {
@@ -1090,6 +1100,36 @@ PanelWindow {
centerWidgetsModel: barWindow.centerWidgetsModel centerWidgetsModel: barWindow.centerWidgetsModel
rightWidgetsModel: barWindow.rightWidgetsModel rightWidgetsModel: barWindow.rightWidgetsModel
} }
MouseArea {
id: hoverPopoutArea
anchors.fill: parent
z: 1
hoverEnabled: barConfig?.hoverPopouts ?? false
enabled: hoverPopoutArea.hoverEnabled && !barWindow.clickThroughEnabled
acceptedButtons: Qt.NoButton
propagateComposedEvents: true
property real lastGlobalX: 0
property real lastGlobalY: 0
onPositionChanged: mouse => {
const gp = mapToItem(null, mouse.x, mouse.y);
lastGlobalX = gp.x;
lastGlobalY = gp.y;
topBarContent.checkHoverPopout(gp.x, gp.y);
}
onWheel: wheel => scrollArea.processWheel(wheel)
onContainsMouseChanged: {
if (containsMouse)
return;
if (topBarContent.cursorOverHoverChain(lastGlobalX, lastGlobalY))
return;
topBarContent.closeHoverSurfaces();
}
}
} }
} }
} }
@@ -1922,4 +1922,53 @@ BasePill {
return; return;
currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom, vertical ?? false, axisObj); currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom, vertical ?? false, axisObj);
} }
function _trayLayoutRoot() {
const contentChildren = root.visualContent?.children;
if (!contentChildren || contentChildren.length === 0)
return null;
const contentRoot = contentChildren[0];
return contentRoot?.layoutLoader?.item || null;
}
function _trayHitAtGlobalPoint(gx, gy) {
if (!root.visible || root.width <= 0 || root.height <= 0)
return null;
const local = root.mapFromItem(null, gx, gy);
if (local.x < 0 || local.y < 0 || local.x > root.width || local.y > root.height)
return null;
const layout = _trayLayoutRoot();
if (!layout)
return null;
const layoutLocal = layout.mapFromItem(null, gx, gy);
const children = layout.children || [];
for (let i = 0; i < children.length; i++) {
const child = children[i];
if (!child.visible || child.width <= 0 || child.height <= 0)
continue;
if (layoutLocal.x < child.x || layoutLocal.x >= child.x + child.width)
continue;
if (layoutLocal.y < child.y || layoutLocal.y >= child.y + child.height)
continue;
if (child.trayItem)
return child;
}
return null;
}
function hoverTriggerAtGlobalPoint(gx, gy) {
const hit = _trayHitAtGlobalPoint(gx, gy);
if (!hit?.trayItem?.hasMenu)
return "";
return "tray-" + (hit.trayItem.id || hit.itemKey || "");
}
function openHoverAtGlobalPoint(gx, gy) {
const hit = _trayHitAtGlobalPoint(gx, gy);
if (!hit?.trayItem?.hasMenu)
return false;
const anchor = hit.children?.length > 0 ? hit.children[0] : hit;
showForTrayItem(hit.trayItem, anchor, parentScreen, isAtBottom, isVerticalOrientation, axis);
return true;
}
} }
@@ -330,6 +330,24 @@ Item {
pluginPopout.toggle(); pluginPopout.toggle();
} }
function triggerHoverPopout(widgetHostId) {
if (pillClickAction) {
triggerPopout();
return;
}
if (!hasPopout)
return;
const pill = isVertical ? verticalPill : horizontalPill;
const globalPos = pill.visualContent.mapToItem(null, 0, 0);
const currentScreen = parentScreen || Screen;
const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1));
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, pill.visualWidth, barSpacing, barPosition, barConfig);
pluginPopout.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen, barPosition, barThickness, barSpacing, barConfig);
PopoutManager.requestHoverPopout(pluginPopout, undefined, widgetHostId || pluginId);
}
PluginPopout { PluginPopout {
id: pluginPopout id: pluginPopout
contentWidth: root.popoutWidth contentWidth: root.popoutWidth
@@ -23,9 +23,9 @@ Item {
SettingsCard { SettingsCard {
width: parent.width width: parent.width
tags: ["niri", "layout", "gaps", "radius", "window", "border"] tags: ["niri", "layout", "gaps", "radius", "window", "border"]
title: I18n.tr("Niri Layout Overrides").replace("Niri", "niri") title: I18n.tr("Niri Layout Overrides")
settingKey: "niriLayout" settingKey: "niriLayout"
iconName: "crop_square" iconName: "layers"
visible: CompositorService.isNiri visible: CompositorService.isNiri
SettingsToggleRow { SettingsToggleRow {
+82 -67
View File
@@ -164,6 +164,7 @@ Item {
scrollEnabled: defaultBar.scrollEnabled ?? true, scrollEnabled: defaultBar.scrollEnabled ?? true,
scrollXBehavior: defaultBar.scrollXBehavior ?? "column", scrollXBehavior: defaultBar.scrollXBehavior ?? "column",
scrollYBehavior: defaultBar.scrollYBehavior ?? "workspace", scrollYBehavior: defaultBar.scrollYBehavior ?? "workspace",
hoverPopouts: defaultBar.hoverPopouts ?? false,
shadowIntensity: defaultBar.shadowIntensity ?? 0, shadowIntensity: defaultBar.shadowIntensity ?? 0,
shadowOpacity: defaultBar.shadowOpacity ?? 60, shadowOpacity: defaultBar.shadowOpacity ?? 60,
shadowDirectionMode: defaultBar.shadowDirectionMode ?? "inherit", shadowDirectionMode: defaultBar.shadowDirectionMode ?? "inherit",
@@ -796,18 +797,81 @@ Item {
} }
} }
SettingsCard {
tab: "appearance"
iconName: "opacity"
title: I18n.tr("Opacity")
settingKey: "barTransparency"
visible: dankBarTab.appearanceOnly && selectedBarConfig?.enabled
SettingsSliderRow {
id: barTransparencySlider
visible: !SettingsData.frameEnabled
text: I18n.tr("Bar Opacity")
description: I18n.tr("Controls opacity of the bar background")
value: (selectedBarConfig?.transparency ?? 1.0) * 100
minimum: 0
maximum: 100
unit: "%"
defaultValue: 100
onSliderDragFinished: finalValue => {
SettingsData.updateBarConfig(selectedBarId, {
transparency: finalValue / 100
});
}
Binding {
target: barTransparencySlider
property: "value"
value: (selectedBarConfig?.transparency ?? 1.0) * 100
restoreMode: Binding.RestoreBinding
}
}
SettingsSliderRow {
id: widgetTransparencySlider
text: I18n.tr("Widget Opacity")
description: I18n.tr("Controls opacity of widget backgrounds")
value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100
minimum: 0
maximum: 100
unit: "%"
defaultValue: 100
onSliderDragFinished: finalValue => {
SettingsData.updateBarConfig(selectedBarId, {
widgetTransparency: finalValue / 100
});
}
Binding {
target: widgetTransparencySlider
property: "value"
value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100
restoreMode: Binding.RestoreBinding
}
}
SettingsControlledByFrame { SettingsControlledByFrame {
visible: !dankBarTab.appearanceOnly && SettingsData.frameEnabled visible: SettingsData.frameEnabled
parentModal: dankBarTab.parentModal
settingLabel: I18n.tr("Bar Opacity")
reason: I18n.tr("Managed by Frame")
}
}
SettingsControlledByFrame {
visible: dankBarTab.appearanceOnly && SettingsData.frameEnabled
parentModal: dankBarTab.parentModal parentModal: dankBarTab.parentModal
settingLabel: I18n.tr("Bar spacing and size") settingLabel: I18n.tr("Bar spacing and size")
reason: I18n.tr("Managed by Frame") reason: I18n.tr("Managed by Frame")
} }
SettingsCard { SettingsCard {
tab: "appearance"
iconName: "space_bar" iconName: "space_bar"
title: I18n.tr("Spacing") title: I18n.tr("Spacing")
settingKey: "barSpacing" settingKey: "barSpacing"
visible: !dankBarTab.appearanceOnly && (selectedBarConfig?.enabled ?? false) && !SettingsData.frameEnabled visible: dankBarTab.appearanceOnly && (selectedBarConfig?.enabled ?? false) && !SettingsData.frameEnabled
SettingsSliderRow { SettingsSliderRow {
id: edgeSpacingSlider id: edgeSpacingSlider
@@ -956,68 +1020,6 @@ Item {
} }
} }
SettingsCard {
tab: "appearance"
iconName: "opacity"
title: I18n.tr("Transparency")
settingKey: "barTransparency"
visible: dankBarTab.appearanceOnly && selectedBarConfig?.enabled
SettingsSliderRow {
id: barTransparencySlider
visible: !SettingsData.frameEnabled
text: I18n.tr("Bar Transparency")
description: I18n.tr("Opacity of the bar background")
value: (selectedBarConfig?.transparency ?? 1.0) * 100
minimum: 0
maximum: 100
unit: "%"
defaultValue: 100
onSliderDragFinished: finalValue => {
SettingsData.updateBarConfig(selectedBarId, {
transparency: finalValue / 100
});
}
Binding {
target: barTransparencySlider
property: "value"
value: (selectedBarConfig?.transparency ?? 1.0) * 100
restoreMode: Binding.RestoreBinding
}
}
SettingsSliderRow {
id: widgetTransparencySlider
text: I18n.tr("Widget Transparency")
description: I18n.tr("Opacity of widget backgrounds")
value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100
minimum: 0
maximum: 100
unit: "%"
defaultValue: 100
onSliderDragFinished: finalValue => {
SettingsData.updateBarConfig(selectedBarId, {
widgetTransparency: finalValue / 100
});
}
Binding {
target: widgetTransparencySlider
property: "value"
value: (selectedBarConfig?.widgetTransparency ?? 1.0) * 100
restoreMode: Binding.RestoreBinding
}
}
SettingsControlledByFrame {
visible: SettingsData.frameEnabled
parentModal: dankBarTab.parentModal
settingLabel: I18n.tr("Bar Transparency")
reason: I18n.tr("Managed by Frame")
}
}
SettingsSliderCard { SettingsSliderCard {
id: fontScaleSliderCard id: fontScaleSliderCard
tab: "appearance" tab: "appearance"
@@ -1358,7 +1360,7 @@ Item {
SettingsSliderRow { SettingsSliderRow {
id: borderOpacitySlider id: borderOpacitySlider
text: I18n.tr("Opacity") text: I18n.tr("Opacity")
description: I18n.tr("Transparency of the border") description: I18n.tr("Controls opacity of the border")
value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100 value: (selectedBarConfig?.borderOpacity ?? 1.0) * 100
minimum: 0 minimum: 0
maximum: 100 maximum: 100
@@ -1453,7 +1455,7 @@ Item {
SettingsSliderRow { SettingsSliderRow {
id: widgetOutlineOpacitySlider id: widgetOutlineOpacitySlider
text: I18n.tr("Opacity") text: I18n.tr("Opacity")
description: I18n.tr("Transparency of the widget outline") description: I18n.tr("Controls opacity of the widget outline")
value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100 value: (selectedBarConfig?.widgetOutlineOpacity ?? 1.0) * 100
minimum: 0 minimum: 0
maximum: 100 maximum: 100
@@ -1562,7 +1564,7 @@ Item {
SettingsSliderRow { SettingsSliderRow {
visible: shadowCard.shadowActive visible: shadowCard.shadowActive
text: I18n.tr("Opacity") text: I18n.tr("Opacity")
description: I18n.tr("Transparency of the shadow layer") description: I18n.tr("Controls opacity of the shadow layer")
minimum: 10 minimum: 10
maximum: 100 maximum: 100
unit: "%" unit: "%"
@@ -1740,6 +1742,19 @@ Item {
} }
} }
SettingsToggleCard {
iconName: "touch_app"
title: I18n.tr("Hover Popouts")
description: I18n.tr("Open widget popouts by hovering over the bar. Moving to another widget switches the popout.")
visible: !dankBarTab.appearanceOnly && selectedBarConfig?.enabled
enabled: !(selectedBarConfig?.clickThrough ?? false)
opacity: (selectedBarConfig?.clickThrough ?? false) ? 0.5 : 1.0
checked: selectedBarConfig?.hoverPopouts ?? false
onToggled: checked => SettingsData.updateBarConfig(selectedBarId, {
hoverPopouts: checked
})
}
SettingsToggleCard { SettingsToggleCard {
iconName: "mouse" iconName: "mouse"
title: I18n.tr("Scroll Wheel") title: I18n.tr("Scroll Wheel")
+3 -3
View File
@@ -643,19 +643,19 @@ Item {
SettingsControlledByFrame { SettingsControlledByFrame {
visible: root.connectedFrameModeActive visible: root.connectedFrameModeActive
parentModal: root.parentModal parentModal: root.parentModal
settingLabel: I18n.tr("Dock margin, transparency, and border") settingLabel: I18n.tr("Dock margin, opacity, and border")
reason: I18n.tr("Managed by Frame in Connected Mode") reason: I18n.tr("Managed by Frame in Connected Mode")
} }
SettingsCard { SettingsCard {
width: parent.width width: parent.width
iconName: "opacity" iconName: "opacity"
title: I18n.tr("Transparency") title: I18n.tr("Opacity")
settingKey: "dockTransparency" settingKey: "dockTransparency"
visible: !root.connectedFrameModeActive visible: !root.connectedFrameModeActive
SettingsSliderRow { SettingsSliderRow {
text: I18n.tr("Dock Transparency") text: I18n.tr("Dock Opacity")
value: Math.round(SettingsData.dockTransparency * 100) value: Math.round(SettingsData.dockTransparency * 100)
minimum: 0 minimum: 0
maximum: 100 maximum: 100
+111 -103
View File
@@ -1639,7 +1639,7 @@ Item {
SettingsControlledByFrame { SettingsControlledByFrame {
visible: themeColorsTab.connectedFrameModeActive visible: themeColorsTab.connectedFrameModeActive
parentModal: themeColorsTab.parentModal parentModal: themeColorsTab.parentModal
settingLabel: I18n.tr("Transparency") settingLabel: I18n.tr("Surface Opacity")
reason: I18n.tr("Managed by Frame in Connected Mode") reason: I18n.tr("Managed by Frame in Connected Mode")
} }
@@ -1647,8 +1647,8 @@ Item {
tab: "theme" tab: "theme"
tags: ["surface", "popup", "transparency", "opacity", "modal"] tags: ["surface", "popup", "transparency", "opacity", "modal"]
settingKey: "popupTransparency" settingKey: "popupTransparency"
text: I18n.tr("Transparency") text: I18n.tr("Surface Opacity")
description: I18n.tr("Controls opacity of all popouts, modals, and their content layers") description: I18n.tr("Controls opacity of shell surfaces, popouts, and modals")
visible: !themeColorsTab.connectedFrameModeActive visible: !themeColorsTab.connectedFrameModeActive
value: Math.round(SettingsData.popupTransparency * 100) value: Math.round(SettingsData.popupTransparency * 100)
minimum: 0 minimum: 0
@@ -1671,6 +1671,113 @@ Item {
defaultValue: 12 defaultValue: 12
onSliderValueChanged: newValue => SettingsData.setCornerRadius(newValue) onSliderValueChanged: newValue => SettingsData.setCornerRadius(newValue)
} }
}
SettingsCard {
tab: "theme"
tags: ["blur", "background", "transparency", "glass", "frosted"]
title: I18n.tr("Background Blur")
settingKey: "blurEnabled"
iconName: "blur_on"
SettingsToggleRow {
tab: "theme"
tags: ["blur", "background", "transparency", "glass", "frosted"]
settingKey: "blurEnabled"
text: I18n.tr("Background Blur")
description: !BlurService.available ? I18n.tr("Your compositor does not support background blur (ext-background-effect-v1)") : I18n.tr("Blur the background behind bars, popouts, modals, and notifications. Requires compositor support. Adjust Opacity accordingly.")
checked: SettingsData.blurEnabled ?? false
enabled: BlurService.available
onToggled: checked => SettingsData.set("blurEnabled", checked)
}
SettingsToggleRow {
tab: "theme"
tags: ["blur", "foreground", "layers", "contrast", "glass", "frosted"]
settingKey: "blurForegroundLayers"
text: I18n.tr("Foreground Layers")
description: I18n.tr("Show foreground surfaces on blurred panels for stronger contrast")
checked: SettingsData.blurForegroundLayers ?? true
visible: BlurService.available && (SettingsData.blurEnabled ?? false)
enabled: BlurService.available
onToggled: checked => SettingsData.set("blurForegroundLayers", checked)
}
SettingsSliderRow {
tab: "theme"
tags: ["blur", "foreground", "layers", "outline", "border", "cards", "widgets", "notifications", "control center"]
settingKey: "blurLayerOutlineOpacity"
text: I18n.tr("Layer Outline Opacity")
description: I18n.tr("Controls outlines around blurred foreground cards, pills, and notification cards")
visible: BlurService.available && (SettingsData.blurEnabled ?? false)
value: Math.round((SettingsData.blurLayerOutlineOpacity ?? 0.12) * 100)
minimum: 0
maximum: 40
unit: "%"
defaultValue: 12
onSliderValueChanged: newValue => SettingsData.set("blurLayerOutlineOpacity", newValue / 100)
}
SettingsDropdownRow {
tab: "theme"
tags: ["blur", "border", "outline", "edge"]
settingKey: "blurBorderColor"
text: I18n.tr("Blur Border Color")
description: I18n.tr("Border color around blurred surfaces")
visible: SettingsData.blurEnabled
options: [I18n.tr("Outline", "blur border color"), I18n.tr("Primary", "blur border color"), I18n.tr("Secondary", "blur border color"), I18n.tr("Text Color", "blur border color"), I18n.tr("Custom", "blur border color")]
currentValue: {
switch (SettingsData.blurBorderColor) {
case "primary":
return I18n.tr("Primary", "blur border color");
case "secondary":
return I18n.tr("Secondary", "blur border color");
case "surfaceText":
return I18n.tr("Text Color", "blur border color");
case "custom":
return I18n.tr("Custom", "blur border color");
default:
return I18n.tr("Outline", "blur border color");
}
}
onValueChanged: value => {
if (value === I18n.tr("Primary", "blur border color")) {
SettingsData.set("blurBorderColor", "primary");
} else if (value === I18n.tr("Secondary", "blur border color")) {
SettingsData.set("blurBorderColor", "secondary");
} else if (value === I18n.tr("Text Color", "blur border color")) {
SettingsData.set("blurBorderColor", "surfaceText");
} else if (value === I18n.tr("Custom", "blur border color")) {
SettingsData.set("blurBorderColor", "custom");
openBlurBorderColorPicker();
} else {
SettingsData.set("blurBorderColor", "outline");
}
}
}
SettingsSliderRow {
tab: "theme"
tags: ["blur", "border", "opacity"]
settingKey: "blurBorderOpacity"
text: I18n.tr("Blur Border Opacity")
description: I18n.tr("Controls the outer edge of protocol-blurred windows")
visible: SettingsData.blurEnabled
value: Math.round((SettingsData.blurBorderOpacity ?? 0.35) * 100)
minimum: 0
maximum: 100
unit: "%"
defaultValue: 35
onSliderValueChanged: newValue => SettingsData.set("blurBorderOpacity", newValue / 100)
}
}
SettingsCard {
tab: "theme"
tags: ["elevation", "shadow", "lift", "m3", "material"]
title: I18n.tr("Shadows")
settingKey: "m3ElevationEnabled"
iconName: "layers"
SettingsToggleRow { SettingsToggleRow {
tab: "theme" tab: "theme"
@@ -1702,7 +1809,7 @@ Item {
tags: ["elevation", "shadow", "opacity", "transparency", "m3"] tags: ["elevation", "shadow", "opacity", "transparency", "m3"]
settingKey: "m3ElevationOpacity" settingKey: "m3ElevationOpacity"
text: I18n.tr("Shadow Opacity") text: I18n.tr("Shadow Opacity")
description: I18n.tr("Controls the transparency of the shadow") description: I18n.tr("Controls the opacity of the shadow")
value: SettingsData.m3ElevationOpacity ?? 30 value: SettingsData.m3ElevationOpacity ?? 30
minimum: 0 minimum: 0
maximum: 100 maximum: 100
@@ -1856,105 +1963,6 @@ Item {
} }
} }
SettingsCard {
tab: "theme"
tags: ["blur", "background", "transparency", "glass", "frosted"]
title: I18n.tr("Background Blur")
settingKey: "blurEnabled"
iconName: "blur_on"
SettingsToggleRow {
tab: "theme"
tags: ["blur", "background", "transparency", "glass", "frosted"]
settingKey: "blurEnabled"
text: I18n.tr("Background Blur")
description: !BlurService.available ? I18n.tr("Your compositor does not support background blur (ext-background-effect-v1)") : I18n.tr("Blur the background behind bars, popouts, modals, and notifications. Requires compositor support and configuration.")
checked: SettingsData.blurEnabled ?? false
enabled: BlurService.available
onToggled: checked => SettingsData.set("blurEnabled", checked)
}
SettingsToggleRow {
tab: "theme"
tags: ["blur", "foreground", "layers", "contrast", "glass", "frosted"]
settingKey: "blurForegroundLayers"
text: I18n.tr("Foreground Layers")
description: I18n.tr("Show foreground surfaces on blurred panels for stronger contrast")
checked: SettingsData.blurForegroundLayers ?? true
visible: BlurService.available && (SettingsData.blurEnabled ?? false)
enabled: BlurService.available
onToggled: checked => SettingsData.set("blurForegroundLayers", checked)
}
SettingsSliderRow {
tab: "theme"
tags: ["blur", "foreground", "layers", "outline", "border", "cards", "widgets", "notifications", "control center"]
settingKey: "blurLayerOutlineOpacity"
text: I18n.tr("Layer Outline Opacity")
description: I18n.tr("Controls outlines around blurred foreground cards, pills, and notification cards")
visible: BlurService.available && (SettingsData.blurEnabled ?? false)
value: Math.round((SettingsData.blurLayerOutlineOpacity ?? 0.12) * 100)
minimum: 0
maximum: 40
unit: "%"
defaultValue: 12
onSliderValueChanged: newValue => SettingsData.set("blurLayerOutlineOpacity", newValue / 100)
}
SettingsDropdownRow {
tab: "theme"
tags: ["blur", "border", "outline", "edge"]
settingKey: "blurBorderColor"
text: I18n.tr("Blur Border Color")
description: I18n.tr("Border color around blurred surfaces")
visible: SettingsData.blurEnabled
options: [I18n.tr("Outline", "blur border color"), I18n.tr("Primary", "blur border color"), I18n.tr("Secondary", "blur border color"), I18n.tr("Text Color", "blur border color"), I18n.tr("Custom", "blur border color")]
currentValue: {
switch (SettingsData.blurBorderColor) {
case "primary":
return I18n.tr("Primary", "blur border color");
case "secondary":
return I18n.tr("Secondary", "blur border color");
case "surfaceText":
return I18n.tr("Text Color", "blur border color");
case "custom":
return I18n.tr("Custom", "blur border color");
default:
return I18n.tr("Outline", "blur border color");
}
}
onValueChanged: value => {
if (value === I18n.tr("Primary", "blur border color")) {
SettingsData.set("blurBorderColor", "primary");
} else if (value === I18n.tr("Secondary", "blur border color")) {
SettingsData.set("blurBorderColor", "secondary");
} else if (value === I18n.tr("Text Color", "blur border color")) {
SettingsData.set("blurBorderColor", "surfaceText");
} else if (value === I18n.tr("Custom", "blur border color")) {
SettingsData.set("blurBorderColor", "custom");
openBlurBorderColorPicker();
} else {
SettingsData.set("blurBorderColor", "outline");
}
}
}
SettingsSliderRow {
tab: "theme"
tags: ["blur", "border", "opacity"]
settingKey: "blurBorderOpacity"
text: I18n.tr("Blur Border Opacity")
description: I18n.tr("Controls the outer edge of protocol-blurred windows")
visible: SettingsData.blurEnabled
value: Math.round((SettingsData.blurBorderOpacity ?? 0.35) * 100)
minimum: 0
maximum: 100
unit: "%"
defaultValue: 35
onSliderValueChanged: newValue => SettingsData.set("blurBorderOpacity", newValue / 100)
}
}
SettingsCard { SettingsCard {
tab: "theme" tab: "theme"
tags: ["modal", "darken", "background", "overlay"] tags: ["modal", "darken", "background", "overlay"]
+76 -86
View File
@@ -32,6 +32,8 @@ Variants {
color: "transparent" color: "transparent"
updatesEnabled: root.renderActive || root._settleFrames > 0
mask: Region { mask: Region {
item: Item {} item: Item {}
} }
@@ -84,20 +86,59 @@ Variants {
readonly property bool transitioning: transitionAnimation.running readonly property bool transitioning: transitionAnimation.running
property bool effectActive: false property bool effectActive: false
property bool _renderSettling: true
property bool _overviewBlurSettling: false
property bool useNextForEffect: false property bool useNextForEffect: false
property string pendingWallpaper: "" property string pendingWallpaper: ""
property string _deferredSource: "" property string _deferredSource: ""
readonly property bool overviewBlurActive: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview && currentWallpaper.source !== "" readonly property bool overviewBlurActive: CompositorService.isNiri && SettingsData.blurWallpaperOnOverview && NiriService.inOverview && currentWallpaper.source !== ""
readonly property var backingWindow: Window.window
readonly property bool renderActive: !source || effectActive || overviewBlurActive || pendingWallpaper !== "" || _deferredSource !== "" || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading
property int _settleFrames: 3
function invalidate() {
_settleFrames = 3;
backingWindow?.update();
}
onRenderActiveChanged: invalidate()
onBackingWindowChanged: invalidate()
Connections { Connections {
target: currentWallpaper target: root.backingWindow
function onStatusChanged() { function onFrameSwapped() {
if (currentWallpaper.status !== Image.Ready && currentWallpaper.status !== Image.Error) if (root._settleFrames > 0)
root._settleFrames--;
}
function onVisibleChanged() {
root.invalidate();
}
function onWidthChanged() {
root.invalidate();
}
function onHeightChanged() {
root.invalidate();
}
}
Connections {
target: Quickshell
function onScreensChanged() {
root.invalidate();
}
}
Connections {
target: SettingsData
function onWallpaperFillModeChanged() {
root.invalidate();
}
}
Connections {
target: IdleService
function onIsShellLockedChanged() {
if (IdleService.isShellLocked)
return; return;
root._renderSettling = true; root.invalidate();
renderSettleTimer.restart();
} }
} }
@@ -109,32 +150,11 @@ Variants {
} }
} }
Connections {
target: wallpaperWindow
function onWidthChanged() {
root._renderSettling = true;
renderSettleTimer.restart();
}
function onHeightChanged() {
root._renderSettling = true;
renderSettleTimer.restart();
}
}
Connections {
target: Quickshell
function onScreensChanged() {
root._renderSettling = true;
renderSettleTimer.restart();
}
}
Connections { Connections {
target: NiriService target: NiriService
function onDisplayScalesChanged() { function onDisplayScalesChanged() {
root._recheckScreenScale(); root._recheckScreenScale();
root._renderSettling = true; root.invalidate();
renderSettleTimer.restart();
} }
} }
@@ -142,29 +162,7 @@ Variants {
target: WlrOutputService target: WlrOutputService
function onWlrOutputAvailableChanged() { function onWlrOutputAvailableChanged() {
root._recheckScreenScale(); root._recheckScreenScale();
root._renderSettling = true; root.invalidate();
renderSettleTimer.restart();
}
}
Connections {
target: NiriService
function onInOverviewChanged() {
root._overviewBlurSettling = true;
overviewBlurSettleTimer.restart();
}
}
Connections {
target: SettingsData
function onBlurWallpaperOnOverviewChanged() {
root._overviewBlurSettling = true;
overviewBlurSettleTimer.restart();
}
function onWallpaperFillModeChanged() {
root._renderSettling = true;
renderSettleTimer.restart();
} }
} }
@@ -181,26 +179,22 @@ Variants {
} }
} }
Connections { function handleTransitionLoadError(failedSource) {
target: IdleService log.warn("failed to load candidate wallpaper for", modelData.name + ":", failedSource);
function onIsShellLockedChanged() { transitionDelayTimer.stop();
if (!IdleService.isShellLocked) { transitionAnimation.stop();
root._renderSettling = true; root.useNextForEffect = false;
renderSettleTimer.restart(); root.effectActive = false;
} root.transitionProgress = 0.0;
} currentWallpaper.layer.enabled = false;
} nextWallpaper.layer.enabled = false;
nextWallpaper.source = "";
Timer { if (!root.pendingWallpaper)
id: renderSettleTimer return;
interval: 1000 const pending = root.pendingWallpaper;
onTriggered: root._renderSettling = false root.pendingWallpaper = "";
} Qt.callLater(() => root.changeWallpaper(pending, true));
Timer {
id: overviewBlurSettleTimer
interval: 150
onTriggered: root._overviewBlurSettling = false
} }
function getFillMode(modeName) { function getFillMode(modeName) {
@@ -227,11 +221,6 @@ Variants {
} }
Component.onCompleted: { Component.onCompleted: {
wallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || root.overviewBlurActive || root._overviewBlurSettling || root.pendingWallpaper !== "" || root._deferredSource !== "" || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading);
if (!source) {
root._renderSettling = false;
}
isInitialized = true; isInitialized = true;
} }
@@ -262,8 +251,6 @@ Variants {
transitionAnimation.stop(); transitionAnimation.stop();
root.transitionProgress = 0.0; root.transitionProgress = 0.0;
root.effectActive = false; root.effectActive = false;
root._renderSettling = true;
renderSettleTimer.restart();
root.screenScale = CompositorService.getScreenScale(modelData); root.screenScale = CompositorService.getScreenScale(modelData);
currentWallpaper.source = newSource; currentWallpaper.source = newSource;
nextWallpaper.source = ""; nextWallpaper.source = "";
@@ -328,9 +315,6 @@ Variants {
break; break;
} }
root._renderSettling = true;
renderSettleTimer.restart();
nextWallpaper.source = newPath; nextWallpaper.source = newPath;
if (nextWallpaper.status === Image.Ready) if (nextWallpaper.status === Image.Ready)
@@ -339,7 +323,7 @@ Variants {
Loader { Loader {
anchors.fill: parent anchors.fill: parent
active: !root.source || root.isColorSource active: !root.source || root.isColorSource || currentWallpaper.status === Image.Error
asynchronous: true asynchronous: true
sourceComponent: DankBackdrop { sourceComponent: DankBackdrop {
@@ -364,6 +348,12 @@ Variants {
cache: true cache: true
sourceSize: Qt.size(root.textureWidth, root.textureHeight) sourceSize: Qt.size(root.textureWidth, root.textureHeight)
fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name))
onStatusChanged: {
if (status === Image.Error) {
log.warn("failed to load active wallpaper for", modelData.name + ":", source);
}
}
} }
Image { Image {
@@ -380,11 +370,13 @@ Variants {
fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name))
onStatusChanged: { onStatusChanged: {
if (status === Image.Error) {
root.handleTransitionLoadError(source);
return;
}
if (status !== Image.Ready) if (status !== Image.Ready)
return; return;
if (root.actualTransitionType === "none") { if (root.actualTransitionType === "none") {
root._renderSettling = true;
renderSettleTimer.restart();
currentWallpaper.source = source; currentWallpaper.source = source;
nextWallpaper.source = ""; nextWallpaper.source = "";
root.transitionProgress = 0.0; root.transitionProgress = 0.0;
@@ -632,8 +624,6 @@ Variants {
root.transitionProgress = 0.0; root.transitionProgress = 0.0;
currentWallpaper.layer.enabled = false; currentWallpaper.layer.enabled = false;
nextWallpaper.layer.enabled = false; nextWallpaper.layer.enabled = false;
root._renderSettling = true;
renderSettleTimer.restart();
root.effectActive = false; root.effectActive = false;
if (!root.pendingWallpaper) if (!root.pendingWallpaper)
+44
View File
@@ -24,6 +24,7 @@ Item {
property list<real> animationExitCurve: Theme.variantPopoutExitCurve property list<real> animationExitCurve: Theme.variantPopoutExitCurve
property bool suspendShadowWhileResizing: false property bool suspendShadowWhileResizing: false
property bool shouldBeVisible: false property bool shouldBeVisible: false
property bool hoverDismissEnabled: false
property var customKeyboardFocus: null property var customKeyboardFocus: null
property bool backgroundInteractive: true property bool backgroundInteractive: true
property bool contentHandlesKeys: false property bool contentHandlesKeys: false
@@ -82,6 +83,8 @@ Item {
readonly property real alignedY: impl.item ? impl.item.alignedY : 0 readonly property real alignedY: impl.item ? impl.item.alignedY : 0
readonly property real alignedWidth: impl.item ? impl.item.alignedWidth : 0 readonly property real alignedWidth: impl.item ? impl.item.alignedWidth : 0
readonly property real alignedHeight: impl.item ? impl.item.alignedHeight : 0 readonly property real alignedHeight: impl.item ? impl.item.alignedHeight : 0
readonly property real renderedAlignedY: impl.item ? (impl.item.renderedAlignedY ?? impl.item.alignedY) : 0
readonly property real renderedAlignedHeight: impl.item ? (impl.item.renderedAlignedHeight ?? impl.item.alignedHeight) : 0
readonly property real maskX: impl.item ? impl.item.maskX : 0 readonly property real maskX: impl.item ? impl.item.maskX : 0
readonly property real maskY: impl.item ? impl.item.maskY : 0 readonly property real maskY: impl.item ? impl.item.maskY : 0
readonly property real maskWidth: impl.item ? impl.item.maskWidth : 0 readonly property real maskWidth: impl.item ? impl.item.maskWidth : 0
@@ -172,6 +175,32 @@ Item {
impl.item.close(); impl.item.close();
} }
function cancelHoverDismiss() {
if (impl.item?.cancelHoverDismiss)
impl.item.cancelHoverDismiss();
}
function closeFromHoverDismiss() {
hoverDismissEnabled = false;
if (impl.item) {
impl.item.animationsEnabled = true;
impl.item.animationDuration = Math.round(Theme.expressiveDurations.expressiveDefaultSpatial);
impl.item.animationExitCurve = Theme.expressiveCurves.expressiveDefaultSpatial;
}
if (dashVisible !== undefined) {
dashVisible = false;
return;
}
if (notificationHistoryVisible !== undefined) {
notificationHistoryVisible = false;
return;
}
if (impl.item)
impl.item.close();
else
close();
}
function toggle() { function toggle() {
(shouldBeVisible || _pendingOpen) ? close() : open(); (shouldBeVisible || _pendingOpen) ? close() : open();
} }
@@ -210,6 +239,20 @@ Item {
impl.item.updateSurfacePosition(); impl.item.updateSurfacePosition();
} }
function containsGlobalPoint(gx, gy) {
if (!screen)
return false;
const presented = shouldBeVisible || (impl.item?.isClosing ?? false);
if (!presented)
return false;
const padding = 24;
const x = alignedX - padding;
const y = renderedAlignedY - padding;
const w = alignedWidth + padding * 2;
const h = renderedAlignedHeight + padding * 2;
return gx >= x && gx <= x + w && gy >= y && gy <= y + h;
}
Loader { Loader {
id: impl id: impl
active: root.screen !== null active: root.screen !== null
@@ -261,6 +304,7 @@ Item {
it.screen = Qt.binding(() => root.screen); it.screen = Qt.binding(() => root.screen);
it.effectiveBarPosition = Qt.binding(() => root.effectiveBarPosition); it.effectiveBarPosition = Qt.binding(() => root.effectiveBarPosition);
it.effectiveBarBottomGap = Qt.binding(() => root.effectiveBarBottomGap); it.effectiveBarBottomGap = Qt.binding(() => root.effectiveBarBottomGap);
it.hoverDismissEnabled = Qt.binding(() => root.hoverDismissEnabled);
it.shouldBeVisible = root.shouldBeVisible; it.shouldBeVisible = root.shouldBeVisible;
if (root._primeContent && typeof it.primeContent === "function") if (root._primeContent && typeof it.primeContent === "function")
@@ -5,6 +5,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets
Item { Item {
id: root id: root
@@ -407,6 +408,20 @@ Item {
onFrameOwnsConnectedChromeChanged: _syncPopoutChromeState() onFrameOwnsConnectedChromeChanged: _syncPopoutChromeState()
property bool animationsEnabled: true property bool animationsEnabled: true
property bool hoverDismissEnabled: false
function cancelHoverDismiss() {
hoverDismissTracker.cancelPending();
}
function closeFromHoverDismiss() {
if (isClosing || !shouldBeVisible)
return;
if (popoutHandle?.closeFromHoverDismiss)
popoutHandle.closeFromHoverDismiss();
else
close();
}
function open() { function open() {
if (!screen) if (!screen)
@@ -761,6 +776,27 @@ Item {
visible: false visible: false
color: "transparent" color: "transparent"
MouseArea {
anchors.fill: parent
z: -1
acceptedButtons: Qt.NoButton
hoverEnabled: true
onPositionChanged: mouse => {
const gp = mapToItem(null, mouse.x, mouse.y);
PopoutManager.updateHoverCursor(gp.x, gp.y);
}
}
HoverDismissTracker {
id: hoverDismissTracker
anchors.fill: parent
enabled: root.hoverDismissEnabled && root.shouldBeVisible
shouldDismiss: function () {
return !PopoutManager.cursorOverBar(PopoutManager.hoverCursorGlobalX, PopoutManager.hoverCursorGlobalY);
}
onDismissRequested: root.closeFromHoverDismiss()
}
WindowBlur { WindowBlur {
id: popoutBlur id: popoutBlur
targetWindow: contentWindow targetWindow: contentWindow
@@ -5,6 +5,7 @@ import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets
Item { Item {
id: root id: root
@@ -35,6 +36,21 @@ Item {
property bool shouldBeVisible: false property bool shouldBeVisible: false
property bool isClosing: false property bool isClosing: false
property bool animationsEnabled: true property bool animationsEnabled: true
property bool hoverDismissEnabled: false
function cancelHoverDismiss() {
hoverDismissTracker.cancelPending();
}
function closeFromHoverDismiss() {
if (isClosing || !shouldBeVisible)
return;
if (popoutHandle?.closeFromHoverDismiss)
popoutHandle.closeFromHoverDismiss();
else
close();
}
property var customKeyboardFocus: null property var customKeyboardFocus: null
property bool backgroundInteractive: true property bool backgroundInteractive: true
property bool contentHandlesKeys: false property bool contentHandlesKeys: false
@@ -585,6 +601,27 @@ Item {
color: "transparent" color: "transparent"
readonly property bool closeVisualActive: root.shouldBeVisible || root.isClosing readonly property bool closeVisualActive: root.shouldBeVisible || root.isClosing
MouseArea {
anchors.fill: parent
z: -1
acceptedButtons: Qt.NoButton
hoverEnabled: true
onPositionChanged: mouse => {
const gp = mapToItem(null, mouse.x, mouse.y);
PopoutManager.updateHoverCursor(gp.x, gp.y);
}
}
HoverDismissTracker {
id: hoverDismissTracker
anchors.fill: parent
enabled: root.hoverDismissEnabled && root.shouldBeVisible
shouldDismiss: function () {
return !PopoutManager.cursorOverBar(PopoutManager.hoverCursorGlobalX, PopoutManager.hoverCursorGlobalY);
}
onDismissRequested: root.closeFromHoverDismiss()
}
WindowBlur { WindowBlur {
id: popoutBlur id: popoutBlur
targetWindow: contentWindow targetWindow: contentWindow
+43 -1
View File
@@ -13,6 +13,7 @@ PanelWindow {
WlrLayershell.namespace: layerNamespace WlrLayershell.namespace: layerNamespace
property bool isVisible: false property bool isVisible: false
property bool hoverDismissEnabled: false
property var targetScreen: null property var targetScreen: null
property var modelData: null property var modelData: null
property bool triggerUsesOverlayLayer: false property bool triggerUsesOverlayLayer: false
@@ -39,6 +40,24 @@ PanelWindow {
isVisible = false; isVisible = false;
} }
function hideFromHoverDismiss() {
hoverDismissEnabled = false;
slideAnimation.duration = Math.round(Theme.expressiveDurations.expressiveDefaultSpatial);
hide();
}
function cancelHoverDismiss() {
hoverDismissTracker.cancelPending();
}
function containsGlobalPoint(gx, gy) {
if (!isVisible || !modelData)
return false;
const padding = 24;
const topLeft = slideContainer.mapToItem(null, 0, 0);
return gx >= topLeft.x - padding && gx < topLeft.x + slideContainer.width + padding && gy >= topLeft.y - padding && gy < topLeft.y + slideContainer.height + padding;
}
function toggle() { function toggle() {
if (isVisible) { if (isVisible) {
hide(); hide();
@@ -60,6 +79,27 @@ PanelWindow {
color: "transparent" color: "transparent"
MouseArea {
anchors.fill: parent
z: -1
acceptedButtons: Qt.NoButton
hoverEnabled: true
onPositionChanged: mouse => {
const gp = mapToItem(null, mouse.x, mouse.y);
PopoutManager.updateHoverCursor(gp.x, gp.y);
}
}
HoverDismissTracker {
id: hoverDismissTracker
anchors.fill: parent
enabled: root.hoverDismissEnabled && root.isVisible
shouldDismiss: function () {
return !PopoutManager.cursorOverBar(PopoutManager.hoverCursorGlobalX, PopoutManager.hoverCursorGlobalY);
}
onDismissRequested: root.hideFromHoverDismiss()
}
readonly property bool slideoutBlurActive: root.visible && BlurService.enabled && Theme.connectedSurfaceBlurEnabled readonly property bool slideoutBlurActive: root.visible && BlurService.enabled && Theme.connectedSurfaceBlurEnabled
WlrLayershell.layer: (triggerUsesOverlayLayer || CompositorService.framePeerSurfacesUseOverlayForScreen(modelData)) ? WlrLayershell.Overlay : WlrLayershell.Top WlrLayershell.layer: (triggerUsesOverlayLayer || CompositorService.framePeerSurfacesUseOverlayForScreen(modelData)) ? WlrLayershell.Overlay : WlrLayershell.Top
@@ -104,8 +144,10 @@ PanelWindow {
easing.type: Easing.OutCubic easing.type: Easing.OutCubic
onRunningChanged: { onRunningChanged: {
if (!running && !root.isVisible) { if (!running) {
if (!root.isVisible)
root.mappedVisible = false; root.mappedVisible = false;
slideAnimation.duration = 450;
} }
} }
} }
@@ -0,0 +1,28 @@
pragma ComponentBehavior: Bound
import QtQuick
Item {
id: root
property bool enabled: false
property var shouldDismiss: null
signal dismissRequested
anchors.fill: parent
HoverHandler {
id: hoverHandler
enabled: root.enabled
onHoveredChanged: {
if (hoverHandler.hovered || !root.enabled)
return;
if (typeof root.shouldDismiss === "function" && !root.shouldDismiss())
return;
root.dismissRequested();
}
}
function cancelPending() {}
}
@@ -546,6 +546,7 @@ def main():
output_path = script_dir / "settings_search_index.json" output_path = script_dir / "settings_search_index.json"
with open(output_path, "w", encoding="utf-8") as f: with open(output_path, "w", encoding="utf-8") as f:
json.dump(all_entries, f, indent=2, ensure_ascii=False) json.dump(all_entries, f, indent=2, ensure_ascii=False)
f.write("\n")
print(f"Found {len(settings_entries)} searchable settings") print(f"Found {len(settings_entries)} searchable settings")
print(f"Found {len(tab_entries)} tab entries") print(f"Found {len(tab_entries)} tab entries")
+230 -149
View File
@@ -58,6 +58,7 @@
"targetable", "targetable",
"wallpaper" "wallpaper"
], ],
"icon": "blur_on",
"description": "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.", "description": "Enable compositor-targetable blur layer (namespace: dms:blurwallpaper). Requires manual niri configuration.",
"conditionKey": "isNiri" "conditionKey": "isNiri"
}, },
@@ -727,21 +728,6 @@
], ],
"icon": "dashboard" "icon": "dashboard"
}, },
{
"section": "_tab_3",
"label": "Dank Bar",
"tabIndex": 3,
"category": "Dank Bar",
"keywords": [
"bar",
"dank",
"panel",
"statusbar",
"taskbar",
"topbar"
],
"icon": "toolbar"
},
{ {
"section": "barDisplay", "section": "barDisplay",
"label": "Display Assignment", "label": "Display Assignment",
@@ -777,30 +763,19 @@
"icon": "vertical_align_center" "icon": "vertical_align_center"
}, },
{ {
"section": "barSpacing", "section": "_tab_3",
"label": "Spacing", "label": "Settings",
"tabIndex": 3, "tabIndex": 3,
"category": "Dank Bar", "category": "Dank Bar",
"keywords": [ "keywords": [
"bar", "bar",
"between",
"dank", "dank",
"edges",
"gap",
"gaps",
"margin",
"margins",
"padding",
"panel", "panel",
"screen", "settings",
"space",
"spacing",
"statusbar", "statusbar",
"taskbar",
"topbar" "topbar"
], ],
"icon": "space_bar", "icon": "tune"
"description": "Space between the bar and screen edges"
}, },
{ {
"section": "barUseOverlayLayer", "section": "barUseOverlayLayer",
@@ -1528,6 +1503,19 @@
"windows" "windows"
] ]
}, },
{
"section": "dockTransparency",
"label": "Opacity",
"tabIndex": 5,
"category": "Dock",
"keywords": [
"dock",
"launcher bar",
"opacity",
"taskbar"
],
"icon": "opacity"
},
{ {
"section": "dockTrashFileManager", "section": "dockTrashFileManager",
"label": "Open Trash With", "label": "Open Trash With",
@@ -1745,23 +1733,6 @@
], ],
"icon": "space_bar" "icon": "space_bar"
}, },
{
"section": "dockTransparency",
"label": "Transparency",
"tabIndex": 5,
"category": "Dock",
"keywords": [
"alpha",
"dock",
"launcher bar",
"opacity",
"taskbar",
"translucent",
"transparency",
"transparent"
],
"icon": "opacity"
},
{ {
"section": "dockTrash", "section": "dockTrash",
"label": "Trash", "label": "Trash",
@@ -1798,21 +1769,6 @@
], ],
"description": "Place the dock on the Wayland overlay layer" "description": "Place the dock on the Wayland overlay layer"
}, },
{
"section": "_tab_6",
"label": "Appearance",
"tabIndex": 6,
"category": "Dank Bar",
"keywords": [
"appearance",
"bar",
"dank",
"panel",
"statusbar",
"topbar"
],
"icon": "palette"
},
{ {
"section": "barBorder", "section": "barBorder",
"label": "Border", "label": "Border",
@@ -1862,6 +1818,21 @@
"icon": "rounded_corner", "icon": "rounded_corner",
"description": "Remove corner rounding from the bar" "description": "Remove corner rounding from the bar"
}, },
{
"section": "_tab_6",
"label": "Dank Bar",
"tabIndex": 6,
"category": "Dank Bar",
"keywords": [
"bar",
"dank",
"panel",
"statusbar",
"taskbar",
"topbar"
],
"icon": "toolbar"
},
{ {
"section": "barAppearance", "section": "barAppearance",
"label": "Dank Bar", "label": "Dank Bar",
@@ -1982,6 +1953,25 @@
], ],
"description": "Use a fixed shadow direction for this bar" "description": "Use a fixed shadow direction for this bar"
}, },
{
"section": "barTransparency",
"label": "Opacity",
"tabIndex": 6,
"category": "Dank Bar",
"keywords": [
"background",
"bar",
"controls",
"dank",
"opacity",
"panel",
"statusbar",
"taskbar",
"topbar"
],
"icon": "opacity",
"description": "Controls opacity of the bar background"
},
{ {
"section": "barShadow", "section": "barShadow",
"label": "Shadow Override", "label": "Shadow Override",
@@ -2002,6 +1992,32 @@
"icon": "layers", "icon": "layers",
"description": "Override the global shadow with per-bar settings" "description": "Override the global shadow with per-bar settings"
}, },
{
"section": "barSpacing",
"label": "Spacing",
"tabIndex": 6,
"category": "Dank Bar",
"keywords": [
"bar",
"between",
"dank",
"edges",
"gap",
"gaps",
"margin",
"margins",
"padding",
"panel",
"screen",
"space",
"spacing",
"statusbar",
"taskbar",
"topbar"
],
"icon": "space_bar",
"description": "Space between the bar and screen edges"
},
{ {
"section": "trayIconTint", "section": "trayIconTint",
"label": "System Tray Icon Tint", "label": "System Tray Icon Tint",
@@ -2030,28 +2046,6 @@
"icon": "filter_b_and_w", "icon": "filter_b_and_w",
"description": "Controls how much original icon color is removed before applying tint" "description": "Controls how much original icon color is removed before applying tint"
}, },
{
"section": "barTransparency",
"label": "Transparency",
"tabIndex": 6,
"category": "Dank Bar",
"keywords": [
"alpha",
"background",
"bar",
"dank",
"opacity",
"panel",
"statusbar",
"taskbar",
"topbar",
"translucent",
"transparency",
"transparent"
],
"icon": "opacity",
"description": "Opacity of the bar background"
},
{ {
"section": "barWidgetOutline", "section": "barWidgetOutline",
"label": "Widget Outline", "label": "Widget Outline",
@@ -3792,7 +3786,6 @@
"tabIndex": 10, "tabIndex": 10,
"category": "Theme & Colors", "category": "Theme & Colors",
"keywords": [ "keywords": [
"alpha",
"appearance", "appearance",
"colors", "colors",
"controls", "controls",
@@ -3804,11 +3797,9 @@
"shadow", "shadow",
"style", "style",
"theme", "theme",
"translucent", "transparency"
"transparency",
"transparent"
], ],
"description": "Controls the transparency of the shadow" "description": "Controls the opacity of the shadow"
}, },
{ {
"section": "m3ElevationEnabled", "section": "m3ElevationEnabled",
@@ -3833,8 +3824,34 @@
"style", "style",
"theme" "theme"
], ],
"icon": "layers",
"description": "Material inspired shadows and elevation on modals, popouts, and dialogs" "description": "Material inspired shadows and elevation on modals, popouts, and dialogs"
}, },
{
"section": "popupTransparency",
"label": "Surface Opacity",
"tabIndex": 10,
"category": "Theme & Colors",
"keywords": [
"appearance",
"colors",
"controls",
"look",
"modal",
"modals",
"opacity",
"popouts",
"popup",
"scheme",
"shell",
"style",
"surface",
"surfaces",
"theme",
"transparency"
],
"description": "Controls opacity of shell surfaces, popouts, and modals"
},
{ {
"section": "syncModeWithPortal", "section": "syncModeWithPortal",
"label": "Sync Mode with Portal", "label": "Sync Mode with Portal",
@@ -3966,35 +3983,6 @@
"icon": "palette", "icon": "palette",
"description": "Select the palette algorithm used for wallpaper-based colors" "description": "Select the palette algorithm used for wallpaper-based colors"
}, },
{
"section": "popupTransparency",
"label": "Transparency",
"tabIndex": 10,
"category": "Theme & Colors",
"keywords": [
"alpha",
"appearance",
"colors",
"content",
"controls",
"layers",
"look",
"modal",
"modals",
"opacity",
"popouts",
"popup",
"scheme",
"style",
"surface",
"their",
"theme",
"translucent",
"transparency",
"transparent"
],
"description": "Controls opacity of all popouts, modals, and their content layers"
},
{ {
"section": "matugenTemplateVscode", "section": "matugenTemplateVscode",
"label": "VS Code", "label": "VS Code",
@@ -4563,6 +4551,27 @@
], ],
"description": "Automatically lock the screen when DMS starts" "description": "Automatically lock the screen when DMS starts"
}, },
{
"section": "lockBeforeSuspend",
"label": "Lock before suspend",
"tabIndex": 11,
"category": "Lock Screen",
"keywords": [
"automatic",
"automatically",
"before",
"lock",
"login",
"password",
"prepares",
"screen",
"security",
"sleep",
"suspend",
"system"
],
"description": "Automatically lock the screen when the system prepares to suspend"
},
{ {
"section": "lockScreenNotificationMode", "section": "lockScreenNotificationMode",
"label": "Notification Display", "label": "Notification Display",
@@ -5470,6 +5479,26 @@
], ],
"icon": "dashboard" "icon": "dashboard"
}, },
{
"section": "notificationBodyFontSize",
"label": "Body Font Size",
"tabIndex": 17,
"category": "Notifications",
"keywords": [
"alert",
"alerts",
"body",
"font",
"messages",
"notif",
"notification",
"notifications",
"size",
"text",
"toast"
],
"description": "Set the font size for notification body text (htmlBody)"
},
{ {
"section": "notificationCompactMode", "section": "notificationCompactMode",
"label": "Compact", "label": "Compact",
@@ -5867,22 +5896,19 @@
"keywords": [ "keywords": [
"alert", "alert",
"alerts", "alerts",
"appear", "font",
"choose",
"location",
"messages", "messages",
"notif", "notif",
"notification", "notification",
"notifications", "notifications",
"popup",
"popups", "popups",
"position", "size",
"screen", "summary",
"toast", "text",
"where" "toast"
], ],
"icon": "notifications", "icon": "notifications",
"description": "Choose where notification popups appear on screen" "description": "Set the font size for notification summary text"
}, },
{ {
"section": "notificationRules", "section": "notificationRules",
@@ -6032,6 +6058,26 @@
], ],
"description": "Hide notification content until expanded; popups show collapsed by default" "description": "Hide notification content until expanded; popups show collapsed by default"
}, },
{
"section": "notificationSummaryFontSize",
"label": "Summary Font Size",
"tabIndex": 17,
"category": "Notifications",
"keywords": [
"alert",
"alerts",
"font",
"messages",
"notif",
"notification",
"notifications",
"size",
"summary",
"text",
"toast"
],
"description": "Set the font size for notification summary text"
},
{ {
"section": "notificationDedupeEnabled", "section": "notificationDedupeEnabled",
"label": "Suppress Duplicate Notifications", "label": "Suppress Duplicate Notifications",
@@ -6054,6 +6100,32 @@
"toast" "toast"
] ]
}, },
{
"section": "notificationShowTimeoutBar",
"label": "Timeout Progress Bar",
"tabIndex": 17,
"category": "Notifications",
"keywords": [
"alerts",
"bar",
"countdown",
"drains",
"messages",
"notification",
"notifications",
"panel",
"popup",
"progress",
"show",
"statusbar",
"taskbar",
"timeout",
"timer",
"toast",
"topbar"
],
"description": "Show a bar that drains as the popup"
},
{ {
"section": "osdAlwaysShowValue", "section": "osdAlwaysShowValue",
"label": "Always Show Percentage", "label": "Always Show Percentage",
@@ -6697,27 +6769,6 @@
"icon": "schedule", "icon": "schedule",
"description": "Gradually fade the screen before locking with a configurable grace period" "description": "Gradually fade the screen before locking with a configurable grace period"
}, },
{
"section": "lockBeforeSuspend",
"label": "Lock before suspend",
"tabIndex": 21,
"category": "Power & Sleep",
"keywords": [
"automatically",
"before",
"energy",
"lock",
"power",
"prepares",
"screen",
"security",
"shutdown",
"sleep",
"suspend",
"system"
],
"description": "Automatically lock the screen when the system prepares to suspend"
},
{ {
"section": "fadeToLockGracePeriod", "section": "fadeToLockGracePeriod",
"label": "Lock fade grace period", "label": "Lock fade grace period",
@@ -7119,6 +7170,36 @@
], ],
"description": "Maximum number of entries that can be saved" "description": "Maximum number of entries that can be saved"
}, },
{
"section": "clipboardVisibleEntryActions",
"label": "Visible Entry Actions",
"tabIndex": 23,
"category": "System",
"keywords": [
"action",
"actions",
"appear",
"buttons",
"choose",
"clipboard",
"cliphist",
"copy",
"delete",
"density",
"edit",
"entries",
"entry",
"hide",
"history",
"linux",
"os",
"paste",
"pin",
"system",
"visible"
],
"description": "Choose which action buttons appear on clipboard entries"
},
{ {
"section": "_tab_24", "section": "_tab_24",
"label": "Displays", "label": "Displays",
@@ -8399,7 +8480,7 @@
"topbar", "topbar",
"window" "window"
], ],
"icon": "crop_square", "icon": "layers",
"description": "Use custom gaps instead of bar spacing", "description": "Use custom gaps instead of bar spacing",
"conditionKey": "isNiri" "conditionKey": "isNiri"
}, },