Taskbar: Filter by same output and active workspaces.

This commit is contained in:
Leopold Luley
2025-09-28 15:34:49 +02:00
parent 49961882dd
commit e6b0be77e7
4 changed files with 133 additions and 17 deletions
+8 -7
View File
@@ -41,12 +41,13 @@ Rectangle {
columnSpacing: isVerticalBar ? 0 : Style.marginXXS * root.scaling
Repeater {
model: ToplevelManager && ToplevelManager.toplevels ? ToplevelManager.toplevels : []
model: CompositorService.windows
delegate: Item {
id: taskbarItem
required property Toplevel modelData
property Toplevel toplevel: modelData
property bool isActive: ToplevelManager.activeToplevel === modelData
required property var modelData
// TODO: Make this configurable
visible: modelData.output == screen.name && CompositorService.getActiveWorkspaces().map(ws => ws.id).includes(modelData.workspaceId)
Layout.preferredWidth: root.itemSize
Layout.preferredHeight: root.itemSize
@@ -57,7 +58,7 @@ Rectangle {
anchors.centerIn: parent
width: parent.width
height: parent.height
color: taskbarItem.isActive ? Color.mPrimary : root.color
color: modelData.isFocused ? Color.mPrimary : root.color
border.width: 0
radius: Math.round(Style.radiusXS * root.scaling)
border.color: Color.transparent
@@ -86,13 +87,13 @@ Rectangle {
if (mouse.button === Qt.LeftButton) {
try {
taskbarItem.modelData.activate()
CompositorService.focusWindow(taskbarItem.modelData.id)
} catch (error) {
Logger.error("Taskbar", "Failed to activate toplevel: " + error)
}
} else if (mouse.button === Qt.RightButton) {
try {
taskbarItem.modelData.close()
CompositorService.closeWindow(taskbarItem.modelData.id)
} catch (error) {
Logger.error("Taskbar", "Failed to close toplevel: " + error)
}
+53 -6
View File
@@ -14,7 +14,7 @@ Singleton {
// Generic workspace and window data
property ListModel workspaces: ListModel {}
property var windows: []
property ListModel windows: ListModel {}
property int focusedWindowIndex: -1
// Generic events
@@ -82,10 +82,17 @@ Singleton {
workspaceChanged()
})
backend.activeWindowChanged.connect(activeWindowChanged)
backend.activeWindowChanged.connect(() => {
// Sync active window when it changes
// TODO: Avoid re-syncing all windows
syncWindows()
// Forward the signal
activeWindowChanged()
})
backend.windowListChanged.connect(() => {
// Sync windows when they change
windows = backend.windows
syncWindows()
// Forward the signal
windowListChanged()
})
@@ -97,7 +104,7 @@ Singleton {
// Initial sync
syncWorkspaces()
windows = backend.windows
syncWindows()
focusedWindowIndex = backend.focusedWindowIndex
}
@@ -110,10 +117,20 @@ Singleton {
// Emit signal to notify listeners that workspace list has been updated
workspacesChanged()
}
function syncWindows() {
windows.clear()
const ws = backend.windows
for (var i = 0; i < ws.length; i++) {
windows.append(ws[i])
}
// Emit signal to notify listeners that workspace list has been updated
windowListChanged()
}
// Get window title for focused window
function getFocusedWindowTitle() {
if (focusedWindowIndex >= 0 && focusedWindowIndex < windows.length) {
if (focusedWindowIndex >= 0 && focusedWindowIndex < windows.count) {
return windows[focusedWindowIndex].title || ""
}
return ""
@@ -138,14 +155,44 @@ Singleton {
}
return null
}
// Get active workspaces
function getActiveWorkspaces() {
const activeWorkspaces = []
for (var i = 0; i < workspaces.count; i++) {
const ws = workspaces.get(i)
if (ws.isActive) {
activeWorkspaces.push(ws)
}
}
return activeWorkspaces
}
// Set focused window
function focusWindow(windowId) {
if (backend && backend.focusWindow) {
backend.focusWindow(windowId)
} else {
Logger.warn("Compositor", "No backend available for window focus")
}
}
// Get focused window
function getFocusedWindow() {
if (focusedWindowIndex >= 0 && focusedWindowIndex < windows.length) {
if (focusedWindowIndex >= 0 && focusedWindowIndex < windows.count) {
return windows[focusedWindowIndex]
}
return null
}
// Close window
function closeWindow(windowId) {
if (backend && backend.closeWindow) {
backend.closeWindow(windowId)
} else {
Logger.warn("Compositor", "No backend available for window closing")
}
}
// Session management
function logout() {
+16
View File
@@ -277,6 +277,22 @@ Item {
Logger.error("HyprlandService", "Failed to switch workspace:", e)
}
}
function focusWindow(windowId) {
try {
Hyprland.dispatch(`focuswindow ${windowId}`)
} catch (e) {
Logger.error("HyprlandService", "Failed to switch window:", e)
}
}
function closeWindow(windowId) {
try {
Hyprland.dispatch(`killwindow ${windowId}`)
} catch (e) {
Logger.error("HyprlandService", "Failed to close window:", e)
}
}
function logout() {
try {
+56 -4
View File
@@ -94,12 +94,21 @@ Item {
const windowsList = []
for (const win of windowsData) {
var output = null
for (var i = 0; i < workspaces.count; i++) {
if (workspaces.get(i).id === win.workspace_id) {
output = workspaces.get(i).output
break
}
}
windowsList.push({
"id": win.id,
"title": win.title || "",
"appId": win.app_id || "",
"workspaceId": win.workspace_id || null,
"isFocused": win.is_focused === true
"isFocused": win.is_focused === true,
"output": output
})
}
@@ -161,13 +170,22 @@ Item {
try {
const windowData = eventData.window
const existingIndex = windows.findIndex(w => w.id === windowData.id)
var output = null
for (var i = 0; i < workspaces.count; i++) {
if (workspaces.get(i).id === windowData.workspace_id) {
output = workspaces.get(i).output
break
}
}
const newWindow = {
"id": windowData.id,
"title": windowData.title || "",
"appId": windowData.app_id || "",
"workspaceId": windowData.workspace_id || null,
"isFocused": windowData.is_focused === true
"isFocused": windowData.is_focused === true,
"output": output
}
if (existingIndex >= 0) {
@@ -226,15 +244,24 @@ Item {
const windowsList = []
for (const win of windowsData) {
var output = ""
for (var i = 0; i < workspaces.count; i++) {
if (workspaces.get(i).id === win.workspace_id) {
output = workspaces.get(i).output
break
}
}
windowsList.push({
"id": win.id,
"title": win.title || "",
"appId": win.app_id || "",
"workspaceId": win.workspace_id || null,
"isFocused": win.is_focused === true
"isFocused": win.is_focused === true,
"output": output,
})
}
windowsList.sort((a, b) => a.id - b.id)
windows = windowsList
windowListChanged()
@@ -257,9 +284,18 @@ Item {
function handleWindowFocusChanged(eventData) {
try {
const focusedId = eventData.id
if (windows[focusedWindowIndex]) {
windows[focusedWindowIndex].isFocused = false
}
if (focusedId) {
const newIndex = windows.findIndex(w => w.id === focusedId)
if (newIndex >= 0) {
windows[newIndex].isFocused = true
}
focusedWindowIndex = newIndex >= 0 ? newIndex : -1
} else {
focusedWindowIndex = -1
@@ -279,6 +315,22 @@ Item {
Logger.error("NiriService", "Failed to switch workspace:", e)
}
}
function focusWindow(windowId) {
try {
Quickshell.execDetached(["niri", "msg", "action", "focus-window", "--id", windowId.toString()])
} catch (e) {
Logger.error("NiriService", "Failed to switch window:", e)
}
}
function closeWindow(windowId) {
try {
Quickshell.execDetached(["niri", "msg", "action", "close-window", "--id", windowId.toString()])
} catch (e) {
Logger.error("NiriService", "Failed to close window:", e)
}
}
function logout() {
try {