mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-08 06:28:27 -04:00
refactor(Xray): Update Xray & standalone to frame transitions
- Fix dbar autohide with Xray options that could have blocked bar area content - Fixes #2729
This commit is contained in:
@@ -55,7 +55,7 @@ Singleton {
|
|||||||
|
|
||||||
readonly property bool isDirectionalEffect: isConnectedEffect || _effect === 1
|
readonly property bool isDirectionalEffect: isConnectedEffect || _effect === 1
|
||||||
readonly property bool isDepthEffect: _effect === 2
|
readonly property bool isDepthEffect: _effect === 2
|
||||||
readonly property bool isConnectedEffect: (typeof SettingsData !== "undefined") && SettingsData.connectedFrameModeActive
|
readonly property bool isConnectedEffect: (typeof FrameTransitionState !== "undefined") && FrameTransitionState.effectiveConnectedFrameModeActive
|
||||||
|
|
||||||
readonly property real effectScaleCollapsed: _effectScaleCollapsed[_effect] !== undefined ? _effectScaleCollapsed[_effect] : 0.96
|
readonly property real effectScaleCollapsed: _effectScaleCollapsed[_effect] !== undefined ? _effectScaleCollapsed[_effect] : 0.96
|
||||||
readonly property real effectAnimOffset: _effectAnimOffsets[_effect] !== undefined ? _effectAnimOffsets[_effect] : 16
|
readonly property real effectAnimOffset: _effectAnimOffsets[_effect] !== undefined ? _effectAnimOffsets[_effect] : 16
|
||||||
|
|||||||
@@ -0,0 +1,56 @@
|
|||||||
|
pragma Singleton
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
|
||||||
|
Singleton {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property int revision: 0
|
||||||
|
property int appliedRevision: 0
|
||||||
|
readonly property bool ready: appliedRevision >= revision
|
||||||
|
|
||||||
|
// Latched: surfaces render the last compositor-acknowledged state until the atomic flip on ack
|
||||||
|
property bool effectiveFrameEnabled: false
|
||||||
|
property string effectiveFrameMode: "connected"
|
||||||
|
readonly property bool effectiveConnectedFrameModeActive: effectiveFrameEnabled && effectiveFrameMode === "connected"
|
||||||
|
|
||||||
|
signal transitionRequested(int revision)
|
||||||
|
|
||||||
|
function begin() {
|
||||||
|
revision++;
|
||||||
|
transitionRequested(revision);
|
||||||
|
return revision;
|
||||||
|
}
|
||||||
|
|
||||||
|
function acknowledge(requestRevision) {
|
||||||
|
if (requestRevision > appliedRevision)
|
||||||
|
appliedRevision = requestRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
function syncEffective() {
|
||||||
|
effectiveFrameEnabled = SettingsData.frameEnabled;
|
||||||
|
effectiveFrameMode = SettingsData.frameMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
onReadyChanged: {
|
||||||
|
if (ready)
|
||||||
|
syncEffective();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracks settings-load changes; live toggles begin() first (ready false) so the latch holds
|
||||||
|
Connections {
|
||||||
|
target: SettingsData
|
||||||
|
function onFrameEnabledChanged() {
|
||||||
|
if (root.ready)
|
||||||
|
root.syncEffective();
|
||||||
|
}
|
||||||
|
function onFrameModeChanged() {
|
||||||
|
if (root.ready)
|
||||||
|
root.syncEffective();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component.onCompleted: syncEffective()
|
||||||
|
}
|
||||||
@@ -266,7 +266,11 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
property bool frameEnabled: false
|
property bool frameEnabled: false
|
||||||
onFrameEnabledChanged: saveSettings()
|
onFrameEnabledChanged: {
|
||||||
|
saveSettings();
|
||||||
|
if (!_loading)
|
||||||
|
updateFrameCompositorLayout();
|
||||||
|
}
|
||||||
property real frameThickness: 16
|
property real frameThickness: 16
|
||||||
onFrameThicknessChanged: saveSettings()
|
onFrameThicknessChanged: saveSettings()
|
||||||
property int barInsetPaddingShared: -1
|
property int barInsetPaddingShared: -1
|
||||||
@@ -299,7 +303,11 @@ Singleton {
|
|||||||
onFrameLauncherEdgeHoverChanged: saveSettings()
|
onFrameLauncherEdgeHoverChanged: saveSettings()
|
||||||
readonly property string frameModalEmergeSide: frameLauncherEmergeSide === "top" ? "bottom" : "top"
|
readonly property string frameModalEmergeSide: frameLauncherEmergeSide === "top" ? "bottom" : "top"
|
||||||
property string frameMode: "connected"
|
property string frameMode: "connected"
|
||||||
onFrameModeChanged: saveSettings()
|
onFrameModeChanged: {
|
||||||
|
saveSettings();
|
||||||
|
if (!_loading && frameEnabled)
|
||||||
|
updateFrameCompositorLayout();
|
||||||
|
}
|
||||||
property var connectedFrameBarStyleBackups: ({})
|
property var connectedFrameBarStyleBackups: ({})
|
||||||
onConnectedFrameBarStyleBackupsChanged: saveSettings()
|
onConnectedFrameBarStyleBackupsChanged: saveSettings()
|
||||||
readonly property bool connectedFrameModeActive: frameEnabled && frameMode === "connected"
|
readonly property bool connectedFrameModeActive: frameEnabled && frameMode === "connected"
|
||||||
@@ -1012,6 +1020,13 @@ Singleton {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
function _standaloneBarXrayAvailable(configs) {
|
||||||
|
const activeBars = (configs || []).filter(c => c && c.enabled && (c.visible ?? true));
|
||||||
|
return activeBars.every(c => !c.autoHide);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property bool standaloneBarXrayAvailable: _standaloneBarXrayAvailable(barConfigs)
|
||||||
|
|
||||||
property bool desktopClockEnabled: false
|
property bool desktopClockEnabled: false
|
||||||
property string desktopClockStyle: "analog"
|
property string desktopClockStyle: "analog"
|
||||||
property real desktopClockTransparency: 0.8
|
property real desktopClockTransparency: 0.8
|
||||||
@@ -1456,6 +1471,17 @@ Singleton {
|
|||||||
MangoService.generateLayoutConfig();
|
MangoService.generateLayoutConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateFrameCompositorLayout() {
|
||||||
|
// Generate before begin() so compositor readiness is already pending at transitionRequested
|
||||||
|
if (typeof CompositorService !== "undefined") {
|
||||||
|
if (CompositorService.isNiri && typeof NiriService !== "undefined")
|
||||||
|
NiriService.generateNiriLayoutConfig(true);
|
||||||
|
if (CompositorService.isHyprland && typeof HyprlandService !== "undefined")
|
||||||
|
HyprlandService.generateLayoutConfig(true);
|
||||||
|
}
|
||||||
|
FrameTransitionState.begin();
|
||||||
|
}
|
||||||
|
|
||||||
function resolveIconTheme() {
|
function resolveIconTheme() {
|
||||||
if (iconThemePerMode && typeof SessionData !== "undefined" && SessionData.isLightMode)
|
if (iconThemePerMode && typeof SessionData !== "undefined" && SessionData.isLightMode)
|
||||||
return iconThemeLight;
|
return iconThemeLight;
|
||||||
@@ -2403,13 +2429,17 @@ Singleton {
|
|||||||
if (index === -1)
|
if (index === -1)
|
||||||
return;
|
return;
|
||||||
const positionChanged = updates.position !== undefined && configs[index].position !== updates.position;
|
const positionChanged = updates.position !== undefined && configs[index].position !== updates.position;
|
||||||
|
const barXrayTargetWasAvailable = _standaloneBarXrayAvailable(configs);
|
||||||
if (updates.autoHide === false || updates.visible === false)
|
if (updates.autoHide === false || updates.visible === false)
|
||||||
setBarIpcReveal(barId, false);
|
setBarIpcReveal(barId, false);
|
||||||
|
|
||||||
Object.assign(configs[index], updates);
|
Object.assign(configs[index], updates);
|
||||||
barConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs;
|
const sanitizedConfigs = _sanitizeBarConfigsForConnectedFrame(configs).configs;
|
||||||
|
barConfigs = sanitizedConfigs;
|
||||||
updateBarConfigs();
|
updateBarConfigs();
|
||||||
|
|
||||||
|
if (!frameEnabled && _standaloneBarXrayAvailable(sanitizedConfigs) !== barXrayTargetWasAvailable)
|
||||||
|
updateCompositorLayout();
|
||||||
if (positionChanged) {
|
if (positionChanged) {
|
||||||
NotificationService.dismissAllPopups();
|
NotificationService.dismissAllPopups();
|
||||||
}
|
}
|
||||||
@@ -3542,6 +3572,9 @@ Singleton {
|
|||||||
onLoaded: {
|
onLoaded: {
|
||||||
if (isGreeterMode)
|
if (isGreeterMode)
|
||||||
return;
|
return;
|
||||||
|
const wasLoaded = _hasLoaded;
|
||||||
|
const prevFrameEnabled = frameEnabled;
|
||||||
|
const prevFrameMode = frameMode;
|
||||||
_loading = true;
|
_loading = true;
|
||||||
_hasUnsavedChanges = false;
|
_hasUnsavedChanges = false;
|
||||||
try {
|
try {
|
||||||
@@ -3576,6 +3609,9 @@ Singleton {
|
|||||||
} finally {
|
} finally {
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
|
// External edits reload under _loading, which skips the per-property transition triggers
|
||||||
|
if (wasLoaded && !_parseError && (frameEnabled !== prevFrameEnabled || (frameEnabled && frameMode !== prevFrameMode)))
|
||||||
|
updateFrameCompositorLayout();
|
||||||
}
|
}
|
||||||
onLoadFailed: error => {
|
onLoadFailed: error => {
|
||||||
if (!isGreeterMode) {
|
if (!isGreeterMode) {
|
||||||
|
|||||||
@@ -1076,7 +1076,7 @@ Singleton {
|
|||||||
readonly property real connectedCornerRadius: {
|
readonly property real connectedCornerRadius: {
|
||||||
if (typeof SettingsData === "undefined")
|
if (typeof SettingsData === "undefined")
|
||||||
return 12;
|
return 12;
|
||||||
return SettingsData.connectedFrameModeActive ? SettingsData.frameRounding : cornerRadius;
|
return FrameTransitionState.effectiveConnectedFrameModeActive ? SettingsData.frameRounding : cornerRadius;
|
||||||
}
|
}
|
||||||
readonly property color connectedSurfaceColor: {
|
readonly property color connectedSurfaceColor: {
|
||||||
if (typeof SettingsData === "undefined")
|
if (typeof SettingsData === "undefined")
|
||||||
|
|||||||
+32
-8
@@ -173,6 +173,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
property bool barSurfacesLoaded: true
|
property bool barSurfacesLoaded: true
|
||||||
|
property int pendingFrameTransitionRevision: 0
|
||||||
|
|
||||||
function recreateBarSurfaces() {
|
function recreateBarSurfaces() {
|
||||||
log.info("Recreating bar surfaces, screens:", Quickshell.screens.length, Quickshell.screens.map(s => s.name).join(","));
|
log.info("Recreating bar surfaces, screens:", Quickshell.screens.length, Quickshell.screens.map(s => s.name).join(","));
|
||||||
@@ -181,9 +182,23 @@ Item {
|
|||||||
barSurfaceReloadAction.schedule();
|
barSurfaceReloadAction.schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Holds the bar rebuild until the compositor applies the layout, so the swap lands in one pass
|
||||||
|
function runPendingFrameTransition() {
|
||||||
|
if (pendingFrameTransitionRevision <= 0 || !CompositorService.frameCompositorLayoutReady)
|
||||||
|
return;
|
||||||
|
recreateBarSurfaces();
|
||||||
|
}
|
||||||
|
|
||||||
DeferredAction {
|
DeferredAction {
|
||||||
id: barSurfaceReloadAction
|
id: barSurfaceReloadAction
|
||||||
onTriggered: root.barSurfacesLoaded = true
|
onTriggered: {
|
||||||
|
// Ack first so the latch flips and new bars build directly in the post-transition state
|
||||||
|
if (root.pendingFrameTransitionRevision > 0 && CompositorService.frameCompositorLayoutReady) {
|
||||||
|
FrameTransitionState.acknowledge(root.pendingFrameTransitionRevision);
|
||||||
|
root.pendingFrameTransitionRevision = 0;
|
||||||
|
}
|
||||||
|
root.barSurfacesLoaded = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property string _barLayoutStateJson: {
|
property string _barLayoutStateJson: {
|
||||||
@@ -212,14 +227,23 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: FrameTransitionState
|
||||||
|
function onTransitionRequested(revision) {
|
||||||
|
root.pendingFrameTransitionRevision = Math.max(root.pendingFrameTransitionRevision, revision);
|
||||||
|
root.runPendingFrameTransition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: CompositorService
|
||||||
|
function onFrameCompositorLayoutReadyChanged() {
|
||||||
|
root.runPendingFrameTransition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: SettingsData
|
target: SettingsData
|
||||||
function onFrameEnabledChanged() {
|
|
||||||
root.recreateBarSurfaces();
|
|
||||||
}
|
|
||||||
function onConnectedFrameModeActiveChanged() {
|
|
||||||
root.recreateBarSurfaces();
|
|
||||||
}
|
|
||||||
function onForceDankBarLayoutRefresh() {
|
function onForceDankBarLayoutRefresh() {
|
||||||
root.recreateBarSurfaces();
|
root.recreateBarSurfaces();
|
||||||
}
|
}
|
||||||
@@ -234,7 +258,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: SettingsData.frameEnabled && SettingsData.frameLauncherEdgeHover
|
active: FrameTransitionState.effectiveFrameEnabled && SettingsData.frameLauncherEdgeHover
|
||||||
asynchronous: false
|
asynchronous: false
|
||||||
sourceComponent: FrameLauncherHoverZone {}
|
sourceComponent: FrameLauncherHoverZone {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ Item {
|
|||||||
impl.item.toggle();
|
impl.item.toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var _desiredBackend: SettingsData.connectedFrameModeActive ? connectedComp : standaloneComp
|
readonly property var _desiredBackend: FrameTransitionState.effectiveConnectedFrameModeActive ? connectedComp : standaloneComp
|
||||||
property var _resolvedBackend: null
|
property var _resolvedBackend: null
|
||||||
|
|
||||||
Component.onCompleted: _resolvedBackend = _desiredBackend
|
Component.onCompleted: _resolvedBackend = _desiredBackend
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ Item {
|
|||||||
|
|
||||||
property string preferredConnectedBarSide: SettingsData.frameModalEmergeSide
|
property string preferredConnectedBarSide: SettingsData.frameModalEmergeSide
|
||||||
|
|
||||||
readonly property bool frameConnectedMode: SettingsData.frameEnabled && Theme.isConnectedEffect && !!effectiveScreen && SettingsData.isScreenInPreferences(effectiveScreen, SettingsData.frameScreenPreferences)
|
readonly property bool frameConnectedMode: FrameTransitionState.effectiveFrameEnabled && Theme.isConnectedEffect && !!effectiveScreen && SettingsData.isScreenInPreferences(effectiveScreen, SettingsData.frameScreenPreferences)
|
||||||
|
|
||||||
readonly property string resolvedConnectedBarSide: frameConnectedMode ? preferredConnectedBarSide : ""
|
readonly property string resolvedConnectedBarSide: frameConnectedMode ? preferredConnectedBarSide : ""
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ Item {
|
|||||||
readonly property alias contentWindow: contentWindow
|
readonly property alias contentWindow: contentWindow
|
||||||
readonly property alias clickCatcher: clickCatcher
|
readonly property alias clickCatcher: clickCatcher
|
||||||
readonly property bool useHyprlandFocusGrab: CompositorService.useHyprlandFocusGrab
|
readonly property bool useHyprlandFocusGrab: CompositorService.useHyprlandFocusGrab
|
||||||
readonly property bool useBackground: showBackground && !SettingsData.frameEnabled && SettingsData.modalDarkenBackground
|
readonly property bool useBackground: showBackground && !FrameTransitionState.effectiveFrameEnabled && SettingsData.modalDarkenBackground
|
||||||
readonly property bool useSingleWindow: CompositorService.isHyprland || useBackground
|
readonly property bool useSingleWindow: CompositorService.isHyprland || useBackground
|
||||||
|
|
||||||
signal opened
|
signal opened
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ Item {
|
|||||||
impl.item.toggleWithMode(mode);
|
impl.item.toggleWithMode(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool useSpotlightBackend: !SettingsData.connectedFrameModeActive && SettingsData.launcherStyle === "spotlight"
|
readonly property bool useSpotlightBackend: !FrameTransitionState.effectiveConnectedFrameModeActive && SettingsData.launcherStyle === "spotlight"
|
||||||
readonly property var _desiredBackend: useSpotlightBackend ? spotlightComp : (SettingsData.connectedFrameModeActive ? connectedComp : standaloneComp)
|
readonly property var _desiredBackend: useSpotlightBackend ? spotlightComp : (FrameTransitionState.effectiveConnectedFrameModeActive ? connectedComp : standaloneComp)
|
||||||
property var _resolvedBackend: null
|
property var _resolvedBackend: null
|
||||||
|
|
||||||
Component.onCompleted: _resolvedBackend = _desiredBackend
|
Component.onCompleted: _resolvedBackend = _desiredBackend
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ Item {
|
|||||||
|
|
||||||
readonly property string preferredConnectedBarSide: SettingsData.frameLauncherEmergeSide
|
readonly property string preferredConnectedBarSide: SettingsData.frameLauncherEmergeSide
|
||||||
|
|
||||||
readonly property bool frameConnectedMode: SettingsData.frameEnabled && Theme.isConnectedEffect && !!effectiveScreen && SettingsData.isScreenInPreferences(effectiveScreen, SettingsData.frameScreenPreferences)
|
readonly property bool frameConnectedMode: FrameTransitionState.effectiveFrameEnabled && Theme.isConnectedEffect && !!effectiveScreen && SettingsData.isScreenInPreferences(effectiveScreen, SettingsData.frameScreenPreferences)
|
||||||
|
|
||||||
readonly property string resolvedConnectedBarSide: frameConnectedMode ? preferredConnectedBarSide : ""
|
readonly property string resolvedConnectedBarSide: frameConnectedMode ? preferredConnectedBarSide : ""
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ Item {
|
|||||||
readonly property real screenWidth: effectiveScreen?.width ?? 1920
|
readonly property real screenWidth: effectiveScreen?.width ?? 1920
|
||||||
readonly property real screenHeight: effectiveScreen?.height ?? 1080
|
readonly property real screenHeight: effectiveScreen?.height ?? 1080
|
||||||
readonly property real dpr: effectiveScreen ? CompositorService.getScreenScale(effectiveScreen) : 1
|
readonly property real dpr: effectiveScreen ? CompositorService.getScreenScale(effectiveScreen) : 1
|
||||||
readonly property bool useBackgroundDarken: !SettingsData.frameEnabled && SettingsData.modalDarkenBackground
|
readonly property bool useBackgroundDarken: !FrameTransitionState.effectiveFrameEnabled && SettingsData.modalDarkenBackground
|
||||||
readonly property bool usesOverlayLayer: useBackgroundDarken || SettingsData.launcherUseOverlayLayer || triggerUsesOverlayLayer
|
readonly property bool usesOverlayLayer: useBackgroundDarken || SettingsData.launcherUseOverlayLayer || triggerUsesOverlayLayer
|
||||||
readonly property var effectiveLauncherLayer: LayerShell.fromEnv("DMS_MODAL_LAYER", root.usesOverlayLayer ? WlrLayer.Overlay : WlrLayer.Top, {
|
readonly property var effectiveLauncherLayer: LayerShell.fromEnv("DMS_MODAL_LAYER", root.usesOverlayLayer ? WlrLayer.Overlay : WlrLayer.Top, {
|
||||||
"allow": ["top", "overlay"],
|
"allow": ["top", "overlay"],
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ Item {
|
|||||||
readonly property real windowHeight: alignedHeight + contentY + shadowPad
|
readonly property real windowHeight: alignedHeight + contentY + shadowPad
|
||||||
|
|
||||||
readonly property color backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
readonly property color backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||||
readonly property bool useBackgroundDarken: !SettingsData.frameEnabled && SettingsData.modalDarkenBackground
|
readonly property bool useBackgroundDarken: !FrameTransitionState.effectiveFrameEnabled && SettingsData.modalDarkenBackground
|
||||||
readonly property bool useSingleWindow: CompositorService.isHyprland || useBackgroundDarken
|
readonly property bool useSingleWindow: CompositorService.isHyprland || useBackgroundDarken
|
||||||
readonly property bool usesOverlayLayer: useBackgroundDarken || SettingsData.launcherUseOverlayLayer || triggerUsesOverlayLayer
|
readonly property bool usesOverlayLayer: useBackgroundDarken || SettingsData.launcherUseOverlayLayer || triggerUsesOverlayLayer
|
||||||
readonly property var effectiveLauncherLayer: LayerShell.fromEnv("DMS_MODAL_LAYER", root.usesOverlayLayer ? WlrLayer.Overlay : WlrLayer.Top, {
|
readonly property var effectiveLauncherLayer: LayerShell.fromEnv("DMS_MODAL_LAYER", root.usesOverlayLayer ? WlrLayer.Overlay : WlrLayer.Top, {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Item {
|
|||||||
required property var axis
|
required property var axis
|
||||||
required property var barConfig
|
required property var barConfig
|
||||||
|
|
||||||
readonly property bool frameShapesBar: SettingsData.frameEnabled && barWindow.usesFrameBarChrome
|
readonly property bool frameShapesBar: FrameTransitionState.effectiveFrameEnabled && barWindow.usesFrameBarChrome
|
||||||
|
|
||||||
visible: !frameShapesBar
|
visible: !frameShapesBar
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,6 @@ PanelWindow {
|
|||||||
|
|
||||||
let section = "center";
|
let section = "center";
|
||||||
if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) {
|
if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) {
|
||||||
// Calculate barPosition from axis.edge
|
|
||||||
const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1));
|
const barPosition = axis?.edge === "left" ? 2 : (axis?.edge === "right" ? 3 : (axis?.edge === "top" ? 0 : 1));
|
||||||
section = clockButtonRef.section || "center";
|
section = clockButtonRef.section || "center";
|
||||||
|
|
||||||
@@ -148,7 +147,8 @@ PanelWindow {
|
|||||||
_blurRebuildTimer.restart();
|
_blurRebuildTimer.restart();
|
||||||
}
|
}
|
||||||
function onUsesFrameBarChromeChanged() {
|
function onUsesFrameBarChromeChanged() {
|
||||||
_blurRebuildTimer.restart();
|
// Rebuild immediately so the bar region never overlaps FrameWindow's during chrome handoff
|
||||||
|
barBlur.rebuild();
|
||||||
}
|
}
|
||||||
function onBarRevealedChanged() {
|
function onBarRevealedChanged() {
|
||||||
_blurRebuildTimer.restart();
|
_blurRebuildTimer.restart();
|
||||||
@@ -179,17 +179,11 @@ PanelWindow {
|
|||||||
teardown();
|
teardown();
|
||||||
if (!BlurService.enabled || !BlurService.available)
|
if (!BlurService.enabled || !BlurService.available)
|
||||||
return;
|
return;
|
||||||
// When the bar is hidden (auto-hide, or config not visible) keep the blur
|
// Hidden bar keeps a null region — an empty clip makes Hyprland blur the whole surface box
|
||||||
// region empty rather than sliding it off-surface. Some compositors (Hyprland)
|
|
||||||
// gate blur on a non-empty region and then blur the whole surface box when the
|
|
||||||
// clip degenerates to empty, leaving the bar strip blurred while the bar is
|
|
||||||
// hidden (issue #2656). A null region disables the effect cleanly.
|
|
||||||
if (!barWindow.barRevealed)
|
if (!barWindow.barRevealed)
|
||||||
return;
|
return;
|
||||||
// In frame mode, FrameWindow owns the blur region for the entire screen edge
|
// FrameWindow owns the blur region for the whole edge while the bar wears frame chrome
|
||||||
// (including the bar area). The bar must not set its own competing blur region
|
if (FrameTransitionState.effectiveFrameEnabled && barWindow.usesFrameBarChrome)
|
||||||
// so that frameBlurEnabled acts as the single control for all blur in frame mode.
|
|
||||||
if (SettingsData.frameEnabled && barWindow.usesFrameBarChrome)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const widgets = barWindow._blurWidgetItems.filter(w => w && w.visible && w.width > 0 && w.height > 0);
|
const widgets = barWindow._blurWidgetItems.filter(w => w && w.visible && w.width > 0 && w.height > 0);
|
||||||
@@ -245,8 +239,8 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: SettingsData
|
target: FrameTransitionState
|
||||||
function onFrameEnabledChanged() {
|
function onEffectiveFrameEnabledChanged() {
|
||||||
barBlur.rebuild();
|
barBlur.rebuild();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,7 +293,7 @@ PanelWindow {
|
|||||||
readonly property color _surfaceContainer: Theme.surfaceContainer
|
readonly property color _surfaceContainer: Theme.surfaceContainer
|
||||||
readonly property string _barId: barConfig?.id ?? "default"
|
readonly property string _barId: barConfig?.id ?? "default"
|
||||||
property real _backgroundAlpha: barConfig?.transparency ?? 1.0
|
property real _backgroundAlpha: barConfig?.transparency ?? 1.0
|
||||||
readonly property color _bgColor: (SettingsData.frameEnabled && usesFrameBarChrome) ? Theme.withAlpha(SettingsData.effectiveFrameColor, SettingsData.frameOpacity) : Theme.withAlpha(_surfaceContainer, _backgroundAlpha)
|
readonly property color _bgColor: (FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome) ? Theme.withAlpha(SettingsData.effectiveFrameColor, SettingsData.frameOpacity) : Theme.withAlpha(_surfaceContainer, _backgroundAlpha)
|
||||||
|
|
||||||
function _updateBackgroundAlpha() {
|
function _updateBackgroundAlpha() {
|
||||||
const live = SettingsData.barConfigs.find(c => c.id === _barId);
|
const live = SettingsData.barConfigs.find(c => c.id === _barId);
|
||||||
@@ -331,9 +325,8 @@ PanelWindow {
|
|||||||
return Theme.snap(Theme.elevationRenderPadding(Theme.elevationLevel2, "top", 4, 8, 16), _dpr);
|
return Theme.snap(Theme.elevationRenderPadding(Theme.elevationLevel2, "top", 4, 8, 16), _dpr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flatten/spacing collapse for maximized windows is only for frame-integrated layout.
|
// Flatten/spacing collapse for maximized windows only applies to frame-integrated layout
|
||||||
// When the bar draws its own pill, keep rounded corners and spacing like the dock.
|
readonly property bool flattenForMaximizedWindow: !FrameTransitionState.effectiveFrameEnabled || usesFrameBarChrome
|
||||||
readonly property bool flattenForMaximizedWindow: !SettingsData.frameEnabled || usesFrameBarChrome
|
|
||||||
|
|
||||||
property bool hasMaximizedToplevel: false
|
property bool hasMaximizedToplevel: false
|
||||||
property bool shouldHideForWindows: false
|
property bool shouldHideForWindows: false
|
||||||
@@ -455,7 +448,7 @@ PanelWindow {
|
|||||||
shouldHideForWindows = filtered.length > 0;
|
shouldHideForWindows = filtered.length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
property real effectiveSpacing: (SettingsData.frameEnabled && usesFrameBarChrome) ? 0 : ((flattenForMaximizedWindow && hasMaximizedToplevel) ? 0 : (barConfig?.spacing ?? 4))
|
property real effectiveSpacing: (FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome) ? 0 : ((flattenForMaximizedWindow && hasMaximizedToplevel) ? 0 : (barConfig?.spacing ?? 4))
|
||||||
|
|
||||||
Behavior on effectiveSpacing {
|
Behavior on effectiveSpacing {
|
||||||
enabled: barWindow.visible
|
enabled: barWindow.visible
|
||||||
@@ -466,8 +459,8 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
readonly property int notificationCount: NotificationService.notifications.length
|
readonly property int notificationCount: NotificationService.notifications.length
|
||||||
readonly property real effectiveBarThickness: (SettingsData.frameEnabled && usesFrameBarChrome) ? SettingsData.frameBarSize : Theme.snap(Math.max(barWindow.widgetThickness + (barConfig?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))), _dpr)
|
readonly property real effectiveBarThickness: (FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome) ? SettingsData.frameBarSize : Theme.snap(Math.max(barWindow.widgetThickness + (barConfig?.innerPadding ?? 4) + 4, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))), _dpr)
|
||||||
readonly property bool effectiveOpenOnOverview: SettingsData.frameEnabled ? SettingsData.frameShowOnOverview : (barConfig?.openOnOverview ?? false)
|
readonly property bool effectiveOpenOnOverview: FrameTransitionState.effectiveFrameEnabled ? SettingsData.frameShowOnOverview : (barConfig?.openOnOverview ?? false)
|
||||||
readonly property real widgetThickness: Theme.snap(Math.max(20, 26 + (barConfig?.innerPadding ?? 4) * 0.6), _dpr)
|
readonly property real widgetThickness: Theme.snap(Math.max(20, 26 + (barConfig?.innerPadding ?? 4) * 0.6), _dpr)
|
||||||
|
|
||||||
readonly property bool hasAdjacentTopBar: {
|
readonly property bool hasAdjacentTopBar: {
|
||||||
@@ -665,7 +658,7 @@ PanelWindow {
|
|||||||
anchors.left: !isVertical ? true : (barPos === SettingsData.Position.Left)
|
anchors.left: !isVertical ? true : (barPos === SettingsData.Position.Left)
|
||||||
anchors.right: !isVertical ? true : (barPos === SettingsData.Position.Right)
|
anchors.right: !isVertical ? true : (barPos === SettingsData.Position.Right)
|
||||||
|
|
||||||
readonly property bool reserveExclusiveWhenAutoHidden: SettingsData.frameEnabled && usesFrameBarChrome && !!barWindow.screen && SettingsData.isScreenInPreferences(barWindow.screen, SettingsData.frameScreenPreferences)
|
readonly property bool reserveExclusiveWhenAutoHidden: FrameTransitionState.effectiveFrameEnabled && usesFrameBarChrome && !!barWindow.screen && SettingsData.isScreenInPreferences(barWindow.screen, SettingsData.frameScreenPreferences)
|
||||||
|
|
||||||
exclusiveZone: (!(barConfig?.visible ?? true) || (topBarCore.autoHide && !barWindow.reserveExclusiveWhenAutoHidden)) ? -1 : (barWindow.effectiveBarThickness + effectiveSpacing + (usesFrameBarChrome ? 0 : (barConfig?.bottomGap ?? 0)))
|
exclusiveZone: (!(barConfig?.visible ?? true) || (topBarCore.autoHide && !barWindow.reserveExclusiveWhenAutoHidden)) ? -1 : (barWindow.effectiveBarThickness + effectiveSpacing + (usesFrameBarChrome ? 0 : (barConfig?.bottomGap ?? 0)))
|
||||||
|
|
||||||
@@ -1111,7 +1104,7 @@ PanelWindow {
|
|||||||
rightWidgetsModel: barWindow.rightWidgetsModel
|
rightWidgetsModel: barWindow.rightWidgetsModel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Passive HoverHandler to track cursor without intercepting clicks or scroll events.
|
// Passive: tracks cursor without intercepting clicks or scroll
|
||||||
HoverHandler {
|
HoverHandler {
|
||||||
id: hoverPopoutHandler
|
id: hoverPopoutHandler
|
||||||
enabled: (barConfig?.hoverPopouts ?? false) && !barWindow.clickThroughEnabled
|
enabled: (barConfig?.hoverPopouts ?? false) && !barWindow.clickThroughEnabled
|
||||||
|
|||||||
@@ -717,7 +717,7 @@ Variants {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: !usesConnectedFrameChrome && (!SettingsData.connectedFrameModeActive || dock.reveal)
|
visible: !usesConnectedFrameChrome && (!FrameTransitionState.effectiveConnectedFrameModeActive || dock.reveal)
|
||||||
color: dock.surfaceColor
|
color: dock.surfaceColor
|
||||||
topLeftRadius: dock.surfaceTopLeftRadius
|
topLeftRadius: dock.surfaceTopLeftRadius
|
||||||
topRightRadius: dock.surfaceTopRightRadius
|
topRightRadius: dock.surfaceTopRightRadius
|
||||||
@@ -727,7 +727,7 @@ Variants {
|
|||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: !usesConnectedFrameChrome && (!SettingsData.connectedFrameModeActive || dock.reveal)
|
visible: !usesConnectedFrameChrome && (!FrameTransitionState.effectiveConnectedFrameModeActive || dock.reveal)
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
topLeftRadius: dock.surfaceTopLeftRadius
|
topLeftRadius: dock.surfaceTopLeftRadius
|
||||||
topRightRadius: dock.surfaceTopRightRadius
|
topRightRadius: dock.surfaceTopRightRadius
|
||||||
@@ -747,7 +747,7 @@ Variants {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: dockConnectedChrome
|
id: dockConnectedChrome
|
||||||
visible: Theme.isConnectedEffect && dock.reveal && !SettingsData.connectedFrameModeActive
|
visible: Theme.isConnectedEffect && dock.reveal && !FrameTransitionState.effectiveConnectedFrameModeActive
|
||||||
readonly property real extraLeft: dock.isVertical ? 0 : Theme.connectedCornerRadius
|
readonly property real extraLeft: dock.isVertical ? 0 : Theme.connectedCornerRadius
|
||||||
readonly property real extraTop: dock.isVertical ? Theme.connectedCornerRadius : 0
|
readonly property real extraTop: dock.isVertical ? Theme.connectedCornerRadius : 0
|
||||||
readonly property real bodyRadius: dock.surfaceRadius
|
readonly property real bodyRadius: dock.surfaceRadius
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ Variants {
|
|||||||
|
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
||||||
active: SettingsData.frameEnabled && SettingsData.isScreenInPreferences(instanceLoader.modelData, SettingsData.frameScreenPreferences)
|
// Live-or-latched: instances build early on enable, survive until ack on disable
|
||||||
|
active: (SettingsData.frameEnabled || FrameTransitionState.effectiveFrameEnabled) && SettingsData.isScreenInPreferences(instanceLoader.modelData, SettingsData.frameScreenPreferences)
|
||||||
asynchronous: false
|
asynchronous: false
|
||||||
|
|
||||||
sourceComponent: FrameInstance {
|
sourceComponent: FrameInstance {
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
readonly property real _dpr: CompositorService.getScreenScale(win.targetScreen)
|
readonly property real _dpr: CompositorService.getScreenScale(win.targetScreen)
|
||||||
readonly property bool _frameActive: SettingsData.frameEnabled && SettingsData.isScreenInPreferences(win.targetScreen, SettingsData.frameScreenPreferences)
|
readonly property bool _frameActive: FrameTransitionState.effectiveFrameEnabled && SettingsData.isScreenInPreferences(win.targetScreen, SettingsData.frameScreenPreferences)
|
||||||
readonly property int _windowRegionWidth: win._regionInt(win.width)
|
readonly property int _windowRegionWidth: win._regionInt(win.width)
|
||||||
readonly property int _windowRegionHeight: win._regionInt(win.height)
|
readonly property int _windowRegionHeight: win._regionInt(win.height)
|
||||||
readonly property string _screenName: win.targetScreen ? win.targetScreen.name : ""
|
readonly property string _screenName: win.targetScreen ? win.targetScreen.name : ""
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ Rectangle {
|
|||||||
readonly property real actionButtonHeight: compactMode ? 20 : 24
|
readonly property real actionButtonHeight: compactMode ? 20 : 24
|
||||||
readonly property real collapsedContentHeight: Math.max(iconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2))
|
readonly property real collapsedContentHeight: Math.max(iconSize, Theme.fontSizeSmall * 1.2 + Theme.fontSizeMedium * 1.2 + Theme.fontSizeSmall * 1.2 * (compactMode ? 1 : 2))
|
||||||
readonly property real baseCardHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + contentSpacing
|
readonly property real baseCardHeight: cardPadding * 2 + collapsedContentHeight + actionButtonHeight + contentSpacing
|
||||||
readonly property bool connectedFrameMode: SettingsData.connectedFrameModeActive
|
readonly property bool connectedFrameMode: FrameTransitionState.effectiveConnectedFrameModeActive
|
||||||
|
|
||||||
width: parent ? parent.width : 400
|
width: parent ? parent.width : 400
|
||||||
height: expanded ? (expandedContent.height + cardPadding * 2) : (baseCardHeight + collapsedContent.extraHeight)
|
height: expanded ? (expandedContent.height + cardPadding * 2) : (baseCardHeight + collapsedContent.extraHeight)
|
||||||
|
|||||||
@@ -323,10 +323,12 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
// Hidden in Frame Connected mode, where it has no target
|
// Hidden in Frame Connected mode, where it has no target
|
||||||
visible: !(SettingsData.frameEnabled && SettingsData.frameMode === "connected")
|
visible: !(SettingsData.frameEnabled && SettingsData.frameMode === "connected")
|
||||||
|
enabled: SettingsData.frameEnabled || SettingsData.standaloneBarXrayAvailable
|
||||||
|
opacity: enabled ? 1 : 0.5
|
||||||
tags: ["niri", "xray", "bar", "frame", "performance"]
|
tags: ["niri", "xray", "bar", "frame", "performance"]
|
||||||
settingKey: "niriLayoutBarXrayEnabled"
|
settingKey: "niriLayoutBarXrayEnabled"
|
||||||
text: SettingsData.frameEnabled ? I18n.tr("Frame Xray") : I18n.tr("Dank Bar Xray")
|
text: SettingsData.frameEnabled ? I18n.tr("Frame Xray") : I18n.tr("Dank Bar Xray")
|
||||||
description: SettingsData.niriLayoutBarXrayEnabled ? (SettingsData.frameEnabled ? I18n.tr("Xray on makes the Frame's border visible through to the wallpaper; more efficient") : I18n.tr("Xray on makes the Dank Bar visible through to the wallpaper; more efficient")) : (SettingsData.frameEnabled ? I18n.tr("Xray off shows the real background beneath the Frame's border") : I18n.tr("Xray off shows the real background beneath the Dank Bar"))
|
description: !SettingsData.frameEnabled && !SettingsData.standaloneBarXrayAvailable ? I18n.tr("Unavailable while using Auto Hide as Xray would reveal the wallpaper through windows") : (SettingsData.niriLayoutBarXrayEnabled ? (SettingsData.frameEnabled ? I18n.tr("Xray on makes the Frame's border visible through to the wallpaper; more efficient") : I18n.tr("Xray on makes the Dank Bar visible through to the wallpaper; more efficient")) : (SettingsData.frameEnabled ? I18n.tr("Xray off shows the real background beneath the Frame's border") : I18n.tr("Xray off shows the real background beneath the Dank Bar")))
|
||||||
checked: SettingsData.niriLayoutBarXrayEnabled
|
checked: SettingsData.niriLayoutBarXrayEnabled
|
||||||
onToggled: checked => SettingsData.set("niriLayoutBarXrayEnabled", checked)
|
onToggled: checked => SettingsData.set("niriLayoutBarXrayEnabled", checked)
|
||||||
}
|
}
|
||||||
@@ -449,10 +451,12 @@ Item {
|
|||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
// Hidden in Frame Connected mode, where it has no target
|
// Hidden in Frame Connected mode, where it has no target
|
||||||
visible: !(SettingsData.frameEnabled && SettingsData.frameMode === "connected")
|
visible: !(SettingsData.frameEnabled && SettingsData.frameMode === "connected")
|
||||||
|
enabled: SettingsData.frameEnabled || SettingsData.standaloneBarXrayAvailable
|
||||||
|
opacity: enabled ? 1 : 0.5
|
||||||
tags: ["hyprland", "xray", "bar", "frame", "performance"]
|
tags: ["hyprland", "xray", "bar", "frame", "performance"]
|
||||||
settingKey: "hyprlandLayoutBarXrayEnabled"
|
settingKey: "hyprlandLayoutBarXrayEnabled"
|
||||||
text: SettingsData.frameEnabled ? I18n.tr("Frame Xray") : I18n.tr("Dank Bar Xray")
|
text: SettingsData.frameEnabled ? I18n.tr("Frame Xray") : I18n.tr("Dank Bar Xray")
|
||||||
description: SettingsData.hyprlandLayoutBarXrayEnabled ? (SettingsData.frameEnabled ? I18n.tr("Xray on makes the Frame's border visible through to the wallpaper; more efficient") : I18n.tr("Xray on makes the Dank Bar visible through to the wallpaper; more efficient")) : (SettingsData.frameEnabled ? I18n.tr("Xray off shows the real background beneath the Frame's border") : I18n.tr("Xray off shows the real background beneath the Dank Bar"))
|
description: !SettingsData.frameEnabled && !SettingsData.standaloneBarXrayAvailable ? I18n.tr("Unavailable while an enabled Dank Bar uses Auto Hide because Xray would reveal the wallpaper through windows") : (SettingsData.hyprlandLayoutBarXrayEnabled ? (SettingsData.frameEnabled ? I18n.tr("Xray on makes the Frame's border visible through to the wallpaper; more efficient") : I18n.tr("Xray on makes the Dank Bar visible through to the wallpaper; more efficient")) : (SettingsData.frameEnabled ? I18n.tr("Xray off shows the real background beneath the Frame's border") : I18n.tr("Xray off shows the real background beneath the Dank Bar")))
|
||||||
checked: SettingsData.hyprlandLayoutBarXrayEnabled
|
checked: SettingsData.hyprlandLayoutBarXrayEnabled
|
||||||
onToggled: checked => SettingsData.set("hyprlandLayoutBarXrayEnabled", checked)
|
onToggled: checked => SettingsData.set("hyprlandLayoutBarXrayEnabled", checked)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ Singleton {
|
|||||||
property bool isLabwc: false
|
property bool isLabwc: false
|
||||||
property string compositor: "unknown"
|
property string compositor: "unknown"
|
||||||
property bool compositorDetected: false
|
property bool compositorDetected: false
|
||||||
|
readonly property bool frameCompositorLayoutReady: (!isNiri || NiriService.frameLayoutReady) && (!isHyprland || HyprlandService.frameLayoutReady)
|
||||||
readonly property bool useHyprlandFocusGrab: isHyprland && Quickshell.env("DMS_HYPRLAND_EXCLUSIVE_FOCUS") !== "1"
|
readonly property bool useHyprlandFocusGrab: isHyprland && Quickshell.env("DMS_HYPRLAND_EXCLUSIVE_FOCUS") !== "1"
|
||||||
|
|
||||||
readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
|
readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE")
|
||||||
@@ -612,7 +613,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function frameConfiguredForScreen(screenOrName) {
|
function frameConfiguredForScreen(screenOrName) {
|
||||||
if (!SettingsData.frameEnabled)
|
if (!FrameTransitionState.effectiveFrameEnabled)
|
||||||
return false;
|
return false;
|
||||||
const screen = _screenForName(screenOrName);
|
const screen = _screenForName(screenOrName);
|
||||||
if (!screen || !SettingsData.isScreenInPreferences(screen, SettingsData.frameScreenPreferences))
|
if (!screen || !SettingsData.isScreenInPreferences(screen, SettingsData.frameScreenPreferences))
|
||||||
@@ -627,7 +628,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function usesConnectedFrameChromeForScreen(screenOrName) {
|
function usesConnectedFrameChromeForScreen(screenOrName) {
|
||||||
return SettingsData.connectedFrameModeActive && frameWindowVisibleForScreen(screenOrName);
|
return FrameTransitionState.effectiveConnectedFrameModeActive && frameWindowVisibleForScreen(screenOrName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function framePeerSurfacesUseOverlayForScreen(screenOrName) {
|
function framePeerSurfacesUseOverlayForScreen(screenOrName) {
|
||||||
|
|||||||
@@ -25,6 +25,22 @@ Singleton {
|
|||||||
property bool luaConfigStatusReady: false
|
property bool luaConfigStatusReady: false
|
||||||
property bool luaConfigStatusLoading: false
|
property bool luaConfigStatusLoading: false
|
||||||
property string luaConfigFormat: ""
|
property string luaConfigFormat: ""
|
||||||
|
property bool layoutGenerationPending: false
|
||||||
|
property bool layoutGenerationRunning: false
|
||||||
|
property int _layoutRequestRevision: 0
|
||||||
|
property int _layoutAppliedRevision: 0
|
||||||
|
property int _frameTransitionRevision: 0
|
||||||
|
readonly property bool frameLayoutReady: _layoutAppliedRevision >= _frameTransitionRevision
|
||||||
|
|
||||||
|
DeferredAction {
|
||||||
|
id: layoutGenerationAction
|
||||||
|
onTriggered: root.doGenerateLayoutConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
onLuaConfigStatusLoadingChanged: {
|
||||||
|
if (!luaConfigStatusLoading && layoutGenerationPending)
|
||||||
|
layoutGenerationAction.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
onLuaConfigActiveChanged: {
|
onLuaConfigActiveChanged: {
|
||||||
if (luaConfigActive)
|
if (luaConfigActive)
|
||||||
@@ -237,18 +253,39 @@ Singleton {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reloadConfig() {
|
function reloadConfig(callback) {
|
||||||
Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => {
|
Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => {
|
||||||
if (exitCode !== 0)
|
if (exitCode !== 0)
|
||||||
log.warn("hyprctl reload failed:", output);
|
log.warn("hyprctl reload failed:", output);
|
||||||
|
if (callback)
|
||||||
|
callback(exitCode === 0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateLayoutConfig() {
|
function generateLayoutConfig(frameTransition) {
|
||||||
if (!CompositorService.isHyprland)
|
if (!CompositorService.isHyprland)
|
||||||
return;
|
return;
|
||||||
if (!canWriteLuaConfig("layout"))
|
_layoutRequestRevision++;
|
||||||
|
if (frameTransition === true)
|
||||||
|
_frameTransitionRevision = _layoutRequestRevision;
|
||||||
|
layoutGenerationPending = true;
|
||||||
|
layoutGenerationAction.schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
function doGenerateLayoutConfig() {
|
||||||
|
if (layoutGenerationRunning)
|
||||||
return;
|
return;
|
||||||
|
layoutGenerationPending = false;
|
||||||
|
const requestRevision = _layoutRequestRevision;
|
||||||
|
if (!canWriteLuaConfig("layout")) {
|
||||||
|
if (luaConfigStatusLoading || !luaConfigStatusReady) {
|
||||||
|
layoutGenerationPending = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_layoutAppliedRevision = Math.max(_layoutAppliedRevision, requestRevision);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layoutGenerationRunning = true;
|
||||||
|
|
||||||
const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
|
const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
|
||||||
const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
|
const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
|
||||||
@@ -262,10 +299,9 @@ Singleton {
|
|||||||
const barFrameXrayEnabled = typeof SettingsData === "undefined" || SettingsData.hyprlandLayoutBarXrayEnabled;
|
const barFrameXrayEnabled = typeof SettingsData === "undefined" || SettingsData.hyprlandLayoutBarXrayEnabled;
|
||||||
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
||||||
const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected";
|
const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected";
|
||||||
|
// Hyprland `xray = false` is still early-development; unset already samples real content, so only force xray=true
|
||||||
// Hyprland's `xray = false` is still in early development, so unlike niri we never emit it (unset already
|
// Standalone Bar Xray is safe only while every active bar reserves its strip
|
||||||
// samples real content) - we only force xray=true
|
const barFrameTargetNamespace = !frameEnabled ? (SettingsData.standaloneBarXrayAvailable ? "dms:bar" : null) : (frameConnectedMode ? null : "dms:frame");
|
||||||
const barFrameTargetNamespace = !frameEnabled ? "dms:bar" : (frameConnectedMode ? null : "dms:frame");
|
|
||||||
|
|
||||||
let content = `-- Auto-generated by DMS — do not edit manually
|
let content = `-- Auto-generated by DMS — do not edit manually
|
||||||
|
|
||||||
@@ -302,10 +338,21 @@ hl.layer_rule({
|
|||||||
Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
||||||
if (exitCode !== 0) {
|
if (exitCode !== 0) {
|
||||||
log.warn("Failed to write layout config:", output);
|
log.warn("Failed to write layout config:", output);
|
||||||
|
// Best-effort ack so a failed write can't wedge frame transitions
|
||||||
|
_layoutAppliedRevision = Math.max(_layoutAppliedRevision, requestRevision);
|
||||||
|
layoutGenerationRunning = false;
|
||||||
|
if (layoutGenerationPending)
|
||||||
|
layoutGenerationAction.schedule();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log.info("Generated layout config at", layoutPath);
|
log.info("Generated layout config at", layoutPath);
|
||||||
reloadConfig();
|
reloadConfig(success => {
|
||||||
|
// Advance even on failure — proceed degraded rather than wedge the transition
|
||||||
|
_layoutAppliedRevision = Math.max(_layoutAppliedRevision, requestRevision);
|
||||||
|
layoutGenerationRunning = false;
|
||||||
|
if (layoutGenerationPending)
|
||||||
|
layoutGenerationAction.schedule();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ Singleton {
|
|||||||
property bool suppressNextConfigToast: false
|
property bool suppressNextConfigToast: false
|
||||||
property bool matugenSuppression: false
|
property bool matugenSuppression: false
|
||||||
property bool configGenerationPending: false
|
property bool configGenerationPending: false
|
||||||
|
property int _layoutRequestRevision: 0
|
||||||
|
property int _layoutAppliedRevision: 0
|
||||||
|
property int _frameTransitionRevision: 0
|
||||||
|
property int _awaitingLayoutReloadRevision: 0
|
||||||
|
property string _lastGeneratedAlttabContent: ""
|
||||||
|
readonly property bool frameLayoutReady: _layoutAppliedRevision >= _frameTransitionRevision
|
||||||
|
|
||||||
readonly property string screenshotsDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.PicturesLocation)) + "/Screenshots"
|
readonly property string screenshotsDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.PicturesLocation)) + "/Screenshots"
|
||||||
property string pendingScreenshotPath: ""
|
property string pendingScreenshotPath: ""
|
||||||
@@ -72,9 +78,8 @@ Singleton {
|
|||||||
onTriggered: root.matugenSuppression = false
|
onTriggered: root.matugenSuppression = false
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
DeferredAction {
|
||||||
id: configGenerationDebounce
|
id: configGenerationAction
|
||||||
interval: 100
|
|
||||||
onTriggered: root.doGenerateNiriLayoutConfig()
|
onTriggered: root.doGenerateNiriLayoutConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,13 +122,20 @@ Singleton {
|
|||||||
id: writeConfigProcess
|
id: writeConfigProcess
|
||||||
property string configContent: ""
|
property string configContent: ""
|
||||||
property string configPath: ""
|
property string configPath: ""
|
||||||
|
property int requestRevision: 0
|
||||||
|
|
||||||
onExited: exitCode => {
|
onExited: exitCode => {
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
log.info("Generated layout config at", configPath);
|
log.info("Generated layout config at", configPath);
|
||||||
return;
|
} else {
|
||||||
|
if (root._awaitingLayoutReloadRevision === requestRevision)
|
||||||
|
root._awaitingLayoutReloadRevision = 0;
|
||||||
|
// Best-effort ack so a failed write can't wedge frame transitions
|
||||||
|
root._layoutAppliedRevision = Math.max(root._layoutAppliedRevision, requestRevision);
|
||||||
|
log.warn("Failed to write layout config, exit code:", exitCode);
|
||||||
}
|
}
|
||||||
log.warn("Failed to write layout config, exit code:", exitCode);
|
if (root.configGenerationPending && root._awaitingLayoutReloadRevision <= root._layoutAppliedRevision)
|
||||||
|
configGenerationAction.schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,12 +571,25 @@ Singleton {
|
|||||||
function handleConfigLoaded(data) {
|
function handleConfigLoaded(data) {
|
||||||
if (data.failed) {
|
if (data.failed) {
|
||||||
validateProcess.running = true;
|
validateProcess.running = true;
|
||||||
|
// Best-effort ack: a rejected reload must not wedge frame transitions
|
||||||
|
if (_awaitingLayoutReloadRevision > _layoutAppliedRevision) {
|
||||||
|
_layoutAppliedRevision = _awaitingLayoutReloadRevision;
|
||||||
|
_awaitingLayoutReloadRevision = 0;
|
||||||
|
}
|
||||||
|
if (configGenerationPending)
|
||||||
|
configGenerationAction.schedule();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
configValidationOutput = "";
|
configValidationOutput = "";
|
||||||
ToastService.dismissCategory("niri-config");
|
ToastService.dismissCategory("niri-config");
|
||||||
fetchOutputs();
|
fetchOutputs();
|
||||||
|
if (_awaitingLayoutReloadRevision > _layoutAppliedRevision) {
|
||||||
|
_layoutAppliedRevision = _awaitingLayoutReloadRevision;
|
||||||
|
_awaitingLayoutReloadRevision = 0;
|
||||||
|
}
|
||||||
|
if (configGenerationPending)
|
||||||
|
configGenerationAction.schedule();
|
||||||
configReloaded();
|
configReloaded();
|
||||||
|
|
||||||
if (hasInitialConnection && !suppressConfigToast && !suppressNextConfigToast && !matugenSuppression) {
|
if (hasInitialConnection && !suppressConfigToast && !suppressNextConfigToast && !matugenSuppression) {
|
||||||
@@ -1069,15 +1094,21 @@ Singleton {
|
|||||||
return _matchAndEnrichToplevels(toplevels, windows.filter(nw => outputWorkspaceIds.has(nw.workspace_id)));
|
return _matchAndEnrichToplevels(toplevels, windows.filter(nw => outputWorkspaceIds.has(nw.workspace_id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateNiriLayoutConfig() {
|
function generateNiriLayoutConfig(frameTransition) {
|
||||||
if (!CompositorService.isNiri || configGenerationPending)
|
if (!CompositorService.isNiri)
|
||||||
return;
|
return;
|
||||||
|
_layoutRequestRevision++;
|
||||||
|
if (frameTransition === true)
|
||||||
|
_frameTransitionRevision = _layoutRequestRevision;
|
||||||
suppressNextToast();
|
suppressNextToast();
|
||||||
configGenerationPending = true;
|
configGenerationPending = true;
|
||||||
configGenerationDebounce.restart();
|
configGenerationAction.schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
function doGenerateNiriLayoutConfig() {
|
function doGenerateNiriLayoutConfig() {
|
||||||
|
if (writeConfigProcess.running || _awaitingLayoutReloadRevision > _layoutAppliedRevision)
|
||||||
|
return;
|
||||||
|
configGenerationPending = false;
|
||||||
log.debug("Generating layout config...");
|
log.debug("Generating layout config...");
|
||||||
|
|
||||||
const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
|
const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
|
||||||
@@ -1091,19 +1122,14 @@ Singleton {
|
|||||||
const barFrameXrayEnabled = typeof SettingsData === "undefined" || SettingsData.niriLayoutBarXrayEnabled;
|
const barFrameXrayEnabled = typeof SettingsData === "undefined" || SettingsData.niriLayoutBarXrayEnabled;
|
||||||
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
const frameEnabled = typeof SettingsData !== "undefined" && SettingsData.frameEnabled;
|
||||||
const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected";
|
const frameConnectedMode = frameEnabled && SettingsData.frameMode === "connected";
|
||||||
|
// Standalone Bar Xray is safe only while every active bar reserves its strip
|
||||||
// The one wallpaper-flush surface to force xray=true on: bar (Frame off) or Frame's Separate-mode border
|
const barFrameTargetNamespace = !frameEnabled ? (SettingsData.standaloneBarXrayAvailable ? "dms:bar" : null) : (frameConnectedMode ? null : "dms:frame");
|
||||||
const barFrameTargetNamespace = !frameEnabled ? "dms:bar" : (frameConnectedMode ? null : "dms:frame");
|
|
||||||
|
|
||||||
let xrayRules = "";
|
let xrayRules = "";
|
||||||
if (!xrayEnabled) {
|
if (!xrayEnabled) {
|
||||||
let excludes = "";
|
|
||||||
if (frameEnabled)
|
|
||||||
excludes += `
|
|
||||||
exclude namespace="^dms:bar$"`;
|
|
||||||
xrayRules += `
|
xrayRules += `
|
||||||
layer-rule {
|
layer-rule {
|
||||||
match namespace=".*"` + excludes + `
|
match namespace=".*"
|
||||||
background-effect {
|
background-effect {
|
||||||
xray false
|
xray false
|
||||||
}
|
}
|
||||||
@@ -1157,13 +1183,18 @@ Singleton {
|
|||||||
|
|
||||||
writeConfigProcess.configContent = configContent;
|
writeConfigProcess.configContent = configContent;
|
||||||
writeConfigProcess.configPath = configPath;
|
writeConfigProcess.configPath = configPath;
|
||||||
|
writeConfigProcess.requestRevision = _layoutRequestRevision;
|
||||||
writeConfigProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${configPath}" << 'EOF'\n${configContent}\nEOF`];
|
writeConfigProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${configPath}" << 'EOF'\n${configContent}\nEOF`];
|
||||||
|
_awaitingLayoutReloadRevision = Math.max(_awaitingLayoutReloadRevision, _layoutRequestRevision);
|
||||||
writeConfigProcess.running = true;
|
writeConfigProcess.running = true;
|
||||||
|
|
||||||
writeAlttabProcess.alttabContent = alttabContent;
|
if (_lastGeneratedAlttabContent !== alttabContent) {
|
||||||
writeAlttabProcess.alttabPath = alttabPath;
|
_lastGeneratedAlttabContent = alttabContent;
|
||||||
writeAlttabProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${alttabPath}" << 'EOF'\n${alttabContent}\nEOF`];
|
writeAlttabProcess.alttabContent = alttabContent;
|
||||||
writeAlttabProcess.running = true;
|
writeAlttabProcess.alttabPath = alttabPath;
|
||||||
|
writeAlttabProcess.command = ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${alttabPath}" << 'EOF'\n${alttabContent}\nEOF`];
|
||||||
|
writeAlttabProcess.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (const name of ["outputs", "binds", "cursor", "windowrules", "colors", "alttab", "layout"]) {
|
for (const name of ["outputs", "binds", "cursor", "windowrules", "colors", "alttab", "layout"]) {
|
||||||
const path = niriDmsDir + "/" + name + ".kdl";
|
const path = niriDmsDir + "/" + name + ".kdl";
|
||||||
@@ -1173,7 +1204,6 @@ Singleton {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
configGenerationPending = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateNiriBlurrule() {
|
function generateNiriBlurrule() {
|
||||||
|
|||||||
@@ -8649,18 +8649,39 @@
|
|||||||
"category": "Personalization",
|
"category": "Personalization",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"appearance",
|
"appearance",
|
||||||
|
"auto",
|
||||||
|
"background",
|
||||||
"bar",
|
"bar",
|
||||||
|
"because",
|
||||||
|
"bg",
|
||||||
"custom",
|
"custom",
|
||||||
"customize",
|
"customize",
|
||||||
|
"dank",
|
||||||
|
"desktop",
|
||||||
|
"enabled",
|
||||||
"frame",
|
"frame",
|
||||||
|
"hide",
|
||||||
"hyprland",
|
"hyprland",
|
||||||
"makes",
|
"image",
|
||||||
|
"panel",
|
||||||
"performance",
|
"performance",
|
||||||
"personal",
|
"personal",
|
||||||
"personalization",
|
"personalization",
|
||||||
|
"picture",
|
||||||
|
"reveal",
|
||||||
|
"statusbar",
|
||||||
|
"taskbar",
|
||||||
|
"through",
|
||||||
|
"topbar",
|
||||||
|
"unavailable",
|
||||||
|
"uses",
|
||||||
|
"wallpaper",
|
||||||
|
"while",
|
||||||
|
"windows",
|
||||||
|
"would",
|
||||||
"xray"
|
"xray"
|
||||||
],
|
],
|
||||||
"description": "Xray on makes the Frame"
|
"description": "Unavailable while an enabled Dank Bar uses Auto Hide because Xray would reveal the wallpaper through windows"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "niriLayoutBarXrayEnabled",
|
"section": "niriLayoutBarXrayEnabled",
|
||||||
@@ -8669,18 +8690,31 @@
|
|||||||
"category": "Personalization",
|
"category": "Personalization",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"appearance",
|
"appearance",
|
||||||
|
"auto",
|
||||||
|
"background",
|
||||||
"bar",
|
"bar",
|
||||||
|
"bg",
|
||||||
"custom",
|
"custom",
|
||||||
"customize",
|
"customize",
|
||||||
|
"desktop",
|
||||||
"frame",
|
"frame",
|
||||||
"makes",
|
"hide",
|
||||||
|
"image",
|
||||||
"niri",
|
"niri",
|
||||||
"performance",
|
"performance",
|
||||||
"personal",
|
"personal",
|
||||||
"personalization",
|
"personalization",
|
||||||
|
"picture",
|
||||||
|
"reveal",
|
||||||
|
"through",
|
||||||
|
"unavailable",
|
||||||
|
"wallpaper",
|
||||||
|
"while",
|
||||||
|
"windows",
|
||||||
|
"would",
|
||||||
"xray"
|
"xray"
|
||||||
],
|
],
|
||||||
"description": "Xray on makes the Frame"
|
"description": "Unavailable while using Auto Hide as Xray would reveal the wallpaper through windows"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"section": "hyprlandLayout",
|
"section": "hyprlandLayout",
|
||||||
|
|||||||
Reference in New Issue
Block a user