From c668ab9fdf827f4bc578cc4079fe1128d2598d7b Mon Sep 17 00:00:00 2001 From: bbedward Date: Thu, 1 Oct 2026 18:44:12 -0400 Subject: [PATCH] cc: place popout menus by the host window's margins --- quickshell/Common/QmlUtils.js | 14 ++++++++++++++ .../Components/WidgetConfigOverlay.qml | 11 ++++++----- .../Modules/ControlCenter/Widgets/CcMenu.qml | 11 ++++++----- 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/quickshell/Common/QmlUtils.js b/quickshell/Common/QmlUtils.js index cf485b833..cc08a46ff 100644 --- a/quickshell/Common/QmlUtils.js +++ b/quickshell/Common/QmlUtils.js @@ -27,6 +27,20 @@ function findSettings(item) { return null; } +// mapToGlobal ignores a layer window's margins, so detached popouts need them added back +function screenPointOf(window, item, x, y) { + const screen = window?.screen; + if (!window || !screen || !item) + return null; + const pos = item.mapToGlobal(x, y); + const originX = window.anchors.left ? window.margins.left : window.anchors.right ? screen.width - window.margins.right - window.width : 0; + const originY = window.anchors.top ? window.margins.top : window.anchors.bottom ? screen.height - window.margins.bottom - window.height : 0; + return { + x: pos.x - screen.x + originX, + y: pos.y - screen.y + originY + }; +} + function normalizePinList(value) { if (Array.isArray(value)) return value.filter(v => v); diff --git a/quickshell/Modules/ControlCenter/Components/WidgetConfigOverlay.qml b/quickshell/Modules/ControlCenter/Components/WidgetConfigOverlay.qml index 0b64b7927..16c5663cb 100644 --- a/quickshell/Modules/ControlCenter/Components/WidgetConfigOverlay.qml +++ b/quickshell/Modules/ControlCenter/Components/WidgetConfigOverlay.qml @@ -8,6 +8,7 @@ import qs.Modules.ControlCenter.Widgets import qs.Modules.DankBar.Widgets import qs.Modules.DankDash import "../utils/widgets.js" as WidgetUtils +import "../../../Common/QmlUtils.js" as QmlUtils import qs.Services import qs.Widgets @@ -38,12 +39,12 @@ Item { // Placement needs the final menu height, which settles after widgetIndex propagates. Qt.callLater(() => { const window = root.QsWindow.window; - const screen = window?.screen; - if (root.widgetIndex !== index || !anchorItem || !screen) + const pos = QmlUtils.screenPointOf(window, anchorItem, 0, 0); + if (root.widgetIndex !== index || !pos) return; - const pos = anchorItem.mapToGlobal(0, 0); - const x = pos.x - screen.x; - const y = pos.y - screen.y; + const screen = window.screen; + const x = pos.x; + const y = pos.y; const menuX = I18n.isRtl ? x : x + anchorItem.width - contextMenu.effectiveMenuWidth; const aboveY = () => y - contextMenu.effectiveMenuHeight - Theme.spacingS; if (aboveY() < Theme.spacingS) { diff --git a/quickshell/Modules/ControlCenter/Widgets/CcMenu.qml b/quickshell/Modules/ControlCenter/Widgets/CcMenu.qml index b228d1783..f6e535a0b 100644 --- a/quickshell/Modules/ControlCenter/Widgets/CcMenu.qml +++ b/quickshell/Modules/ControlCenter/Widgets/CcMenu.qml @@ -5,6 +5,7 @@ import Quickshell import qs.Common import qs.Modules.ControlCenter import qs.Widgets +import "../../../Common/QmlUtils.js" as QmlUtils Item { id: root @@ -19,14 +20,14 @@ Item { function openAt(anchor) { const window = root.QsWindow.window; - const screen = window?.screen; - if (!anchor || !screen) + const pos = QmlUtils.screenPointOf(window, anchor, 0, 0); + if (!pos) return; _anchor = anchor; - const pos = anchor.mapToGlobal(0, 0); - const x = pos.x - screen.x; - const y = pos.y - screen.y; + const screen = window.screen; + const x = pos.x; + const y = pos.y; const menuX = I18n.isRtl ? x : x + anchor.width - menu.effectiveMenuWidth; const below = y + anchor.height + Theme.spacingXS; const menuY = below + menu.effectiveMenuHeight > screen.height - Theme.spacingS