This repository has been archived on 2023-08-08. You can view files and clone it, but cannot push or open issues or pull requests.
tomo-old/backends/x/event.go

411 lines
10 KiB
Go
Raw Normal View History

2023-01-08 23:03:19 -07:00
package x
import "image"
2023-03-30 21:19:04 -06:00
import "git.tebibyte.media/sashakoshka/tomo"
2023-02-01 23:47:55 -07:00
import "git.tebibyte.media/sashakoshka/tomo/input"
2023-01-08 23:03:19 -07:00
import "github.com/jezek/xgbutil"
import "github.com/jezek/xgb/xproto"
import "github.com/jezek/xgbutil/xevent"
type scrollSum struct {
x, y int
}
const scrollDistance = 16
func (sum *scrollSum) add (button xproto.Button, window *window, state uint16) {
shift :=
(state & xproto.ModMaskShift) > 0 ||
(state & window.backend.modifierMasks.shiftLock) > 0
if shift {
switch button {
case 4: sum.x -= scrollDistance
case 5: sum.x += scrollDistance
case 6: sum.y -= scrollDistance
case 7: sum.y += scrollDistance
}
} else {
switch button {
case 4: sum.y -= scrollDistance
case 5: sum.y += scrollDistance
case 6: sum.x -= scrollDistance
case 7: sum.x += scrollDistance
}
2023-01-08 23:03:19 -07:00
}
}
func (window *window) handleExpose (
2023-01-26 00:08:07 -07:00
connection *xgbutil.XUtil,
event xevent.ExposeEvent,
) {
_, region := window.compressExpose(*event.ExposeEvent)
2023-04-13 22:25:05 -06:00
window.system.afterEvent()
window.pushRegion(region)
2023-01-26 00:08:07 -07:00
}
func (window *window) updateBounds (x, y int16, width, height uint16) {
window.metrics.bounds =
image.Rect(0, 0, int(width), int(height)).
Add(image.Pt(int(x), int(y)))
}
func (window *window) handleConfigureNotify (
2023-01-08 23:03:19 -07:00
connection *xgbutil.XUtil,
event xevent.ConfigureNotifyEvent,
) {
2023-01-15 10:23:13 -07:00
if window.child == nil { return }
2023-01-08 23:03:19 -07: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 (
configureEvent.X, configureEvent.Y,
configureEvent.Width, configureEvent.Height)
2023-01-08 23:03:19 -07:00
if sizeChanged {
configureEvent = window.compressConfigureNotify(configureEvent)
window.updateBounds (
configureEvent.X, configureEvent.Y,
configureEvent.Width, configureEvent.Height)
2023-01-08 23:03:19 -07:00
window.reallocateCanvas()
window.resizeChildToFit()
2023-01-26 00:08:07 -07:00
if !window.exposeEventFollows(configureEvent) {
2023-04-13 22:25:05 -06:00
window.child.Invalidate()
window.child.InvalidateLayout()
2023-01-26 00:08:07 -07:00
}
2023-04-13 22:25:05 -06:00
window.system.afterEvent()
2023-01-08 23:03:19 -07:00
}
}
func (window *window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (found bool) {
2023-01-26 00:08:07 -07:00
nextEvents := xevent.Peek(window.backend.connection)
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
}
func (window *window) modifiersFromState (
state uint16,
) (
2023-02-01 23:47:55 -07:00
modifiers input.Modifiers,
) {
2023-02-01 23:47:55 -07:00
return input.Modifiers {
Shift:
(state & xproto.ModMaskShift) > 0 ||
(state & window.backend.modifierMasks.shiftLock) > 0,
Control: (state & xproto.ModMaskControl) > 0,
Alt: (state & window.backend.modifierMasks.alt) > 0,
Meta: (state & window.backend.modifierMasks.meta) > 0,
Super: (state & window.backend.modifierMasks.super) > 0,
Hyper: (state & window.backend.modifierMasks.hyper) > 0,
}
}
func (window *window) handleKeyPress (
2023-01-08 23:03:19 -07:00
connection *xgbutil.XUtil,
event xevent.KeyPressEvent,
) {
2023-04-14 21:58:14 -06:00
if window.hasModal { return }
2023-01-08 23:03:19 -07:00
keyEvent := *event.KeyPressEvent
key, numberPad := window.backend.keycodeToKey(keyEvent.Detail, keyEvent.State)
modifiers := window.modifiersFromState(keyEvent.State)
modifiers.NumberPad = numberPad
2023-01-08 23:03:19 -07:00
2023-02-01 23:47:55 -07:00
if key == input.KeyTab && modifiers.Alt {
if modifiers.Shift {
window.system.focusPrevious()
} else {
window.system.focusNext()
}
2023-04-10 14:47:03 -06:00
} else if key == input.KeyEscape && window.shy {
window.Close()
} else if window.focused != nil {
focused, ok := window.focused.element.(tomo.KeyboardTarget)
if ok { focused.HandleKeyDown(key, modifiers) }
}
2023-04-13 22:25:05 -06:00
window.system.afterEvent()
}
func (window *window) handleKeyRelease (
2023-01-08 23:03:19 -07:00
connection *xgbutil.XUtil,
event xevent.KeyReleaseEvent,
) {
keyEvent := *event.KeyReleaseEvent
// do not process this event if it was generated from a key repeat
nextEvents := xevent.Peek(window.backend.connection)
if len(nextEvents) > 0 {
untypedEvent := nextEvents[0]
if untypedEvent.Err == nil {
typedEvent, ok :=
untypedEvent.Event.(xproto.KeyPressEvent)
if ok && typedEvent.Detail == keyEvent.Detail &&
typedEvent.Event == keyEvent.Event &&
typedEvent.State == keyEvent.State {
return
}
}
2023-01-08 23:03:19 -07:00
}
2023-01-15 10:23:13 -07:00
key, numberPad := window.backend.keycodeToKey(keyEvent.Detail, keyEvent.State)
modifiers := window.modifiersFromState(keyEvent.State)
modifiers.NumberPad = numberPad
2023-04-14 21:58:14 -06:00
if window.focused != nil {
focused, ok := window.focused.element.(tomo.KeyboardTarget)
if ok { focused.HandleKeyUp(key, modifiers) }
window.system.afterEvent()
}
2023-01-08 23:03:19 -07:00
}
func (window *window) handleButtonPress (
2023-01-08 23:03:19 -07:00
connection *xgbutil.XUtil,
event xevent.ButtonPressEvent,
) {
if window.hasModal { return }
2023-04-10 14:47:03 -06:00
buttonEvent := *event.ButtonPressEvent
point := image.Pt(int(buttonEvent.EventX), int(buttonEvent.EventY))
insideWindow := point.In(window.canvas.Bounds())
scrolling := buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7
underneath := window.system.childAt(point)
if !insideWindow && window.shy && !scrolling {
2023-04-10 14:47:03 -06:00
window.Close()
} else if scrolling {
if child, ok := underneath.element.(tomo.ScrollTarget); ok {
2023-01-15 10:23:13 -07:00
sum := scrollSum { }
sum.add(buttonEvent.Detail, window, buttonEvent.State)
2023-01-15 10:23:13 -07:00
window.compressScrollSum(buttonEvent, &sum)
child.HandleScroll (
point.X, point.Y,
2023-01-15 10:23:13 -07:00
float64(sum.x), float64(sum.y))
}
} else {
if child, ok := underneath.element.(tomo.MouseTarget); ok {
window.system.drags[buttonEvent.Detail] = child
2023-01-15 10:23:13 -07:00
child.HandleMouseDown (
point.X, point.Y,
2023-02-01 23:47:55 -07:00
input.Button(buttonEvent.Detail))
2023-01-15 10:23:13 -07:00
}
2023-01-08 23:03:19 -07:00
}
2023-01-15 10:23:13 -07:00
2023-04-13 22:25:05 -06:00
window.system.afterEvent()
2023-01-08 23:03:19 -07:00
}
func (window *window) handleButtonRelease (
2023-01-08 23:03:19 -07:00
connection *xgbutil.XUtil,
event xevent.ButtonReleaseEvent,
) {
buttonEvent := *event.ButtonReleaseEvent
if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return }
child := window.system.drags[buttonEvent.Detail]
if child != nil {
2023-01-15 10:23:13 -07:00
child.HandleMouseUp (
int(buttonEvent.EventX),
int(buttonEvent.EventY),
2023-02-01 23:47:55 -07:00
input.Button(buttonEvent.Detail))
2023-01-15 10:23:13 -07:00
}
2023-04-13 22:25:05 -06:00
window.system.afterEvent()
2023-01-08 23:03:19 -07:00
}
func (window *window) handleMotionNotify (
2023-01-08 23:03:19 -07:00
connection *xgbutil.XUtil,
event xevent.MotionNotifyEvent,
) {
motionEvent := window.compressMotionNotify(*event.MotionNotifyEvent)
x := int(motionEvent.EventX)
y :=int(motionEvent.EventY)
handled := false
for _, child := range window.system.drags {
if child, ok := child.(tomo.MotionTarget); ok {
child.HandleMotion(x, y)
handled = true
}
}
if !handled {
child := window.system.childAt(image.Pt(x, y))
if child, ok := child.element.(tomo.MotionTarget); ok {
child.HandleMotion(x, y)
}
2023-01-15 10:23:13 -07:00
}
2023-04-13 22:25:05 -06:00
window.system.afterEvent()
2023-01-08 23:03:19 -07:00
}
2023-03-27 18:44:39 -06:00
func (window *window) handleSelectionNotify (
connection *xgbutil.XUtil,
event xevent.SelectionNotifyEvent,
) {
if window.selectionRequest == nil { return }
window.selectionRequest.handleSelectionNotify(connection, event)
if !window.selectionRequest.open() { window.selectionRequest = nil }
2023-03-27 18:44:39 -06:00
}
2023-03-29 21:24:42 -06:00
func (window *window) handlePropertyNotify (
connection *xgbutil.XUtil,
event xevent.PropertyNotifyEvent,
) {
if window.selectionRequest == nil { return }
window.selectionRequest.handlePropertyNotify(connection, event)
if !window.selectionRequest.open() { window.selectionRequest = nil }
}
func (window *window) handleSelectionClear (
connection *xgbutil.XUtil,
event xevent.SelectionClearEvent,
) {
2023-03-30 11:10:58 -06:00
window.selectionClaim = nil
}
func (window *window) handleSelectionRequest (
connection *xgbutil.XUtil,
event xevent.SelectionRequestEvent,
) {
if window.selectionClaim == nil { return }
window.selectionClaim.handleSelectionRequest(connection, event)
2023-03-29 21:24:42 -06:00
}
func (window *window) compressExpose (
2023-01-26 00:08:07 -07:00
firstEvent xproto.ExposeEvent,
) (
lastEvent xproto.ExposeEvent,
region image.Rectangle,
2023-01-26 00:08:07 -07:00
) {
region = image.Rect (
int(firstEvent.X), int(firstEvent.Y),
int(firstEvent.X + firstEvent.Width),
int(firstEvent.Y + firstEvent.Height))
2023-01-26 00:08:07 -07:00
window.backend.connection.Sync()
xevent.Read(window.backend.connection, false)
lastEvent = firstEvent
for index, untypedEvent := range xevent.Peek(window.backend.connection) {
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)))
2023-01-26 00:08:07 -07:00
lastEvent = typedEvent
defer func (index int) {
xevent.DequeueAt(window.backend.connection, index)
} (index)
}
}
return
}
2023-01-08 23:03:19 -07:00
func (window *window) compressConfigureNotify (
2023-01-08 23:03:19 -07:00
firstEvent xproto.ConfigureNotifyEvent,
) (
lastEvent xproto.ConfigureNotifyEvent,
) {
window.backend.connection.Sync()
xevent.Read(window.backend.connection, false)
lastEvent = firstEvent
for index, untypedEvent := range xevent.Peek(window.backend.connection) {
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.connection, index)
} (index)
}
}
return
}
func (window *window) compressScrollSum (
2023-01-08 23:03:19 -07:00
firstEvent xproto.ButtonPressEvent,
sum *scrollSum,
) {
window.backend.connection.Sync()
xevent.Read(window.backend.connection, false)
for index, untypedEvent := range xevent.Peek(window.backend.connection) {
if untypedEvent.Err != nil { continue }
typedEvent, ok := untypedEvent.Event.(xproto.ButtonPressEvent)
if !ok { continue }
if firstEvent.Event == typedEvent.Event &&
typedEvent.Detail >= 4 &&
typedEvent.Detail <= 7 {
sum.add(typedEvent.Detail, window, typedEvent.State)
2023-01-08 23:03:19 -07:00
defer func (index int) {
xevent.DequeueAt(window.backend.connection, index)
} (index)
}
}
return
}
func (window *window) compressMotionNotify (
2023-01-08 23:03:19 -07:00
firstEvent xproto.MotionNotifyEvent,
) (
lastEvent xproto.MotionNotifyEvent,
) {
window.backend.connection.Sync()
xevent.Read(window.backend.connection, false)
lastEvent = firstEvent
for index, untypedEvent := range xevent.Peek(window.backend.connection) {
if untypedEvent.Err != nil { continue }
typedEvent, ok := untypedEvent.Event.(xproto.MotionNotifyEvent)
if !ok { continue }
if firstEvent.Event == typedEvent.Event {
2023-01-08 23:03:19 -07:00
lastEvent = typedEvent
defer func (index int) {
xevent.DequeueAt(window.backend.connection, index)
} (index)
}
}
return
}