blob: 040f4d4f3dbcea8c7a85a1ce669a5ef73f2538e8 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
// Copyright (C) 2026 Danilo M. <danix@danix.xyz>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
pragma Singleton
import Quickshell
import Quickshell.Hyprland
import QtQuick
// Everything that touches Hyprland lives here, so the filter, the sort and
// the dispatch syntax are in one place rather than spread across the UI.
Singleton {
id: root
// Hyprland.toplevels reads 0 until this is called.
function refresh() { Hyprland.refreshToplevels(); }
// Windows on a special: workspace are the scratchpad, which is reached by
// its own bind and is not something to tab to. Windows on other
// workspaces are kept whatever their visibility: jumping to another
// desktop is the point.
readonly property var windows: {
const out = [];
for (const t of Hyprland.toplevels.values) {
const ws = t.workspace;
if (!ws || String(ws.name).startsWith("special:")) continue;
out.push(t);
}
// Lowest focusHistoryID is the most recently used. HyprlandToplevel
// does not expose it as a property, only inside the raw hyprctl
// object, where a missing one sorts last rather than as 0.
out.sort((a, b) => root.focusOrder(a) - root.focusOrder(b));
return out;
}
function focusOrder(toplevel) {
const o = toplevel.lastIpcObject;
const n = o ? Number(o.focusHistoryID) : NaN;
return isNaN(n) ? Number.MAX_SAFE_INTEGER : n;
}
// Dispatch arguments are evaluated as Lua on Hyprland 0.56.2, so the
// documented-looking `focuswindow address:0x...` is a syntax error that
// fails silently. This form is the one that works.
//
// HyprlandToplevel.address has no 0x prefix, while the dispatch needs one.
function addressOf(toplevel) {
const a = String(toplevel.address);
return a.startsWith("0x") ? a : "0x" + a;
}
function focus(toplevel) {
Hyprland.dispatch(`hl.dsp.focus({ window = "address:${addressOf(toplevel)}" })`);
}
function closeWindow(toplevel) {
Hyprland.dispatch(`hl.dsp.window.close({ window = "address:${addressOf(toplevel)}" })`);
}
}
|