This commit is contained in:
Milarin 2024-02-09 20:24:48 +01:00
commit 8edaa9d713
13 changed files with 337 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
hypr_test.go

24
dispatch.go Normal file
View File

@ -0,0 +1,24 @@
package hypr
import (
"fmt"
"io"
"strings"
)
func (i *Instance) Dispatch(cmd string) (io.ReadCloser, error) {
return readSocketRaw(i.SocketPath(), strings.NewReader(cmd))
}
func (i *Instance) DispatchExpectOK(cmd string) error {
str, err := readSocketString(i.SocketPath(), strings.NewReader(cmd))
if err != nil {
return err
}
if strings.ToLower(strings.TrimSpace(str)) != "ok" {
return fmt.Errorf("dispatcher '%s' returned an error: %s", cmd, str)
}
return nil
}

70
get_instances.go Normal file
View File

@ -0,0 +1,70 @@
package hypr
import (
"errors"
"fmt"
"io"
"io/fs"
"os"
"strconv"
"strings"
"git.milar.in/milarin/slices"
)
func GetInstance(signature string) (*Instance, error) {
lockFilePath := fmt.Sprintf("/tmp/hypr/%s.lock", signature)
file, err := os.Open(lockFilePath)
if err != nil {
return nil, err
}
defer file.Close()
data, err := io.ReadAll(file)
if err != nil {
return nil, err
}
lines := strings.Split(string(data), "\n")
pid, err := strconv.Atoi(lines[0])
if err != nil {
return nil, err
}
return &Instance{
Signature: signature,
PID: pid,
WaylandSocket: lines[1],
}, nil
}
func GetDefaultInstance() (*Instance, error) {
signature, ok := os.LookupEnv("HYPRLAND_INSTANCE_SIGNATURE")
if !ok {
return nil, errors.New("default instance not found because HYPRLAND_INSTANCE_SIGNATURE is not set")
}
return GetInstance(signature)
}
func GetInstances() ([]*Instance, error) {
entries, err := os.ReadDir("/tmp/hypr")
if err != nil {
return nil, err
}
entries = slices.Filter(entries, fs.DirEntry.IsDir)
instances := make([]*Instance, 0, len(entries))
for _, entry := range entries {
instance, err := GetInstance(entry.Name())
if err != nil {
fmt.Println(err)
continue
}
instances = append(instances, instance)
}
return instances, nil
}

33
getters.go Normal file
View File

@ -0,0 +1,33 @@
package hypr
import (
"strings"
)
func (i *Instance) GetActiveWindow() (*Window, error) {
return readSocket[*Window](i.SocketPath(), strings.NewReader("j/activewindow"))
}
func (i *Instance) GetActiveWorkspace() (*Workspace, error) {
return readSocket[*Workspace](i.SocketPath(), strings.NewReader("j/activeworkspace"))
}
func (i *Instance) GetBinds() ([]*Bind, error) {
return readSocket[[]*Bind](i.SocketPath(), strings.NewReader("j/binds"))
}
func (i *Instance) GetWindows() ([]*Window, error) {
return readSocket[[]*Window](i.SocketPath(), strings.NewReader("j/clients"))
}
func (i *Instance) GetCursorPos() (Point, error) {
return readSocket[Point](i.SocketPath(), strings.NewReader("j/cursorpos"))
}
func (i *Instance) GetMonitors() ([]*Monitor, error) {
return readSocket[[]*Monitor](i.SocketPath(), strings.NewReader("j/monitors"))
}
func (i *Instance) GetWorkspaces() ([]*Workspace, error) {
return readSocket[[]*Workspace](i.SocketPath(), strings.NewReader("j/workspaces"))
}

7
go.mod Normal file
View File

@ -0,0 +1,7 @@
module git.milar.in/milarin/hypr
go 1.21.6
require git.milar.in/milarin/slices v0.0.8
require git.milar.in/milarin/gmath v0.0.3 // indirect

4
go.sum Normal file
View File

@ -0,0 +1,4 @@
git.milar.in/milarin/gmath v0.0.3 h1:ii6rKNItS55O/wtIFhD1cTN2BMwDZjTBmiOocKURvxM=
git.milar.in/milarin/gmath v0.0.3/go.mod h1:HDLftG5RLpiNGKiIWh+O2G1PYkNzyLDADO8Cd/1abiE=
git.milar.in/milarin/slices v0.0.8 h1:qN9TE3tkArdTixMKSnwvNPcApwAjxpLVwA5a9k1rm2s=
git.milar.in/milarin/slices v0.0.8/go.mod h1:qMhdtMnfWswc1rHpwgNw33lB84aNEkdBn5BDiYA+G3k=

22
model_bind.go Normal file
View File

@ -0,0 +1,22 @@
package hypr
import "encoding/json"
type Bind struct {
Locked bool `json:"locked"`
Mouse bool `json:"mouse"`
Release bool `json:"release"`
Repeat bool `json:"repeat"`
NonConsuming bool `json:"non_consuming"`
ModMask int `json:"modmask"`
Submap string `json:"submap"`
Key string `json:"key"`
KeyCode int `json:"keycode"`
Dispatcher string `json:"dispatcher"`
Arg string `json:"arg"`
}
func (b Bind) String() string {
data, _ := json.MarshalIndent(b, "", "\t")
return string(data)
}

25
model_instance.go Normal file
View File

@ -0,0 +1,25 @@
package hypr
import (
"encoding/json"
"fmt"
)
type Instance struct {
Signature string `json:"instance"`
PID int `json:"pid"`
WaylandSocket string `json:"wl_socket"`
}
func (i Instance) String() string {
data, _ := json.MarshalIndent(i, "", "\t")
return string(data)
}
func (i Instance) SocketPath() string {
return fmt.Sprintf("/tmp/hypr/%s/.socket.sock", i.Signature)
}
func (i Instance) EventSocketPath() string {
return fmt.Sprintf("/tmp/hypr/%s/.socket2.sock", i.Signature)
}

13
model_misc.go Normal file
View File

@ -0,0 +1,13 @@
package hypr
import "encoding/json"
type Point struct {
X int `json:"x"`
Y int `json:"y"`
}
func (p Point) String() string {
data, _ := json.MarshalIndent(p, "", "\t")
return string(data)
}

31
model_monitor.go Normal file
View File

@ -0,0 +1,31 @@
package hypr
import "encoding/json"
type Monitor struct {
ID int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Make string `json:"make"`
Model string `json:"model"`
Serial string `json:"serial"`
Width int `json:"width"`
Height int `json:"height"`
RefreshRate float64 `json:"refreshRate"`
X int `json:"x"`
Y int `json:"y"`
ActiveWorkspace WorkspaceIdent `json:"activeWorkspace"`
SpecialWorkspace WorkspaceIdent `json:"specialWorkspace"`
Reserved [4]int `json:"reserved"`
Scale float64 `json:"scale"`
Transform int `json:"transform"`
Focused bool `json:"focused"`
DPMSStatus bool `json:"dpmsStatus"`
VRR bool `json:"vrr"`
ActivelyTearing bool `json:"activelyTearing"`
}
func (m Monitor) String() string {
data, _ := json.MarshalIndent(m, "", "\t")
return string(data)
}

32
model_window.go Normal file
View File

@ -0,0 +1,32 @@
package hypr
import "encoding/json"
type Window struct {
Address string `json:"address"`
Mapped bool `json:"mapped"`
Hidden bool `json:"hidden"`
At [2]int `json:"at"`
Size [2]int `json:"size"`
Workspace WorkspaceIdent `json:"workspace"`
Floating bool `json:"floating"`
MonitorID int `json:"monitor"`
Class string `json:"class"`
Title string `json:"title"`
InitialClass string `json:"initialClass"`
InitialTitle string `json:"initialTitle"`
PID int `json:"pid"`
Xwayland bool `json:"xwayland"`
Pinned bool `json:"pinned"`
Fullscreen bool `json:"fullscreen"`
FullscreenMode int `json:"fullscreenMode"`
FakeFullscreen bool `json:"fakeFullscreen"`
Grouped []interface{} `json:"grouped"` // TODO
Swallowing string `json:"swallowing"`
FocusHistoryID int `json:"focusHistoryID"`
}
func (w Window) String() string {
data, _ := json.MarshalIndent(w, "", "\t")
return string(data)
}

24
model_workspace.go Normal file
View File

@ -0,0 +1,24 @@
package hypr
import "encoding/json"
type WorkspaceIdent struct {
ID int `json:"id"`
Name string `json:"name"`
}
type Workspace struct {
ID int `json:"id"`
Name string `json:"name"`
Monitor string `json:"monitor"`
MonitorID int `json:"monitorID"`
Windows int `json:"windows"`
HasFullscreen bool `json:"hasfullscreen"`
LastWindow string `json:"lastwindow"`
LastWindowTitle string `json:"lastwindowtitle"`
}
func (w Workspace) String() string {
data, _ := json.MarshalIndent(w, "", "\t")
return string(data)
}

51
utils.go Normal file
View File

@ -0,0 +1,51 @@
package hypr
import (
"encoding/json"
"io"
"net"
)
func readSocketRaw(socket string, body io.Reader) (io.ReadCloser, error) {
conn, err := net.Dial("unix", socket)
if err != nil {
return nil, err
}
if _, err := io.Copy(conn, body); err != nil {
conn.Close()
return nil, err
}
return conn, nil
}
func readSocketString(socket string, body io.Reader) (string, error) {
r, err := readSocketRaw(socket, body)
if err != nil {
return "", err
}
defer r.Close()
data, err := io.ReadAll(r)
if err != nil {
return "", err
}
return string(data), nil
}
func readSocket[T any](socket string, body io.Reader) (T, error) {
r, err := readSocketRaw(socket, body)
if err != nil {
return *new(T), err
}
defer r.Close()
value := new(T)
if err := json.NewDecoder(r).Decode(value); err != nil {
return *new(T), err
}
return *value, nil
}