Fix x/window.go

This commit is contained in:
Sasha Koshka 2024-09-12 02:07:57 -04:00
parent ee64650c19
commit b58932f02b

View File

@ -1,6 +1,7 @@
package x package x
import "image" import "image"
import "strings"
import "git.tebibyte.media/tomo/tomo" import "git.tebibyte.media/tomo/tomo"
import "git.tebibyte.media/tomo/tomo/data" import "git.tebibyte.media/tomo/tomo/data"
@ -41,7 +42,10 @@ type window struct {
innerBounds image.Rectangle // bounds of the drawable area innerBounds image.Rectangle // bounds of the drawable area
} }
onClose event.FuncBroadcaster on struct {
close event.FuncBroadcaster
tryClose event.Broadcaster[func () bool]
}
} }
type windowLink struct { type windowLink struct {
@ -64,27 +68,12 @@ func (this *windowLink) NotifyMinimumSizeChange () {
this.window.doMinimumSize() this.window.doMinimumSize()
} }
func (this *Backend) NewWindow ( func (this *Backend) NewWindow (kind tomo.WindowKind, bounds image.Rectangle) (tomo.Window, error) {
bounds image.Rectangle,
) (
output tomo.Window,
err error,
) {
this.assert()
return this.newWindow(bounds, false)
}
func (this *Backend) NewPlainWindow (
bounds image.Rectangle,
) (
output tomo.Window,
err error,
) {
this.assert() this.assert()
window, err := this.newWindow(bounds, false) window, err := this.newWindow(bounds, false)
window.setType("dock") if err != nil { return nil, err }
window.setKind(kind)
return window, err return window, nil
} }
func (this *Backend) newWindow ( func (this *Backend) newWindow (
@ -131,7 +120,11 @@ func (this *Backend) newWindow (
if err != nil { return } if err != nil { return }
window.xWindow.WMGracefulClose (func (xWindow *xwindow.Window) { window.xWindow.WMGracefulClose (func (xWindow *xwindow.Window) {
window.Close() holdOff := false
for _, callback := range window.on.tryClose.Listeners() {
if !callback() { holdOff = true }
}
if !holdOff { window.Close() }
}) })
xevent.ExposeFun(window.handleExpose). xevent.ExposeFun(window.handleExpose).
@ -247,56 +240,29 @@ func (this *window) SetBounds (bounds image.Rectangle) {
bounds.Min.Y + bounds.Dy()) bounds.Min.Y + bounds.Dy())
} }
func (this *window) NewChild (bounds image.Rectangle) (tomo.Window, error) { func (this *window) NewChild (kind tomo.WindowKind, bounds image.Rectangle) (tomo.Window, error) {
leader := this.leader leader := this.leader
child, err := this.backend.newWindow ( child, err := this.backend.newWindow (
bounds.Add(this.metrics.innerBounds.Min), false) bounds.Add(this.metrics.innerBounds.Min), false)
child.leader = leader
if err != nil { return nil, err } if err != nil { return nil, err }
child.setClientLeader(leader) child.leader = leader
leader.setClientLeader(leader) err = child.setKind(kind)
if err != nil { return nil, err }
if kind == tomo.WindowKindModal {
this.hasModal = true
child.modalParent = this
}
icccm.WmTransientForSet ( icccm.WmTransientForSet (
this.backend.x, this.backend.x,
child.xWindow.Id, child.xWindow.Id,
leader.xWindow.Id) leader.xWindow.Id)
child.setType("UTILITY")
// child.inheritProperties(leader.window) // child.inheritProperties(leader.window)
return child, err return child, err
} }
func (this *window) NewMenu (bounds image.Rectangle) (tomo.Window, error) {
menu, err := this.backend.newWindow (
bounds.Add(this.metrics.innerBounds.Min), true)
menu.shy = true
icccm.WmTransientForSet (
this.backend.x,
menu.xWindow.Id,
this.xWindow.Id)
menu.setType("POPUP_MENU")
// menu.inheritProperties(this)
return menu, err
}
func (this *window) NewModal (bounds image.Rectangle) (tomo.Window, error) {
modal, err := this.backend.newWindow (
bounds.Add(this.metrics.innerBounds.Min), false)
icccm.WmTransientForSet (
this.backend.x,
modal.xWindow.Id,
this.xWindow.Id)
ewmh.WmStateSet (
this.backend.x,
modal.xWindow.Id,
[]string { "_NET_WM_STATE_MODAL" })
modal.modalParent = this
this.hasModal = true
// modal.inheritProperties(window)
return modal, err
}
func (this *window) Modifiers () input.Modifiers { func (this *window) Modifiers () input.Modifiers {
return this.hierarchy.Modifiers() return this.hierarchy.Modifiers()
} }
@ -330,12 +296,12 @@ func (this *window) Visible () bool {
return this.visible return this.visible
} }
func (this *window) Close () { func (this *window) Close () error {
xevent .Detach(this.backend.x, this.xWindow.Id) xevent .Detach(this.backend.x, this.xWindow.Id)
keybind .Detach(this.backend.x, this.xWindow.Id) keybind .Detach(this.backend.x, this.xWindow.Id)
mousebind.Detach(this.backend.x, this.xWindow.Id) mousebind.Detach(this.backend.x, this.xWindow.Id)
this.onClose.Broadcast() this.on.close.Broadcast()
if this.modalParent != nil { if this.modalParent != nil {
// we are a modal dialog, so unlock the parent // we are a modal dialog, so unlock the parent
this.modalParent.hasModal = false this.modalParent.hasModal = false
@ -345,10 +311,15 @@ func (this *window) Close () {
delete(this.backend.windows, this.xWindow.Id) delete(this.backend.windows, this.xWindow.Id)
this.xWindow.Destroy() this.xWindow.Destroy()
this.hierarchy.Close() this.hierarchy.Close()
return nil // TODO maybe return an error? maybe join them?
} }
func (this *window) OnClose (callback func ()) event.Cookie { func (this *window) OnClose (callback func ()) event.Cookie {
return this.onClose.Connect(callback) return this.on.close.Connect(callback)
}
func (this *window) OnTryClose (callback func () bool) event.Cookie {
return this.on.tryClose.Connect(callback)
} }
func (this *window) grabInput () { func (this *window) grabInput () {
@ -364,6 +335,19 @@ func (this *window) ungrabInput () {
mousebind.UngrabPointer(this.backend.x) mousebind.UngrabPointer(this.backend.x)
} }
func (this *window) setKind (kind tomo.WindowKind) error {
err := this.setType(windowKindToType(kind))
if err != nil { return err }
if kind == tomo.WindowKindModal {
err = this.setState("MODAL")
if err != nil { return err }
}
if kind == tomo.WindowKindMenu {
this.shy = true
}
return nil
}
func (this *window) setType (ty string) error { func (this *window) setType (ty string) error {
return ewmh.WmWindowTypeSet ( return ewmh.WmWindowTypeSet (
this.backend.x, this.backend.x,
@ -371,6 +355,13 @@ func (this *window) setType (ty string) error {
[]string { "_NET_WM_WINDOW_TYPE_" + ty }) []string { "_NET_WM_WINDOW_TYPE_" + ty })
} }
func (this *window) setState (state string) error {
return ewmh.WmStateSet (
this.backend.x,
this.xWindow.Id,
[]string { "_NET_WM_STATE_" + state })
}
func (this *window) setClientLeader (leader *window) error { func (this *window) setClientLeader (leader *window) error {
hints, _ := icccm.WmHintsGet(this.backend.x, this.xWindow.Id) hints, _ := icccm.WmHintsGet(this.backend.x, this.xWindow.Id)
if hints == nil { if hints == nil {
@ -476,3 +467,15 @@ func (this *window) doMinimumSize () {
this.xWindow.Resize(newWidth, newHeight) this.xWindow.Resize(newWidth, newHeight)
} }
} }
func windowKindToType (kind tomo.WindowKind) string {
switch kind {
case tomo.WindowKindNormal: return "NORMAL"
case tomo.WindowKindPlain: return "DOCK"
case tomo.WindowKindUtility: return "UTILITY"
case tomo.WindowKindToolbar: return "TOOLBAR"
case tomo.WindowKindMenu: return "POPUP_MENU"
case tomo.WindowKindModal: return "NORMAL"
default: return strings.ReplaceAll(strings.ToUpper(string(kind)), " ", "_")
}
}