reorganize #17
@ -3,7 +3,7 @@ package ability
|
|||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/canvas"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
|
||||||
// Layoutable represents an element that needs to perform layout calculations
|
// Layoutable represents an element that needs to perform layout calculations
|
||||||
// before it can draw itself.
|
// before it can draw itself.
|
||||||
@ -23,7 +23,7 @@ type Container interface {
|
|||||||
// the specified canvas. The bounds of this canvas specify the area that
|
// the specified canvas. The bounds of this canvas specify the area that
|
||||||
// is actually drawn to, while the Entity bounds specify the actual area
|
// is actually drawn to, while the Entity bounds specify the actual area
|
||||||
// of the element.
|
// of the element.
|
||||||
DrawBackground (canvas.Canvas)
|
DrawBackground (artist.Canvas)
|
||||||
|
|
||||||
// HandleChildMinimumSizeChange is called when a child's minimum size is
|
// HandleChildMinimumSizeChange is called when a child's minimum size is
|
||||||
// changed.
|
// changed.
|
||||||
|
21
plugins/x/main.go
Normal file
21
plugins/x/main.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Plugin x provides the X11 backend as a plugin.
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/plugins/x/x"
|
||||||
|
|
||||||
|
func Expects () tomo.Version {
|
||||||
|
return tomo.Version { 0, 0, 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
func Name () string {
|
||||||
|
return "X"
|
||||||
|
}
|
||||||
|
|
||||||
|
func Description () string {
|
||||||
|
return "Provides an X11 backend."
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewBackend () (tomo.Backend, error) {
|
||||||
|
return x.NewBackend()
|
||||||
|
}
|
@ -112,7 +112,7 @@ var keypadCodeTable = map[xproto.Keysym] input.Key {
|
|||||||
|
|
||||||
// initializeKeymapInformation grabs keyboard mapping information from the X
|
// initializeKeymapInformation grabs keyboard mapping information from the X
|
||||||
// server.
|
// server.
|
||||||
func (backend *Backend) initializeKeymapInformation () {
|
func (backend *backend) initializeKeymapInformation () {
|
||||||
keybind.Initialize(backend.connection)
|
keybind.Initialize(backend.connection)
|
||||||
backend.modifierMasks.capsLock = backend.keysymToMask(0xFFE5)
|
backend.modifierMasks.capsLock = backend.keysymToMask(0xFFE5)
|
||||||
backend.modifierMasks.shiftLock = backend.keysymToMask(0xFFE6)
|
backend.modifierMasks.shiftLock = backend.keysymToMask(0xFFE6)
|
||||||
@ -127,7 +127,7 @@ func (backend *Backend) initializeKeymapInformation () {
|
|||||||
|
|
||||||
// keysymToKeycode converts an X keysym to an X keycode, instead of the other
|
// keysymToKeycode converts an X keysym to an X keycode, instead of the other
|
||||||
// way around.
|
// way around.
|
||||||
func (backend *Backend) keysymToKeycode (
|
func (backend *backend) keysymToKeycode (
|
||||||
symbol xproto.Keysym,
|
symbol xproto.Keysym,
|
||||||
) (
|
) (
|
||||||
code xproto.Keycode,
|
code xproto.Keycode,
|
||||||
@ -148,7 +148,7 @@ func (backend *Backend) keysymToKeycode (
|
|||||||
}
|
}
|
||||||
|
|
||||||
// keysymToMask returns the X modmask for a given modifier key.
|
// keysymToMask returns the X modmask for a given modifier key.
|
||||||
func (backend *Backend) keysymToMask (
|
func (backend *backend) keysymToMask (
|
||||||
symbol xproto.Keysym,
|
symbol xproto.Keysym,
|
||||||
) (
|
) (
|
||||||
mask uint16,
|
mask uint16,
|
||||||
@ -164,7 +164,7 @@ func (backend *Backend) keysymToMask (
|
|||||||
// fleshed out version of some of the logic found in xgbutil/keybind/encoding.go
|
// fleshed out version of some of the logic found in xgbutil/keybind/encoding.go
|
||||||
// to get a full keycode to keysym conversion, but eliminates redundant work by
|
// to get a full keycode to keysym conversion, but eliminates redundant work by
|
||||||
// going straight to a tomo keycode.
|
// going straight to a tomo keycode.
|
||||||
func (backend *Backend) keycodeToKey (
|
func (backend *backend) keycodeToKey (
|
||||||
keycode xproto.Keycode,
|
keycode xproto.Keycode,
|
||||||
state uint16,
|
state uint16,
|
||||||
) (
|
) (
|
||||||
|
@ -3,6 +3,7 @@ package x
|
|||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
||||||
|
|
||||||
type entity struct {
|
type entity struct {
|
||||||
window *window
|
window *window
|
||||||
@ -20,9 +21,9 @@ type entity struct {
|
|||||||
isContainer bool
|
isContainer bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (backend *Backend) NewEntity (owner tomo.Element) tomo.Entity {
|
func (backend *backend) NewEntity (owner tomo.Element) tomo.Entity {
|
||||||
entity := &entity { element: owner }
|
entity := &entity { element: owner }
|
||||||
if _, ok := owner.(tomo.Container); ok {
|
if _, ok := owner.(ability.Container); ok {
|
||||||
entity.isContainer = true
|
entity.isContainer = true
|
||||||
entity.InvalidateLayout()
|
entity.InvalidateLayout()
|
||||||
}
|
}
|
||||||
@ -44,7 +45,7 @@ func (ent *entity) unlink () {
|
|||||||
ent.parent = nil
|
ent.parent = nil
|
||||||
ent.window = nil
|
ent.window = nil
|
||||||
|
|
||||||
if element, ok := ent.element.(tomo.Selectable); ok {
|
if element, ok := ent.element.(ability.Selectable); ok {
|
||||||
ent.selected = false
|
ent.selected = false
|
||||||
element.HandleSelectionChange()
|
element.HandleSelectionChange()
|
||||||
}
|
}
|
||||||
@ -111,15 +112,15 @@ func (entity *entity) scrollTargetChildAt (point image.Point) *entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := entity.element.(tomo.ScrollTarget); ok {
|
if _, ok := entity.element.(ability.ScrollTarget); ok {
|
||||||
return entity
|
return entity
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entity *entity) forMouseTargetContainers (callback func (tomo.MouseTargetContainer, tomo.Element)) {
|
func (entity *entity) forMouseTargetContainers (callback func (ability.MouseTargetContainer, tomo.Element)) {
|
||||||
if entity.parent == nil { return }
|
if entity.parent == nil { return }
|
||||||
if parent, ok := entity.parent.element.(tomo.MouseTargetContainer); ok {
|
if parent, ok := entity.parent.element.(ability.MouseTargetContainer); ok {
|
||||||
callback(parent, entity.element)
|
callback(parent, entity.element)
|
||||||
}
|
}
|
||||||
entity.parent.forMouseTargetContainers(callback)
|
entity.parent.forMouseTargetContainers(callback)
|
||||||
@ -156,18 +157,19 @@ func (entity *entity) SetMinimumSize (width, height int) {
|
|||||||
entity.window.setMinimumSize(width, height)
|
entity.window.setMinimumSize(width, height)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
entity.parent.element.(tomo.Container).
|
entity.parent.element.(ability.Container).
|
||||||
HandleChildMinimumSizeChange(entity.element)
|
HandleChildMinimumSizeChange(entity.element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entity *entity) DrawBackground (destination canvas.Canvas) {
|
func (entity *entity) DrawBackground (destination artist.Canvas) {
|
||||||
if entity.parent != nil {
|
if entity.parent != nil {
|
||||||
entity.parent.element.(tomo.Container).DrawBackground(destination)
|
entity.parent.element.(ability.Container).DrawBackground(destination)
|
||||||
} else if entity.window != nil {
|
} else if entity.window != nil {
|
||||||
entity.window.system.theme.Pattern (
|
entity.window.system.theme.Pattern (
|
||||||
tomo.PatternBackground,
|
tomo.PatternBackground,
|
||||||
tomo.State { }).Draw (
|
tomo.State { },
|
||||||
|
tomo.C("tomo", "window")).Draw (
|
||||||
destination,
|
destination,
|
||||||
entity.window.canvas.Bounds())
|
entity.window.canvas.Bounds())
|
||||||
}
|
}
|
||||||
@ -233,7 +235,7 @@ func (entity *entity) PlaceChild (index int, bounds image.Rectangle) {
|
|||||||
|
|
||||||
func (entity *entity) SelectChild (index int, selected bool) {
|
func (entity *entity) SelectChild (index int, selected bool) {
|
||||||
child := entity.children[index]
|
child := entity.children[index]
|
||||||
if element, ok := child.element.(tomo.Selectable); ok {
|
if element, ok := child.element.(ability.Selectable); ok {
|
||||||
if child.selected == selected { return }
|
if child.selected == selected { return }
|
||||||
child.selected = selected
|
child.selected = selected
|
||||||
element.HandleSelectionChange()
|
element.HandleSelectionChange()
|
||||||
@ -275,9 +277,9 @@ func (entity *entity) Selected () bool {
|
|||||||
|
|
||||||
func (entity *entity) NotifyFlexibleHeightChange () {
|
func (entity *entity) NotifyFlexibleHeightChange () {
|
||||||
if entity.parent == nil { return }
|
if entity.parent == nil { return }
|
||||||
if parent, ok := entity.parent.element.(tomo.FlexibleContainer); ok {
|
if parent, ok := entity.parent.element.(ability.FlexibleContainer); ok {
|
||||||
parent.HandleChildFlexibleHeightChange (
|
parent.HandleChildFlexibleHeightChange (
|
||||||
entity.element.(tomo.Flexible))
|
entity.element.(ability.Flexible))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,8 +287,8 @@ func (entity *entity) NotifyFlexibleHeightChange () {
|
|||||||
|
|
||||||
func (entity *entity) NotifyScrollBoundsChange () {
|
func (entity *entity) NotifyScrollBoundsChange () {
|
||||||
if entity.parent == nil { return }
|
if entity.parent == nil { return }
|
||||||
if parent, ok := entity.parent.element.(tomo.ScrollableContainer); ok {
|
if parent, ok := entity.parent.element.(ability.ScrollableContainer); ok {
|
||||||
parent.HandleChildScrollBoundsChange (
|
parent.HandleChildScrollBoundsChange (
|
||||||
entity.element.(tomo.Scrollable))
|
entity.element.(ability.Scrollable))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package x
|
|||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/input"
|
import "git.tebibyte.media/sashakoshka/tomo/input"
|
||||||
|
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
||||||
|
|
||||||
import "github.com/jezek/xgbutil"
|
import "github.com/jezek/xgbutil"
|
||||||
import "github.com/jezek/xgb/xproto"
|
import "github.com/jezek/xgb/xproto"
|
||||||
@ -134,7 +135,7 @@ func (window *window) handleKeyPress (
|
|||||||
} else if key == input.KeyEscape && window.shy {
|
} else if key == input.KeyEscape && window.shy {
|
||||||
window.Close()
|
window.Close()
|
||||||
} else if window.focused != nil {
|
} else if window.focused != nil {
|
||||||
focused, ok := window.focused.element.(tomo.KeyboardTarget)
|
focused, ok := window.focused.element.(ability.KeyboardTarget)
|
||||||
if ok { focused.HandleKeyDown(key, modifiers) }
|
if ok { focused.HandleKeyDown(key, modifiers) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +170,7 @@ func (window *window) handleKeyRelease (
|
|||||||
modifiers.NumberPad = numberPad
|
modifiers.NumberPad = numberPad
|
||||||
|
|
||||||
if window.focused != nil {
|
if window.focused != nil {
|
||||||
focused, ok := window.focused.element.(tomo.KeyboardTarget)
|
focused, ok := window.focused.element.(ability.KeyboardTarget)
|
||||||
if ok { focused.HandleKeyUp(key, modifiers) }
|
if ok { focused.HandleKeyUp(key, modifiers) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,7 +192,7 @@ func (window *window) handleButtonPress (
|
|||||||
} else if scrolling {
|
} else if scrolling {
|
||||||
underneath := window.system.scrollTargetChildAt(point)
|
underneath := window.system.scrollTargetChildAt(point)
|
||||||
if underneath != nil {
|
if underneath != nil {
|
||||||
if child, ok := underneath.element.(tomo.ScrollTarget); ok {
|
if child, ok := underneath.element.(ability.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)
|
||||||
@ -203,12 +204,12 @@ func (window *window) handleButtonPress (
|
|||||||
} else {
|
} else {
|
||||||
underneath := window.system.childAt(point)
|
underneath := window.system.childAt(point)
|
||||||
window.system.drags[buttonEvent.Detail] = underneath
|
window.system.drags[buttonEvent.Detail] = underneath
|
||||||
if child, ok := underneath.element.(tomo.MouseTarget); ok {
|
if child, ok := underneath.element.(ability.MouseTarget); ok {
|
||||||
child.HandleMouseDown (
|
child.HandleMouseDown (
|
||||||
point, input.Button(buttonEvent.Detail),
|
point, input.Button(buttonEvent.Detail),
|
||||||
modifiers)
|
modifiers)
|
||||||
}
|
}
|
||||||
callback := func (container tomo.MouseTargetContainer, child tomo.Element) {
|
callback := func (container ability.MouseTargetContainer, child tomo.Element) {
|
||||||
container.HandleChildMouseDown (
|
container.HandleChildMouseDown (
|
||||||
point, input.Button(buttonEvent.Detail),
|
point, input.Button(buttonEvent.Detail),
|
||||||
modifiers, child)
|
modifiers, child)
|
||||||
@ -229,7 +230,7 @@ func (window *window) handleButtonRelease (
|
|||||||
dragging := window.system.drags[buttonEvent.Detail]
|
dragging := window.system.drags[buttonEvent.Detail]
|
||||||
|
|
||||||
if dragging != nil {
|
if dragging != nil {
|
||||||
if child, ok := dragging.element.(tomo.MouseTarget); ok {
|
if child, ok := dragging.element.(ability.MouseTarget); ok {
|
||||||
child.HandleMouseUp (
|
child.HandleMouseUp (
|
||||||
image.Pt (
|
image.Pt (
|
||||||
int(buttonEvent.EventX),
|
int(buttonEvent.EventX),
|
||||||
@ -237,7 +238,7 @@ func (window *window) handleButtonRelease (
|
|||||||
input.Button(buttonEvent.Detail),
|
input.Button(buttonEvent.Detail),
|
||||||
modifiers)
|
modifiers)
|
||||||
}
|
}
|
||||||
callback := func (container tomo.MouseTargetContainer, child tomo.Element) {
|
callback := func (container ability.MouseTargetContainer, child tomo.Element) {
|
||||||
container.HandleChildMouseUp (
|
container.HandleChildMouseUp (
|
||||||
image.Pt (
|
image.Pt (
|
||||||
int(buttonEvent.EventX),
|
int(buttonEvent.EventX),
|
||||||
@ -262,7 +263,7 @@ func (window *window) handleMotionNotify (
|
|||||||
handled := false
|
handled := false
|
||||||
for _, child := range window.system.drags {
|
for _, child := range window.system.drags {
|
||||||
if child == nil { continue }
|
if child == nil { continue }
|
||||||
if child, ok := child.element.(tomo.MotionTarget); ok {
|
if child, ok := child.element.(ability.MotionTarget); ok {
|
||||||
child.HandleMotion(image.Pt(x, y))
|
child.HandleMotion(image.Pt(x, y))
|
||||||
handled = true
|
handled = true
|
||||||
}
|
}
|
||||||
@ -270,7 +271,7 @@ func (window *window) handleMotionNotify (
|
|||||||
|
|
||||||
if !handled {
|
if !handled {
|
||||||
child := window.system.childAt(image.Pt(x, y))
|
child := window.system.childAt(image.Pt(x, y))
|
||||||
if child, ok := child.element.(tomo.MotionTarget); ok {
|
if child, ok := child.element.(ability.MotionTarget); ok {
|
||||||
child.HandleMotion(image.Pt(x, y))
|
child.HandleMotion(image.Pt(x, y))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,9 @@ package x
|
|||||||
import "image"
|
import "image"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo"
|
import "git.tebibyte.media/sashakoshka/tomo"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
import "git.tebibyte.media/sashakoshka/tomo/artist"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
import "git.tebibyte.media/sashakoshka/tomo/ability"
|
||||||
import "git.tebibyte.media/sashakoshka/tomo/default/config"
|
import defaultTheme "git.tebibyte.media/sashakoshka/tomo/default/theme"
|
||||||
|
import defaultConfig "git.tebibyte.media/sashakoshka/tomo/default/config"
|
||||||
|
|
||||||
type entitySet map[*entity] struct { }
|
type entitySet map[*entity] struct { }
|
||||||
|
|
||||||
@ -24,10 +25,10 @@ func (set entitySet) Add (entity *entity) {
|
|||||||
type system struct {
|
type system struct {
|
||||||
child *entity
|
child *entity
|
||||||
focused *entity
|
focused *entity
|
||||||
canvas canvas.BasicCanvas
|
canvas artist.BasicCanvas
|
||||||
|
|
||||||
theme theme.Wrapped
|
theme tomo.Theme
|
||||||
config config.Wrapped
|
config tomo.Config
|
||||||
|
|
||||||
invalidateIgnore bool
|
invalidateIgnore bool
|
||||||
drawingInvalid entitySet
|
drawingInvalid entitySet
|
||||||
@ -42,21 +43,29 @@ func (system *system) initialize () {
|
|||||||
system.drawingInvalid = make(entitySet)
|
system.drawingInvalid = make(entitySet)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (system *system) SetTheme (theme tomo.Theme) {
|
func (system *system) setTheme (theme tomo.Theme) {
|
||||||
system.theme.Theme = theme
|
if theme == nil {
|
||||||
|
system.theme = defaultTheme.Default { }
|
||||||
|
} else {
|
||||||
|
system.theme = theme
|
||||||
|
}
|
||||||
system.propagate (func (entity *entity) bool {
|
system.propagate (func (entity *entity) bool {
|
||||||
if child, ok := system.child.element.(tomo.Themeable); ok {
|
if child, ok := system.child.element.(ability.Themeable); ok {
|
||||||
child.SetTheme(theme)
|
child.HandleThemeChange()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (system *system) SetConfig (config tomo.Config) {
|
func (system *system) setConfig (config tomo.Config) {
|
||||||
system.config.Config = config
|
if config == nil {
|
||||||
|
system.config = defaultConfig.Default { }
|
||||||
|
} else {
|
||||||
|
system.config = config
|
||||||
|
}
|
||||||
system.propagate (func (entity *entity) bool {
|
system.propagate (func (entity *entity) bool {
|
||||||
if child, ok := system.child.element.(tomo.Configurable); ok {
|
if child, ok := system.child.element.(ability.Configurable); ok {
|
||||||
child.SetConfig(config)
|
child.HandleConfigChange()
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -66,10 +75,10 @@ func (system *system) focus (entity *entity) {
|
|||||||
previous := system.focused
|
previous := system.focused
|
||||||
system.focused = entity
|
system.focused = entity
|
||||||
if previous != nil {
|
if previous != nil {
|
||||||
previous.element.(tomo.Focusable).HandleFocusChange()
|
previous.element.(ability.Focusable).HandleFocusChange()
|
||||||
}
|
}
|
||||||
if entity != nil {
|
if entity != nil {
|
||||||
entity.element.(tomo.Focusable).HandleFocusChange()
|
entity.element.(ability.Focusable).HandleFocusChange()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +88,7 @@ func (system *system) focusNext () {
|
|||||||
system.propagateAlt (func (entity *entity) bool {
|
system.propagateAlt (func (entity *entity) bool {
|
||||||
if found {
|
if found {
|
||||||
// looking for the next element to select
|
// looking for the next element to select
|
||||||
child, ok := entity.element.(tomo.Focusable)
|
child, ok := entity.element.(ability.Focusable)
|
||||||
if ok && child.Enabled() {
|
if ok && child.Enabled() {
|
||||||
// found it
|
// found it
|
||||||
entity.Focus()
|
entity.Focus()
|
||||||
@ -106,7 +115,7 @@ func (system *system) focusPrevious () {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
child, ok := entity.element.(tomo.Focusable)
|
child, ok := entity.element.(ability.Focusable)
|
||||||
if ok && child.Enabled() { behind = entity }
|
if ok && child.Enabled() { behind = entity }
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -153,7 +162,7 @@ func (system *system) afterEvent () {
|
|||||||
func (system *system) layout (entity *entity, force bool) {
|
func (system *system) layout (entity *entity, force bool) {
|
||||||
if entity == nil { return }
|
if entity == nil { return }
|
||||||
if entity.layoutInvalid == true || force {
|
if entity.layoutInvalid == true || force {
|
||||||
if element, ok := entity.element.(tomo.Layoutable); ok {
|
if element, ok := entity.element.(ability.Layoutable); ok {
|
||||||
element.Layout()
|
element.Layout()
|
||||||
entity.layoutInvalid = false
|
entity.layoutInvalid = false
|
||||||
force = true
|
force = true
|
||||||
@ -176,7 +185,7 @@ func (system *system) draw () {
|
|||||||
|
|
||||||
for entity := range system.drawingInvalid {
|
for entity := range system.drawingInvalid {
|
||||||
if entity.clippedBounds.Empty() { continue }
|
if entity.clippedBounds.Empty() { continue }
|
||||||
entity.element.Draw (canvas.Cut (
|
entity.element.Draw (artist.Cut (
|
||||||
system.canvas,
|
system.canvas,
|
||||||
entity.clippedBounds))
|
entity.clippedBounds))
|
||||||
finalBounds = finalBounds.Union(entity.clippedBounds)
|
finalBounds = finalBounds.Union(entity.clippedBounds)
|
||||||
|
@ -20,7 +20,7 @@ type menuWindow struct { *window }
|
|||||||
type window struct {
|
type window struct {
|
||||||
system
|
system
|
||||||
|
|
||||||
backend *Backend
|
backend *backend
|
||||||
xWindow *xwindow.Window
|
xWindow *xwindow.Window
|
||||||
xCanvas *xgraphics.Image
|
xCanvas *xgraphics.Image
|
||||||
|
|
||||||
@ -40,7 +40,7 @@ type window struct {
|
|||||||
onClose func ()
|
onClose func ()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (backend *Backend) NewWindow (
|
func (backend *backend) NewWindow (
|
||||||
bounds image.Rectangle,
|
bounds image.Rectangle,
|
||||||
) (
|
) (
|
||||||
output tomo.MainWindow,
|
output tomo.MainWindow,
|
||||||
@ -53,7 +53,7 @@ func (backend *Backend) NewWindow (
|
|||||||
return output, err
|
return output, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (backend *Backend) newWindow (
|
func (backend *backend) newWindow (
|
||||||
bounds image.Rectangle,
|
bounds image.Rectangle,
|
||||||
override bool,
|
override bool,
|
||||||
) (
|
) (
|
||||||
@ -67,7 +67,6 @@ func (backend *Backend) newWindow (
|
|||||||
|
|
||||||
window.system.initialize()
|
window.system.initialize()
|
||||||
window.system.pushFunc = window.pasteAndPush
|
window.system.pushFunc = window.pasteAndPush
|
||||||
window.theme.Case = tomo.C("tomo", "window")
|
|
||||||
|
|
||||||
window.xWindow, err = xwindow.Generate(backend.connection)
|
window.xWindow, err = xwindow.Generate(backend.connection)
|
||||||
if err != nil { return }
|
if err != nil { return }
|
||||||
@ -122,8 +121,8 @@ func (backend *Backend) newWindow (
|
|||||||
xevent.SelectionRequestFun(window.handleSelectionRequest).
|
xevent.SelectionRequestFun(window.handleSelectionRequest).
|
||||||
Connect(backend.connection, window.xWindow.Id)
|
Connect(backend.connection, window.xWindow.Id)
|
||||||
|
|
||||||
window.SetTheme(backend.theme)
|
window.setTheme(backend.theme)
|
||||||
window.SetConfig(backend.config)
|
window.setConfig(backend.config)
|
||||||
|
|
||||||
window.metrics.bounds = bounds
|
window.metrics.bounds = bounds
|
||||||
window.setMinimumSize(8, 8)
|
window.setMinimumSize(8, 8)
|
||||||
@ -418,7 +417,7 @@ func (window *window) pasteAndPush (region image.Rectangle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (window *window) paste (region image.Rectangle) {
|
func (window *window) paste (region image.Rectangle) {
|
||||||
canvas := canvas.Cut(window.canvas, region)
|
canvas := artist.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())
|
||||||
|
|
||||||
|
@ -8,8 +8,7 @@ import "github.com/jezek/xgbutil/xevent"
|
|||||||
import "github.com/jezek/xgbutil/keybind"
|
import "github.com/jezek/xgbutil/keybind"
|
||||||
import "github.com/jezek/xgbutil/mousebind"
|
import "github.com/jezek/xgbutil/mousebind"
|
||||||
|
|
||||||
// Backend is an instance of an X backend.
|
type backend struct {
|
||||||
type Backend struct {
|
|
||||||
connection *xgbutil.XUtil
|
connection *xgbutil.XUtil
|
||||||
|
|
||||||
doChannel chan(func ())
|
doChannel chan(func ())
|
||||||
@ -36,7 +35,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 (), 32),
|
doChannel: make(chan func (), 32),
|
||||||
open: true,
|
open: true,
|
||||||
@ -54,9 +53,7 @@ func NewBackend () (output tomo.Backend, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run runs the backend's event loop. This method will not exit until Stop() is
|
func (backend *backend) Run () (err error) {
|
||||||
// called, or the backend experiences a fatal error.
|
|
||||||
func (backend *Backend) Run () (err error) {
|
|
||||||
backend.assert()
|
backend.assert()
|
||||||
pingBefore,
|
pingBefore,
|
||||||
pingAfter,
|
pingAfter,
|
||||||
@ -76,8 +73,7 @@ func (backend *Backend) Run () (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop gracefully closes the connection and stops the event loop.
|
func (backend *backend) Stop () {
|
||||||
func (backend *Backend) Stop () {
|
|
||||||
backend.assert()
|
backend.assert()
|
||||||
if !backend.open { return }
|
if !backend.open { return }
|
||||||
backend.open = false
|
backend.open = false
|
||||||
@ -93,31 +89,27 @@ func (backend *Backend) Stop () {
|
|||||||
backend.connection.Conn().Close()
|
backend.connection.Conn().Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do executes the specified callback within the main thread as soon as
|
func (backend *backend) Do (callback func ()) {
|
||||||
// possible. This function can be safely called from other threads.
|
|
||||||
func (backend *Backend) Do (callback func ()) {
|
|
||||||
backend.assert()
|
backend.assert()
|
||||||
backend.doChannel <- callback
|
backend.doChannel <- callback
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTheme sets the theme of all open windows.
|
func (backend *backend) SetTheme (theme tomo.Theme) {
|
||||||
func (backend *Backend) SetTheme (theme tomo.Theme) {
|
|
||||||
backend.assert()
|
backend.assert()
|
||||||
backend.theme = theme
|
backend.theme = theme
|
||||||
for _, window := range backend.windows {
|
for _, window := range backend.windows {
|
||||||
window.SetTheme(theme)
|
window.setTheme(theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetConfig sets the configuration of all open windows.
|
func (backend *backend) SetConfig (config tomo.Config) {
|
||||||
func (backend *Backend) SetConfig (config tomo.Config) {
|
|
||||||
backend.assert()
|
backend.assert()
|
||||||
backend.config = config
|
backend.config = config
|
||||||
for _, window := range backend.windows {
|
for _, window := range backend.windows {
|
||||||
window.SetConfig(config)
|
window.setConfig(config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (backend *Backend) assert () {
|
func (backend *backend) assert () {
|
||||||
if backend == nil { panic("nil backend") }
|
if backend == nil { panic("nil backend") }
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user