robust-parenting #12
@ -14,7 +14,7 @@ type scrollSum struct {
|
||||
|
||||
const scrollDistance = 16
|
||||
|
||||
func (sum *scrollSum) add (button xproto.Button, window *Window, state uint16) {
|
||||
func (sum *scrollSum) add (button xproto.Button, window *window, state uint16) {
|
||||
shift :=
|
||||
(state & xproto.ModMaskShift) > 0 ||
|
||||
(state & window.backend.modifierMasks.shiftLock) > 0
|
||||
@ -44,7 +44,7 @@ func (sum *scrollSum) add (button xproto.Button, window *Window, state uint16) {
|
||||
|
||||
}
|
||||
|
||||
func (window *Window) handleExpose (
|
||||
func (window *window) handleExpose (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.ExposeEvent,
|
||||
) {
|
||||
@ -52,7 +52,7 @@ func (window *Window) handleExpose (
|
||||
window.pushRegion(region)
|
||||
}
|
||||
|
||||
func (window *Window) handleConfigureNotify (
|
||||
func (window *window) handleConfigureNotify (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.ConfigureNotifyEvent,
|
||||
) {
|
||||
@ -81,7 +81,7 @@ func (window *Window) handleConfigureNotify (
|
||||
}
|
||||
}
|
||||
|
||||
func (window *Window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (found bool) {
|
||||
func (window *window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (found bool) {
|
||||
nextEvents := xevent.Peek(window.backend.connection)
|
||||
if len(nextEvents) > 0 {
|
||||
untypedEvent := nextEvents[0]
|
||||
@ -97,7 +97,7 @@ func (window *Window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (fo
|
||||
return false
|
||||
}
|
||||
|
||||
func (window *Window) modifiersFromState (
|
||||
func (window *window) modifiersFromState (
|
||||
state uint16,
|
||||
) (
|
||||
modifiers input.Modifiers,
|
||||
@ -114,7 +114,7 @@ func (window *Window) modifiersFromState (
|
||||
}
|
||||
}
|
||||
|
||||
func (window *Window) handleKeyPress (
|
||||
func (window *window) handleKeyPress (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.KeyPressEvent,
|
||||
) {
|
||||
@ -141,7 +141,7 @@ func (window *Window) handleKeyPress (
|
||||
}
|
||||
}
|
||||
|
||||
func (window *Window) handleKeyRelease (
|
||||
func (window *window) handleKeyRelease (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.KeyReleaseEvent,
|
||||
) {
|
||||
@ -175,23 +175,25 @@ func (window *Window) handleKeyRelease (
|
||||
}
|
||||
}
|
||||
|
||||
func (window *Window) handleButtonPress (
|
||||
func (window *window) handleButtonPress (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.ButtonPressEvent,
|
||||
) {
|
||||
if window.child == nil { return }
|
||||
|
||||
if child, ok := window.child.(elements.MouseTarget); ok {
|
||||
buttonEvent := *event.ButtonPressEvent
|
||||
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 {
|
||||
buttonEvent := *event.ButtonPressEvent
|
||||
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 {
|
||||
if child, ok := window.child.(elements.ScrollTarget); ok {
|
||||
sum := scrollSum { }
|
||||
sum.add(buttonEvent.Detail, window, buttonEvent.State)
|
||||
window.compressScrollSum(buttonEvent, &sum)
|
||||
child.HandleMouseScroll (
|
||||
child.HandleScroll (
|
||||
int(buttonEvent.EventX),
|
||||
int(buttonEvent.EventY),
|
||||
float64(sum.x), float64(sum.y))
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
if child, ok := window.child.(elements.MouseTarget); ok {
|
||||
child.HandleMouseDown (
|
||||
int(buttonEvent.EventX),
|
||||
int(buttonEvent.EventY),
|
||||
@ -201,7 +203,7 @@ func (window *Window) handleButtonPress (
|
||||
|
||||
}
|
||||
|
||||
func (window *Window) handleButtonRelease (
|
||||
func (window *window) handleButtonRelease (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.ButtonReleaseEvent,
|
||||
) {
|
||||
@ -217,21 +219,21 @@ func (window *Window) handleButtonRelease (
|
||||
}
|
||||
}
|
||||
|
||||
func (window *Window) handleMotionNotify (
|
||||
func (window *window) handleMotionNotify (
|
||||
connection *xgbutil.XUtil,
|
||||
event xevent.MotionNotifyEvent,
|
||||
) {
|
||||
if window.child == nil { return }
|
||||
|
||||
if child, ok := window.child.(elements.MouseTarget); ok {
|
||||
if child, ok := window.child.(elements.MotionTarget); ok {
|
||||
motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
|
||||
child.HandleMouseMove (
|
||||
child.HandleMotion (
|
||||
int(motionEvent.EventX),
|
||||
int(motionEvent.EventY))
|
||||
}
|
||||
}
|
||||
|
||||
func (window *Window) compressExpose (
|
||||
func (window *window) compressExpose (
|
||||
firstEvent xproto.ExposeEvent,
|
||||
) (
|
||||
lastEvent xproto.ExposeEvent,
|
||||
@ -268,7 +270,7 @@ func (window *Window) compressExpose (
|
||||
return
|
||||
}
|
||||
|
||||
func (window *Window) compressConfigureNotify (
|
||||
func (window *window) compressConfigureNotify (
|
||||
firstEvent xproto.ConfigureNotifyEvent,
|
||||
) (
|
||||
lastEvent xproto.ConfigureNotifyEvent,
|
||||
@ -296,7 +298,7 @@ func (window *Window) compressConfigureNotify (
|
||||
return
|
||||
}
|
||||
|
||||
func (window *Window) compressScrollSum (
|
||||
func (window *window) compressScrollSum (
|
||||
firstEvent xproto.ButtonPressEvent,
|
||||
sum *scrollSum,
|
||||
) {
|
||||
@ -323,7 +325,7 @@ func (window *Window) compressScrollSum (
|
||||
return
|
||||
}
|
||||
|
||||
func (window *Window) compressMotionNotify (
|
||||
func (window *window) compressMotionNotify (
|
||||
firstEvent xproto.MotionNotifyEvent,
|
||||
) (
|
||||
lastEvent xproto.MotionNotifyEvent,
|
||||
|
@ -14,7 +14,7 @@ import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||
import "git.tebibyte.media/sashakoshka/tomo/elements"
|
||||
// import "runtime/debug"
|
||||
|
||||
type Window struct {
|
||||
type window struct {
|
||||
backend *Backend
|
||||
xWindow *xwindow.Window
|
||||
xCanvas *xgraphics.Image
|
||||
@ -40,7 +40,7 @@ func (backend *Backend) NewWindow (
|
||||
) {
|
||||
if backend == nil { panic("nil backend") }
|
||||
|
||||
window := &Window { backend: backend }
|
||||
window := &window { backend: backend }
|
||||
|
||||
window.xWindow, err = xwindow.Generate(backend.connection)
|
||||
if err != nil { return }
|
||||
@ -90,18 +90,15 @@ func (backend *Backend) NewWindow (
|
||||
return
|
||||
}
|
||||
|
||||
func (window *Window) Adopt (child elements.Element) {
|
||||
func (window *window) NotifyMinimumSizeChange (child elements.Element) {
|
||||
window.childMinimumSizeChangeCallback(child.MinimumSize())
|
||||
}
|
||||
|
||||
func (window *window) Adopt (child elements.Element) {
|
||||
// disown previous child
|
||||
if window.child != nil {
|
||||
window.child.OnDamage(nil)
|
||||
window.child.OnMinimumSizeChange(nil)
|
||||
}
|
||||
if previousChild, ok := window.child.(elements.Focusable); ok {
|
||||
previousChild.OnFocusRequest(nil)
|
||||
previousChild.OnFocusMotionRequest(nil)
|
||||
if previousChild.Focused() {
|
||||
previousChild.HandleUnfocus()
|
||||
}
|
||||
window.child.SetParent(nil)
|
||||
window.child.DrawTo(nil, image.Rectangle { }, nil)
|
||||
}
|
||||
|
||||
// adopt new child
|
||||
@ -112,15 +109,7 @@ func (window *Window) Adopt (child elements.Element) {
|
||||
if newChild, ok := child.(elements.Configurable); ok {
|
||||
newChild.SetConfig(window.config)
|
||||
}
|
||||
if newChild, ok := child.(elements.Focusable); ok {
|
||||
newChild.OnFocusRequest(window.childSelectionRequestCallback)
|
||||
}
|
||||
if child != nil {
|
||||
child.OnDamage(window.childDrawCallback)
|
||||
child.OnMinimumSizeChange (func () {
|
||||
window.childMinimumSizeChangeCallback (
|
||||
child.MinimumSize())
|
||||
})
|
||||
if !window.childMinimumSizeChangeCallback(child.MinimumSize()) {
|
||||
window.resizeChildToFit()
|
||||
window.redrawChildEntirely()
|
||||
@ -128,19 +117,19 @@ func (window *Window) Adopt (child elements.Element) {
|
||||
}
|
||||
}
|
||||
|
||||
func (window *Window) Child () (child elements.Element) {
|
||||
func (window *window) Child () (child elements.Element) {
|
||||
child = window.child
|
||||
return
|
||||
}
|
||||
|
||||
func (window *Window) SetTitle (title string) {
|
||||
func (window *window) SetTitle (title string) {
|
||||
ewmh.WmNameSet (
|
||||
window.backend.connection,
|
||||
window.xWindow.Id,
|
||||
title)
|
||||
}
|
||||
|
||||
func (window *Window) SetIcon (sizes []image.Image) {
|
||||
func (window *window) SetIcon (sizes []image.Image) {
|
||||
wmIcons := []ewmh.WmIcon { }
|
||||
|
||||
for _, icon := range sizes {
|
||||
@ -179,7 +168,7 @@ func (window *Window) SetIcon (sizes []image.Image) {
|
||||
wmIcons)
|
||||
}
|
||||
|
||||
func (window *Window) Show () {
|
||||
func (window *window) Show () {
|
||||
if window.child == nil {
|
||||
window.xCanvas.For (func (x, y int) xgraphics.BGRA {
|
||||
return xgraphics.BGRA { }
|
||||
@ -191,35 +180,35 @@ func (window *Window) Show () {
|
||||
window.xWindow.Map()
|
||||
}
|
||||
|
||||
func (window *Window) Hide () {
|
||||
func (window *window) Hide () {
|
||||
window.xWindow.Unmap()
|
||||
}
|
||||
|
||||
func (window *Window) Close () {
|
||||
func (window *window) Close () {
|
||||
if window.onClose != nil { window.onClose() }
|
||||
delete(window.backend.windows, window.xWindow.Id)
|
||||
window.xWindow.Destroy()
|
||||
}
|
||||
|
||||
func (window *Window) OnClose (callback func ()) {
|
||||
func (window *window) OnClose (callback func ()) {
|
||||
window.onClose = callback
|
||||
}
|
||||
|
||||
func (window *Window) SetTheme (theme theme.Theme) {
|
||||
func (window *window) SetTheme (theme theme.Theme) {
|
||||
window.theme = theme
|
||||
if child, ok := window.child.(elements.Themeable); ok {
|
||||
child.SetTheme(theme)
|
||||
}
|
||||
}
|
||||
|
||||
func (window *Window) SetConfig (config config.Config) {
|
||||
func (window *window) SetConfig (config config.Config) {
|
||||
window.config = config
|
||||
if child, ok := window.child.(elements.Configurable); ok {
|
||||
child.SetConfig(config)
|
||||
}
|
||||
}
|
||||
|
||||
func (window *Window) reallocateCanvas () {
|
||||
func (window *window) reallocateCanvas () {
|
||||
window.canvas.Reallocate(window.metrics.width, window.metrics.height)
|
||||
|
||||
previousWidth, previousHeight := 0, 0
|
||||
@ -250,23 +239,28 @@ func (window *Window) reallocateCanvas () {
|
||||
|
||||
}
|
||||
|
||||
func (window *Window) redrawChildEntirely () {
|
||||
window.pushRegion(window.paste(window.canvas))
|
||||
|
||||
func (window *window) redrawChildEntirely () {
|
||||
window.paste(window.canvas.Bounds())
|
||||
window.pushRegion(window.canvas.Bounds())
|
||||
}
|
||||
|
||||
func (window *Window) resizeChildToFit () {
|
||||
func (window *window) resizeChildToFit () {
|
||||
window.skipChildDrawCallback = true
|
||||
window.child.DrawTo(window.canvas, window.canvas.Bounds())
|
||||
window.child.DrawTo (
|
||||
window.canvas,
|
||||
window.canvas.Bounds(),
|
||||
window.childDrawCallback)
|
||||
window.skipChildDrawCallback = false
|
||||
}
|
||||
|
||||
func (window *Window) childDrawCallback (region canvas.Canvas) {
|
||||
func (window *window) childDrawCallback (region image.Rectangle) {
|
||||
if window.skipChildDrawCallback { return }
|
||||
window.pushRegion(window.paste(region))
|
||||
window.paste(region)
|
||||
window.pushRegion(region)
|
||||
}
|
||||
|
||||
func (window *Window) paste (canvas canvas.Canvas) (updatedRegion image.Rectangle) {
|
||||
func (window *window) paste (region image.Rectangle) {
|
||||
canvas := canvas.Cut(window.canvas, region)
|
||||
data, stride := canvas.Buffer()
|
||||
bounds := canvas.Bounds().Intersect(window.xCanvas.Bounds())
|
||||
|
||||
@ -286,11 +280,9 @@ func (window *Window) paste (canvas canvas.Canvas) (updatedRegion image.Rectangl
|
||||
dstData[index + 3] = rgba.A
|
||||
}
|
||||
}
|
||||
|
||||
return bounds
|
||||
}
|
||||
|
||||
func (window *Window) childMinimumSizeChangeCallback (width, height int) (resized bool) {
|
||||
func (window *window) childMinimumSizeChangeCallback (width, height int) (resized bool) {
|
||||
icccm.WmNormalHintsSet (
|
||||
window.backend.connection,
|
||||
window.xWindow.Id,
|
||||
@ -312,14 +304,14 @@ func (window *Window) childMinimumSizeChangeCallback (width, height int) (resize
|
||||
return false
|
||||
}
|
||||
|
||||
func (window *Window) childSelectionRequestCallback () (granted bool) {
|
||||
func (window *window) childSelectionRequestCallback () (granted bool) {
|
||||
if _, ok := window.child.(elements.Focusable); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (window *Window) childSelectionMotionRequestCallback (
|
||||
func (window *window) childSelectionMotionRequestCallback (
|
||||
direction input.KeynavDirection,
|
||||
) (
|
||||
granted bool,
|
||||
@ -333,7 +325,7 @@ func (window *Window) childSelectionMotionRequestCallback (
|
||||
return true
|
||||
}
|
||||
|
||||
func (window *Window) pushRegion (region image.Rectangle) {
|
||||
func (window *window) pushRegion (region image.Rectangle) {
|
||||
if window.xCanvas == nil { panic("whoopsie!!!!!!!!!!!!!!") }
|
||||
image, ok := window.xCanvas.SubImage(region).(*xgraphics.Image)
|
||||
if ok {
|
||||
|
@ -30,7 +30,7 @@ type Backend struct {
|
||||
theme theme.Theme
|
||||
config config.Config
|
||||
|
||||
windows map[xproto.Window] *Window
|
||||
windows map[xproto.Window] *window
|
||||
|
||||
open bool
|
||||
}
|
||||
@ -38,7 +38,7 @@ type Backend struct {
|
||||
// NewBackend instantiates an X backend.
|
||||
func NewBackend () (output tomo.Backend, err error) {
|
||||
backend := &Backend {
|
||||
windows: map[xproto.Window] *Window { },
|
||||
windows: map[xproto.Window] *window { },
|
||||
doChannel: make(chan func (), 0),
|
||||
theme: theme.Default { },
|
||||
config: config.Default { },
|
||||
@ -79,7 +79,7 @@ func (backend *Backend) Stop () {
|
||||
if !backend.open { return }
|
||||
backend.open = false
|
||||
|
||||
toClose := []*Window { }
|
||||
toClose := []*window { }
|
||||
for _, window := range backend.windows {
|
||||
toClose = append(toClose, window)
|
||||
}
|
||||
|
Reference in New Issue
Block a user