/ services / Hyprland.qml
Hyprland.qml
  1  pragma Singleton
  2  
  3  import Quickshell
  4  import Quickshell.Io
  5  import Quickshell.Hyprland
  6  import QtQuick
  7  
  8  Singleton {
  9      id: root
 10  
 11      readonly property list<Client> clients: []
 12      readonly property var workspaces: Hyprland.workspaces
 13      readonly property var monitors: Hyprland.monitors
 14      property Client activeClient: null
 15      readonly property HyprlandWorkspace activeWorkspace: focusedMonitor?.activeWorkspace ?? null
 16      readonly property HyprlandMonitor focusedMonitor: Hyprland.focusedMonitor
 17      readonly property int activeWsId: activeWorkspace?.id ?? 1
 18      property point cursorPos
 19  
 20      function reload() {
 21          Hyprland.refreshWorkspaces();
 22          Hyprland.refreshMonitors();
 23          getClients.running = true;
 24          getActiveClient.running = true;
 25      }
 26  
 27      function dispatch(request: string): void {
 28          Hyprland.dispatch(request);
 29      }
 30  
 31      Component.onCompleted: reload()
 32  
 33      Connections {
 34          target: Hyprland
 35  
 36          function onRawEvent(event: HyprlandEvent): void {
 37              if (!event.name.endsWith("v2"))
 38                  root.reload();
 39          }
 40      }
 41  
 42      Process {
 43          id: getClients
 44          command: ["sh", "-c", "hyprctl -j clients | jq -c"]
 45          stdout: SplitParser {
 46              onRead: data => {
 47                  const clients = JSON.parse(data);
 48                  const rClients = root.clients;
 49  
 50                  const destroyed = rClients.filter(rc => !clients.find(c => c.address === rc.address));
 51                  for (const client of destroyed)
 52                      rClients.splice(rClients.indexOf(client), 1).forEach(c => c.destroy());
 53  
 54                  for (const client of clients) {
 55                      const match = rClients.find(c => c.address === client.address);
 56                      if (match) {
 57                          match.lastIpcObject = client;
 58                      } else {
 59                          rClients.push(clientComp.createObject(root, {
 60                              lastIpcObject: client
 61                          }));
 62                      }
 63                  }
 64              }
 65          }
 66      }
 67  
 68      Process {
 69          id: getActiveClient
 70          command: ["hyprctl", "-j", "activewindow"]
 71          stdout: SplitParser {
 72              splitMarker: ""
 73              onRead: data => {
 74                  const client = JSON.parse(data);
 75                  const rClient = root.activeClient;
 76                  if (client.address) {
 77                      if (rClient)
 78                          rClient.lastIpcObject = client;
 79                      else
 80                          root.activeClient = clientComp.createObject(root, {
 81                              lastIpcObject: client
 82                          });
 83                  } else if (rClient) {
 84                      rClient.destroy();
 85                      root.activeClient = null;
 86                  }
 87              }
 88          }
 89      }
 90  
 91      component Client: QtObject {
 92          required property var lastIpcObject
 93          readonly property string address: lastIpcObject.address
 94          readonly property string wmClass: lastIpcObject.class
 95          readonly property string title: lastIpcObject.title
 96          readonly property string initialClass: lastIpcObject.initialClass
 97          readonly property string initialTitle: lastIpcObject.initialTitle
 98          readonly property int x: lastIpcObject.at[0]
 99          readonly property int y: lastIpcObject.at[1]
100          readonly property int width: lastIpcObject.size[0]
101          readonly property int height: lastIpcObject.size[1]
102          readonly property HyprlandWorkspace workspace: Hyprland.workspaces.values.find(w => w.id === lastIpcObject.workspace.id) ?? null
103          readonly property bool floating: lastIpcObject.floating
104          readonly property bool fullscreen: lastIpcObject.fullscreen
105          readonly property int pid: lastIpcObject.pid
106          readonly property int focusHistoryId: lastIpcObject.focusHistoryID
107      }
108  
109      Component {
110          id: clientComp
111  
112          Client {}
113      }
114  }