From 1c01774fdef4f8d7bb3996bd837352492291ae77 Mon Sep 17 00:00:00 2001 From: purian23 Date: Thu, 7 May 2026 23:03:31 -0400 Subject: [PATCH] fix(ConnectedMode): Update modal state management w/ownership Id --- quickshell/Common/ConnectedModeState.qml | 49 ++++++++++++++++--- .../Modals/Common/DankModalConnected.qml | 24 ++++++--- .../Modals/DankLauncherV2/ActionPanel.qml | 2 +- .../DankLauncherV2ModalConnected.qml | 28 ++++++----- .../Modals/DankLauncherV2/LauncherContent.qml | 2 +- 5 files changed, 79 insertions(+), 26 deletions(-) diff --git a/quickshell/Common/ConnectedModeState.qml b/quickshell/Common/ConnectedModeState.qml index e8bbd92c..488dd04b 100644 --- a/quickshell/Common/ConnectedModeState.qml +++ b/quickshell/Common/ConnectedModeState.qml @@ -292,6 +292,7 @@ Singleton { }) property var modalStates: ({}) + property var modalOwners: ({}) function _normalizeModalState(state) { return { @@ -320,31 +321,62 @@ Singleton { return a.visible === b.visible && a.barSide === b.barSide && a.omitStartConnector === b.omitStartConnector && a.omitEndConnector === b.omitEndConnector && _sameModalGeometry(a, b); } - function setModalState(screenName, state) { + function claimModalState(screenName, state, ownerId) { if (!screenName || !state) return false; - + if (ownerId) { + const nextOwners = _cloneDict(modalOwners); + nextOwners[screenName] = ownerId; + modalOwners = nextOwners; + } const normalized = _normalizeModalState(state); if (_sameModalState(modalStates[screenName], normalized)) return true; - const next = _cloneDict(modalStates); next[screenName] = normalized; modalStates = next; return true; } - function clearModalState(screenName) { + function updateModalState(screenName, state, ownerId) { + if (!screenName || !state) + return false; + if (ownerId && modalOwners[screenName] && 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; + return true; + } + + function setModalState(screenName, state) { + return updateModalState(screenName, state, null); + } + + function clearModalState(screenName, ownerId) { if (!screenName || !modalStates[screenName]) return false; + if (ownerId && modalOwners[screenName] && modalOwners[screenName] !== ownerId) + return false; const next = _cloneDict(modalStates); delete next[screenName]; modalStates = next; + + if (modalOwners[screenName]) { + const nextOwners = _cloneDict(modalOwners); + delete nextOwners[screenName]; + modalOwners = nextOwners; + } return true; } - function setModalAnim(screenName, animX, animY) { + function setModalAnim(screenName, animX, animY, ownerId) { + if (ownerId && modalOwners[screenName] && modalOwners[screenName] !== ownerId) + return false; const cur = screenName ? modalStates[screenName] : null; if (!cur) return false; @@ -361,7 +393,9 @@ Singleton { return true; } - function setModalBody(screenName, bodyX, bodyY, bodyW, bodyH) { + function setModalBody(screenName, bodyX, bodyY, bodyW, bodyH, ownerId) { + if (ownerId && modalOwners[screenName] && modalOwners[screenName] !== ownerId) + return false; const cur = screenName ? modalStates[screenName] : null; if (!cur) return false; @@ -455,6 +489,9 @@ Singleton { const nextModal = pruneKeyed(modalStates); if (nextModal !== null) modalStates = nextModal; + const nextModalOwners = pruneKeyed(modalOwners); + if (nextModalOwners !== null) + modalOwners = nextModalOwners; let retractChanged = false; const nextRetract = {}; diff --git a/quickshell/Modals/Common/DankModalConnected.qml b/quickshell/Modals/Common/DankModalConnected.qml index 1f1232ec..82d5cb31 100644 --- a/quickshell/Modals/Common/DankModalConnected.qml +++ b/quickshell/Modals/Common/DankModalConnected.qml @@ -116,11 +116,11 @@ Item { return effectiveScreen ? effectiveScreen.name : ""; } - function _publishModalChromeState() { + function _publishModalChromeState(isClaim) { const screenName = _currentScreenName(); if (!screenName) return; - ConnectedModeState.setModalState(screenName, { + const state = { "visible": shouldBeVisible || contentWindow.visible, "barSide": resolvedConnectedBarSide, "bodyX": alignedX, @@ -131,7 +131,11 @@ Item { "animY": modalContainer ? modalContainer.animY : 0, "omitStartConnector": false, "omitEndConnector": false - }); + }; + if (isClaim) + ConnectedModeState.claimModalState(screenName, state, _chromeClaimId); + else + ConnectedModeState.updateModalState(screenName, state, _chromeClaimId); } function _syncModalChromeState() { @@ -139,9 +143,10 @@ Item { _releaseModalChrome(); return; } + const isClaim = !_chromeClaimId; if (!_chromeClaimId) _chromeClaimId = _nextChromeClaimId(); - _publishModalChromeState(); + _publishModalChromeState(isClaim); if (_dockBlocksEmergence && (shouldBeVisible || contentWindow.visible)) ConnectedModeState.requestDockRetract(_chromeClaimId, _currentScreenName(), resolvedConnectedBarSide); else @@ -187,7 +192,7 @@ Item { const screenName = _currentScreenName(); if (!screenName || !modalContainer) return; - ConnectedModeState.setModalAnim(screenName, modalContainer.animX, modalContainer.animY); + ConnectedModeState.setModalAnim(screenName, modalContainer.animX, modalContainer.animY, _chromeClaimId); } function _syncModalBody() { @@ -196,17 +201,18 @@ Item { const screenName = _currentScreenName(); if (!screenName) return; - ConnectedModeState.setModalBody(screenName, alignedX, alignedY, alignedWidth, alignedHeight); + ConnectedModeState.setModalBody(screenName, alignedX, alignedY, alignedWidth, alignedHeight, _chromeClaimId); } function _releaseModalChrome() { if (!_chromeClaimId) return; ConnectedModeState.releaseDockRetract(_chromeClaimId); + const claimId = _chromeClaimId; _chromeClaimId = ""; const screenName = _currentScreenName(); if (screenName) - ConnectedModeState.clearModalState(screenName); + ConnectedModeState.clearModalState(screenName, claimId); } onFrameOwnsConnectedChromeChanged: _syncModalChromeState() @@ -262,6 +268,10 @@ Item { } function close() { + if (modalContainer) { + frozenMotionOffsetX = modalContainer.offsetX; + frozenMotionOffsetY = modalContainer.offsetY; + } shouldBeVisible = false; shouldHaveFocus = false; ModalManager.closeModal(modalHandle); diff --git a/quickshell/Modals/DankLauncherV2/ActionPanel.qml b/quickshell/Modals/DankLauncherV2/ActionPanel.qml index 31ada32a..5c936c50 100644 --- a/quickshell/Modals/DankLauncherV2/ActionPanel.qml +++ b/quickshell/Modals/DankLauncherV2/ActionPanel.qml @@ -88,7 +88,7 @@ Rectangle { width: parent?.width ?? 200 height: expanded && hasActions ? 52 : 0 - color: Theme.surfaceContainerHigh + color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) radius: Theme.cornerRadius clip: true diff --git a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml index 430714b3..ed7b4828 100644 --- a/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml +++ b/quickshell/Modals/DankLauncherV2/DankLauncherV2ModalConnected.qml @@ -235,11 +235,11 @@ Item { return effectiveScreen ? effectiveScreen.name : ""; } - function _publishModalChromeState() { + function _publishModalChromeState(isClaim) { const screenName = _currentScreenName(); if (!screenName) return; - ConnectedModeState.setModalState(screenName, { + const state = { "visible": spotlightOpen || contentWindow.visible, "barSide": resolvedConnectedBarSide, "bodyX": _connectedChromeX, @@ -250,7 +250,11 @@ Item { "animY": contentContainer ? contentContainer.animY : 0, "omitStartConnector": false, "omitEndConnector": false - }); + }; + if (isClaim) + ConnectedModeState.claimModalState(screenName, state, _chromeClaimId); + else + ConnectedModeState.updateModalState(screenName, state, _chromeClaimId); } function _syncModalChromeState() { @@ -258,9 +262,10 @@ Item { _releaseModalChrome(); return; } + const isClaim = !_chromeClaimId; if (!_chromeClaimId) _chromeClaimId = _nextChromeClaimId(); - _publishModalChromeState(); + _publishModalChromeState(isClaim); if (_dockBlocksEmergence && (spotlightOpen || contentWindow.visible)) ConnectedModeState.requestDockRetract(_chromeClaimId, _currentScreenName(), resolvedConnectedBarSide); else @@ -306,7 +311,7 @@ Item { const screenName = _currentScreenName(); if (!screenName || !contentContainer) return; - ConnectedModeState.setModalAnim(screenName, contentContainer.animX, contentContainer.animY); + ConnectedModeState.setModalAnim(screenName, contentContainer.animX, contentContainer.animY, _chromeClaimId); } function _syncModalBody() { @@ -315,17 +320,18 @@ Item { const screenName = _currentScreenName(); if (!screenName) return; - ConnectedModeState.setModalBody(screenName, _connectedChromeX, _connectedChromeY, _connectedChromeWidth, _connectedChromeHeight); + ConnectedModeState.setModalBody(screenName, _connectedChromeX, _connectedChromeY, _connectedChromeWidth, _connectedChromeHeight, _chromeClaimId); } function _releaseModalChrome() { - if (_chromeClaimId) { - ConnectedModeState.releaseDockRetract(_chromeClaimId); - _chromeClaimId = ""; - } + if (!_chromeClaimId) + return; + ConnectedModeState.releaseDockRetract(_chromeClaimId); + const claimId = _chromeClaimId; + _chromeClaimId = ""; const screenName = _currentScreenName(); if (screenName) - ConnectedModeState.clearModalState(screenName); + ConnectedModeState.clearModalState(screenName, claimId); } onFrameOwnsConnectedChromeChanged: _syncModalChromeState() diff --git a/quickshell/Modals/DankLauncherV2/LauncherContent.qml b/quickshell/Modals/DankLauncherV2/LauncherContent.qml index 954d7f29..f621f8c4 100644 --- a/quickshell/Modals/DankLauncherV2/LauncherContent.qml +++ b/quickshell/Modals/DankLauncherV2/LauncherContent.qml @@ -284,7 +284,7 @@ FocusScope { anchors.bottom: parent.bottom anchors.leftMargin: root.parentModal?.borderWidth ?? 1 anchors.rightMargin: root.parentModal?.borderWidth ?? 1 - anchors.bottomMargin: _connectedBottomEmerge ? Theme.spacingM : (root.parentModal?.borderWidth ?? 1) + anchors.bottomMargin: _connectedBottomEmerge ? Theme.spacingS : (root.parentModal?.borderWidth ?? 1) height: showFooter ? (_connectedArcAtFooter ? 76 : 36) : 0 visible: showFooter clip: true