Overhauled event system
This commit is contained in:
@@ -3,12 +3,13 @@ package x
|
||||
import "image"
|
||||
import "image/draw"
|
||||
import "golang.org/x/image/math/fixed"
|
||||
import "github.com/jezek/xgbutil/xgraphics"
|
||||
|
||||
import "git.tebibyte.media/sashakoshka/stone"
|
||||
|
||||
func (backend *Backend) Draw () {
|
||||
backend.drawLock.Lock()
|
||||
defer backend.drawLock.Unlock()
|
||||
backend.lock.Lock()
|
||||
defer backend.lock.Unlock()
|
||||
|
||||
boundsChanged :=
|
||||
backend.memory.windowWidth != backend.metrics.windowWidth ||
|
||||
@@ -22,25 +23,77 @@ func (backend *Backend) Draw () {
|
||||
backend.canvas.XDraw()
|
||||
backend.canvas.XPaint(backend.window.Id)
|
||||
} else {
|
||||
backend.updateWindowAreas(backend.drawCells(false)...)
|
||||
backend.canvas.XPaintRects (
|
||||
backend.window.Id,
|
||||
backend.drawCells(false)...)
|
||||
}
|
||||
}
|
||||
|
||||
func (backend *Backend) updateWindowAreas (areas ...image.Rectangle) {
|
||||
backend.canvas.XPaintRects(backend.window.Id, areas...)
|
||||
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.ColorBackground]
|
||||
})
|
||||
|
||||
backend.canvas.XSurfaceSet(backend.window.Id)
|
||||
}
|
||||
|
||||
func (backend *Backend) drawRune (x, y int, character rune, runeColor stone.Color) {
|
||||
func (backend *Backend) drawCells (forceRedraw bool) (areas []image.Rectangle) {
|
||||
width, height := backend.application.Size()
|
||||
for y := 0; y < height; y ++ {
|
||||
for x := 0; x < width; x ++ {
|
||||
if !forceRedraw && backend.application.Clean(x, y) { continue }
|
||||
backend.application.MarkClean(x, y)
|
||||
|
||||
cell := backend.application.Cell(x, y)
|
||||
content := cell.Rune()
|
||||
|
||||
if forceRedraw && content < 32 { continue }
|
||||
|
||||
areas = append(areas, backend.boundsOfCell(x, y))
|
||||
backend.drawRune(x, y, content, cell.Color(), !forceRedraw)
|
||||
}}
|
||||
|
||||
if backend.drawBufferBounds && forceRedraw {
|
||||
strokeRectangle (
|
||||
&image.Uniform {
|
||||
C: backend.config.Color(stone.ColorForeground),
|
||||
},
|
||||
backend.canvas,
|
||||
image.Rectangle {
|
||||
Min: backend.originOfCell(0, 0),
|
||||
Max: backend.originOfCell(width, height),
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (backend *Backend) drawRune (
|
||||
x, y int,
|
||||
character rune,
|
||||
runeColor stone.Color,
|
||||
drawBackground bool,
|
||||
) {
|
||||
// TODO: cache these draws as non-transparent buffers with the
|
||||
// application background color as the background. that way, we won't
|
||||
// need to redraw the characters *or* composite them.
|
||||
|
||||
fillRectangle (
|
||||
&image.Uniform {
|
||||
C: backend.config.Color(stone.ColorBackground),
|
||||
},
|
||||
backend.canvas,
|
||||
backend.boundsOfCell(x, y))
|
||||
|
||||
if drawBackground {
|
||||
fillRectangle (
|
||||
&image.Uniform {
|
||||
C: backend.config.Color(stone.ColorBackground),
|
||||
},
|
||||
backend.canvas,
|
||||
backend.boundsOfCell(x, y))
|
||||
}
|
||||
|
||||
if character < 32 { return }
|
||||
|
||||
@@ -73,36 +126,6 @@ func (backend *Backend) drawRune (x, y int, character rune, runeColor stone.Colo
|
||||
draw.Over)
|
||||
}
|
||||
|
||||
func (backend *Backend) drawCells (forceRedraw bool) (areas []image.Rectangle) {
|
||||
width, height := backend.application.Size()
|
||||
for y := 0; y < height; y ++ {
|
||||
for x := 0; x < width; x ++ {
|
||||
if !forceRedraw && backend.application.Clean(x, y) { continue }
|
||||
backend.application.MarkClean(x, y)
|
||||
|
||||
cell := backend.application.Cell(x, y)
|
||||
content := cell.Rune()
|
||||
|
||||
if forceRedraw && content < 32 { continue }
|
||||
|
||||
areas = append(areas, backend.boundsOfCell(x, y))
|
||||
backend.drawRune(x, y, content, cell.Color())
|
||||
}}
|
||||
|
||||
if backend.drawBufferBounds && forceRedraw {
|
||||
strokeRectangle (
|
||||
&image.Uniform {
|
||||
C: backend.config.Color(stone.ColorForeground),
|
||||
},
|
||||
backend.canvas,
|
||||
image.Rectangle {
|
||||
Min: backend.originOfCell(0, 0),
|
||||
Max: backend.originOfCell(width, height),
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func fillRectangle (
|
||||
source image.Image,
|
||||
destination draw.Image,
|
||||
|
||||
@@ -8,17 +8,19 @@ import "github.com/jezek/xgbutil/xevent"
|
||||
|
||||
import "git.tebibyte.media/sashakoshka/stone"
|
||||
|
||||
func (backend *Backend) Run (channel chan(stone.Event)) {
|
||||
backend.channel = channel
|
||||
func (backend *Backend) Run () {
|
||||
backend.callbackManager.RunStart()
|
||||
backend.Draw()
|
||||
xevent.Main(backend.connection)
|
||||
backend.shutDown()
|
||||
}
|
||||
|
||||
|
||||
func (backend *Backend) handleConfigureNotify (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.ConfigureNotifyEvent,
|
||||
) {
|
||||
backend.lock.Lock()
|
||||
|
||||
configureEvent := *event.ConfigureNotifyEvent
|
||||
|
||||
newWidth := int(configureEvent.Width)
|
||||
@@ -44,8 +46,13 @@ func (backend *Backend) handleConfigureNotify (
|
||||
(backend.metrics.windowWidth - frameWidth) / 2
|
||||
backend.metrics.paddingY =
|
||||
(backend.metrics.windowHeight - frameHeight) / 2
|
||||
|
||||
backend.channel <- stone.EventResize { }
|
||||
}
|
||||
|
||||
backend.lock.Unlock()
|
||||
|
||||
if sizeChanged {
|
||||
backend.callbackManager.RunResize()
|
||||
backend.Draw()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,9 +61,7 @@ func (backend *Backend) handleButtonPress (
|
||||
event xevent.ButtonPressEvent,
|
||||
) {
|
||||
buttonEvent := *event.ButtonPressEvent
|
||||
backend.channel <- stone.EventPress {
|
||||
Button: stone.Button(buttonEvent.Detail + 127),
|
||||
}
|
||||
backend.callbackManager.RunPress(stone.Button(buttonEvent.Detail + 127))
|
||||
}
|
||||
|
||||
func (backend *Backend) handleButtonRelease (
|
||||
@@ -64,9 +69,7 @@ func (backend *Backend) handleButtonRelease (
|
||||
event xevent.ButtonReleaseEvent,
|
||||
) {
|
||||
buttonEvent := *event.ButtonReleaseEvent
|
||||
backend.channel <- stone.EventRelease {
|
||||
Button: stone.Button(buttonEvent.Detail + 127),
|
||||
}
|
||||
backend.callbackManager.RunRelease(stone.Button(buttonEvent.Detail + 127))
|
||||
}
|
||||
|
||||
func (backend *Backend) handleKeyPress (
|
||||
@@ -75,7 +78,7 @@ func (backend *Backend) handleKeyPress (
|
||||
) {
|
||||
keyEvent := *event.KeyPressEvent
|
||||
button := backend.keycodeToButton(keyEvent.Detail, keyEvent.State)
|
||||
backend.channel <- stone.EventPress { Button: button }
|
||||
backend.callbackManager.RunPress(button)
|
||||
}
|
||||
|
||||
func (backend *Backend) handleKeyRelease (
|
||||
@@ -84,7 +87,7 @@ func (backend *Backend) handleKeyRelease (
|
||||
) {
|
||||
keyEvent := *event.KeyReleaseEvent
|
||||
button := backend.keycodeToButton(keyEvent.Detail, keyEvent.State)
|
||||
backend.channel <- stone.EventRelease { Button: button }
|
||||
backend.callbackManager.RunRelease(button)
|
||||
}
|
||||
|
||||
func (backend *Backend) handleMotionNotify (
|
||||
@@ -96,10 +99,7 @@ func (backend *Backend) handleMotionNotify (
|
||||
X: int(motionEvent.EventX),
|
||||
Y: int(motionEvent.EventY),
|
||||
})
|
||||
backend.channel <- stone.EventMouseMove {
|
||||
X: x,
|
||||
Y: y,
|
||||
}
|
||||
backend.callbackManager.RunMouseMove(x, y)
|
||||
}
|
||||
|
||||
func (backend *Backend) compressConfigureNotify (
|
||||
@@ -127,5 +127,5 @@ func (backend *Backend) compressConfigureNotify (
|
||||
}
|
||||
|
||||
func (backend *Backend) shutDown () {
|
||||
backend.channel <- stone.EventQuit { }
|
||||
backend.callbackManager.RunQuit()
|
||||
}
|
||||
|
||||
@@ -18,10 +18,17 @@ import "git.tebibyte.media/sashakoshka/stone"
|
||||
import "github.com/flopp/go-findfont"
|
||||
|
||||
// factory instantiates an X backend.
|
||||
func factory (application *stone.Application) (output stone.Backend, err error) {
|
||||
func factory (
|
||||
application *stone.Application,
|
||||
callbackManager *stone.CallbackManager,
|
||||
) (
|
||||
output stone.Backend,
|
||||
err error,
|
||||
) {
|
||||
backend := &Backend {
|
||||
application: application,
|
||||
config: application.Config(),
|
||||
application: application,
|
||||
config: application.Config(),
|
||||
callbackManager: callbackManager,
|
||||
}
|
||||
|
||||
// load font
|
||||
@@ -76,8 +83,6 @@ func factory (application *stone.Application) (output stone.Backend, err error)
|
||||
backend.metrics.windowWidth, backend.metrics.windowHeight,
|
||||
0)
|
||||
backend.window.Map()
|
||||
// TODO: also listen to mouse movement (compressed) and mouse and
|
||||
// keyboard buttons (uncompressed)
|
||||
err = backend.window.Listen (
|
||||
xproto.EventMaskStructureNotify,
|
||||
xproto.EventMaskPointerMotion,
|
||||
|
||||
@@ -14,17 +14,17 @@ 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)
|
||||
application *stone.Application
|
||||
config *stone.Config
|
||||
callbackManager *stone.CallbackManager
|
||||
connection *xgbutil.XUtil
|
||||
window *xwindow.Window
|
||||
canvas *xgraphics.Image
|
||||
|
||||
drawCellBounds bool
|
||||
drawBufferBounds bool
|
||||
|
||||
drawLock sync.Mutex
|
||||
lock sync.Mutex
|
||||
|
||||
font struct {
|
||||
face font.Face
|
||||
@@ -114,23 +114,6 @@ func (backend *Backend) calculateBufferSize () (width, height int) {
|
||||
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.ColorBackground]
|
||||
})
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user