app/internal/window: [Wayland] make notifications wakeup-only

Before, notifying the event loop implied a redraw. Derive the need
for redrawing expliticly and use the notification pipe for wakeups
only.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2020-05-16 11:56:27 +02:00
parent f2fee00bab
commit b99151c211
+14 -25
View File
@@ -857,22 +857,20 @@ func gio_onFrameDone(data unsafe.Pointer, callback *C.struct_wl_callback, t C.ui
func (w *window) loop() error { func (w *window) loop() error {
var p poller var p poller
for { for {
notified, err := w.disp.dispatch(&p) if err := w.disp.dispatch(&p); err != nil {
if err != nil {
return err return err
} }
if w.dead { if w.dead {
w.w.Event(system.DestroyEvent{}) w.w.Event(system.DestroyEvent{})
break break
} }
if notified { // pass false to skip unnecessary drawing.
w.draw(false) w.draw(false)
}
} }
return nil return nil
} }
func (d *wlDisplay) dispatch(p *poller) (bool, error) { func (d *wlDisplay) dispatch(p *poller) error {
dispfd := C.wl_display_get_fd(d.disp) dispfd := C.wl_display_get_fd(d.disp)
// Poll for events and notifications. // Poll for events and notifications.
pollfds := append(p.pollfds[:0], pollfds := append(p.pollfds[:0],
@@ -882,16 +880,15 @@ func (d *wlDisplay) dispatch(p *poller) (bool, error) {
dispFd := &pollfds[0] dispFd := &pollfds[0]
if ret, err := C.wl_display_flush(d.disp); ret < 0 { if ret, err := C.wl_display_flush(d.disp); ret < 0 {
if err != syscall.EAGAIN { if err != syscall.EAGAIN {
return false, fmt.Errorf("wayland: wl_display_flush failed: %v", err) return fmt.Errorf("wayland: wl_display_flush failed: %v", err)
} }
// EAGAIN means the output buffer was full. Poll for // EAGAIN means the output buffer was full. Poll for
// POLLOUT to know when we can write again. // POLLOUT to know when we can write again.
dispFd.Events |= syscall.POLLOUT dispFd.Events |= syscall.POLLOUT
} }
if _, err := syscall.Poll(pollfds, -1); err != nil && err != syscall.EINTR { if _, err := syscall.Poll(pollfds, -1); err != nil && err != syscall.EINTR {
return false, fmt.Errorf("wayland: poll failed: %v", err) return fmt.Errorf("wayland: poll failed: %v", err)
} }
notified := false
// Clear notifications. // Clear notifications.
for { for {
_, err := syscall.Read(d.notify.read, p.buf[:]) _, err := syscall.Read(d.notify.read, p.buf[:])
@@ -899,31 +896,27 @@ func (d *wlDisplay) dispatch(p *poller) (bool, error) {
break break
} }
if err != nil { if err != nil {
return false, fmt.Errorf("wayland: read from notify pipe failed: %v", err) return fmt.Errorf("wayland: read from notify pipe failed: %v", err)
} }
notified = true
} }
// Handle events // Handle events
switch { switch {
case dispFd.Revents&syscall.POLLIN != 0: case dispFd.Revents&syscall.POLLIN != 0:
if ret, err := C.wl_display_dispatch(d.disp); ret < 0 { if ret, err := C.wl_display_dispatch(d.disp); ret < 0 {
return false, fmt.Errorf("wayland: wl_display_dispatch failed: %v", err) return fmt.Errorf("wayland: wl_display_dispatch failed: %v", err)
} }
case dispFd.Revents&(syscall.POLLERR|syscall.POLLHUP) != 0: case dispFd.Revents&(syscall.POLLERR|syscall.POLLHUP) != 0:
return false, errors.New("wayland: display file descriptor gone") return errors.New("wayland: display file descriptor gone")
} }
d.repeat.Repeat(d) d.repeat.Repeat(d)
return notified, nil return nil
} }
func (w *window) SetAnimating(anim bool) { func (w *window) SetAnimating(anim bool) {
w.mu.Lock() w.mu.Lock()
w.animating = anim w.animating = anim
animating := w.isAnimating()
w.mu.Unlock() w.mu.Unlock()
if animating { w.disp.wakeup()
w.disp.wakeup()
}
} }
// Wakeup wakes up the event loop through the notification pipe. // Wakeup wakes up the event loop through the notification pipe.
@@ -1093,24 +1086,20 @@ func (w *window) config() (int, int, config) {
} }
} }
func (w *window) isAnimating() bool {
return w.animating || w.fling.anim.Active()
}
func (w *window) draw(sync bool) { func (w *window) draw(sync bool) {
w.flushScroll() w.flushScroll()
w.mu.Lock() w.mu.Lock()
animating := w.isAnimating() anim := w.animating || w.fling.anim.Active()
dead := w.dead dead := w.dead
w.mu.Unlock() w.mu.Unlock()
if dead || (!animating && !sync) { if dead || (!anim && !sync) {
return return
} }
width, height, cfg := w.config() width, height, cfg := w.config()
if cfg == (config{}) { if cfg == (config{}) {
return return
} }
if animating && w.lastFrameCallback == nil { if anim && w.lastFrameCallback == nil {
w.lastFrameCallback = C.wl_surface_frame(w.surf) w.lastFrameCallback = C.wl_surface_frame(w.surf)
// Use the surface as listener data for gio_onFrameDone. // Use the surface as listener data for gio_onFrameDone.
C.gio_wl_callback_add_listener(w.lastFrameCallback, unsafe.Pointer(w.surf)) C.gio_wl_callback_add_listener(w.lastFrameCallback, unsafe.Pointer(w.surf))