initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*_test.go
|
52
do.go
Normal file
52
do.go
Normal file
@ -0,0 +1,52 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (c *Client) Action(action Action) error {
|
||||
// print request and response to console:
|
||||
//
|
||||
// io.Copy(os.Stdout, asJsonReader(action))
|
||||
// r, err := readSocketRaw(c.GetSocketPath(), asJsonReader(action))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// io.Copy(os.Stdout, r)
|
||||
// return nil
|
||||
|
||||
resp := readSocket[string](c.GetSocketPath(), asJsonReader(action))
|
||||
if resp.Err != nil {
|
||||
return errors.New(*resp.Err)
|
||||
} else if resp.OK == nil {
|
||||
return errors.New("unexpected response value: nil")
|
||||
} else if *resp.OK != "Handled" {
|
||||
return fmt.Errorf("unexpected response value: %s", *resp.OK)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) Output(outputAction OutputActionRequest) error {
|
||||
body := map[string]OutputActionRequest{"Output": outputAction}
|
||||
|
||||
// print request and response to console:
|
||||
//
|
||||
// io.Copy(os.Stdout, asJsonReader(body))
|
||||
// r, err := readSocketRaw(c.GetSocketPath(), asJsonReader(body))
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// io.Copy(os.Stdout, r)
|
||||
// return nil
|
||||
|
||||
resp := readSocket[outputActionResponse](c.GetSocketPath(), asJsonReader(body))
|
||||
if resp.Err != nil {
|
||||
return errors.New(*resp.Err)
|
||||
} else if resp.OK == nil {
|
||||
return errors.New("unexpected response value: nil")
|
||||
} else if resp.OK.OutputConfigChanged != "Applied" {
|
||||
return fmt.Errorf("unexpected response value: %s", resp.OK.OutputConfigChanged)
|
||||
}
|
||||
return nil
|
||||
}
|
15
event_stream.go
Normal file
15
event_stream.go
Normal file
@ -0,0 +1,15 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"git.tordarus.net/tordarus/channel"
|
||||
)
|
||||
|
||||
func (c *Client) SubscribeEvents(ctx context.Context) (<-chan Event, error) {
|
||||
ch, err := subscribeSocket[*eventContainer](ctx, c.GetSocketPath(), asJsonReader("EventStream"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return channel.MapSuccessive(ch, (*eventContainer).event), nil
|
||||
}
|
103
getters.go
Normal file
103
getters.go
Normal file
@ -0,0 +1,103 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
|
||||
"git.tordarus.net/tordarus/slices"
|
||||
)
|
||||
|
||||
func (c *Client) GetOutputs() ([]Output, error) {
|
||||
resp := readSocket[map[string]map[string]Output](c.GetSocketPath(), asJsonReader("Outputs"))
|
||||
if resp.Err != nil {
|
||||
return nil, fmt.Errorf("retrieving outputs: %s", *resp.Err)
|
||||
}
|
||||
return slices.OfMap((*resp.OK)["Outputs"], slices.UnmapValue), nil
|
||||
}
|
||||
|
||||
func (c *Client) GetWorkspaces() ([]Workspace, error) {
|
||||
resp := readSocket[map[string][]Workspace](c.GetSocketPath(), asJsonReader("Workspaces"))
|
||||
if resp.Err != nil {
|
||||
return nil, fmt.Errorf("retrieving workspaces: %s", *resp.Err)
|
||||
}
|
||||
return (*resp.OK)["Workspaces"], nil
|
||||
}
|
||||
|
||||
func (c *Client) GetWindows() ([]Window, error) {
|
||||
resp := readSocket[map[string][]Window](c.GetSocketPath(), asJsonReader("Windows"))
|
||||
if resp.Err != nil {
|
||||
return nil, fmt.Errorf("retrieving windows: %s", *resp.Err)
|
||||
}
|
||||
return (*resp.OK)["Windows"], nil
|
||||
}
|
||||
|
||||
func (c *Client) GetLayers() ([]LayerSurface, error) {
|
||||
resp := readSocket[map[string][]LayerSurface](c.GetSocketPath(), asJsonReader("Layers"))
|
||||
if resp.Err != nil {
|
||||
return nil, fmt.Errorf("retrieving layers: %s", *resp.Err)
|
||||
}
|
||||
return (*resp.OK)["Layers"], nil
|
||||
}
|
||||
|
||||
func (c *Client) GetKeyboardLayouts() (*KeyboardLayouts, error) {
|
||||
resp := readSocket[map[string]KeyboardLayouts](c.GetSocketPath(), asJsonReader("KeyboardLayouts"))
|
||||
if resp.Err != nil {
|
||||
return nil, fmt.Errorf("retrieving layers: %s", *resp.Err)
|
||||
}
|
||||
value := (*resp.OK)["KeyboardLayouts"]
|
||||
return &value, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetFocusedOutput() (*Output, error) {
|
||||
resp := readSocket[map[string]Output](c.GetSocketPath(), asJsonReader("FocusedOutput"))
|
||||
if resp.Err != nil {
|
||||
return nil, fmt.Errorf("retrieving outputs: %s", *resp.Err)
|
||||
}
|
||||
value := (*resp.OK)["FocusedOutput"]
|
||||
return &value, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetFocusedWindow() (*Window, error) {
|
||||
resp := readSocket[map[string]Window](c.GetSocketPath(), asJsonReader("FocusedWindow"))
|
||||
if resp.Err != nil {
|
||||
return nil, fmt.Errorf("retrieving outputs: %s", *resp.Err)
|
||||
}
|
||||
value := (*resp.OK)["FocusedWindow"]
|
||||
return &value, nil
|
||||
}
|
||||
|
||||
func (c *Client) PickWindow() (*Window, error) {
|
||||
resp := readSocket[map[string]Window](c.GetSocketPath(), asJsonReader("PickWindow"))
|
||||
if resp.Err != nil {
|
||||
return nil, fmt.Errorf("retrieving outputs: %s", *resp.Err)
|
||||
}
|
||||
value := (*resp.OK)["PickedWindow"]
|
||||
return &value, nil
|
||||
}
|
||||
|
||||
func (c *Client) PickColor() (color.Color, error) {
|
||||
resp := readSocket[map[string]niriColor](c.GetSocketPath(), asJsonReader("PickColor"))
|
||||
if resp.Err != nil {
|
||||
return nil, fmt.Errorf("retrieving outputs: %s", *resp.Err)
|
||||
}
|
||||
value := (*resp.OK)["PickedColor"]
|
||||
return value.AsColor(), nil
|
||||
}
|
||||
|
||||
func (c *Client) GetVersion() (string, error) {
|
||||
resp := readSocket[map[string]string](c.GetSocketPath(), asJsonReader("Version"))
|
||||
if resp.Err != nil {
|
||||
return "", fmt.Errorf("retrieving version: %s", *resp.Err)
|
||||
}
|
||||
value := (*resp.OK)["Version"]
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (c *Client) GetOverviewState() (bool, error) {
|
||||
resp := readSocket[map[string]overviewState](c.GetSocketPath(), asJsonReader("OverviewState"))
|
||||
if resp.Err != nil {
|
||||
return false, fmt.Errorf("retrieving version: %s", *resp.Err)
|
||||
}
|
||||
value := (*resp.OK)["OverviewState"]
|
||||
return value.IsOpen, nil
|
||||
}
|
14
go.mod
Normal file
14
go.mod
Normal file
@ -0,0 +1,14 @@
|
||||
module git.tordarus.net/niri-tools/niri
|
||||
|
||||
go 1.24.4
|
||||
|
||||
require (
|
||||
git.tordarus.net/tordarus/channel v0.1.20
|
||||
git.tordarus.net/tordarus/slices v0.0.15
|
||||
github.com/adrg/xdg v0.5.3
|
||||
)
|
||||
|
||||
require (
|
||||
git.tordarus.net/tordarus/gmath v0.0.7 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
)
|
18
go.sum
Normal file
18
go.sum
Normal file
@ -0,0 +1,18 @@
|
||||
git.tordarus.net/tordarus/channel v0.1.20 h1:kHAyp18IauDAyFtkbN67+qD2SB40Wiy0w1tC4JpHbOo=
|
||||
git.tordarus.net/tordarus/channel v0.1.20/go.mod h1:8/dWFTdGO7g4AeSZ7cF6GerkGbe9c4dBVMVDBxOd9m4=
|
||||
git.tordarus.net/tordarus/gmath v0.0.7 h1:tR48idt9AUL0r556ww3ZxByTKJEr6NWCTlhl2ihzYxQ=
|
||||
git.tordarus.net/tordarus/gmath v0.0.7/go.mod h1:mO7aPlvNrGVE9UFXEuuACjZgMDsM63l3OcQy6xSQnoE=
|
||||
git.tordarus.net/tordarus/slices v0.0.15 h1:qxKS+7BCZ/LzQbRCvdDFoLQXaJZ2C0GfVju/kPt1r3g=
|
||||
git.tordarus.net/tordarus/slices v0.0.15/go.mod h1:eJBw6pSDNivPI0l4e0sGKUJzou/lbzHflXdAUzp1g4o=
|
||||
github.com/adrg/xdg v0.5.3 h1:xRnxJXne7+oWDatRhR1JLnvuccuIeCoBu2rtuLqQB78=
|
||||
github.com/adrg/xdg v0.5.3/go.mod h1:nlTsY+NNiCBGCK2tpm09vRqfVzrc2fLmXGpBLF0zlTQ=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
547
model_action.go
Normal file
547
model_action.go
Normal file
@ -0,0 +1,547 @@
|
||||
package niri
|
||||
|
||||
import "time"
|
||||
|
||||
type Action struct {
|
||||
Action map[string]any `json:"Action"`
|
||||
}
|
||||
|
||||
func ActionCustom[T any](actionName string, actionContent T) Action {
|
||||
return Action{map[string]any{actionName: actionContent}}
|
||||
}
|
||||
|
||||
func ActionQuit(skipConfirmation bool) Action {
|
||||
return ActionCustom("Quit", map[string]any{"skip_confirmation": skipConfirmation})
|
||||
}
|
||||
|
||||
func ActionPowerOffMonitors() Action {
|
||||
return ActionCustom("PowerOffMonitors", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionPowerOnMonitors() Action {
|
||||
return ActionCustom("PowerOnMonitors", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionSpawn(command []string) Action {
|
||||
return ActionCustom("Spawn", map[string]any{"command": command})
|
||||
}
|
||||
|
||||
func ActionDoScreenTransition(delay Option[time.Duration]) Action {
|
||||
return ActionCustom("DoScreenTransition", map[string]any{"delay_ms": mapOption(delay, time.Duration.Milliseconds)})
|
||||
}
|
||||
|
||||
func ActionScreenshot(showPointer bool) Action {
|
||||
return ActionCustom("Screenshot", map[string]any{"show_pointer": showPointer})
|
||||
}
|
||||
|
||||
func ActionScreenshotScreen(writeToDisk, showPointer bool) Action {
|
||||
return ActionCustom("ScreenshotScreen", map[string]any{"write_to_disk": writeToDisk, "show_pointer": showPointer})
|
||||
}
|
||||
|
||||
func ActionScreenshotWindow(id Option[WindowID], writeToDisk bool) Action {
|
||||
return ActionCustom("ScreenshotWindow", map[string]any{"id": id, "write_to_disk": writeToDisk})
|
||||
}
|
||||
|
||||
func ActionToggleKeyboardShortcutsInhibit() Action {
|
||||
return ActionCustom("ToggleKeyboardShortcutsInhibit", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionCloseWindow(id Option[WindowID]) Action {
|
||||
return ActionCustom("CloseWindow", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionFullscreenWindow(id Option[WindowID]) Action {
|
||||
return ActionCustom("FullscreenWindow", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionToggleWindowedFullscreen(id Option[WindowID]) Action {
|
||||
return ActionCustom("ToggleWindowedFullscreen", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionFocusWindow(id WindowID) Action {
|
||||
return ActionCustom("FocusWindow", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionFocusWindowInColumn(index int) Action {
|
||||
return ActionCustom("FocusWindowInColumn", map[string]any{"index": index})
|
||||
}
|
||||
|
||||
func ActionFocusWindowPrevious() Action {
|
||||
return ActionCustom("FocusWindowPrevious", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusColumnLeft() Action {
|
||||
return ActionCustom("FocusColumnLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusColumnRight() Action {
|
||||
return ActionCustom("FocusColumnRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusColumnFirst() Action {
|
||||
return ActionCustom("FocusColumnFirst", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusColumnLast() Action {
|
||||
return ActionCustom("FocusColumnLast", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusColumnRightOrFirst() Action {
|
||||
return ActionCustom("FocusColumnRightOrFirst", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusColumnLeftOrLast() Action {
|
||||
return ActionCustom("FocusColumnLeftOrLast", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusColumn(index int) Action {
|
||||
return ActionCustom("FocusColumn", map[string]any{"index": index})
|
||||
}
|
||||
|
||||
func ActionFocusWindowOrMonitorUp() Action {
|
||||
return ActionCustom("FocusWindowOrMonitorUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowOrMonitorDown() Action {
|
||||
return ActionCustom("FocusWindowOrMonitorDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusColumnOrMonitorLeft() Action {
|
||||
return ActionCustom("FocusColumnOrMonitorLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusColumnOrMonitorRight() Action {
|
||||
return ActionCustom("FocusColumnOrMonitorRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowDown() Action {
|
||||
return ActionCustom("FocusWindowDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowUp() Action {
|
||||
return ActionCustom("FocusWindowUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowDownOrColumnLeft() Action {
|
||||
return ActionCustom("FocusWindowDownOrColumnLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowDownOrColumnRight() Action {
|
||||
return ActionCustom("FocusWindowDownOrColumnRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowUpOrColumnLeft() Action {
|
||||
return ActionCustom("FocusWindowUpOrColumnLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowUpOrColumnRight() Action {
|
||||
return ActionCustom("FocusWindowUpOrColumnRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowOrWorkspaceDown() Action {
|
||||
return ActionCustom("FocusWindowOrWorkspaceDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowOrWorkspaceUp() Action {
|
||||
return ActionCustom("FocusWindowOrWorkspaceUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowTop() Action {
|
||||
return ActionCustom("FocusWindowTop", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowBottom() Action {
|
||||
return ActionCustom("FocusWindowBottom", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowDownOrTop() Action {
|
||||
return ActionCustom("FocusWindowDownOrTop", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWindowUpOrBottom() Action {
|
||||
return ActionCustom("FocusWindowUpOrBottom", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnLeft() Action {
|
||||
return ActionCustom("MoveColumnLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnRight() Action {
|
||||
return ActionCustom("MoveColumnRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToFirst() Action {
|
||||
return ActionCustom("MoveColumnToFirst", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToLast() Action {
|
||||
return ActionCustom("MoveColumnToLast", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnLeftOrToMonitorLeft() Action {
|
||||
return ActionCustom("MoveColumnLeftOrToMonitorLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnRightOrToMonitorRight() Action {
|
||||
return ActionCustom("MoveColumnRightOrToMonitorRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToIndex(index int) Action {
|
||||
return ActionCustom("MoveColumnToIndex", map[string]any{"index": index})
|
||||
}
|
||||
|
||||
func ActionMoveWindowDown() Action {
|
||||
return ActionCustom("MoveWindowDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowUp() Action {
|
||||
return ActionCustom("MoveWindowUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowDownOrToWorkspaceDown() Action {
|
||||
return ActionCustom("MoveWindowDownOrToWorkspaceDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowUpOrToWorkspaceUp() Action {
|
||||
return ActionCustom("MoveWindowUpOrToWorkspaceUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionConsumeOrExpelWindowLeft(id Option[WindowID]) Action {
|
||||
return ActionCustom("ConsumeOrExpelWindowLeft", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionConsumeOrExpelWindowRight(id Option[WindowID]) Action {
|
||||
return ActionCustom("ConsumeOrExpelWindowRight", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionConsumeWindowIntoColumn() Action {
|
||||
return ActionCustom("ConsumeWindowIntoColumn", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionExpelWindowFromColumn() Action {
|
||||
return ActionCustom("ExpelWindowFromColumn", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionSwapWindowRight() Action {
|
||||
return ActionCustom("SwapWindowRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionSwapWindowLeft() Action {
|
||||
return ActionCustom("SwapWindowLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionToggleColumnTabbedDisplay() Action {
|
||||
return ActionCustom("ToggleColumnTabbedDisplay", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionSetColumnDisplay(display ColumnDisplay) Action {
|
||||
return ActionCustom("SetColumnDisplay", map[string]any{"display": display})
|
||||
}
|
||||
|
||||
func ActionCenterColumn() Action {
|
||||
return ActionCustom("CenterColumn", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionCenterWindow(id Option[WindowID]) Action {
|
||||
return ActionCustom("CenterWindow", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionCenterVisibleColumns() Action {
|
||||
return ActionCustom("CenterVisibleColumns", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWorkspaceDown() Action {
|
||||
return ActionCustom("FocusWorkspaceDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWorkspaceUp() Action {
|
||||
return ActionCustom("FocusWorkspaceUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusWorkspace(reference WorkspaceReferenceArg) Action {
|
||||
return ActionCustom("FocusWorkspace", map[string]any{"reference": reference})
|
||||
}
|
||||
|
||||
func ActionFocusWorkspacePrevious() Action {
|
||||
return ActionCustom("FocusWorkspacePrevious", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToWorkspaceDown() Action {
|
||||
return ActionCustom("MoveWindowToWorkspaceDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToWorkspaceUp() Action {
|
||||
return ActionCustom("MoveWindowToWorkspaceUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToWorkspace(id Option[WindowID], reference WorkspaceReferenceArg, focus bool) Action {
|
||||
return ActionCustom("MoveWindowToWorkspace", map[string]any{"id": id, "reference": reference, "focus": focus})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToWorkspaceDown(focus bool) Action {
|
||||
return ActionCustom("MoveColumnToWorkspaceDown", map[string]any{"focus": focus})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToWorkspaceUp(focus bool) Action {
|
||||
return ActionCustom("MoveColumnToWorkspaceUp", map[string]any{"focus": focus})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToWorkspace(reference WorkspaceReferenceArg, focus bool) Action {
|
||||
return ActionCustom("MoveColumnToWorkspace", map[string]any{"reference": reference, "focus": focus})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceDown() Action {
|
||||
return ActionCustom("MoveWorkspaceDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceUp() Action {
|
||||
return ActionCustom("MoveWorkspaceUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceToIndex(index int, reference Option[WorkspaceReferenceArg]) Action {
|
||||
return ActionCustom("MoveWorkspaceToIndex", map[string]any{"index": index, "reference": reference})
|
||||
}
|
||||
|
||||
func ActionSetWorkspaceName(name string, workspace Option[WorkspaceReferenceArg]) Action {
|
||||
return ActionCustom("SetWorkspaceName", map[string]any{"name": name, "workspace": workspace})
|
||||
}
|
||||
|
||||
func ActionUnsetWorkspaceName(reference Option[WorkspaceReferenceArg]) Action {
|
||||
return ActionCustom("UnsetWorkspaceName", map[string]any{"reference": reference})
|
||||
}
|
||||
|
||||
func ActionFocusMonitorLeft() Action {
|
||||
return ActionCustom("FocusMonitorLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusMonitorRight() Action {
|
||||
return ActionCustom("FocusMonitorRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusMonitorDown() Action {
|
||||
return ActionCustom("FocusMonitorDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusMonitorUp() Action {
|
||||
return ActionCustom("FocusMonitorUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusMonitorPrevious() Action {
|
||||
return ActionCustom("FocusMonitorPrevious", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusMonitorNext() Action {
|
||||
return ActionCustom("FocusMonitorNext", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusMonitor(output OutputName) Action {
|
||||
return ActionCustom("FocusMonitorNext", map[string]any{"output": output})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToMonitorLeft() Action {
|
||||
return ActionCustom("MoveWindowToMonitorLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToMonitorRight() Action {
|
||||
return ActionCustom("MoveWindowToMonitorRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToMonitorDown() Action {
|
||||
return ActionCustom("MoveWindowToMonitorDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToMonitorUp() Action {
|
||||
return ActionCustom("MoveWindowToMonitorUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToMonitorPrevious() Action {
|
||||
return ActionCustom("MoveWindowToMonitorPrevious", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToMonitorNext() Action {
|
||||
return ActionCustom("MoveWindowToMonitorNext", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToMonitor(id Option[WindowID], output OutputName) Action {
|
||||
return ActionCustom("FocusMonitorNext", map[string]any{"id": id, "output": output})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToMonitorLeft() Action {
|
||||
return ActionCustom("MoveColumnToMonitorLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToMonitorRight() Action {
|
||||
return ActionCustom("MoveColumnToMonitorRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToMonitorDown() Action {
|
||||
return ActionCustom("MoveColumnToMonitorDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToMonitorUp() Action {
|
||||
return ActionCustom("MoveColumnToMonitorUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToMonitorPrevious() Action {
|
||||
return ActionCustom("MoveColumnToMonitorPrevious", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToMonitorNext() Action {
|
||||
return ActionCustom("MoveColumnToMonitorNext", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveColumnToMonitor(output OutputName) Action {
|
||||
return ActionCustom("FocusMonitorNext", map[string]any{"output": output})
|
||||
}
|
||||
|
||||
func ActionSetWindowWidth(id Option[WindowID], change SizeChange) Action {
|
||||
return ActionCustom("SetWindowWidth", map[string]any{"id": id, "change": change})
|
||||
}
|
||||
|
||||
func ActionSetWindowHeight(id Option[WindowID], change SizeChange) Action {
|
||||
return ActionCustom("SetWindowHeight", map[string]any{"id": id, "change": change})
|
||||
}
|
||||
|
||||
func ActionResetWindowHeight(id Option[WindowID]) Action {
|
||||
return ActionCustom("ResetWindowHeight", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionSwitchPresetColumnWidth() Action {
|
||||
return ActionCustom("SwitchPresetColumnWidth", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionSwitchPresetWindowWidth(id Option[WindowID]) Action {
|
||||
return ActionCustom("SwitchPresetWindowWidth", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionSwitchPresetWindowHeight(id Option[WindowID]) Action {
|
||||
return ActionCustom("SwitchPresetWindowHeight", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionMaximizeColumn() Action {
|
||||
return ActionCustom("MaximizeColumn", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionSetColumnWidth(change SizeChange) Action {
|
||||
return ActionCustom("SetColumnWidth", map[string]any{"change": change})
|
||||
}
|
||||
|
||||
func ActionExpandColumnToAvailableWidth() Action {
|
||||
return ActionCustom("ExpandColumnToAvailableWidth", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionSwitchLayout(layout LayoutSwitchTarget) Action {
|
||||
return ActionCustom("SwitchLayout", map[string]any{"layout": layout})
|
||||
}
|
||||
|
||||
func ActionShowHotkeyOverlay() Action {
|
||||
return ActionCustom("ShowHotkeyOverlay", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceToMonitorLeft() Action {
|
||||
return ActionCustom("MoveWorkspaceToMonitorLeft", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceToMonitorRight() Action {
|
||||
return ActionCustom("MoveWorkspaceToMonitorRight", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceToMonitorDown() Action {
|
||||
return ActionCustom("MoveWorkspaceToMonitorDown", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceToMonitorUp() Action {
|
||||
return ActionCustom("MoveWorkspaceToMonitorUp", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceToMonitorPrevious() Action {
|
||||
return ActionCustom("MoveWorkspaceToMonitorPrevious", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceToMonitorNext() Action {
|
||||
return ActionCustom("MoveWorkspaceToMonitorNext", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveWorkspaceToMonitor(output OutputName, reference Option[WorkspaceReferenceArg]) Action {
|
||||
return ActionCustom("MoveWorkspaceToMonitor", map[string]any{"output": output, "reference": reference})
|
||||
}
|
||||
|
||||
func ActionToggleDebugTint() Action {
|
||||
return ActionCustom("ToggleDebugTint", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionDebugToggleOpaqueRegions() Action {
|
||||
return ActionCustom("DebugToggleOpaqueRegions", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionDebugToggleDamage() Action {
|
||||
return ActionCustom("DebugToggleDamage", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionToggleWindowFloating(id Option[WindowID]) Action {
|
||||
return ActionCustom("ToggleWindowFloating", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToFloating(id Option[WindowID]) Action {
|
||||
return ActionCustom("MoveWindowToFloating", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionMoveWindowToTiling(id Option[WindowID]) Action {
|
||||
return ActionCustom("MoveWindowToTiling", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionFocusFloating() Action {
|
||||
return ActionCustom("FocusFloating", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionFocusTiling() Action {
|
||||
return ActionCustom("FocusTiling", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionSwitchFocusBetweenFloatingAndTiling() Action {
|
||||
return ActionCustom("SwitchFocusBetweenFloatingAndTiling", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionMoveFloatingWindow(id Option[WindowID], x PositionChange, y PositionChange) Action {
|
||||
return ActionCustom("MoveFloatingWindow", map[string]any{"id": id, "x": x, "y": y})
|
||||
}
|
||||
|
||||
func ActionToggleWindowRuleOpacity(id Option[WindowID]) Action {
|
||||
return ActionCustom("ToggleWindowRuleOpacity", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionSetDynamicCastWindow(id Option[WindowID]) Action {
|
||||
return ActionCustom("SetDynamicCastWindow", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionSetDynamicCastMonitor(output Option[OutputName]) Action {
|
||||
return ActionCustom("SetDynamicCastMonitor", map[string]any{"output": output})
|
||||
}
|
||||
|
||||
func ActionClearDynamicCastTarget() Action {
|
||||
return ActionCustom("ClearDynamicCastTarget", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionToggleOverview() Action {
|
||||
return ActionCustom("ToggleOverview", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionOpenOverview() Action {
|
||||
return ActionCustom("OpenOverview", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionCloseOverview() Action {
|
||||
return ActionCustom("CloseOverview", map[string]any{})
|
||||
}
|
||||
|
||||
func ActionToggleWindowUrgent(id Option[WindowID]) Action {
|
||||
return ActionCustom("ToggleWindowUrgent", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionSetWindowUrgent(id Option[WindowID]) Action {
|
||||
return ActionCustom("SetWindowUrgent", map[string]any{"id": id})
|
||||
}
|
||||
|
||||
func ActionUnsetWindowUrgent(id Option[WindowID]) Action {
|
||||
return ActionCustom("UnsetWindowUrgent", map[string]any{"id": id})
|
||||
}
|
109
model_client.go
Normal file
109
model_client.go
Normal file
@ -0,0 +1,109 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"git.tordarus.net/tordarus/slices"
|
||||
"github.com/adrg/xdg"
|
||||
)
|
||||
|
||||
var niriSocketFilenameFormat = "niri.wayland-%d.%d.sock"
|
||||
var niriSocketFilenamePattern = regexp.MustCompile(`^niri\.wayland-(\d+?)\.(\d+?)\.sock$`)
|
||||
|
||||
type Client struct {
|
||||
display int
|
||||
pid int
|
||||
}
|
||||
|
||||
var ErrClientNotFound = errors.New("client not found")
|
||||
|
||||
func GetClientByPID(pid int) (*Client, error) {
|
||||
clients, err := GetAllClients()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range clients {
|
||||
if c.pid == pid {
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrClientNotFound
|
||||
}
|
||||
|
||||
func GetClientByDisplay(display int) (*Client, error) {
|
||||
clients, err := GetAllClients()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range clients {
|
||||
if c.display == display {
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, ErrClientNotFound
|
||||
}
|
||||
|
||||
func GetDefaultClient() (*Client, error) {
|
||||
if niriSocket, ok := os.LookupEnv("NIRI_SOCKET"); ok {
|
||||
return GetClientBySocketPath(niriSocket)
|
||||
}
|
||||
|
||||
if display, ok := os.LookupEnv("WAYLAND_DISPLAY"); ok {
|
||||
displayInt, err := strconv.Atoi(display)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return GetClientByDisplay(displayInt)
|
||||
}
|
||||
|
||||
return nil, ErrClientNotFound
|
||||
}
|
||||
|
||||
func GetAllClients() ([]*Client, error) {
|
||||
runtimeDir := xdg.RuntimeDir
|
||||
|
||||
entries, err := os.ReadDir(runtimeDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return slices.Filter(slices.Map(entries, parseEntryAsClient), notNull), nil
|
||||
}
|
||||
|
||||
func GetClientBySocketPath(socketPath string) (*Client, error) {
|
||||
baseName := filepath.Base(socketPath)
|
||||
|
||||
matches := niriSocketFilenamePattern.FindStringSubmatch(baseName)
|
||||
if matches == nil {
|
||||
return nil, errors.New("invalid niri socket path")
|
||||
}
|
||||
|
||||
display, err := strconv.Atoi(matches[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(matches[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Client{
|
||||
display: display,
|
||||
pid: pid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c Client) GetSocketPath() string {
|
||||
return filepath.Join(xdg.RuntimeDir, fmt.Sprintf(niriSocketFilenameFormat, c.display, c.pid))
|
||||
}
|
19
model_color.go
Normal file
19
model_color.go
Normal file
@ -0,0 +1,19 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
)
|
||||
|
||||
type niriColor struct {
|
||||
RGB [3]float64 `json:"rgb"`
|
||||
}
|
||||
|
||||
func (c niriColor) AsColor() color.Color {
|
||||
return color.NRGBA64{
|
||||
R: uint16(c.RGB[0] * math.MaxUint16),
|
||||
G: uint16(c.RGB[1] * math.MaxUint16),
|
||||
B: uint16(c.RGB[2] * math.MaxUint16),
|
||||
A: math.MaxUint16,
|
||||
}
|
||||
}
|
8
model_column_display.go
Normal file
8
model_column_display.go
Normal file
@ -0,0 +1,8 @@
|
||||
package niri
|
||||
|
||||
type ColumnDisplay string
|
||||
|
||||
const (
|
||||
ColumnDisplayNormal ColumnDisplay = "Normal"
|
||||
ColumnDisplayTabbed ColumnDisplay = "Tabbed"
|
||||
)
|
198
model_event.go
Normal file
198
model_event.go
Normal file
@ -0,0 +1,198 @@
|
||||
package niri
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type Event interface {
|
||||
private()
|
||||
}
|
||||
|
||||
type eventContainer struct {
|
||||
EventWorkspacesChanged *EventWorkspacesChanged `json:"WorkspacesChanged"`
|
||||
EventWorkspaceUrgencyChanged *EventWorkspaceUrgencyChanged `json:"WorkspaceUrgencyChanged"`
|
||||
EventWorkspaceActivated *EventWorkspaceActivated `json:"WorkspaceActivated"`
|
||||
EventWorkspaceActiveWindowChanged *EventWorkspaceActiveWindowChanged `json:"WorkspaceActiveWindowChanged"`
|
||||
EventWindowsChanged *EventWindowsChanged `json:"WindowsChanged"`
|
||||
EventWindowOpenedOrChanged *EventWindowOpenedOrChanged `json:"WindowOpenedOrChanged"`
|
||||
EventWindowClosed *EventWindowClosed `json:"WindowClosed"`
|
||||
EventWindowFocusChanged *EventWindowFocusChanged `json:"WindowFocusChanged"`
|
||||
EventWindowUrgencyChanged *EventWindowUrgencyChanged `json:"WindowUrgencyChanged"`
|
||||
EventKeyboardLayoutsChanged *EventKeyboardLayoutsChanged `json:"KeyboardLayoutsChanged"`
|
||||
EventKeyboardLayoutSwitched *EventKeyboardLayoutSwitched `json:"KeyboardLayoutSwitched"`
|
||||
EventOverviewOpenedOrClosed *EventOverviewOpenedOrClosed `json:"OverviewOpenedOrClosed"`
|
||||
}
|
||||
|
||||
func (c *eventContainer) event() Event {
|
||||
if c.EventWorkspacesChanged != nil {
|
||||
return c.EventWorkspacesChanged
|
||||
} else if c.EventWorkspaceUrgencyChanged != nil {
|
||||
return c.EventWorkspaceUrgencyChanged
|
||||
} else if c.EventWorkspaceActivated != nil {
|
||||
return c.EventWorkspaceActivated
|
||||
} else if c.EventWorkspaceActiveWindowChanged != nil {
|
||||
return c.EventWorkspaceActiveWindowChanged
|
||||
} else if c.EventWindowsChanged != nil {
|
||||
return c.EventWindowsChanged
|
||||
} else if c.EventWindowOpenedOrChanged != nil {
|
||||
return c.EventWindowOpenedOrChanged
|
||||
} else if c.EventWindowClosed != nil {
|
||||
return c.EventWindowClosed
|
||||
} else if c.EventWindowFocusChanged != nil {
|
||||
return c.EventWindowFocusChanged
|
||||
} else if c.EventWindowUrgencyChanged != nil {
|
||||
return c.EventWindowUrgencyChanged
|
||||
} else if c.EventKeyboardLayoutsChanged != nil {
|
||||
return c.EventKeyboardLayoutsChanged
|
||||
} else if c.EventKeyboardLayoutSwitched != nil {
|
||||
return c.EventKeyboardLayoutSwitched
|
||||
} else if c.EventOverviewOpenedOrClosed != nil {
|
||||
return c.EventOverviewOpenedOrClosed
|
||||
}
|
||||
|
||||
return &EventInvalid{}
|
||||
}
|
||||
|
||||
type EventInvalid struct {
|
||||
}
|
||||
|
||||
func (m *EventInvalid) private() {}
|
||||
|
||||
func (m *EventInvalid) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventWorkspacesChanged struct {
|
||||
Workspaces []Workspace `json:"workspaces"`
|
||||
}
|
||||
|
||||
func (m *EventWorkspacesChanged) private() {}
|
||||
|
||||
func (m *EventWorkspacesChanged) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventWorkspaceUrgencyChanged struct {
|
||||
ID WorkspaceID `json:"id"`
|
||||
Urgent bool `json:"urgent"`
|
||||
}
|
||||
|
||||
func (m *EventWorkspaceUrgencyChanged) private() {}
|
||||
|
||||
func (m *EventWorkspaceUrgencyChanged) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventWorkspaceActivated struct {
|
||||
ID WorkspaceID `json:"id"`
|
||||
Focused bool `json:"focused"`
|
||||
}
|
||||
|
||||
func (m *EventWorkspaceActivated) private() {}
|
||||
|
||||
func (m *EventWorkspaceActivated) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventWorkspaceActiveWindowChanged struct {
|
||||
WorkspaceID WorkspaceID `json:"workspace_id"`
|
||||
ActiveWindowID Option[WindowID] `json:"active_window_id"`
|
||||
}
|
||||
|
||||
func (m *EventWorkspaceActiveWindowChanged) private() {}
|
||||
|
||||
func (m *EventWorkspaceActiveWindowChanged) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventWindowsChanged struct {
|
||||
Windows []Window `json:"windows"`
|
||||
}
|
||||
|
||||
func (m *EventWindowsChanged) private() {}
|
||||
|
||||
func (m *EventWindowsChanged) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventWindowOpenedOrChanged struct {
|
||||
Window Window `json:"window"`
|
||||
}
|
||||
|
||||
func (m *EventWindowOpenedOrChanged) private() {}
|
||||
|
||||
func (m *EventWindowOpenedOrChanged) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventWindowClosed struct {
|
||||
ID WindowID `json:"id"`
|
||||
}
|
||||
|
||||
func (m *EventWindowClosed) private() {}
|
||||
|
||||
func (m *EventWindowClosed) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventWindowFocusChanged struct {
|
||||
ID Option[WindowID] `json:"id"`
|
||||
}
|
||||
|
||||
func (m *EventWindowFocusChanged) private() {}
|
||||
|
||||
func (m *EventWindowFocusChanged) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventWindowUrgencyChanged struct {
|
||||
ID WindowID `json:"id"`
|
||||
Urgent bool `json:"urgent"`
|
||||
}
|
||||
|
||||
func (m *EventWindowUrgencyChanged) private() {}
|
||||
|
||||
func (m *EventWindowUrgencyChanged) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventKeyboardLayoutsChanged struct {
|
||||
KeyboardLayouts KeyboardLayouts `json:"keyboard_layouts"`
|
||||
}
|
||||
|
||||
func (m *EventKeyboardLayoutsChanged) private() {}
|
||||
|
||||
func (m *EventKeyboardLayoutsChanged) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventKeyboardLayoutSwitched struct {
|
||||
Index int `json:"idx"`
|
||||
}
|
||||
|
||||
func (m *EventKeyboardLayoutSwitched) private() {}
|
||||
|
||||
func (m *EventKeyboardLayoutSwitched) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type EventOverviewOpenedOrClosed struct {
|
||||
IsOpen bool `json:"is_open"`
|
||||
}
|
||||
|
||||
func (m *EventOverviewOpenedOrClosed) private() {}
|
||||
|
||||
func (m *EventOverviewOpenedOrClosed) String() string {
|
||||
data, _ := json.Marshal(m)
|
||||
return string(data)
|
||||
}
|
13
model_keyboard_layout.go
Normal file
13
model_keyboard_layout.go
Normal file
@ -0,0 +1,13 @@
|
||||
package niri
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type KeyboardLayouts struct {
|
||||
Names []string `json:"names"`
|
||||
CurrentIndex int `json:"current_idx"`
|
||||
}
|
||||
|
||||
func (m KeyboardLayouts) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
32
model_layersurface.go
Normal file
32
model_layersurface.go
Normal file
@ -0,0 +1,32 @@
|
||||
package niri
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type LayerSurface struct {
|
||||
Namespace string `json:"namespace"`
|
||||
Output OutputName `json:"output"`
|
||||
Layer Layer `json:"layer"`
|
||||
KeyboardInteractivity LayerSurfaceKeyboardInteractivity `json:"keyboard_interactivity"`
|
||||
}
|
||||
|
||||
func (m LayerSurface) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type Layer string
|
||||
|
||||
const (
|
||||
LayerBackground Layer = "Background"
|
||||
LayerBottom Layer = "Bottom"
|
||||
LayerTop Layer = "Top"
|
||||
LayerOverlay Layer = "Overlay"
|
||||
)
|
||||
|
||||
type LayerSurfaceKeyboardInteractivity string
|
||||
|
||||
const (
|
||||
KeyboardInteractivityNone LayerSurfaceKeyboardInteractivity = "None"
|
||||
KeyboardInteractivityExclusive LayerSurfaceKeyboardInteractivity = "Exclusive"
|
||||
KeyboardInteractivityOnDemand LayerSurfaceKeyboardInteractivity = "OnDemand"
|
||||
)
|
36
model_layout_switch_target.go
Normal file
36
model_layout_switch_target.go
Normal file
@ -0,0 +1,36 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type LayoutSwitchTarget struct {
|
||||
prev Option[bool]
|
||||
next Option[bool]
|
||||
index Option[int]
|
||||
}
|
||||
|
||||
func LayoutSwitchTargetPrev() LayoutSwitchTarget {
|
||||
return LayoutSwitchTarget{prev: OptionOf(true)}
|
||||
}
|
||||
|
||||
func LayoutSwitchTargetNext() LayoutSwitchTarget {
|
||||
return LayoutSwitchTarget{next: OptionOf(true)}
|
||||
}
|
||||
|
||||
func LayoutSwitchTargetIndex(index int) LayoutSwitchTarget {
|
||||
return LayoutSwitchTarget{index: OptionOf(index)}
|
||||
}
|
||||
|
||||
func (m LayoutSwitchTarget) MarshalJSON() ([]byte, error) {
|
||||
if m.prev != nil {
|
||||
return json.Marshal("Prev")
|
||||
} else if m.next != nil {
|
||||
return json.Marshal("Next")
|
||||
} else if m.index != nil {
|
||||
return json.Marshal(map[string]int{"Index": *m.index})
|
||||
}
|
||||
|
||||
return nil, errors.New("LayoutSwitchTarget.MarshalJson()")
|
||||
}
|
18
model_option.go
Normal file
18
model_option.go
Normal file
@ -0,0 +1,18 @@
|
||||
package niri
|
||||
|
||||
type Option[T any] = *T
|
||||
|
||||
func OptionOf[T any](v T) Option[T] {
|
||||
return &v
|
||||
}
|
||||
|
||||
func OptionEmpty[T any]() Option[T] {
|
||||
return nil
|
||||
}
|
||||
|
||||
func mapOption[T any, R any](o Option[T], mapper func(T) R) Option[R] {
|
||||
if o == nil {
|
||||
return nil
|
||||
}
|
||||
return OptionOf(mapper(*o))
|
||||
}
|
70
model_output.go
Normal file
70
model_output.go
Normal file
@ -0,0 +1,70 @@
|
||||
package niri
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type OutputName string
|
||||
|
||||
type Output struct {
|
||||
Name OutputName `json:"name"`
|
||||
Make string `json:"make"`
|
||||
Model string `json:"model"`
|
||||
Serial string `json:"serial"`
|
||||
PhysicalSize [2]int `json:"physical_size"`
|
||||
Modes []OutputMode `json:"modes"`
|
||||
CurrentMode int `json:"current_mode"`
|
||||
VrrSupported bool `json:"vrr_supported"`
|
||||
VrrEnabled bool `json:"vrr_enabled"`
|
||||
Logical OutputLogical `json:"logical"`
|
||||
}
|
||||
|
||||
func (m Output) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type OutputMode struct {
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
RefreshRate int `json:"refresh_rate"`
|
||||
IsPreferred bool `json:"is_preferred"`
|
||||
}
|
||||
|
||||
func (m OutputMode) Configured() ConfiguredMode {
|
||||
return ConfiguredMode{
|
||||
Width: m.Width,
|
||||
Height: m.Height,
|
||||
Refresh: OptionOf(float64(m.RefreshRate) / 100),
|
||||
}
|
||||
}
|
||||
|
||||
func (m OutputMode) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type OutputLogical struct {
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Scale float64 `json:"scale"`
|
||||
Transform OutputTransform `json:"transform"`
|
||||
}
|
||||
|
||||
func (m OutputLogical) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
||||
|
||||
type OutputTransform string
|
||||
|
||||
const (
|
||||
TransformNormal OutputTransform = "Normal"
|
||||
Transform90 OutputTransform = "90"
|
||||
Transform180 OutputTransform = "180"
|
||||
Transform270 OutputTransform = "270"
|
||||
TransformFlipped OutputTransform = "Flipped"
|
||||
TransformFlipped90 OutputTransform = "Flipped90"
|
||||
TransformFlipped180 OutputTransform = "Flipped180"
|
||||
TransformFlipped270 OutputTransform = "Flipped270"
|
||||
)
|
87
model_output_action.go
Normal file
87
model_output_action.go
Normal file
@ -0,0 +1,87 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type OutputActionRequest struct {
|
||||
Output OutputName `json:"output"`
|
||||
Action OutputAction `json:"action"`
|
||||
}
|
||||
|
||||
type outputActionResponse struct {
|
||||
OutputConfigChanged string `json:"OutputConfigChanged"`
|
||||
}
|
||||
|
||||
type OutputAction struct {
|
||||
off Option[bool]
|
||||
on Option[bool]
|
||||
mode Option[ModeToSet]
|
||||
scale Option[ScaleToSet]
|
||||
transform Option[OutputTransform]
|
||||
position Option[PositionToSet]
|
||||
vrr Option[ConfiguredVrr]
|
||||
}
|
||||
|
||||
func OutputActionOff(output string) OutputActionRequest {
|
||||
return OutputActionRequest{
|
||||
Output: OutputName(output),
|
||||
Action: OutputAction{off: OptionOf(true)},
|
||||
}
|
||||
}
|
||||
|
||||
func OutputActionOn(output string) OutputActionRequest {
|
||||
return OutputActionRequest{
|
||||
Output: OutputName(output),
|
||||
Action: OutputAction{on: OptionOf(true)},
|
||||
}
|
||||
}
|
||||
|
||||
func OutputActionMode(output string, mode ModeToSet) OutputActionRequest {
|
||||
return OutputActionRequest{
|
||||
Output: OutputName(output),
|
||||
Action: OutputAction{mode: OptionOf(mode)},
|
||||
}
|
||||
}
|
||||
|
||||
func OutputActionScale(output string, scale ScaleToSet) OutputActionRequest {
|
||||
return OutputActionRequest{
|
||||
Output: OutputName(output),
|
||||
Action: OutputAction{scale: OptionOf(scale)},
|
||||
}
|
||||
}
|
||||
|
||||
func OutputActionTransform(output string, transform OutputTransform) OutputActionRequest {
|
||||
return OutputActionRequest{
|
||||
Output: OutputName(output),
|
||||
Action: OutputAction{transform: OptionOf(transform)},
|
||||
}
|
||||
}
|
||||
|
||||
func OutputActionVrr(output string, vrr ConfiguredVrr) OutputActionRequest {
|
||||
return OutputActionRequest{
|
||||
Output: OutputName(output),
|
||||
Action: OutputAction{vrr: OptionOf(vrr)},
|
||||
}
|
||||
}
|
||||
|
||||
func (m OutputAction) MarshalJSON() ([]byte, error) {
|
||||
if m.off != nil {
|
||||
return json.Marshal("Off")
|
||||
} else if m.on != nil {
|
||||
return json.Marshal("On")
|
||||
} else if m.mode != nil {
|
||||
return json.Marshal(map[string]map[string]ModeToSet{"Mode": {"mode": *m.mode}})
|
||||
} else if m.scale != nil {
|
||||
return json.Marshal(map[string]map[string]ScaleToSet{"Scale": {"scale": *m.scale}})
|
||||
} else if m.transform != nil {
|
||||
return json.Marshal(map[string]map[string]OutputTransform{"Transform": {"transform": *m.transform}})
|
||||
} else if m.position != nil {
|
||||
return json.Marshal(map[string]map[string]PositionToSet{"Position": {"position": *m.position}})
|
||||
} else if m.vrr != nil {
|
||||
return json.Marshal(map[string]map[string]ConfiguredVrr{"Vrr": {"vrr": *m.vrr}})
|
||||
}
|
||||
|
||||
return nil, errors.New("OutputAction.MarshalJson()")
|
||||
}
|
17
model_output_action_configured_models.go
Normal file
17
model_output_action_configured_models.go
Normal file
@ -0,0 +1,17 @@
|
||||
package niri
|
||||
|
||||
type ConfiguredMode struct {
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Refresh Option[float64] `json:"refresh,omitempty"`
|
||||
}
|
||||
|
||||
type ConfiguredPosition struct {
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
}
|
||||
|
||||
type ConfiguredVrr struct {
|
||||
Vrr bool `json:"vrr"`
|
||||
OnDemand bool `json:"on_demand"`
|
||||
}
|
75
model_output_toset.go
Normal file
75
model_output_toset.go
Normal file
@ -0,0 +1,75 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
json "encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type ModeToSet struct {
|
||||
automatic Option[bool]
|
||||
specific Option[ConfiguredMode]
|
||||
}
|
||||
|
||||
func OutputActionModeAutomatic() ModeToSet {
|
||||
return ModeToSet{automatic: OptionOf(true)}
|
||||
}
|
||||
|
||||
func OutputActionModeSpecific(mode ConfiguredMode) ModeToSet {
|
||||
return ModeToSet{specific: OptionOf(mode)}
|
||||
}
|
||||
|
||||
func (m ModeToSet) MarshalJSON() ([]byte, error) {
|
||||
if m.automatic != nil {
|
||||
return json.Marshal("Automatic")
|
||||
} else if m.specific != nil {
|
||||
return json.Marshal(map[string]any{"Specific": m.specific})
|
||||
}
|
||||
|
||||
return nil, errors.New("ModeToSet.MarshalJson()")
|
||||
}
|
||||
|
||||
type ScaleToSet struct {
|
||||
automatic Option[bool]
|
||||
specific Option[float64]
|
||||
}
|
||||
|
||||
func OutputActionScaleAutomatic() ScaleToSet {
|
||||
return ScaleToSet{automatic: OptionOf(true)}
|
||||
}
|
||||
|
||||
func OutputActionScaleSpecific(scale float64) ScaleToSet {
|
||||
return ScaleToSet{specific: OptionOf(scale)}
|
||||
}
|
||||
|
||||
func (m ScaleToSet) MarshalJSON() ([]byte, error) {
|
||||
if m.automatic != nil {
|
||||
return json.Marshal("Automatic")
|
||||
} else if m.specific != nil {
|
||||
return json.Marshal(map[string]any{"Specific": m.specific})
|
||||
}
|
||||
|
||||
return nil, errors.New("ScaleToSet.MarshalJson()")
|
||||
}
|
||||
|
||||
type PositionToSet struct {
|
||||
automatic Option[bool]
|
||||
specific Option[ConfiguredPosition]
|
||||
}
|
||||
|
||||
func OutputActionPositionAutomatic() *PositionToSet {
|
||||
return &PositionToSet{automatic: OptionOf(true)}
|
||||
}
|
||||
|
||||
func OutputActionPositionSpecific(position ConfiguredPosition) *PositionToSet {
|
||||
return &PositionToSet{specific: OptionOf(position)}
|
||||
}
|
||||
|
||||
func (m PositionToSet) MarshalJSON() ([]byte, error) {
|
||||
if m.automatic != nil {
|
||||
return json.Marshal("Automatic")
|
||||
} else if m.specific != nil {
|
||||
return json.Marshal(m.specific)
|
||||
}
|
||||
|
||||
return nil, errors.New("PositionToSet.MarshalJson()")
|
||||
}
|
12
model_overview_state.go
Normal file
12
model_overview_state.go
Normal file
@ -0,0 +1,12 @@
|
||||
package niri
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type overviewState struct {
|
||||
IsOpen bool `json:"is_open"`
|
||||
}
|
||||
|
||||
func (m overviewState) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
61
model_position_change.go
Normal file
61
model_position_change.go
Normal file
@ -0,0 +1,61 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type PositionChange struct {
|
||||
SetFixed Option[int] `json:"SetFixed,omitempty"`
|
||||
AdjustFixed Option[int] `json:"AdjustFixed,omitempty"`
|
||||
}
|
||||
|
||||
func (m PositionChange) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func PositionSetFixed(position int) PositionChange {
|
||||
return PositionChange{SetFixed: &position}
|
||||
}
|
||||
|
||||
func PositionAdjustFixed(position int) PositionChange {
|
||||
return PositionChange{AdjustFixed: &position}
|
||||
}
|
||||
|
||||
const positionPatternString = `^(\+|-)?(\d+?)$`
|
||||
const positionPatternGroupAdjust = 1
|
||||
const positionPatternGroupIntValue = 2
|
||||
|
||||
var positionPattern = regexp.MustCompile(positionPatternString)
|
||||
|
||||
func ParsePosition(str string) (PositionChange, error) {
|
||||
matches := positionPattern.FindStringSubmatch(str)
|
||||
if matches == nil {
|
||||
return PositionChange{}, fmt.Errorf("invalid position spec '%s'. Expected pattern: %s", str, positionPatternString)
|
||||
}
|
||||
|
||||
adjust := matches[positionPatternGroupAdjust] != ""
|
||||
negative := matches[positionPatternGroupAdjust] == "-"
|
||||
|
||||
factor := 1
|
||||
if negative {
|
||||
factor = -1
|
||||
}
|
||||
|
||||
intValue, err := strconv.ParseInt(matches[positionPatternGroupIntValue], 10, 64)
|
||||
if err != nil {
|
||||
return PositionChange{}, fmt.Errorf("invalid position spec '%s'. Expected pattern: %s", str, positionPatternString)
|
||||
}
|
||||
|
||||
switch true {
|
||||
case adjust:
|
||||
return PositionAdjustFixed(int(intValue) * factor), nil
|
||||
case !adjust:
|
||||
return PositionSetFixed(int(intValue) * factor), nil
|
||||
default:
|
||||
return PositionChange{}, fmt.Errorf("invalid position spec '%s'. Expected pattern: %s", str, positionPatternString)
|
||||
}
|
||||
}
|
11
model_response.go
Normal file
11
model_response.go
Normal file
@ -0,0 +1,11 @@
|
||||
package niri
|
||||
|
||||
type Response[T any] struct {
|
||||
OK *T `json:"Ok"`
|
||||
Err *string `json:"Err"`
|
||||
}
|
||||
|
||||
func errResponse[T any](err error) Response[T] {
|
||||
errStr := err.Error()
|
||||
return Response[T]{Err: &errStr}
|
||||
}
|
83
model_size_change.go
Normal file
83
model_size_change.go
Normal file
@ -0,0 +1,83 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type SizeChange struct {
|
||||
SetFixed *int `json:"SetFixed,omitempty"`
|
||||
SetProportion *float64 `json:"SetProportion,omitempty"`
|
||||
AdjustFixed *int `json:"AdjustFixed,omitempty"`
|
||||
AdjustProportion *float64 `json:"AdjustProportion,omitempty"`
|
||||
}
|
||||
|
||||
func (m SizeChange) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
||||
|
||||
func SizeSetFixed(size int) SizeChange {
|
||||
return SizeChange{SetFixed: &size}
|
||||
}
|
||||
|
||||
func SizeSetProportion(size float64) SizeChange {
|
||||
return SizeChange{SetProportion: &size}
|
||||
}
|
||||
|
||||
func SizeAdjustFixed(size int) SizeChange {
|
||||
return SizeChange{AdjustFixed: &size}
|
||||
}
|
||||
|
||||
func SizeAdjustProportion(size float64) SizeChange {
|
||||
return SizeChange{AdjustProportion: &size}
|
||||
}
|
||||
|
||||
const sizePatternString = `^(\+|-)?((\d+?)(?:\.\d+)?)(%)?$`
|
||||
const sizePatternGroupAdjust = 1
|
||||
const sizePatternGroupFloatValue = 2
|
||||
const sizePatternGroupIntValue = 3
|
||||
const sizePatternGroupPercentage = 4
|
||||
|
||||
var sizePattern = regexp.MustCompile(sizePatternString)
|
||||
|
||||
func ParseSize(str string) (SizeChange, error) {
|
||||
matches := sizePattern.FindStringSubmatch(str)
|
||||
if matches == nil {
|
||||
return SizeChange{}, fmt.Errorf("invalid size spec '%s'. Expected pattern: %s", str, sizePatternString)
|
||||
}
|
||||
|
||||
adjust := matches[sizePatternGroupAdjust] != ""
|
||||
proportion := matches[sizePatternGroupPercentage] == "%"
|
||||
negative := matches[sizePatternGroupAdjust] == "-"
|
||||
|
||||
factor := 1
|
||||
if negative {
|
||||
factor = -1
|
||||
}
|
||||
|
||||
floatValue, err := strconv.ParseFloat(matches[sizePatternGroupFloatValue], 64)
|
||||
if err != nil {
|
||||
return SizeChange{}, fmt.Errorf("invalid size spec '%s'. Expected pattern: %s", str, sizePatternString)
|
||||
}
|
||||
|
||||
intValue, err := strconv.ParseInt(matches[sizePatternGroupIntValue], 10, 64)
|
||||
if err != nil {
|
||||
return SizeChange{}, fmt.Errorf("invalid size spec '%s'. Expected pattern: %s", str, sizePatternString)
|
||||
}
|
||||
|
||||
switch true {
|
||||
case adjust && proportion:
|
||||
return SizeAdjustProportion(floatValue * float64(factor)), nil
|
||||
case adjust && !proportion:
|
||||
return SizeAdjustFixed(int(intValue) * factor), nil
|
||||
case !adjust && proportion:
|
||||
return SizeSetProportion(floatValue * float64(factor)), nil
|
||||
case !adjust && !proportion:
|
||||
return SizeSetFixed(int(intValue) * factor), nil
|
||||
default:
|
||||
return SizeChange{}, fmt.Errorf("invalid size spec '%s'. Expected pattern: %s", str, sizePatternString)
|
||||
}
|
||||
}
|
21
model_window.go
Normal file
21
model_window.go
Normal file
@ -0,0 +1,21 @@
|
||||
package niri
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type WindowID int
|
||||
|
||||
type Window struct {
|
||||
ID WindowID `json:"id"`
|
||||
Title string `json:"title"`
|
||||
AppID string `json:"app_id"`
|
||||
PID int `json:"pid"`
|
||||
WorkspaceID WorkspaceID `json:"workspace_id"`
|
||||
Urgent bool `json:"is_urgent"`
|
||||
Floating bool `json:"is_floating"`
|
||||
Focused bool `json:"is_focused"`
|
||||
}
|
||||
|
||||
func (m Window) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
20
model_workspace.go
Normal file
20
model_workspace.go
Normal file
@ -0,0 +1,20 @@
|
||||
package niri
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type WorkspaceID int
|
||||
|
||||
type Workspace struct {
|
||||
ID WorkspaceID `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Output string `json:"output"`
|
||||
Urgent bool `json:"is_urgent"`
|
||||
Active bool `json:"is_active"`
|
||||
Focused bool `json:"is_focused"`
|
||||
ActiveWindowID WindowID `json:"active_window_id"`
|
||||
}
|
||||
|
||||
func (m Workspace) String() string {
|
||||
data, _ := json.MarshalIndent(m, "", "\t")
|
||||
return string(data)
|
||||
}
|
19
model_workspace_reference.go
Normal file
19
model_workspace_reference.go
Normal file
@ -0,0 +1,19 @@
|
||||
package niri
|
||||
|
||||
type WorkspaceReferenceArg struct {
|
||||
ID *WorkspaceID `json:"Id,omitempty"`
|
||||
Index *int `json:"Index,omitempty"`
|
||||
Name *string `json:"Name,omitempty"`
|
||||
}
|
||||
|
||||
func WorkspaceByID(id WorkspaceID) WorkspaceReferenceArg {
|
||||
return WorkspaceReferenceArg{ID: &id}
|
||||
}
|
||||
|
||||
func WorkspaceByIndex(index int) WorkspaceReferenceArg {
|
||||
return WorkspaceReferenceArg{Index: &index}
|
||||
}
|
||||
|
||||
func WorkspaceByName(name string) WorkspaceReferenceArg {
|
||||
return WorkspaceReferenceArg{Name: &name}
|
||||
}
|
113
utils.go
Normal file
113
utils.go
Normal file
@ -0,0 +1,113 @@
|
||||
package niri
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
)
|
||||
|
||||
func notNull(c *Client) bool {
|
||||
return c != nil
|
||||
}
|
||||
|
||||
func parseEntryAsClient(entry os.DirEntry) *Client {
|
||||
if entry.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
client, err := GetClientBySocketPath(entry.Name())
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
func readSocket[T any](socket string, body io.Reader) Response[T] {
|
||||
r, err := readSocketRaw(socket, body)
|
||||
if err != nil {
|
||||
return errResponse[T](err)
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
value := new(Response[T])
|
||||
if err := json.NewDecoder(r).Decode(value); err != nil {
|
||||
return errResponse[T](err)
|
||||
}
|
||||
return *value
|
||||
}
|
||||
|
||||
func subscribeSocket[T any](ctx context.Context, socket string, body io.Reader) (<-chan T, error) {
|
||||
ch, err := readSocketGeneric[T](ctx, socket, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make(chan T, 10)
|
||||
|
||||
go func() {
|
||||
defer close(out)
|
||||
|
||||
for {
|
||||
select {
|
||||
case event := <-ch:
|
||||
out <- event
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func readSocketGeneric[T any](ctx context.Context, socket string, body io.Reader) (<-chan T, error) {
|
||||
r, err := readSocketRaw(socket, body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make(chan T, 10)
|
||||
|
||||
go func() {
|
||||
defer close(out)
|
||||
defer r.Close()
|
||||
|
||||
for ctx.Err() == nil {
|
||||
value := new(T)
|
||||
if err := json.NewDecoder(r).Decode(value); err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
return
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
out <- *value
|
||||
}
|
||||
}()
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
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 asJsonReader(v any) io.Reader {
|
||||
data, _ := json.Marshal(v)
|
||||
return bytes.NewReader(append(data, '\n'))
|
||||
}
|
Reference in New Issue
Block a user