// setupEventHandlers attaches the canvas' channels to the window and // sets the appropriate callbacks to some events: // ConfigureNotify events will cause the window to update its state of geometry. // Expose events will cause the window to repaint the current image. // Button events to allow panning. // Key events to perform various tasks when certain keys are pressed. func (w *Window) setupEventHandlers(chans chans) { w.Listen(xproto.EventMaskStructureNotify | xproto.EventMaskExposure | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // Get the current geometry in case we don't get a ConfigureNotify event // (or have already missed it). if _, err := w.Geometry(); err != nil { errLg.Fatal(err) } // Keep a state of window geometry. xevent.ConfigureNotifyFun( func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { w.Geom.WidthSet(int(ev.Width)) w.Geom.HeightSet(int(ev.Height)) }).Connect(w.X, w.Id) // Repaint the window on expose events. xevent.ExposeFun( func(X *xgbutil.XUtil, ev xevent.ExposeEvent) { chans.ctl <- []string{"pan", "origin"} }).Connect(w.X, w.Id) // Setup a drag handler to allow panning. mousebind.Drag(w.X, w.Id, w.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { chans.panStartChan <- image.Point{ex, ey} return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { chans.panStepChan <- image.Point{ex, ey} }, // We do nothing on mouse release func(X *xgbutil.XUtil, rx, ry, ex, ey int) { return }) for _, kb := range keybinds { k := kb // Needed because the callback closure will capture kb err := keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { chans.ctl <- k.command }).Connect(w.X, w.Id, k.key, false) if err != nil { errLg.Println(err) } } }
// setupEventHandlers attaches the canvas' channels to the window and // sets the appropriate callbacks to some events: // ConfigureNotify events will cause the window to update its state of geometry. // Expose events will cause the window to repaint the current image. // Button events to allow panning. // Key events to perform various tasks when certain keys are pressed. Should // these be configurable? Meh. func (w *window) setupEventHandlers(chans chans) { w.chans = chans w.Listen(xproto.EventMaskStructureNotify | xproto.EventMaskExposure | xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // Get the current geometry in case we don't get a ConfigureNotify event // (or have already missed it). _, err := w.Geometry() if err != nil { errLg.Fatal(err) } // And ask the canvas to draw the first image when it gets around to it. go func() { w.chans.drawChan <- func(origin image.Point) image.Point { return image.Point{} } }() // Keep a state of window geometry. xevent.ConfigureNotifyFun( func(X *xgbutil.XUtil, ev xevent.ConfigureNotifyEvent) { w.Geom.WidthSet(int(ev.Width)) w.Geom.HeightSet(int(ev.Height)) }).Connect(w.X, w.Id) // Repaint the window on expose events. xevent.ExposeFun( func(X *xgbutil.XUtil, ev xevent.ExposeEvent) { w.chans.drawChan <- func(origin image.Point) image.Point { return origin } }).Connect(w.X, w.Id) // Setup a drag handler to allow panning. mousebind.Drag(w.X, w.Id, w.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { w.chans.panStartChan <- image.Point{ex, ey} return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { w.chans.panStepChan <- image.Point{ex, ey} }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { w.chans.panEndChan <- image.Point{ex, ey} }) // Set up a map of keybindings to avoid a lot of boiler plate. // for keystring, fun := range kbs { for _, keyb := range keybinds { keyb := keyb err := keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { keyb.action(w) }).Connect(w.X, w.Id, keyb.key, false) if err != nil { errLg.Println(err) } } }
func makeWindow(ximage *xgraphics.Image) (*xwindow.Window, *bool) { w, h := ximage.Rect.Dx(), ximage.Rect.Dy() window, err := xwindow.Generate(ximage.X) if err != nil { xgbutil.Logger.Printf("Could not generate new window id: %s", err) return nil, nil } window.Create(ximage.X.RootWin(), 0, 0, w, h, xproto.CwBackPixel, 0x00000000) window.Listen(xproto.EventMaskExposure, xproto.EventMaskKeyPress, xproto.EventMaskStructureNotify, xproto.EventMaskVisibilityChange) window.WMGracefulClose(func(w *xwindow.Window) { xevent.Detach(w.X, w.Id) keybind.Detach(w.X, w.Id) mousebind.Detach(w.X, w.Id) w.Destroy() xevent.Quit(w.X) }) err = icccm.WmStateSet(ximage.X, window.Id, &icccm.WmState{ State: icccm.StateNormal, }) if err != nil { xgbutil.Logger.Printf("Could not set WM_STATE: %s", err) } err = ewmh.WmNameSet(ximage.X, window.Id, "Computer System Monitor") if err != nil { xgbutil.Logger.Printf("Could not set _NET_WM_NAME: %s", err) } err = keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { err := ewmh.WmStateReq(ximage.X, window.Id, ewmh.StateToggle, "_NET_WM_STATE_FULLSCREEN") if err != nil { log.Fatal(err) } }).Connect(ximage.X, window.Id, "f", false) if err != nil { log.Fatal(err) } xevent.ExposeFun( func(xu *xgbutil.XUtil, event xevent.ExposeEvent) { ximage.XExpPaint(window.Id, 0, 0) }).Connect(ximage.X, window.Id) obscured := false xevent.VisibilityNotifyFun( func(xu *xgbutil.XUtil, event xevent.VisibilityNotifyEvent) { obscured = event.State == xproto.VisibilityFullyObscured }).Connect(ximage.X, window.Id) window.Map() return window, &obscured }