2022-11-09 13:52:49 -07:00
|
|
|
package x
|
|
|
|
|
|
|
|
import "image"
|
|
|
|
|
|
|
|
import "github.com/jezek/xgbutil"
|
|
|
|
// import "github.com/jezek/xgbutil/ewmh"
|
2022-11-09 16:53:14 -07:00
|
|
|
import "github.com/jezek/xgbutil/xevent"
|
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-09 16:53:14 -07:00
|
|
|
ping struct {
|
|
|
|
before chan(struct { })
|
|
|
|
after chan(struct { })
|
|
|
|
quit chan(struct { })
|
|
|
|
}
|
|
|
|
|
|
|
|
metrics struct {
|
|
|
|
cellWidth int
|
|
|
|
cellHeight int
|
|
|
|
padding int
|
|
|
|
paddingX int
|
|
|
|
paddingY int
|
|
|
|
descent int
|
|
|
|
}
|
2022-11-09 13:52:49 -07:00
|
|
|
}
|
|
|
|
|
2022-11-09 16:53:14 -07:00
|
|
|
func (backend *Backend) Run (channel chan(stone.Event)) {
|
|
|
|
backend.channel = channel
|
2022-11-09 13:52:49 -07:00
|
|
|
|
2022-11-09 16:53:14 -07:00
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <- backend.ping.before:
|
|
|
|
<- backend.ping.after
|
|
|
|
|
|
|
|
case <- backend.ping.quit:
|
|
|
|
backend.shutDown()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
2022-11-09 13:52:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (backend *Backend) SetTitle (title string) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func (backend *Backend) SetIcon (icons []image.Image) {
|
|
|
|
|
|
|
|
}
|
2022-11-09 16:53:14 -07:00
|
|
|
|
|
|
|
func (backend *Backend) shutDown () {
|
|
|
|
backend.channel <- stone.EventQuit { }
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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-09 17:07:40 -07:00
|
|
|
func (backend *Backend) bindCanvas () {
|
|
|
|
backend.canvas.XSurfaceSet(backend.window.Id)
|
|
|
|
backend.canvas.XDraw()
|
|
|
|
backend.canvas.XPaint(backend.window.Id)
|
|
|
|
}
|
2022-11-09 16:53:14 -07:00
|
|
|
|
|
|
|
// factory instantiates an X backend.
|
|
|
|
func factory (application *stone.Application) (output stone.Backend, err error) {
|
|
|
|
backend := &Backend {
|
|
|
|
application: application,
|
|
|
|
config: application.Config(),
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate metrics
|
|
|
|
// TODO: base these off of font metrics
|
|
|
|
backend.metrics.cellWidth = 8
|
|
|
|
backend.metrics.cellHeight = 16
|
|
|
|
backend.metrics.padding =
|
|
|
|
backend.config.Padding() *
|
|
|
|
backend.metrics.cellHeight
|
|
|
|
backend.metrics.paddingX = backend.metrics.padding
|
|
|
|
backend.metrics.paddingY = backend.metrics.padding
|
|
|
|
|
|
|
|
// connect to X
|
|
|
|
backend.connection, err = xgbutil.NewConn()
|
|
|
|
if err != nil { return }
|
|
|
|
backend.window, err = xwindow.Generate(backend.connection)
|
|
|
|
if err != nil { return }
|
|
|
|
|
|
|
|
// create the window
|
|
|
|
windowWidth, windowHeight := backend.calculateWindowSize()
|
|
|
|
backend.window.Create (
|
|
|
|
backend.connection.RootWin(),
|
|
|
|
0, 0, windowWidth, windowHeight,
|
|
|
|
0)
|
|
|
|
backend.window.Map()
|
|
|
|
|
2022-11-09 17:07:40 -07:00
|
|
|
// create a canvas
|
|
|
|
backend.canvas = xgraphics.New (
|
|
|
|
backend.connection,
|
|
|
|
image.Rect (
|
|
|
|
0, 0,
|
|
|
|
windowWidth,
|
|
|
|
windowHeight))
|
|
|
|
backend.bindCanvas()
|
|
|
|
|
2022-11-09 16:53:14 -07:00
|
|
|
// attatch graceful close handler
|
|
|
|
backend.window.WMGracefulClose (func (window *xwindow.Window) {
|
|
|
|
backend.window.Destroy()
|
|
|
|
backend.shutDown()
|
|
|
|
})
|
|
|
|
|
|
|
|
// start event loop
|
|
|
|
backend.ping.before,
|
|
|
|
backend.ping.after,
|
|
|
|
backend.ping.quit = xevent.MainPing(backend.connection)
|
|
|
|
|
|
|
|
output = backend
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// init registers this backend when the program starts.
|
|
|
|
func init () {
|
|
|
|
stone.RegisterBackend(factory)
|
|
|
|
}
|