update
This commit is contained in:
parent
b4da3d53fd
commit
5e9454d225
|
@ -2,11 +2,14 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/jezek/xgbutil"
|
||||||
"tuxpa.in/t/wm/src/bsp"
|
"tuxpa.in/t/wm/src/bsp"
|
||||||
"tuxpa.in/t/wm/src/handler"
|
"tuxpa.in/t/wm/src/handler"
|
||||||
"tuxpa.in/t/wm/src/handler/domains"
|
"tuxpa.in/t/wm/src/handler/domains"
|
||||||
|
@ -14,13 +17,32 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// create socket
|
|
||||||
ln, err := sock.Server("./bspwm.sock")
|
err := _main()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
defer ln.Close()
|
|
||||||
|
}
|
||||||
|
func _main() error {
|
||||||
|
// connect to the x server
|
||||||
|
log.Printf("connecting to xorg")
|
||||||
|
x11, err := xgbutil.NewConn()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer x11.Conn().Close()
|
||||||
|
|
||||||
|
addr := parsePath(x11, "./bspwm.sock")
|
||||||
|
// create socket
|
||||||
log.Printf("starting bspwm")
|
log.Printf("starting bspwm")
|
||||||
|
ln, err := sock.Server(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer ln.Close()
|
||||||
|
|
||||||
|
// construct context
|
||||||
ctx, stop := signal.NotifyContext(context.Background(),
|
ctx, stop := signal.NotifyContext(context.Background(),
|
||||||
os.Interrupt,
|
os.Interrupt,
|
||||||
syscall.SIGTERM,
|
syscall.SIGTERM,
|
||||||
|
@ -28,31 +50,49 @@ func main() {
|
||||||
syscall.SIGINT,
|
syscall.SIGINT,
|
||||||
)
|
)
|
||||||
defer stop()
|
defer stop()
|
||||||
|
|
||||||
// initialize WM state
|
// initialize WM state
|
||||||
w := bsp.NewWM()
|
w := bsp.NewWM()
|
||||||
// create a wm manager
|
// create a wm-x11 connection
|
||||||
xwm := bsp.NewXWM(w, ln.X11())
|
xwm := bsp.NewXWM(w, x11)
|
||||||
// install the handler
|
// create a handler
|
||||||
h := &handler.Handler{
|
h := &handler.Handler{
|
||||||
XWM: xwm,
|
XWM: xwm,
|
||||||
}
|
}
|
||||||
|
// install the handlers
|
||||||
handler.AddDomain[domains.Todo](h, "node")
|
handler.AddDomain[domains.Todo](h, "node")
|
||||||
handler.AddDomain[domains.Todo](h, "desktop")
|
handler.AddDomain[domains.Todo](h, "desktop")
|
||||||
handler.AddDomain[domains.Todo](h, "monitor")
|
handler.AddDomain[domains.Todo](h, "monitor")
|
||||||
handler.AddDomain[domains.Todo](h, "wm")
|
handler.AddDomain[domains.Wm](h, "wm")
|
||||||
handler.AddDomain[domains.Todo](h, "rule")
|
handler.AddDomain[domains.Todo](h, "rule")
|
||||||
handler.AddDomain[domains.Todo](h, "config")
|
handler.AddDomain[domains.Todo](h, "config")
|
||||||
handler.AddDomain[domains.Todo](h, "subscribe")
|
handler.AddDomain[domains.Todo](h, "subscribe")
|
||||||
handler.AddDomain[domains.Todo](h, "quit")
|
handler.AddDomain[domains.Todo](h, "quit")
|
||||||
handler.AddDomain[domains.Query](h, "query")
|
handler.AddDomain[domains.Query](h, "query")
|
||||||
handler.AddDomain[domains.Echo](h, "echo")
|
handler.AddDomain[domains.Echo](h, "echo")
|
||||||
|
|
||||||
|
// message listen loop
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case m := <-ln.Msg():
|
case m := <-ln.Msg():
|
||||||
h.Run(m)
|
h.Run(m)
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
log.Println("bspwm shutting down...")
|
log.Println("bspwm shutting down...")
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parsePath(xc *xgbutil.XUtil, path string) *net.UnixAddr {
|
||||||
|
if path == "" {
|
||||||
|
path = os.Getenv(sock.SOCKET_ENV_VAR)
|
||||||
|
}
|
||||||
|
if path == "" {
|
||||||
|
path = fmt.Sprintf(sock.SOCKET_PATH_TPL, "", xc.Conn().DisplayNumber, xc.Conn().DefaultScreen)
|
||||||
|
}
|
||||||
|
addr, err := net.ResolveUnixAddr("unix", path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return addr
|
||||||
|
}
|
||||||
|
|
11
go.mod
11
go.mod
|
@ -8,4 +8,13 @@ replace github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0 => ./xgbutil
|
||||||
|
|
||||||
require github.com/jezek/xgb v1.1.0
|
require github.com/jezek/xgb v1.1.0
|
||||||
|
|
||||||
require github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0
|
require (
|
||||||
|
github.com/jezek/xgbutil v0.0.0-20230603163917-04188eb39cf0
|
||||||
|
github.com/stretchr/testify v1.8.4
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
|
|
10
go.sum
10
go.sum
|
@ -1,2 +1,12 @@
|
||||||
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ=
|
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ=
|
||||||
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=
|
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=
|
||||||
|
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.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
@ -0,0 +1,173 @@
|
||||||
|
package cfg
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"tuxpa.in/t/wm/src/copies"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Read will return the first non nil value or the default value
|
||||||
|
func Read[T any](xs ...*T) T {
|
||||||
|
for _, v := range xs {
|
||||||
|
if v != nil {
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// zero value if all else fails
|
||||||
|
return *new(T)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadFunc[T any, V any](fn func(*T) *V, xs ...*T) V {
|
||||||
|
for _, v := range xs {
|
||||||
|
if v == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
vv := fn(v)
|
||||||
|
if vv != nil {
|
||||||
|
return *vv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *new(V)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Modifier[T any] struct {
|
||||||
|
Ref T
|
||||||
|
|
||||||
|
setters map[string]func(v string) error
|
||||||
|
getters map[string]func() (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewModifier[T any](start T) *Modifier[T] {
|
||||||
|
m := &Modifier[T]{
|
||||||
|
Ref: start,
|
||||||
|
setters: map[string]func(v string) error{},
|
||||||
|
getters: map[string]func() (string, error){},
|
||||||
|
}
|
||||||
|
m.setup()
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Modifier[T]) Set(k, v string) error {
|
||||||
|
fn, ok := m.setters[k]
|
||||||
|
if !ok {
|
||||||
|
// TODO: some error here
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return fn(v)
|
||||||
|
}
|
||||||
|
func (m *Modifier[T]) GetString(k string) (string, error) {
|
||||||
|
fn, ok := m.getters[k]
|
||||||
|
if !ok {
|
||||||
|
// TODO: some error here
|
||||||
|
return "", fmt.Errorf("config key '%s' not found", k)
|
||||||
|
}
|
||||||
|
return fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Modifier[T]) FillDefaults() {
|
||||||
|
rt := reflect.TypeOf(m.Ref).Elem()
|
||||||
|
for i := 0; i < rt.NumField(); i++ {
|
||||||
|
ft := rt.Field(i)
|
||||||
|
k := ft.Tag.Get("cfg")
|
||||||
|
dv := ft.Tag.Get("default")
|
||||||
|
if dv == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m.Set(k, dv)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Modifier[T]) setup() {
|
||||||
|
// grab the value
|
||||||
|
rv := reflect.ValueOf(m.Ref).Elem()
|
||||||
|
rt := reflect.TypeOf(m.Ref).Elem()
|
||||||
|
for i := 0; i < rv.NumField(); i++ {
|
||||||
|
fv := rv.Field(i)
|
||||||
|
ft := rt.Field(i)
|
||||||
|
k := ft.Tag.Get("cfg")
|
||||||
|
kind := ft.Type.Elem().Kind()
|
||||||
|
switch kind {
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||||
|
m.setters[k] = func(v string) error {
|
||||||
|
val, err := strconv.ParseUint(v, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return copies.NewInvalidValueErr(k, v)
|
||||||
|
}
|
||||||
|
if fv.IsNil() {
|
||||||
|
fv.Set(reflect.New(ft.Type.Elem()))
|
||||||
|
}
|
||||||
|
fv.Elem().SetUint(uint64(val))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
m.getters[k] = func() (string, error) {
|
||||||
|
if fv.IsNil() {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", fv.Elem()), nil
|
||||||
|
}
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
m.setters[k] = func(v string) error {
|
||||||
|
val, err := strconv.Atoi(v)
|
||||||
|
if err != nil {
|
||||||
|
return copies.NewInvalidValueErr(k, v)
|
||||||
|
}
|
||||||
|
if fv.IsNil() {
|
||||||
|
fv.Set(reflect.New(ft.Type.Elem()))
|
||||||
|
}
|
||||||
|
fv.Elem().SetInt(int64(val))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
m.getters[k] = func() (string, error) {
|
||||||
|
if fv.IsNil() {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", fv.Elem()), nil
|
||||||
|
}
|
||||||
|
case reflect.Bool:
|
||||||
|
m.setters[k] = func(v string) error {
|
||||||
|
var b bool
|
||||||
|
switch strings.ToLower(v) {
|
||||||
|
case "true", "on":
|
||||||
|
b = true
|
||||||
|
case "false", "off":
|
||||||
|
b = false
|
||||||
|
default:
|
||||||
|
return copies.NewInvalidValueErr(k, v)
|
||||||
|
}
|
||||||
|
if fv.IsNil() {
|
||||||
|
fv.Set(reflect.New(ft.Type.Elem()))
|
||||||
|
}
|
||||||
|
fv.Elem().SetBool(b)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
m.getters[k] = func() (string, error) {
|
||||||
|
if fv.IsNil() {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", fv.Elem()), nil
|
||||||
|
}
|
||||||
|
case reflect.String:
|
||||||
|
m.setters[k] = func(v string) error {
|
||||||
|
if fv.IsNil() {
|
||||||
|
fv.Set(reflect.New(ft.Type.Elem()))
|
||||||
|
}
|
||||||
|
fv.Elem().SetString(strings.TrimSpace(v))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
m.getters[k] = func() (string, error) {
|
||||||
|
if fv.IsNil() {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%v", fv.Elem()), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getStructTag(f reflect.StructField, tagName string) string {
|
||||||
|
return string(f.Tag.Get(tagName))
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package cfg_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"tuxpa.in/t/wm/src/bsp/cfg"
|
||||||
|
)
|
||||||
|
|
||||||
|
type E int
|
||||||
|
|
||||||
|
const (
|
||||||
|
D0 E = 0
|
||||||
|
D1
|
||||||
|
)
|
||||||
|
|
||||||
|
type s1 struct {
|
||||||
|
A *int `cfg:"a" default:"4"`
|
||||||
|
B *bool `cfg:"b"`
|
||||||
|
C *string `cfg:"c" default:"crabs"`
|
||||||
|
D *E `cfg:"d"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestModifierS1(t *testing.T) {
|
||||||
|
s := &s1{}
|
||||||
|
m := cfg.NewModifier(s)
|
||||||
|
m.FillDefaults()
|
||||||
|
assert.EqualValues(t, *m.Ref.C, "crabs")
|
||||||
|
|
||||||
|
m.Set("b", "on")
|
||||||
|
assert.EqualValues(t, *m.Ref.B, true)
|
||||||
|
assert.Nil(t, m.Ref.D)
|
||||||
|
m.Set("d", "442")
|
||||||
|
assert.EqualValues(t, *m.Ref.D, 442)
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package bsp
|
||||||
|
|
||||||
|
type ColorCode string
|
|
@ -0,0 +1,108 @@
|
||||||
|
package bsp
|
||||||
|
|
||||||
|
type AUTOMATIC_SCHEME_T int
|
||||||
|
|
||||||
|
const (
|
||||||
|
SCHEME_LONGEST_SIDE AUTOMATIC_SCHEME_T = iota
|
||||||
|
SCHEME_ALTERNATE
|
||||||
|
SCHEME_SPIRAL
|
||||||
|
)
|
||||||
|
|
||||||
|
type HONOR_SIZE_HINTS_MODE_T int
|
||||||
|
|
||||||
|
const (
|
||||||
|
HONOR_SIZE_HINTS_NO HONOR_SIZE_HINTS_MODE_T = iota
|
||||||
|
HONOR_SIZE_HINTS_YES
|
||||||
|
HONOR_SIZE_HINTS_FLOATING
|
||||||
|
HONOR_SIZE_HINTS_TILED
|
||||||
|
HONOR_SIZE_HINTS_DEFAULT
|
||||||
|
)
|
||||||
|
|
||||||
|
type TIGHTNESS_T int
|
||||||
|
|
||||||
|
const (
|
||||||
|
TIGHTNESS_LOW TIGHTNESS_T = iota
|
||||||
|
TIGHTNESS_HIGH
|
||||||
|
)
|
||||||
|
|
||||||
|
type CHILD_POLARITY_T int
|
||||||
|
|
||||||
|
const (
|
||||||
|
FIRST_CHILD CHILD_POLARITY_T = iota
|
||||||
|
SECOND_CHILD
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
|
||||||
|
// pointer options
|
||||||
|
PointerAction1 *string `cfg:"pointer_action1"`
|
||||||
|
PointerAction2 *string `cfg:"pointer_action2"`
|
||||||
|
PointerAction3 *string `cfg:"pointer_action3"`
|
||||||
|
|
||||||
|
PointerFollowsMonitor *bool `cfg:"pointer_follows_monitor"`
|
||||||
|
FocusFollowsPointer *bool `cfg:"focus_follows_pointer"`
|
||||||
|
PointerFollowsFocus *bool `cfg:"pointer_follows_focus"`
|
||||||
|
PointerMotionInterval *string `cfg:"pointer_motion_interval"`
|
||||||
|
|
||||||
|
// control
|
||||||
|
PointerModifier *string `cfg:"pointer_modifier" default:"XCB_MOD_MASK_4"`
|
||||||
|
StatusPrefix *string `cfg:"status_prefix" default:"W"`
|
||||||
|
ExternalRulesCommand *string `cfg:"external_rules_command" default:""`
|
||||||
|
|
||||||
|
// click
|
||||||
|
ClickToFocus *string `cfg:"click_to_focus" default:"XCB_BUTTON_INDEX_1"`
|
||||||
|
SwallowFirstClick *bool `cfg:"swallow_first_click"`
|
||||||
|
|
||||||
|
// ewmh
|
||||||
|
IgnoreEwmhFocus *bool `cfg:"ignore_ewmh_focus"`
|
||||||
|
IgnoreEwmhFullscreen *bool `cfg:"ignore_ewmh_fullscreen"`
|
||||||
|
IgnoreEwmhStruts *bool `cfg:"ignore_ewmh_struts"`
|
||||||
|
|
||||||
|
// monocole
|
||||||
|
PreselFeedback *bool `cfg:"presel_feedback" default:"true"`
|
||||||
|
GaplessMonocle *bool `cfg:"gapless_monocle"`
|
||||||
|
BorderlessMonocle *bool `cfg:"borderless_monocle"`
|
||||||
|
SingleMonocle *bool `cfg:"single_monocle"`
|
||||||
|
|
||||||
|
// padding
|
||||||
|
TopPadding *int `cfg:"top_padding"`
|
||||||
|
BottomPadding *int `cfg:"bottom_padding"`
|
||||||
|
LeftPadding *int `cfg:"left_padding"`
|
||||||
|
RightPadding *int `cfg:"right_padding"`
|
||||||
|
|
||||||
|
// monocle padding
|
||||||
|
TopMonoclePadding *int `cfg:"top_monocle_padding"`
|
||||||
|
BottomMonoclePadding *int `cfg:"bottom_monocle_padding"`
|
||||||
|
LeftMonoclePadding *int `cfg:"left_monocle_padding"`
|
||||||
|
RightMonoclePadding *int `cfg:"right_monocle_padding"`
|
||||||
|
|
||||||
|
// splits
|
||||||
|
SplitRatio *float64 `cfg:"split_ratio" default:"0.5"`
|
||||||
|
AutomaticScheme *AUTOMATIC_SCHEME_T `cfg:"automatic_scheme"`
|
||||||
|
RemovalAdjustment *string `cfg:"removal_adjustment"`
|
||||||
|
|
||||||
|
// gap
|
||||||
|
WindowGap *int `cfg:"window_gap"`
|
||||||
|
BorderlessSingleton *bool `cfg:"borderless_singleton"`
|
||||||
|
BorderWidth *bool `cfg:"border_width"`
|
||||||
|
|
||||||
|
//colors
|
||||||
|
ActiveBorderColor *ColorCode `cfg:"active_border_color"`
|
||||||
|
PreselFeedbackColor *ColorCode `cfg:"presel_feedback_color"`
|
||||||
|
FocusedBorderColor *ColorCode `cfg:"focused_border_color"`
|
||||||
|
NormalBorderColor *ColorCode `cfg:"normal_border_color"`
|
||||||
|
|
||||||
|
//monitor
|
||||||
|
RemoveDisabledMonitors *bool `cfg:"remove_disabled_monitors"`
|
||||||
|
RemoveUnpluggedMonitors *bool `cfg:"remove_unplugged_monitors"`
|
||||||
|
MergeOverlappingMonitors *bool `cfg:"merge_overlapping_monitors"`
|
||||||
|
|
||||||
|
// more
|
||||||
|
CenterPseudoTiled *bool `cfg:"center_pseudo_tiled" default:"true"`
|
||||||
|
HonorSizeHints *HONOR_SIZE_HINTS_MODE_T `cfg:"honor_size_hints"`
|
||||||
|
MappingEventsCount *int `cfg:"mapping_events_count" default:"1"`
|
||||||
|
|
||||||
|
//etc
|
||||||
|
DirectionalFocusTightness *TIGHTNESS_T `cfg:"directional_focus_tightness"`
|
||||||
|
InitialPolarity *CHILD_POLARITY_T `cfg:"initial_polarity"`
|
||||||
|
}
|
|
@ -7,14 +7,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type XWM struct {
|
type XWM struct {
|
||||||
w *WM
|
W *WM
|
||||||
x *xgbutil.XUtil
|
X *xgbutil.XUtil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewXWM(w *WM, x *xgbutil.XUtil) *XWM {
|
func NewXWM(w *WM, x *xgbutil.XUtil) *XWM {
|
||||||
xwm := &XWM{
|
xwm := &XWM{
|
||||||
w: w,
|
W: w,
|
||||||
x: x,
|
X: x,
|
||||||
}
|
}
|
||||||
return xwm
|
return xwm
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,22 +2,36 @@ package bsp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"tuxpa.in/t/wm/src/bsp/cfg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WM struct {
|
type WM struct {
|
||||||
Desktops []*Desktop
|
Desktops []*Desktop
|
||||||
Monitors []*Monitor
|
Monitors []*Monitor
|
||||||
|
|
||||||
|
Cfg *cfg.Modifier[*Config]
|
||||||
|
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
type Desktop struct {
|
type Desktop struct {
|
||||||
Name string
|
Name string
|
||||||
Monitor *Monitor
|
Monitor *Monitor
|
||||||
|
|
||||||
|
Cfg *cfg.Modifier[Config]
|
||||||
}
|
}
|
||||||
|
|
||||||
type Monitor struct {
|
type Monitor struct {
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
|
Cfg *cfg.Modifier[Config]
|
||||||
|
}
|
||||||
|
|
||||||
|
type Node struct {
|
||||||
|
Name string
|
||||||
|
|
||||||
|
Cfg *cfg.Modifier[Config]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *WM) Mutate(fn func() error) {
|
func (w *WM) Mutate(fn func() error) {
|
||||||
|
@ -41,6 +55,10 @@ func (w *WM) AddDesktop(name string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWM() *WM {
|
func NewWM() *WM {
|
||||||
w := &WM{}
|
w := &WM{
|
||||||
|
Cfg: cfg.NewModifier(&Config{}),
|
||||||
|
}
|
||||||
|
w.Cfg.FillDefaults()
|
||||||
|
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,31 @@ package copies
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
|
type ErrInvalidArgumentCount struct {
|
||||||
|
Name string
|
||||||
|
Value int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ErrInvalidArgumentCount) Error() string {
|
||||||
|
return fmt.Sprintf(`Was expecting %s arguments, received %d.\n`, u.Name, u.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ErrInvalidValue struct {
|
||||||
|
Name string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *ErrInvalidValue) Error() string {
|
||||||
|
return fmt.Sprintf(`%s: Invalid value: '%s'.\n`, u.Name, u.Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewInvalidValueErr(n, v string) *ErrInvalidValue {
|
||||||
|
return &ErrInvalidValue{
|
||||||
|
Name: n,
|
||||||
|
Value: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type ErrUnknownDomainOrCommand struct {
|
type ErrUnknownDomainOrCommand struct {
|
||||||
Str string
|
Str string
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,72 @@
|
||||||
package domains
|
package domains
|
||||||
|
|
||||||
import "tuxpa.in/t/wm/src/bsp"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"tuxpa.in/t/wm/src/bsp"
|
||||||
|
"tuxpa.in/t/wm/src/copies"
|
||||||
|
"tuxpa.in/t/wm/src/sock"
|
||||||
|
)
|
||||||
|
|
||||||
type inject struct {
|
type inject struct {
|
||||||
xwm
|
xwm
|
||||||
}
|
}
|
||||||
|
type desktop_sel struct {
|
||||||
|
desktopsel string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *desktop_sel) readDesktopSel(msg *sock.Msg) error {
|
||||||
|
if !msg.HasNext() {
|
||||||
|
return &copies.ErrMissingArguments{}
|
||||||
|
}
|
||||||
|
str := msg.Next()
|
||||||
|
switch str {
|
||||||
|
case "any", "first_ancestor",
|
||||||
|
"last", "newest", "older", "newer",
|
||||||
|
"focused", "pointed", "biggest", "smallest":
|
||||||
|
n.desktopsel = str
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type node_sel struct {
|
||||||
|
nodesel string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *node_sel) readNodeSel(msg *sock.Msg) error {
|
||||||
|
if !msg.HasNext() {
|
||||||
|
return &copies.ErrMissingArguments{}
|
||||||
|
}
|
||||||
|
str := msg.Next()
|
||||||
|
switch str {
|
||||||
|
case "any", "first_ancestor",
|
||||||
|
"last", "newest", "older", "newer",
|
||||||
|
"focused", "pointed", "biggest", "smallest":
|
||||||
|
n.nodesel = str
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type cmd struct {
|
||||||
|
Command string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *cmd) SetCommand(x string) {
|
||||||
|
c.Command = x
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *cmd) readCommand(msg *sock.Msg, c string) (bool, error) {
|
||||||
|
if n.Command == "" {
|
||||||
|
n.Command = c
|
||||||
|
return msg.HasNext(), nil
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf("multiple commands given")
|
||||||
|
}
|
||||||
|
|
||||||
type xwm struct {
|
type xwm struct {
|
||||||
XWM *bsp.XWM
|
XWM *bsp.XWM
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x xwm) SetXWM(z *bsp.XWM) {
|
func (x *xwm) SetXWM(z *bsp.XWM) {
|
||||||
x.XWM = z
|
x.XWM = z
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
package domains
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"tuxpa.in/t/wm/src/copies"
|
||||||
|
"tuxpa.in/t/wm/src/sock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
UseNames bool
|
||||||
|
|
||||||
|
configKey string
|
||||||
|
configValue string
|
||||||
|
|
||||||
|
cmd
|
||||||
|
inject
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Config) Run(msg *sock.Msg) ([]byte, error) {
|
||||||
|
if !msg.HasNext() {
|
||||||
|
return nil, &copies.ErrMissingArguments{}
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
ok, err := n.parse(msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n.configValue == "" {
|
||||||
|
str, err := n.XWM.W.Cfg.GetString(n.configKey)
|
||||||
|
return []byte(str), err
|
||||||
|
}
|
||||||
|
err := n.XWM.W.Cfg.Set(n.configKey, n.configValue)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Config) parse(msg *sock.Msg) (bool, error) {
|
||||||
|
if !msg.HasNext() {
|
||||||
|
return false, &copies.ErrMissingArguments{}
|
||||||
|
}
|
||||||
|
arg := msg.Next()
|
||||||
|
switch arg {
|
||||||
|
case "-d":
|
||||||
|
return n.readCommand(msg, "desktops")
|
||||||
|
case "-m":
|
||||||
|
return n.readCommand(msg, "monitors")
|
||||||
|
case "-n":
|
||||||
|
return n.readCommand(msg, "nodes")
|
||||||
|
default:
|
||||||
|
n.configKey = arg
|
||||||
|
if msg.HasNext() {
|
||||||
|
n.configValue = msg.Next()
|
||||||
|
}
|
||||||
|
if msg.HasNext() {
|
||||||
|
return false, &copies.ErrInvalidArgumentCount{Name: "2 or 3", Value: len(msg.Args())}
|
||||||
|
}
|
||||||
|
return false, fmt.Errorf(`unknown option: '%s'`, arg)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,58 @@
|
||||||
package domains
|
package domains
|
||||||
|
|
||||||
import "tuxpa.in/t/wm/src/copies"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"tuxpa.in/t/wm/src/copies"
|
||||||
|
"tuxpa.in/t/wm/src/sock"
|
||||||
|
)
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
|
UseNames bool
|
||||||
|
|
||||||
inject
|
inject
|
||||||
|
|
||||||
|
cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Node) Run(args ...string) error {
|
func (n *Node) Run(msg *sock.Msg) ([]byte, error) {
|
||||||
if len(args) == 0 {
|
if !msg.HasNext() {
|
||||||
return &copies.ErrMissingArguments{}
|
return nil, &copies.ErrMissingArguments{}
|
||||||
}
|
}
|
||||||
return nil
|
for {
|
||||||
|
ok, err := n.parse(msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Node) parse(msg *sock.Msg) (bool, error) {
|
||||||
|
if !msg.HasNext() {
|
||||||
|
return false, &copies.ErrMissingArguments{}
|
||||||
|
}
|
||||||
|
arg := msg.Next()
|
||||||
|
switch arg {
|
||||||
|
case "--desktop", "-d":
|
||||||
|
case "--desktops", "-D":
|
||||||
|
return n.readCommand(msg, "desktops")
|
||||||
|
case "--monitor", "-m":
|
||||||
|
case "--monitors", "-M":
|
||||||
|
return n.readCommand(msg, "monitors")
|
||||||
|
case "--names":
|
||||||
|
n.UseNames = true
|
||||||
|
case "--node", "-n":
|
||||||
|
case "--nodes", "-N":
|
||||||
|
return n.readCommand(msg, "nodes")
|
||||||
|
case "--tree", "-T":
|
||||||
|
return n.readCommand(msg, "tree")
|
||||||
|
default:
|
||||||
|
return false, fmt.Errorf(`unknown option: '%s'`, arg)
|
||||||
|
}
|
||||||
|
return msg.HasNext(), nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,14 +9,14 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
Command string
|
|
||||||
|
|
||||||
UseNames bool
|
UseNames bool
|
||||||
|
|
||||||
inject
|
inject
|
||||||
|
|
||||||
|
cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n Query) Run(msg *sock.Msg) ([]byte, error) {
|
func (n *Query) Run(msg *sock.Msg) ([]byte, error) {
|
||||||
if !msg.HasNext() {
|
if !msg.HasNext() {
|
||||||
return nil, &copies.ErrMissingArguments{}
|
return nil, &copies.ErrMissingArguments{}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@ func (n *Query) desktops(msg *sock.Msg) ([]byte, error) {
|
||||||
o := new(bytes.Buffer)
|
o := new(bytes.Buffer)
|
||||||
o.WriteString("hi there")
|
o.WriteString("hi there")
|
||||||
return o.Bytes(), nil
|
return o.Bytes(), nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Query) parse(msg *sock.Msg) (bool, error) {
|
func (n *Query) parse(msg *sock.Msg) (bool, error) {
|
||||||
|
@ -68,11 +67,3 @@ func (n *Query) parse(msg *sock.Msg) (bool, error) {
|
||||||
}
|
}
|
||||||
return msg.HasNext(), nil
|
return msg.HasNext(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Query) readCommand(msg *sock.Msg, c string) (bool, error) {
|
|
||||||
if n.Command == "" {
|
|
||||||
n.Command = c
|
|
||||||
return msg.HasNext(), nil
|
|
||||||
}
|
|
||||||
return false, fmt.Errorf("multiple commands given")
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package domains
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"tuxpa.in/t/wm/src/copies"
|
||||||
|
"tuxpa.in/t/wm/src/sock"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Wm struct {
|
||||||
|
UseNames bool
|
||||||
|
|
||||||
|
inject
|
||||||
|
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Wm) Run(msg *sock.Msg) ([]byte, error) {
|
||||||
|
if !msg.HasNext() {
|
||||||
|
return nil, &copies.ErrMissingArguments{}
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
ok, err := n.parse(msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Wm) parse(msg *sock.Msg) (bool, error) {
|
||||||
|
if !msg.HasNext() {
|
||||||
|
return false, &copies.ErrMissingArguments{}
|
||||||
|
}
|
||||||
|
arg := msg.Next()
|
||||||
|
switch arg {
|
||||||
|
case "--desktop", "-d":
|
||||||
|
case "--desktops", "-D":
|
||||||
|
return n.readCommand(msg, "desktops")
|
||||||
|
case "--monitor", "-m":
|
||||||
|
case "--monitors", "-M":
|
||||||
|
return n.readCommand(msg, "monitors")
|
||||||
|
case "--names":
|
||||||
|
n.UseNames = true
|
||||||
|
case "--node", "-n":
|
||||||
|
case "--nodes", "-N":
|
||||||
|
return n.readCommand(msg, "nodes")
|
||||||
|
case "--tree", "-T":
|
||||||
|
return n.readCommand(msg, "tree")
|
||||||
|
default:
|
||||||
|
return false, fmt.Errorf(`unknown option: '%s'`, arg)
|
||||||
|
}
|
||||||
|
return msg.HasNext(), nil
|
||||||
|
}
|
|
@ -4,15 +4,11 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jezek/xgbutil"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type SockListener struct {
|
type SockListener struct {
|
||||||
xgb *xgbutil.XUtil
|
l *net.UnixListener
|
||||||
l *net.UnixListener
|
|
||||||
|
|
||||||
ch chan *Msg
|
ch chan *Msg
|
||||||
}
|
}
|
||||||
|
@ -20,32 +16,10 @@ type SockListener struct {
|
||||||
func (s *SockListener) Msg() <-chan *Msg {
|
func (s *SockListener) Msg() <-chan *Msg {
|
||||||
return s.ch
|
return s.ch
|
||||||
}
|
}
|
||||||
func (s *SockListener) X11() *xgbutil.XUtil {
|
|
||||||
return s.xgb
|
|
||||||
}
|
|
||||||
func getUnixAddr(xc *xgbutil.XUtil, path string) *net.UnixAddr {
|
|
||||||
if path == "" {
|
|
||||||
path = os.Getenv(SOCKET_ENV_VAR)
|
|
||||||
}
|
|
||||||
if path == "" {
|
|
||||||
path = fmt.Sprintf(SOCKET_PATH_TPL, "", xc.Conn().DisplayNumber, xc.Conn().DefaultScreen)
|
|
||||||
}
|
|
||||||
addr, err := net.ResolveUnixAddr("unix", path)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
func Server(path string) (*SockListener, error) {
|
func Server(addr *net.UnixAddr) (*SockListener, error) {
|
||||||
s := &SockListener{}
|
s := &SockListener{}
|
||||||
s.ch = make(chan *Msg, 1)
|
s.ch = make(chan *Msg, 1)
|
||||||
xc, err := xgbutil.NewConn()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
s.xgb = xc
|
|
||||||
addr := getUnixAddr(xc, path)
|
|
||||||
conn, err := net.ListenUnix("unix", addr)
|
conn, err := net.ListenUnix("unix", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
Loading…
Reference in New Issue