rewrite
This commit is contained in:
commit
8edaa9d713
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
hypr_test.go
|
24
dispatch.go
Normal file
24
dispatch.go
Normal 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
70
get_instances.go
Normal 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
33
getters.go
Normal 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
7
go.mod
Normal 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
4
go.sum
Normal 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
22
model_bind.go
Normal 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
25
model_instance.go
Normal 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
13
model_misc.go
Normal 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
31
model_monitor.go
Normal 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
32
model_window.go
Normal 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
24
model_workspace.go
Normal 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
51
utils.go
Normal 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
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user