2023-07-03 22:04:00 -06:00
|
|
|
package x
|
|
|
|
|
|
|
|
import "image"
|
|
|
|
|
|
|
|
import "github.com/jezek/xgbutil"
|
|
|
|
import "github.com/jezek/xgb/xproto"
|
2023-07-15 22:42:47 -06:00
|
|
|
import "git.tebibyte.media/tomo/xgbkb"
|
2023-07-03 22:04:00 -06:00
|
|
|
import "github.com/jezek/xgbutil/xevent"
|
2023-07-15 22:42:47 -06:00
|
|
|
import "git.tebibyte.media/tomo/tomo/input"
|
2023-07-03 22:04:00 -06:00
|
|
|
|
|
|
|
func (window *window) handleExpose (
|
|
|
|
connection *xgbutil.XUtil,
|
|
|
|
event xevent.ExposeEvent,
|
|
|
|
) {
|
2023-07-04 22:44:56 -06:00
|
|
|
if window.xCanvas == nil {
|
|
|
|
window.reallocateCanvas()
|
|
|
|
}
|
2023-07-03 22:04:00 -06:00
|
|
|
window.compressExpose(*event.ExposeEvent)
|
2023-07-04 22:44:56 -06:00
|
|
|
window.pushAll()
|
2023-07-03 22:04:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func (window *window) updateBounds () {
|
|
|
|
// FIXME: some window managers parent windows more than once, we might
|
|
|
|
// need to sum up all their positions.
|
|
|
|
decorGeometry, _ := window.xWindow.DecorGeometry()
|
|
|
|
windowGeometry, _ := window.xWindow.Geometry()
|
|
|
|
origin := image.Pt(
|
|
|
|
windowGeometry.X() + decorGeometry.X(),
|
|
|
|
windowGeometry.Y() + decorGeometry.Y())
|
|
|
|
window.metrics.bounds = image.Rectangle {
|
|
|
|
Min: origin,
|
|
|
|
Max: origin.Add(image.Pt(windowGeometry.Width(), windowGeometry.Height())),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (window *window) handleConfigureNotify (
|
|
|
|
connection *xgbutil.XUtil,
|
|
|
|
event xevent.ConfigureNotifyEvent,
|
|
|
|
) {
|
|
|
|
if window.root == nil { return }
|
2023-07-04 22:44:56 -06:00
|
|
|
|
2023-07-03 22:04:00 -06:00
|
|
|
configureEvent := *event.ConfigureNotifyEvent
|
|
|
|
|
|
|
|
newWidth := int(configureEvent.Width)
|
|
|
|
newHeight := int(configureEvent.Height)
|
|
|
|
sizeChanged :=
|
|
|
|
window.metrics.bounds.Dx() != newWidth ||
|
|
|
|
window.metrics.bounds.Dy() != newHeight
|
|
|
|
window.updateBounds()
|
|
|
|
|
|
|
|
if sizeChanged {
|
|
|
|
configureEvent = window.compressConfigureNotify(configureEvent)
|
|
|
|
window.reallocateCanvas()
|
2023-07-04 22:44:56 -06:00
|
|
|
|
2023-07-03 22:04:00 -06:00
|
|
|
// TODO figure out what to do with this
|
|
|
|
// if !window.exposeEventFollows(configureEvent) {
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (window *window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (found bool) {
|
|
|
|
nextEvents := xevent.Peek(window.backend.x)
|
|
|
|
if len(nextEvents) > 0 {
|
|
|
|
untypedEvent := nextEvents[0]
|
|
|
|
if untypedEvent.Err == nil {
|
|
|
|
typedEvent, ok :=
|
|
|
|
untypedEvent.Event.(xproto.ConfigureNotifyEvent)
|
|
|
|
|
|
|
|
if ok && typedEvent.Window == event.Window {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-07-15 22:42:47 -06:00
|
|
|
|
|
|
|
func (window *window) handleButtonPress (
|
|
|
|
connection *xgbutil.XUtil,
|
|
|
|
event xevent.ButtonPressEvent,
|
|
|
|
) {
|
|
|
|
if window.hasModal { return }
|
|
|
|
|
|
|
|
buttonEvent := *event.ButtonPressEvent
|
|
|
|
point := image.Pt(int(buttonEvent.EventX), int(buttonEvent.EventY))
|
|
|
|
insideWindow := point.In(window.xCanvas.Bounds())
|
|
|
|
scrolling := buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7
|
|
|
|
window.updateModifiers(buttonEvent.State)
|
|
|
|
window.updateMousePosition(buttonEvent.EventX, buttonEvent.EventY)
|
|
|
|
|
|
|
|
if !insideWindow && window.shy && !scrolling {
|
|
|
|
window.Close()
|
|
|
|
} else if scrolling {
|
|
|
|
// underneath := window.scrollTargetChildAt(point)
|
|
|
|
// if underneath != nil {
|
|
|
|
// if child, ok := underneath.element.(ability.ScrollTarget); ok {
|
|
|
|
// sum := scrollSum { }
|
|
|
|
// sum.add(buttonEvent.Detail, window, buttonEvent.State)
|
|
|
|
// window.compressScrollSum(buttonEvent, &sum)
|
|
|
|
// child.HandleScroll (
|
|
|
|
// point, float64(sum.x), float64(sum.y),
|
|
|
|
// modifiers)
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
} else {
|
|
|
|
underneath := window.boxUnder(point)
|
|
|
|
window.drags[buttonEvent.Detail] = underneath
|
|
|
|
if underneath != nil {
|
|
|
|
underneath.handleMouseDown(input.Button(buttonEvent.Detail))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (window *window) handleButtonRelease (
|
|
|
|
connection *xgbutil.XUtil,
|
|
|
|
event xevent.ButtonReleaseEvent,
|
|
|
|
) {
|
|
|
|
if window.hasModal { return }
|
|
|
|
|
|
|
|
buttonEvent := *event.ButtonReleaseEvent
|
|
|
|
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return }
|
|
|
|
window.updateModifiers(buttonEvent.State)
|
|
|
|
window.updateMousePosition(buttonEvent.EventX, buttonEvent.EventY)
|
|
|
|
dragging := window.drags[buttonEvent.Detail]
|
|
|
|
|
|
|
|
if dragging != nil {
|
|
|
|
dragging.handleMouseUp(input.Button(buttonEvent.Detail))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-07-03 22:04:00 -06:00
|
|
|
func (window *window) compressExpose (
|
|
|
|
firstEvent xproto.ExposeEvent,
|
|
|
|
) (
|
|
|
|
lastEvent xproto.ExposeEvent,
|
|
|
|
region image.Rectangle,
|
|
|
|
) {
|
|
|
|
region = image.Rect (
|
|
|
|
int(firstEvent.X), int(firstEvent.Y),
|
|
|
|
int(firstEvent.X + firstEvent.Width),
|
|
|
|
int(firstEvent.Y + firstEvent.Height))
|
|
|
|
|
|
|
|
window.backend.x.Sync()
|
|
|
|
xevent.Read(window.backend.x, false)
|
|
|
|
lastEvent = firstEvent
|
|
|
|
|
|
|
|
for index, untypedEvent := range xevent.Peek(window.backend.x) {
|
|
|
|
if untypedEvent.Err != nil { continue }
|
|
|
|
|
|
|
|
typedEvent, ok := untypedEvent.Event.(xproto.ExposeEvent)
|
|
|
|
if !ok { continue }
|
|
|
|
|
|
|
|
if firstEvent.Window == typedEvent.Window {
|
|
|
|
region = region.Union (image.Rect (
|
|
|
|
int(typedEvent.X), int(typedEvent.Y),
|
|
|
|
int(typedEvent.X + typedEvent.Width),
|
|
|
|
int(typedEvent.Y + typedEvent.Height)))
|
|
|
|
|
|
|
|
lastEvent = typedEvent
|
|
|
|
defer func (index int) {
|
|
|
|
xevent.DequeueAt(window.backend.x, index)
|
|
|
|
} (index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (window *window) compressConfigureNotify (
|
|
|
|
firstEvent xproto.ConfigureNotifyEvent,
|
|
|
|
) (
|
|
|
|
lastEvent xproto.ConfigureNotifyEvent,
|
|
|
|
) {
|
|
|
|
window.backend.x.Sync()
|
|
|
|
xevent.Read(window.backend.x, false)
|
|
|
|
lastEvent = firstEvent
|
|
|
|
|
|
|
|
for index, untypedEvent := range xevent.Peek(window.backend.x) {
|
|
|
|
if untypedEvent.Err != nil { continue }
|
|
|
|
|
|
|
|
typedEvent, ok := untypedEvent.Event.(xproto.ConfigureNotifyEvent)
|
|
|
|
if !ok { continue }
|
|
|
|
|
|
|
|
if firstEvent.Event == typedEvent.Event &&
|
|
|
|
firstEvent.Window == typedEvent.Window {
|
|
|
|
|
|
|
|
lastEvent = typedEvent
|
|
|
|
defer func (index int) {
|
|
|
|
xevent.DequeueAt(window.backend.x, index)
|
|
|
|
} (index)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
2023-07-15 22:42:47 -06:00
|
|
|
|
|
|
|
func (window *window) updateModifiers (state uint16) {
|
|
|
|
modifiers := xgbkb.StateToModifiers(state)
|
|
|
|
window.modifiers.Shift = modifiers.Shift || modifiers.ShiftLock
|
|
|
|
window.modifiers.Control = modifiers.Control
|
|
|
|
window.modifiers.Alt = modifiers.Alt
|
|
|
|
window.modifiers.Meta = modifiers.Meta
|
|
|
|
window.modifiers.Super = modifiers.Super
|
|
|
|
window.modifiers.Hyper = modifiers.Hyper
|
|
|
|
}
|
|
|
|
|
|
|
|
func (window *window) updateMousePosition (x, y int16) {
|
|
|
|
window.mousePosition = image.Pt(int(x), int(y))
|
|
|
|
}
|