pragma Singleton import QtQuick import Quickshell import Quickshell.Hyprland import Quickshell.Wayland import Quickshell.Io import qs.Common Singleton { id: root readonly property string hyprlandSignature: Quickshell.env("HYPRLAND_INSTANCE_SIGNATURE") readonly property var focusedMon: Hyprland.focusedMonitor property bool hasFullscreen: false property bool isScreencasting: false property ListModel sortedDesktopApplicationsModel: ListModel {} // Derived property of sorted toplevels property var sortedTopLevels: { const topLevels = Array.from(Hyprland.toplevels?.values ?? []); const sorted = topLevels.sort((a, b) => { if (a.monitor && b.monitor) { const monitorCompare = a.monitor.name.localeCompare(b.monitor.name); if (monitorCompare !== 0) return monitorCompare; } if (a.workspace && b.workspace) { const workspaceCompare = a.workspace.id - b.workspace.id; if (workspaceCompare !== 0) return workspaceCompare; } if (a.lastIpcObject?.at && b.lastIpcObject?.at) { const xCompare = a.lastIpcObject.at[0] - b.lastIpcObject.at[0]; if (Math.abs(xCompare) > 10) return xCompare; return a.lastIpcObject.at[1] - b.lastIpcObject.at[1]; } if (a.title && b.title) return a.title.localeCompare(b.title); return 0; }); return sorted.filter(tl => tl.wayland !== null); } property var topLevelWorkspaces: { return sortedTopLevels.map(toplevel => toplevel.workspace); } onSortedTopLevelsChanged: refreshSortedDesktopApplications() Timer { id: retryTimer interval: 300 repeat: false onTriggered: refreshSortedDesktopApplications() } function refreshSortedDesktopApplications() { if (!Hyprland.toplevels || Hyprland.toplevels.size === 0) return; try { sortedDesktopApplicationsModel.clear(); for (const topLevel of sortedTopLevels) { const entry = DesktopEntries.heuristicLookup(topLevel.wayland.appId); if (!entry) { retryTimer.restart(); return; } sortedDesktopApplicationsModel.append({ topLevel: topLevel, desktopEntry: entry }); } } catch (err) { retryTimer.restart(); } } function workspaceApps(workspaceIndexAlign) { const list = []; for (let i = 0; i < sortedDesktopApplicationsModel.count; i++) { const item = sortedDesktopApplicationsModel.get(i); if (item.topLevel.workspace.id === workspaceIndexAlign) list.push(item.desktopEntry); } return list; } // Hyprland socket listener Socket { path: `${Quickshell.env("XDG_RUNTIME_DIR")}/hypr/${root.hyprlandSignature}/.socket2.sock` connected: true parser: SplitParser { property var fullscreenRegex: /fullscreen>>./ property var screencastRegex: /screencast>>.*/ onRead: msg => { if (fullscreenRegex.test(msg)) { root.hasFullscreen = msg.split(">>")[1] === "1"; } if (screencastRegex.test(msg)) { root.isScreencasting = msg.split(">>")[1].split(',')[0] === "1"; } } } } }