func (ct *CommandTray) Init() { var err error ct.img = xgraphics.New(ct.X, image.Rect(0, 0, ct.Width, ct.Height)) ct.pu_img = xgraphics.New(ct.X, image.Rect(0, 0, ct.Width, ct.Height*10)) ct.window, err = xwindow.Create(ct.X, ct.Parent.Id) utils.FailMeMaybe(err) utils.FailMeMaybe(ct.img.XSurfaceSet(ct.window.Id)) ct.window.Move(ct.Position, 0) ct.window.Resize(ct.Width, ct.Height) ct.window.Map() }
// DrawText is a convenience function that will create a new image, render // the provided text to it, paint the image to the provided window, and resize // the window to fit the text snugly. // // An error can occur when rendering the text to an image. func DrawText(win *xwindow.Window, font *truetype.Font, size float64, fontClr, bgClr render.Color, text string) error { // BUG(burntsushi): If `text` is zero-length, very bad things happen. if len(text) == 0 { text = " " } // Over estimate the extents. ew, eh := xgraphics.Extents(font, size, text) // Create an image using the over estimated extents. img := xgraphics.New(win.X, image.Rect(0, 0, ew, eh)) xgraphics.BlendBgColor(img, bgClr.ImageColor()) // Now draw the text, grab the (x, y) position advanced by the text, and // check for an error in rendering. _, _, err := img.Text(0, 0, fontClr.ImageColor(), size, font, text) if err != nil { return err } // Resize the window to the geometry determined by (x, y). win.Resize(ew, eh) // Now draw the image to the window and destroy it. img.XSurfaceSet(win.Id) // subimg := img.SubImage(image.Rect(0, 0, ew, eh)) img.XDraw() img.XPaint(win.Id) img.Destroy() return nil }
// New allocates and initializes a new DockApp. NewDockApp does not initialize // the window contents and does not map the window to the display screen. The // window is mapped to the screen when the Main method is called on the // returned DockApp. func New(x *xgbutil.XUtil, rect image.Rectangle) (*DockApp, error) { win, err := xwindow.Generate(x) if err != nil { log.Fatalf("generate window: %v", err) } win.Create(x.RootWin(), 0, 0, rect.Size().X, rect.Size().Y, 0) // Set WM hints so that Openbox puts the window into the dock. hints := &icccm.Hints{ Flags: icccm.HintState | icccm.HintIconWindow, InitialState: icccm.StateWithdrawn, IconWindow: win.Id, WindowGroup: win.Id, } err = icccm.WmHintsSet(x, win.Id, hints) if err != nil { win.Destroy() return nil, fmt.Errorf("wm hints: %v", err) } img := xgraphics.New(x, rect) err = img.XSurfaceSet(win.Id) if err != nil { img.Destroy() win.Destroy() return nil, fmt.Errorf("xsurface set: %v", err) } app := &DockApp{ x: x, img: img, win: win, } return app, nil }
// DrawText is a convenience function that will create a new image, render // the provided text to it, paint the image to the provided window, and resize // the window to fit the text snugly. // // An error can occur when rendering the text to an image. func DrawText(win *xwindow.Window, font *truetype.Font, size float64, fontClr, bgClr color.RGBA, text string) error { // Over estimate the extents. ew, eh := xgraphics.TextMaxExtents(font, size, text) eh += misc.TextBreathe // <-- this is the bug // Create an image using the over estimated extents. img := xgraphics.New(win.X, image.Rect(0, 0, ew, eh)) xgraphics.BlendBgColor(img, bgClr) // Now draw the text, grab the (x, y) position advanced by the text, and // check for an error in rendering. x, y, err := img.Text(0, 0, fontClr, size, font, text) if err != nil { return err } // Resize the window to the geometry determined by (x, y). w, h := x, y+misc.TextBreathe // <-- also part of the bug win.Resize(w, h) // Now draw the image to the window and destroy it. img.XSurfaceSet(win.Id) subimg := img.SubImage(image.Rect(0, 0, w, h)) subimg.XDraw() subimg.XPaint(win.Id) img.Destroy() return nil }
// NewInput constructs Input values. It needs an X connection, a parent window, // the width of the input box, and theme information related for the font // and background. Padding separating the text and the edges of the window // may also be specified. // // While NewInput returns an *Input, a Input value also has an xwindow.Window // value embedded into it. Thus, an Input can also be treated as a normal // window on which you can assign callbacks, close, destroy, etc. // // As with all windows, the Input window should be destroyed when it is no // longer in used. func NewInput(X *xgbutil.XUtil, parent xproto.Window, width int, padding int, font *truetype.Font, fontSize float64, fontColor, bgColor render.Color) *Input { _, height := xgraphics.TextMaxExtents(font, fontSize, "M") height += misc.TextBreathe width, height = width+2*padding, height+2*padding img := xgraphics.New(X, image.Rect(0, 0, width, height)) win := xwindow.Must(xwindow.Create(X, parent)) win.Listen(xproto.EventMaskKeyPress) win.Resize(width, height) ti := &Input{ Window: win, img: img, Text: make([]rune, 0, 50), font: font, fontSize: fontSize, fontColor: fontColor, bgColor: bgColor, padding: padding, } ti.Render() return ti }
// NewImage returns a new image canvas // that draws to the given image. The // minimum point of the given image // should probably be 0,0. func NewImage(img draw.Image, name string) (*Canvas, error) { w := float64(img.Bounds().Max.X - img.Bounds().Min.X) h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y) X, err := xgbutil.NewConn() if err != nil { return nil, err } keybind.Initialize(X) ximg := xgraphics.New(X, image.Rect(0, 0, int(w), int(h))) err = ximg.CreatePixmap() if err != nil { return nil, err } painter := NewPainter(ximg) gc := draw2d.NewGraphicContextWithPainter(ximg, painter) gc.SetDPI(dpi) gc.Scale(1, -1) gc.Translate(0, -h) wid := ximg.XShowExtra(name, true) go func() { xevent.Main(X) }() c := &Canvas{ Canvas: vgimg.NewWith(vgimg.UseImageWithContext(img, gc)), x: X, ximg: ximg, wid: wid, } vg.Initialize(c) return c, nil }
func NewDisplay(width, height, border, heading int, name string) (*Display, error) { d := new(Display) d.w = float64(width) d.h = float64(height) d.bord = float64(border) d.head = float64(heading) X, err := xgbutil.NewConn() if err != nil { return nil, err } keybind.Initialize(X) d.ximg = xgraphics.New(X, image.Rect( 0, 0, border*2+width, border*2+heading+height)) err = d.ximg.CreatePixmap() if err != nil { return nil, err } painter := NewXimgPainter(d.ximg) d.gc = draw2d.NewGraphicContextWithPainter(d.ximg, painter) d.gc.Save() d.gc.SetStrokeColor(color.White) d.gc.SetFillColor(color.White) d.gc.Clear() d.wid = d.ximg.XShowExtra(name, true) d.x = X go func() { xevent.Main(X) }() return d, nil }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } // Load some font. You may need to change the path depending upon your // system configuration. fontReader, err := os.Open(fontPath) if err != nil { log.Fatal(err) } // Now parse the font. font, err := xgraphics.ParseFont(fontReader) if err != nil { log.Fatal(err) } // Create some canvas. ximg := xgraphics.New(X, image.Rect(0, 0, canvasWidth, canvasHeight)) ximg.For(func(x, y int) xgraphics.BGRA { return bg }) // Now write the text. _, _, err = ximg.Text(10, 10, fg, size, font, msg) if err != nil { log.Fatal(err) } // Compute extents of first line of text. _, firsth := xgraphics.Extents(font, size, msg) // Now show the image in its own window. win := ximg.XShowExtra("Drawing text using xgraphics", true) // Now draw some more text below the above and demonstrate how to update // only the region we've updated. _, _, err = ximg.Text(10, 10+firsth, fg, size, font, "Some more text.") if err != nil { log.Fatal(err) } // Now compute extents of the second line of text, so we know which region // to update. secw, sech := xgraphics.Extents(font, size, "Some more text.") // Now repaint on the region that we drew text on. Then update the screen. bounds := image.Rect(10, 10+firsth, 10+secw, 10+firsth+sech) ximg.SubImage(bounds).XDraw() ximg.XPaint(win.Id) // All we really need to do is block, which could be achieved using // 'select{}'. Invoking the main event loop however, will emit error // message if anything went seriously wrong above. xevent.Main(X) }
func NewSolid(X *xgbutil.XUtil, bgColor Color, width, height int) *Image { img := New(xgraphics.New(X, image.Rect(0, 0, width, height))) r, g, b := bgColor.RGB8() img.ForExp(func(x, y int) (uint8, uint8, uint8, uint8) { return r, g, b, 0xff }) return img }
func NewGUI(board *Board) *GUI { gui := new(GUI) X, _ := xgbutil.NewConn() gui.canvas = xgraphics.New(X, image.Rect(0, 0, board.Width(), board.Height())) gui.queue = make(map[Pos]bool, board.Width()*board.Height()) gui.win = gui.canvas.XShow() gui.board = board board.onUpdate = func(p Pos) { gui.Update(p) } gui.StartLoop() return gui }
func NewWindow(width, height int) (w *Window, err error) { w = new(Window) w.width, w.height = width, height w.xu, err = xgbutil.NewConn() if err != nil { return } w.conn = w.xu.Conn() screen := w.xu.Screen() w.win, err = xwindow.Generate(w.xu) if err != nil { return } err = w.win.CreateChecked(screen.Root, 600, 500, width, height, 0) if err != nil { return } 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 }
// NewBackground creates an xgraphics.Image which spans the entire screen, // initialized to black. func NewBackground(X *xgbutil.XUtil) (*xgraphics.Image, error) { res, err := randr.GetScreenResources(X.Conn(), X.RootWin()).Reply() if err != nil { return nil, err } var bgRect image.Rectangle for _, output := range res.Outputs { r, err := util.OutputRect(X, output) // NOTE: It doesn't really matter if this returns a Zero Rectangle. if err != nil { return nil, err } bgRect = bgRect.Union(r) } return xgraphics.New(X, bgRect), nil }
func (c *Clock) Init() { var err error c.img = xgraphics.New(c.X, image.Rect(0, 0, c.Width, c.Height)) c.window, err = xwindow.Create(c.X, c.Parent.Id) utils.FailMeMaybe(err) c.window.Resize(c.Width, c.Height) c.window.Move(c.Position, 0) c.img.XSurfaceSet(c.window.Id) c.window.Map() c.Draw() go c.tickTock() }
func main() { runtime.GOMAXPROCS(64) X, err := xgbutil.NewConn() if err != nil { log.Fatal(err) } keybind.Initialize(X) font := loadFont("/usr/share/fonts/truetype/freefont/FreeMono.ttf") font.Color = xgraphics.BGRA{B: 0x00, G: 0xff, R: 0x00, A: 0xff} font.Size = 12.0 ximage := xgraphics.New(X, image.Rect(0, 0, 300, 300)) ximage.CreatePixmap() window, obscured := makeWindow(ximage) battery := batteryItem(font, 10, ximage, window) cpu := cpuItem(font, 30, ximage, window) memory := memoryItem(font, 50, ximage, window) before, after, quit := xevent.MainPing(X) loop: for { select { case <-before: <-after case <-quit: break loop case text := <-battery.Text: if *obscured { continue loop } battery.update(text) case text := <-cpu.Text: if *obscured { continue loop } cpu.update(text) case text := <-memory.Text: if *obscured { continue loop } memory.update(text) } } }
func (sb *StatusBar) Init() { sb.img = xgraphics.New(sb.X, image.Rect(0, 0, sb.Width, sb.Height)) var err error sb.window, err = xwindow.Create(sb.X, sb.Parent.Id) utils.FailMeMaybe(err) sb.window.Move(sb.Position, 0) sb.window.Resize(sb.Width, sb.Height) sb.window.Map() sb.img.XSurfaceSet(sb.window.Id) utils.FailMeMaybe(sb.initTray()) sb.Draw() }
func NewBorder(X *xgbutil.XUtil, borderType int, borderColor, bgColor Color, width, height, gradientType, gradientDir int) *Image { img := New(xgraphics.New(X, image.Rect(0, 0, width, height))) // bgClr could be a gradient! if bgColor.IsGradient() { img.Gradient(gradientType, gradientDir, bgColor) } else { r, g, b := bgColor.RGB8() img.ForExp(func(x, y int) (uint8, uint8, uint8, uint8) { return r, g, b, 0xff }) } img.ThinBorder(borderType, borderColor) return img }
func NewCorner(X *xgbutil.XUtil, borderType int, borderColor, bgColor Color, width, height, diagonal int) *Image { // If bgColor isn't a gradient, then we can cheat if !bgColor.IsGradient() { return NewBorder(X, borderType, borderColor, bgColor, width, height, 0, 0) } img := New(xgraphics.New(X, image.Rect(0, 0, width, height))) // aliases for convenience vert, horz := GradientVert, GradientHorz reg, rev := GradientRegular, GradientReverse // for Top Left to Bottom Right diagonals belowTLDiag := func(x, y int) bool { return y > x } aboveTLDiag := func(x, y int) bool { return y <= x } // for Bottom Left to Top Right diagonals belowBLDiag := func(x, y int) bool { return y > (width - x) } aboveBLDiag := func(x, y int) bool { return y <= (width - x) } switch diagonal { case DiagBottomLeft: img.GradientFunc(horz, reg, bgColor, aboveBLDiag) img.GradientFunc(vert, rev, bgColor, belowBLDiag) case DiagTopRight: img.GradientFunc(vert, reg, bgColor, aboveBLDiag) img.GradientFunc(horz, rev, bgColor, belowBLDiag) case DiagBottomRight: img.GradientFunc(horz, rev, bgColor, aboveTLDiag) img.GradientFunc(vert, rev, bgColor, belowTLDiag) default: // DiagTopLeft: img.GradientFunc(vert, reg, bgColor, aboveTLDiag) img.GradientFunc(horz, reg, bgColor, belowTLDiag) } img.ThinBorder(borderType, borderColor) return img }
// NewImage returns a new image canvas // that draws to the given image. The // minimum point of the given image // should probably be 0,0. func NewImage(img draw.Image, name string) (*XImgCanvas, error) { w := float64(img.Bounds().Max.X - img.Bounds().Min.X) h := float64(img.Bounds().Max.Y - img.Bounds().Min.Y) X, err := xgbutil.NewConn() if err != nil { return nil, err } keybind.Initialize(X) ximg := xgraphics.New(X, image.Rect(0, 0, int(w), int(h))) err = ximg.CreatePixmap() if err != nil { return nil, err } painter := NewXimgPainter(ximg) gc := draw2d.NewGraphicContextWithPainter(ximg, painter) gc.SetDPI(dpi) gc.Scale(1, -1) gc.Translate(0, -h) wid := ximg.XShowExtra(name, true) go func() { xevent.Main(X) }() c := &XImgCanvas{ gc: gc, w: vg.Inches(w / dpi), h: vg.Inches(h / dpi), color: []color.Color{color.Black}, x: X, ximg: ximg, wid: wid, } vg.Initialize(c) return c, nil }
// paintGradient creates a new xgraphics.Image value and draws a gradient // starting at color 'start' and ending at color 'end'. // // Since xgraphics.Image values use pixmaps and pixmaps cannot be resized, // a new pixmap must be allocated for each resize event. func paintGradient(X *xgbutil.XUtil, wid xproto.Window, width, height int, start, end color.RGBA) { ximg := xgraphics.New(X, image.Rect(0, 0, width, height)) // Now calculate the increment step between each RGB channel in // the start and end colors. rinc := (0xff * (int(end.R) - int(start.R))) / width ginc := (0xff * (int(end.G) - int(start.G))) / width binc := (0xff * (int(end.B) - int(start.B))) / width // Now apply the increment to each "column" in the image. // Using 'ForExp' allows us to bypass the creation of a color.BGRA value // for each pixel in the image. ximg.ForExp(func(x, y int) (uint8, uint8, uint8, uint8) { return uint8(int(start.B) + (binc*x)/0xff), uint8(int(start.G) + (ginc*x)/0xff), uint8(int(start.R) + (rinc*x)/0xff), 0xff }) // Set the surface to paint on for ximg. // (This simply sets the background pixmap of the window to the pixmap // used by ximg.) ximg.XSurfaceSet(wid) // XDraw will draw the contents of ximg to its corresponding pixmap. ximg.XDraw() // XPaint will "clear" the window provided so that it shows the updated // pixmap. ximg.XPaint(wid) // Since we will not reuse ximg, we must destroy its pixmap. ximg.Destroy() }
func (t *Tracker) Init() { var err error t.img = xgraphics.New(t.X, image.Rect(0, 0, t.Size, t.Size)) t.window, err = xwindow.Create(t.X, t.Parent.Id) utils.FailMeMaybe(err) t.window.Resize(t.Size, t.Size) t.window.Move(t.Position, 0) t.img.XSurfaceSet(t.window.Id) t.window.Map() t.stopMe = true l := startup.Listener{ X: t.X, Callbacks: t, } l.Initialize() t.Draw() }
func (w *Window) handleEvents() { var noX int32 = 1<<31 - 1 noX++ 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) }
func main() { X, err := xgbutil.NewConn() if err != nil { log.Println(err) return } //Initialize the keybind package keybind.Initialize(X) //Create a window win, err := xwindow.Generate(X) if err != nil { log.Fatalf("Could not generate a new window X id: %s", err) } win.Create(X.RootWin(), 0, 0, 1024, 768, xproto.CwBackPixel, 0x606060ff) // Listen for Key{Press,Release} events. win.Listen(xproto.EventMaskKeyPress, xproto.EventMaskKeyRelease) // Map the window. This is what makes it on the screen win.Map() //Make a ...callback... for the events and connect xevent.KeyPressFun( func(X *xgbutil.XUtil, e xevent.KeyPressEvent) { modStr := keybind.ModifierString(e.State) keyStr := keybind.LookupString(X, e.State, e.Detail) if len(modStr) > 0 { log.Printf("Key: %s-%s\n", modStr, keyStr) } else { log.Println("Key:", keyStr) } if keybind.KeyMatch(X, "Escape", e.State, e.Detail) { if e.State&xproto.ModMaskControl > 0 { log.Println("Control-Escape detected. Quitting...") xevent.Quit(X) } } }).Connect(X, win.Id) //So here i'm going to try to make a image..' img := xgraphics.New(X, image.Rect(0, 0, 1024, 768)) err = img.XSurfaceSet(win.Id) if err != nil { log.Printf("Error while setting window surface to image %d: %s\n", win, err) } else { log.Printf("Window %d surface set to image OK\n", win) } // I /think/ XDraw actually sends data to server? img.XDraw() // I /think/ XPaint tells the server to paint image to window img.XPaint(win.Id) //Start the routine that updates the window go updater(img, win) //This seems to start a main loop for listening to xevents xevent.Main(X) }
func main() { // Signal Handling. sigChan := make(chan os.Signal) signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT) paths := basedir.Paths{ XDGSuffix: "gobar", GoImportPath: "github.com/AmandaCameron/gobar/data", } file, err := paths.ConfigFile("config.wini") utils.FailMeMaybe(err) cfg := loadConfig(file) //os.Getenv("HOME") + "/.config/gobar/config.wini") // Load Images. images.Init(paths) // Setup the X Connection X, err := xgbutil.NewConn() utils.FailMeMaybe(err) win, err := xwindow.Create(X, X.RootWin()) utils.FailMeMaybe(err) win.Resize(cfg.BarWidth, cfg.BarSize) // Setup the EWMH Stuff utils.FailMeMaybe(ewmh.RestackWindow(X, win.Id)) var strut *ewmh.WmStrutPartial if cfg.Position == "Top" { strut = &ewmh.WmStrutPartial{ Top: uint(cfg.BarSize), TopStartX: 0, TopEndX: uint(cfg.BarWidth), } win.Move(0, 0) } else if cfg.Position == "Bottom" { strut = &ewmh.WmStrutPartial{ Bottom: uint(cfg.BarSize), BottomStartX: 0, BottomEndX: uint(cfg.BarWidth), } win.Move(0, 600-cfg.BarSize) } else { println("Invalid Position:", cfg.Position) os.Exit(1) } utils.FailMeMaybe(ewmh.WmStrutPartialSet(X, win.Id, strut)) utils.FailMeMaybe(ewmh.WmWindowTypeSet(X, win.Id, []string{ "_NET_WM_WINDOW_TYPE_DOCK", })) // Put us everywhere. utils.FailMeMaybe(ewmh.WmDesktopSet(X, win.Id, 0xFFFFFFFF)) win.Map() keybind.Initialize(X) // Get the DE settings, if we can. xs, err := xsettings.New(X) if err != nil { // Maybe this should be an error, maybe not? xs = nil } // Draw the background bg := xgraphics.BGRA{ R: 64, G: 64, B: 64, A: 255, } img := xgraphics.New(X, image.Rect(0, 0, cfg.BarWidth, cfg.BarSize)) img.For(func(x, y int) xgraphics.BGRA { return bg }) utils.FailMeMaybe(img.XSurfaceSet(win.Id)) img.XDraw() img.XPaint(win.Id) // Connect to DBus sys, err := dbus.Connect(dbus.SystemBus) utils.FailMeMaybe(err) // The session bus, too. sess, err := dbus.Connect(dbus.SessionBus) utils.FailMeMaybe(err) // Blah x := xdg.New() // TODO: How should this fail? I imagine defaulting to gnome is the wrong thing to do, // but I'm not really sure what it should do. if xs != nil { theme, err := xs.GetString("Net/IconThemeName") if err == nil { x.SetTheme(theme) } } var dev *nm.Device var batt *upower.Device up := upower.New(sys) cli := nm.New(sys) if devs, err := cli.GetDevices(); err == nil { for _, d := range devs { if d.Type() == nm.Wireless { dev = d break } } } if pdevs, err := up.GetDevices(); err == nil { for _, d := range pdevs { if d.Type() == upower.Battery { batt = d break } } } // Clock clck := &Clock{ X: X, Position: cfg.Clock.Position, Width: cfg.Clock.Width, Height: cfg.BarSize, Parent: win, Format: cfg.ClockFormat, Background: xgraphics.BGRA{R: 48, G: 48, B: 48, A: 255}, Foreground: xgraphics.BGRA{R: 255, G: 255, B: 255, A: 255}, Font: utils.OpenFont(cfg.Clock.Font.Name), FontSize: cfg.Clock.Font.Size, } clck.Init() // App Launch Tracker tracker := &Tracker{ X: X, Position: cfg.Tracker.Position, Size: cfg.BarSize, Background: bg, Parent: win, } tracker.Init() // Command Tray ct := &commandtray.CommandTray{ X: X, Width: cfg.Command.Width, Height: cfg.BarSize, Position: cfg.Command.Position, Parent: win, Font: utils.OpenFont(cfg.Command.Font.Name), FontSize: cfg.Command.Font.Size, } commandtray.Register(commandtray.AppSource{ Xdg: x, X: X, AppTracker: tracker, }) if sess != nil { commandtray.Register(commandtray.GnomeSessionSource{ Obj: sess.Object("org.gnome.SessionManager", "/org/gnome/SessionManager"), Xdg: x, }) commandtray.Register(commandtray.NewShellSource(sess, x)) commandtray.Register(&commandtray.AppMenuSource{ Conn: sess, }) } // Done, maybe? ct.Init() ct.Bind(cfg.CommandAccel) ct.Draw() // Status Bar sb := &statbar.StatusBar{ X: X, Width: cfg.StatusBar.Width, Position: cfg.StatusBar.Position, Height: cfg.BarSize, Parent: win, } sb.Init() if batt != nil { sb.Add(&statbar.SbPower{batt}) } if dev != nil { sb.Add(&statbar.SbNmWifi{dev}) commandtray.Register(commandtray.NmSource{dev}) } sb.Draw() // My My this anikin guy... go func() { for { select { case <-sigChan: sb.Teardown() time.Sleep(1 * time.Second) // Anybody else? xevent.Quit(X) } } }() xevent.Main(X) }
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) }