can now query monitors
This commit is contained in:
parent
9efd1c2290
commit
65162b1651
|
@ -10,6 +10,7 @@ import (
|
|||
"syscall"
|
||||
|
||||
"github.com/jezek/xgbutil"
|
||||
"github.com/jezek/xgbutil/xevent"
|
||||
"tuxpa.in/a/zlog/log"
|
||||
"tuxpa.in/t/wm/src/bsp"
|
||||
"tuxpa.in/t/wm/src/handler"
|
||||
|
@ -102,14 +103,19 @@ func _main() (code int, err error) {
|
|||
return d
|
||||
})
|
||||
|
||||
beforeCh, afterCh, quitCh := xevent.MainPing(xwm.X)
|
||||
// message listen loop
|
||||
for {
|
||||
select {
|
||||
case <-beforeCh:
|
||||
<-afterCh
|
||||
case m := <-ln.Msg():
|
||||
h.Run(m)
|
||||
case cint := <-codeCh:
|
||||
stop()
|
||||
return cint, nil
|
||||
case <-quitCh:
|
||||
stop()
|
||||
case <-ctx.Done():
|
||||
return 0, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package bsp
|
||||
|
||||
import (
|
||||
"github.com/jezek/xgb/xproto"
|
||||
"github.com/jezek/xgbutil/ewmh"
|
||||
"github.com/jezek/xgbutil/icccm"
|
||||
"github.com/jezek/xgbutil/xwindow"
|
||||
"tuxpa.in/a/zlog/log"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
win *xwindow.Window
|
||||
winId xproto.Window
|
||||
|
||||
name string
|
||||
}
|
||||
|
||||
// registers a client to be obtained later
|
||||
func (xwm *XWM) RegisterClient(wid xproto.Window) *Client {
|
||||
c := &Client{
|
||||
winId: wid,
|
||||
}
|
||||
xwm.X.Grab()
|
||||
defer xwm.X.Ungrab()
|
||||
// dont duplicate registration
|
||||
if xwm.FindClient(wid) != nil {
|
||||
log.Trace().Any("id", wid).Msg("duplicate client registration")
|
||||
return nil
|
||||
}
|
||||
// ok this is a new one, so we need to make a new client
|
||||
c.win = xwindow.New(xwm.X, wid)
|
||||
if _, err := c.win.Geometry(); err != nil {
|
||||
log.Err(err).Any("id", wid).Msg("get geometry")
|
||||
return nil
|
||||
}
|
||||
err := xproto.ChangeSaveSetChecked(xwm.X.Conn(), xproto.SetModeInsert, c.winId).Check()
|
||||
if err != nil {
|
||||
log.Err(err).Any("id", wid).Msg("change save set checked")
|
||||
return nil
|
||||
}
|
||||
xwm.initClient(c)
|
||||
return c
|
||||
}
|
||||
|
||||
func (xwm *XWM) initClient(c *Client) {
|
||||
xwm.updateName(c)
|
||||
}
|
||||
func (xwm *XWM) updateName(c *Client) {
|
||||
newName := func() (n string) {
|
||||
n, _ = ewmh.WmNameGet(xwm.X, c.winId)
|
||||
if len(n) > 0 {
|
||||
return
|
||||
}
|
||||
|
||||
n, _ = icccm.WmNameGet(xwm.X, c.winId)
|
||||
if len(n) > 0 {
|
||||
return
|
||||
}
|
||||
return
|
||||
}()
|
||||
|
||||
if newName != c.name {
|
||||
c.name = newName
|
||||
ewmh.WmVisibleNameSet(xwm.X, c.winId, c.name)
|
||||
}
|
||||
}
|
||||
|
||||
func (xwm *XWM) FindClient(wid xproto.Window) (c *Client) {
|
||||
xwm.W.View(func() error {
|
||||
val, ok := xwm.W.Clients[wid]
|
||||
if ok {
|
||||
c = val
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return
|
||||
}
|
|
@ -83,8 +83,8 @@ type Config struct {
|
|||
|
||||
// gap
|
||||
WindowGap *int `cfg:"window_gap"`
|
||||
BorderWidth *int `cfg:"border_width"`
|
||||
BorderlessSingleton *bool `cfg:"borderless_singleton"`
|
||||
BorderWidth *bool `cfg:"border_width"`
|
||||
|
||||
//colors
|
||||
ActiveBorderColor *ColorCode `cfg:"active_border_color"`
|
||||
|
|
125
src/bsp/loop.go
125
src/bsp/loop.go
|
@ -2,12 +2,16 @@ package bsp
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/jezek/xgb/randr"
|
||||
"github.com/jezek/xgb/xinerama"
|
||||
"github.com/jezek/xgb/xproto"
|
||||
"github.com/jezek/xgbutil"
|
||||
"github.com/jezek/xgbutil/keybind"
|
||||
"github.com/jezek/xgbutil/mousebind"
|
||||
"github.com/jezek/xgbutil/xevent"
|
||||
"github.com/jezek/xgbutil/xwindow"
|
||||
"tuxpa.in/a/zlog/log"
|
||||
)
|
||||
|
||||
|
@ -24,10 +28,97 @@ func NewXWM(w *WM, x *xgbutil.XUtil) *XWM {
|
|||
return xwm
|
||||
}
|
||||
|
||||
func (xwm *XWM) Start(ctx context.Context) error {
|
||||
func (xwm *XWM) initBinding(ctx context.Context) error {
|
||||
randr.Init(xwm.X.Conn())
|
||||
xinerama.Init(xwm.X.Conn())
|
||||
keybind.Initialize(xwm.X)
|
||||
|
||||
mousebind.Initialize(xwm.X)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (xwm *XWM) Start(ctx context.Context) error {
|
||||
if err := xwm.initBinding(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := xwm.initMonitors(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := xwm.initRoot(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := xwm.initExistingWindows(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
// for {
|
||||
// err := xwm.run(ctx)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
return nil
|
||||
}
|
||||
|
||||
func (xwm *XWM) initMonitors(ctx context.Context) error {
|
||||
xwm.X.Grab()
|
||||
defer xwm.X.Ungrab()
|
||||
res, err := randr.GetScreenResources(xwm.X.Conn(), xwm.X.RootWin()).Reply()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, output := range res.Outputs {
|
||||
info, err := randr.GetOutputInfo(xwm.X.Conn(), output, res.ConfigTimestamp).Reply()
|
||||
if err != nil {
|
||||
log.Err(err).Any("output", output).Msg("fail get output info")
|
||||
continue
|
||||
}
|
||||
monitorId, err := xproto.NewMonitorId(xwm.X.Conn())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
xwm.W.Mutate(func() error {
|
||||
xwm.W.Monitors = append(xwm.W.Monitors, &Monitor{
|
||||
Name: string(info.Name),
|
||||
Id: monitorId,
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (xwm *XWM) initRoot(ctx context.Context) error {
|
||||
// important masks
|
||||
|
||||
evMasks := xproto.EventMaskPropertyChange |
|
||||
xproto.EventMaskFocusChange |
|
||||
xproto.EventMaskButtonPress |
|
||||
xproto.EventMaskButtonRelease |
|
||||
xproto.EventMaskStructureNotify |
|
||||
xproto.EventMaskSubstructureNotify |
|
||||
xproto.EventMaskSubstructureRedirect |
|
||||
xproto.EventMaskPointerMotion
|
||||
|
||||
err := xwindow.New(xwm.X, xwm.X.RootWin()).Listen(evMasks)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cant listen to root events: %w", err)
|
||||
}
|
||||
|
||||
// TODO: need to add listener when root window changes size
|
||||
|
||||
// attach root window
|
||||
if err = xwm.W.Mutate(func() error {
|
||||
xwm.W.Root = xwindow.New(xwm.X, xwm.X.RootWin())
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// map requests
|
||||
xevent.MapRequestFun(func(X *xgbutil.XUtil, ev xevent.MapRequestEvent) {
|
||||
}).Connect(xwm.X, xwm.W.Root.Id)
|
||||
|
||||
captureCombos := []string{
|
||||
"Mod4-1",
|
||||
|
@ -35,7 +126,6 @@ func (xwm *XWM) Start(ctx context.Context) error {
|
|||
"Mod2-1",
|
||||
"Mod1-1",
|
||||
}
|
||||
|
||||
for _, combo := range captureCombos {
|
||||
err := mousebind.ButtonPressFun(func(xu *xgbutil.XUtil, event xevent.ButtonPressEvent) {
|
||||
log.Trace().Str("name", event.String()).Str("mod", combo).Msg("press")
|
||||
|
@ -50,6 +140,15 @@ func (xwm *XWM) Start(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
|
||||
xevent.ConfigureNotifyFun(func(xu *xgbutil.XUtil, event xevent.ConfigureNotifyEvent) {
|
||||
log.Trace().Str("name", event.String()).Msg("notify event")
|
||||
}).Connect(xwm.X, xwm.X.RootWin())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (xwm *XWM) initExistingWindows(ctx context.Context) error {
|
||||
tree, err := xproto.QueryTree(xwm.X.Conn(), xwm.X.RootWin()).Reply()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -65,24 +164,12 @@ func (xwm *XWM) Start(ctx context.Context) error {
|
|||
if attrs.MapState == xproto.MapStateUnmapped {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Trace().
|
||||
Uint16("class", attrs.Class).
|
||||
Msg("found existing window")
|
||||
log.Println(attrs)
|
||||
c := xwm.RegisterClient(v)
|
||||
if c != nil {
|
||||
log.Printf("%+v", c)
|
||||
}
|
||||
}
|
||||
|
||||
xevent.ConfigureNotifyFun(func(xu *xgbutil.XUtil, event xevent.ConfigureNotifyEvent) {
|
||||
log.Trace().Str("name", event.String()).Msg("notify event")
|
||||
}).Connect(xwm.X, xwm.X.RootWin())
|
||||
xevent.Main(xwm.X)
|
||||
|
||||
// for {
|
||||
// err := xwm.run(ctx)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// }
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
package bsp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/jezek/xgb/randr"
|
||||
"github.com/jezek/xgb/xproto"
|
||||
"github.com/jezek/xgbutil/xwindow"
|
||||
"tuxpa.in/t/wm/src/bsp/cfg"
|
||||
)
|
||||
|
||||
|
@ -13,6 +19,10 @@ type WM struct {
|
|||
|
||||
Cfg *cfg.Modifier[*Config]
|
||||
|
||||
Root *xwindow.Window
|
||||
|
||||
Clients map[xproto.Window]*Client
|
||||
|
||||
mu sync.RWMutex
|
||||
}
|
||||
|
||||
|
@ -25,10 +35,19 @@ type Desktop struct {
|
|||
|
||||
type Monitor struct {
|
||||
Name string
|
||||
Id xproto.Monitor
|
||||
|
||||
raw *randr.GetOutputInfoReply
|
||||
|
||||
Cfg *cfg.Modifier[*Config]
|
||||
}
|
||||
|
||||
func (m *Monitor) HexId() []byte {
|
||||
o := bytes.NewBuffer([]byte("0x"))
|
||||
binary.Write(hex.NewEncoder(o), binary.LittleEndian, m.Id)
|
||||
return o.Bytes()
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
Name string
|
||||
|
||||
|
@ -53,15 +72,6 @@ func (w *WM) View(fn func() error) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (w *WM) AddMonitor(name string) error {
|
||||
return w.Mutate(func() error {
|
||||
w.Monitors = append(w.Monitors, &Monitor{
|
||||
Name: name,
|
||||
Cfg: cfg.NewModifier(&Config{}),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
func (w *WM) AddDesktop(name string, monitorName string) error {
|
||||
return w.Mutate(func() error {
|
||||
var monitor *Monitor
|
||||
|
@ -84,7 +94,8 @@ func (w *WM) AddDesktop(name string, monitorName string) error {
|
|||
|
||||
func NewWM() *WM {
|
||||
w := &WM{
|
||||
Cfg: cfg.NewModifier(&Config{}),
|
||||
Cfg: cfg.NewModifier(&Config{}),
|
||||
Clients: make(map[xproto.Window]*Client),
|
||||
}
|
||||
w.Cfg.FillDefaults()
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package domains
|
||||
|
||||
import (
|
||||
"tuxpa.in/a/zlog/log"
|
||||
"tuxpa.in/t/wm/src/copies"
|
||||
"tuxpa.in/t/wm/src/sock"
|
||||
)
|
||||
|
@ -36,6 +37,7 @@ func (n *Config) Run(msg *sock.Msg) ([]byte, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Trace().Str("key", n.configKey).Any("string", n.configValue).Msg("config set")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -32,11 +32,28 @@ func (n *Query) Run(msg *sock.Msg) ([]byte, error) {
|
|||
switch n.Command {
|
||||
case "desktops":
|
||||
return n.desktops(msg)
|
||||
case "monitors":
|
||||
return n.monitors(msg)
|
||||
default:
|
||||
return nil, &copies.ErrTODO{}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Query) monitors(msg *sock.Msg) ([]byte, error) {
|
||||
o := new(bytes.Buffer)
|
||||
n.XWM.W.View(func() error {
|
||||
for _, v := range n.XWM.W.Monitors {
|
||||
if n.UseNames {
|
||||
o.WriteString(v.Name)
|
||||
} else {
|
||||
o.Write(v.HexId())
|
||||
}
|
||||
o.WriteRune('\n')
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return o.Bytes(), nil
|
||||
}
|
||||
func (n *Query) desktops(msg *sock.Msg) ([]byte, error) {
|
||||
o := new(bytes.Buffer)
|
||||
o.WriteString("hi there")
|
||||
|
|
|
@ -66,7 +66,7 @@ func (m *Msg) Reply(xs []byte) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(xs) != 0 {
|
||||
if len(xs) != 0 && xs[len(xs)-1] != '\n' {
|
||||
wr.Write([]byte("\n"))
|
||||
}
|
||||
wr.Write([]byte{0})
|
||||
|
|
|
@ -6394,6 +6394,16 @@ func VisualInfoListBytes(buf []byte, list []VisualInfo) int {
|
|||
|
||||
type Visualid uint32
|
||||
|
||||
type Monitor uint32
|
||||
|
||||
func NewMonitorId(c *xgb.Conn) (Monitor, error) {
|
||||
id, err := c.NewId()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return Monitor(id), nil
|
||||
}
|
||||
|
||||
type Window uint32
|
||||
|
||||
func NewWindowId(c *xgb.Conn) (Window, error) {
|
||||
|
|
Loading…
Reference in New Issue