1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-08-01 19:18:28 -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
+10 -30
View File
@@ -162,37 +162,16 @@ Item {
_publishModalChromeState();
}
property bool _animSyncQueued: false
property bool _bodySyncQueued: false
function _queueFullSync() {
_fullSyncPending = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _queueAnimSync() {
_animSyncQueued = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _queueBodySync() {
_bodySyncQueued = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _flushSync() {
const fullDirty = _fullSyncPending;
const animDirty = _animSyncQueued;
const bodyDirty = _bodySyncQueued;
if (!_fullSyncPending)
return;
_fullSyncPending = false;
_animSyncQueued = false;
_bodySyncQueued = false;
if (fullDirty)
_syncModalChromeState();
if (animDirty)
_syncModalAnim();
if (bodyDirty)
_syncModalBody();
_syncModalChromeState();
}
function _syncModalAnim() {
@@ -216,10 +195,11 @@ Item {
onFrameOwnsConnectedChromeChanged: _syncModalChromeState()
onResolvedConnectedBarSideChanged: _queueFullSync()
onShouldBeVisibleChanged: _queueFullSync()
onAlignedXChanged: _queueBodySync()
onAlignedYChanged: _queueBodySync()
onAlignedWidthChanged: _queueBodySync()
onAlignedHeightChanged: _queueBodySync()
// Low resource scalar writes: publish synchronously to stay in the same frame
onAlignedXChanged: _syncModalBody()
onAlignedYChanged: _syncModalBody()
onAlignedWidthChanged: _syncModalBody()
onAlignedHeightChanged: _syncModalBody()
Connections {
target: contentWindow
@@ -613,9 +593,9 @@ Item {
readonly property real scaleValue: computedScaleCollapsed + (1.0 - computedScaleCollapsed) * morph.openProgress
onAnimXChanged: if (root.frameOwnsConnectedChrome)
root._queueAnimSync()
root._syncModalAnim()
onAnimYChanged: if (root.frameOwnsConnectedChrome)
root._queueAnimSync()
root._syncModalAnim()
Item {
id: contentContainer
@@ -244,11 +244,11 @@ Item {
WindowBlur {
targetWindow: contentWindow
readonly property real s: Math.min(1, modalContainer.scaleValue)
readonly property real op: Math.max(0, Math.min(1, (morph.openProgress - 0.06) * 2))
blurX: modalContainer.x + modalContainer.width * (1 - s * op) * 0.5 + Theme.snap(modalContainer.animX, root.dpr)
blurY: modalContainer.y + modalContainer.height * (1 - s * op) * 0.5 + Theme.snap(modalContainer.animY, root.dpr)
blurWidth: root.shouldBeVisible ? modalContainer.width * s * op : 0
blurHeight: root.shouldBeVisible ? modalContainer.height * s * op : 0
// Blur tracks the surface's scaled rect, matching the connected backend.
blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5 + Theme.snap(modalContainer.animX, root.dpr)
blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5 + Theme.snap(modalContainer.animY, root.dpr)
blurWidth: root.shouldBeVisible ? modalContainer.width * s : 0
blurHeight: root.shouldBeVisible ? modalContainer.height * s : 0
blurRadius: root.cornerRadius
}
@@ -364,11 +364,11 @@ Item {
WindowBlur {
targetWindow: launcherWindow
readonly property real s: Math.min(1, modalContainer.publishedScale)
readonly property real op: Math.max(0, Math.min(1, (modalContainer.publishedOpacity - 0.06) * 2))
blurX: modalContainer.x + modalContainer.width * (1 - s * op) * 0.5
blurY: modalContainer.y + modalContainer.height * (1 - s * op) * 0.5
blurWidth: contentVisible ? modalContainer.width * s * op : 0
blurHeight: contentVisible ? modalContainer.height * s * op : 0
// Blur tracks the surface's scaled rect
blurX: modalContainer.x + modalContainer.width * (1 - s) * 0.5
blurY: modalContainer.y + modalContainer.height * (1 - s) * 0.5
blurWidth: contentVisible ? modalContainer.width * s : 0
blurHeight: contentVisible ? modalContainer.height * s : 0
blurRadius: root.cornerRadius
}
+5 -3
View File
@@ -154,10 +154,12 @@ Singleton {
continue;
if (!x || !y)
return false;
// Only niri's enriched snapshots support value comparison.
if (x.niriWindowId === undefined || y.niriWindowId === undefined)
// Only niri/mango enriched snapshots support value comparison
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;
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 true;
+21 -35
View File
@@ -39,6 +39,8 @@ Item {
property bool fullHeightSurface: false
property bool _primeContent: 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 real _chromeAnimTravelX: 1
property real _chromeAnimTravelY: 1
@@ -241,7 +243,8 @@ Item {
}
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 phase = root.isClosing ? "closing" : (!presented ? "hidden" : (!contentWindow.visible && root.shouldBeVisible ? "opening" : "open"));
const bodyX = Theme.snap(root.pubBodyX, root.dpr);
@@ -353,48 +356,26 @@ Item {
_publishedBodyValid = false;
}
property bool _animSyncQueued: false
property bool _bodySyncQueued: false
function _queueFullSync() {
_fullSyncQueued = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _queueAnimSync() {
_animSyncQueued = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _queueBodySync() {
_bodySyncQueued = true;
if (!_syncTimer.running)
_syncTimer.restart();
}
function _flushSync() {
const fullDirty = _fullSyncQueued;
const animDirty = _animSyncQueued;
const bodyDirty = _bodySyncQueued;
if (!_fullSyncQueued)
return;
_fullSyncQueued = false;
_animSyncQueued = false;
_bodySyncQueued = false;
if (fullDirty)
_syncPopoutChromeState();
if (animDirty) {
_syncPopoutAnim("x");
_syncPopoutAnim("y");
}
if (bodyDirty)
_syncPopoutBody();
_syncPopoutChromeState();
}
onAlignedXChanged: _queueFullSync()
onAlignedYChanged: _queueFullSync()
onAlignedWidthChanged: _queueFullSync()
onContentAnimXChanged: _queueAnimSync()
onContentAnimYChanged: _queueAnimSync()
onRenderedAlignedYChanged: _queueBodySync()
onRenderedAlignedHeightChanged: _queueBodySync()
// Cheap deduped scalar writes: publish synchronously to stay in the same frame.
onContentAnimXChanged: _syncPopoutAnim("x")
onContentAnimYChanged: _syncPopoutAnim("y")
onRenderedAlignedYChanged: _syncPopoutBody()
onRenderedAlignedHeightChanged: _syncPopoutBody()
onScreenChanged: {
_resetPublishedBody();
_queueFullSync();
@@ -517,6 +498,10 @@ Item {
animationsEnabled = true;
shouldBeVisible = true;
Qt.callLater(() => {
if (root.shouldBeVisible)
root._keyboardReady = true;
});
if (shouldBeVisible && screen) {
opened();
}
@@ -530,6 +515,7 @@ Item {
_resetPublishedBody();
isClosing = true;
shouldBeVisible = false;
_keyboardReady = false;
_primeContent = false;
PopoutManager.popoutChanged();
closeTimer.restart();
@@ -743,9 +729,9 @@ Item {
readonly property real pubBodyW: morphSeedW + (alignedWidth - morphSeedW) * morphProgress
readonly property real pubBodyH: morphSeedH + (renderedAlignedHeight - morphSeedH) * morphProgress
// One animation drives all four coordinates, so queue one coalesced state update
// per progress tick instead of reacting independently to each derived property.
onMorphProgressChanged: _queueBodySync()
// One animation drives all four coordinates, so publish once per progress
// tick instead of reacting independently to each derived property.
onMorphProgressChanged: _syncPopoutBody()
function _beginMorphTravel() {
morphTravelEnabled = false;
@@ -967,7 +953,7 @@ Item {
WlrLayershell.namespace: root.layerNamespace
WlrLayershell.layer: root.effectivePopoutLayer
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(shouldBeVisible, customKeyboardFocus)
WlrLayershell.keyboardFocus: KeyboardFocus.keyboardFocus(shouldBeVisible && root._keyboardReady, customKeyboardFocus)
readonly property bool _fullHeight: root.fullHeightSurface
anchors {
+5 -5
View File
@@ -620,13 +620,13 @@ Item {
id: popoutBlur
targetWindow: contentWindow
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
blurX: revealClipActive ? contentContainer.x : contentContainer.x + contentContainer.width * (1 - s * op) * 0.5 + Theme.snap(contentContainer.animX, root.dpr)
blurY: revealClipActive ? contentContainer.y : contentContainer.y + contentContainer.height * (1 - s * op) * 0.5 + Theme.snap(contentContainer.animY, root.dpr)
blurWidth: root.shouldBeVisible ? (revealClipActive ? contentContainer.width : contentContainer.width * s * op) : 0
blurHeight: root.shouldBeVisible ? (revealClipActive ? contentContainer.height : contentContainer.height * s * op) : 0
// Blur tracks the surface's scaled rect, matching the connected backend
blurX: revealClipActive ? contentContainer.x : contentContainer.x + contentContainer.width * (1 - s) * 0.5 + Theme.snap(contentContainer.animX, root.dpr)
blurY: revealClipActive ? contentContainer.y : contentContainer.y + contentContainer.height * (1 - s) * 0.5 + Theme.snap(contentContainer.animY, root.dpr)
blurWidth: root.shouldBeVisible ? (revealClipActive ? contentContainer.width : contentContainer.width * s) : 0
blurHeight: root.shouldBeVisible ? (revealClipActive ? contentContainer.height : contentContainer.height * s) : 0
blurRadius: Theme.cornerRadius
clipEnabled: revealClipActive
clipX: contentContainer.x + contentContainer.revealX
+2 -1
View File
@@ -99,8 +99,9 @@ Item {
root._clear();
}
function onResourcesLost() {
lifecycleKickAction.cancel();
root._clear();
// Re-arm so blur self-heals since instances are no longer recreated per open
root._scheduleLifecycleKick();
}
function onWindowConnected() {
root._scheduleLifecycleKick();