mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-15 15:45:20 -04:00
refactor(framemode): unify connected surface chrome via SDF pipeline
- Shadow system rewrite with SDF quads - Replace ConnectedShape/layer FBOs w/frame & chrome SDF shaders - Improve frame blur performance - Plugin performance gate
This commit is contained in:
@@ -3,10 +3,123 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import "ConnectedSurfaceDescriptor.js" as SurfaceDescriptor
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property var surfaceDescriptors: ({})
|
||||
|
||||
function _surfaceSlot(kind) {
|
||||
return SurfaceDescriptor.slotForKind(kind);
|
||||
}
|
||||
|
||||
function surfaceDescriptor(screenName, kind) {
|
||||
const slot = _surfaceSlot(kind);
|
||||
const screenDescriptors = screenName ? surfaceDescriptors[screenName] : null;
|
||||
const descriptor = screenDescriptors && screenDescriptors[slot] ? screenDescriptors[slot] : SurfaceDescriptor.empty(kind, screenName);
|
||||
let bodyRect = descriptor.bodyRect;
|
||||
let animationOffset = descriptor.animationOffset;
|
||||
if (slot === "popout" && popoutScreen === screenName) {
|
||||
bodyRect = {
|
||||
"x": popoutBodyX,
|
||||
"y": popoutBodyY,
|
||||
"width": popoutBodyW,
|
||||
"height": popoutBodyH
|
||||
};
|
||||
animationOffset = {
|
||||
"x": popoutAnimX,
|
||||
"y": popoutAnimY
|
||||
};
|
||||
} else if (slot === "modal" && modalStates[screenName]) {
|
||||
const modal = modalStates[screenName];
|
||||
bodyRect = {
|
||||
"x": modal.bodyX,
|
||||
"y": modal.bodyY,
|
||||
"width": modal.bodyW,
|
||||
"height": modal.bodyH
|
||||
};
|
||||
animationOffset = {
|
||||
"x": modal.animX,
|
||||
"y": modal.animY
|
||||
};
|
||||
} else if (slot === "dock" && dockStates[screenName]) {
|
||||
const dock = dockStates[screenName];
|
||||
const slide = dockSlides[screenName] || {
|
||||
"x": dock.slideX,
|
||||
"y": dock.slideY
|
||||
};
|
||||
bodyRect = {
|
||||
"x": dock.bodyX,
|
||||
"y": dock.bodyY,
|
||||
"width": dock.bodyW,
|
||||
"height": dock.bodyH
|
||||
};
|
||||
animationOffset = {
|
||||
"x": slide.x,
|
||||
"y": slide.y
|
||||
};
|
||||
} else if (slot === "notification" && notificationStates[screenName]) {
|
||||
const notification = notificationStates[screenName];
|
||||
bodyRect = {
|
||||
"x": notification.bodyX,
|
||||
"y": notification.bodyY,
|
||||
"width": notification.bodyW,
|
||||
"height": notification.bodyH
|
||||
};
|
||||
}
|
||||
return SurfaceDescriptor.normalize({
|
||||
"bodyRect": bodyRect,
|
||||
"animationOffset": animationOffset
|
||||
}, descriptor);
|
||||
}
|
||||
|
||||
function hasSurfaceDescriptor(screenName, kind, ownerId) {
|
||||
const descriptor = surfaceDescriptor(screenName, kind);
|
||||
return descriptor.phase !== "hidden" && (!ownerId || descriptor.ownerId === ownerId);
|
||||
}
|
||||
|
||||
function _setSurfaceDescriptor(screenName, slotKind, state, ownerId) {
|
||||
if (!screenName || !state)
|
||||
return false;
|
||||
const slot = _surfaceSlot(slotKind);
|
||||
const currentScreen = surfaceDescriptors[screenName] || {};
|
||||
const previous = currentScreen[slot] || SurfaceDescriptor.empty(state.kind || slotKind, screenName);
|
||||
let normalized = SurfaceDescriptor.normalize(Object.assign({}, state, {
|
||||
"ownerId": ownerId !== undefined ? ownerId : previous.ownerId,
|
||||
"screenName": screenName,
|
||||
"revision": previous.revision
|
||||
}), previous);
|
||||
if (SurfaceDescriptor.same(previous, normalized))
|
||||
return true;
|
||||
normalized = SurfaceDescriptor.withRevision(normalized, previous.revision + 1);
|
||||
const nextScreen = _cloneDict(currentScreen);
|
||||
nextScreen[slot] = normalized;
|
||||
const next = _cloneDict(surfaceDescriptors);
|
||||
next[screenName] = nextScreen;
|
||||
surfaceDescriptors = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
function _clearSurfaceDescriptor(screenName, kind, ownerId) {
|
||||
if (!screenName)
|
||||
return false;
|
||||
const slot = _surfaceSlot(kind);
|
||||
const currentScreen = surfaceDescriptors[screenName];
|
||||
const current = currentScreen ? currentScreen[slot] : null;
|
||||
if (!current || (ownerId && current.ownerId !== ownerId))
|
||||
return false;
|
||||
const nextScreen = _cloneDict(currentScreen);
|
||||
delete nextScreen[slot];
|
||||
const next = _cloneDict(surfaceDescriptors);
|
||||
if (Object.keys(nextScreen).length > 0)
|
||||
next[screenName] = nextScreen;
|
||||
else
|
||||
delete next[screenName];
|
||||
surfaceDescriptors = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
readonly property var emptyDockState: ({
|
||||
"reveal": false,
|
||||
"barSide": "bottom",
|
||||
@@ -18,7 +131,6 @@ Singleton {
|
||||
"slideY": 0
|
||||
})
|
||||
|
||||
// Popout state (updated by DankPopout when connectedFrameModeActive)
|
||||
property string popoutOwnerId: ""
|
||||
property bool popoutVisible: false
|
||||
property string popoutBarSide: "top"
|
||||
@@ -32,14 +144,10 @@ Singleton {
|
||||
property bool popoutOmitStartConnector: false
|
||||
property bool popoutOmitEndConnector: false
|
||||
|
||||
// Dock state (updated by Dock when connectedFrameModeActive), keyed by screen.name
|
||||
property var dockStates: ({})
|
||||
|
||||
// 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) {
|
||||
@@ -69,8 +177,10 @@ Singleton {
|
||||
popoutOwnerId = claimId;
|
||||
const ok = updatePopout(claimId, state);
|
||||
if (ok) {
|
||||
if (previousScreen && previousScreen !== popoutScreen)
|
||||
if (previousScreen && previousScreen !== popoutScreen) {
|
||||
_clearSurfaceDescriptor(previousScreen, "popout");
|
||||
_bumpSurfaceRevision(previousScreen);
|
||||
}
|
||||
_bumpSurfaceRevision(popoutScreen);
|
||||
}
|
||||
return ok;
|
||||
@@ -103,6 +213,21 @@ Singleton {
|
||||
if (state.omitEndConnector !== undefined)
|
||||
popoutOmitEndConnector = !!state.omitEndConnector;
|
||||
|
||||
_setSurfaceDescriptor(popoutScreen, "popout", Object.assign({}, state, {
|
||||
"kind": "popout",
|
||||
"screenName": popoutScreen,
|
||||
"visible": popoutVisible,
|
||||
"presented": state.presented !== undefined ? !!state.presented : popoutVisible,
|
||||
"barSide": popoutBarSide,
|
||||
"bodyX": popoutBodyX,
|
||||
"bodyY": popoutBodyY,
|
||||
"bodyW": popoutBodyW,
|
||||
"bodyH": popoutBodyH,
|
||||
"animX": popoutAnimX,
|
||||
"animY": popoutAnimY,
|
||||
"omitStartConnector": popoutOmitStartConnector,
|
||||
"omitEndConnector": popoutOmitEndConnector
|
||||
}), claimId);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -123,6 +248,7 @@ Singleton {
|
||||
popoutScreen = "";
|
||||
popoutOmitStartConnector = false;
|
||||
popoutOmitEndConnector = false;
|
||||
_clearSurfaceDescriptor(releasedScreen, "popout", claimId);
|
||||
_bumpSurfaceRevision(releasedScreen);
|
||||
return true;
|
||||
}
|
||||
@@ -193,13 +319,21 @@ Singleton {
|
||||
return false;
|
||||
|
||||
const normalized = _normalizeDockState(state);
|
||||
if (_sameDockState(dockStates[screenName], normalized))
|
||||
return true;
|
||||
const descriptorState = Object.assign({}, state, normalized, {
|
||||
"kind": "dock",
|
||||
"screenName": screenName,
|
||||
"visible": normalized.reveal,
|
||||
"presented": normalized.reveal,
|
||||
"phase": normalized.reveal ? (state.phase || "open") : "hidden"
|
||||
});
|
||||
const previous = dockStates[screenName] || emptyDockState;
|
||||
|
||||
const next = _cloneDict(dockStates);
|
||||
next[screenName] = normalized;
|
||||
dockStates = next;
|
||||
const stateChanged = !_sameDockState(dockStates[screenName], normalized);
|
||||
if (stateChanged) {
|
||||
const next = _cloneDict(dockStates);
|
||||
next[screenName] = normalized;
|
||||
dockStates = next;
|
||||
}
|
||||
_setSurfaceDescriptor(screenName, "dock", descriptorState, "dock:" + screenName);
|
||||
if (!!previous.reveal !== !!normalized.reveal)
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
@@ -212,8 +346,8 @@ Singleton {
|
||||
const next = _cloneDict(dockStates);
|
||||
delete next[screenName];
|
||||
dockStates = next;
|
||||
_clearSurfaceDescriptor(screenName, "dock");
|
||||
|
||||
// Also clear corresponding slide
|
||||
if (dockSlides[screenName]) {
|
||||
const nextSlides = _cloneDict(dockSlides);
|
||||
delete nextSlides[screenName];
|
||||
@@ -283,13 +417,20 @@ Singleton {
|
||||
return false;
|
||||
|
||||
const normalized = _normalizeNotificationState(state);
|
||||
if (_sameNotificationState(notificationStates[screenName], normalized))
|
||||
return true;
|
||||
const descriptorState = Object.assign({}, state, normalized, {
|
||||
"kind": "notification",
|
||||
"screenName": screenName,
|
||||
"presented": normalized.visible,
|
||||
"phase": normalized.visible ? (state.phase || "open") : "hidden"
|
||||
});
|
||||
const previous = notificationStates[screenName] || emptyNotificationState;
|
||||
|
||||
const next = _cloneDict(notificationStates);
|
||||
next[screenName] = normalized;
|
||||
notificationStates = next;
|
||||
const stateChanged = !_sameNotificationState(notificationStates[screenName], normalized);
|
||||
if (stateChanged) {
|
||||
const next = _cloneDict(notificationStates);
|
||||
next[screenName] = normalized;
|
||||
notificationStates = next;
|
||||
}
|
||||
_setSurfaceDescriptor(screenName, "notification", descriptorState, "notification:" + screenName);
|
||||
if (!!previous.visible !== !!normalized.visible)
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
@@ -302,11 +443,11 @@ Singleton {
|
||||
const next = _cloneDict(notificationStates);
|
||||
delete next[screenName];
|
||||
notificationStates = next;
|
||||
_clearSurfaceDescriptor(screenName, "notification");
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
}
|
||||
|
||||
// DankModal / DankLauncherV2Modal State
|
||||
readonly property var emptyModalState: ({
|
||||
"visible": false,
|
||||
"barSide": "bottom",
|
||||
@@ -362,6 +503,10 @@ Singleton {
|
||||
const next = _cloneDict(modalStates);
|
||||
next[screenName] = normalized;
|
||||
modalStates = next;
|
||||
_setSurfaceDescriptor(screenName, "modal", Object.assign({}, state, normalized, {
|
||||
"kind": state.kind || "modal",
|
||||
"screenName": screenName
|
||||
}), ownerId || "");
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
}
|
||||
@@ -372,11 +517,16 @@ Singleton {
|
||||
if (ownerId && modalOwners[screenName] !== ownerId)
|
||||
return false;
|
||||
const normalized = _normalizeModalState(state);
|
||||
if (_sameModalState(modalStates[screenName], normalized))
|
||||
return true;
|
||||
const next = _cloneDict(modalStates);
|
||||
next[screenName] = normalized;
|
||||
modalStates = next;
|
||||
const descriptorState = Object.assign({}, state, normalized, {
|
||||
"kind": state.kind || (surfaceDescriptor(screenName, "modal").kind || "modal"),
|
||||
"screenName": screenName
|
||||
});
|
||||
if (!_sameModalState(modalStates[screenName], normalized)) {
|
||||
const next = _cloneDict(modalStates);
|
||||
next[screenName] = normalized;
|
||||
modalStates = next;
|
||||
}
|
||||
_setSurfaceDescriptor(screenName, "modal", descriptorState, ownerId || modalOwners[screenName] || "");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -395,10 +545,6 @@ Singleton {
|
||||
return updateModalState(screenName, state, ownerId);
|
||||
}
|
||||
|
||||
function setModalState(screenName, state) {
|
||||
return updateModalState(screenName, state, null);
|
||||
}
|
||||
|
||||
function clearModalState(screenName, ownerId) {
|
||||
if (!screenName)
|
||||
return false;
|
||||
@@ -418,6 +564,7 @@ Singleton {
|
||||
delete nextOwners[screenName];
|
||||
modalOwners = nextOwners;
|
||||
}
|
||||
_clearSurfaceDescriptor(screenName, "modal", ownerId);
|
||||
_bumpSurfaceRevision(screenName);
|
||||
return true;
|
||||
}
|
||||
@@ -501,9 +648,6 @@ Singleton {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Prune state for screens that are no longer connected. Stale entries
|
||||
// accumulate across hotplug cycles otherwise — Frame's per-screen
|
||||
// FrameInstance doesn't notice when its peer dicts go orphan.
|
||||
function _pruneToLiveScreens() {
|
||||
const live = {};
|
||||
const screens = Quickshell.screens || [];
|
||||
@@ -543,6 +687,9 @@ Singleton {
|
||||
const nextSurfaceRevisions = pruneKeyed(surfaceRevisions);
|
||||
if (nextSurfaceRevisions !== null)
|
||||
surfaceRevisions = nextSurfaceRevisions;
|
||||
const nextDescriptors = pruneKeyed(surfaceDescriptors);
|
||||
if (nextDescriptors !== null)
|
||||
surfaceDescriptors = nextDescriptors;
|
||||
|
||||
let retractChanged = false;
|
||||
const nextRetract = {};
|
||||
|
||||
Reference in New Issue
Block a user