stone/backends/x/x.go

157 lines
3.6 KiB
Go

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)
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
}