package x // import "fmt" import "sync" import "image" import "golang.org/x/image/font" // import "github.com/jezek/xgb" import "github.com/jezek/xgbutil" import "github.com/jezek/xgbutil/ewmh" import "github.com/jezek/xgbutil/xwindow" import "github.com/jezek/xgbutil/xgraphics" import "git.tebibyte.media/sashakoshka/stone" type Backend struct { application *stone.Application config *stone.Config connection *xgbutil.XUtil window *xwindow.Window canvas *xgraphics.Image channel chan(stone.Event) drawCellBounds bool drawBufferBounds bool drawLock sync.Mutex font struct { face font.Face } colors [4]xgraphics.BGRA metrics struct { windowWidth int windowHeight int cellWidth int cellHeight int padding int paddingX int paddingY int descent int } memory struct { windowWidth int windowHeight int } } func (backend *Backend) SetTitle (title string) (err error) { err = ewmh.WmNameSet(backend.connection, backend.window.Id, title) return } func (backend *Backend) SetIcon (icons []image.Image) (err error) { wmIcons := []ewmh.WmIcon { } for _, icon := range icons { width := icon.Bounds().Max.X height := icon.Bounds().Max.Y wmIcon := ewmh.WmIcon { Width: uint(width), Height: uint(height), Data: make ([]uint, width * height), } // manually convert image data beacuse of course we have to do // this index := 0 for y := 0; y < height; y ++ { for x := 0; x < width; x ++ { r, g, b, a := icon.At(x, y).RGBA() r >>= 8 g >>= 8 b >>= 8 a >>= 8 wmIcon.Data[index] = (uint(a) << 24) | (uint(r) << 16) | (uint(g) << 8) | (uint(b) << 0) index ++ }} wmIcons = append(wmIcons, wmIcon) } err = ewmh.WmIconSet(backend.connection, backend.window.Id, wmIcons) return } // calculateWindowSize calculates window bounds based on the internal buffer // size. func (backend *Backend) calculateWindowSize () (x, y int) { width, height := backend.application.Size() x = width * backend.metrics.cellWidth + backend.metrics.padding * 2 y = height * backend.metrics.cellHeight + backend.metrics.padding * 2 return } func (backend *Backend) calculateBufferSize () (width, height int) { width = (backend.metrics.windowWidth - backend.metrics.padding * 2) / backend.metrics.cellWidth height = (backend.metrics.windowHeight - backend.metrics.padding * 2) / backend.metrics.cellHeight return } func (backend *Backend) reallocateCanvas () { if backend.canvas != nil { backend.canvas.Destroy() } backend.canvas = xgraphics.New ( backend.connection, image.Rect ( 0, 0, backend.metrics.windowWidth, backend.metrics.windowHeight)) backend.canvas.For (func (x, y int) xgraphics.BGRA { return backend.colors[stone.ColorApplication] }) backend.canvas.XSurfaceSet(backend.window.Id) } func (backend *Backend) cellAt (onScreen image.Point) (x, y int) { x = (onScreen.X - backend.metrics.paddingX) / backend.metrics.cellWidth y = (onScreen.Y - backend.metrics.paddingY) / backend.metrics.cellHeight return } func (backend *Backend) cellSubImage (x, y int) (cell *xgraphics.Image) { cell = backend.canvas.SubImage(backend.boundsOfCell(x, y)).(*xgraphics.Image) return } func (backend *Backend) originOfCell (x, y int) (origin image.Point) { origin = image.Point { X: x * backend.metrics.cellWidth + backend.metrics.paddingX, Y: y * backend.metrics.cellHeight + backend.metrics.paddingY, } return } func (backend *Backend) boundsOfCell (x, y int) (bounds image.Rectangle) { bounds = image.Rectangle { Min: backend.originOfCell(x, y), Max: backend.originOfCell(x + 1, y + 1), } return }