import std/[os, strformat, strutils, streams, tables, net, sugar] import ./lib export tables import yaml, jsony type # Remove effects? HyprlandDefect* = Defect Workspace = object name*: string id*: int Client = object class*: string workspace*: Workspace ActiveWorkspace = object name*: string id*: int Monitor = object activeWorkspace*: ActiveWorkspace name: string id*: int proc hyprSocketPath(): string = let runtimeDir = getEnv("XDG_RUNTIME_DIR") let instancSig = getEnv("HYPRLAND_INSTANCE_SIGNATURE") result = runtimeDir / "hypr" / instancSig let hyprSocket = hyprSocketPath() / ".socket.sock" hyprSocket2 = hyprSocketPath() / ".socket2.sock" # TODO: revamp? proc getData[T](msg: string, to: typedesc[T]): T = let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP) try: socket.connectUnix(hyprSocket) except OSError: raise newException( HyprlandDefect, "Could not connect to Hyprland IPC UNIX path; is Hyprland running?" ) socket.send msg var recvData: string while true: let response = socket.recv(4096) if response == "": break recvData.add response socket.close() # is this necessary? result = recvData.fromJson(T) proc getMonitors*(): seq[Monitor] = result = getData("[-j]/monitors", seq[Monitor]) proc getClients(): seq[Client] = result = getData("[-j]/clients", seq[Client]) type EwwWorkspace = object icon*, class*: string id*: int proc add(ws: var EwwWorkspace, client: Client) = let clientIcon = config.pickIcon(client.class) if ws.icon == config.`no-client`: ws.icon = clientIcon else: ws.icon.add clientIcon func openWorkspaces(monitors: seq[Monitor]): seq[int] = for m in monitors: result.add m.activeWorkspace.id func setActive(workspaces: seq[EwwWorkspace], m: Monitor): seq[EwwWorkspace] = let id = m.activeWorkspace.id result = workspaces result[id - 1].class.add " ws-button-active-" & $(id) proc writeEwwClasses*() = let monitors = getMonitors() clients = getClients() var workspaces= collect: for i in 0..<9: EwwWorkspace( icon: config.`no-client`, class: fmt"ws-button-{i+1}", id: i+1 ) for client in clients: let id = client.workspace.id - 1 workspaces[id].add client for id in openWorkspaces(monitors): workspaces[id - 1].class.add " ws-button-open" var ewwClasses = collect: for m in monitors: workspaces.setActive m stdout.write (ewwClasses.toJson() & "\n") flushFile stdout proc handleHyprEvent(event: string) = let s = event.split(">>", 1) event = s[0] # use enum? case event: of "monitoraddedv2": # TODO: open as many bars as necessary depending on num monitors # is it ok to just call open bar again? notify("monitor added") of "openwindow", "workspacev2": writeEwwClasses() else: discard proc watchHyprland*() = let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP) try: socket.connectUnix(hyprSocket2) except OSError: raise newException( HyprlandDefect, "Could not connect to Hyprland IPC UNIX path; is Hyprland running?" ) writeEwwClasses() while true: var line: string socket.readLine line handleHyprEvent line