2022-11-09 13:52:49 -07:00
|
|
|
package x
|
|
|
|
|
2022-11-12 17:02:24 -07:00
|
|
|
// import "fmt"
|
2022-11-11 20:30:59 -07:00
|
|
|
import "sync"
|
2022-11-09 13:52:49 -07:00
|
|
|
import "image"
|
2022-11-10 10:38:02 -07:00
|
|
|
import "golang.org/x/image/font"
|
2022-11-09 13:52:49 -07:00
|
|
|
|
2022-11-12 17:02:24 -07:00
|
|
|
// import "github.com/jezek/xgb"
|
2022-11-09 13:52:49 -07:00
|
|
|
import "github.com/jezek/xgbutil"
|
2022-11-10 00:02:08 -07:00
|
|
|
import "github.com/jezek/xgbutil/ewmh"
|
2022-11-09 13:52:49 -07:00
|
|
|
import "github.com/jezek/xgbutil/xwindow"
|
|
|
|
import "github.com/jezek/xgbutil/xgraphics"
|
|
|
|
|
|
|
|
import "git.tebibyte.media/sashakoshka/stone"
|
|
|
|
|
|
|
|
type Backend struct {
|
2022-11-09 16:53:14 -07:00
|
|
|
application *stone.Application
|
|
|
|
config *stone.Config
|
|
|
|
connection *xgbutil.XUtil
|
|
|
|
window *xwindow.Window
|
|
|
|
canvas *xgraphics.Image
|
|
|
|
channel chan(stone.Event)
|
2022-11-09 13:52:49 -07:00
|
|
|
|
2022-11-14 21:32:05 -07:00
|
|
|
drawCellBounds bool
|
|
|
|
drawBufferBounds bool
|
|
|
|
|
2022-11-11 20:30:59 -07:00
|
|
|
drawLock sync.Mutex
|
|
|
|
|
2022-11-10 10:38:02 -07:00
|
|
|
font struct {
|
|
|
|
face font.Face
|
|
|
|
}
|
2022-11-10 18:43:27 -07:00
|
|
|
|
2022-11-15 09:16:29 -07:00
|
|
|
colors [8]xgraphics.BGRA
|
2022-11-09 16:53:14 -07:00
|
|
|
|
|
|
|
metrics struct {
|
2022-11-09 20:33:18 -07:00
|
|
|
windowWidth int
|
|
|
|
windowHeight int
|
|
|
|
cellWidth int
|
|
|
|
cellHeight int
|
|
|
|
padding int
|
|
|
|
paddingX int
|
|
|
|
paddingY int
|
|
|
|
descent int
|
2022-11-09 16:53:14 -07:00
|
|
|
}
|
2022-11-11 21:24:20 -07:00
|
|
|
|
|
|
|
memory struct {
|
|
|
|
windowWidth int
|
|
|
|
windowHeight int
|
|
|
|
}
|
2022-11-09 13:52:49 -07:00
|
|
|
}
|
|
|
|
|
2022-11-10 00:02:08 -07:00
|
|
|
func (backend *Backend) SetTitle (title string) (err error) {
|
|
|
|
err = ewmh.WmNameSet(backend.connection, backend.window.Id, title)
|
|
|
|
return
|
2022-11-09 13:52:49 -07:00
|
|
|
}
|
|
|
|
|
2022-11-10 00:02:08 -07:00
|
|
|
func (backend *Backend) SetIcon (icons []image.Image) (err error) {
|
|
|
|
wmIcons := []ewmh.WmIcon { }
|
2022-11-09 13:52:49 -07:00
|
|
|
|
2022-11-10 00:02:08 -07:00
|
|
|
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
|
2022-11-09 13:52:49 -07:00
|
|
|
}
|
2022-11-09 16:53:14 -07:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2022-11-11 20:46:07 -07:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-11-10 18:43:27 -07:00
|
|
|
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 {
|
2022-11-15 09:16:29 -07:00
|
|
|
return backend.colors[stone.ColorBackground]
|
2022-11-10 18:43:27 -07:00
|
|
|
})
|
2022-11-10 19:32:02 -07:00
|
|
|
|
2022-11-09 17:07:40 -07:00
|
|
|
backend.canvas.XSurfaceSet(backend.window.Id)
|
|
|
|
}
|
2022-11-09 16:53:14 -07:00
|
|
|
|
2022-11-12 20:43:36 -07:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-11-10 19:32:02 -07:00
|
|
|
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
|
2022-11-10 10:38:02 -07:00
|
|
|
}
|