import QtQuick import QtQuick.Controls import Quickshell import Quickshell.Widgets import qs.Common import qs.Services import qs.Widgets Rectangle { id: root property string section: "left" property var parentScreen property var hoveredItem: null property var topBar: null // The visual root for this window property Item windowRoot: (Window.window ? Window.window.contentItem : null) readonly property int windowCount: NiriService.windows.length readonly property int calculatedWidth: windowCount > 0 ? windowCount * 24 + (windowCount - 1) * Theme.spacingXS + Theme.spacingS * 2 : 0 width: calculatedWidth height: 30 radius: Theme.cornerRadius visible: windowCount > 0 clip: false color: { if (windowCount === 0) return "transparent" const baseColor = Theme.secondaryHover return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency) } Row { id: windowRow anchors.centerIn: parent spacing: Theme.spacingXS Repeater { id: windowRepeater model: NiriService.windows delegate: Item { id: delegateItem property bool isFocused: String(modelData.id) === String(FocusedWindowService.focusedWindowId) property string appId: modelData.app_id || "" property string windowTitle: modelData.title || "(Unnamed)" property int windowId: modelData.id property string tooltipText: { var appName = "Unknown" if (appId) { var desktopEntry = DesktopEntries.byId(appId) appName = desktopEntry && desktopEntry.name ? desktopEntry.name : appId } return appName + (windowTitle ? " • " + windowTitle : "") } width: 24 height: 24 Rectangle { anchors.fill: parent radius: Theme.cornerRadius color: { if (isFocused) { return mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2) } else { return mouseArea.containsMouse ? Qt.rgba(Theme.primaryHover.r, Theme.primaryHover.g, Theme.primaryHover.b, 0.1) : "transparent" } } Behavior on color { ColorAnimation { duration: Theme.shortDuration easing.type: Theme.standardEasing } } } // App icon IconImage { id: iconImg anchors.centerIn: parent width: 18 height: 18 source: { if (!appId) return "" var desktopEntry = DesktopEntries.byId(appId) if (desktopEntry && desktopEntry.icon) { var iconPath = Quickshell.iconPath( desktopEntry.icon, SettingsData.iconTheme === "System Default" ? "" : SettingsData.iconTheme) return iconPath } return "" } smooth: true mipmap: true asynchronous: true visible: status === Image.Ready } // Fallback text if no icon found Text { anchors.centerIn: parent visible: !iconImg.visible text: { if (!appId) return "?" var desktopEntry = DesktopEntries.byId(appId) if (desktopEntry && desktopEntry.name) { return desktopEntry.name.charAt(0).toUpperCase() } return appId.charAt(0).toUpperCase() } font.pixelSize: 10 color: Theme.surfaceText font.weight: Font.Medium } MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: { NiriService.focusWindow(windowId) } onEntered: { root.hoveredItem = delegateItem var globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height) tooltipLoader.active = true if (tooltipLoader.item) { var tooltipY = Theme.barHeight + SettingsData.topBarSpacing + Theme.spacingXS tooltipLoader.item.showTooltip(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen) } } onExited: { if (root.hoveredItem === delegateItem) { root.hoveredItem = null if (tooltipLoader.item) { tooltipLoader.item.hideTooltip() } tooltipLoader.active = false } } } } } } Loader { id: tooltipLoader active: false sourceComponent: RunningAppsTooltip { } } }