111 lines
3.5 KiB
QML
111 lines
3.5 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Hyprland
|
|
import Quickshell.Io
|
|
|
|
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: root.refreshSortedDesktopApplications()
|
|
}
|
|
|
|
function refreshSortedDesktopApplications() {
|
|
if (!Hyprland.toplevels)
|
|
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";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|