mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-10 05:03:28 -04:00
refactor(frame): improve connected mode surface recovery
- share modal and launcher ownership handling - recover missing background and blur layers
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var modalHandle
|
||||
required property string claimPrefix
|
||||
property string screenName: ""
|
||||
property bool enabled: false
|
||||
property bool active: false
|
||||
property bool presented: false
|
||||
property bool dockBlocked: false
|
||||
property string dockSide: ""
|
||||
|
||||
property string claimId: ""
|
||||
property string claimedScreenName: ""
|
||||
|
||||
signal recoveryRequested
|
||||
|
||||
visible: false
|
||||
|
||||
function _nextClaimId() {
|
||||
return claimPrefix + ":" + (new Date()).getTime() + ":" + Math.floor(Math.random() * 1000);
|
||||
}
|
||||
|
||||
function _isCurrentModal(name) {
|
||||
return !!name && ModalManager.isCurrentModal(modalHandle, name);
|
||||
}
|
||||
|
||||
function _shouldRecover() {
|
||||
return active && enabled && _isCurrentModal(screenName);
|
||||
}
|
||||
|
||||
function _requestRecovery() {
|
||||
if (_shouldRecover())
|
||||
recoveryRequested();
|
||||
}
|
||||
|
||||
function publish(state) {
|
||||
if (!enabled || !screenName || !state) {
|
||||
release();
|
||||
return false;
|
||||
}
|
||||
if (claimedScreenName && claimedScreenName !== screenName)
|
||||
release();
|
||||
|
||||
const isCurrent = _isCurrentModal(screenName);
|
||||
let isClaim = !claimId;
|
||||
if (isClaim && !isCurrent)
|
||||
return false;
|
||||
if (isClaim)
|
||||
claimId = _nextClaimId();
|
||||
|
||||
let published = isClaim ? ConnectedModeState.claimModalState(screenName, state, claimId) : ConnectedModeState.ensureModalState(screenName, state, claimId);
|
||||
if (!published && !isClaim && isCurrent) {
|
||||
ConnectedModeState.releaseDockRetract(claimId);
|
||||
claimId = _nextClaimId();
|
||||
published = ConnectedModeState.claimModalState(screenName, state, claimId);
|
||||
}
|
||||
if (!published)
|
||||
return false;
|
||||
|
||||
claimedScreenName = screenName;
|
||||
if (dockBlocked && presented)
|
||||
ConnectedModeState.requestDockRetract(claimId, screenName, dockSide);
|
||||
else
|
||||
ConnectedModeState.releaseDockRetract(claimId);
|
||||
return true;
|
||||
}
|
||||
|
||||
function updateAnim(animX, animY) {
|
||||
if (!enabled || !claimId || !claimedScreenName)
|
||||
return false;
|
||||
if (!ConnectedModeState.hasModalOwner(claimedScreenName, claimId)) {
|
||||
_requestRecovery();
|
||||
return false;
|
||||
}
|
||||
return ConnectedModeState.setModalAnim(claimedScreenName, animX, animY, claimId);
|
||||
}
|
||||
|
||||
function updateBody(bodyX, bodyY, bodyW, bodyH) {
|
||||
if (!enabled || !claimId || !claimedScreenName)
|
||||
return false;
|
||||
if (!ConnectedModeState.hasModalOwner(claimedScreenName, claimId)) {
|
||||
_requestRecovery();
|
||||
return false;
|
||||
}
|
||||
return ConnectedModeState.setModalBody(claimedScreenName, bodyX, bodyY, bodyW, bodyH, claimId);
|
||||
}
|
||||
|
||||
function release() {
|
||||
if (!claimId)
|
||||
return;
|
||||
ConnectedModeState.releaseDockRetract(claimId);
|
||||
const releasedClaimId = claimId;
|
||||
const releasedScreenName = claimedScreenName;
|
||||
claimId = "";
|
||||
claimedScreenName = "";
|
||||
if (releasedScreenName)
|
||||
ConnectedModeState.clearModalState(releasedScreenName, releasedClaimId);
|
||||
}
|
||||
|
||||
Component.onDestruction: release()
|
||||
|
||||
Connections {
|
||||
target: ModalManager
|
||||
function onModalChanged() {
|
||||
root._requestRecovery();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: ConnectedModeState
|
||||
function onModalOwnersChanged() {
|
||||
if (!ConnectedModeState.hasModalOwner(root.screenName, root.claimId))
|
||||
root._requestRecovery();
|
||||
}
|
||||
function onModalStatesChanged() {
|
||||
if (!ConnectedModeState.modalStates[root.screenName])
|
||||
root._requestRecovery();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,10 @@ Singleton {
|
||||
// Dock slide offsets — hot-path updates separated from full geometry state
|
||||
property var dockSlides: ({})
|
||||
|
||||
// Surfaces are keyed by screen.name. FrameWindow watches to refresh connected chrome
|
||||
// after claim/release boundaries without tracking each animation frame
|
||||
property var surfaceRevisions: ({})
|
||||
|
||||
function _cloneDict(src) {
|
||||
const next = {};
|
||||
for (const k in src)
|
||||
@@ -45,16 +49,31 @@ Singleton {
|
||||
return next;
|
||||
}
|
||||
|
||||
function _bumpSurfaceRevision(screenName) {
|
||||
if (!screenName)
|
||||
return;
|
||||
const next = _cloneDict(surfaceRevisions);
|
||||
next[screenName] = Number(next[screenName] || 0) + 1;
|
||||
surfaceRevisions = next;
|
||||
}
|
||||
|
||||
function hasPopoutOwner(claimId) {
|
||||
return !!claimId && popoutOwnerId === claimId;
|
||||
}
|
||||
|
||||
function claimPopout(claimId, state) {
|
||||
if (!claimId)
|
||||
if (!claimId || !state)
|
||||
return false;
|
||||
|
||||
const previousScreen = popoutScreen;
|
||||
popoutOwnerId = claimId;
|
||||
return updatePopout(claimId, state);
|
||||
const ok = updatePopout(claimId, state);
|
||||
if (ok) {
|
||||
if (previousScreen && previousScreen !== popoutScreen)
|
||||
_bumpSurfaceRevision(previousScreen);
|
||||
_bumpSurfaceRevision(popoutScreen);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
function updatePopout(claimId, state) {
|
||||
@@ -91,6 +110,7 @@ Singleton {
|
||||
if (!hasPopoutOwner(claimId))
|
||||
return false;
|
||||
|
||||
const releasedScreen = popoutScreen;
|
||||
popoutOwnerId = "";
|
||||
popoutVisible = false;
|
||||
popoutBarSide = "top";
|
||||
@@ -103,6 +123,7 @@ Singleton {
|
||||
popoutScreen = "";
|
||||
popoutOmitStartConnector = false;
|
||||
popoutOmitEndConnector = false;
|
||||
_bumpSurfaceRevision(releasedScreen);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -174,10 +195,13 @@ Singleton {
|
||||
const normalized = _normalizeDockState(state);
|
||||
if (_sameDockState(dockStates[screenName], normalized))
|
||||
return true;
|
||||
const previous = dockStates[screenName] || emptyDockState;
|
||||
|
||||
const next = _cloneDict(dockStates);
|
||||
next[screenName] = normalized;
|
||||
dockStates = next;
|
||||
if (!!previous.reveal !== !!normalized.reveal)
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -195,6 +219,7 @@ Singleton {
|
||||
delete nextSlides[screenName];
|
||||
dockSlides = nextSlides;
|
||||
}
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -260,10 +285,13 @@ Singleton {
|
||||
const normalized = _normalizeNotificationState(state);
|
||||
if (_sameNotificationState(notificationStates[screenName], normalized))
|
||||
return true;
|
||||
const previous = notificationStates[screenName] || emptyNotificationState;
|
||||
|
||||
const next = _cloneDict(notificationStates);
|
||||
next[screenName] = normalized;
|
||||
notificationStates = next;
|
||||
if (!!previous.visible !== !!normalized.visible)
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -274,6 +302,7 @@ Singleton {
|
||||
const next = _cloneDict(notificationStates);
|
||||
delete next[screenName];
|
||||
notificationStates = next;
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -330,18 +359,17 @@ Singleton {
|
||||
modalOwners = nextOwners;
|
||||
}
|
||||
const normalized = _normalizeModalState(state);
|
||||
if (_sameModalState(modalStates[screenName], normalized))
|
||||
return true;
|
||||
const next = _cloneDict(modalStates);
|
||||
next[screenName] = normalized;
|
||||
modalStates = next;
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
}
|
||||
|
||||
function updateModalState(screenName, state, ownerId) {
|
||||
if (!screenName || !state)
|
||||
return false;
|
||||
if (ownerId && modalOwners[screenName] && modalOwners[screenName] !== ownerId)
|
||||
if (ownerId && modalOwners[screenName] !== ownerId)
|
||||
return false;
|
||||
const normalized = _normalizeModalState(state);
|
||||
if (_sameModalState(modalStates[screenName], normalized))
|
||||
@@ -352,30 +380,50 @@ Singleton {
|
||||
return true;
|
||||
}
|
||||
|
||||
function hasModalOwner(screenName, ownerId) {
|
||||
return !!screenName && !!ownerId && modalOwners[screenName] === ownerId;
|
||||
}
|
||||
|
||||
function ensureModalState(screenName, state, ownerId) {
|
||||
if (!screenName || !state || !ownerId)
|
||||
return false;
|
||||
const currentOwner = modalOwners[screenName] || "";
|
||||
if (currentOwner && currentOwner !== ownerId)
|
||||
return false;
|
||||
if (!currentOwner)
|
||||
return claimModalState(screenName, state, ownerId);
|
||||
return updateModalState(screenName, state, ownerId);
|
||||
}
|
||||
|
||||
function setModalState(screenName, state) {
|
||||
return updateModalState(screenName, state, null);
|
||||
}
|
||||
|
||||
function clearModalState(screenName, ownerId) {
|
||||
if (!screenName || !modalStates[screenName])
|
||||
if (!screenName)
|
||||
return false;
|
||||
if (ownerId && modalOwners[screenName] && modalOwners[screenName] !== ownerId)
|
||||
if (ownerId && modalOwners[screenName] !== ownerId)
|
||||
return false;
|
||||
if (!modalStates[screenName] && !modalOwners[screenName])
|
||||
return false;
|
||||
|
||||
const next = _cloneDict(modalStates);
|
||||
delete next[screenName];
|
||||
modalStates = next;
|
||||
if (modalStates[screenName]) {
|
||||
const next = _cloneDict(modalStates);
|
||||
delete next[screenName];
|
||||
modalStates = next;
|
||||
}
|
||||
|
||||
if (modalOwners[screenName]) {
|
||||
const nextOwners = _cloneDict(modalOwners);
|
||||
delete nextOwners[screenName];
|
||||
modalOwners = nextOwners;
|
||||
}
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
}
|
||||
|
||||
function setModalAnim(screenName, animX, animY, ownerId) {
|
||||
if (ownerId && modalOwners[screenName] && modalOwners[screenName] !== ownerId)
|
||||
if (ownerId && modalOwners[screenName] !== ownerId)
|
||||
return false;
|
||||
const cur = screenName ? modalStates[screenName] : null;
|
||||
if (!cur)
|
||||
@@ -394,7 +442,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function setModalBody(screenName, bodyX, bodyY, bodyW, bodyH, ownerId) {
|
||||
if (ownerId && modalOwners[screenName] && modalOwners[screenName] !== ownerId)
|
||||
if (ownerId && modalOwners[screenName] !== ownerId)
|
||||
return false;
|
||||
const cur = screenName ? modalStates[screenName] : null;
|
||||
if (!cur)
|
||||
@@ -492,6 +540,9 @@ Singleton {
|
||||
const nextModalOwners = pruneKeyed(modalOwners);
|
||||
if (nextModalOwners !== null)
|
||||
modalOwners = nextModalOwners;
|
||||
const nextSurfaceRevisions = pruneKeyed(surfaceRevisions);
|
||||
if (nextSurfaceRevisions !== null)
|
||||
surfaceRevisions = nextSurfaceRevisions;
|
||||
|
||||
let retractChanged = false;
|
||||
const nextRetract = {};
|
||||
@@ -512,7 +563,12 @@ Singleton {
|
||||
Connections {
|
||||
target: Quickshell
|
||||
function onScreensChanged() {
|
||||
root._pruneToLiveScreens();
|
||||
screenPruneAction.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
DeferredAction {
|
||||
id: screenPruneAction
|
||||
onTriggered: root._pruneToLiveScreens()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,11 @@ Singleton {
|
||||
});
|
||||
}
|
||||
|
||||
function isCurrentModal(modal, screenName) {
|
||||
const name = screenName || modal?.effectiveScreen?.name || "unknown";
|
||||
return currentModalsByScreen[name] === modal;
|
||||
}
|
||||
|
||||
function closeModal(modal) {
|
||||
const screenName = modal.effectiveScreen?.name ?? "unknown";
|
||||
if (currentModalsByScreen[screenName] === modal) {
|
||||
|
||||
@@ -98,6 +98,11 @@ Singleton {
|
||||
return currentPopoutsByScreen[screen.name] || null;
|
||||
}
|
||||
|
||||
function isCurrentPopout(popout, screenName) {
|
||||
const name = screenName || popout?.screen?.name || "";
|
||||
return !!name && currentPopoutsByScreen[name] === popout;
|
||||
}
|
||||
|
||||
function requestPopout(popout, tabIndex, triggerSource) {
|
||||
if (!popout || !popout.screen)
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user