From c0f072217cb8c045d2ea2e7a3c9dbcd97d4e2b6e Mon Sep 17 00:00:00 2001 From: bbedward Date: Tue, 18 Nov 2025 16:18:24 -0500 Subject: [PATCH] dankbar: split up monolithic file --- quickshell/Modules/DankBar/DankBar.qml | 1498 +---------------- quickshell/Modules/DankBar/DankBarContent.qml | 1009 +++++++++++ quickshell/Modules/DankBar/DankBarWindow.qml | 538 ++++++ .../Modules/DankBar/Widgets/SystemTrayBar.qml | 17 +- 4 files changed, 1553 insertions(+), 1509 deletions(-) create mode 100644 quickshell/Modules/DankBar/DankBarContent.qml create mode 100644 quickshell/Modules/DankBar/DankBarWindow.qml diff --git a/quickshell/Modules/DankBar/DankBar.qml b/quickshell/Modules/DankBar/DankBar.qml index 804689f4..ae33539c 100644 --- a/quickshell/Modules/DankBar/DankBar.qml +++ b/quickshell/Modules/DankBar/DankBar.qml @@ -85,1502 +85,8 @@ Item { id: barVariants model: SettingsData.getFilteredScreens("dankBar") - delegate: PanelWindow { - id: barWindow - - property var controlCenterButtonRef: null - property var clockButtonRef: null - - function triggerControlCenter() { - controlCenterLoader.active = true - if (!controlCenterLoader.item) { - return - } - - if (controlCenterButtonRef && controlCenterLoader.item.setTriggerPosition) { - const globalPos = controlCenterButtonRef.mapToGlobal(0, 0) - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, controlCenterButtonRef.width) - const section = controlCenterButtonRef.section || "right" - controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) - } else { - controlCenterLoader.item.triggerScreen = barWindow.screen - } - - controlCenterLoader.item.toggle() - if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) { - NetworkService.scanWifi() - } - } - - function triggerWallpaperBrowser() { - dankDashPopoutLoader.active = true - if (!dankDashPopoutLoader.item) { - return - } - - if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) { - const globalPos = clockButtonRef.visualContent.mapToGlobal(0, 0) - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, clockButtonRef.visualWidth) - const section = clockButtonRef.section || "center" - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen - } - - PopoutManager.requestPopout(dankDashPopoutLoader.item, 2) - } - - readonly property var dBarLayer: { - switch (Quickshell.env("DMS_DANKBAR_LAYER")) { - case "bottom": - return WlrLayer.Bottom - case "overlay": - return WlrLayer.Overlay - case "background": - return WlrLayer.background - default: - return WlrLayer.Top - } - } - - WlrLayershell.layer: dBarLayer - WlrLayershell.namespace: "dms:bar" - - property var modelData: item - - signal colorPickerRequested - - onColorPickerRequested: root.colorPickerRequested() - - AxisContext { - id: axis - edge: { - switch (SettingsData.dankBarPosition) { - case SettingsData.Position.Top: - return "top" - case SettingsData.Position.Bottom: - return "bottom" - case SettingsData.Position.Left: - return "left" - case SettingsData.Position.Right: - return "right" - default: - return "top" - } - } - } - - readonly property bool isVertical: axis.isVertical - - property bool gothCornersEnabled: SettingsData.dankBarGothCornersEnabled - property real wingtipsRadius: SettingsData.dankBarGothCornerRadiusOverride ? SettingsData.dankBarGothCornerRadiusValue : Theme.cornerRadius - readonly property real _wingR: Math.max(0, wingtipsRadius) - readonly property color _surfaceContainer: Theme.surfaceContainer - readonly property real _backgroundAlpha: topBarCore?.backgroundTransparency ?? SettingsData.dankBarTransparency - readonly property color _bgColor: Theme.withAlpha(_surfaceContainer, _backgroundAlpha) - readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen) - - property string screenName: modelData.name - readonly property int notificationCount: NotificationService.notifications.length - readonly property real effectiveBarThickness: Math.max(barWindow.widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) - readonly property real widgetThickness: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6) - - screen: modelData - implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0 - implicitWidth: isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0 - color: "transparent" - - property var nativeInhibitor: null - - Component.onCompleted: { - if (SettingsData.forceStatusBarLayoutRefresh) { - SettingsData.forceStatusBarLayoutRefresh.connect(() => { - Qt.callLater(() => { - stackContainer.visible = false - Qt.callLater(() => { - stackContainer.visible = true - }) - }) - }) - } - - updateGpuTempConfig() - - inhibitorInitTimer.start() - } - - Timer { - id: inhibitorInitTimer - interval: 300 - repeat: false - onTriggered: { - if (SessionService.nativeInhibitorAvailable) { - createNativeInhibitor() - } - } - } - - Connections { - target: PluginService - function onPluginLoaded(pluginId) { - console.info("DankBar: Plugin loaded:", pluginId) - SettingsData.widgetDataChanged() - } - function onPluginUnloaded(pluginId) { - console.info("DankBar: Plugin unloaded:", pluginId) - SettingsData.widgetDataChanged() - } - } - - function updateGpuTempConfig() { - const allWidgets = [...(SettingsData.dankBarLeftWidgets || []), ...(SettingsData.dankBarCenterWidgets || []), ...(SettingsData.dankBarRightWidgets || [])] - - const hasGpuTempWidget = allWidgets.some(widget => { - const widgetId = typeof widget === "string" ? widget : widget.id - const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false) - return widgetId === "gpuTemp" && widgetEnabled - }) - - DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled - DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled - DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled - } - - function createNativeInhibitor() { - if (!SessionService.nativeInhibitorAvailable) { - return - } - - try { - const qmlString = ` - import QtQuick - import Quickshell.Wayland - - IdleInhibitor { - enabled: false - } - ` - - nativeInhibitor = Qt.createQmlObject(qmlString, barWindow, "DankBar.NativeInhibitor") - nativeInhibitor.window = barWindow - nativeInhibitor.enabled = Qt.binding(() => SessionService.idleInhibited) - nativeInhibitor.enabledChanged.connect(function () { - console.log("DankBar: Native inhibitor enabled changed to:", nativeInhibitor.enabled) - if (SessionService.idleInhibited !== nativeInhibitor.enabled) { - SessionService.idleInhibited = nativeInhibitor.enabled - SessionService.inhibitorChanged() - } - }) - console.log("DankBar: Created native Wayland IdleInhibitor for", barWindow.screenName) - } catch (e) { - console.warn("DankBar: Failed to create native IdleInhibitor:", e) - nativeInhibitor = null - } - } - - Connections { - function onDankBarLeftWidgetsChanged() { - barWindow.updateGpuTempConfig() - } - - function onDankBarCenterWidgetsChanged() { - barWindow.updateGpuTempConfig() - } - - function onDankBarRightWidgetsChanged() { - barWindow.updateGpuTempConfig() - } - - target: SettingsData - } - - Connections { - function onNvidiaGpuTempEnabledChanged() { - barWindow.updateGpuTempConfig() - } - - function onNonNvidiaGpuTempEnabledChanged() { - barWindow.updateGpuTempConfig() - } - - target: SessionData - } - - Connections { - target: barWindow.screen - function onGeometryChanged() { - Qt.callLater(forceWidgetRefresh) - } - } - - Timer { - id: refreshTimer - interval: 0 - running: false - repeat: false - onTriggered: { - forceWidgetRefresh() - } - } - - Connections { - target: axis - function onChanged() { - Qt.application.active - refreshTimer.restart() - } - } - - anchors.top: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Top) : true - anchors.bottom: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom) : true - anchors.left: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Left) - anchors.right: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Right) - - exclusiveZone: (!SettingsData.dankBarVisible || topBarCore.autoHide) ? -1 : (barWindow.effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap) - - Item { - id: inputMask - - readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) - - readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview - readonly property bool effectiveVisible: SettingsData.dankBarVisible || inOverviewWithShow - readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide) - - readonly property int maskThickness: showing ? barThickness : 1 - - x: { - if (!axis.isVertical) { - return 0 - } else { - switch (SettingsData.dankBarPosition) { - case SettingsData.Position.Left: - return 0 - case SettingsData.Position.Right: - return parent.width - maskThickness - default: - return 0 - } - } - } - y: { - if (axis.isVertical) { - return 0 - } else { - switch (SettingsData.dankBarPosition) { - case SettingsData.Position.Top: - return 0 - case SettingsData.Position.Bottom: - return parent.height - maskThickness - default: - return 0 - } - } - } - width: axis.isVertical ? maskThickness : parent.width - height: axis.isVertical ? parent.height : maskThickness - } - - mask: Region { - item: inputMask - } - - Item { - id: topBarCore - anchors.fill: parent - layer.enabled: true - - property real backgroundTransparency: SettingsData.dankBarTransparency - property bool autoHide: SettingsData.dankBarAutoHide - property bool revealSticky: false - - Timer { - id: revealHold - interval: SettingsData.dankBarAutoHideDelay - repeat: false - onTriggered: topBarCore.revealSticky = false - } - - property bool reveal: { - if (CompositorService.isNiri && NiriService.inOverview) { - return SettingsData.dankBarOpenOnOverview || topBarMouseArea.containsMouse || hasActivePopout || revealSticky - } - return SettingsData.dankBarVisible && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky) - } - - readonly property bool hasActivePopout: { - const loaders = [{ - "loader": appDrawerLoader, - "prop": "shouldBeVisible" - }, { - "loader": dankDashPopoutLoader, - "prop": "shouldBeVisible" - }, { - "loader": processListPopoutLoader, - "prop": "shouldBeVisible" - }, { - "loader": notificationCenterLoader, - "prop": "shouldBeVisible" - }, { - "loader": batteryPopoutLoader, - "prop": "shouldBeVisible" - }, { - "loader": layoutPopoutLoader, - "prop": "shouldBeVisible" - }, { - "loader": vpnPopoutLoader, - "prop": "shouldBeVisible" - }, { - "loader": controlCenterLoader, - "prop": "shouldBeVisible" - }, { - "loader": clipboardHistoryModalPopup, - "prop": "visible" - }, { - "loader": systemUpdateLoader, - "prop": "shouldBeVisible" - }] - return loaders.some(item => { - if (item.loader && item.loader.item) { - return item.loader.item[item.prop] - } - return false - }) || root.systemTrayMenuOpen - } - - Connections { - function onDankBarTransparencyChanged() { - topBarCore.backgroundTransparency = SettingsData.dankBarTransparency - } - - target: SettingsData - } - - Connections { - target: topBarMouseArea - function onContainsMouseChanged() { - if (topBarMouseArea.containsMouse) { - topBarCore.revealSticky = true - revealHold.stop() - } else { - if (topBarCore.autoHide && !topBarCore.hasActivePopout) { - revealHold.restart() - } - } - } - } - - onHasActivePopoutChanged: { - if (hasActivePopout) { - revealSticky = true - revealHold.stop() - } else if (autoHide && !topBarMouseArea.containsMouse) { - revealSticky = true - revealHold.restart() - } - } - - MouseArea { - id: topBarMouseArea - y: !barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? parent.height - height : 0) : 0 - x: barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.width - width : 0) : 0 - height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined - width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined - anchors { - left: !barWindow.isVertical ? parent.left : (SettingsData.dankBarPosition === SettingsData.Position.Left ? parent.left : undefined) - right: !barWindow.isVertical ? parent.right : (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.right : undefined) - top: barWindow.isVertical ? parent.top : undefined - bottom: barWindow.isVertical ? parent.bottom : undefined - } - readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview - hoverEnabled: SettingsData.dankBarAutoHide && !topBarCore.reveal && !inOverview - acceptedButtons: Qt.NoButton - enabled: SettingsData.dankBarAutoHide && !topBarCore.reveal && !inOverview - - Item { - id: topBarContainer - anchors.fill: parent - - transform: Translate { - id: topBarSlide - x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0 - y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0 - - Behavior on x { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - - Behavior on y { - NumberAnimation { - duration: Theme.shortDuration - easing.type: Easing.OutCubic - } - } - } - - Item { - id: barUnitInset - anchors.fill: parent - anchors.leftMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "left" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0) - anchors.rightMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "right" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0) - anchors.topMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? 0 : Theme.px(SettingsData.dankBarSpacing, barWindow._dpr)) - anchors.bottomMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0) - - BarCanvas { - id: barBackground - barWindow: barWindow - axis: axis - } - - MouseArea { - id: scrollArea - anchors.fill: parent - acceptedButtons: Qt.NoButton - propagateComposedEvents: true - z: -1 - - property real scrollAccumulator: 0 - property real touchpadThreshold: 500 - property bool actionInProgress: false - - Timer { - id: cooldownTimer - interval: 100 - onTriggered: parent.actionInProgress = false - } - - onWheel: wheel => { - if (actionInProgress) { - wheel.accepted = false - return - } - - const deltaY = wheel.angleDelta.y - const deltaX = wheel.angleDelta.x - - if (CompositorService.isNiri && Math.abs(deltaX) > Math.abs(deltaY)) { - topBarContent.switchApp(deltaX) - wheel.accepted = false - return - } - - const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0 - const direction = deltaY < 0 ? 1 : -1 - - if (isMouseWheel) { - topBarContent.switchWorkspace(direction) - actionInProgress = true - cooldownTimer.restart() - } else { - scrollAccumulator += deltaY - - if (Math.abs(scrollAccumulator) >= touchpadThreshold) { - const touchDirection = scrollAccumulator < 0 ? 1 : -1 - topBarContent.switchWorkspace(touchDirection) - scrollAccumulator = 0 - actionInProgress = true - cooldownTimer.restart() - } - } - - wheel.accepted = false - } - } - - Item { - id: topBarContent - anchors.fill: parent - anchors.leftMargin: !barWindow.isVertical ? Math.max(Theme.spacingXS, SettingsData.dankBarInnerPadding * 0.8) : SettingsData.dankBarInnerPadding / 2 - anchors.rightMargin: !barWindow.isVertical ? Math.max(Theme.spacingXS, SettingsData.dankBarInnerPadding * 0.8) : SettingsData.dankBarInnerPadding / 2 - anchors.topMargin: !barWindow.isVertical ? 0 : Math.max(Theme.spacingXS, SettingsData.dankBarInnerPadding * 0.8) - anchors.bottomMargin: !barWindow.isVertical ? 0 : Math.max(Theme.spacingXS, SettingsData.dankBarInnerPadding * 0.8) - clip: false - - property int componentMapRevision: 0 - - function updateComponentMap() { - componentMapRevision++ - } - - readonly property var sortedToplevels: { - return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, barWindow.screenName); - } - - function getRealWorkspaces() { - if (CompositorService.isNiri) { - if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { - return NiriService.getCurrentOutputWorkspaceNumbers() - } - const workspaces = NiriService.allWorkspaces.filter(ws => ws.output === barWindow.screenName).map(ws => ws.idx + 1) - return workspaces.length > 0 ? workspaces : [1, 2] - } else if (CompositorService.isHyprland) { - const workspaces = Hyprland.workspaces?.values || [] - - if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { - const sorted = workspaces.slice().sort((a, b) => a.id - b.id) - const filtered = sorted.filter(ws => ws.id > -1) - return filtered.length > 0 ? filtered : [{"id": 1, "name": "1"}] - } - - const monitorWorkspaces = workspaces.filter(ws => { - return ws.lastIpcObject && ws.lastIpcObject.monitor === barWindow.screenName && ws.id > -1 - }) - - if (monitorWorkspaces.length === 0) { - return [{"id": 1, "name": "1"}] - } - - return monitorWorkspaces.sort((a, b) => a.id - b.id) - } else if (CompositorService.isDwl) { - if (!DwlService.dwlAvailable) { - return [0] - } - if (SettingsData.dwlShowAllTags) { - return Array.from({length: DwlService.tagCount}, (_, i) => i) - } - return DwlService.getVisibleTags(barWindow.screenName) - } else if (CompositorService.isSway) { - const workspaces = I3.workspaces?.values || [] - if (workspaces.length === 0) return [{"num": 1}] - - if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { - return workspaces.slice().sort((a, b) => a.num - b.num) - } - - const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === barWindow.screenName) - return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num) : [{"num": 1}] - } - return [1] - } - - function getCurrentWorkspace() { - if (CompositorService.isNiri) { - if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { - return NiriService.getCurrentWorkspaceNumber() - } - const activeWs = NiriService.allWorkspaces.find(ws => ws.output === barWindow.screenName && ws.is_active) - return activeWs ? activeWs.idx + 1 : 1 - } else if (CompositorService.isHyprland) { - const monitors = Hyprland.monitors?.values || [] - const currentMonitor = monitors.find(monitor => monitor.name === barWindow.screenName) - return currentMonitor?.activeWorkspace?.id ?? 1 - } else if (CompositorService.isDwl) { - if (!DwlService.dwlAvailable) return 0 - const outputState = DwlService.getOutputState(barWindow.screenName) - if (!outputState || !outputState.tags) return 0 - const activeTags = DwlService.getActiveTags(barWindow.screenName) - return activeTags.length > 0 ? activeTags[0] : 0 - } else if (CompositorService.isSway) { - if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { - const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true) - return focusedWs ? focusedWs.num : 1 - } - - const focusedWs = I3.workspaces?.values?.find(ws => ws.monitor?.name === barWindow.screenName && ws.focused === true) - return focusedWs ? focusedWs.num : 1 - } - return 1 - } - - function switchWorkspace(direction) { - const realWorkspaces = getRealWorkspaces() - if (realWorkspaces.length < 2) { - return - } - - if (CompositorService.isNiri) { - const currentWs = getCurrentWorkspace() - const currentIndex = realWorkspaces.findIndex(ws => ws === currentWs) - const validIndex = currentIndex === -1 ? 0 : currentIndex - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0) - - if (nextIndex !== validIndex) { - NiriService.switchToWorkspace(realWorkspaces[nextIndex] - 1) - } - } else if (CompositorService.isHyprland) { - const currentWs = getCurrentWorkspace() - const currentIndex = realWorkspaces.findIndex(ws => ws.id === currentWs) - const validIndex = currentIndex === -1 ? 0 : currentIndex - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0) - - if (nextIndex !== validIndex) { - Hyprland.dispatch(`workspace ${realWorkspaces[nextIndex].id}`) - } - } else if (CompositorService.isDwl) { - const currentTag = getCurrentWorkspace() - const currentIndex = realWorkspaces.findIndex(tag => tag === currentTag) - const validIndex = currentIndex === -1 ? 0 : currentIndex - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0) - - if (nextIndex !== validIndex) { - DwlService.switchToTag(barWindow.screenName, realWorkspaces[nextIndex]) - } - } else if (CompositorService.isSway) { - const currentWs = getCurrentWorkspace() - const currentIndex = realWorkspaces.findIndex(ws => ws.num === currentWs) - const validIndex = currentIndex === -1 ? 0 : currentIndex - const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0) - - if (nextIndex !== validIndex) { - try { I3.dispatch(`workspace number ${realWorkspaces[nextIndex].num}`) } catch(_){} - } - } - } - - function switchApp(deltaY) { - const windows = sortedToplevels; - if (windows.length < 2) { - return; - } - let currentIndex = -1; - for (let i = 0; i < windows.length; i++) { - if (windows[i].activated) { - currentIndex = i; - break; - } - } - let nextIndex; - if (deltaY < 0) { - if (currentIndex === -1) { - nextIndex = 0; - } else { - nextIndex = currentIndex + 1; - } - } else { - if (currentIndex === -1) { - nextIndex = windows.length - 1; - } else { - nextIndex = currentIndex - 1; - } - } - const nextWindow = windows[nextIndex]; - if (nextWindow) { - nextWindow.activate(); - } - } - - readonly property int availableWidth: width - readonly property int launcherButtonWidth: 40 - readonly property int workspaceSwitcherWidth: 120 - readonly property int focusedAppMaxWidth: 456 - readonly property int estimatedLeftSectionWidth: launcherButtonWidth + workspaceSwitcherWidth + focusedAppMaxWidth + (Theme.spacingXS * 2) - readonly property int rightSectionWidth: 200 - readonly property int clockWidth: 120 - readonly property int mediaMaxWidth: 280 - readonly property int weatherWidth: 80 - readonly property bool validLayout: availableWidth > 100 && estimatedLeftSectionWidth > 0 && rightSectionWidth > 0 - readonly property int clockLeftEdge: (availableWidth - clockWidth) / 2 - readonly property int clockRightEdge: clockLeftEdge + clockWidth - readonly property int leftSectionRightEdge: estimatedLeftSectionWidth - readonly property int mediaLeftEdge: clockLeftEdge - mediaMaxWidth - Theme.spacingS - readonly property int rightSectionLeftEdge: availableWidth - rightSectionWidth - readonly property int leftToClockGap: Math.max(0, clockLeftEdge - leftSectionRightEdge) - readonly property int leftToMediaGap: mediaMaxWidth > 0 ? Math.max(0, mediaLeftEdge - leftSectionRightEdge) : leftToClockGap - readonly property int mediaToClockGap: mediaMaxWidth > 0 ? Theme.spacingS : 0 - readonly property int clockToRightGap: validLayout ? Math.max(0, rightSectionLeftEdge - clockRightEdge) : 1000 - readonly property bool spacingTight: !barWindow.isVertical && validLayout && (leftToMediaGap < 150 || clockToRightGap < 100) - readonly property bool overlapping: !barWindow.isVertical && validLayout && (leftToMediaGap < 100 || clockToRightGap < 50) - - function getWidgetEnabled(enabled) { - return enabled !== false - } - - function getWidgetSection(parentItem) { - let current = parentItem - while (current) { - if (current.objectName === "leftSection") { - return "left" - } - if (current.objectName === "centerSection") { - return "center" - } - if (current.objectName === "rightSection") { - return "right" - } - current = current.parent - } - return "left" - } - - readonly property var widgetVisibility: ({ - "cpuUsage": DgopService.dgopAvailable, - "memUsage": DgopService.dgopAvailable, - "cpuTemp": DgopService.dgopAvailable, - "gpuTemp": DgopService.dgopAvailable, - "network_speed_monitor": DgopService.dgopAvailable - }) - - function getWidgetVisible(widgetId) { - return widgetVisibility[widgetId] ?? true - } - - readonly property var componentMap: { - // This property depends on componentMapRevision to ensure it updates when plugins change - componentMapRevision - - let baseMap = { - "launcherButton": launcherButtonComponent, - "workspaceSwitcher": workspaceSwitcherComponent, - "focusedWindow": focusedWindowComponent, - "runningApps": runningAppsComponent, - "clock": clockComponent, - "music": mediaComponent, - "weather": weatherComponent, - "systemTray": systemTrayComponent, - "privacyIndicator": privacyIndicatorComponent, - "clipboard": clipboardComponent, - "cpuUsage": cpuUsageComponent, - "memUsage": memUsageComponent, - "diskUsage": diskUsageComponent, - "cpuTemp": cpuTempComponent, - "gpuTemp": gpuTempComponent, - "notificationButton": notificationButtonComponent, - "battery": batteryComponent, - "layout": layoutComponent, - "controlCenterButton": controlCenterButtonComponent, - "capsLockIndicator": capsLockIndicatorComponent, - "idleInhibitor": idleInhibitorComponent, - "spacer": spacerComponent, - "separator": separatorComponent, - "network_speed_monitor": networkComponent, - "keyboard_layout_name": keyboardLayoutNameComponent, - "vpn": vpnComponent, - "notepadButton": notepadButtonComponent, - "colorPicker": colorPickerComponent, - "systemUpdate": systemUpdateComponent - } - - // Merge with plugin widgets - let pluginMap = PluginService.getWidgetComponents() - return Object.assign(baseMap, pluginMap) - } - - function getWidgetComponent(widgetId) { - return componentMap[widgetId] || null - } - - readonly property var allComponents: ({ - "launcherButtonComponent": launcherButtonComponent, - "workspaceSwitcherComponent": workspaceSwitcherComponent, - "focusedWindowComponent": focusedWindowComponent, - "runningAppsComponent": runningAppsComponent, - "clockComponent": clockComponent, - "mediaComponent": mediaComponent, - "weatherComponent": weatherComponent, - "systemTrayComponent": systemTrayComponent, - "privacyIndicatorComponent": privacyIndicatorComponent, - "clipboardComponent": clipboardComponent, - "cpuUsageComponent": cpuUsageComponent, - "memUsageComponent": memUsageComponent, - "diskUsageComponent": diskUsageComponent, - "cpuTempComponent": cpuTempComponent, - "gpuTempComponent": gpuTempComponent, - "notificationButtonComponent": notificationButtonComponent, - "batteryComponent": batteryComponent, - "layoutComponent": layoutComponent, - "controlCenterButtonComponent": controlCenterButtonComponent, - "capsLockIndicatorComponent": capsLockIndicatorComponent, - "idleInhibitorComponent": idleInhibitorComponent, - "spacerComponent": spacerComponent, - "separatorComponent": separatorComponent, - "networkComponent": networkComponent, - "keyboardLayoutNameComponent": keyboardLayoutNameComponent, - "vpnComponent": vpnComponent, - "notepadButtonComponent": notepadButtonComponent, - "colorPickerComponent": colorPickerComponent, - "systemUpdateComponent": systemUpdateComponent - }) - - Item { - id: stackContainer - anchors.fill: parent - - Item { - id: horizontalStack - anchors.fill: parent - visible: !axis.isVertical - - LeftSection { - id: hLeftSection - objectName: "leftSection" - overrideAxisLayout: true - forceVerticalLayout: false - anchors { - left: parent.left - verticalCenter: parent.verticalCenter - } - axis: axis - widgetsModel: SettingsData.dankBarLeftWidgetsModel - components: topBarContent.allComponents - noBackground: SettingsData.dankBarNoBackground - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - } - - RightSection { - id: hRightSection - objectName: "rightSection" - overrideAxisLayout: true - forceVerticalLayout: false - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - } - axis: axis - widgetsModel: SettingsData.dankBarRightWidgetsModel - components: topBarContent.allComponents - noBackground: SettingsData.dankBarNoBackground - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - } - - CenterSection { - id: hCenterSection - objectName: "centerSection" - overrideAxisLayout: true - forceVerticalLayout: false - anchors { - verticalCenter: parent.verticalCenter - horizontalCenter: parent.horizontalCenter - } - axis: axis - widgetsModel: SettingsData.dankBarCenterWidgetsModel - components: topBarContent.allComponents - noBackground: SettingsData.dankBarNoBackground - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - } - } - - Item { - id: verticalStack - anchors.fill: parent - visible: axis.isVertical - - LeftSection { - id: vLeftSection - objectName: "leftSection" - overrideAxisLayout: true - forceVerticalLayout: true - width: parent.width - anchors { - top: parent.top - horizontalCenter: parent.horizontalCenter - } - axis: axis - widgetsModel: SettingsData.dankBarLeftWidgetsModel - components: topBarContent.allComponents - noBackground: SettingsData.dankBarNoBackground - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - } - - CenterSection { - id: vCenterSection - objectName: "centerSection" - overrideAxisLayout: true - forceVerticalLayout: true - width: parent.width - anchors { - verticalCenter: parent.verticalCenter - horizontalCenter: parent.horizontalCenter - } - axis: axis - widgetsModel: SettingsData.dankBarCenterWidgetsModel - components: topBarContent.allComponents - noBackground: SettingsData.dankBarNoBackground - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - } - - RightSection { - id: vRightSection - objectName: "rightSection" - overrideAxisLayout: true - forceVerticalLayout: true - width: parent.width - height: implicitHeight - anchors { - bottom: parent.bottom - horizontalCenter: parent.horizontalCenter - } - axis: axis - widgetsModel: SettingsData.dankBarRightWidgetsModel - components: topBarContent.allComponents - noBackground: SettingsData.dankBarNoBackground - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - } - } - } - - Component { - id: clipboardComponent - - ClipboardButton { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - onClicked: { - clipboardHistoryModalPopup.toggle() - } - } - } - - Component { - id: launcherButtonComponent - - LauncherButton { - id: launcherButton - isActive: false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - section: topBarContent.getWidgetSection(parent) - popoutTarget: appDrawerLoader.item - parentScreen: barWindow.screen - hyprlandOverviewLoader: root.hyprlandOverviewLoader - onClicked: { - appDrawerLoader.active = true - if (appDrawerLoader.item && appDrawerLoader.item.setTriggerPosition) { - const globalPos = launcherButton.visualContent.mapToGlobal(0, 0) - const currentScreen = barWindow.screen - const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barWindow.effectiveBarThickness, launcherButton.visualWidth) - appDrawerLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, launcherButton.section, currentScreen) - } - if (appDrawerLoader.item) { - PopoutManager.requestPopout(appDrawerLoader.item, undefined, "appDrawer") - } - } - } - } - - Component { - id: workspaceSwitcherComponent - - WorkspaceSwitcher { - axis: barWindow.axis - screenName: barWindow.screenName - widgetHeight: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - parentScreen: barWindow.screen - hyprlandOverviewLoader: root.hyprlandOverviewLoader - } - } - - Component { - id: focusedWindowComponent - - FocusedApp { - axis: barWindow.axis - availableWidth: topBarContent.leftToMediaGap - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - parentScreen: barWindow.screen - } - } - - Component { - id: runningAppsComponent - - RunningApps { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) - parentScreen: barWindow.screen - topBar: topBarContent - } - } - - Component { - id: clockComponent - - Clock { - axis: barWindow.axis - compactMode: topBarContent.overlapping - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: { - dankDashPopoutLoader.active = true - return dankDashPopoutLoader.item - } - parentScreen: barWindow.screen - - Component.onCompleted: { - barWindow.clockButtonRef = this - } - - Component.onDestruction: { - if (barWindow.clockButtonRef === this) { - barWindow.clockButtonRef = null - } - } - - onClockClicked: { - dankDashPopoutLoader.active = true - if (dankDashPopoutLoader.item) { - if (dankDashPopoutLoader.item.setTriggerPosition) { - const globalPos = visualContent.mapToGlobal(0, 0) - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, visualWidth) - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen - } - PopoutManager.requestPopout(dankDashPopoutLoader.item, 0) - } - } - } - } - - Component { - id: mediaComponent - - Media { - axis: barWindow.axis - compactMode: topBarContent.spacingTight || topBarContent.overlapping - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: { - dankDashPopoutLoader.active = true - return dankDashPopoutLoader.item - } - parentScreen: barWindow.screen - onClicked: { - dankDashPopoutLoader.active = true - if (dankDashPopoutLoader.item) { - if (dankDashPopoutLoader.item.setTriggerPosition) { - const globalPos = visualContent.mapToGlobal(0, 0) - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, visualWidth) - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen - } - PopoutManager.requestPopout(dankDashPopoutLoader.item, 1) - } - } - } - } - - Component { - id: weatherComponent - - Weather { - axis: barWindow.axis - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: { - dankDashPopoutLoader.active = true - return dankDashPopoutLoader.item - } - parentScreen: barWindow.screen - onClicked: { - dankDashPopoutLoader.active = true - if (dankDashPopoutLoader.item) { - if (dankDashPopoutLoader.item.setTriggerPosition) { - const globalPos = visualContent.mapToGlobal(0, 0) - const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, visualWidth) - dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) - } else { - dankDashPopoutLoader.item.triggerScreen = barWindow.screen - } - PopoutManager.requestPopout(dankDashPopoutLoader.item, 3) - } - } - } - } - - Component { - id: systemTrayComponent - - SystemTrayBar { - parentWindow: root - parentScreen: barWindow.screen - widgetThickness: barWindow.widgetThickness - isAtBottom: SettingsData.dankBarPosition === SettingsData.Position.Bottom - visible: SettingsData.getFilteredScreens("systemTray").includes(barWindow.screen) && SystemTray.items.values.length > 0 - } - } - - Component { - id: privacyIndicatorComponent - - PrivacyIndicator { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: cpuUsageComponent - - CpuMonitor { - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: { - processListPopoutLoader.active = true - return processListPopoutLoader.item - } - parentScreen: barWindow.screen - widgetData: parent.widgetData - toggleProcessList: () => { - processListPopoutLoader.active = true - return processListPopoutLoader.item?.toggle() - } - } - } - - Component { - id: memUsageComponent - - RamMonitor { - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: { - processListPopoutLoader.active = true - return processListPopoutLoader.item - } - parentScreen: barWindow.screen - widgetData: parent.widgetData - toggleProcessList: () => { - processListPopoutLoader.active = true - return processListPopoutLoader.item?.toggle() - } - } - } - - Component { - id: diskUsageComponent - - DiskUsage { - widgetThickness: barWindow.widgetThickness - widgetData: parent.widgetData - parentScreen: barWindow.screen - } - } - - Component { - id: cpuTempComponent - - CpuTemperature { - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: { - processListPopoutLoader.active = true - return processListPopoutLoader.item - } - parentScreen: barWindow.screen - widgetData: parent.widgetData - toggleProcessList: () => { - processListPopoutLoader.active = true - return processListPopoutLoader.item?.toggle() - } - } - } - - Component { - id: gpuTempComponent - - GpuTemperature { - barThickness: barWindow.effectiveBarThickness - widgetThickness: barWindow.widgetThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: { - processListPopoutLoader.active = true - return processListPopoutLoader.item - } - parentScreen: barWindow.screen - widgetData: parent.widgetData - toggleProcessList: () => { - processListPopoutLoader.active = true - return processListPopoutLoader.item?.toggle() - } - } - } - - Component { - id: networkComponent - - NetworkMonitor {} - } - - Component { - id: notificationButtonComponent - - NotificationCenterButton { - hasUnread: barWindow.notificationCount > 0 - isActive: notificationCenterLoader.item ? notificationCenterLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: { - notificationCenterLoader.active = true - return notificationCenterLoader.item - } - parentScreen: barWindow.screen - onClicked: { - notificationCenterLoader.active = true - if (notificationCenterLoader.item) { - PopoutManager.requestPopout(notificationCenterLoader.item, undefined, "notifications") - } - } - } - } - - Component { - id: batteryComponent - - Battery { - batteryPopupVisible: batteryPopoutLoader.item ? batteryPopoutLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: { - batteryPopoutLoader.active = true - return batteryPopoutLoader.item - } - parentScreen: barWindow.screen - onToggleBatteryPopup: { - batteryPopoutLoader.active = true - if (batteryPopoutLoader.item) { - PopoutManager.requestPopout(batteryPopoutLoader.item, undefined, "battery") - } - } - } - } - - Component { - id: layoutComponent - - DWLLayout { - layoutPopupVisible: layoutPopoutLoader.item ? layoutPopoutLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "center" - popoutTarget: { - layoutPopoutLoader.active = true - return layoutPopoutLoader.item - } - parentScreen: barWindow.screen - onToggleLayoutPopup: { - layoutPopoutLoader.active = true - if (layoutPopoutLoader.item) { - PopoutManager.requestPopout(layoutPopoutLoader.item, undefined, "layout") - } - } - } - } - - Component { - id: vpnComponent - - Vpn { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: { - vpnPopoutLoader.active = true - return vpnPopoutLoader.item - } - parentScreen: barWindow.screen - onToggleVpnPopup: { - vpnPopoutLoader.active = true - if (vpnPopoutLoader.item) { - PopoutManager.requestPopout(vpnPopoutLoader.item, undefined, "vpn") - } - } - } - } - - Component { - id: controlCenterButtonComponent - - ControlCenterButton { - isActive: controlCenterLoader.item ? controlCenterLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: { - controlCenterLoader.active = true - return controlCenterLoader.item - } - parentScreen: barWindow.screen - widgetData: parent.widgetData - - Component.onCompleted: { - barWindow.controlCenterButtonRef = this - } - - Component.onDestruction: { - if (barWindow.controlCenterButtonRef === this) { - barWindow.controlCenterButtonRef = null - } - } - - onClicked: { - controlCenterLoader.active = true - if (!controlCenterLoader.item) { - return - } - controlCenterLoader.item.triggerScreen = barWindow.screen - PopoutManager.requestPopout(controlCenterLoader.item, undefined, "controlCenter") - if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) { - NetworkService.scanWifi() - } - } - } - } - - Component { - id: capsLockIndicatorComponent - - CapsLockIndicator { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: idleInhibitorComponent - - IdleInhibitor { - widgetThickness: barWindow.widgetThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: spacerComponent - - Item { - width: barWindow.isVertical ? barWindow.widgetThickness : (parent.spacerSize || 20) - height: barWindow.isVertical ? (parent.spacerSize || 20) : barWindow.widgetThickness - implicitWidth: width - implicitHeight: height - - Rectangle { - anchors.fill: parent - color: "transparent" - border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) - border.width: 1 - radius: 2 - visible: false - - MouseArea { - anchors.fill: parent - hoverEnabled: true - acceptedButtons: Qt.NoButton // do not consume clicks - propagateComposedEvents: true // let events pass through - cursorShape: Qt.ArrowCursor // don't override widget cursors - onEntered: parent.visible = true - onExited: parent.visible = false - } - } - } - } - - Component { - id: separatorComponent - - Item { - width: barWindow.isVertical ? parent.barThickness : 1 - height: barWindow.isVertical ? 1 : parent.barThickness - implicitWidth: width - implicitHeight: height - - Rectangle { - width: barWindow.isVertical ? parent.width * 0.6 : 1 - height: barWindow.isVertical ? 1 : parent.height * 0.6 - anchors.centerIn: parent - color: Theme.outline - opacity: 0.3 - } - } - } - - Component { - id: keyboardLayoutNameComponent - - KeyboardLayoutName {} - } - - Component { - id: notepadButtonComponent - - NotepadButton { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - } - } - - Component { - id: colorPickerComponent - - ColorPicker { - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - section: topBarContent.getWidgetSection(parent) || "right" - parentScreen: barWindow.screen - onColorPickerRequested: { - barWindow.colorPickerRequested() - } - } - } - - Component { - id: systemUpdateComponent - - SystemUpdate { - isActive: systemUpdateLoader.item ? systemUpdateLoader.item.shouldBeVisible : false - widgetThickness: barWindow.widgetThickness - barThickness: barWindow.effectiveBarThickness - axis: barWindow.axis - section: topBarContent.getWidgetSection(parent) || "right" - popoutTarget: { - systemUpdateLoader.active = true - return systemUpdateLoader.item - } - parentScreen: barWindow.screen - onClicked: { - systemUpdateLoader.active = true - systemUpdateLoader.item?.toggle() - } - } - } - } - } - } - } - } + delegate: DankBarWindow { + rootWindow: root } } } diff --git a/quickshell/Modules/DankBar/DankBarContent.qml b/quickshell/Modules/DankBar/DankBarContent.qml new file mode 100644 index 00000000..a789ce02 --- /dev/null +++ b/quickshell/Modules/DankBar/DankBarContent.qml @@ -0,0 +1,1009 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Effects +import QtQuick.Shapes +import Quickshell +import Quickshell.Hyprland +import Quickshell.I3 +import Quickshell.Io +import Quickshell.Services.Mpris +import Quickshell.Services.Notifications +import Quickshell.Services.SystemTray +import Quickshell.Wayland +import Quickshell.Widgets +import qs.Common +import qs.Modules +import qs.Modules.DankBar.Widgets +import qs.Modules.DankBar.Popouts +import qs.Services +import qs.Widgets + +Item { + id: topBarContent + + required property var barWindow + required property var rootWindow + + anchors.fill: parent + anchors.leftMargin: !barWindow.isVertical ? Math.max(Theme.spacingXS, SettingsData.dankBarInnerPadding * 0.8) : SettingsData.dankBarInnerPadding / 2 + anchors.rightMargin: !barWindow.isVertical ? Math.max(Theme.spacingXS, SettingsData.dankBarInnerPadding * 0.8) : SettingsData.dankBarInnerPadding / 2 + anchors.topMargin: !barWindow.isVertical ? 0 : Math.max(Theme.spacingXS, SettingsData.dankBarInnerPadding * 0.8) + anchors.bottomMargin: !barWindow.isVertical ? 0 : Math.max(Theme.spacingXS, SettingsData.dankBarInnerPadding * 0.8) + clip: false + + property int componentMapRevision: 0 + + function updateComponentMap() { + componentMapRevision++ + } + + readonly property var sortedToplevels: { + return CompositorService.filterCurrentWorkspace(CompositorService.sortedToplevels, barWindow.screenName); + } + + function getRealWorkspaces() { + if (CompositorService.isNiri) { + if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { + return NiriService.getCurrentOutputWorkspaceNumbers() + } + const workspaces = NiriService.allWorkspaces.filter(ws => ws.output === barWindow.screenName).map(ws => ws.idx + 1) + return workspaces.length > 0 ? workspaces : [1, 2] + } else if (CompositorService.isHyprland) { + const workspaces = Hyprland.workspaces?.values || [] + + if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { + const sorted = workspaces.slice().sort((a, b) => a.id - b.id) + const filtered = sorted.filter(ws => ws.id > -1) + return filtered.length > 0 ? filtered : [{"id": 1, "name": "1"}] + } + + const monitorWorkspaces = workspaces.filter(ws => { + return ws.lastIpcObject && ws.lastIpcObject.monitor === barWindow.screenName && ws.id > -1 + }) + + if (monitorWorkspaces.length === 0) { + return [{"id": 1, "name": "1"}] + } + + return monitorWorkspaces.sort((a, b) => a.id - b.id) + } else if (CompositorService.isDwl) { + if (!DwlService.dwlAvailable) { + return [0] + } + if (SettingsData.dwlShowAllTags) { + return Array.from({length: DwlService.tagCount}, (_, i) => i) + } + return DwlService.getVisibleTags(barWindow.screenName) + } else if (CompositorService.isSway) { + const workspaces = I3.workspaces?.values || [] + if (workspaces.length === 0) return [{"num": 1}] + + if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { + return workspaces.slice().sort((a, b) => a.num - b.num) + } + + const monitorWorkspaces = workspaces.filter(ws => ws.monitor?.name === barWindow.screenName) + return monitorWorkspaces.length > 0 ? monitorWorkspaces.sort((a, b) => a.num - b.num) : [{"num": 1}] + } + return [1] + } + + function getCurrentWorkspace() { + if (CompositorService.isNiri) { + if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { + return NiriService.getCurrentWorkspaceNumber() + } + const activeWs = NiriService.allWorkspaces.find(ws => ws.output === barWindow.screenName && ws.is_active) + return activeWs ? activeWs.idx + 1 : 1 + } else if (CompositorService.isHyprland) { + const monitors = Hyprland.monitors?.values || [] + const currentMonitor = monitors.find(monitor => monitor.name === barWindow.screenName) + return currentMonitor?.activeWorkspace?.id ?? 1 + } else if (CompositorService.isDwl) { + if (!DwlService.dwlAvailable) return 0 + const outputState = DwlService.getOutputState(barWindow.screenName) + if (!outputState || !outputState.tags) return 0 + const activeTags = DwlService.getActiveTags(barWindow.screenName) + return activeTags.length > 0 ? activeTags[0] : 0 + } else if (CompositorService.isSway) { + if (!barWindow.screenName || !SettingsData.workspacesPerMonitor) { + const focusedWs = I3.workspaces?.values?.find(ws => ws.focused === true) + return focusedWs ? focusedWs.num : 1 + } + + const focusedWs = I3.workspaces?.values?.find(ws => ws.monitor?.name === barWindow.screenName && ws.focused === true) + return focusedWs ? focusedWs.num : 1 + } + return 1 + } + + function switchWorkspace(direction) { + const realWorkspaces = getRealWorkspaces() + if (realWorkspaces.length < 2) { + return + } + + if (CompositorService.isNiri) { + const currentWs = getCurrentWorkspace() + const currentIndex = realWorkspaces.findIndex(ws => ws === currentWs) + const validIndex = currentIndex === -1 ? 0 : currentIndex + const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0) + + if (nextIndex !== validIndex) { + NiriService.switchToWorkspace(realWorkspaces[nextIndex] - 1) + } + } else if (CompositorService.isHyprland) { + const currentWs = getCurrentWorkspace() + const currentIndex = realWorkspaces.findIndex(ws => ws.id === currentWs) + const validIndex = currentIndex === -1 ? 0 : currentIndex + const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0) + + if (nextIndex !== validIndex) { + Hyprland.dispatch(`workspace ${realWorkspaces[nextIndex].id}`) + } + } else if (CompositorService.isDwl) { + const currentTag = getCurrentWorkspace() + const currentIndex = realWorkspaces.findIndex(tag => tag === currentTag) + const validIndex = currentIndex === -1 ? 0 : currentIndex + const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0) + + if (nextIndex !== validIndex) { + DwlService.switchToTag(barWindow.screenName, realWorkspaces[nextIndex]) + } + } else if (CompositorService.isSway) { + const currentWs = getCurrentWorkspace() + const currentIndex = realWorkspaces.findIndex(ws => ws.num === currentWs) + const validIndex = currentIndex === -1 ? 0 : currentIndex + const nextIndex = direction > 0 ? Math.min(validIndex + 1, realWorkspaces.length - 1) : Math.max(validIndex - 1, 0) + + if (nextIndex !== validIndex) { + try { I3.dispatch(`workspace number ${realWorkspaces[nextIndex].num}`) } catch(_){} + } + } + } + + function switchApp(deltaY) { + const windows = sortedToplevels; + if (windows.length < 2) { + return; + } + let currentIndex = -1; + for (let i = 0; i < windows.length; i++) { + if (windows[i].activated) { + currentIndex = i; + break; + } + } + let nextIndex; + if (deltaY < 0) { + if (currentIndex === -1) { + nextIndex = 0; + } else { + nextIndex = currentIndex + 1; + } + } else { + if (currentIndex === -1) { + nextIndex = windows.length - 1; + } else { + nextIndex = currentIndex - 1; + } + } + const nextWindow = windows[nextIndex]; + if (nextWindow) { + nextWindow.activate(); + } + } + + readonly property int availableWidth: width + readonly property int launcherButtonWidth: 40 + readonly property int workspaceSwitcherWidth: 120 + readonly property int focusedAppMaxWidth: 456 + readonly property int estimatedLeftSectionWidth: launcherButtonWidth + workspaceSwitcherWidth + focusedAppMaxWidth + (Theme.spacingXS * 2) + readonly property int rightSectionWidth: 200 + readonly property int clockWidth: 120 + readonly property int mediaMaxWidth: 280 + readonly property int weatherWidth: 80 + readonly property bool validLayout: availableWidth > 100 && estimatedLeftSectionWidth > 0 && rightSectionWidth > 0 + readonly property int clockLeftEdge: (availableWidth - clockWidth) / 2 + readonly property int clockRightEdge: clockLeftEdge + clockWidth + readonly property int leftSectionRightEdge: estimatedLeftSectionWidth + readonly property int mediaLeftEdge: clockLeftEdge - mediaMaxWidth - Theme.spacingS + readonly property int rightSectionLeftEdge: availableWidth - rightSectionWidth + readonly property int leftToClockGap: Math.max(0, clockLeftEdge - leftSectionRightEdge) + readonly property int leftToMediaGap: mediaMaxWidth > 0 ? Math.max(0, mediaLeftEdge - leftSectionRightEdge) : leftToClockGap + readonly property int mediaToClockGap: mediaMaxWidth > 0 ? Theme.spacingS : 0 + readonly property int clockToRightGap: validLayout ? Math.max(0, rightSectionLeftEdge - clockRightEdge) : 1000 + readonly property bool spacingTight: !barWindow.isVertical && validLayout && (leftToMediaGap < 150 || clockToRightGap < 100) + readonly property bool overlapping: !barWindow.isVertical && validLayout && (leftToMediaGap < 100 || clockToRightGap < 50) + + function getWidgetEnabled(enabled) { + return enabled !== false + } + + function getWidgetSection(parentItem) { + let current = parentItem + while (current) { + if (current.objectName === "leftSection") { + return "left" + } + if (current.objectName === "centerSection") { + return "center" + } + if (current.objectName === "rightSection") { + return "right" + } + current = current.parent + } + return "left" + } + + readonly property var widgetVisibility: ({ + "cpuUsage": DgopService.dgopAvailable, + "memUsage": DgopService.dgopAvailable, + "cpuTemp": DgopService.dgopAvailable, + "gpuTemp": DgopService.dgopAvailable, + "network_speed_monitor": DgopService.dgopAvailable + }) + + function getWidgetVisible(widgetId) { + return widgetVisibility[widgetId] ?? true + } + + readonly property var componentMap: { + componentMapRevision + + let baseMap = { + "launcherButton": launcherButtonComponent, + "workspaceSwitcher": workspaceSwitcherComponent, + "focusedWindow": focusedWindowComponent, + "runningApps": runningAppsComponent, + "clock": clockComponent, + "music": mediaComponent, + "weather": weatherComponent, + "systemTray": systemTrayComponent, + "privacyIndicator": privacyIndicatorComponent, + "clipboard": clipboardComponent, + "cpuUsage": cpuUsageComponent, + "memUsage": memUsageComponent, + "diskUsage": diskUsageComponent, + "cpuTemp": cpuTempComponent, + "gpuTemp": gpuTempComponent, + "notificationButton": notificationButtonComponent, + "battery": batteryComponent, + "layout": layoutComponent, + "controlCenterButton": controlCenterButtonComponent, + "capsLockIndicator": capsLockIndicatorComponent, + "idleInhibitor": idleInhibitorComponent, + "spacer": spacerComponent, + "separator": separatorComponent, + "network_speed_monitor": networkComponent, + "keyboard_layout_name": keyboardLayoutNameComponent, + "vpn": vpnComponent, + "notepadButton": notepadButtonComponent, + "colorPicker": colorPickerComponent, + "systemUpdate": systemUpdateComponent + } + + let pluginMap = PluginService.getWidgetComponents() + return Object.assign(baseMap, pluginMap) + } + + function getWidgetComponent(widgetId) { + return componentMap[widgetId] || null + } + + readonly property var allComponents: ({ + "launcherButtonComponent": launcherButtonComponent, + "workspaceSwitcherComponent": workspaceSwitcherComponent, + "focusedWindowComponent": focusedWindowComponent, + "runningAppsComponent": runningAppsComponent, + "clockComponent": clockComponent, + "mediaComponent": mediaComponent, + "weatherComponent": weatherComponent, + "systemTrayComponent": systemTrayComponent, + "privacyIndicatorComponent": privacyIndicatorComponent, + "clipboardComponent": clipboardComponent, + "cpuUsageComponent": cpuUsageComponent, + "memUsageComponent": memUsageComponent, + "diskUsageComponent": diskUsageComponent, + "cpuTempComponent": cpuTempComponent, + "gpuTempComponent": gpuTempComponent, + "notificationButtonComponent": notificationButtonComponent, + "batteryComponent": batteryComponent, + "layoutComponent": layoutComponent, + "controlCenterButtonComponent": controlCenterButtonComponent, + "capsLockIndicatorComponent": capsLockIndicatorComponent, + "idleInhibitorComponent": idleInhibitorComponent, + "spacerComponent": spacerComponent, + "separatorComponent": separatorComponent, + "networkComponent": networkComponent, + "keyboardLayoutNameComponent": keyboardLayoutNameComponent, + "vpnComponent": vpnComponent, + "notepadButtonComponent": notepadButtonComponent, + "colorPickerComponent": colorPickerComponent, + "systemUpdateComponent": systemUpdateComponent + }) + + Item { + id: stackContainer + anchors.fill: parent + + Item { + id: horizontalStack + anchors.fill: parent + visible: !barWindow.axis.isVertical + + LeftSection { + id: hLeftSection + objectName: "leftSection" + overrideAxisLayout: true + forceVerticalLayout: false + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + axis: barWindow.axis + widgetsModel: SettingsData.dankBarLeftWidgetsModel + components: topBarContent.allComponents + noBackground: SettingsData.dankBarNoBackground + parentScreen: barWindow.screen + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + } + + RightSection { + id: hRightSection + objectName: "rightSection" + overrideAxisLayout: true + forceVerticalLayout: false + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + axis: barWindow.axis + widgetsModel: SettingsData.dankBarRightWidgetsModel + components: topBarContent.allComponents + noBackground: SettingsData.dankBarNoBackground + parentScreen: barWindow.screen + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + } + + CenterSection { + id: hCenterSection + objectName: "centerSection" + overrideAxisLayout: true + forceVerticalLayout: false + anchors { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + axis: barWindow.axis + widgetsModel: SettingsData.dankBarCenterWidgetsModel + components: topBarContent.allComponents + noBackground: SettingsData.dankBarNoBackground + parentScreen: barWindow.screen + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + } + } + + Item { + id: verticalStack + anchors.fill: parent + visible: barWindow.axis.isVertical + + LeftSection { + id: vLeftSection + objectName: "leftSection" + overrideAxisLayout: true + forceVerticalLayout: true + width: parent.width + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + } + axis: barWindow.axis + widgetsModel: SettingsData.dankBarLeftWidgetsModel + components: topBarContent.allComponents + noBackground: SettingsData.dankBarNoBackground + parentScreen: barWindow.screen + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + } + + CenterSection { + id: vCenterSection + objectName: "centerSection" + overrideAxisLayout: true + forceVerticalLayout: true + width: parent.width + anchors { + verticalCenter: parent.verticalCenter + horizontalCenter: parent.horizontalCenter + } + axis: barWindow.axis + widgetsModel: SettingsData.dankBarCenterWidgetsModel + components: topBarContent.allComponents + noBackground: SettingsData.dankBarNoBackground + parentScreen: barWindow.screen + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + } + + RightSection { + id: vRightSection + objectName: "rightSection" + overrideAxisLayout: true + forceVerticalLayout: true + width: parent.width + height: implicitHeight + anchors { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + axis: barWindow.axis + widgetsModel: SettingsData.dankBarRightWidgetsModel + components: topBarContent.allComponents + noBackground: SettingsData.dankBarNoBackground + parentScreen: barWindow.screen + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + } + } + } + + Component { + id: clipboardComponent + + ClipboardButton { + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) + parentScreen: barWindow.screen + onClicked: { + clipboardHistoryModalPopup.toggle() + } + } + } + + Component { + id: launcherButtonComponent + + LauncherButton { + id: launcherButton + isActive: false + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + section: topBarContent.getWidgetSection(parent) + popoutTarget: appDrawerLoader.item + parentScreen: barWindow.screen + hyprlandOverviewLoader: rootWindow ? rootWindow.hyprlandOverviewLoader : null + onClicked: { + appDrawerLoader.active = true + if (appDrawerLoader.item && appDrawerLoader.item.setTriggerPosition) { + const globalPos = launcherButton.visualContent.mapToGlobal(0, 0) + const currentScreen = barWindow.screen + const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barWindow.effectiveBarThickness, launcherButton.visualWidth) + appDrawerLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, launcherButton.section, currentScreen) + } + if (appDrawerLoader.item) { + PopoutManager.requestPopout(appDrawerLoader.item, undefined, "appDrawer") + } + } + } + } + + Component { + id: workspaceSwitcherComponent + + WorkspaceSwitcher { + axis: barWindow.axis + screenName: barWindow.screenName + widgetHeight: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + parentScreen: barWindow.screen + hyprlandOverviewLoader: rootWindow ? rootWindow.hyprlandOverviewLoader : null + } + } + + Component { + id: focusedWindowComponent + + FocusedApp { + axis: barWindow.axis + availableWidth: topBarContent.leftToMediaGap + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + parentScreen: barWindow.screen + } + } + + Component { + id: runningAppsComponent + + RunningApps { + widgetThickness: barWindow.widgetThickness + section: topBarContent.getWidgetSection(parent) + parentScreen: barWindow.screen + topBar: topBarContent + } + } + + Component { + id: clockComponent + + Clock { + axis: barWindow.axis + compactMode: topBarContent.overlapping + barThickness: barWindow.effectiveBarThickness + widgetThickness: barWindow.widgetThickness + section: topBarContent.getWidgetSection(parent) || "center" + popoutTarget: { + dankDashPopoutLoader.active = true + return dankDashPopoutLoader.item + } + parentScreen: barWindow.screen + + Component.onCompleted: { + barWindow.clockButtonRef = this + } + + Component.onDestruction: { + if (barWindow.clockButtonRef === this) { + barWindow.clockButtonRef = null + } + } + + onClockClicked: { + dankDashPopoutLoader.active = true + if (dankDashPopoutLoader.item) { + if (dankDashPopoutLoader.item.setTriggerPosition) { + const globalPos = visualContent.mapToGlobal(0, 0) + const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, visualWidth) + dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) + } else { + dankDashPopoutLoader.item.triggerScreen = barWindow.screen + } + PopoutManager.requestPopout(dankDashPopoutLoader.item, 0) + } + } + } + } + + Component { + id: mediaComponent + + Media { + axis: barWindow.axis + compactMode: topBarContent.spacingTight || topBarContent.overlapping + barThickness: barWindow.effectiveBarThickness + widgetThickness: barWindow.widgetThickness + section: topBarContent.getWidgetSection(parent) || "center" + popoutTarget: { + dankDashPopoutLoader.active = true + return dankDashPopoutLoader.item + } + parentScreen: barWindow.screen + onClicked: { + dankDashPopoutLoader.active = true + if (dankDashPopoutLoader.item) { + if (dankDashPopoutLoader.item.setTriggerPosition) { + const globalPos = visualContent.mapToGlobal(0, 0) + const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, visualWidth) + dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) + } else { + dankDashPopoutLoader.item.triggerScreen = barWindow.screen + } + PopoutManager.requestPopout(dankDashPopoutLoader.item, 1) + } + } + } + } + + Component { + id: weatherComponent + + Weather { + axis: barWindow.axis + barThickness: barWindow.effectiveBarThickness + widgetThickness: barWindow.widgetThickness + section: topBarContent.getWidgetSection(parent) || "center" + popoutTarget: { + dankDashPopoutLoader.active = true + return dankDashPopoutLoader.item + } + parentScreen: barWindow.screen + onClicked: { + dankDashPopoutLoader.active = true + if (dankDashPopoutLoader.item) { + if (dankDashPopoutLoader.item.setTriggerPosition) { + const globalPos = visualContent.mapToGlobal(0, 0) + const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, visualWidth) + dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) + } else { + dankDashPopoutLoader.item.triggerScreen = barWindow.screen + } + PopoutManager.requestPopout(dankDashPopoutLoader.item, 3) + } + } + } + } + + Component { + id: systemTrayComponent + + SystemTrayBar { + parentWindow: rootWindow + parentScreen: barWindow.screen + widgetThickness: barWindow.widgetThickness + isAtBottom: SettingsData.dankBarPosition === SettingsData.Position.Bottom + visible: SettingsData.getFilteredScreens("systemTray").includes(barWindow.screen) && SystemTray.items.values.length > 0 + } + } + + Component { + id: privacyIndicatorComponent + + PrivacyIndicator { + widgetThickness: barWindow.widgetThickness + section: topBarContent.getWidgetSection(parent) || "right" + parentScreen: barWindow.screen + } + } + + Component { + id: cpuUsageComponent + + CpuMonitor { + barThickness: barWindow.effectiveBarThickness + widgetThickness: barWindow.widgetThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + popoutTarget: { + processListPopoutLoader.active = true + return processListPopoutLoader.item + } + parentScreen: barWindow.screen + widgetData: parent.widgetData + toggleProcessList: () => { + processListPopoutLoader.active = true + return processListPopoutLoader.item?.toggle() + } + } + } + + Component { + id: memUsageComponent + + RamMonitor { + barThickness: barWindow.effectiveBarThickness + widgetThickness: barWindow.widgetThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + popoutTarget: { + processListPopoutLoader.active = true + return processListPopoutLoader.item + } + parentScreen: barWindow.screen + widgetData: parent.widgetData + toggleProcessList: () => { + processListPopoutLoader.active = true + return processListPopoutLoader.item?.toggle() + } + } + } + + Component { + id: diskUsageComponent + + DiskUsage { + widgetThickness: barWindow.widgetThickness + widgetData: parent.widgetData + parentScreen: barWindow.screen + } + } + + Component { + id: cpuTempComponent + + CpuTemperature { + barThickness: barWindow.effectiveBarThickness + widgetThickness: barWindow.widgetThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + popoutTarget: { + processListPopoutLoader.active = true + return processListPopoutLoader.item + } + parentScreen: barWindow.screen + widgetData: parent.widgetData + toggleProcessList: () => { + processListPopoutLoader.active = true + return processListPopoutLoader.item?.toggle() + } + } + } + + Component { + id: gpuTempComponent + + GpuTemperature { + barThickness: barWindow.effectiveBarThickness + widgetThickness: barWindow.widgetThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + popoutTarget: { + processListPopoutLoader.active = true + return processListPopoutLoader.item + } + parentScreen: barWindow.screen + widgetData: parent.widgetData + toggleProcessList: () => { + processListPopoutLoader.active = true + return processListPopoutLoader.item?.toggle() + } + } + } + + Component { + id: networkComponent + + NetworkMonitor {} + } + + Component { + id: notificationButtonComponent + + NotificationCenterButton { + hasUnread: barWindow.notificationCount > 0 + isActive: notificationCenterLoader.item ? notificationCenterLoader.item.shouldBeVisible : false + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + popoutTarget: { + notificationCenterLoader.active = true + return notificationCenterLoader.item + } + parentScreen: barWindow.screen + onClicked: { + notificationCenterLoader.active = true + if (notificationCenterLoader.item) { + PopoutManager.requestPopout(notificationCenterLoader.item, undefined, "notifications") + } + } + } + } + + Component { + id: batteryComponent + + Battery { + batteryPopupVisible: batteryPopoutLoader.item ? batteryPopoutLoader.item.shouldBeVisible : false + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + popoutTarget: { + batteryPopoutLoader.active = true + return batteryPopoutLoader.item + } + parentScreen: barWindow.screen + onToggleBatteryPopup: { + batteryPopoutLoader.active = true + if (batteryPopoutLoader.item) { + PopoutManager.requestPopout(batteryPopoutLoader.item, undefined, "battery") + } + } + } + } + + Component { + id: layoutComponent + + DWLLayout { + layoutPopupVisible: layoutPopoutLoader.item ? layoutPopoutLoader.item.shouldBeVisible : false + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "center" + popoutTarget: { + layoutPopoutLoader.active = true + return layoutPopoutLoader.item + } + parentScreen: barWindow.screen + onToggleLayoutPopup: { + layoutPopoutLoader.active = true + if (layoutPopoutLoader.item) { + PopoutManager.requestPopout(layoutPopoutLoader.item, undefined, "layout") + } + } + } + } + + Component { + id: vpnComponent + + Vpn { + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + popoutTarget: { + vpnPopoutLoader.active = true + return vpnPopoutLoader.item + } + parentScreen: barWindow.screen + onToggleVpnPopup: { + vpnPopoutLoader.active = true + if (vpnPopoutLoader.item) { + PopoutManager.requestPopout(vpnPopoutLoader.item, undefined, "vpn") + } + } + } + } + + Component { + id: controlCenterButtonComponent + + ControlCenterButton { + isActive: controlCenterLoader.item ? controlCenterLoader.item.shouldBeVisible : false + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + popoutTarget: { + controlCenterLoader.active = true + return controlCenterLoader.item + } + parentScreen: barWindow.screen + widgetData: parent.widgetData + + Component.onCompleted: { + barWindow.controlCenterButtonRef = this + } + + Component.onDestruction: { + if (barWindow.controlCenterButtonRef === this) { + barWindow.controlCenterButtonRef = null + } + } + + onClicked: { + controlCenterLoader.active = true + if (!controlCenterLoader.item) { + return + } + controlCenterLoader.item.triggerScreen = barWindow.screen + PopoutManager.requestPopout(controlCenterLoader.item, undefined, "controlCenter") + if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) { + NetworkService.scanWifi() + } + } + } + } + + Component { + id: capsLockIndicatorComponent + + CapsLockIndicator { + widgetThickness: barWindow.widgetThickness + section: topBarContent.getWidgetSection(parent) || "right" + parentScreen: barWindow.screen + } + } + + Component { + id: idleInhibitorComponent + + IdleInhibitor { + widgetThickness: barWindow.widgetThickness + section: topBarContent.getWidgetSection(parent) || "right" + parentScreen: barWindow.screen + } + } + + Component { + id: spacerComponent + + Item { + width: barWindow.isVertical ? barWindow.widgetThickness : (parent.spacerSize || 20) + height: barWindow.isVertical ? (parent.spacerSize || 20) : barWindow.widgetThickness + implicitWidth: width + implicitHeight: height + + Rectangle { + anchors.fill: parent + color: "transparent" + border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.1) + border.width: 1 + radius: 2 + visible: false + + MouseArea { + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.NoButton + propagateComposedEvents: true + cursorShape: Qt.ArrowCursor + onEntered: parent.visible = true + onExited: parent.visible = false + } + } + } + } + + Component { + id: separatorComponent + + Item { + width: barWindow.isVertical ? parent.barThickness : 1 + height: barWindow.isVertical ? 1 : parent.barThickness + implicitWidth: width + implicitHeight: height + + Rectangle { + width: barWindow.isVertical ? parent.width * 0.6 : 1 + height: barWindow.isVertical ? 1 : parent.height * 0.6 + anchors.centerIn: parent + color: Theme.outline + opacity: 0.3 + } + } + } + + Component { + id: keyboardLayoutNameComponent + + KeyboardLayoutName {} + } + + Component { + id: notepadButtonComponent + + NotepadButton { + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + parentScreen: barWindow.screen + } + } + + Component { + id: colorPickerComponent + + ColorPicker { + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + section: topBarContent.getWidgetSection(parent) || "right" + parentScreen: barWindow.screen + onColorPickerRequested: { + rootWindow.colorPickerRequested() + } + } + } + + Component { + id: systemUpdateComponent + + SystemUpdate { + isActive: systemUpdateLoader.item ? systemUpdateLoader.item.shouldBeVisible : false + widgetThickness: barWindow.widgetThickness + barThickness: barWindow.effectiveBarThickness + axis: barWindow.axis + section: topBarContent.getWidgetSection(parent) || "right" + popoutTarget: { + systemUpdateLoader.active = true + return systemUpdateLoader.item + } + parentScreen: barWindow.screen + onClicked: { + systemUpdateLoader.active = true + systemUpdateLoader.item?.toggle() + } + } + } +} diff --git a/quickshell/Modules/DankBar/DankBarWindow.qml b/quickshell/Modules/DankBar/DankBarWindow.qml new file mode 100644 index 00000000..0e47bc95 --- /dev/null +++ b/quickshell/Modules/DankBar/DankBarWindow.qml @@ -0,0 +1,538 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Effects +import QtQuick.Shapes +import Quickshell +import Quickshell.Hyprland +import Quickshell.I3 +import Quickshell.Io +import Quickshell.Services.Mpris +import Quickshell.Services.Notifications +import Quickshell.Services.SystemTray +import Quickshell.Wayland +import Quickshell.Widgets +import qs.Common +import qs.Modules +import qs.Modules.DankBar.Widgets +import qs.Modules.DankBar.Popouts +import qs.Services +import qs.Widgets + +PanelWindow { + id: barWindow + + required property var rootWindow + property var modelData: item + + property var controlCenterButtonRef: null + property var clockButtonRef: null + + function triggerControlCenter() { + controlCenterLoader.active = true + if (!controlCenterLoader.item) { + return + } + + if (controlCenterButtonRef && controlCenterLoader.item.setTriggerPosition) { + const globalPos = controlCenterButtonRef.mapToGlobal(0, 0) + const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, controlCenterButtonRef.width) + const section = controlCenterButtonRef.section || "right" + controlCenterLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) + } else { + controlCenterLoader.item.triggerScreen = barWindow.screen + } + + controlCenterLoader.item.toggle() + if (controlCenterLoader.item.shouldBeVisible && NetworkService.wifiEnabled) { + NetworkService.scanWifi() + } + } + + function triggerWallpaperBrowser() { + dankDashPopoutLoader.active = true + if (!dankDashPopoutLoader.item) { + return + } + + if (clockButtonRef && clockButtonRef.visualContent && dankDashPopoutLoader.item.setTriggerPosition) { + const globalPos = clockButtonRef.visualContent.mapToGlobal(0, 0) + const pos = SettingsData.getPopupTriggerPosition(globalPos, barWindow.screen, barWindow.effectiveBarThickness, clockButtonRef.visualWidth) + const section = clockButtonRef.section || "center" + dankDashPopoutLoader.item.setTriggerPosition(pos.x, pos.y, pos.width, section, barWindow.screen) + } else { + dankDashPopoutLoader.item.triggerScreen = barWindow.screen + } + + PopoutManager.requestPopout(dankDashPopoutLoader.item, 2) + } + + readonly property var dBarLayer: { + switch (Quickshell.env("DMS_DANKBAR_LAYER")) { + case "bottom": + return WlrLayer.Bottom + case "overlay": + return WlrLayer.Overlay + case "background": + return WlrLayer.background + default: + return WlrLayer.Top + } + } + + WlrLayershell.layer: dBarLayer + WlrLayershell.namespace: "dms:bar" + + signal colorPickerRequested + + onColorPickerRequested: rootWindow.colorPickerRequested() + + property alias axis: axis + + AxisContext { + id: axis + edge: { + switch (SettingsData.dankBarPosition) { + case SettingsData.Position.Top: + return "top" + case SettingsData.Position.Bottom: + return "bottom" + case SettingsData.Position.Left: + return "left" + case SettingsData.Position.Right: + return "right" + default: + return "top" + } + } + } + + readonly property bool isVertical: axis.isVertical + + property bool gothCornersEnabled: SettingsData.dankBarGothCornersEnabled + property real wingtipsRadius: SettingsData.dankBarGothCornerRadiusOverride ? SettingsData.dankBarGothCornerRadiusValue : Theme.cornerRadius + readonly property real _wingR: Math.max(0, wingtipsRadius) + readonly property color _surfaceContainer: Theme.surfaceContainer + readonly property real _backgroundAlpha: topBarCore?.backgroundTransparency ?? SettingsData.dankBarTransparency + readonly property color _bgColor: Theme.withAlpha(_surfaceContainer, _backgroundAlpha) + readonly property real _dpr: CompositorService.getScreenScale(barWindow.screen) + + property string screenName: modelData.name + readonly property int notificationCount: NotificationService.notifications.length + readonly property real effectiveBarThickness: Math.max(barWindow.widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + readonly property real widgetThickness: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6) + + screen: modelData + implicitHeight: !isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0 + implicitWidth: isVertical ? Theme.px(effectiveBarThickness + SettingsData.dankBarSpacing + (SettingsData.dankBarGothCornersEnabled ? _wingR : 0), _dpr) : 0 + color: "transparent" + + property var nativeInhibitor: null + + Component.onCompleted: { + if (SettingsData.forceStatusBarLayoutRefresh) { + SettingsData.forceStatusBarLayoutRefresh.connect(() => { + Qt.callLater(() => { + stackContainer.visible = false + Qt.callLater(() => { + stackContainer.visible = true + }) + }) + }) + } + + updateGpuTempConfig() + + inhibitorInitTimer.start() + } + + Timer { + id: inhibitorInitTimer + interval: 300 + repeat: false + onTriggered: { + if (SessionService.nativeInhibitorAvailable) { + createNativeInhibitor() + } + } + } + + Connections { + target: PluginService + function onPluginLoaded(pluginId) { + console.info("DankBar: Plugin loaded:", pluginId) + SettingsData.widgetDataChanged() + } + function onPluginUnloaded(pluginId) { + console.info("DankBar: Plugin unloaded:", pluginId) + SettingsData.widgetDataChanged() + } + } + + function updateGpuTempConfig() { + const allWidgets = [...(SettingsData.dankBarLeftWidgets || []), ...(SettingsData.dankBarCenterWidgets || []), ...(SettingsData.dankBarRightWidgets || [])] + + const hasGpuTempWidget = allWidgets.some(widget => { + const widgetId = typeof widget === "string" ? widget : widget.id + const widgetEnabled = typeof widget === "string" ? true : (widget.enabled !== false) + return widgetId === "gpuTemp" && widgetEnabled + }) + + DgopService.gpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled || SessionData.nonNvidiaGpuTempEnabled + DgopService.nvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nvidiaGpuTempEnabled + DgopService.nonNvidiaGpuTempEnabled = hasGpuTempWidget || SessionData.nonNvidiaGpuTempEnabled + } + + function createNativeInhibitor() { + if (!SessionService.nativeInhibitorAvailable) { + return + } + + try { + const qmlString = ` + import QtQuick + import Quickshell.Wayland + + IdleInhibitor { + enabled: false + } + ` + + nativeInhibitor = Qt.createQmlObject(qmlString, barWindow, "DankBar.NativeInhibitor") + nativeInhibitor.window = barWindow + nativeInhibitor.enabled = Qt.binding(() => SessionService.idleInhibited) + nativeInhibitor.enabledChanged.connect(function () { + console.log("DankBar: Native inhibitor enabled changed to:", nativeInhibitor.enabled) + if (SessionService.idleInhibited !== nativeInhibitor.enabled) { + SessionService.idleInhibited = nativeInhibitor.enabled + SessionService.inhibitorChanged() + } + }) + console.log("DankBar: Created native Wayland IdleInhibitor for", barWindow.screenName) + } catch (e) { + console.warn("DankBar: Failed to create native IdleInhibitor:", e) + nativeInhibitor = null + } + } + + Connections { + function onDankBarLeftWidgetsChanged() { + barWindow.updateGpuTempConfig() + } + + function onDankBarCenterWidgetsChanged() { + barWindow.updateGpuTempConfig() + } + + function onDankBarRightWidgetsChanged() { + barWindow.updateGpuTempConfig() + } + + target: SettingsData + } + + Connections { + function onNvidiaGpuTempEnabledChanged() { + barWindow.updateGpuTempConfig() + } + + function onNonNvidiaGpuTempEnabledChanged() { + barWindow.updateGpuTempConfig() + } + + target: SessionData + } + + Connections { + target: barWindow.screen + function onGeometryChanged() { + Qt.callLater(forceWidgetRefresh) + } + } + + Timer { + id: refreshTimer + interval: 0 + running: false + repeat: false + onTriggered: { + forceWidgetRefresh() + } + } + + Connections { + target: axis + function onChanged() { + Qt.application.active + refreshTimer.restart() + } + } + + anchors.top: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Top) : true + anchors.bottom: !isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom) : true + anchors.left: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Left) + anchors.right: !isVertical ? true : (SettingsData.dankBarPosition === SettingsData.Position.Right) + + exclusiveZone: (!SettingsData.dankBarVisible || topBarCore.autoHide) ? -1 : (barWindow.effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap) + + Item { + id: inputMask + + readonly property int barThickness: Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) + + readonly property bool inOverviewWithShow: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview + readonly property bool effectiveVisible: SettingsData.dankBarVisible || inOverviewWithShow + readonly property bool showing: effectiveVisible && (topBarCore.reveal || inOverviewWithShow || !topBarCore.autoHide) + + readonly property int maskThickness: showing ? barThickness : 1 + + x: { + if (!axis.isVertical) { + return 0 + } else { + switch (SettingsData.dankBarPosition) { + case SettingsData.Position.Left: + return 0 + case SettingsData.Position.Right: + return parent.width - maskThickness + default: + return 0 + } + } + } + y: { + if (axis.isVertical) { + return 0 + } else { + switch (SettingsData.dankBarPosition) { + case SettingsData.Position.Top: + return 0 + case SettingsData.Position.Bottom: + return parent.height - maskThickness + default: + return 0 + } + } + } + width: axis.isVertical ? maskThickness : parent.width + height: axis.isVertical ? parent.height : maskThickness + } + + mask: Region { + item: inputMask + } + + Item { + id: topBarCore + anchors.fill: parent + layer.enabled: true + + property real backgroundTransparency: SettingsData.dankBarTransparency + property bool autoHide: SettingsData.dankBarAutoHide + property bool revealSticky: false + + Timer { + id: revealHold + interval: SettingsData.dankBarAutoHideDelay + repeat: false + onTriggered: topBarCore.revealSticky = false + } + + property bool reveal: { + if (CompositorService.isNiri && NiriService.inOverview) { + return SettingsData.dankBarOpenOnOverview || topBarMouseArea.containsMouse || hasActivePopout || revealSticky + } + return SettingsData.dankBarVisible && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky) + } + + readonly property bool hasActivePopout: { + const loaders = [{ + "loader": appDrawerLoader, + "prop": "shouldBeVisible" + }, { + "loader": dankDashPopoutLoader, + "prop": "shouldBeVisible" + }, { + "loader": processListPopoutLoader, + "prop": "shouldBeVisible" + }, { + "loader": notificationCenterLoader, + "prop": "shouldBeVisible" + }, { + "loader": batteryPopoutLoader, + "prop": "shouldBeVisible" + }, { + "loader": layoutPopoutLoader, + "prop": "shouldBeVisible" + }, { + "loader": vpnPopoutLoader, + "prop": "shouldBeVisible" + }, { + "loader": controlCenterLoader, + "prop": "shouldBeVisible" + }, { + "loader": clipboardHistoryModalPopup, + "prop": "visible" + }, { + "loader": systemUpdateLoader, + "prop": "shouldBeVisible" + }] + return loaders.some(item => { + if (item.loader && item.loader.item) { + return item.loader.item[item.prop] + } + return false + }) || rootWindow.systemTrayMenuOpen + } + + Connections { + function onDankBarTransparencyChanged() { + topBarCore.backgroundTransparency = SettingsData.dankBarTransparency + } + + target: SettingsData + } + + Connections { + target: topBarMouseArea + function onContainsMouseChanged() { + if (topBarMouseArea.containsMouse) { + topBarCore.revealSticky = true + revealHold.stop() + } else { + if (topBarCore.autoHide && !topBarCore.hasActivePopout) { + revealHold.restart() + } + } + } + } + + onHasActivePopoutChanged: { + if (hasActivePopout) { + revealSticky = true + revealHold.stop() + } else if (autoHide && !topBarMouseArea.containsMouse) { + revealSticky = true + revealHold.restart() + } + } + + MouseArea { + id: topBarMouseArea + y: !barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? parent.height - height : 0) : 0 + x: barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.width - width : 0) : 0 + height: !barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined + width: barWindow.isVertical ? Theme.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing, barWindow._dpr) : undefined + anchors { + left: !barWindow.isVertical ? parent.left : (SettingsData.dankBarPosition === SettingsData.Position.Left ? parent.left : undefined) + right: !barWindow.isVertical ? parent.right : (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.right : undefined) + top: barWindow.isVertical ? parent.top : undefined + bottom: barWindow.isVertical ? parent.bottom : undefined + } + readonly property bool inOverview: CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview + hoverEnabled: SettingsData.dankBarAutoHide && !topBarCore.reveal && !inOverview + acceptedButtons: Qt.NoButton + enabled: SettingsData.dankBarAutoHide && !topBarCore.reveal && !inOverview + + Item { + id: topBarContainer + anchors.fill: parent + + transform: Translate { + id: topBarSlide + x: barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Right ? barWindow.implicitWidth : -barWindow.implicitWidth), barWindow._dpr) : 0 + y: !barWindow.isVertical ? Theme.snap(topBarCore.reveal ? 0 : (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? barWindow.implicitHeight : -barWindow.implicitHeight), barWindow._dpr) : 0 + + Behavior on x { + NumberAnimation { + duration: Theme.shortDuration + easing.type: Easing.OutCubic + } + } + + Behavior on y { + NumberAnimation { + duration: Theme.shortDuration + easing.type: Easing.OutCubic + } + } + } + + Item { + id: barUnitInset + anchors.fill: parent + anchors.leftMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "left" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0) + anchors.rightMargin: !barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.edge === "right" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0) + anchors.topMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? 0 : Theme.px(SettingsData.dankBarSpacing, barWindow._dpr)) + anchors.bottomMargin: barWindow.isVertical ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : (axis.outerVisualEdge() === "bottom" ? Theme.px(SettingsData.dankBarSpacing, barWindow._dpr) : 0) + + BarCanvas { + id: barBackground + barWindow: barWindow + axis: axis + } + + MouseArea { + id: scrollArea + anchors.fill: parent + acceptedButtons: Qt.NoButton + propagateComposedEvents: true + z: -1 + + property real scrollAccumulator: 0 + property real touchpadThreshold: 500 + property bool actionInProgress: false + + Timer { + id: cooldownTimer + interval: 100 + onTriggered: parent.actionInProgress = false + } + + onWheel: wheel => { + if (actionInProgress) { + wheel.accepted = false + return + } + + const deltaY = wheel.angleDelta.y + const deltaX = wheel.angleDelta.x + + if (CompositorService.isNiri && Math.abs(deltaX) > Math.abs(deltaY)) { + topBarContent.switchApp(deltaX) + wheel.accepted = false + return + } + + const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0 + const direction = deltaY < 0 ? 1 : -1 + + if (isMouseWheel) { + topBarContent.switchWorkspace(direction) + actionInProgress = true + cooldownTimer.restart() + } else { + scrollAccumulator += deltaY + + if (Math.abs(scrollAccumulator) >= touchpadThreshold) { + const touchDirection = scrollAccumulator < 0 ? 1 : -1 + topBarContent.switchWorkspace(touchDirection) + scrollAccumulator = 0 + actionInProgress = true + cooldownTimer.restart() + } + } + + wheel.accepted = false + } + } + + DankBarContent { + id: topBarContent + barWindow: barWindow + rootWindow: rootWindow + } + } + } + } + } +} diff --git a/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml b/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml index 513de728..c5377c3d 100644 --- a/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml +++ b/quickshell/Modules/DankBar/Widgets/SystemTrayBar.qml @@ -505,11 +505,6 @@ Item { } function updatePosition() { - if (!root.parentWindow) { - anchorPos = Qt.point(screen.width / 2, screen.height / 2) - return - } - const globalPos = root.mapToGlobal(0, 0) const screenX = screen.x || 0 const screenY = screen.y || 0 @@ -958,12 +953,8 @@ Item { } function updatePosition() { - if (!root.parentWindow) { - anchorPos = Qt.point(screen.width / 2, screen.height / 2) - return - } - - const globalPos = root.mapToGlobal(0, 0) + const targetItem = (typeof menuRoot !== "undefined" && menuRoot.anchorItem) ? menuRoot.anchorItem : root + const globalPos = targetItem.mapToGlobal(0, 0) const screenX = screen.x || 0 const screenY = screen.y || 0 const relativeX = globalPos.x - screenX @@ -977,12 +968,12 @@ Item { let targetX = edge === "left" ? effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance : screen.width - (effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance) - anchorPos = Qt.point(targetX, relativeY + root.height / 2) + anchorPos = Qt.point(targetX, relativeY + targetItem.height / 2) } else { let targetY = root.isAtBottom ? screen.height - (effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap + Theme.popupDistance) : effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap + Theme.popupDistance - anchorPos = Qt.point(relativeX + root.width / 2, targetY) + anchorPos = Qt.point(relativeX + targetItem.width / 2, targetY) } }