180 lines
3.9 KiB
Go
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
|
|
}
|