package x import "image" import "github.com/jezek/xgbutil" import "github.com/jezek/xgb/xproto" import "git.tebibyte.media/tomo/xgbkb" import "github.com/jezek/xgbutil/xevent" import "git.tebibyte.media/tomo/tomo/input" func (window *window) handleExpose ( connection *xgbutil.XUtil, event xevent.ExposeEvent, ) { if window.xCanvas == nil { window.reallocateCanvas() } window.compressExpose(*event.ExposeEvent) window.pushAll() } 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 } 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() // 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 } 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)) } } 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 } 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)) }