Basic support in X backend for new API
This commit is contained in:
parent
bb9c5df088
commit
e931717241
@ -10,18 +10,25 @@ type entity struct {
|
|||||||
children []*entity
|
children []*entity
|
||||||
element tomo.Element
|
element tomo.Element
|
||||||
|
|
||||||
drawDirty bool
|
bounds image.Rectangle
|
||||||
layoutDirty bool
|
clippedBounds image.Rectangle
|
||||||
|
minWidth int
|
||||||
bounds image.Rectangle
|
minHeight int
|
||||||
minWidth int
|
|
||||||
minHeight int
|
layoutInvalid bool
|
||||||
|
isContainer bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func bind (element tomo.Element) *entity {
|
func bind (parent *entity, window *window, element tomo.Element) *entity {
|
||||||
entity := &entity { drawDirty: true }
|
entity := &entity {
|
||||||
|
window: window,
|
||||||
|
parent: parent,
|
||||||
|
element: element,
|
||||||
|
}
|
||||||
|
entity.Invalidate()
|
||||||
if _, ok := element.(tomo.Container); ok {
|
if _, ok := element.(tomo.Container); ok {
|
||||||
entity.layoutDirty = true
|
entity.isContainer = true
|
||||||
|
entity.InvalidateLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
element.Bind(entity)
|
element.Bind(entity)
|
||||||
@ -38,7 +45,8 @@ func (entity *entity) unbind () {
|
|||||||
// ----------- Entity ----------- //
|
// ----------- Entity ----------- //
|
||||||
|
|
||||||
func (entity *entity) Invalidate () {
|
func (entity *entity) Invalidate () {
|
||||||
entity.drawDirty = true
|
if entity.window.system.invalidateIgnore { return }
|
||||||
|
entity.window.drawingInvalid.Add(entity)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entity *entity) Bounds () image.Rectangle {
|
func (entity *entity) Bounds () image.Rectangle {
|
||||||
@ -64,18 +72,20 @@ func (entity *entity) DrawBackground (destination canvas.Canvas, bounds image.Re
|
|||||||
// ----------- ContainerEntity ----------- //
|
// ----------- ContainerEntity ----------- //
|
||||||
|
|
||||||
func (entity *entity) InvalidateLayout () {
|
func (entity *entity) InvalidateLayout () {
|
||||||
entity.layoutDirty = true
|
if !entity.isContainer { return }
|
||||||
|
entity.layoutInvalid = true
|
||||||
|
entity.window.system.anyLayoutInvalid = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entity *entity) Adopt (child tomo.Element) {
|
func (entity *entity) Adopt (child tomo.Element) {
|
||||||
entity.children = append(entity.children, bind(child))
|
entity.children = append(entity.children, bind(entity, entity.window, child))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entity *entity) Insert (index int, child tomo.Element) {
|
func (entity *entity) Insert (index int, child tomo.Element) {
|
||||||
entity.children = append (
|
entity.children = append (
|
||||||
entity.children[:index + 1],
|
entity.children[:index + 1],
|
||||||
entity.children[index:]...)
|
entity.children[index:]...)
|
||||||
entity.children[index] = bind(child)
|
entity.children[index] = bind(entity, entity.window, child)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entity *entity) Disown (index int) {
|
func (entity *entity) Disown (index int) {
|
||||||
@ -104,7 +114,13 @@ func (entity *entity) CountChildren () int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (entity *entity) PlaceChild (index int, bounds image.Rectangle) {
|
func (entity *entity) PlaceChild (index int, bounds image.Rectangle) {
|
||||||
entity.children[index].bounds = bounds
|
child := entity.children[index]
|
||||||
|
child.bounds = bounds
|
||||||
|
child.clippedBounds = entity.bounds.Intersect(bounds)
|
||||||
|
child.Invalidate()
|
||||||
|
if child.isContainer {
|
||||||
|
child.InvalidateLayout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entity *entity) ChildMinimumSize (index int) (width, height int) {
|
func (entity *entity) ChildMinimumSize (index int) (width, height int) {
|
||||||
|
@ -41,7 +41,6 @@ func (sum *scrollSum) add (button xproto.Button, window *window, state uint16) {
|
|||||||
sum.x += scrollDistance
|
sum.x += scrollDistance
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) handleExpose (
|
func (window *window) handleExpose (
|
||||||
@ -49,6 +48,7 @@ func (window *window) handleExpose (
|
|||||||
event xevent.ExposeEvent,
|
event xevent.ExposeEvent,
|
||||||
) {
|
) {
|
||||||
_, region := window.compressExpose(*event.ExposeEvent)
|
_, region := window.compressExpose(*event.ExposeEvent)
|
||||||
|
window.system.afterEvent()
|
||||||
window.pushRegion(region)
|
window.pushRegion(region)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +74,6 @@ func (window *window) handleConfigureNotify (
|
|||||||
window.updateBounds (
|
window.updateBounds (
|
||||||
configureEvent.X, configureEvent.Y,
|
configureEvent.X, configureEvent.Y,
|
||||||
configureEvent.Width, configureEvent.Height)
|
configureEvent.Width, configureEvent.Height)
|
||||||
|
|
||||||
|
|
||||||
if sizeChanged {
|
if sizeChanged {
|
||||||
configureEvent = window.compressConfigureNotify(configureEvent)
|
configureEvent = window.compressConfigureNotify(configureEvent)
|
||||||
@ -85,8 +84,11 @@ func (window *window) handleConfigureNotify (
|
|||||||
window.resizeChildToFit()
|
window.resizeChildToFit()
|
||||||
|
|
||||||
if !window.exposeEventFollows(configureEvent) {
|
if !window.exposeEventFollows(configureEvent) {
|
||||||
window.redrawChildEntirely()
|
window.child.Invalidate()
|
||||||
|
window.child.InvalidateLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.system.afterEvent()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,21 +138,21 @@ func (window *window) handleKeyPress (
|
|||||||
modifiers.NumberPad = numberPad
|
modifiers.NumberPad = numberPad
|
||||||
|
|
||||||
if key == input.KeyTab && modifiers.Alt {
|
if key == input.KeyTab && modifiers.Alt {
|
||||||
if child, ok := window.child.(tomo.Focusable); ok {
|
// if child, ok := window.child.element.(tomo.Focusable); ok {
|
||||||
direction := input.KeynavDirectionForward
|
// direction := input.KeynavDirectionForward
|
||||||
if modifiers.Shift {
|
// if modifiers.Shift {
|
||||||
direction = input.KeynavDirectionBackward
|
// direction = input.KeynavDirectionBackward
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if !child.HandleFocus(direction) {
|
// // TODO
|
||||||
child.HandleUnfocus()
|
// }
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if key == input.KeyEscape && window.shy {
|
} else if key == input.KeyEscape && window.shy {
|
||||||
window.Close()
|
window.Close()
|
||||||
} else if child, ok := window.child.(tomo.KeyboardTarget); ok {
|
} else if child, ok := window.child.element.(tomo.KeyboardTarget); ok {
|
||||||
child.HandleKeyDown(key, modifiers)
|
child.HandleKeyDown(key, modifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.system.afterEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) handleKeyRelease (
|
func (window *window) handleKeyRelease (
|
||||||
@ -182,9 +184,11 @@ func (window *window) handleKeyRelease (
|
|||||||
modifiers := window.modifiersFromState(keyEvent.State)
|
modifiers := window.modifiersFromState(keyEvent.State)
|
||||||
modifiers.NumberPad = numberPad
|
modifiers.NumberPad = numberPad
|
||||||
|
|
||||||
if child, ok := window.child.(tomo.KeyboardTarget); ok {
|
if child, ok := window.child.element.(tomo.KeyboardTarget); ok {
|
||||||
child.HandleKeyUp(key, modifiers)
|
child.HandleKeyUp(key, modifiers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.system.afterEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) handleButtonPress (
|
func (window *window) handleButtonPress (
|
||||||
@ -205,7 +209,7 @@ func (window *window) handleButtonPress (
|
|||||||
if !insideWindow && window.shy && !scrolling {
|
if !insideWindow && window.shy && !scrolling {
|
||||||
window.Close()
|
window.Close()
|
||||||
} else if scrolling {
|
} else if scrolling {
|
||||||
if child, ok := window.child.(tomo.ScrollTarget); ok {
|
if child, ok := window.child.element.(tomo.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)
|
||||||
@ -215,7 +219,7 @@ func (window *window) handleButtonPress (
|
|||||||
float64(sum.x), float64(sum.y))
|
float64(sum.x), float64(sum.y))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if child, ok := window.child.(tomo.MouseTarget); ok {
|
if child, ok := window.child.element.(tomo.MouseTarget); ok {
|
||||||
child.HandleMouseDown (
|
child.HandleMouseDown (
|
||||||
int(buttonEvent.EventX),
|
int(buttonEvent.EventX),
|
||||||
int(buttonEvent.EventY),
|
int(buttonEvent.EventY),
|
||||||
@ -223,6 +227,7 @@ func (window *window) handleButtonPress (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.system.afterEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) handleButtonRelease (
|
func (window *window) handleButtonRelease (
|
||||||
@ -231,7 +236,7 @@ func (window *window) handleButtonRelease (
|
|||||||
) {
|
) {
|
||||||
if window.child == nil { return }
|
if window.child == nil { return }
|
||||||
|
|
||||||
if child, ok := window.child.(tomo.MouseTarget); ok {
|
if child, ok := window.child.element.(tomo.MouseTarget); ok {
|
||||||
buttonEvent := *event.ButtonReleaseEvent
|
buttonEvent := *event.ButtonReleaseEvent
|
||||||
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return }
|
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return }
|
||||||
child.HandleMouseUp (
|
child.HandleMouseUp (
|
||||||
@ -239,6 +244,8 @@ func (window *window) handleButtonRelease (
|
|||||||
int(buttonEvent.EventY),
|
int(buttonEvent.EventY),
|
||||||
input.Button(buttonEvent.Detail))
|
input.Button(buttonEvent.Detail))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.system.afterEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) handleMotionNotify (
|
func (window *window) handleMotionNotify (
|
||||||
@ -247,12 +254,14 @@ func (window *window) handleMotionNotify (
|
|||||||
) {
|
) {
|
||||||
if window.child == nil { return }
|
if window.child == nil { return }
|
||||||
|
|
||||||
if child, ok := window.child.(tomo.MotionTarget); ok {
|
if child, ok := window.child.element.(tomo.MotionTarget); ok {
|
||||||
motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
|
motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
|
||||||
child.HandleMotion (
|
child.HandleMotion (
|
||||||
int(motionEvent.EventX),
|
int(motionEvent.EventX),
|
||||||
int(motionEvent.EventY))
|
int(motionEvent.EventY))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.system.afterEvent()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) handleSelectionNotify (
|
func (window *window) handleSelectionNotify (
|
||||||
|
109
backends/x/system.go
Normal file
109
backends/x/system.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
package x
|
||||||
|
|
||||||
|
import "image"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
|
|
||||||
|
type entitySet map[*entity] struct { }
|
||||||
|
|
||||||
|
func (set entitySet) Empty () bool {
|
||||||
|
return len(set) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (set entitySet) Has (entity *entity) bool {
|
||||||
|
_, ok := set[entity]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (set entitySet) Add (entity *entity) {
|
||||||
|
set[entity] = struct { } { }
|
||||||
|
}
|
||||||
|
|
||||||
|
type system struct {
|
||||||
|
child *entity
|
||||||
|
focused *entity
|
||||||
|
canvas canvas.BasicCanvas
|
||||||
|
|
||||||
|
theme tomo.Theme
|
||||||
|
config tomo.Config
|
||||||
|
|
||||||
|
invalidateIgnore bool
|
||||||
|
drawingInvalid entitySet
|
||||||
|
anyLayoutInvalid bool
|
||||||
|
|
||||||
|
pushFunc func (image.Rectangle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (system *system) initialize () {
|
||||||
|
system.drawingInvalid = make(entitySet)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (system *system) SetTheme (theme tomo.Theme) {
|
||||||
|
system.theme = theme
|
||||||
|
if system.child == nil { return }
|
||||||
|
if child, ok := system.child.element.(tomo.Themeable); ok {
|
||||||
|
child.SetTheme(theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (system *system) SetConfig (config tomo.Config) {
|
||||||
|
system.config = config
|
||||||
|
if system.child == nil { return }
|
||||||
|
if child, ok := system.child.element.(tomo.Configurable); ok {
|
||||||
|
child.SetConfig(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (system *system) resizeChildToFit () {
|
||||||
|
system.child.bounds = system.canvas.Bounds()
|
||||||
|
system.child.clippedBounds = system.child.bounds
|
||||||
|
system.child.Invalidate()
|
||||||
|
if system.child.isContainer {
|
||||||
|
system.child.InvalidateLayout()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (system *system) afterEvent () {
|
||||||
|
if system.anyLayoutInvalid {
|
||||||
|
system.layout(system.child, false)
|
||||||
|
system.anyLayoutInvalid = false
|
||||||
|
}
|
||||||
|
system.draw()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (system *system) layout (entity *entity, force bool) {
|
||||||
|
if entity == nil { return }
|
||||||
|
if entity.layoutInvalid == true || force {
|
||||||
|
entity.element.(tomo.Container).Layout()
|
||||||
|
entity.layoutInvalid = false
|
||||||
|
force = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, child := range entity.children {
|
||||||
|
system.layout(child, force)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (system *system) draw () {
|
||||||
|
finalBounds := image.Rectangle { }
|
||||||
|
|
||||||
|
// ignore invalidations that result from drawing elements, because if an
|
||||||
|
// element decides to do that it really needs to rethink its life
|
||||||
|
// choices.
|
||||||
|
system.invalidateIgnore = true
|
||||||
|
defer func () { system.invalidateIgnore = false } ()
|
||||||
|
|
||||||
|
for entity := range system.drawingInvalid {
|
||||||
|
entity.element.Draw (canvas.Cut (
|
||||||
|
system.canvas,
|
||||||
|
entity.clippedBounds))
|
||||||
|
finalBounds = finalBounds.Union(entity.clippedBounds)
|
||||||
|
}
|
||||||
|
system.drawingInvalid = make(entitySet)
|
||||||
|
|
||||||
|
// TODO: don't just union all the bounds together, we can definetly
|
||||||
|
// consolidateupdated regions more efficiently than this.
|
||||||
|
if !finalBounds.Empty() {
|
||||||
|
system.pushFunc(finalBounds)
|
||||||
|
}
|
||||||
|
}
|
@ -13,20 +13,16 @@ import "github.com/jezek/xgbutil/mousebind"
|
|||||||
import "github.com/jezek/xgbutil/xgraphics"
|
import "github.com/jezek/xgbutil/xgraphics"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/data"
|
import "git.tebibyte.media/sashakoshka/tomo/data"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
||||||
// import "runtime/debug"
|
|
||||||
|
|
||||||
type mainWindow struct { *window }
|
type mainWindow struct { *window }
|
||||||
type menuWindow struct { *window }
|
type menuWindow struct { *window }
|
||||||
type window struct {
|
type window struct {
|
||||||
|
system
|
||||||
|
|
||||||
backend *Backend
|
backend *Backend
|
||||||
xWindow *xwindow.Window
|
xWindow *xwindow.Window
|
||||||
xCanvas *xgraphics.Image
|
xCanvas *xgraphics.Image
|
||||||
canvas canvas.BasicCanvas
|
|
||||||
child *entity
|
|
||||||
focused *entity
|
|
||||||
onClose func ()
|
|
||||||
|
|
||||||
title, application string
|
title, application string
|
||||||
|
|
||||||
@ -34,15 +30,14 @@ type window struct {
|
|||||||
hasModal bool
|
hasModal bool
|
||||||
shy bool
|
shy bool
|
||||||
|
|
||||||
theme tomo.Theme
|
|
||||||
config tomo.Config
|
|
||||||
|
|
||||||
selectionRequest *selectionRequest
|
selectionRequest *selectionRequest
|
||||||
selectionClaim *selectionClaim
|
selectionClaim *selectionClaim
|
||||||
|
|
||||||
metrics struct {
|
metrics struct {
|
||||||
bounds image.Rectangle
|
bounds image.Rectangle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onClose func ()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (backend *Backend) NewWindow (
|
func (backend *Backend) NewWindow (
|
||||||
@ -53,6 +48,10 @@ func (backend *Backend) NewWindow (
|
|||||||
) {
|
) {
|
||||||
if backend == nil { panic("nil backend") }
|
if backend == nil { panic("nil backend") }
|
||||||
window, err := backend.newWindow(bounds, false)
|
window, err := backend.newWindow(bounds, false)
|
||||||
|
|
||||||
|
window.system.initialize()
|
||||||
|
window.system.pushFunc = window.paste
|
||||||
|
|
||||||
output = mainWindow { window }
|
output = mainWindow { window }
|
||||||
return output, err
|
return output, err
|
||||||
}
|
}
|
||||||
@ -136,69 +135,24 @@ func (backend *Backend) newWindow (
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) NotifyMinimumSizeChange (child tomo.Element) {
|
|
||||||
window.childMinimumSizeChangeCallback(child.MinimumSize())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) Window () tomo.Window {
|
func (window *window) Window () tomo.Window {
|
||||||
return window
|
return window
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) RequestFocus (
|
|
||||||
child tomo.Focusable,
|
|
||||||
) (
|
|
||||||
granted bool,
|
|
||||||
) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) RequestFocusNext (child tomo.Focusable) {
|
|
||||||
if child, ok := window.child.(tomo.Focusable); ok {
|
|
||||||
if !child.HandleFocus(input.KeynavDirectionForward) {
|
|
||||||
child.HandleUnfocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) RequestFocusPrevious (child tomo.Focusable) {
|
|
||||||
if child, ok := window.child.(tomo.Focusable); ok {
|
|
||||||
if !child.HandleFocus(input.KeynavDirectionBackward) {
|
|
||||||
child.HandleUnfocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) Adopt (child tomo.Element) {
|
func (window *window) Adopt (child tomo.Element) {
|
||||||
// disown previous child
|
// disown previous child
|
||||||
if window.child != nil {
|
if window.child != nil {
|
||||||
window.child.SetParent(nil)
|
window.child.unbind()
|
||||||
window.child.DrawTo(nil, image.Rectangle { }, nil)
|
window.child = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// adopt new child
|
||||||
if child != nil {
|
if child != nil {
|
||||||
// adopt new child
|
window.child = bind(nil, window, child)
|
||||||
window.child = child
|
window.resizeChildToFit()
|
||||||
child.SetParent(window)
|
|
||||||
if newChild, ok := child.(tomo.Themeable); ok {
|
|
||||||
newChild.SetTheme(window.theme)
|
|
||||||
}
|
|
||||||
if newChild, ok := child.(tomo.Configurable); ok {
|
|
||||||
newChild.SetConfig(window.config)
|
|
||||||
}
|
|
||||||
if child != nil {
|
|
||||||
if !window.childMinimumSizeChangeCallback(child.MinimumSize()) {
|
|
||||||
window.resizeChildToFit()
|
|
||||||
window.redrawChildEntirely()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) Child () (child tomo.Element) {
|
|
||||||
child = window.child
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) SetTitle (title string) {
|
func (window *window) SetTitle (title string) {
|
||||||
window.title = title
|
window.title = title
|
||||||
ewmh.WmNameSet (
|
ewmh.WmNameSet (
|
||||||
@ -317,43 +271,6 @@ func (window menuWindow) Pin () {
|
|||||||
// TODO iungrab keyboard and mouse
|
// TODO iungrab keyboard and mouse
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) grabInput () {
|
|
||||||
keybind.GrabKeyboard(window.backend.connection, window.xWindow.Id)
|
|
||||||
mousebind.GrabPointer (
|
|
||||||
window.backend.connection,
|
|
||||||
window.xWindow.Id,
|
|
||||||
window.backend.connection.RootWin(), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) ungrabInput () {
|
|
||||||
keybind.UngrabKeyboard(window.backend.connection)
|
|
||||||
mousebind.UngrabPointer(window.backend.connection)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) inheritProperties (parent *window) {
|
|
||||||
window.SetApplicationName(parent.application)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) setType (ty string) error {
|
|
||||||
return ewmh.WmWindowTypeSet (
|
|
||||||
window.backend.connection,
|
|
||||||
window.xWindow.Id,
|
|
||||||
[]string { "_NET_WM_WINDOW_TYPE_" + ty })
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) setClientLeader (leader *window) error {
|
|
||||||
hints, _ := icccm.WmHintsGet(window.backend.connection, window.xWindow.Id)
|
|
||||||
if hints == nil {
|
|
||||||
hints = &icccm.Hints { }
|
|
||||||
}
|
|
||||||
hints.Flags |= icccm.HintWindowGroup
|
|
||||||
hints.WindowGroup = leader.xWindow.Id
|
|
||||||
return icccm.WmHintsSet (
|
|
||||||
window.backend.connection,
|
|
||||||
window.xWindow.Id,
|
|
||||||
hints)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
@ -362,7 +279,7 @@ func (window *window) Show () {
|
|||||||
|
|
||||||
window.pushRegion(window.xCanvas.Bounds())
|
window.pushRegion(window.xCanvas.Bounds())
|
||||||
}
|
}
|
||||||
|
|
||||||
window.xWindow.Map()
|
window.xWindow.Map()
|
||||||
if window.shy { window.grabInput() }
|
if window.shy { window.grabInput() }
|
||||||
}
|
}
|
||||||
@ -417,18 +334,41 @@ func (window *window) OnClose (callback func ()) {
|
|||||||
window.onClose = callback
|
window.onClose = callback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) SetTheme (theme tomo.Theme) {
|
func (window *window) grabInput () {
|
||||||
window.theme = theme
|
keybind.GrabKeyboard(window.backend.connection, window.xWindow.Id)
|
||||||
if child, ok := window.child.(tomo.Themeable); ok {
|
mousebind.GrabPointer (
|
||||||
child.SetTheme(theme)
|
window.backend.connection,
|
||||||
}
|
window.xWindow.Id,
|
||||||
|
window.backend.connection.RootWin(), 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) SetConfig (config tomo.Config) {
|
func (window *window) ungrabInput () {
|
||||||
window.config = config
|
keybind.UngrabKeyboard(window.backend.connection)
|
||||||
if child, ok := window.child.(tomo.Configurable); ok {
|
mousebind.UngrabPointer(window.backend.connection)
|
||||||
child.SetConfig(config)
|
}
|
||||||
|
|
||||||
|
func (window *window) inheritProperties (parent *window) {
|
||||||
|
window.SetApplicationName(parent.application)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (window *window) setType (ty string) error {
|
||||||
|
return ewmh.WmWindowTypeSet (
|
||||||
|
window.backend.connection,
|
||||||
|
window.xWindow.Id,
|
||||||
|
[]string { "_NET_WM_WINDOW_TYPE_" + ty })
|
||||||
|
}
|
||||||
|
|
||||||
|
func (window *window) setClientLeader (leader *window) error {
|
||||||
|
hints, _ := icccm.WmHintsGet(window.backend.connection, window.xWindow.Id)
|
||||||
|
if hints == nil {
|
||||||
|
hints = &icccm.Hints { }
|
||||||
}
|
}
|
||||||
|
hints.Flags |= icccm.HintWindowGroup
|
||||||
|
hints.WindowGroup = leader.xWindow.Id
|
||||||
|
return icccm.WmHintsSet (
|
||||||
|
window.backend.connection,
|
||||||
|
window.xWindow.Id,
|
||||||
|
hints)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) reallocateCanvas () {
|
func (window *window) reallocateCanvas () {
|
||||||
@ -464,26 +404,6 @@ func (window *window) reallocateCanvas () {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) redrawChildEntirely () {
|
|
||||||
window.paste(window.canvas.Bounds())
|
|
||||||
window.pushRegion(window.canvas.Bounds())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) resizeChildToFit () {
|
|
||||||
window.skipChildDrawCallback = true
|
|
||||||
window.child.DrawTo (
|
|
||||||
window.canvas,
|
|
||||||
window.canvas.Bounds(),
|
|
||||||
window.childDrawCallback)
|
|
||||||
window.skipChildDrawCallback = false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) childDrawCallback (region image.Rectangle) {
|
|
||||||
if window.skipChildDrawCallback { return }
|
|
||||||
window.paste(region)
|
|
||||||
window.pushRegion(region)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (window *window) paste (region image.Rectangle) {
|
func (window *window) paste (region image.Rectangle) {
|
||||||
canvas := canvas.Cut(window.canvas, region)
|
canvas := canvas.Cut(window.canvas, region)
|
||||||
data, stride := canvas.Buffer()
|
data, stride := canvas.Buffer()
|
||||||
@ -492,7 +412,6 @@ func (window *window) paste (region image.Rectangle) {
|
|||||||
dstStride := window.xCanvas.Stride
|
dstStride := window.xCanvas.Stride
|
||||||
dstData := window.xCanvas.Pix
|
dstData := window.xCanvas.Pix
|
||||||
|
|
||||||
// debug.PrintStack()
|
|
||||||
for y := bounds.Min.Y; y < bounds.Max.Y; y ++ {
|
for y := bounds.Min.Y; y < bounds.Max.Y; y ++ {
|
||||||
srcYComponent := y * stride
|
srcYComponent := y * stride
|
||||||
dstYComponent := y * dstStride
|
dstYComponent := y * dstStride
|
||||||
@ -507,6 +426,18 @@ func (window *window) paste (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 {
|
||||||
|
image.XDraw()
|
||||||
|
image.XExpPaint (
|
||||||
|
window.xWindow.Id,
|
||||||
|
image.Bounds().Min.X,
|
||||||
|
image.Bounds().Min.Y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
@ -528,15 +459,3 @@ func (window *window) childMinimumSizeChangeCallback (width, height int) (resize
|
|||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) pushRegion (region image.Rectangle) {
|
|
||||||
if window.xCanvas == nil { panic("whoopsie!!!!!!!!!!!!!!") }
|
|
||||||
image, ok := window.xCanvas.SubImage(region).(*xgraphics.Image)
|
|
||||||
if ok {
|
|
||||||
image.XDraw()
|
|
||||||
image.XExpPaint (
|
|
||||||
window.xWindow.Id,
|
|
||||||
image.Bounds().Min.X,
|
|
||||||
image.Bounds().Min.Y)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -67,6 +67,9 @@ func (backend *Backend) Run () (err error) {
|
|||||||
<- pingAfter
|
<- pingAfter
|
||||||
case callback := <- backend.doChannel:
|
case callback := <- backend.doChannel:
|
||||||
callback()
|
callback()
|
||||||
|
for _, window := range backend.windows {
|
||||||
|
window.system.afterEvent()
|
||||||
|
}
|
||||||
case <- pingQuit:
|
case <- pingQuit:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ func NewArtist () *Artist {
|
|||||||
|
|
||||||
func (element *Artist) Bind (entity tomo.Entity) {
|
func (element *Artist) Bind (entity tomo.Entity) {
|
||||||
element.entity = entity
|
element.entity = entity
|
||||||
entity.SetMinimumSize(240, 240)
|
if entity != nil { entity.SetMinimumSize(240, 240) }
|
||||||
}
|
}
|
||||||
|
|
||||||
func (element *Artist) Draw (destination canvas.Canvas) {
|
func (element *Artist) Draw (destination canvas.Canvas) {
|
||||||
|
@ -15,9 +15,6 @@ type Window interface {
|
|||||||
// these at one time.
|
// these at one time.
|
||||||
Adopt (Element)
|
Adopt (Element)
|
||||||
|
|
||||||
// Child returns the root element of the window.
|
|
||||||
Child () Element
|
|
||||||
|
|
||||||
// SetTitle sets the title that appears on the window's title bar. This
|
// SetTitle sets the title that appears on the window's title bar. This
|
||||||
// method might have no effect with some backends.
|
// method might have no effect with some backends.
|
||||||
SetTitle (string)
|
SetTitle (string)
|
||||||
|
Reference in New Issue
Block a user