1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-29 16:02:51 -05:00

feat: add configurable per-monitor workspace filtering and system tray monitor selection (#163)

This commit is contained in:
Kyle Moore
2025-09-05 15:36:23 -04:00
committed by GitHub
parent 18484bb9cc
commit 68157ca636
6 changed files with 98 additions and 19 deletions

View File

@@ -50,6 +50,10 @@ Singleton {
function moddedAppId(appId: string): string { function moddedAppId(appId: string): string {
if (appId === "Spotify") if (appId === "Spotify")
return "spotify-launcher" return "spotify-launcher"
if (appId === "beepertexts")
return "beeper"
if (appId === "home assistant desktop")
return "homeassistant-desktop"
return appId return appId
} }
} }

View File

@@ -48,6 +48,7 @@ Singleton {
property bool showWorkspacePadding: false property bool showWorkspacePadding: false
property bool showWorkspaceApps: false property bool showWorkspaceApps: false
property int maxWorkspaceIcons: 3 property int maxWorkspaceIcons: 3
property bool workspacesPerMonitor: true
property var workspaceNameIcons: ({}) property var workspaceNameIcons: ({})
property bool clockCompactMode: false property bool clockCompactMode: false
property bool focusedWindowCompactMode: false property bool focusedWindowCompactMode: false
@@ -199,6 +200,7 @@ Singleton {
showWorkspaceApps = settings.showWorkspaceApps !== undefined ? settings.showWorkspaceApps : false showWorkspaceApps = settings.showWorkspaceApps !== undefined ? settings.showWorkspaceApps : false
maxWorkspaceIcons = settings.maxWorkspaceIcons !== undefined ? settings.maxWorkspaceIcons : 3 maxWorkspaceIcons = settings.maxWorkspaceIcons !== undefined ? settings.maxWorkspaceIcons : 3
workspaceNameIcons = settings.workspaceNameIcons !== undefined ? settings.workspaceNameIcons : ({}) workspaceNameIcons = settings.workspaceNameIcons !== undefined ? settings.workspaceNameIcons : ({})
workspacesPerMonitor = settings.workspacesPerMonitor !== undefined ? settings.workspacesPerMonitor : true
clockCompactMode = settings.clockCompactMode !== undefined ? settings.clockCompactMode : false clockCompactMode = settings.clockCompactMode !== undefined ? settings.clockCompactMode : false
focusedWindowCompactMode = settings.focusedWindowCompactMode !== undefined ? settings.focusedWindowCompactMode : false focusedWindowCompactMode = settings.focusedWindowCompactMode !== undefined ? settings.focusedWindowCompactMode : false
runningAppsCompactMode = settings.runningAppsCompactMode !== undefined ? settings.runningAppsCompactMode : true runningAppsCompactMode = settings.runningAppsCompactMode !== undefined ? settings.runningAppsCompactMode : true
@@ -307,6 +309,8 @@ Singleton {
"showWorkspaceIndex": showWorkspaceIndex, "showWorkspaceIndex": showWorkspaceIndex,
"showWorkspacePadding": showWorkspacePadding, "showWorkspacePadding": showWorkspacePadding,
"showWorkspaceApps": showWorkspaceApps, "showWorkspaceApps": showWorkspaceApps,
"maxWorkspaceIcons": maxWorkspaceIcons,
"workspacesPerMonitor": workspacesPerMonitor,
"workspaceNameIcons": workspaceNameIcons, "workspaceNameIcons": workspaceNameIcons,
"clockCompactMode": clockCompactMode, "clockCompactMode": clockCompactMode,
"focusedWindowCompactMode": focusedWindowCompactMode, "focusedWindowCompactMode": focusedWindowCompactMode,
@@ -370,6 +374,11 @@ Singleton {
saveSettings() saveSettings()
} }
function setWorkspacesPerMonitor(enabled) {
workspacesPerMonitor = enabled
saveSettings()
}
function setWorkspaceNameIcon(workspaceName, iconData) { function setWorkspaceNameIcon(workspaceName, iconData) {
var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons)) var iconMap = JSON.parse(JSON.stringify(workspaceNameIcons))
iconMap[workspaceName] = iconData iconMap[workspaceName] = iconData

View File

@@ -44,6 +44,11 @@ Item {
"name": "Notepad Slideout", "name": "Notepad Slideout",
"description": "Quick note-taking slideout panel", "description": "Quick note-taking slideout panel",
"icon": "sticky_note_2" "icon": "sticky_note_2"
}, {
"id": "systemTray",
"name": "System Tray",
"description": "System tray icons",
"icon": "notifications"
}] }]
function getScreenPreferences(componentId) { function getScreenPreferences(componentId) {

View File

@@ -284,6 +284,16 @@ Item {
} }
} }
} }
DankToggle {
width: parent.width
text: "Per-Monitor Workspaces"
description: "Show only workspaces belonging to each specific monitor."
checked: SettingsData.workspacesPerMonitor
onToggled: checked => {
return SettingsData.setWorkspacesPerMonitor(checked);
}
}
} }
} }

View File

@@ -729,6 +729,7 @@ PanelWindow {
parentWindow: root parentWindow: root
parentScreen: root.screen parentScreen: root.screen
widgetHeight: root.widgetHeight widgetHeight: root.widgetHeight
visible: SettingsData.getFilteredScreens("systemTray").includes(root.screen)
} }
} }

View File

@@ -16,7 +16,7 @@ Rectangle {
if (CompositorService.isNiri) { if (CompositorService.isNiri) {
return getNiriActiveWorkspace() return getNiriActiveWorkspace()
} else if (CompositorService.isHyprland) { } else if (CompositorService.isHyprland) {
return Hyprland.focusedWorkspace ? Hyprland.focusedWorkspace.id : 1 return getHyprlandActiveWorkspace()
} }
return 1 return 1
} }
@@ -26,15 +26,8 @@ Rectangle {
return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList
} }
if (CompositorService.isHyprland) { if (CompositorService.isHyprland) {
const workspaces = Hyprland.workspaces?.values || [] const baseList = getHyprlandWorkspaces()
if (workspaces.length === 0) { return SettingsData.showWorkspacePadding ? padWorkspaces(baseList) : baseList
return [{
"id": 1,
"name": "1"
}]
}
const sorted = workspaces.slice().sort((a, b) => a.id - b.id)
return SettingsData.showWorkspacePadding ? padWorkspaces(sorted) : sorted
} }
return [1] return [1]
} }
@@ -61,7 +54,8 @@ Rectangle {
return [] return []
} }
const wins = CompositorService.isNiri ? (NiriService.windows || []) : (Hyprland.clients?.values || []) const wins = CompositorService.isNiri ? (NiriService.windows || []) : CompositorService.sortedToplevels
const byApp = {} const byApp = {}
const isActiveWs = CompositorService.isNiri ? NiriService.allWorkspaces.some(ws => ws.id === targetWorkspaceId && ws.is_active) : targetWorkspaceId === root.currentWorkspace const isActiveWs = CompositorService.isNiri ? NiriService.allWorkspaces.some(ws => ws.id === targetWorkspaceId && ws.is_active) : targetWorkspaceId === root.currentWorkspace
@@ -71,13 +65,22 @@ Rectangle {
return return
} }
const winWs = CompositorService.isNiri ? w.workspace_id : (w.workspace?.id ?? w.workspaceId) let winWs = null
if (CompositorService.isNiri) {
winWs = w.workspace_id
} else {
// For Hyprland, we need to find the corresponding Hyprland toplevel to get workspace
const hyprlandToplevels = Array.from(Hyprland.toplevels?.values || [])
const hyprToplevel = hyprlandToplevels.find(ht => ht.wayland === w)
winWs = hyprToplevel?.workspace?.id
}
if (winWs === undefined || winWs === null || winWs !== targetWorkspaceId) { if (winWs === undefined || winWs === null || winWs !== targetWorkspaceId) {
return return
} }
const keyBase = (w.app_id || w.appId || w.class || w.windowClass || w.exe || "unknown").toLowerCase() const keyBase = (w.appId || w.class || w.windowClass || "unknown").toLowerCase()
const key = isActiveWs ? `${keyBase}_${i}` : keyBase const key = isActiveWs ? `${keyBase}_${i}` : keyBase
if (!byApp[key]) { if (!byApp[key]) {
@@ -85,14 +88,14 @@ Rectangle {
byApp[key] = { byApp[key] = {
"type": "icon", "type": "icon",
"icon": icon, "icon": icon,
"active": !!(w.is_focused || w.activated), "active": !!(w.activated || (CompositorService.isNiri && w.is_focused)),
"count": 1, "count": 1,
"windowId": w.id || w.address, "windowId": w.address || w.id,
"fallbackText": w.app_id || w.appId || w.class || w.title || "" "fallbackText": w.appId || w.class || w.title || ""
} }
} else { } else {
byApp[key].count++ byApp[key].count++
if (w.is_focused || w.activated) { if (w.activated || (CompositorService.isNiri && w.is_focused)) {
byApp[key].active = true byApp[key].active = true
} }
} }
@@ -118,7 +121,7 @@ Rectangle {
return [1, 2] return [1, 2]
} }
if (!root.screenName) { if (!root.screenName || !SettingsData.workspacesPerMonitor) {
return NiriService.getCurrentOutputWorkspaceNumbers() return NiriService.getCurrentOutputWorkspaceNumbers()
} }
@@ -131,7 +134,7 @@ Rectangle {
return 1 return 1
} }
if (!root.screenName) { if (!root.screenName || !SettingsData.workspacesPerMonitor) {
return NiriService.getCurrentWorkspaceNumber() return NiriService.getCurrentWorkspaceNumber()
} }
@@ -139,6 +142,53 @@ Rectangle {
return activeWs ? activeWs.idx + 1 : 1 return activeWs ? activeWs.idx + 1 : 1
} }
function getHyprlandWorkspaces() {
const workspaces = Hyprland.workspaces?.values || []
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
// Show all workspaces on all monitors if per-monitor filtering is disabled
const sorted = workspaces.slice().sort((a, b) => a.id - b.id)
return sorted.length > 0 ? sorted : [{
"id": 1,
"name": "1"
}]
}
// Filter workspaces for this specific monitor using lastIpcObject.monitor
// This matches the approach from the original kyle-config
const monitorWorkspaces = workspaces.filter(ws => {
return ws.lastIpcObject && ws.lastIpcObject.monitor === root.screenName
})
if (monitorWorkspaces.length === 0) {
// Fallback if no workspaces exist for this monitor
return [{
"id": 1,
"name": "1"
}]
}
// Return all workspaces for this monitor, sorted by ID
return monitorWorkspaces.sort((a, b) => a.id - b.id)
}
function getHyprlandActiveWorkspace() {
if (!root.screenName || !SettingsData.workspacesPerMonitor) {
return Hyprland.focusedWorkspace ? Hyprland.focusedWorkspace.id : 1
}
// Find the monitor object for this screen
const monitors = Hyprland.monitors?.values || []
const currentMonitor = monitors.find(monitor => monitor.name === root.screenName)
if (!currentMonitor) {
return 1
}
// Use the monitor's active workspace ID (like original config)
return currentMonitor.activeWorkspace?.id ?? 1
}
readonly property real padding: (widgetHeight - workspaceRow.implicitHeight) / 2 readonly property real padding: (widgetHeight - workspaceRow.implicitHeight) / 2
function getRealWorkspaces() { function getRealWorkspaces() {