Compare commits

..

No commits in common. "64641a34026be172309f193ca5376833098c665a" and "c90248a597c265f84f6cd88d74c210e2b232537d" have entirely different histories.

View file

@ -1,13 +1,28 @@
import std/[ import std/[os,net, json, sugar, strformat, strutils, tables]
asyncdispatch, asyncnet, json,
net, os, osproc,
strformat, strutils, sugar, const icons = {
tables "[Running] - Oracle VM VirtualBox": "",
] "Visual Studio Code": "",
"vivaldi-stable": "󰖟",
"LibreOffice": "",
"Geneious Prime": "󰚄",
"Firefox": "",
"- NVIM": "",
"Alacritty": "",
"- Wezterm": "",
"org.wezfurlong.wezterm":""
}.toTable
type type
HyprlandDefect* = Defect HyprlandDefect* = Defect
# Workspace = object
# id, monitorID, windows: int
# name, monitor, lastwindow, lastwindowtitle: string
# hasfullscreen: bool
WorkspaceIcon = object WorkspaceIcon = object
id: int id: int
icon, class: string icon, class: string
@ -24,15 +39,10 @@ type
workspace: ActiveWorkspace workspace: ActiveWorkspace
class, title: string class, title: string
Context = object
icons: Table[string, string]
delay = 500
var ctx = Context()
let his = getenv("HYPRLAND_INSTANCE_SIGNATURE")
proc getData(data: string): string = proc getData(data: string): string =
let let
his = getenv("HYPRLAND_INSTANCE_SIGNATURE")
socketPath = "/tmp/hypr" / his / ".socket.sock" socketPath = "/tmp/hypr" / his / ".socket.sock"
let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP) let socket = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP)
@ -53,10 +63,9 @@ proc getData(data: string): string =
proc getDefaultWorkspaces(): seq[WorkspaceIcon] = proc getDefaultWorkspaces(): seq[WorkspaceIcon] =
let clients = parseJson(getData("[-j]/clients")).to(seq[Client]) let clients = parseJson(getData("[-j]/clients")).to(seq[Client])
result = collect(for i in 1..9: WorkspaceIcon(id: i, icon: "", result = collect(for i in 1..9: WorkspaceIcon(id: i, icon:"",class:fmt"ws-button-{i - 1}"))
class: fmt"ws-button-{i - 1}"))
for client in clients: for client in clients:
let match = ctx.icons.getOrDefault($(client.class), "") let match = icons.getOrDefault($(client.class),"")
if client.workspace.id < 0: continue if client.workspace.id < 0: continue
result[client.workspace.id - 1].icon &= match result[client.workspace.id - 1].icon &= match
for ws in result.mitems: for ws in result.mitems:
@ -68,130 +77,16 @@ proc getActive(m: Monitor): int {.inline.} = m.activeWorkspace.id
proc getState(): seq[seq[WorkspaceIcon]] = proc getState(): seq[seq[WorkspaceIcon]] =
let let
monitors = parseJson(getData("[-j]/monitors")).to(seq[Monitor]) monitors = parseJson(getData("[-j]/monitors")).to(seq[Monitor])
defaultWorkspaces = getDefaultWorkspaces() defaultWorkspaces = getDefaultWorkspaces()
for m in monitors: for m in monitors:
result.add defaultWorkspaces result.add defaultWorkspaces
result[m.id][getActive(m) - 1].class &= result[m.id][getActive(m) - 1].class &=
" " & "ws-button-open" " " & "ws-button-open"
proc workspaceMonitor() = when isMainModule:
while true: while true:
sleep ctx.delay sleep 500
try: try:
echo (%* getState()) echo (%* getState())
except JsonParsingError as e: except JsonParsingError as e:
writeLine(stderr, e.msg) writeLine(stderr, e.msg)
proc parseEvent(line: string): (string, string) {.inline.} =
let s = line.split(">>", 1)
return (s[0], s[1])
proc reactEvent(line: string) =
let (event, _) = parseEvent(line)
case event
of "monitorremoved":
echo "monitor removed"
discard execCmd "eww close bar1"
of "monitoradded":
echo "monitor added"
discard execCmd "eww open bar1"
sleep 1000
discard execCmd "eww reload"
else: discard
proc initEww() =
let monitors = parseJson(getData("[-j]/monitors")).to(seq[Monitor])
discard execCmd "eww daemon"
discard execCmd "eww open bar0"
if monitors.len > 1:
discard execCmd "eww open bar1"
proc watchHyprlandEvents() {.async.} =
initEww()
let
socketPath = "/tmp/hypr" / his / ".socket2.sock"
socket = newAsyncSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP)
try:
socket.connectUnix(socketPath)
except OSError:
raise newException(HyprlandDefect, "Could not connect to Hyprland IPC UNIX path; is Hyprland running?")
while true:
let line = await socket.recvLine()
if line.len == 0: break
reactEvent(line)
socket.close()
proc loadIcons(iconPath: string): Table[string, string] =
if not fileExists iconPath:
echo "icon file: ", iconPath, " not found"
quit 1
result = parseFile(iconPath).to(Table[string, string])
proc noBlank(key: string, val: string) =
const longflags = ["icons", "delay"]
const shortflags = ['i', 'd']
if (
(key in longflags or
key[0] in shortflags) and
val == ""
):
echo "ERROR: expected value for: ", key
quit 1
proc loadDefaultIcons() =
let
configHome = getEnv("XDG_CONFIG_HOME", getEnv("HOME") / ".config")
iconPath = configHome / "hyprman" / "icons.json"
if fileExists iconPath:
ctx.icons = loadIcons(iconPath)
when isMainModule:
import std/parseopt
const usage = """
hyprman <cmd> [opts]
commands:
workspace (w)
watch workspace/client activity and write to stdout
monitors (m)
reflect monitor changes to eww
options:
-h, --help
show this help
-i, --icons
path to icons.json [default: $XDG_CONFIG_HOME/hyprman/icons.json]
-d, --delay
time between socket poll in ms [default: 500]
"""
loadDefaultIcons()
var cmd: string
for kind, key, val in getopt(shortNoVal = {'h'}, longNoVal = @["help"]):
case kind
of cmdArgument:
cmd = key
of cmdShortOption, cmdLongOption:
noBlank(key, val)
case key
of "h", "help":
echo usage; quit 0;
of "i", "icons":
ctx.icons = loadIcons(val)
of "d", "delay":
ctx.delay = parseInt(val)
of cmdEnd: discard
case cmd
of "w", "workspace":
workspaceMonitor()
of "m", "monitors":
waitFor watchHyprlandEvents()
of "":
echo "please specify a command"; quit 1
else:
echo "unknown cmd: ", cmd; quit 1