26 Commits

Author SHA1 Message Date
868b6fdfe9 Fix crash when CanvasBox draws with nil canvas 2024-06-24 18:43:54 -04:00
1c803ff9c1 Fix out of bounds panic with polygon filling 2024-06-24 18:42:43 -04:00
fdcf254891 Box re-applies theme on role change 2024-06-20 16:44:24 -04:00
e23e794730 CanvasBox no longer crashes on nil drawer 2024-06-19 12:13:31 -04:00
caa261665f Remove obsolete TODO 2024-06-15 23:35:44 -04:00
e21b57a915 X backend properly converts image data 2024-06-15 23:33:59 -04:00
727a801243 Attempt to fix strange issue with overflowing 2024-06-14 02:30:59 -04:00
76701d4383 Fix style application part 2 2024-06-12 02:12:24 -04:00
6619987b5a Fixed style application 2024-06-12 00:39:00 -04:00
02de78c997 Window is resizable by default (lol) 2024-06-12 00:29:07 -04:00
95b1d033a9 SetResizable has been implemented 2024-06-11 23:58:19 -04:00
1951b6e408 Partially implement new stuff for X 2024-06-11 23:45:49 -04:00
c7f09c7894 Add recommended sizes and all that jazz 2024-06-11 22:45:40 -04:00
80f60b42de I lied 2024-06-11 18:35:40 -04:00
995e6fd624 Add theme setting nonsense 2024-06-11 18:12:47 -04:00
26b69d3e21 Update Tomo API 2024-06-11 17:18:30 -04:00
52a0136e60 Fixed Window.NewChild returning the parent (oops) 2024-06-07 01:47:24 -04:00
5657f85c83 Update Window.SetIcon 2024-06-07 01:12:04 -04:00
a9ac9f6600 Change scrolling speed from 16 to 32 2024-06-07 01:07:48 -04:00
6eff6887e7 Unify window and mainWindow 2024-06-07 01:07:28 -04:00
adf0ef3a89 Update Tomo API 2024-06-07 01:07:15 -04:00
07bcd119d7 X backend uses Close method instead of Destroy to free canvas 2024-06-03 20:54:45 -04:00
c51ce65c88 System no longer requires a NewCanvas method 2024-06-03 20:44:58 -04:00
0d93d73c32 Backend returns CanvasCloser 2024-06-03 20:43:05 -04:00
006921d690 Store Role in Box 2024-06-03 20:42:54 -04:00
f2bcc217a4 Update Tomo API 2024-06-03 20:42:08 -04:00
14 changed files with 313 additions and 90 deletions

5
go.mod
View File

@@ -3,11 +3,8 @@ module git.tebibyte.media/tomo/backend
go 1.20
require (
git.tebibyte.media/tomo/tomo v0.34.0
git.tebibyte.media/tomo/tomo v0.38.0
git.tebibyte.media/tomo/typeset v0.7.1
)
require (
git.tebibyte.media/tomo/xgbkb v1.0.1
github.com/jezek/xgb v1.1.1
github.com/jezek/xgbutil v0.0.0-20231116234834-47f30c120111

4
go.sum
View File

@@ -1,6 +1,6 @@
git.tebibyte.media/sashakoshka/xgbkb v1.0.0/go.mod h1:pNcE6TRO93vHd6q42SdwLSTTj25L0Yzggz7yLe0JV6Q=
git.tebibyte.media/tomo/tomo v0.34.0 h1:r5yJPks9rtzdDI2RyAUdqa1qb6BebG0QFe2cTmcFi+0=
git.tebibyte.media/tomo/tomo v0.34.0/go.mod h1:C9EzepS9wjkTJjnZaPBh22YvVPyA4hbBAJVU20Rdmps=
git.tebibyte.media/tomo/tomo v0.38.0 h1:K5TP67RxnszudeNfmGZiU5cFTRjFueXiI3NCsgw+05U=
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/go.mod h1:PwDpSdBF3l/EzoIsa2ME7QffVVajnTHZN6l3MHEGe1g=
git.tebibyte.media/tomo/xgbkb v1.0.1 h1:b3HDUopjdQp1MZrb5Vpil4bOtk3NnNXtfQW27Blw2kE=

View File

@@ -19,6 +19,11 @@ type box struct {
parent parent
outer anyBox
role tomo.Role
styleCookie event.Cookie
lastStyleNonce int
lastIconsNonce int
bounds image.Rectangle
minSize image.Point
userMinSize image.Point
@@ -42,19 +47,21 @@ type box struct {
drawer canvas.Drawer
on struct {
focusEnter event.FuncBroadcaster
focusLeave event.FuncBroadcaster
dndEnter event.FuncBroadcaster
dndLeave event.FuncBroadcaster
dndDrop event.Broadcaster[func (data.Data)]
mouseEnter event.FuncBroadcaster
mouseLeave event.FuncBroadcaster
mouseMove event.FuncBroadcaster
mouseDown event.Broadcaster[func (input.Button)]
mouseUp event.Broadcaster[func (input.Button)]
scroll event.Broadcaster[func (float64, float64)]
keyDown event.Broadcaster[func (input.Key, bool)]
keyUp event.Broadcaster[func (input.Key, bool)]
focusEnter event.FuncBroadcaster
focusLeave event.FuncBroadcaster
dndEnter event.FuncBroadcaster
dndLeave event.FuncBroadcaster
dndDrop event.Broadcaster[func (data.Data)]
mouseEnter event.FuncBroadcaster
mouseLeave event.FuncBroadcaster
mouseMove event.FuncBroadcaster
mouseDown event.Broadcaster[func (input.Button)]
mouseUp event.Broadcaster[func (input.Button)]
scroll event.Broadcaster[func (float64, float64)]
keyDown event.Broadcaster[func (input.Key, bool)]
keyUp event.Broadcaster[func (input.Key, bool)]
styleChange event.FuncBroadcaster
iconsChange event.FuncBroadcaster
}
}
@@ -106,6 +113,10 @@ func (this *box) MinimumSize () image.Point {
return this.minSize
}
func (this *box) Role () tomo.Role {
return this.role
}
func (this *box) borderSum () tomo.Inset {
sum := tomo.Inset { }
for _, border := range this.border {
@@ -117,6 +128,15 @@ func (this *box) borderSum () tomo.Inset {
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) {
if this.bounds == bounds { return }
this.bounds = bounds
@@ -182,6 +202,13 @@ func (this *box) SetPadding (padding tomo.Inset) {
this.invalidateMinimum()
}
func (this *box) SetRole (role tomo.Role) {
if this.role == role { return }
this.role = role
this.lastStyleNonce = -1
this.outer.recursiveReApply()
}
func (this *box) SetDNDData (dat data.Data) {
this.dndData = dat
}
@@ -272,6 +299,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 {
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 () {
this.on.focusEnter.Broadcast()
}
@@ -441,7 +474,7 @@ func (this *box) doLayout () {
// laycnt ++
this.innerClippingBounds = this.borderSum().Apply(this.bounds)
this.loseCanvas()
this.outer.recursiveLoseCanvas()
}
func (this *box) setParent (parent parent) {
@@ -449,6 +482,7 @@ func (this *box) setParent (parent parent) {
this.SetFocused(false)
}
this.parent = parent
this.outer.recursiveReApply()
}
func (this *box) getParent () parent {
@@ -471,7 +505,7 @@ func (this *box) recursiveRedo () {
this.doDraw()
}
func (this *box) loseCanvas () {
func (this *box) recursiveLoseCanvas () {
this.canvas.InvalidateTo(nil)
}
@@ -496,6 +530,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 {
return this.focusable
}
@@ -529,7 +593,23 @@ func (this *box) getWindow () tomo.Window {
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 {
if this.parent == nil { return nil }
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

@@ -29,7 +29,10 @@ func (this *canvasBox) Invalidate () {
}
func (this *canvasBox) Draw (can canvas.Canvas) {
if can == nil { return }
this.box.Draw(can)
this.userDrawer.Draw (
can.SubCanvas(this.padding.Apply(this.innerClippingBounds)))
if this.userDrawer != nil {
this.userDrawer.Draw (
can.SubCanvas(this.padding.Apply(this.innerClippingBounds)))
}
}

View File

@@ -73,6 +73,24 @@ func (this *containerBox) ScrollTo (point image.Point) {
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 {
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 {
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]),
needDraw: make(util.Set[anyBox]),
}
this.hierarchies.Add(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.
func (this *Hierarchy) SetCanvas (can canvas.Canvas) {
this.canvas = can
if this.root != nil { this.root.loseCanvas() }
if this.root != nil { this.root.recursiveLoseCanvas() }
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 {
return this
}
@@ -143,6 +158,18 @@ func (this *Hierarchy) getWindow () tomo.Window {
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 {
return this.canvas
}

View File

@@ -51,13 +51,17 @@ type anyBox interface {
// flushActionQueue performs any queued actions, like invalidating the
// minimum size or grabbing input focus.
flushActionQueue ()
flushActionQueue ()
// recursiveRedo recursively recalculates the minimum size, layout, and
// re-paints this anyBox and all of its children.
recursiveRedo ()
recursiveRedo ()
// loseCanvas causes this anyBox and its children (if applicable) to
// 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 () image.Point
@@ -81,19 +85,19 @@ type anyBox interface {
propagate (func (anyBox) bool) bool
propagateAlt (func (anyBox) bool) bool
handleFocusEnter ()
handleFocusLeave ()
// handleDndEnter ()
// handleDndLeave ()
// handleDndDrop (data.Data)
handleMouseEnter ()
handleMouseLeave ()
handleMouseMove ()
handleMouseDown (input.Button)
handleMouseUp (input.Button)
handleScroll (float64, float64)
handleKeyDown (input.Key, bool)
handleKeyUp (input.Key, bool)
handleFocusEnter ()
handleFocusLeave ()
// handleDndEnter ()
// handleDndLeave ()
// handleDndDrop (data.Data)
handleMouseEnter ()
handleMouseLeave ()
handleMouseMove ()
handleMouseDown (input.Button)
handleMouseUp (input.Button)
handleScroll (float64, float64)
handleKeyDown (input.Key, bool)
handleKeyUp (input.Key, bool)
}
func assertAnyBox (unknown tomo.Box) anyBox {

View File

@@ -2,12 +2,20 @@ package system
import "io"
import "image"
import "git.tebibyte.media/tomo/tomo"
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
// and Boxes.
type System struct {
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
@@ -15,8 +23,6 @@ type System struct {
type BackendLink interface {
// NewTexture creates a new texture from an image.
NewTexture (image.Image) canvas.TextureCloser
// NewCanvas creates a new blank canvas with the specified bounds.
NewCanvas (image.Rectangle) canvas.Canvas
// NewSurface creates a new surface with the specified bounds.
NewSurface (image.Rectangle) (SurfaceLink, error)
}
@@ -32,6 +38,29 @@ type SurfaceLink interface {
// New creates a new System.
func New (link BackendLink) *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()
}
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 {
return this.on.contentBoundsChange.Connect(callback)
}

View File

@@ -31,10 +31,6 @@ func (this *backendLink) NewTexture (source image.Image) canvas.TextureCloser {
return this.backend.NewTexture(source)
}
func (this *backendLink) NewCanvas (bounds image.Rectangle) canvas.Canvas {
return this.backend.NewCanvas(bounds)
}
func (this *backendLink) NewSurface (bounds image.Rectangle) (system.SurfaceLink, error) {
// TODO
return nil, errors.New("x: not implemented")
@@ -126,10 +122,18 @@ func (this *Backend) NewTexture (source image.Image) canvas.TextureCloser {
return xcanvas.NewTextureFrom(source)
}
func (this *Backend) NewCanvas (bounds image.Rectangle) canvas.Canvas {
func (this *Backend) NewCanvas (bounds image.Rectangle) canvas.CanvasCloser {
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 () {
if this == nil { panic("x: nil backend") }
}

View File

@@ -49,9 +49,10 @@ func (this *Canvas) Push (window xproto.Window) {
}
// Close frees this canvas from the X server.
func (this *Canvas) Close () {
func (this *Canvas) Close () error {
this.assert()
this.Image.Destroy()
return nil
}
func (this *Canvas) assert () {

View File

@@ -215,7 +215,7 @@ type fillingContext struct {
}
func (context *fillingContext) fillPolygonHotOpaque () {
for index := 0; index < len(context.boundaries); index += 2 {
for index := 0; index < len(context.boundaries) - 1; index += 2 {
left := context.boundaries[index]
right := context.boundaries[index + 1]
@@ -240,7 +240,7 @@ func (context *fillingContext) fillPolygonHotOpaque () {
}
func (context *fillingContext) fillPolygonHotTransparent () {
for index := 0; index < len(context.boundaries); index += 2 {
for index := 0; index < len(context.boundaries) - 1; index += 2 {
left := context.boundaries[index]
right := context.boundaries[index + 1]

View File

@@ -13,7 +13,7 @@ type scrollSum struct {
}
// 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) {
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/xgraphics"
type mainWindow struct { *window }
type window struct {
backend *Backend
hierarchy *system.Hierarchy
@@ -28,10 +27,13 @@ type window struct {
title string
leader *window
modalParent *window
hasModal bool
shy bool
visible bool
resizeX bool
resizeY bool
metrics struct {
bounds image.Rectangle
@@ -63,28 +65,24 @@ func (this *windowLink) NotifyMinimumSizeChange () {
func (this *Backend) NewWindow (
bounds image.Rectangle,
) (
output tomo.MainWindow,
output tomo.Window,
err error,
) {
this.assert()
window, err := this.newWindow(bounds, false)
output = mainWindow { window: window }
return output, err
return this.newWindow(bounds, false)
}
func (this *Backend) NewPlainWindow (
bounds image.Rectangle,
) (
output tomo.MainWindow,
output tomo.Window,
err error,
) {
this.assert()
window, err := this.newWindow(bounds, false)
window.setType("dock")
output = mainWindow { window: window }
return output, err
return window, err
}
func (this *Backend) newWindow (
@@ -100,6 +98,9 @@ func (this *Backend) newWindow (
window := &window { backend: this }
link := &windowLink { window: window }
window.hierarchy = this.system.NewHierarchy(link)
window.leader = window
window.resizeX = true
window.resizeY = true
window.xWindow, err = xwindow.Generate(this.x)
if err != nil { return }
@@ -178,12 +179,16 @@ func (this *window) SetTitle (title string) {
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 { }
for _, icon := range sizes {
width := icon.Bounds().Max.X
height := icon.Bounds().Max.Y
icon, ok := icon.(*xcanvas.Texture)
if !ok { continue }
bounds := icon.Bounds()
width := bounds.Dx()
height := bounds.Dy()
wmIcon := ewmh.WmIcon {
Width: uint(width),
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
// this
index := 0
for y := 0; y < height; y ++ {
for x := 0; x < width; x ++ {
r, g, b, a := icon.At(x, y).RGBA()
r >>= 8
g >>= 8
b >>= 8
a >>= 8
for y := bounds.Min.Y; y < bounds.Max.Y; y ++ {
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
pixel := icon.BGRAAt(x, y)
wmIcon.Data[index] =
(uint(a) << 24) |
(uint(r) << 16) |
(uint(g) << 8) |
(uint(b) << 0)
(uint(pixel.A) << 24) |
(uint(pixel.R) << 16) |
(uint(pixel.G) << 8) |
(uint(pixel.B) << 0)
index ++
}}
@@ -217,6 +218,20 @@ func (this *window) SetIcon (sizes ...image.Image) {
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) {
menu, err := this.backend.newWindow (
bounds.Add(this.metrics.bounds.Min), true)
@@ -247,19 +262,24 @@ func (this *window) NewModal (bounds image.Rectangle) (tomo.Window, error) {
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 (
bounds.Add(this.metrics.bounds.Min), false)
child.leader = leader
if err != nil { return nil, err }
child.setClientLeader(this.window)
this.setClientLeader(this.window)
child.setClientLeader(leader)
leader.setClientLeader(leader)
icccm.WmTransientForSet (
this.backend.x,
this.xWindow.Id,
this.xWindow.Id)
this.setType("UTILITY")
// this.inheritProperties(this.window)
return this, err
child.xWindow.Id,
leader.xWindow.Id)
child.setType("UTILITY")
// child.inheritProperties(leader.window)
return child, err
}
func (this *window) Widget () (tomo.Window, error) {
@@ -306,6 +326,7 @@ func (this *window) Close () {
this.SetRoot(nil)
delete(this.backend.windows, this.xWindow.Id)
this.xWindow.Destroy()
this.hierarchy.Close()
}
func (this *window) OnClose (callback func ()) event.Cookie {
@@ -361,7 +382,7 @@ func (this *window) reallocateCanvas () {
if larger || smaller {
if this.xCanvas != nil {
this.xCanvas.Destroy()
this.xCanvas.Close()
}
this.xCanvas = xcanvas.NewCanvasFrom(xgraphics.New (
this.backend.x,
@@ -404,14 +425,30 @@ func (this *window) doMinimumSize () {
if size.X < 8 { size.X = 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 (
this.backend.x,
this.xWindow.Id,
&icccm.NormalHints {
Flags: icccm.SizeHintPMinSize,
MinWidth: uint(size.X),
MinHeight: uint(size.Y),
})
&hints)
newWidth := this.metrics.bounds.Dx()
newHeight := this.metrics.bounds.Dy()
if newWidth < size.X { newWidth = size.X }