wm/src/bsp/loop.go
2023-06-15 10:24:04 -05:00

180 lines
3.9 KiB
Go

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"
)
type XWM struct {
W *WM
X *xgbutil.XUtil
}
func NewXWM(w *WM, x *xgbutil.XUtil) *XWM {
xwm := &XWM{
W: w,
X: x,
}
return xwm
}
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",
"Mod3-1",
"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")
}).Connect(xwm.X, xwm.X.RootWin(), combo, false, true)
if err != nil {
return err
}
err = mousebind.ButtonReleaseFun(func(xu *xgbutil.XUtil, event xevent.ButtonReleaseEvent) {
log.Trace().Str("name", event.String()).Str("mod", combo).Msg("depress")
}).Connect(xwm.X, xwm.X.RootWin(), combo, false, true)
if err != nil {
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
}
for _, v := range tree.Children {
if v == xwm.X.Dummy() {
continue
}
attrs, err := xproto.GetWindowAttributes(xwm.X.Conn(), v).Reply()
if err != nil {
continue
}
if attrs.MapState == xproto.MapStateUnmapped {
continue
}
c := xwm.RegisterClient(v)
if c != nil {
log.Printf("%+v", c)
}
}
return nil
}
func (xwm *XWM) run(ctx context.Context) error {
return nil
}