Made the X backend into a plugin
This commit is contained in:
		
							parent
							
								
									a2a9af3311
								
							
						
					
					
						commit
						77e1151bd8
					
				@ -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