x-backend #2
133
backends/x/x.go
133
backends/x/x.go
@ -1,6 +1,7 @@
|
||||
package x
|
||||
|
||||
import "os"
|
||||
// import "fmt"
|
||||
import "sync"
|
||||
import "image"
|
||||
import "image/draw"
|
||||
@ -9,7 +10,7 @@ import "golang.org/x/image/math/fixed"
|
||||
import "golang.org/x/image/font/opentype"
|
||||
import "golang.org/x/image/font/basicfont"
|
||||
|
||||
import "github.com/jezek/xgb"
|
||||
// import "github.com/jezek/xgb"
|
||||
import "github.com/jezek/xgbutil"
|
||||
import "github.com/jezek/xgb/xproto"
|
||||
import "github.com/jezek/xgbutil/ewmh"
|
||||
@ -31,12 +32,6 @@ type Backend struct {
|
||||
|
||||
drawLock sync.Mutex
|
||||
|
||||
ping struct {
|
||||
before chan(struct { })
|
||||
after chan(struct { })
|
||||
quit chan(struct { })
|
||||
}
|
||||
|
||||
font struct {
|
||||
face font.Face
|
||||
}
|
||||
@ -62,30 +57,8 @@ type Backend struct {
|
||||
|
||||
func (backend *Backend) Run (channel chan(stone.Event)) {
|
||||
backend.channel = channel
|
||||
|
||||
for {
|
||||
select {
|
||||
case <- backend.ping.before:
|
||||
// if the queue is empty, don't dequeue anything because
|
||||
// it would cause a fucking segfault lmao (???)
|
||||
if !xevent.Empty(backend.connection) {
|
||||
event, err := xevent.Dequeue(backend.connection)
|
||||
if err != nil {
|
||||
// TODO: do something with err
|
||||
}
|
||||
|
||||
if event != nil {
|
||||
backend.handleXEvent(event)
|
||||
}
|
||||
}
|
||||
|
||||
<- backend.ping.after
|
||||
|
||||
case <- backend.ping.quit:
|
||||
backend.shutDown()
|
||||
return
|
||||
}
|
||||
}
|
||||
xevent.Main(backend.connection)
|
||||
backend.shutDown()
|
||||
}
|
||||
|
||||
func (backend *Backend) Draw () {
|
||||
@ -104,10 +77,6 @@ func (backend *Backend) Draw () {
|
||||
backend.canvas.XDraw()
|
||||
backend.canvas.XPaint(backend.window.Id)
|
||||
} else {
|
||||
// backend.drawCells(false)
|
||||
// backend.canvas.XDraw()
|
||||
// backend.canvas.XPaint(backend.window.Id)
|
||||
// FIXME use this instead once it works
|
||||
backend.updateWindowAreas(backend.drawCells(false)...)
|
||||
}
|
||||
}
|
||||
@ -154,28 +123,44 @@ func (backend *Backend) SetIcon (icons []image.Image) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (backend *Backend) handleXEvent (event xgb.Event) {
|
||||
switch event.(type) {
|
||||
case xproto.ConfigureNotifyEvent:
|
||||
configureEvent := event.(xproto.ConfigureNotifyEvent)
|
||||
|
||||
newWidth := int(configureEvent.Width)
|
||||
newHeight := int(configureEvent.Height)
|
||||
sizeChanged :=
|
||||
backend.metrics.windowWidth != newWidth ||
|
||||
backend.metrics.windowHeight != newHeight
|
||||
backend.metrics.windowWidth = newWidth
|
||||
backend.metrics.windowHeight = newHeight
|
||||
func (backend *Backend) handleConfigureNotify (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.ConfigureNotifyEvent,
|
||||
) {
|
||||
configureEvent := *event.ConfigureNotifyEvent
|
||||
|
||||
newWidth := int(configureEvent.Width)
|
||||
newHeight := int(configureEvent.Height)
|
||||
sizeChanged :=
|
||||
backend.metrics.windowWidth != newWidth ||
|
||||
backend.metrics.windowHeight != newHeight
|
||||
backend.metrics.windowWidth = newWidth
|
||||
backend.metrics.windowHeight = newHeight
|
||||
|
||||
if sizeChanged {
|
||||
configureEvent =
|
||||
backend.compressConfigureNotify(configureEvent)
|
||||
backend.application.SetSize(backend.calculateBufferSize())
|
||||
backend.channel <- stone.EventResize { }
|
||||
}
|
||||
if sizeChanged {
|
||||
configureEvent =
|
||||
backend.compressConfigureNotify(configureEvent)
|
||||
backend.application.SetSize(backend.calculateBufferSize())
|
||||
backend.channel <- stone.EventResize { }
|
||||
}
|
||||
}
|
||||
|
||||
func (backend *Backend) handleButtonPress (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.ButtonPressEvent,
|
||||
) {
|
||||
buttonEvent := *event.ButtonPressEvent
|
||||
backend.channel <- stone.EventPress(buttonEvent.Detail)
|
||||
}
|
||||
|
||||
func (backend *Backend) handleButtonRelease (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.ButtonReleaseEvent,
|
||||
) {
|
||||
buttonEvent := *event.ButtonReleaseEvent
|
||||
backend.channel <- stone.EventRelease(buttonEvent.Detail)
|
||||
}
|
||||
|
||||
func (backend *Backend) compressConfigureNotify (
|
||||
firstEvent xproto.ConfigureNotifyEvent,
|
||||
) (
|
||||
@ -253,7 +238,8 @@ func (backend *Backend) drawCells (forceRedraw bool) (areas []image.Rectangle) {
|
||||
|
||||
cell := backend.application.Cell(x, y)
|
||||
content := cell.Rune()
|
||||
if content < 32 { continue }
|
||||
|
||||
if forceRedraw && content < 32 { continue }
|
||||
|
||||
areas = append(areas, backend.boundsOfCell(x, y))
|
||||
backend.drawRune(x, y, content)
|
||||
@ -269,6 +255,16 @@ func (backend *Backend) drawRune (x, y int, character rune) {
|
||||
// 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.ColorApplication),
|
||||
},
|
||||
backend.canvas,
|
||||
backend.boundsOfCell(x, y))
|
||||
|
||||
if character < 32 { return }
|
||||
|
||||
origin := backend.originOfCell(x, y + 1)
|
||||
destinationRectangle, mask, maskPoint, _, _ := backend.font.face.Glyph (
|
||||
fixed.Point26_6 {
|
||||
@ -277,13 +273,6 @@ func (backend *Backend) drawRune (x, y int, character rune) {
|
||||
},
|
||||
character)
|
||||
|
||||
fillRectangle (
|
||||
&image.Uniform {
|
||||
C: backend.config.Color(stone.ColorApplication),
|
||||
},
|
||||
backend.canvas,
|
||||
backend.boundsOfCell(x, y))
|
||||
|
||||
// strokeRectangle (
|
||||
// &image.Uniform {
|
||||
// C: backend.config.Color(stone.ColorForeground),
|
||||
@ -382,7 +371,16 @@ func factory (application *stone.Application) (output stone.Backend, err error)
|
||||
backend.metrics.windowWidth, backend.metrics.windowHeight,
|
||||
0)
|
||||
backend.window.Map()
|
||||
backend.window.Listen(xproto.EventMaskStructureNotify)
|
||||
// TODO: also listen to mouse movement (compressed) and mouse and
|
||||
// keyboard buttons (uncompressed)
|
||||
err = backend.window.Listen (
|
||||
xproto.EventMaskStructureNotify,
|
||||
// xproto.EventMaskPointerMotion,
|
||||
// xproto.EventMaskKeyPress,
|
||||
// xproto.EventMaskKeyRelease,
|
||||
xproto.EventMaskButtonPress,
|
||||
xproto.EventMaskButtonRelease,
|
||||
)
|
||||
backend.SetTitle(application.Title())
|
||||
backend.SetIcon(application.Icon())
|
||||
|
||||
@ -395,10 +393,13 @@ func factory (application *stone.Application) (output stone.Backend, err error)
|
||||
backend.shutDown()
|
||||
})
|
||||
|
||||
// start event loop
|
||||
backend.ping.before,
|
||||
backend.ping.after,
|
||||
backend.ping.quit = xevent.MainPing(backend.connection)
|
||||
// attatch event handlers
|
||||
xevent.ConfigureNotifyFun(backend.handleConfigureNotify).
|
||||
Connect(backend.connection, backend.window.Id)
|
||||
xevent.ButtonPressFun(backend.handleButtonPress).
|
||||
Connect(backend.connection, backend.window.Id)
|
||||
xevent.ButtonReleaseFun(backend.handleButtonRelease).
|
||||
Connect(backend.connection, backend.window.Id)
|
||||
|
||||
output = backend
|
||||
return
|
||||
|
65
examples/draw/main.go
Normal file
65
examples/draw/main.go
Normal file
@ -0,0 +1,65 @@
|
||||
package main
|
||||
|
||||
import "os"
|
||||
import "image"
|
||||
import _ "image/png"
|
||||
import "git.tebibyte.media/sashakoshka/stone"
|
||||
import _ "git.tebibyte.media/sashakoshka/stone/backends/x"
|
||||
|
||||
var application = &stone.Application { }
|
||||
var mousePressed bool
|
||||
|
||||
func main () {
|
||||
application.SetTitle("hellorld")
|
||||
application.SetSize(32, 16)
|
||||
|
||||
iconFile16, err := os.Open("assets/scaffold16.png")
|
||||
if err != nil { panic(err) }
|
||||
icon16, _, err := image.Decode(iconFile16)
|
||||
if err != nil { panic(err) }
|
||||
iconFile16.Close()
|
||||
iconFile32, err := os.Open("assets/scaffold32.png")
|
||||
if err != nil { panic(err) }
|
||||
icon32, _, err := image.Decode(iconFile32)
|
||||
if err != nil { panic(err) }
|
||||
iconFile16.Close()
|
||||
|
||||
application.SetIcon([]image.Image { icon16, icon32 })
|
||||
|
||||
channel, err := application.Run()
|
||||
if err != nil { panic(err) }
|
||||
|
||||
application.Draw()
|
||||
|
||||
for {
|
||||
event := <- channel
|
||||
switch event.(type) {
|
||||
case stone.EventQuit:
|
||||
os.Exit(0)
|
||||
|
||||
case stone.EventPress:
|
||||
event := event.(stone.EventPress)
|
||||
if stone.Button(event) == stone.MouseButtonLeft {
|
||||
mousePressed = true
|
||||
application.SetRune(0, 0, '+')
|
||||
application.Draw()
|
||||
}
|
||||
|
||||
case stone.EventRelease:
|
||||
event := event.(stone.EventRelease)
|
||||
if stone.Button(event) == stone.MouseButtonLeft {
|
||||
mousePressed = false
|
||||
application.SetRune(0, 0, 0)
|
||||
application.Draw()
|
||||
}
|
||||
|
||||
case stone.EventMouseMove:
|
||||
event := event.(stone.EventMouseMove)
|
||||
application.SetRune(event.X, event.Y, '#')
|
||||
application.Draw()
|
||||
|
||||
case stone.EventResize:
|
||||
application.Draw()
|
||||
}
|
||||
}
|
||||
}
|
31
input.go
31
input.go
@ -1,7 +1,5 @@
|
||||
package stone
|
||||
|
||||
// These should be identical to the glfw keys
|
||||
|
||||
type Button int
|
||||
|
||||
const (
|
||||
@ -129,15 +127,22 @@ const (
|
||||
KeyRightSuper Button = 257
|
||||
KeyMenu Button = 256
|
||||
|
||||
MouseButton1 Button = 0
|
||||
MouseButton2 Button = 1
|
||||
MouseButton3 Button = 2
|
||||
MouseButton4 Button = 3
|
||||
MouseButton5 Button = 4
|
||||
MouseButton6 Button = 5
|
||||
MouseButton7 Button = 6
|
||||
MouseButton8 Button = 7
|
||||
MouseButtonLeft Button = MouseButton1
|
||||
MouseButtonRight Button = MouseButton2
|
||||
MouseButtonMiddle Button = MouseButton3
|
||||
MouseButton1 Button = 1
|
||||
MouseButton2 Button = 2
|
||||
MouseButton3 Button = 3
|
||||
MouseButton4 Button = 4
|
||||
MouseButton5 Button = 5
|
||||
MouseButton6 Button = 6
|
||||
MouseButton7 Button = 7
|
||||
MouseButton8 Button = 8
|
||||
MouseButton9 Button = 9
|
||||
MouseButtonLeft Button = MouseButton1
|
||||
MouseButtonMiddle Button = MouseButton2
|
||||
MouseButtonRight Button = MouseButton3
|
||||
MouseButtonScrollUp Button = MouseButton4
|
||||
MouseButtonScrollDown Button = MouseButton5
|
||||
MouseButtonScrollLeft Button = MouseButton6
|
||||
MouseButtonScrollRight Button = MouseButton7
|
||||
MouseButtonBack Button = MouseButton8
|
||||
MouseButtonForward Button = MouseButton9
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user