func NewWindow(width, height int) (wde.Window, error) { var err error w := new(Window) w.width, w.height = width, height w.xu, err = xgbutil.NewConn() if err != nil { return nil, err } w.conn = w.xu.Conn() screen := w.xu.Screen() w.win, err = xwindow.Generate(w.xu) if err != nil { return nil, err } err = w.win.CreateChecked(screen.Root, 600, 500, width, height, 0) if err != nil { return nil, err } w.win.Listen(AllEventsMask) err = icccm.WmProtocolsSet(w.xu, w.win.Id, []string{"WM_DELETE_WINDOW"}) if err != nil { fmt.Println(err) err = nil } w.bufferLck = &sync.Mutex{} w.buffer = xgraphics.New(w.xu, image.Rect(0, 0, width, height)) w.buffer.XSurfaceSet(w.win.Id) keyMap, modMap := keybind.MapsGet(w.xu) keybind.KeyMapSet(w.xu, keyMap) keybind.ModMapSet(w.xu, modMap) w.events = make(chan interface{}) w.SetIcon(Gordon) w.SetIconName("Go") go w.handleEvents() return w, nil }
func main() { X, err := xgbutil.NewConn() fatal(err) // Whenever the mousebind package is used, you must call Initialize. // Similarly for the keybind package. keybind.Initialize(X) mousebind.Initialize(X) // Easter egg! Use a right click to draw a gopher. gopherPng, _, err := image.Decode(bytes.NewBuffer(gopher.GopherPng())) fatal(err) // Now scale it to a reasonable size. gopher := xgraphics.Scale(gopherPng, gopherWidth, gopherHeight) // Create a new xgraphics.Image. It automatically creates an X pixmap for // you, and handles drawing to windows in the XDraw, XPaint and // XSurfaceSet functions. // N.B. An error is possible since X pixmap allocation can fail. canvas := xgraphics.New(X, image.Rect(0, 0, width, height)) // Color in the background color. canvas.For(func(x, y int) xgraphics.BGRA { return bg }) // Use the convenience function XShowExtra to create and map the // canvas window. // XShowExtra will also set the surface window of canvas for us. // We also use XShowExtra to set the name of the window and to quit the // main event loop when the window is closed. win := canvas.XShowExtra("Pointer painting", true) // Listen for pointer motion events and key press events. win.Listen(xproto.EventMaskButtonPress | xproto.EventMaskButtonRelease | xproto.EventMaskKeyPress) // The mousebind drag function runs three callbacks: one when the drag is // first started, another at each "step" in the drag, and a final one when // the drag is done. // The button sequence (in this case '1') is pressed, the first callback // is executed. If the first return value is true, the drag continues // and a pointer grab is initiated with the cursor id specified in the // second return value (use 0 to keep the cursor unchanged). // If it's false, the drag stops. // Note that Drag will automatically compress MotionNotify events. mousebind.Drag(X, win.Id, win.Id, "1", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { drawPencil(canvas, win, ex, ey) return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { drawPencil(canvas, win, ex, ey) }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) {}) mousebind.Drag(X, win.Id, win.Id, "3", false, func(X *xgbutil.XUtil, rx, ry, ex, ey int) (bool, xproto.Cursor) { drawGopher(canvas, gopher, win, ex, ey) return true, 0 }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) { drawGopher(canvas, gopher, win, ex, ey) }, func(X *xgbutil.XUtil, rx, ry, ex, ey int) {}) // Bind to the clear key specified, and just redraw the bg color. keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { clearCanvas(canvas, win) }).Connect(X, win.Id, clearKey, false) // Bind a callback to each key specified in the 'pencils' color map. // The response is to simply switch the pencil color. for key, clr := range pencils { c := clr keybind.KeyPressFun( func(X *xgbutil.XUtil, ev xevent.KeyPressEvent) { log.Printf("Changing pencil color to: %#v", c) pencil = c }).Connect(X, win.Id, key, false) } // Output some basic directions. fmt.Println("Use the left or right buttons on your mouse to paint " + "squares and gophers.") fmt.Println("Pressing numbers 1, 2, 3, 4, 5 or 6 will switch your pencil " + "color.") fmt.Println("Pressing 'c' will clear the canvas.") xevent.Main(X) }
func (w *Window) handleEvents() { const noX int32 = -1 var lastX, lastY int32 = noX, 0 var button wde.Button downKeys := map[string]bool{} for { e, err := w.conn.WaitForEvent() if err != nil { fmt.Println("[go.wde X error] ", err) continue } switch e := e.(type) { case xproto.ButtonPressEvent: button = button | buttonForDetail(e.Detail) var bpe wde.MouseDownEvent bpe.Which = buttonForDetail(e.Detail) bpe.Where.X = int(e.EventX) bpe.Where.Y = int(e.EventY) lastX = int32(e.EventX) lastY = int32(e.EventY) w.events <- bpe case xproto.ButtonReleaseEvent: button = button & ^buttonForDetail(e.Detail) var bue wde.MouseUpEvent bue.Which = buttonForDetail(e.Detail) bue.Where.X = int(e.EventX) bue.Where.Y = int(e.EventY) lastX = int32(e.EventX) lastY = int32(e.EventY) w.events <- bue case xproto.LeaveNotifyEvent: var wee wde.MouseExitedEvent wee.Where.X = int(e.EventX) wee.Where.Y = int(e.EventY) if lastX != noX { wee.From.X = int(lastX) wee.From.Y = int(lastY) } else { wee.From.X = wee.Where.X wee.From.Y = wee.Where.Y } lastX = int32(e.EventX) lastY = int32(e.EventY) w.events <- wee case xproto.EnterNotifyEvent: var wee wde.MouseEnteredEvent wee.Where.X = int(e.EventX) wee.Where.Y = int(e.EventY) if lastX != noX { wee.From.X = int(lastX) wee.From.Y = int(lastY) } else { wee.From.X = wee.Where.X wee.From.Y = wee.Where.Y } lastX = int32(e.EventX) lastY = int32(e.EventY) w.events <- wee case xproto.MotionNotifyEvent: var mme wde.MouseMovedEvent mme.Where.X = int(e.EventX) mme.Where.Y = int(e.EventY) if lastX != noX { mme.From.X = int(lastX) mme.From.Y = int(lastY) } else { mme.From.X = mme.Where.X mme.From.Y = mme.Where.Y } lastX = int32(e.EventX) lastY = int32(e.EventY) if button == 0 { w.events <- mme } else { var mde wde.MouseDraggedEvent mde.MouseMovedEvent = mme mde.Which = button w.events <- mde } case xproto.KeyPressEvent: var ke wde.KeyEvent code := keybind.LookupString(w.xu, e.State, e.Detail) ke.Key = keyForCode(code) w.events <- wde.KeyDownEvent(ke) downKeys[ke.Key] = true kpe := wde.KeyTypedEvent{ KeyEvent: ke, Glyph: letterForCode(code), Chord: wde.ConstructChord(downKeys), } w.events <- kpe case xproto.KeyReleaseEvent: var ke wde.KeyUpEvent ke.Key = keyForCode(keybind.LookupString(w.xu, e.State, e.Detail)) delete(downKeys, ke.Key) w.events <- ke case xproto.ConfigureNotifyEvent: var re wde.ResizeEvent re.Width = int(e.Width) re.Height = int(e.Height) if re.Width != w.width || re.Height != w.height { w.width, w.height = re.Width, re.Height w.bufferLck.Lock() w.buffer.Destroy() w.buffer = xgraphics.New(w.xu, image.Rect(0, 0, re.Width, re.Height)) w.bufferLck.Unlock() w.events <- re } case xproto.ClientMessageEvent: if icccm.IsDeleteProtocol(w.xu, xevent.ClientMessageEvent{&e}) { w.events <- wde.CloseEvent{} } case xproto.DestroyNotifyEvent: case xproto.ReparentNotifyEvent: case xproto.MapNotifyEvent: case xproto.UnmapNotifyEvent: case xproto.PropertyNotifyEvent: default: fmt.Printf("unhandled event: type %T\n%+v\n", e, e) } } close(w.events) }