diff --git a/quickshell/Modules/DankBar/DankBarBody.qml b/quickshell/Modules/DankBar/DankBarBody.qml index f0d8b96e7..d0537fba3 100644 --- a/quickshell/Modules/DankBar/DankBarBody.qml +++ b/quickshell/Modules/DankBar/DankBarBody.qml @@ -1168,20 +1168,8 @@ Item { HoverHandler { id: hoverPopoutHandler enabled: (barConfig?.hoverPopouts ?? false) && !barWindow.clickThroughEnabled - - property real lastGlobalX: 0 - property real lastGlobalY: 0 - - onPointChanged: { - const gp = barUnitInset.mapToItem(null, point.position.x, point.position.y); - lastGlobalX = gp.x; - lastGlobalY = gp.y; - topBarContent.queueHoverPopout(gp.x, gp.y); - } - - onHoveredChanged: { - topBarContent.updateHoverBarHovered(hovered); - } + onPointChanged: topBarContent.queueHoverFromItem(barUnitInset, point) + onHoveredChanged: topBarContent.updateHoverBarHovered(hovered) } } } diff --git a/quickshell/Modules/DankBar/DankBarContent.qml b/quickshell/Modules/DankBar/DankBarContent.qml index b7a2cb9ea..b53d99bf8 100644 --- a/quickshell/Modules/DankBar/DankBarContent.qml +++ b/quickshell/Modules/DankBar/DankBarContent.qml @@ -19,6 +19,8 @@ Item { property var leftWidgetsModel property var centerWidgetsModel property var rightWidgetsModel + property var widgetOwner: null + property var hoverSections: null property bool _animateFrameInsets: false readonly property real innerPadding: barConfig?.innerPadding ?? 4 @@ -85,6 +87,34 @@ Item { property alias vCenterSection: vCenterSection property alias vRightSection: vRightSection + readonly property var _defaultHoverSections: barWindow.isVertical ? [ + { + section: vLeftSection, + name: "left" + }, + { + section: vCenterSection, + name: "center" + }, + { + section: vRightSection, + name: "right" + } + ] : [ + { + section: hLeftSection, + name: "left" + }, + { + section: hCenterSection, + name: "center" + }, + { + section: hRightSection, + name: "right" + } + ] + anchors.fill: parent anchors.leftMargin: _leftMargin anchors.rightMargin: _rightMargin @@ -413,12 +443,8 @@ Item { barContent: topBarContent barWindow: topBarContent.barWindow barConfig: topBarContent.barConfig - hLeftSection: topBarContent.hLeftSection - hCenterSection: topBarContent.hCenterSection - hRightSection: topBarContent.hRightSection - vLeftSection: topBarContent.vLeftSection - vCenterSection: topBarContent.vCenterSection - vRightSection: topBarContent.vRightSection + widgetOwner: topBarContent.widgetOwner + sections: topBarContent.hoverSections || topBarContent._defaultHoverSections leftWidgetsModel: topBarContent.leftWidgetsModel centerWidgetsModel: topBarContent.centerWidgetsModel rightWidgetsModel: topBarContent.rightWidgetsModel @@ -427,6 +453,28 @@ Item { readonly property string activeHoverTrigger: hoverController.activeHoverTrigger readonly property bool hoverPopoutsEnabled: hoverController.hoverPopoutsEnabled + function mapItemToScreen(item, x, y) { + if (!item || typeof item.mapToItem !== "function") + return null; + try { + const raw = item.mapToItem(null, x ?? 0, y ?? 0); + if (!raw) + return null; + return Qt.point(raw.x + (barWindow?.hostOriginX ?? 0), raw.y + (barWindow?.hostOriginY ?? 0)); + } catch (e) { + return null; + } + } + + function queueHoverFromItem(item, point) { + if (!point) + return; + const gp = mapItemToScreen(item, point.position.x, point.position.y); + if (!gp) + return; + queueHoverPopout(gp.x, gp.y); + } + function queueHoverPopout(gx, gy) { hoverController.queueHoverPoint(gx, gy); } @@ -447,6 +495,10 @@ Item { hoverController.updateBarHovered(hovered); } + function invalidateHoverCandidateCache() { + hoverController.invalidateCandidateCache(); + } + function resetHoverForBarGeometryChange() { hoverController.resetForBarGeometryChange(); } @@ -465,14 +517,13 @@ Item { const centerSection = barWindow.isVertical ? vCenterSection : hCenterSection; if (centerSection) { if (barWindow.isVertical) { - const centerY = centerSection.height / 2; return { - triggerPos: centerSection.mapToItem(null, 0, centerY), + triggerPos: mapItemToScreen(centerSection, 0, centerSection.height / 2), triggerWidth: centerSection.height }; } return { - triggerPos: centerSection.mapToItem(null, 0, 0), + triggerPos: mapItemToScreen(centerSection, 0, 0), triggerWidth: centerSection.width }; } @@ -480,7 +531,7 @@ Item { const ref = opts.visualItem || widgetItem.visualContent || widgetItem; const w = opts.triggerWidth !== undefined ? opts.triggerWidth : (widgetItem.visualWidth !== undefined ? widgetItem.visualWidth : widgetItem.width); return { - triggerPos: ref.mapToItem(null, 0, 0), + triggerPos: mapItemToScreen(ref, 0, 0), triggerWidth: w }; } @@ -987,7 +1038,9 @@ Item { if (loader.item.setBarContext) loader.item.setBarContext(barPosition, effectiveBarConfig?.bottomGap ?? 0); if (loader.item.setTriggerPosition) { - const globalPos = launcherButton.visualContent.mapToItem(null, 0, 0); + const globalPos = topBarContent.mapItemToScreen(launcherButton.visualContent, 0, 0); + if (!globalPos) + return false; const currentScreen = barWindow.screen; const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barWindow.effectiveBarThickness, launcherButton.visualWidth, effectiveBarConfig?.spacing ?? 4, barPosition, effectiveBarConfig); loader.item.setTriggerPosition(pos.x, pos.y, pos.width, launcherButton.section, currentScreen, barPosition, barWindow.effectiveBarThickness, effectiveBarConfig?.spacing ?? 4, effectiveBarConfig); diff --git a/quickshell/Modules/DankBar/DankBarHoverController.qml b/quickshell/Modules/DankBar/DankBarHoverController.qml index 5e5c4c9d1..08ab7ee2b 100644 --- a/quickshell/Modules/DankBar/DankBarHoverController.qml +++ b/quickshell/Modules/DankBar/DankBarHoverController.qml @@ -10,12 +10,8 @@ Item { required property var barContent required property var barWindow required property var barConfig - required property var hLeftSection - required property var hCenterSection - required property var hRightSection - required property var vLeftSection - required property var vCenterSection - required property var vRightSection + property var widgetOwner: null + property var sections: [] property var leftWidgetsModel property var centerWidgetsModel @@ -46,6 +42,7 @@ Item { onLeftWidgetsModelChanged: invalidateCandidateCache() onCenterWidgetsModelChanged: invalidateCandidateCache() onRightWidgetsModelChanged: invalidateCandidateCache() + onSectionsChanged: invalidateCandidateCache() onHoverPopoutsEnabledChanged: { if (hoverPopoutsEnabled) @@ -62,7 +59,7 @@ Item { Component.onDestruction: _disconnectCandidateWatchers() Connections { - target: root.barContent + target: root.widgetOwner || root.barContent function onWidthChanged() { root.invalidateCandidateCache(); @@ -227,41 +224,12 @@ Item { } function _getBarSections() { - if (barWindow.isVertical) { - return [ - { - section: vLeftSection, - name: "left" - }, - { - section: vCenterSection, - name: "center" - }, - { - section: vRightSection, - name: "right" - } - ]; - } - return [ - { - section: hLeftSection, - name: "left" - }, - { - section: hCenterSection, - name: "center" - }, - { - section: hRightSection, - name: "right" - } - ]; + return root.sections || []; } // The widget registry is keyed by (widgetId, screenName) function _itemBelongsToThisBar(item) { - const owner = barContent; + const owner = root.widgetOwner || barContent; if (!owner || !item) return true; let node = item; @@ -489,17 +457,15 @@ Item { } function _globalItemBounds(item) { - try { - const topLeft = item.mapToItem(null, 0, 0); - return { - x: topLeft.x, - y: topLeft.y, - width: item.width, - height: item.height - }; - } catch (e) { + const topLeft = barContent.mapItemToScreen(item, 0, 0); + if (!topLeft) return null; - } + return { + x: topLeft.x, + y: topLeft.y, + width: item.width, + height: item.height + }; } function _hitBoundsForWidget(widgetItem, wrapper) { diff --git a/quickshell/Modules/DankIsland/IslandSatelliteHost.qml b/quickshell/Modules/DankIsland/IslandSatelliteHost.qml index ca9d59b15..1d5ac1704 100644 --- a/quickshell/Modules/DankIsland/IslandSatelliteHost.qml +++ b/quickshell/Modules/DankIsland/IslandSatelliteHost.qml @@ -153,6 +153,9 @@ Item { property bool hasAdjacentLeftBar: false property bool hasAdjacentRightBar: false property var hyprlandOverviewLoader: root.hyprlandOverviewLoader + property var hostWindow: root.hostWindow + readonly property int hostOriginX: hostWindow?.hostOriginX ?? 0 + readonly property int hostOriginY: hostWindow?.hostOriginY ?? 0 property var controlCenterButtonRef: null property var clockButtonRef: null property var systemUpdateButtonRef: null @@ -269,9 +272,16 @@ Item { return; blurRebuildTimer.restart(); blurTrailTimer.restart(); + componentProvider.invalidateHoverCandidateCache(); } } + function onSatelliteRowMoved() { + kickBlur(); + if (!root.motionRunning) + componentProvider.invalidateHoverCandidateCache(); + } + function kickBlur() { if (root.motionRunning) return; @@ -412,11 +422,26 @@ Item { barWindow: satelliteBarWindow rootWindow: root.hostWindow barConfig: root.satelliteConfig + widgetOwner: root + hoverSections: [ + { + section: leadingWidgetSection, + name: "left" + }, + { + section: trailingWidgetSection, + name: "right" + } + ] leftWidgetsModel: emptyWidgetsModel centerWidgetsModel: emptyWidgetsModel rightWidgetsModel: emptyWidgetsModel } + readonly property bool satelliteHoverTracking: root.visible && componentProvider.hoverPopoutsEnabled && !root.controller.inputSuspended + readonly property bool satellitesHovered: satelliteHoverTracking && (leadingEnvelopeHoverHandler.hovered || trailingEnvelopeHoverHandler.hovered || leadingWidgetHoverHandler.hovered || trailingWidgetHoverHandler.hovered) + onSatellitesHoveredChanged: componentProvider.updateHoverBarHovered(satellitesHovered) + Item { id: leadingInputEnvelope @@ -429,6 +454,12 @@ Item { y: root.isVertical ? alongPos : crossPos width: root.isVertical ? crossSize : alongSize height: root.isVertical ? alongSize : crossSize + + HoverHandler { + id: leadingEnvelopeHoverHandler + enabled: root.satelliteHoverTracking + onPointChanged: componentProvider.queueHoverFromItem(leadingInputEnvelope, point) + } } Item { @@ -444,6 +475,12 @@ Item { y: root.isVertical ? alongPos : crossPos width: root.isVertical ? crossSize : alongSize height: root.isVertical ? alongSize : crossSize + + HoverHandler { + id: trailingEnvelopeHoverHandler + enabled: root.satelliteHoverTracking + onPointChanged: componentProvider.queueHoverFromItem(trailingInputEnvelope, point) + } } IslandSatelliteChrome { @@ -500,8 +537,10 @@ Item { y: root.isVertical ? alongPos : root.rowCross width: root.isVertical ? crossSize : alongSize height: root.isVertical ? alongSize : crossSize - onAlongPosChanged: root.kickBlur() - onAlongSizeChanged: root.kickBlur() + onXChanged: root.onSatelliteRowMoved() + onYChanged: root.onSatelliteRowMoved() + onWidthChanged: root.onSatelliteRowMoved() + onHeightChanged: root.onSatelliteRowMoved() LeftSection { id: leadingWidgetSection @@ -521,6 +560,12 @@ Item { crossEdgeExtension: root.crossEdgeExtension edgeIsScreenEdge: root.edgeAligned } + + HoverHandler { + id: leadingWidgetHoverHandler + enabled: root.satelliteHoverTracking + onPointChanged: componentProvider.queueHoverFromItem(leadingInput, point) + } } Item { @@ -534,8 +579,10 @@ Item { y: root.isVertical ? alongPos : root.rowCross width: root.isVertical ? crossSize : alongSize height: root.isVertical ? alongSize : crossSize - onAlongPosChanged: root.kickBlur() - onAlongSizeChanged: root.kickBlur() + onXChanged: root.onSatelliteRowMoved() + onYChanged: root.onSatelliteRowMoved() + onWidthChanged: root.onSatelliteRowMoved() + onHeightChanged: root.onSatelliteRowMoved() RightSection { id: trailingWidgetSection @@ -555,5 +602,11 @@ Item { crossEdgeExtension: root.crossEdgeExtension edgeIsScreenEdge: root.edgeAligned } + + HoverHandler { + id: trailingWidgetHoverHandler + enabled: root.satelliteHoverTracking + onPointChanged: componentProvider.queueHoverFromItem(trailingInput, point) + } } }