17 Commits

11 changed files with 290 additions and 75 deletions

2
go.mod
View File

@@ -3,7 +3,7 @@ module git.tebibyte.media/tomo/backend
go 1.20 go 1.20
require ( require (
git.tebibyte.media/tomo/tomo v0.35.0 git.tebibyte.media/tomo/tomo v0.38.0
git.tebibyte.media/tomo/typeset v0.7.1 git.tebibyte.media/tomo/typeset v0.7.1
git.tebibyte.media/tomo/xgbkb v1.0.1 git.tebibyte.media/tomo/xgbkb v1.0.1
github.com/jezek/xgb v1.1.1 github.com/jezek/xgb v1.1.1

4
go.sum
View File

@@ -1,6 +1,6 @@
git.tebibyte.media/sashakoshka/xgbkb v1.0.0/go.mod h1:pNcE6TRO93vHd6q42SdwLSTTj25L0Yzggz7yLe0JV6Q= git.tebibyte.media/sashakoshka/xgbkb v1.0.0/go.mod h1:pNcE6TRO93vHd6q42SdwLSTTj25L0Yzggz7yLe0JV6Q=
git.tebibyte.media/tomo/tomo v0.35.0 h1:1XvcUcWg1rBZXov3KfuX6VfiuBQ2mcJHIslHMLn07no= git.tebibyte.media/tomo/tomo v0.38.0 h1:K5TP67RxnszudeNfmGZiU5cFTRjFueXiI3NCsgw+05U=
git.tebibyte.media/tomo/tomo v0.35.0/go.mod h1:C9EzepS9wjkTJjnZaPBh22YvVPyA4hbBAJVU20Rdmps= git.tebibyte.media/tomo/tomo v0.38.0/go.mod h1:C9EzepS9wjkTJjnZaPBh22YvVPyA4hbBAJVU20Rdmps=
git.tebibyte.media/tomo/typeset v0.7.1 h1:aZrsHwCG5ZB4f5CruRFsxLv5ezJUCFUFsQJJso2sXQ8= git.tebibyte.media/tomo/typeset v0.7.1 h1:aZrsHwCG5ZB4f5CruRFsxLv5ezJUCFUFsQJJso2sXQ8=
git.tebibyte.media/tomo/typeset v0.7.1/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g= git.tebibyte.media/tomo/typeset v0.7.1/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
git.tebibyte.media/tomo/xgbkb v1.0.1 h1:b3HDUopjdQp1MZrb5Vpil4bOtk3NnNXtfQW27Blw2kE= git.tebibyte.media/tomo/xgbkb v1.0.1 h1:b3HDUopjdQp1MZrb5Vpil4bOtk3NnNXtfQW27Blw2kE=

View File

@@ -19,7 +19,10 @@ type box struct {
parent parent parent parent
outer anyBox outer anyBox
role tomo.Role role tomo.Role
styleCookie event.Cookie
lastStyleNonce int
lastIconsNonce int
bounds image.Rectangle bounds image.Rectangle
minSize image.Point minSize image.Point
@@ -44,19 +47,21 @@ type box struct {
drawer canvas.Drawer drawer canvas.Drawer
on struct { on struct {
focusEnter event.FuncBroadcaster focusEnter event.FuncBroadcaster
focusLeave event.FuncBroadcaster focusLeave event.FuncBroadcaster
dndEnter event.FuncBroadcaster dndEnter event.FuncBroadcaster
dndLeave event.FuncBroadcaster dndLeave event.FuncBroadcaster
dndDrop event.Broadcaster[func (data.Data)] dndDrop event.Broadcaster[func (data.Data)]
mouseEnter event.FuncBroadcaster mouseEnter event.FuncBroadcaster
mouseLeave event.FuncBroadcaster mouseLeave event.FuncBroadcaster
mouseMove event.FuncBroadcaster mouseMove event.FuncBroadcaster
mouseDown event.Broadcaster[func (input.Button)] mouseDown event.Broadcaster[func (input.Button)]
mouseUp event.Broadcaster[func (input.Button)] mouseUp event.Broadcaster[func (input.Button)]
scroll event.Broadcaster[func (float64, float64)] scroll event.Broadcaster[func (float64, float64)]
keyDown event.Broadcaster[func (input.Key, bool)] keyDown event.Broadcaster[func (input.Key, bool)]
keyUp event.Broadcaster[func (input.Key, bool)] keyUp event.Broadcaster[func (input.Key, bool)]
styleChange event.FuncBroadcaster
iconsChange event.FuncBroadcaster
} }
} }
@@ -123,6 +128,15 @@ func (this *box) borderSum () tomo.Inset {
return sum return sum
} }
func (this *box) borderAndPaddingSum () tomo.Inset {
sum := this.borderSum()
sum[0] += this.padding[0]
sum[1] += this.padding[1]
sum[2] += this.padding[2]
sum[3] += this.padding[3]
return sum
}
func (this *box) SetBounds (bounds image.Rectangle) { func (this *box) SetBounds (bounds image.Rectangle) {
if this.bounds == bounds { return } if this.bounds == bounds { return }
this.bounds = bounds this.bounds = bounds
@@ -282,6 +296,12 @@ func (this *box) OnKeyDown (callback func(key input.Key, numberPad bool)) event.
func (this *box) OnKeyUp (callback func(key input.Key, numberPad bool)) event.Cookie { func (this *box) OnKeyUp (callback func(key input.Key, numberPad bool)) event.Cookie {
return this.on.keyUp.Connect(callback) return this.on.keyUp.Connect(callback)
} }
func (this *box) OnStyleChange (callback func()) event.Cookie {
return this.on.styleChange.Connect(callback)
}
func (this *box) OnIconsChange (callback func()) event.Cookie {
return this.on.iconsChange.Connect(callback)
}
func (this *box) handleFocusEnter () { func (this *box) handleFocusEnter () {
this.on.focusEnter.Broadcast() this.on.focusEnter.Broadcast()
} }
@@ -451,7 +471,7 @@ func (this *box) doLayout () {
// laycnt ++ // laycnt ++
this.innerClippingBounds = this.borderSum().Apply(this.bounds) this.innerClippingBounds = this.borderSum().Apply(this.bounds)
this.loseCanvas() this.outer.recursiveLoseCanvas()
} }
func (this *box) setParent (parent parent) { func (this *box) setParent (parent parent) {
@@ -459,6 +479,7 @@ func (this *box) setParent (parent parent) {
this.SetFocused(false) this.SetFocused(false)
} }
this.parent = parent this.parent = parent
this.outer.recursiveReApply()
} }
func (this *box) getParent () parent { func (this *box) getParent () parent {
@@ -481,7 +502,7 @@ func (this *box) recursiveRedo () {
this.doDraw() this.doDraw()
} }
func (this *box) loseCanvas () { func (this *box) recursiveLoseCanvas () {
this.canvas.InvalidateTo(nil) this.canvas.InvalidateTo(nil)
} }
@@ -506,6 +527,36 @@ func (this *box) invalidateMinimum () {
} }
} }
func (this *box) recursiveReApply () {
if this.getHierarchy() == nil { return }
// re-apply styling, icons *if needed*
// style
hierarchyStyleNonce := this.getStyleNonce()
if this.lastStyleNonce != hierarchyStyleNonce {
// remove old style
this.lastStyleNonce = hierarchyStyleNonce
if this.styleCookie != nil {
this.styleCookie.Close()
this.styleCookie = nil
}
// apply new one
if style := this.getStyle(); style != nil {
this.styleCookie = style.Apply(this.outer)
}
this.on.styleChange.Broadcast()
}
// icons
hierarchyIconsNonce := this.getIconsNonce()
if this.lastIconsNonce != hierarchyIconsNonce {
this.lastIconsNonce = hierarchyIconsNonce
this.on.iconsChange.Broadcast()
}
}
func (this *box) canBeFocused () bool { func (this *box) canBeFocused () bool {
return this.focusable return this.focusable
} }
@@ -539,7 +590,23 @@ func (this *box) getWindow () tomo.Window {
return hierarchy.getWindow() return hierarchy.getWindow()
} }
func (this *box) getStyle () tomo.Style {
hierarchy := this.getHierarchy()
if hierarchy == nil { return nil }
return hierarchy.getStyle()
}
func (this *box) getHierarchy () *Hierarchy { func (this *box) getHierarchy () *Hierarchy {
if this.parent == nil { return nil } if this.parent == nil { return nil }
return this.parent.getHierarchy() return this.parent.getHierarchy()
} }
func (this *box) getStyleNonce () int {
// should panic if not in the tree
return this.getHierarchy().getStyleNonce()
}
func (this *box) getIconsNonce () int {
// should panic if not in the tree
return this.getHierarchy().getIconsNonce()
}

View File

@@ -73,6 +73,24 @@ func (this *containerBox) ScrollTo (point image.Point) {
this.invalidateLayout() this.invalidateLayout()
} }
func (this *containerBox) RecommendedHeight (width int) int {
if this.layout == nil || this.vOverflow {
return this.MinimumSize().Y
} else {
return this.layout.RecommendedHeight(this.layoutHints(), this.children, width) +
this.borderAndPaddingSum().Vertical()
}
}
func (this *containerBox) RecommendedWidth (height int) int {
if this.layout == nil || this.hOverflow {
return this.MinimumSize().X
} else {
return this.layout.RecommendedWidth(this.layoutHints(), this.children, height) +
this.borderAndPaddingSum().Horizontal()
}
}
func (this *containerBox) OnContentBoundsChange (callback func()) event.Cookie { func (this *containerBox) OnContentBoundsChange (callback func()) event.Cookie {
return this.on.contentBoundsChange.Connect(callback) return this.on.contentBoundsChange.Connect(callback)
} }
@@ -335,6 +353,20 @@ func (this *containerBox) recursiveRedo () {
} }
} }
func (this *containerBox) recursiveLoseCanvas () {
this.box.recursiveLoseCanvas()
for _, child := range this.children {
child.(anyBox).recursiveLoseCanvas()
}
}
func (this *containerBox) recursiveReApply () {
this.box.recursiveReApply()
for _, child := range this.children {
child.(anyBox).recursiveReApply()
}
}
func (this *containerBox) boxUnder (point image.Point, category eventCategory) anyBox { func (this *containerBox) boxUnder (point image.Point, category eventCategory) anyBox {
if !point.In(this.bounds) { return nil } if !point.In(this.bounds) { return nil }

View File

@@ -56,6 +56,7 @@ func (this *System) NewHierarchy (link WindowLink) *Hierarchy {
needLayout: make(util.Set[anyBox]), needLayout: make(util.Set[anyBox]),
needDraw: make(util.Set[anyBox]), needDraw: make(util.Set[anyBox]),
} }
this.hierarchies.Add(hierarchy)
return hierarchy return hierarchy
} }
@@ -85,7 +86,7 @@ func (this *Hierarchy) Empty () bool {
// draw to. The Hierarchy will use the canvas.Canvas's bounds to lay itself out. // draw to. The Hierarchy will use the canvas.Canvas's bounds to lay itself out.
func (this *Hierarchy) SetCanvas (can canvas.Canvas) { func (this *Hierarchy) SetCanvas (can canvas.Canvas) {
this.canvas = can this.canvas = can
if this.root != nil { this.root.loseCanvas() } if this.root != nil { this.root.recursiveLoseCanvas() }
this.needRedo = true this.needRedo = true
} }
@@ -135,6 +136,20 @@ func (this *Hierarchy) AfterEvent () {
} }
} }
// Close closes the Hierarchy. This should be called when the Window that
// contains it has been closed.
func (this *Hierarchy) Close () {
this.system.removeHierarchy(this)
}
func (this *Hierarchy) setStyle () {
if this.root != nil { this.root.recursiveReApply() }
}
func (this *Hierarchy) setIcons () {
if this.root != nil { this.root.recursiveReApply() }
}
func (this *Hierarchy) getHierarchy () *Hierarchy { func (this *Hierarchy) getHierarchy () *Hierarchy {
return this return this
} }
@@ -143,6 +158,18 @@ func (this *Hierarchy) getWindow () tomo.Window {
return this.link.GetWindow() return this.link.GetWindow()
} }
func (this *Hierarchy) getStyle () tomo.Style {
return this.system.style
}
func (this *Hierarchy) getStyleNonce () int {
return this.system.styleNonce
}
func (this *Hierarchy) getIconsNonce () int {
return this.system.iconsNonce
}
func (this *Hierarchy) getCanvas () canvas.Canvas { func (this *Hierarchy) getCanvas () canvas.Canvas {
return this.canvas return this.canvas
} }

View File

@@ -51,13 +51,17 @@ type anyBox interface {
// flushActionQueue performs any queued actions, like invalidating the // flushActionQueue performs any queued actions, like invalidating the
// minimum size or grabbing input focus. // minimum size or grabbing input focus.
flushActionQueue () flushActionQueue ()
// recursiveRedo recursively recalculates the minimum size, layout, and // recursiveRedo recursively recalculates the minimum size, layout, and
// re-paints this anyBox and all of its children. // re-paints this anyBox and all of its children.
recursiveRedo () recursiveRedo ()
// loseCanvas causes this anyBox and its children (if applicable) to // loseCanvas causes this anyBox and its children (if applicable) to
// lose their canvases and re-cut them as needed. // lose their canvases and re-cut them as needed.
loseCanvas () recursiveLoseCanvas ()
// recursiveReAppply causes this anyBox and its children (if applicable)
// to check whether they have an outdated style or icon set, and if so,
// update it and trigger the appropriate event broadcasters.
recursiveReApply ()
// contentMinimum returns the minimum dimensions of this box's content // contentMinimum returns the minimum dimensions of this box's content
contentMinimum () image.Point contentMinimum () image.Point
@@ -81,19 +85,19 @@ type anyBox interface {
propagate (func (anyBox) bool) bool propagate (func (anyBox) bool) bool
propagateAlt (func (anyBox) bool) bool propagateAlt (func (anyBox) bool) bool
handleFocusEnter () handleFocusEnter ()
handleFocusLeave () handleFocusLeave ()
// handleDndEnter () // handleDndEnter ()
// handleDndLeave () // handleDndLeave ()
// handleDndDrop (data.Data) // handleDndDrop (data.Data)
handleMouseEnter () handleMouseEnter ()
handleMouseLeave () handleMouseLeave ()
handleMouseMove () handleMouseMove ()
handleMouseDown (input.Button) handleMouseDown (input.Button)
handleMouseUp (input.Button) handleMouseUp (input.Button)
handleScroll (float64, float64) handleScroll (float64, float64)
handleKeyDown (input.Key, bool) handleKeyDown (input.Key, bool)
handleKeyUp (input.Key, bool) handleKeyUp (input.Key, bool)
} }
func assertAnyBox (unknown tomo.Box) anyBox { func assertAnyBox (unknown tomo.Box) anyBox {

View File

@@ -2,12 +2,20 @@ package system
import "io" import "io"
import "image" import "image"
import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/tomo/canvas" import "git.tebibyte.media/tomo/tomo/canvas"
import "git.tebibyte.media/tomo/backend/internal/util"
// System is coupled to a tomo.Backend implementation, and manages Hierarchies // System is coupled to a tomo.Backend implementation, and manages Hierarchies
// and Boxes. // and Boxes.
type System struct { type System struct {
link BackendLink link BackendLink
style tomo.Style
styleNonce int
iconsNonce int
hierarchies util.Set[*Hierarchy]
} }
// BackendLink allows the System to call up into the tomo.Backend implementation // BackendLink allows the System to call up into the tomo.Backend implementation
@@ -30,6 +38,29 @@ type SurfaceLink interface {
// New creates a new System. // New creates a new System.
func New (link BackendLink) *System { func New (link BackendLink) *System {
return &System { return &System {
link: link, link: link,
hierarchies: make(util.Set[*Hierarchy]),
} }
} }
// SetStyle sets the tomo.Style that is applied to objects, and notifies them
// that the style has changed.
func (this *System) SetStyle (style tomo.Style) {
this.style = style
this.styleNonce ++
for hierarchy := range this.hierarchies {
hierarchy.setStyle()
}
}
// SetIcons notifies objects that the icons have changed.
func (this *System) SetIcons (icons tomo.Icons) {
this.iconsNonce ++
for hierarchy := range this.hierarchies {
hierarchy.setIcons()
}
}
func (this *System) removeHierarchy (hierarchy *Hierarchy) {
delete(this.hierarchies, hierarchy)
}

View File

@@ -65,6 +65,15 @@ func (this *textBox) ScrollTo (point image.Point) {
this.invalidateLayout() this.invalidateLayout()
} }
func (this *textBox) RecommendedHeight (width int) int {
return this.drawer.ReccomendedHeightFor(width) + this.borderAndPaddingSum().Vertical()
}
func (this *textBox) RecommendedWidth (height int) int {
// TODO maybe not the best idea?
return this.MinimumSize().X
}
func (this *textBox) OnContentBoundsChange (callback func()) event.Cookie { func (this *textBox) OnContentBoundsChange (callback func()) event.Cookie {
return this.on.contentBoundsChange.Connect(callback) return this.on.contentBoundsChange.Connect(callback)
} }

View File

@@ -126,6 +126,14 @@ func (this *Backend) NewCanvas (bounds image.Rectangle) canvas.CanvasCloser {
return xcanvas.NewCanvas(this.x, bounds) return xcanvas.NewCanvas(this.x, bounds)
} }
func (this *Backend) SetStyle (style tomo.Style) {
this.system.SetStyle(style)
}
func (this *Backend) SetIcons (icons tomo.Icons) {
this.system.SetIcons(icons)
}
func (this *Backend) assert () { func (this *Backend) assert () {
if this == nil { panic("x: nil backend") } if this == nil { panic("x: nil backend") }
} }

View File

@@ -13,7 +13,7 @@ type scrollSum struct {
} }
// TODO: this needs to be configurable, we need a config api // TODO: this needs to be configurable, we need a config api
const scrollDistance = 16 const scrollDistance = 32
func (sum *scrollSum) add (button xproto.Button, window *window, state uint16) { func (sum *scrollSum) add (button xproto.Button, window *window, state uint16) {
if xgbkb.StateToModifiers(state).Shift { if xgbkb.StateToModifiers(state).Shift {

View File

@@ -18,7 +18,6 @@ import "github.com/jezek/xgbutil/keybind"
import "github.com/jezek/xgbutil/mousebind" import "github.com/jezek/xgbutil/mousebind"
import "github.com/jezek/xgbutil/xgraphics" import "github.com/jezek/xgbutil/xgraphics"
type mainWindow struct { *window }
type window struct { type window struct {
backend *Backend backend *Backend
hierarchy *system.Hierarchy hierarchy *system.Hierarchy
@@ -28,10 +27,13 @@ type window struct {
title string title string
leader *window
modalParent *window modalParent *window
hasModal bool hasModal bool
shy bool shy bool
visible bool visible bool
resizeX bool
resizeY bool
metrics struct { metrics struct {
bounds image.Rectangle bounds image.Rectangle
@@ -63,28 +65,24 @@ func (this *windowLink) NotifyMinimumSizeChange () {
func (this *Backend) NewWindow ( func (this *Backend) NewWindow (
bounds image.Rectangle, bounds image.Rectangle,
) ( ) (
output tomo.MainWindow, output tomo.Window,
err error, err error,
) { ) {
this.assert() this.assert()
window, err := this.newWindow(bounds, false) return this.newWindow(bounds, false)
output = mainWindow { window: window }
return output, err
} }
func (this *Backend) NewPlainWindow ( func (this *Backend) NewPlainWindow (
bounds image.Rectangle, bounds image.Rectangle,
) ( ) (
output tomo.MainWindow, output tomo.Window,
err error, err error,
) { ) {
this.assert() this.assert()
window, err := this.newWindow(bounds, false) window, err := this.newWindow(bounds, false)
window.setType("dock") window.setType("dock")
output = mainWindow { window: window } return window, err
return output, err
} }
func (this *Backend) newWindow ( func (this *Backend) newWindow (
@@ -100,6 +98,9 @@ func (this *Backend) newWindow (
window := &window { backend: this } window := &window { backend: this }
link := &windowLink { window: window } link := &windowLink { window: window }
window.hierarchy = this.system.NewHierarchy(link) window.hierarchy = this.system.NewHierarchy(link)
window.leader = window
window.resizeX = true
window.resizeY = true
window.xWindow, err = xwindow.Generate(this.x) window.xWindow, err = xwindow.Generate(this.x)
if err != nil { return } if err != nil { return }
@@ -178,12 +179,16 @@ func (this *window) SetTitle (title string) {
icccm.WmIconNameSet (this.backend.x, this.xWindow.Id, title) icccm.WmIconNameSet (this.backend.x, this.xWindow.Id, title)
} }
func (this *window) SetIcon (sizes ...image.Image) { func (this *window) SetIcon (sizes ...canvas.Texture) {
wmIcons := []ewmh.WmIcon { } wmIcons := []ewmh.WmIcon { }
for _, icon := range sizes { for _, icon := range sizes {
width := icon.Bounds().Max.X icon, ok := icon.(*xcanvas.Texture)
height := icon.Bounds().Max.Y if !ok { continue }
bounds := icon.Bounds()
width := bounds.Dx()
height := bounds.Dy()
wmIcon := ewmh.WmIcon { wmIcon := ewmh.WmIcon {
Width: uint(width), Width: uint(width),
Height: uint(height), Height: uint(height),
@@ -193,18 +198,14 @@ func (this *window) SetIcon (sizes ...image.Image) {
// manually convert image data beacuse of course we have to do // manually convert image data beacuse of course we have to do
// this // this
index := 0 index := 0
for y := 0; y < height; y ++ { for y := bounds.Min.Y; y < bounds.Max.Y; y ++ {
for x := 0; x < width; x ++ { for x := bounds.Min.X; x < bounds.Max.X; x ++ {
r, g, b, a := icon.At(x, y).RGBA() pixel := icon.BGRAAt(x, y)
r >>= 8
g >>= 8
b >>= 8
a >>= 8
wmIcon.Data[index] = wmIcon.Data[index] =
(uint(a) << 24) | (uint(pixel.A) << 24) |
(uint(r) << 16) | (uint(pixel.R) << 16) |
(uint(g) << 8) | (uint(pixel.G) << 8) |
(uint(b) << 0) (uint(pixel.B) << 0)
index ++ index ++
}} }}
@@ -217,6 +218,20 @@ func (this *window) SetIcon (sizes ...image.Image) {
wmIcons) wmIcons)
} }
func (this *window) SetResizable (x, y bool) {
if this.resizeX == x && this.resizeY == y { return }
this.resizeX = x
this.resizeY = y
this.doMinimumSize()
}
func (this *window) SetBounds (bounds image.Rectangle) {
this.xWindow.WMMoveResize (
bounds.Min.X, bounds.Min.Y,
bounds.Min.X + bounds.Dx(),
bounds.Min.Y + bounds.Dy())
}
func (this *window) NewMenu (bounds image.Rectangle) (tomo.Window, error) { func (this *window) NewMenu (bounds image.Rectangle) (tomo.Window, error) {
menu, err := this.backend.newWindow ( menu, err := this.backend.newWindow (
bounds.Add(this.metrics.bounds.Min), true) bounds.Add(this.metrics.bounds.Min), true)
@@ -247,19 +262,24 @@ func (this *window) NewModal (bounds image.Rectangle) (tomo.Window, error) {
return modal, err return modal, err
} }
func (this mainWindow) NewChild (bounds image.Rectangle) (tomo.Window, error) { func (this *window) NewChild (bounds image.Rectangle) (tomo.Window, error) {
leader := this.leader
child, err := this.backend.newWindow ( child, err := this.backend.newWindow (
bounds.Add(this.metrics.bounds.Min), false) bounds.Add(this.metrics.bounds.Min), false)
child.leader = leader
if err != nil { return nil, err } if err != nil { return nil, err }
child.setClientLeader(this.window)
this.setClientLeader(this.window) child.setClientLeader(leader)
leader.setClientLeader(leader)
icccm.WmTransientForSet ( icccm.WmTransientForSet (
this.backend.x, this.backend.x,
this.xWindow.Id, child.xWindow.Id,
this.xWindow.Id) leader.xWindow.Id)
this.setType("UTILITY") child.setType("UTILITY")
// this.inheritProperties(this.window) // child.inheritProperties(leader.window)
return this, err return child, err
} }
func (this *window) Widget () (tomo.Window, error) { func (this *window) Widget () (tomo.Window, error) {
@@ -306,6 +326,7 @@ func (this *window) Close () {
this.SetRoot(nil) this.SetRoot(nil)
delete(this.backend.windows, this.xWindow.Id) delete(this.backend.windows, this.xWindow.Id)
this.xWindow.Destroy() this.xWindow.Destroy()
this.hierarchy.Close()
} }
func (this *window) OnClose (callback func ()) event.Cookie { func (this *window) OnClose (callback func ()) event.Cookie {
@@ -404,14 +425,30 @@ func (this *window) doMinimumSize () {
if size.X < 8 { size.X = 8 } if size.X < 8 { size.X = 8 }
if size.Y < 8 { size.Y = 8 } if size.Y < 8 { size.Y = 8 }
hints := icccm.NormalHints {
Flags: icccm.SizeHintPMinSize,
MinWidth: uint(size.X),
MinHeight: uint(size.Y),
// now you can tell your friends that the max size of a Tomo
// window under X when one of the dimensions is constrained is
// 99999999999
MaxWidth: uint(99999999999),
MaxHeight: uint(99999999999),
}
if !this.resizeX {
hints.Flags |= icccm.SizeHintPMaxSize
hints.MaxWidth = uint(size.X)
}
if !this.resizeY {
hints.Flags |= icccm.SizeHintPMaxSize
hints.MaxHeight = uint(size.Y)
}
icccm.WmNormalHintsSet ( icccm.WmNormalHintsSet (
this.backend.x, this.backend.x,
this.xWindow.Id, this.xWindow.Id,
&icccm.NormalHints { &hints)
Flags: icccm.SizeHintPMinSize,
MinWidth: uint(size.X),
MinHeight: uint(size.Y),
})
newWidth := this.metrics.bounds.Dx() newWidth := this.metrics.bounds.Dx()
newHeight := this.metrics.bounds.Dy() newHeight := this.metrics.bounds.Dy()
if newWidth < size.X { newWidth = size.X } if newWidth < size.X { newWidth = size.X }