136 lines
3.2 KiB
Nim
136 lines
3.2 KiB
Nim
|
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
|
||
|
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
|
||
|
|