1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-10 07:28:30 -04:00

refactor: (modals/popouts): sync functions & improve blur calculations across modals

This commit is contained in:
purian23
2026-07-03 22:20:10 -04:00
parent 9f77b3127c
commit 8dadf73d52
7 changed files with 53 additions and 84 deletions
@@ -162,37 +162,16 @@ Item {
_publishModalChromeState(); _publishModalChromeState();
} }
property bool _animSyncQueued: false
property bool _bodySyncQueued: false
function _queueFullSync() { function _queueFullSync() {
_fullSyncPending = true; _fullSyncPending = true;
if (!_syncTimer.running) if (!_syncTimer.running)
_syncTimer.restart(); _syncTimer.restart();
} }
function _queueAnimSync() {
_animSyncQueued = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _queueBodySync() {
_bodySyncQueued = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _flushSync() { function _flushSync() {
const fullDirty = _fullSyncPending; if (!_fullSyncPending)
const animDirty = _animSyncQueued; return;
const bodyDirty = _bodySyncQueued;
_fullSyncPending = false; _fullSyncPending = false;
_animSyncQueued = false;
_bodySyncQueued = false;
if (fullDirty)
_syncModalChromeState(); _syncModalChromeState();
if (animDirty)
_syncModalAnim();
if (bodyDirty)
_syncModalBody();
} }
function _syncModalAnim() { function _syncModalAnim() {
@@ -216,10 +195,11 @@ Item {
onFrameOwnsConnectedChromeChanged: _syncModalChromeState() onFrameOwnsConnectedChromeChanged: _syncModalChromeState()
onResolvedConnectedBarSideChanged: _queueFullSync() onResolvedConnectedBarSideChanged: _queueFullSync()
onShouldBeVisibleChanged: _queueFullSync() onShouldBeVisibleChanged: _queueFullSync()
onAlignedXChanged: _queueBodySync() // Low resource scalar writes: publish synchronously to stay in the same frame
onAlignedYChanged: _queueBodySync() onAlignedXChanged: _syncModalBody()
onAlignedWidthChanged: _queueBodySync() onAlignedYChanged: _syncModalBody()
onAlignedHeightChanged: _queueBodySync() onAlignedWidthChanged: _syncModalBody()
onAlignedHeightChanged: _syncModalBody()
Connections { Connections {
target: contentWindow target: contentWindow
@@ -613,9 +593,9 @@ Item {
readonly property real scaleValue: computedScaleCollapsed + (1.0 - computedScaleCollapsed) * morph.openProgress readonly property real scaleValue: computedScaleCollapsed + (1.0 - computedScaleCollapsed) * morph.openProgress
onAnimXChanged: if (root.frameOwnsConnectedChrome) onAnimXChanged: if (root.frameOwnsConnectedChrome)
root._queueAnimSync() root._syncModalAnim()
onAnimYChanged: if (root.frameOwnsConnectedChrome) onAnimYChanged: if (root.frameOwnsConnectedChrome)
root._queueAnimSync() root._syncModalAnim()
Item { Item {
id: contentContainer id: contentContainer
@@ -244,11 +244,11 @@ Item {
WindowBlur { WindowBlur {
targetWindow: contentWindow targetWindow: contentWindow
readonly property real s: Math.min(1, modalContainer.scaleValue) readonly property real s: Math.min(1, modalContainer.scaleValue)
readonly property real op: Math.max(0, Math.min(1, (morph.openProgress - 0.06) * 2)) // Blur tracks the surface's scaled rect, matching the connected backend.
blurX: modalContainer.x + modalContainer.width * (1 - s * op) * 0.5 + Theme.snap(modalContainer.animX, root.dpr) blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5 + Theme.snap(modalContainer.animX, root.dpr)
blurY: modalContainer.y + modalContainer.height * (1 - s * op) * 0.5 + Theme.snap(modalContainer.animY, root.dpr) blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5 + Theme.snap(modalContainer.animY, root.dpr)
blurWidth: root.shouldBeVisible ? modalContainer.width * s * op : 0 blurWidth: root.shouldBeVisible ? modalContainer.width * s : 0
blurHeight: root.shouldBeVisible ? modalContainer.height * s * op : 0 blurHeight: root.shouldBeVisible ? modalContainer.height * s : 0
blurRadius: root.cornerRadius blurRadius: root.cornerRadius
} }
@@ -364,11 +364,11 @@ Item {
WindowBlur { WindowBlur {
targetWindow: launcherWindow targetWindow: launcherWindow
readonly property real s: Math.min(1, modalContainer.publishedScale) readonly property real s: Math.min(1, modalContainer.publishedScale)
readonly property real op: Math.max(0, Math.min(1, (modalContainer.publishedOpacity - 0.06) * 2)) // Blur tracks the surface's scaled rect
blurX: modalContainer.x + modalContainer.width * (1 - s * op) * 0.5 blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5
blurY: modalContainer.y + modalContainer.height * (1 - s * op) * 0.5 blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5
blurWidth: contentVisible ? modalContainer.width * s * op : 0 blurWidth: contentVisible ? modalContainer.width * s : 0
blurHeight: contentVisible ? modalContainer.height * s * op : 0 blurHeight: contentVisible ? modalContainer.height * s : 0
blurRadius: root.cornerRadius blurRadius: root.cornerRadius
} }
+5 -3
View File
@@ -154,10 +154,12 @@ Singleton {
continue; continue;
if (!x || !y) if (!x || !y)
return false; return false;
// Only niri's enriched snapshots support value comparison. // Only niri/mango enriched snapshots support value comparison
if (x.niriWindowId === undefined || y.niriWindowId === undefined) const xKey = x.niriWindowId !== undefined ? x.niriWindowId : x.mangoWindowId;
const yKey = y.niriWindowId !== undefined ? y.niriWindowId : y.mangoWindowId;
if (xKey === undefined || yKey === undefined)
return false; return false;
if (x.niriWindowId !== y.niriWindowId || x.niriWorkspaceId !== y.niriWorkspaceId || x.appId !== y.appId || x.title !== y.title || !!x.activated !== !!y.activated || !!x.fullscreen !== !!y.fullscreen || !!x.maximized !== !!y.maximized || !!x.minimized !== !!y.minimized) if (xKey !== yKey || x.niriWorkspaceId !== y.niriWorkspaceId || x.appId !== y.appId || x.title !== y.title || !!x.activated !== !!y.activated || !!x.fullscreen !== !!y.fullscreen || !!x.maximized !== !!y.maximized || !!x.minimized !== !!y.minimized)
return false; return false;
} }
return true; return true;
+20 -34
View File
@@ -39,6 +39,8 @@ Item {
property bool fullHeightSurface: false property bool fullHeightSurface: false
property bool _primeContent: false property bool _primeContent: false
property bool _contentWarm: false property bool _contentWarm: false
// Keyboard focus grabbed one tick after emerge starts, to avoid stalling first frames.
property bool _keyboardReady: false
property bool _resizeActive: false property bool _resizeActive: false
property real _chromeAnimTravelX: 1 property real _chromeAnimTravelX: 1
property real _chromeAnimTravelY: 1 property real _chromeAnimTravelY: 1
@@ -241,7 +243,8 @@ Item {
} }
function _connectedChromeState(visibleOverride) { function _connectedChromeState(visibleOverride) {
const visible = visibleOverride !== undefined ? !!visibleOverride : contentWindow.visible; // Track intent rather than the transient wl_surface state during remap.
const visible = visibleOverride !== undefined ? !!visibleOverride : (contentWindow.visible || root.shouldBeVisible);
const presented = contentWindow.visible || root.shouldBeVisible; const presented = contentWindow.visible || root.shouldBeVisible;
const phase = root.isClosing ? "closing" : (!presented ? "hidden" : (!contentWindow.visible && root.shouldBeVisible ? "opening" : "open")); const phase = root.isClosing ? "closing" : (!presented ? "hidden" : (!contentWindow.visible && root.shouldBeVisible ? "opening" : "open"));
const bodyX = Theme.snap(root.pubBodyX, root.dpr); const bodyX = Theme.snap(root.pubBodyX, root.dpr);
@@ -353,48 +356,26 @@ Item {
_publishedBodyValid = false; _publishedBodyValid = false;
} }
property bool _animSyncQueued: false
property bool _bodySyncQueued: false
function _queueFullSync() { function _queueFullSync() {
_fullSyncQueued = true; _fullSyncQueued = true;
if (!_syncTimer.running) if (!_syncTimer.running)
_syncTimer.restart(); _syncTimer.restart();
} }
function _queueAnimSync() {
_animSyncQueued = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _queueBodySync() {
_bodySyncQueued = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _flushSync() { function _flushSync() {
const fullDirty = _fullSyncQueued; if (!_fullSyncQueued)
const animDirty = _animSyncQueued; return;
const bodyDirty = _bodySyncQueued;
_fullSyncQueued = false; _fullSyncQueued = false;
_animSyncQueued = false;
_bodySyncQueued = false;
if (fullDirty)
_syncPopoutChromeState(); _syncPopoutChromeState();
if (animDirty) {
_syncPopoutAnim("x");
_syncPopoutAnim("y");
}
if (bodyDirty)
_syncPopoutBody();
} }
onAlignedXChanged: _queueFullSync() onAlignedXChanged: _queueFullSync()
onAlignedYChanged: _queueFullSync() onAlignedYChanged: _queueFullSync()
onAlignedWidthChanged: _queueFullSync() onAlignedWidthChanged: _queueFullSync()
onContentAnimXChanged: _queueAnimSync() // Cheap deduped scalar writes: publish synchronously to stay in the same frame.
onContentAnimYChanged: _queueAnimSync() onContentAnimXChanged: _syncPopoutAnim("x")
onRenderedAlignedYChanged: _queueBodySync() onContentAnimYChanged: _syncPopoutAnim("y")
onRenderedAlignedHeightChanged: _queueBodySync() onRenderedAlignedYChanged: _syncPopoutBody()
onRenderedAlignedHeightChanged: _syncPopoutBody()
onScreenChanged: { onScreenChanged: {
_resetPublishedBody(); _resetPublishedBody();
_queueFullSync(); _queueFullSync();
@@ -517,6 +498,10 @@ Item {
animationsEnabled = true; animationsEnabled = true;
shouldBeVisible = true; shouldBeVisible = true;
Qt.callLater(() => {
if (root.shouldBeVisible)
root._keyboardReady = true;
});
if (shouldBeVisible && screen) { if (shouldBeVisible && screen) {
opened(); opened();
} }
@@ -530,6 +515,7 @@ Item {
_resetPublishedBody(); _resetPublishedBody();
isClosing = true; isClosing = true;
shouldBeVisible = false; shouldBeVisible = false;
_keyboardReady = false;
_primeContent = false; _primeContent = false;
PopoutManager.popoutChanged(); PopoutManager.popoutChanged();
closeTimer.restart(); closeTimer.restart();
@@ -743,9 +729,9 @@ Item {
readonly property real pubBodyW: morphSeedW + (alignedWidth - morphSeedW) * morphProgress readonly property real pubBodyW: morphSeedW + (alignedWidth - morphSeedW) * morphProgress
readonly property real pubBodyH: morphSeedH + (renderedAlignedHeight - morphSeedH) * morphProgress readonly property real pubBodyH: morphSeedH + (renderedAlignedHeight - morphSeedH) * morphProgress
// One animation drives all four coordinates, so queue one coalesced state update // One animation drives all four coordinates, so publish once per progress
// per progress tick instead of reacting independently to each derived property. // tick instead of reacting independently to each derived property.
onMorphProgressChanged: _queueBodySync() onMorphProgressChanged: _syncPopoutBody()
function _beginMorphTravel() { function _beginMorphTravel() {
morphTravelEnabled = false; morphTravelEnabled = false;
@@ -967,7 +953,7 @@ Item {
WlrLayershell.namespace: root.layerNamespace WlrLayershell.namespace: root.layerNamespace
WlrLayershell.layer: root.effectivePopoutLayer WlrLayershell.layer: root.effectivePopoutLayer
WlrLayershell.exclusiveZone: -1 WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(shouldBeVisible, customKeyboardFocus) WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(shouldBeVisible && root._keyboardReady, customKeyboardFocus)
readonly property bool _fullHeight: root.fullHeightSurface readonly property bool _fullHeight: root.fullHeightSurface
anchors { anchors {
+5 -5
View File
@@ -620,13 +620,13 @@ Item {
id: popoutBlur id: popoutBlur
targetWindow: contentWindow targetWindow: contentWindow
readonly property real s: Math.min(1, contentContainer.scaleValue) readonly property real s: Math.min(1, contentContainer.scaleValue)
readonly property real op: Math.max(0, Math.min(1, (morph.openProgress - 0.08) * 1.6))
readonly property bool revealClipActive: root.fluidStandaloneActive readonly property bool revealClipActive: root.fluidStandaloneActive
blurX: revealClipActive ? contentContainer.x : contentContainer.x + contentContainer.width * (1 - s * op) * 0.5 + Theme.snap(contentContainer.animX, root.dpr) // Blur tracks the surface's scaled rect, matching the connected backend
blurY: revealClipActive ? contentContainer.y : contentContainer.y + contentContainer.height * (1 - s * op) * 0.5 + Theme.snap(contentContainer.animY, root.dpr) blurX: revealClipActive ? contentContainer.x : contentContainer.x + contentContainer.width * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr)
blurWidth: root.shouldBeVisible ? (revealClipActive ? contentContainer.width : contentContainer.width * s * op) : 0 blurY: revealClipActive ? contentContainer.y : contentContainer.y + contentContainer.height * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr)
blurHeight: root.shouldBeVisible ? (revealClipActive ? contentContainer.height : contentContainer.height * s * op) : 0 blurWidth: root.shouldBeVisible ? (revealClipActive ? contentContainer.width : contentContainer.width * s) : 0
blurHeight: root.shouldBeVisible ? (revealClipActive ? contentContainer.height : contentContainer.height * s) : 0
blurRadius: Theme.cornerRadius blurRadius: Theme.cornerRadius
clipEnabled: revealClipActive clipEnabled: revealClipActive
clipX: contentContainer.x + contentContainer.revealX clipX: contentContainer.x + contentContainer.revealX
+2 -1
View File
@@ -99,8 +99,9 @@ Item {
root._clear(); root._clear();
} }
function onResourcesLost() { function onResourcesLost() {
lifecycleKickAction.cancel();
root._clear(); root._clear();
// Re-arm so blur self-heals since instances are no longer recreated per open
root._scheduleLifecycleKick();
} }
function onWindowConnected() { function onWindowConnected() {
root._scheduleLifecycleKick(); root._scheduleLifecycleKick();