diff --git a/backends/x/event.go b/backends/x/event.go index 189237c..7f8a889 100644 --- a/backends/x/event.go +++ b/backends/x/event.go @@ -42,6 +42,14 @@ func (sum *scrollSum) add (button xproto.Button, window *Window, state uint16) { } +func (window *Window) handleExpose ( + connection *xgbutil.XUtil, + event xevent.ExposeEvent, +) { + _ = window.compressExpose(*event.ExposeEvent) + window.redrawChildEntirely() +} + func (window *Window) handleConfigureNotify ( connection *xgbutil.XUtil, event xevent.ConfigureNotifyEvent, @@ -64,9 +72,29 @@ func (window *Window) handleConfigureNotify ( window.metrics.height = int(configureEvent.Height) window.reallocateCanvas() window.resizeChildToFit() + + if !window.exposeEventFollows(configureEvent) { + window.redrawChildEntirely() + } } } +func (window *Window) exposeEventFollows (event xproto.ConfigureNotifyEvent) (found bool) { + 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, ) ( @@ -201,6 +229,32 @@ func (window *Window) handleMotionNotify ( } } +func (window *Window) compressExpose ( + firstEvent xproto.ExposeEvent, +) ( + lastEvent xproto.ExposeEvent, +) { + 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 } + + // FIXME: union all areas into the last event + if firstEvent.Window == typedEvent.Window { + lastEvent = typedEvent + defer func (index int) { + xevent.DequeueAt(window.backend.connection, index) + } (index) + } + } + + return +} func (window *Window) compressConfigureNotify ( firstEvent xproto.ConfigureNotifyEvent, diff --git a/backends/x/window.go b/backends/x/window.go index 0a9e4cb..70fce0e 100644 --- a/backends/x/window.go +++ b/backends/x/window.go @@ -39,6 +39,7 @@ func (backend *Backend) NewWindow ( backend.connection.RootWin(), 0, 0, width, height, 0) err = window.xWindow.Listen ( + xproto.EventMaskExposure, xproto.EventMaskStructureNotify, xproto.EventMaskPointerMotion, xproto.EventMaskKeyPress, @@ -50,7 +51,9 @@ func (backend *Backend) NewWindow ( window.xWindow.WMGracefulClose (func (xWindow *xwindow.Window) { window.Close() }) - + + xevent.ExposeFun(window.handleExpose). + Connect(backend.connection, window.xWindow.Id) xevent.ConfigureNotifyFun(window.handleConfigureNotify). Connect(backend.connection, window.xWindow.Id) xevent.KeyPressFun(window.handleKeyPress). @@ -108,6 +111,7 @@ func (window *Window) Adopt (child tomo.Element) { }) window.resizeChildToFit() window.childMinimumSizeChangeCallback(child.MinimumSize()) + window.redrawChildEntirely() } } @@ -200,12 +204,14 @@ func (window *Window) reallocateCanvas () { window.metrics.width, window.metrics.height)) - window.xCanvas.XSurfaceSet(window.xWindow.Id) + window.xCanvas.CreatePixmap() } func (window *Window) redrawChildEntirely () { data, stride := window.child.Buffer() + bounds := window.child.Bounds() window.xCanvas.For (func (x, y int) (c xgraphics.BGRA) { + if !(image.Point { x, y }).In(bounds) { return } rgba := data[x + y * stride] c.R, c.G, c.B, c.A = rgba.R, rgba.G, rgba.B, rgba.A return @@ -235,13 +241,11 @@ func (window *Window) resizeChildToFit () { window.child.Resize ( window.metrics.width, window.metrics.height) - window.redrawChildEntirely() } } else { window.child.Resize ( window.metrics.width, window.metrics.height) - window.redrawChildEntirely() } window.skipChildDrawCallback = false } @@ -310,6 +314,9 @@ func (window *Window) pushRegion (region image.Rectangle) { image, ok := window.xCanvas.SubImage(region).(*xgraphics.Image) if ok { image.XDraw() - window.xCanvas.XPaint(window.xWindow.Id) + image.XExpPaint ( + window.xWindow.Id, + image.Bounds().Min.X, + image.Bounds().Min.Y) } }