robust-parenting #12

Merged
sashakoshka merged 17 commits from robust-parenting into main 2023-03-15 22:34:08 -06:00
3 changed files with 62 additions and 68 deletions
Showing only changes of commit 14ad35d85c - Show all commits

View File

@ -14,7 +14,7 @@ type scrollSum struct {
const scrollDistance = 16 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 := shift :=
(state & xproto.ModMaskShift) > 0 || (state & xproto.ModMaskShift) > 0 ||
(state & window.backend.modifierMasks.shiftLock) > 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, connection *xgbutil.XUtil,
event xevent.ExposeEvent, event xevent.ExposeEvent,
) { ) {
@ -52,7 +52,7 @@ func (window *Window) handleExpose (
window.pushRegion(region) window.pushRegion(region)
} }
func (window *Window) handleConfigureNotify ( func (window *window) handleConfigureNotify (
connection *xgbutil.XUtil, connection *xgbutil.XUtil,
event xevent.ConfigureNotifyEvent, 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) nextEvents := xevent.Peek(window.backend.connection)
if len(nextEvents) > 0 { if len(nextEvents) > 0 {
untypedEvent := nextEvents[0] untypedEvent := nextEvents[0]
@ -97,7 +97,7 @@ func (window *Window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (fo
return false return false
} }
func (window *Window) modifiersFromState ( func (window *window) modifiersFromState (
state uint16, state uint16,
) ( ) (
modifiers input.Modifiers, modifiers input.Modifiers,
@ -114,7 +114,7 @@ func (window *Window) modifiersFromState (
} }
} }
func (window *Window) handleKeyPress ( func (window *window) handleKeyPress (
connection *xgbutil.XUtil, connection *xgbutil.XUtil,
event xevent.KeyPressEvent, event xevent.KeyPressEvent,
) { ) {
@ -141,7 +141,7 @@ func (window *Window) handleKeyPress (
} }
} }
func (window *Window) handleKeyRelease ( func (window *window) handleKeyRelease (
connection *xgbutil.XUtil, connection *xgbutil.XUtil,
event xevent.KeyReleaseEvent, event xevent.KeyReleaseEvent,
) { ) {
@ -175,23 +175,25 @@ func (window *Window) handleKeyRelease (
} }
} }
func (window *Window) handleButtonPress ( func (window *window) handleButtonPress (
connection *xgbutil.XUtil, connection *xgbutil.XUtil,
event xevent.ButtonPressEvent, event xevent.ButtonPressEvent,
) { ) {
if window.child == nil { return } if window.child == nil { return }
if child, ok := window.child.(elements.MouseTarget); ok { buttonEvent := *event.ButtonPressEvent
buttonEvent := *event.ButtonPressEvent if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 {
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { if child, ok := window.child.(elements.ScrollTarget); ok {
sum := scrollSum { } sum := scrollSum { }
sum.add(buttonEvent.Detail, window, buttonEvent.State) sum.add(buttonEvent.Detail, window, buttonEvent.State)
window.compressScrollSum(buttonEvent, &sum) window.compressScrollSum(buttonEvent, &sum)
child.HandleMouseScroll ( child.HandleScroll (
int(buttonEvent.EventX), int(buttonEvent.EventX),
int(buttonEvent.EventY), int(buttonEvent.EventY),
float64(sum.x), float64(sum.y)) float64(sum.x), float64(sum.y))
} else { }
} else {
if child, ok := window.child.(elements.MouseTarget); ok {
child.HandleMouseDown ( child.HandleMouseDown (
int(buttonEvent.EventX), int(buttonEvent.EventX),
int(buttonEvent.EventY), int(buttonEvent.EventY),
@ -201,7 +203,7 @@ func (window *Window) handleButtonPress (
} }
func (window *Window) handleButtonRelease ( func (window *window) handleButtonRelease (
connection *xgbutil.XUtil, connection *xgbutil.XUtil,
event xevent.ButtonReleaseEvent, event xevent.ButtonReleaseEvent,
) { ) {
@ -217,21 +219,21 @@ func (window *Window) handleButtonRelease (
} }
} }
func (window *Window) handleMotionNotify ( func (window *window) handleMotionNotify (
connection *xgbutil.XUtil, connection *xgbutil.XUtil,
event xevent.MotionNotifyEvent, event xevent.MotionNotifyEvent,
) { ) {
if window.child == nil { return } 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) motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
child.HandleMouseMove ( child.HandleMotion (
int(motionEvent.EventX), int(motionEvent.EventX),
int(motionEvent.EventY)) int(motionEvent.EventY))
} }
} }
func (window *Window) compressExpose ( func (window *window) compressExpose (
firstEvent xproto.ExposeEvent, firstEvent xproto.ExposeEvent,
) ( ) (
lastEvent xproto.ExposeEvent, lastEvent xproto.ExposeEvent,
@ -268,7 +270,7 @@ func (window *Window) compressExpose (
return return
} }
func (window *Window) compressConfigureNotify ( func (window *window) compressConfigureNotify (
firstEvent xproto.ConfigureNotifyEvent, firstEvent xproto.ConfigureNotifyEvent,
) ( ) (
lastEvent xproto.ConfigureNotifyEvent, lastEvent xproto.ConfigureNotifyEvent,
@ -296,7 +298,7 @@ func (window *Window) compressConfigureNotify (
return return
} }
func (window *Window) compressScrollSum ( func (window *window) compressScrollSum (
firstEvent xproto.ButtonPressEvent, firstEvent xproto.ButtonPressEvent,
sum *scrollSum, sum *scrollSum,
) { ) {
@ -323,7 +325,7 @@ func (window *Window) compressScrollSum (
return return
} }
func (window *Window) compressMotionNotify ( func (window *window) compressMotionNotify (
firstEvent xproto.MotionNotifyEvent, firstEvent xproto.MotionNotifyEvent,
) ( ) (
lastEvent xproto.MotionNotifyEvent, lastEvent xproto.MotionNotifyEvent,

View File

@ -14,7 +14,7 @@ import "git.tebibyte.media/sashakoshka/tomo/canvas"
import "git.tebibyte.media/sashakoshka/tomo/elements" import "git.tebibyte.media/sashakoshka/tomo/elements"
// import "runtime/debug" // import "runtime/debug"
type Window struct { type window struct {
backend *Backend backend *Backend
xWindow *xwindow.Window xWindow *xwindow.Window
xCanvas *xgraphics.Image xCanvas *xgraphics.Image
@ -40,7 +40,7 @@ func (backend *Backend) NewWindow (
) { ) {
if backend == nil { panic("nil backend") } if backend == nil { panic("nil backend") }
window := &Window { backend: backend } window := &window { backend: backend }
window.xWindow, err = xwindow.Generate(backend.connection) window.xWindow, err = xwindow.Generate(backend.connection)
if err != nil { return } if err != nil { return }
@ -90,18 +90,15 @@ func (backend *Backend) NewWindow (
return 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 // disown previous child
if window.child != nil { if window.child != nil {
window.child.OnDamage(nil) window.child.SetParent(nil)
window.child.OnMinimumSizeChange(nil) window.child.DrawTo(nil, image.Rectangle { }, nil)
}
if previousChild, ok := window.child.(elements.Focusable); ok {
previousChild.OnFocusRequest(nil)
previousChild.OnFocusMotionRequest(nil)
if previousChild.Focused() {
previousChild.HandleUnfocus()
}
} }
// adopt new child // adopt new child
@ -112,15 +109,7 @@ func (window *Window) Adopt (child elements.Element) {
if newChild, ok := child.(elements.Configurable); ok { if newChild, ok := child.(elements.Configurable); ok {
newChild.SetConfig(window.config) newChild.SetConfig(window.config)
} }
if newChild, ok := child.(elements.Focusable); ok {
newChild.OnFocusRequest(window.childSelectionRequestCallback)
}
if child != nil { if child != nil {
child.OnDamage(window.childDrawCallback)
child.OnMinimumSizeChange (func () {
window.childMinimumSizeChangeCallback (
child.MinimumSize())
})
if !window.childMinimumSizeChangeCallback(child.MinimumSize()) { if !window.childMinimumSizeChangeCallback(child.MinimumSize()) {
window.resizeChildToFit() window.resizeChildToFit()
window.redrawChildEntirely() 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 child = window.child
return return
} }
func (window *Window) SetTitle (title string) { func (window *window) SetTitle (title string) {
ewmh.WmNameSet ( ewmh.WmNameSet (
window.backend.connection, window.backend.connection,
window.xWindow.Id, window.xWindow.Id,
title) title)
} }
func (window *Window) SetIcon (sizes []image.Image) { func (window *window) SetIcon (sizes []image.Image) {
wmIcons := []ewmh.WmIcon { } wmIcons := []ewmh.WmIcon { }
for _, icon := range sizes { for _, icon := range sizes {
@ -179,7 +168,7 @@ func (window *Window) SetIcon (sizes []image.Image) {
wmIcons) wmIcons)
} }
func (window *Window) Show () { func (window *window) Show () {
if window.child == nil { if window.child == nil {
window.xCanvas.For (func (x, y int) xgraphics.BGRA { window.xCanvas.For (func (x, y int) xgraphics.BGRA {
return xgraphics.BGRA { } return xgraphics.BGRA { }
@ -191,35 +180,35 @@ func (window *Window) Show () {
window.xWindow.Map() window.xWindow.Map()
} }
func (window *Window) Hide () { func (window *window) Hide () {
window.xWindow.Unmap() window.xWindow.Unmap()
} }
func (window *Window) Close () { func (window *window) Close () {
if window.onClose != nil { window.onClose() } if window.onClose != nil { window.onClose() }
delete(window.backend.windows, window.xWindow.Id) delete(window.backend.windows, window.xWindow.Id)
window.xWindow.Destroy() window.xWindow.Destroy()
} }
func (window *Window) OnClose (callback func ()) { func (window *window) OnClose (callback func ()) {
window.onClose = callback window.onClose = callback
} }
func (window *Window) SetTheme (theme theme.Theme) { func (window *window) SetTheme (theme theme.Theme) {
window.theme = theme window.theme = theme
if child, ok := window.child.(elements.Themeable); ok { if child, ok := window.child.(elements.Themeable); ok {
child.SetTheme(theme) child.SetTheme(theme)
} }
} }
func (window *Window) SetConfig (config config.Config) { func (window *window) SetConfig (config config.Config) {
window.config = config window.config = config
if child, ok := window.child.(elements.Configurable); ok { if child, ok := window.child.(elements.Configurable); ok {
child.SetConfig(config) child.SetConfig(config)
} }
} }
func (window *Window) reallocateCanvas () { func (window *window) reallocateCanvas () {
window.canvas.Reallocate(window.metrics.width, window.metrics.height) window.canvas.Reallocate(window.metrics.width, window.metrics.height)
previousWidth, previousHeight := 0, 0 previousWidth, previousHeight := 0, 0
@ -250,23 +239,28 @@ func (window *Window) reallocateCanvas () {
} }
func (window *Window) redrawChildEntirely () { func (window *window) redrawChildEntirely () {
window.pushRegion(window.paste(window.canvas)) window.paste(window.canvas.Bounds())
window.pushRegion(window.canvas.Bounds())
} }
func (window *Window) resizeChildToFit () { func (window *window) resizeChildToFit () {
window.skipChildDrawCallback = true window.skipChildDrawCallback = true
window.child.DrawTo(window.canvas, window.canvas.Bounds()) window.child.DrawTo (
window.canvas,
window.canvas.Bounds(),
window.childDrawCallback)
window.skipChildDrawCallback = false window.skipChildDrawCallback = false
} }
func (window *Window) childDrawCallback (region canvas.Canvas) { func (window *window) childDrawCallback (region image.Rectangle) {
if window.skipChildDrawCallback { return } 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() data, stride := canvas.Buffer()
bounds := canvas.Bounds().Intersect(window.xCanvas.Bounds()) 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 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 ( icccm.WmNormalHintsSet (
window.backend.connection, window.backend.connection,
window.xWindow.Id, window.xWindow.Id,
@ -312,14 +304,14 @@ func (window *Window) childMinimumSizeChangeCallback (width, height int) (resize
return false return false
} }
func (window *Window) childSelectionRequestCallback () (granted bool) { func (window *window) childSelectionRequestCallback () (granted bool) {
if _, ok := window.child.(elements.Focusable); ok { if _, ok := window.child.(elements.Focusable); ok {
return true return true
} }
return false return false
} }
func (window *Window) childSelectionMotionRequestCallback ( func (window *window) childSelectionMotionRequestCallback (
direction input.KeynavDirection, direction input.KeynavDirection,
) ( ) (
granted bool, granted bool,
@ -333,7 +325,7 @@ func (window *Window) childSelectionMotionRequestCallback (
return true return true
} }
func (window *Window) pushRegion (region image.Rectangle) { func (window *window) pushRegion (region image.Rectangle) {
if window.xCanvas == nil { panic("whoopsie!!!!!!!!!!!!!!") } if window.xCanvas == nil { panic("whoopsie!!!!!!!!!!!!!!") }
image, ok := window.xCanvas.SubImage(region).(*xgraphics.Image) image, ok := window.xCanvas.SubImage(region).(*xgraphics.Image)
if ok { if ok {

View File

@ -30,7 +30,7 @@ type Backend struct {
theme theme.Theme theme theme.Theme
config config.Config config config.Config
windows map[xproto.Window] *Window windows map[xproto.Window] *window
open bool open bool
} }
@ -38,7 +38,7 @@ type Backend struct {
// NewBackend instantiates an X backend. // NewBackend instantiates an X backend.
func NewBackend () (output tomo.Backend, err error) { func NewBackend () (output tomo.Backend, err error) {
backend := &Backend { backend := &Backend {
windows: map[xproto.Window] *Window { }, windows: map[xproto.Window] *window { },
doChannel: make(chan func (), 0), doChannel: make(chan func (), 0),
theme: theme.Default { }, theme: theme.Default { },
config: config.Default { }, config: config.Default { },
@ -79,7 +79,7 @@ func (backend *Backend) Stop () {
if !backend.open { return } if !backend.open { return }
backend.open = false backend.open = false
toClose := []*Window { } toClose := []*window { }
for _, window := range backend.windows { for _, window := range backend.windows {
toClose = append(toClose, window) toClose = append(toClose, window)
} }