Compare commits
No commits in common. "283e7bd1fc8cd64462dc6e008ea08ca50e9d1208" and "e4ea87582a704182883595c0ead66f95c943abb9" have entirely different histories.
283e7bd1fc
...
e4ea87582a
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
|||||||
*_test.go
|
*_test.go
|
24
dispatch.go
24
dispatch.go
@ -1,24 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
21
execute_command.go
Normal file
21
execute_command.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package hypr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Execute(cmd string) error {
|
||||||
|
conn, err := net.Dial("unix", os.ExpandEnv("/tmp/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
if _, err := fmt.Fprintln(conn, cmd); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
36
get_clients.go
Normal file
36
get_clients.go
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
package hypr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os/exec"
|
||||||
|
|
||||||
|
"git.milar.in/milarin/slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetWindows() ([]*Window, error) {
|
||||||
|
cmd := exec.Command("hyprctl", "-j", "clients")
|
||||||
|
|
||||||
|
stdout, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
windows := make([]*Window, 0, 5)
|
||||||
|
if err := json.NewDecoder(stdout).Decode(&windows); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
windows = slices.Filter(windows, func(w *Window) bool {
|
||||||
|
return w.PID != -1
|
||||||
|
})
|
||||||
|
|
||||||
|
return windows, nil
|
||||||
|
}
|
46
get_events.go
Normal file
46
get_events.go
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package hypr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"context"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.milar.in/milarin/channel"
|
||||||
|
"git.milar.in/milarin/slices"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetEventChannel(ctx context.Context, types ...EventType) (<-chan Event, error) {
|
||||||
|
conn, err := net.Dial("unix", os.ExpandEnv("/tmp/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make(chan Event, 10)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer conn.Close()
|
||||||
|
<-ctx.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(out)
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
sc := bufio.NewScanner(conn)
|
||||||
|
for sc.Scan() {
|
||||||
|
out <- parseEvent(sc.Text())
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if len(types) == 0 {
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
typeMap := slices.ToStructMap(slices.Map(types, strings.ToLower))
|
||||||
|
return channel.Filter(out, func(e Event) bool {
|
||||||
|
_, ok := typeMap[e.Type]
|
||||||
|
return ok
|
||||||
|
}), nil
|
||||||
|
}
|
@ -1,70 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
30
get_monitors.go
Normal file
30
get_monitors.go
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
package hypr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetMonitors() ([]*Monitor, error) {
|
||||||
|
cmd := exec.Command("hyprctl", "-j", "monitors")
|
||||||
|
|
||||||
|
stdout, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
monitors := make([]*Monitor, 0, 5)
|
||||||
|
if err := json.NewDecoder(stdout).Decode(&monitors); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return monitors, nil
|
||||||
|
}
|
54
get_workspaces.go
Normal file
54
get_workspaces.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package hypr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"os/exec"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetWorkspaces() ([]*Workspace, error) {
|
||||||
|
cmd := exec.Command("hyprctl", "-j", "workspaces")
|
||||||
|
|
||||||
|
stdout, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
workspaces := make([]*Workspace, 0, 5)
|
||||||
|
if err := json.NewDecoder(stdout).Decode(&workspaces); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return workspaces, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetActiveWorkspace() (*Workspace, error) {
|
||||||
|
cmd := exec.Command("hyprctl", "-j", "activeworkspace")
|
||||||
|
|
||||||
|
stdout, err := cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Start(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace := &Workspace{}
|
||||||
|
if err := json.NewDecoder(stdout).Decode(workspace); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cmd.Wait(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return workspace, nil
|
||||||
|
}
|
33
getters.go
33
getters.go
@ -1,33 +0,0 @@
|
|||||||
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"))
|
|
||||||
}
|
|
6
go.mod
6
go.mod
@ -1,10 +1,10 @@
|
|||||||
module git.milar.in/milarin/hypr
|
module git.milar.in/milarin/hypr
|
||||||
|
|
||||||
go 1.21.6
|
go 1.21.5
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.milar.in/milarin/channel v0.1.2
|
git.milar.in/milarin/channel v0.1.1
|
||||||
git.milar.in/milarin/slices v0.0.8
|
git.milar.in/milarin/slices v0.0.8
|
||||||
)
|
)
|
||||||
|
|
||||||
require git.milar.in/milarin/gmath v0.0.3 // indirect
|
require git.milar.in/milarin/gmath v0.0.5 // indirect
|
||||||
|
8
go.sum
8
go.sum
@ -1,6 +1,6 @@
|
|||||||
git.milar.in/milarin/channel v0.1.2 h1:43nWriSppDxa2dO6Midhy2RymzMz2F/Mp1D6lgapQnQ=
|
git.milar.in/milarin/channel v0.1.1 h1:s8+BdiOMmuRUDmChQ2i4G5GWsDCK9tKNHt1knLJx9zM=
|
||||||
git.milar.in/milarin/channel v0.1.2/go.mod h1:We83LTI8S7u7II3pD+A2ChCDWJfCkcBUCUqii9HjTtM=
|
git.milar.in/milarin/channel v0.1.1/go.mod h1:We83LTI8S7u7II3pD+A2ChCDWJfCkcBUCUqii9HjTtM=
|
||||||
git.milar.in/milarin/gmath v0.0.3 h1:ii6rKNItS55O/wtIFhD1cTN2BMwDZjTBmiOocKURvxM=
|
git.milar.in/milarin/gmath v0.0.5 h1:qQQMUTbxEk5LriMMSRbElExDSouSJKYBo6zRcOYKVIU=
|
||||||
git.milar.in/milarin/gmath v0.0.3/go.mod h1:HDLftG5RLpiNGKiIWh+O2G1PYkNzyLDADO8Cd/1abiE=
|
git.milar.in/milarin/gmath v0.0.5/go.mod h1:HDLftG5RLpiNGKiIWh+O2G1PYkNzyLDADO8Cd/1abiE=
|
||||||
git.milar.in/milarin/slices v0.0.8 h1:qN9TE3tkArdTixMKSnwvNPcApwAjxpLVwA5a9k1rm2s=
|
git.milar.in/milarin/slices v0.0.8 h1:qN9TE3tkArdTixMKSnwvNPcApwAjxpLVwA5a9k1rm2s=
|
||||||
git.milar.in/milarin/slices v0.0.8/go.mod h1:qMhdtMnfWswc1rHpwgNw33lB84aNEkdBn5BDiYA+G3k=
|
git.milar.in/milarin/slices v0.0.8/go.mod h1:qMhdtMnfWswc1rHpwgNw33lB84aNEkdBn5BDiYA+G3k=
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
51
utils.go
51
utils.go
@ -1,51 +0,0 @@
|
|||||||
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