diff --git a/Modules/DankBar/Widgets/WorkspaceSwitcher.qml b/Modules/DankBar/Widgets/WorkspaceSwitcher.qml index de25a5d5..b1805283 100644 --- a/Modules/DankBar/Widgets/WorkspaceSwitcher.qml +++ b/Modules/DankBar/Widgets/WorkspaceSwitcher.qml @@ -293,19 +293,30 @@ Rectangle { property bool isHovered: mouseArea.containsMouse property var loadedWorkspaceData: null + property bool loadedIsUrgent: false + property bool isUrgent: { + if (CompositorService.isHyprland) { + return modelData?.urgent ?? false + } + if (CompositorService.isNiri) { + return loadedIsUrgent + } + return false + } property var loadedIconData: null property bool loadedHasIcon: false property var loadedIcons: [] Timer { id: dataUpdateTimer - interval: 50 // Defer data calculation by 50ms + interval: 50 onTriggered: { if (isPlaceholder) { delegateRoot.loadedWorkspaceData = null delegateRoot.loadedIconData = null delegateRoot.loadedHasIcon = false delegateRoot.loadedIcons = [] + delegateRoot.loadedIsUrgent = false return } @@ -316,6 +327,7 @@ Rectangle { wsData = modelData; } delegateRoot.loadedWorkspaceData = wsData; + delegateRoot.loadedIsUrgent = wsData?.is_urgent ?? false; var icData = null; if (wsData?.name) { @@ -363,7 +375,10 @@ Rectangle { } } radius: Math.min(width, height) / 2 - color: isActive ? Theme.primary : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.outlineButton : Theme.surfaceTextAlpha + color: isActive ? Theme.primary : isUrgent ? Theme.error : isPlaceholder ? Theme.surfaceTextLight : isHovered ? Theme.outlineButton : Theme.surfaceTextAlpha + + border.width: isUrgent && !isActive ? 2 : 0 + border.color: isUrgent && !isActive ? Theme.error : Theme.withAlpha(Theme.error, 0) Behavior on width { enabled: (!SettingsData.showWorkspaceApps || SettingsData.maxWorkspaceIcons <= 3) @@ -381,6 +396,20 @@ Rectangle { } } + Behavior on color { + ColorAnimation { + duration: Theme.mediumDuration + easing.type: Theme.emphasizedEasing + } + } + + Behavior on border.width { + NumberAnimation { + duration: Theme.shortDuration + easing.type: Theme.emphasizedEasing + } + } + MouseArea { id: mouseArea @@ -619,6 +648,7 @@ Rectangle { target: NiriService enabled: CompositorService.isNiri function onAllWorkspacesChanged() { delegateRoot.updateAllData() } + function onWindowUrgentChanged() { delegateRoot.updateAllData() } } Connections { target: SettingsData diff --git a/Services/NiriService.qml b/Services/NiriService.qml index 56ca37de..071b9506 100644 --- a/Services/NiriService.qml +++ b/Services/NiriService.qml @@ -23,6 +23,8 @@ Singleton { property var windows: [] + signal windowUrgentChanged() + property bool inOverview: false property int currentKeyboardLayoutIndex: 0 @@ -189,6 +191,9 @@ Singleton { case 'KeyboardLayoutSwitched': handleKeyboardLayoutSwitched(event.KeyboardLayoutSwitched); break; + case 'WorkspaceUrgencyChanged': + handleWorkspaceUrgencyChanged(event.WorkspaceUrgencyChanged); + break; } } @@ -373,6 +378,22 @@ Singleton { currentKeyboardLayoutIndex = data.idx } + function handleWorkspaceUrgencyChanged(data) { + const ws = root.workspaces[data.id] + if (!ws) { + return + } + + ws.is_urgent = data.urgent + + const idx = allWorkspaces.findIndex(w => w.id === data.id) + if (idx >= 0) { + allWorkspaces[idx].is_urgent = data.urgent + } + + windowUrgentChanged() + } + Process { id: validateProcess command: ["niri", "validate"]