1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-05-03 02:52:07 -04:00

general fixes and audit

This commit is contained in:
bbedward
2026-05-01 11:58:43 -04:00
committed by purian23
parent 9018002959
commit 5f1cff2e58
12 changed files with 232 additions and 102 deletions

View File

@@ -200,8 +200,6 @@ Singleton {
return true;
}
// ─── Notification state (per screen, updated by NotificationSurface) ──────
readonly property var emptyNotificationState: ({
"visible": false,
"barSide": "top",
@@ -369,8 +367,6 @@ Singleton {
return true;
}
// ─── Dock retract coordination ────────────────────────────────
property var dockRetractRequests: ({})
function requestDockRetract(requesterId, screenName, side) {
@@ -407,4 +403,64 @@ 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 || [];
for (let i = 0; i < screens.length; i++) {
const s = screens[i];
if (s && s.name)
live[s.name] = true;
}
function pruneKeyed(dict) {
let changed = false;
const next = {};
for (const k in dict) {
if (live[k])
next[k] = dict[k];
else
changed = true;
}
return changed ? next : null;
}
const nextDock = pruneKeyed(dockStates);
if (nextDock !== null)
dockStates = nextDock;
const nextSlides = pruneKeyed(dockSlides);
if (nextSlides !== null)
dockSlides = nextSlides;
const nextNotif = pruneKeyed(notificationStates);
if (nextNotif !== null)
notificationStates = nextNotif;
const nextModal = pruneKeyed(modalStates);
if (nextModal !== null)
modalStates = nextModal;
let retractChanged = false;
const nextRetract = {};
for (const k in dockRetractRequests) {
const r = dockRetractRequests[k];
if (r && live[r.screenName])
nextRetract[k] = r;
else
retractChanged = true;
}
if (retractChanged)
dockRetractRequests = nextRetract;
if (popoutOwnerId && popoutScreen && !live[popoutScreen])
releasePopout(popoutOwnerId);
}
Connections {
target: Quickshell
function onScreensChanged() {
root._pruneToLiveScreens();
}
}
}

View File

@@ -986,7 +986,6 @@ Singleton {
"expressiveEffects": [0.34, 0.8, 0.34, 1, 1, 1]
}
// ─── Animation variant proxy ──────────────────────────────────────────────
// Theme is the canonical access point for animation variant state. The
// aliases below forward to AnimVariants.qml so consumers don't need two
// imports. ~200 call sites read through Theme.variantEnterCurve /

View File

@@ -84,9 +84,31 @@ Item {
impl.item.toggle();
}
readonly property var _desiredBackend: SettingsData.connectedFrameModeActive ? connectedComp : standaloneComp
property var _resolvedBackend: null
Component.onCompleted: _resolvedBackend = _desiredBackend
Connections {
target: SettingsData
function onConnectedFrameModeActiveChanged() {
root._maybeResolveBackend();
}
}
// Defer Loader source-component swap until impl is fully closed; avoids
// tearing down a modal mid-animation when frame mode is toggled.
function _maybeResolveBackend() {
if (_resolvedBackend === _desiredBackend)
return;
if (impl.item && (impl.item.shouldBeVisible || impl.item.isClosing))
return;
_resolvedBackend = _desiredBackend;
}
Loader {
id: impl
sourceComponent: SettingsData.connectedFrameModeActive ? connectedComp : standaloneComp
sourceComponent: root._resolvedBackend
onItemChanged: if (item)
root._wireBackend(item)
}
@@ -137,20 +159,7 @@ Item {
it.useOverlayLayer = Qt.binding(() => root.useOverlayLayer);
it.shouldBeVisible = root.shouldBeVisible;
it.shouldBeVisibleChanged.connect(function () {
if (root.shouldBeVisible !== it.shouldBeVisible)
root.shouldBeVisible = it.shouldBeVisible;
});
it.shouldHaveFocus = root.shouldHaveFocus;
it.shouldHaveFocusChanged.connect(function () {
if (root.shouldHaveFocus !== it.shouldHaveFocus)
root.shouldHaveFocus = it.shouldHaveFocus;
});
it.opened.connect(root.opened);
it.dialogClosed.connect(root.dialogClosed);
it.backgroundClicked.connect(root.backgroundClicked);
if (it.modalFocusScope)
_modalFocusScope.parent = it.modalFocusScope;
@@ -167,4 +176,32 @@ Item {
impl.item.shouldHaveFocus = root.shouldHaveFocus;
}
}
Connections {
target: impl.item
ignoreUnknownSignals: true
function onShouldBeVisibleChanged() {
if (impl.item && root.shouldBeVisible !== impl.item.shouldBeVisible)
root.shouldBeVisible = impl.item.shouldBeVisible;
}
function onShouldHaveFocusChanged() {
if (impl.item && root.shouldHaveFocus !== impl.item.shouldHaveFocus)
root.shouldHaveFocus = impl.item.shouldHaveFocus;
}
function onOpened() {
root.opened();
}
function onDialogClosed() {
root.dialogClosed();
root._maybeResolveBackend();
}
function onBackgroundClicked() {
root.backgroundClicked();
}
}
}

View File

@@ -95,7 +95,6 @@ Item {
property bool animationsEnabled: true
// ─── Connected chrome sync ────────────────────────────────────────────────
property string _chromeClaimId: ""
property bool _fullSyncPending: false
@@ -341,8 +340,6 @@ Item {
readonly property real shadowMotionPadding: {
if (Theme.isConnectedEffect)
return 0;
if (Theme.isDirectionalEffect)
return 0;
if (animationType === "slide")
return 30;
if (Theme.isDirectionalEffect)

View File

@@ -60,9 +60,31 @@ Item {
impl.item.toggleWithMode(mode);
}
readonly property var _desiredBackend: SettingsData.connectedFrameModeActive ? connectedComp : standaloneComp
property var _resolvedBackend: null
Component.onCompleted: _resolvedBackend = _desiredBackend
Connections {
target: SettingsData
function onConnectedFrameModeActiveChanged() {
root._maybeResolveBackend();
}
}
// Defer Loader source-component swap until impl is fully closed; avoids
// tearing down the launcher mid-animation when frame mode is toggled.
function _maybeResolveBackend() {
if (_resolvedBackend === _desiredBackend)
return;
if (impl.item && (impl.item.spotlightOpen || impl.item.isClosing))
return;
_resolvedBackend = _desiredBackend;
}
Loader {
id: impl
sourceComponent: SettingsData.connectedFrameModeActive ? connectedComp : standaloneComp
sourceComponent: root._resolvedBackend
onItemChanged: if (item)
root._wireBackend(item)
}
@@ -81,6 +103,15 @@ Item {
if (!it)
return;
it.modalHandle = root;
it.dialogClosed.connect(root.dialogClosed);
}
Connections {
target: impl.item
ignoreUnknownSignals: true
function onDialogClosed() {
root.dialogClosed();
root._maybeResolveBackend();
}
}
}

View File

@@ -191,7 +191,6 @@ Item {
signal dialogClosed
// ─── Connected chrome sync ────────────────────────────────────────────────
property string _chromeClaimId: ""
property bool _fullSyncPending: false
@@ -558,7 +557,6 @@ Item {
}
}
// ── Background window: fullscreen, handles darkening + click-to-dismiss ──
PanelWindow {
id: backgroundWindow
visible: false
@@ -616,7 +614,6 @@ Item {
}
}
// ── Content window: SMALL, positioned with margins — only renders the modal area ──
PanelWindow {
id: contentWindow
visible: false

View File

@@ -145,7 +145,6 @@ Variants {
return Math.round(v * _dpr) / _dpr;
}
// ─── ConnectedModeState sync ────────────────────────────────────────
// Dock window origin in screen-relative coordinates (FrameWindow space).
function _dockWindowOriginX() {
if (!dock.isVertical)

View File

@@ -49,7 +49,6 @@ PanelWindow {
readonly property var _notifState: ConnectedModeState.notificationStates[win._screenName] || ConnectedModeState.emptyNotificationState
readonly property var _modalState: ConnectedModeState.modalStates[win._screenName] || ConnectedModeState.emptyModalState
// ─── Connected chrome convenience properties ──────────────────────────────
readonly property bool _connectedActive: win._frameActive && SettingsData.connectedFrameModeActive
readonly property string _barSide: {
const edges = win.barEdges;
@@ -780,7 +779,6 @@ PanelWindow {
radius: win._blurCutoutRadius
}
// ── Connected popout blur regions ──
Region {
item: _popoutBodyBlurAnchor
radius: win._surfaceRadius
@@ -827,7 +825,6 @@ PanelWindow {
}
}
// ── Connected dock blur regions ──
Region {
item: _dockBodyBlurAnchor
radius: win._dockBodyBlurRadius()
@@ -898,7 +895,6 @@ PanelWindow {
}
}
// ── Connected modal blur regions ──
Region {
item: _modalBodyBlurAnchor
radius: win._surfaceRadius
@@ -946,8 +942,6 @@ PanelWindow {
}
}
// ─── Connector position helpers ────────────────────────────────────────
function _dockBodyBlurRadius() {
return _dockBodyBlurAnchor._active ? Math.max(0, Math.min(win._surfaceRadius, _dockBodyBlurAnchor.width / 2, _dockBodyBlurAnchor.height / 2)) : win._surfaceRadius;
}
@@ -1219,8 +1213,6 @@ PanelWindow {
return (arcCorner === "topLeft" || arcCorner === "topRight") ? connectorY - r : connectorY + connectorHeight - r;
}
// ─── Blur build / teardown ────────────────────────────────────────────────
function _buildBlur() {
try {
if (!BlurService.enabled || !SettingsData.frameBlurEnabled || !win._frameActive || !win.visible) {
@@ -1297,8 +1289,6 @@ PanelWindow {
Component.onCompleted: Qt.callLater(() => win._buildBlur())
Component.onDestruction: win._teardownBlur()
// ─── Frame border ─────────────────────────────────────────────────────────
FrameBorder {
anchors.fill: parent
visible: win._frameActive && !win._connectedActive
@@ -1309,8 +1299,6 @@ PanelWindow {
cutoutRadius: win.cutoutRadius
}
// ─── Connected chrome fills ───────────────────────────────────────────────
Item {
id: _connectedSurfaceLayer
anchors.fill: parent

View File

@@ -130,8 +130,8 @@ Scope {
MouseArea {
anchors.fill: parent
onClicked: mouse => {
const localPos = mapToItem(contentContainer, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > contentContainer.width || localPos.y < 0 || localPos.y > contentContainer.height) {
const localPos = mapToItem(contentAnchor, mouse.x, mouse.y);
if (localPos.x < 0 || localPos.x > contentAnchor.width || localPos.y < 0 || localPos.y > contentAnchor.height) {
overviewScope.overviewOpen = false;
closeTimer.restart();
}
@@ -140,47 +140,24 @@ Scope {
}
Item {
id: contentContainer
id: contentAnchor
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 100
width: childrenRect.width
height: childrenRect.height
width: contentContainer.width
height: contentContainer.height
opacity: overviewScope.overviewOpen ? 1 : 0
transform: [scaleTransform, motionTransform]
Item {
id: contentContainer
width: childrenRect.width
height: childrenRect.height
transformOrigin: Item.Center
Scale {
id: scaleTransform
origin.x: contentContainer.width / 2
origin.y: contentContainer.height / 2
xScale: overviewScope.overviewOpen ? 1 : Theme.effectScaleCollapsed
yScale: overviewScope.overviewOpen ? 1 : Theme.effectScaleCollapsed
Behavior on xScale {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Behavior on yScale {
NumberAnimation {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
}
Translate {
id: motionTransform
opacity: overviewScope.overviewOpen ? 1 : 0
scale: overviewScope.overviewOpen ? 1 : Theme.effectScaleCollapsed
x: {
if (overviewScope.overviewOpen)
return 0;
if (Theme.isDirectionalEffect)
return 0;
if (Theme.isDepthEffect)
return Theme.effectAnimOffset * 0.25;
return 0;
@@ -195,8 +172,24 @@ Scope {
return Theme.effectAnimOffset;
}
Behavior on opacity {
OpacityAnimator {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Behavior on scale {
ScaleAnimator {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Behavior on x {
NumberAnimation {
XAnimator {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
@@ -204,30 +197,22 @@ Scope {
}
Behavior on y {
NumberAnimation {
YAnimator {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
}
Behavior on opacity {
OpacityAnimator {
duration: Theme.variantDuration(Theme.expressiveDurations.expressiveDefaultSpatial, overviewScope.overviewOpen)
easing.type: Easing.BezierSpline
easing.bezierCurve: overviewScope.overviewOpen ? Theme.variantModalEnterCurve : Theme.variantModalExitCurve
}
}
Loader {
id: overviewLoader
active: overviewScope.overviewOpen
asynchronous: false
Loader {
id: overviewLoader
active: overviewScope.overviewOpen
asynchronous: false
sourceComponent: OverviewWidget {
panelWindow: root
overviewOpen: overviewScope.overviewOpen
sourceComponent: OverviewWidget {
panelWindow: root
overviewOpen: overviewScope.overviewOpen
}
}
}
}

View File

@@ -23,7 +23,6 @@ Item {
property color fillColor: "transparent"
// ── Derived layout ──
readonly property bool _horiz: barSide === "top" || barSide === "bottom"
readonly property real _sc: Math.max(0, startConnectorRadius)
readonly property real _ec: Math.max(0, endConnectorRadius)

View File

@@ -75,6 +75,21 @@ Item {
readonly property real barWidth: impl.item ? impl.item.barWidth : 0
readonly property real barHeight: impl.item ? impl.item.barHeight : 0
readonly property bool useConnectedBackend: SettingsData.connectedFrameModeActive && !!screen && SettingsData.isScreenInPreferences(screen, SettingsData.frameScreenPreferences)
readonly property var _desiredBackend: useConnectedBackend ? connectedComp : standaloneComp
property var _resolvedBackend: null
onUseConnectedBackendChanged: _maybeResolveBackend()
Component.onCompleted: _resolvedBackend = _desiredBackend
// Defer Loader source-component swap until impl is fully closed; avoids
// tearing down a popout mid-animation when frame mode is toggled.
function _maybeResolveBackend() {
if (_resolvedBackend === _desiredBackend)
return;
if (impl.item && (impl.item.shouldBeVisible || impl.item.isClosing))
return;
_resolvedBackend = _desiredBackend;
}
function open() {
if (impl.item)
@@ -121,7 +136,7 @@ Item {
Loader {
id: impl
active: root.screen !== null
sourceComponent: root.useConnectedBackend ? connectedComp : standaloneComp
sourceComponent: root._resolvedBackend
onItemChanged: if (item)
root._wireBackend(item)
}
@@ -207,6 +222,7 @@ Item {
function onPopoutClosed() {
root.popoutClosed();
root._maybeResolveBackend();
}
function onBackgroundClicked() {

View File

@@ -178,15 +178,40 @@ Item {
setBarContext(pos, bottomGap);
}
// Briefly forces backgroundWindow.updatesEnabled true while the surface
// body changes, so the contentHoleRect mask carve-out commits to the
// compositor — otherwise the input region stays stuck at the popup's
// initial size and clicks in any newly-grown area dismiss the popup.
// Cleared by the frameSwapped Connections below as soon as the dirty
// frame ships, so the bg window goes back to skipping buffer updates.
property bool _bgCommitWindow: false
function _setSurfaceGeometry(bodyX, bodyY, bodyW, bodyH) {
_surfaceBodyX = Theme.snap(bodyX, dpr);
_surfaceBodyY = Theme.snap(bodyY, dpr);
_surfaceBodyW = Theme.snap(bodyW, dpr);
_surfaceBodyH = Theme.snap(bodyH, dpr);
const newX = Theme.snap(bodyX, dpr);
const newY = Theme.snap(bodyY, dpr);
const newW = Theme.snap(bodyW, dpr);
const newH = Theme.snap(bodyH, dpr);
const changed = newX !== _surfaceBodyX || newY !== _surfaceBodyY || newW !== _surfaceBodyW || newH !== _surfaceBodyH;
_surfaceBodyX = newX;
_surfaceBodyY = newY;
_surfaceBodyW = newW;
_surfaceBodyH = newH;
_surfaceMarginLeft = _surfaceBodyX - shadowBuffer;
_surfaceMarginTop = _surfaceBodyY - shadowBuffer;
_surfaceW = _surfaceBodyW + shadowBuffer * 2;
_surfaceH = _surfaceBodyH + shadowBuffer * 2;
if (changed && backgroundWindow.visible) {
_bgCommitWindow = true;
}
}
Connections {
target: backgroundWindow
ignoreUnknownSignals: true
function onFrameSwapped() {
if (root._bgCommitWindow)
root._bgCommitWindow = false;
}
}
function _setSettledSurfaceGeometry() {
@@ -455,9 +480,10 @@ Item {
screen: root.screen
visible: false
color: "transparent"
// When there's no overlay to render, skip buffer updates. Re-evaluates if
// overlayContent is assigned later (e.g., via a dispatcher forwarding it).
updatesEnabled: root.overlayContent !== null
// Skip buffer updates when there's nothing to render. Briefly flipped
// true via _bgCommitWindow when _surfaceBodyW/H changes so the
// contentHoleRect mask carve-out actually commits to the compositor.
updatesEnabled: root.overlayContent !== null || root._bgCommitWindow
WlrLayershell.namespace: root.layerNamespace + ":background"
WlrLayershell.layer: WlrLayershell.Top