package x import "image" import "github.com/jezek/xgbutil" import "github.com/jezek/xgb/xproto" import "github.com/jezek/xgbutil/xevent" import "git.tebibyte.media/sashakoshka/stone" type scrollSum struct { x, y int } func (sum *scrollSum) add (button xproto.Button) { switch button { case 4: sum.y -- case 5: sum.y ++ case 6: sum.x -- case 7: sum.x ++ } } func (backend *Backend) Run () { backend.callbackManager.RunStart() backend.Draw() xevent.Main(backend.connection) backend.callbackManager.RunQuit() } func (backend *Backend) handleConfigureNotify ( connection *xgbutil.XUtil, event xevent.ConfigureNotifyEvent, ) { backend.lock.Lock() configureEvent := *event.ConfigureNotifyEvent newWidth := int(configureEvent.Width) newHeight := int(configureEvent.Height) sizeChanged := backend.metrics.windowWidth != newWidth || backend.metrics.windowHeight != newHeight backend.metrics.windowWidth = newWidth backend.metrics.windowHeight = newHeight if sizeChanged { configureEvent = backend.compressConfigureNotify(configureEvent) // resize buffer width, height := backend.calculateBufferSize() backend.application.SetSize(width, height) if backend.config.Center() { // position buffer in the center of the screen frameWidth := width * backend.metrics.cellWidth frameHeight := height * backend.metrics.cellHeight backend.metrics.paddingX = (backend.metrics.windowWidth - frameWidth) / 2 backend.metrics.paddingY = (backend.metrics.windowHeight - frameHeight) / 2 } else { backend.metrics.paddingX = backend.metrics.padding backend.metrics.paddingY = backend.metrics.padding } backend.windowBoundsClean = false } backend.lock.Unlock() if sizeChanged { backend.callbackManager.RunResize() backend.Draw() } } func (backend *Backend) handleButtonPress ( connection *xgbutil.XUtil, event xevent.ButtonPressEvent, ) { buttonEvent := *event.ButtonPressEvent if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { sum := scrollSum { } sum.add(buttonEvent.Detail) backend.compressScrollSum(&sum) backend.callbackManager.RunScroll(sum.x, sum.y) } else { backend.callbackManager.RunPress ( stone.Button(buttonEvent.Detail + 127), stone.Modifiers { }) } } func (backend *Backend) handleButtonRelease ( connection *xgbutil.XUtil, event xevent.ButtonReleaseEvent, ) { buttonEvent := *event.ButtonReleaseEvent if buttonEvent.Detail >= 4 && buttonEvent.Detail <= 7 { return } backend.callbackManager.RunRelease(stone.Button(buttonEvent.Detail + 127)) } func (backend *Backend) handleKeyPress ( connection *xgbutil.XUtil, event xevent.KeyPressEvent, ) { keyEvent := *event.KeyPressEvent button, num := backend.keycodeToButton(keyEvent.Detail, keyEvent.State) backend.callbackManager.RunPress (button, stone.Modifiers { Shift: (keyEvent.State & xproto.ModMaskShift) > 0 || (keyEvent.State & backend.modifierMasks.shiftLock) > 0, Control: (keyEvent.State & xproto.ModMaskControl) > 0, Alt: (keyEvent.State & backend.modifierMasks.alt) > 0, Meta: (keyEvent.State & backend.modifierMasks.meta) > 0, Super: (keyEvent.State & backend.modifierMasks.super) > 0, Hyper: (keyEvent.State & backend.modifierMasks.hyper) > 0, NumberPad: num, }) } func (backend *Backend) handleKeyRelease ( connection *xgbutil.XUtil, event xevent.KeyReleaseEvent, ) { keyEvent := *event.KeyReleaseEvent button, _ := backend.keycodeToButton(keyEvent.Detail, keyEvent.State) backend.callbackManager.RunRelease(button) } func (backend *Backend) handleMotionNotify ( connection *xgbutil.XUtil, event xevent.MotionNotifyEvent, ) { motionEvent := backend.compressMotionNotify(*event.MotionNotifyEvent) x, y := backend.cellAt (image.Point { X: int(motionEvent.EventX), Y: int(motionEvent.EventY), }) backend.callbackManager.RunMouseMove(x, y) } func (backend *Backend) compressConfigureNotify ( firstEvent xproto.ConfigureNotifyEvent, ) ( lastEvent xproto.ConfigureNotifyEvent, ) { backend.connection.Sync() xevent.Read(backend.connection, false) lastEvent = firstEvent for index, untypedEvent := range xevent.Peek(backend.connection) { if untypedEvent.Err != nil { continue } typedEvent, ok := untypedEvent.Event.(xproto.ConfigureNotifyEvent) if !ok { continue } lastEvent = typedEvent defer func (index int) { xevent.DequeueAt(backend.connection, index) } (index) } return } func (backend *Backend) compressMotionNotify ( firstEvent xproto.MotionNotifyEvent, ) ( lastEvent xproto.MotionNotifyEvent, ) { backend.connection.Sync() xevent.Read(backend.connection, false) lastEvent = firstEvent for index, untypedEvent := range xevent.Peek(backend.connection) { if untypedEvent.Err != nil { continue } typedEvent, ok := untypedEvent.Event.(xproto.MotionNotifyEvent) if !ok { continue } lastEvent = typedEvent defer func (index int) { xevent.DequeueAt(backend.connection, index) } (index) } return } func (backend *Backend) compressScrollSum (sum *scrollSum) { backend.connection.Sync() xevent.Read(backend.connection, false) for index, untypedEvent := range xevent.Peek(backend.connection) { if untypedEvent.Err != nil { continue } typedEvent, ok := untypedEvent.Event.(xproto.ButtonPressEvent) if !ok { continue } sum.add(typedEvent.Detail) defer func (index int) { xevent.DequeueAt(backend.connection, index) } (index) } return }