mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-01 07:35:40 +00:00
app: ignore Invalidate for Windows not yet created
While here, don't overflow the Windows event queue. Fixes: https://todo.sr.ht/~eliasnaur/gio/596 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -173,19 +173,13 @@ type context interface {
|
|||||||
Unlock()
|
Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// basicDriver is the subset of [driver] that may be called even after
|
// driver is the interface for the platform implementation
|
||||||
// a window is destroyed.
|
// of a window.
|
||||||
type basicDriver interface {
|
type driver interface {
|
||||||
// Event blocks until an event is available and returns it.
|
// Event blocks until an event is available and returns it.
|
||||||
Event() event.Event
|
Event() event.Event
|
||||||
// Invalidate requests a FrameEvent.
|
// Invalidate requests a FrameEvent.
|
||||||
Invalidate()
|
Invalidate()
|
||||||
}
|
|
||||||
|
|
||||||
// driver is the interface for the platform implementation
|
|
||||||
// of a window.
|
|
||||||
type driver interface {
|
|
||||||
basicDriver
|
|
||||||
// SetAnimating sets the animation flag. When the window is animating,
|
// SetAnimating sets the animation flag. When the window is animating,
|
||||||
// FrameEvents are delivered as fast as the display can handle them.
|
// FrameEvents are delivered as fast as the display can handle them.
|
||||||
SetAnimating(anim bool)
|
SetAnimating(anim bool)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"gioui.org/io/event"
|
|
||||||
"gioui.org/io/pointer"
|
"gioui.org/io/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -57,35 +56,12 @@ func newWindow(window *callbacks, options []Option) {
|
|||||||
errFirst = err
|
errFirst = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
window.SetDriver(&dummyDriver{
|
|
||||||
win: window,
|
|
||||||
wakeups: make(chan event.Event, 1),
|
|
||||||
})
|
|
||||||
if errFirst == nil {
|
if errFirst == nil {
|
||||||
errFirst = errors.New("app: no window driver available")
|
errFirst = errors.New("app: no window driver available")
|
||||||
}
|
}
|
||||||
window.ProcessEvent(DestroyEvent{Err: errFirst})
|
window.ProcessEvent(DestroyEvent{Err: errFirst})
|
||||||
}
|
}
|
||||||
|
|
||||||
type dummyDriver struct {
|
|
||||||
win *callbacks
|
|
||||||
wakeups chan event.Event
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *dummyDriver) Event() event.Event {
|
|
||||||
if e, ok := d.win.nextEvent(); ok {
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
return <-d.wakeups
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *dummyDriver) Invalidate() {
|
|
||||||
select {
|
|
||||||
case d.wakeups <- wakeupEvent{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// xCursor contains mapping from pointer.Cursor to XCursor.
|
// xCursor contains mapping from pointer.Cursor to XCursor.
|
||||||
var xCursor = [...]string{
|
var xCursor = [...]string{
|
||||||
pointer.CursorDefault: "left_ptr",
|
pointer.CursorDefault: "left_ptr",
|
||||||
|
|||||||
+1
-11
@@ -217,10 +217,6 @@ type window struct {
|
|||||||
wakeups chan struct{}
|
wakeups chan struct{}
|
||||||
|
|
||||||
closing bool
|
closing bool
|
||||||
|
|
||||||
// invMu avoids the race between the destruction of disp and
|
|
||||||
// Invalidate waking it up.
|
|
||||||
invMu sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type poller struct {
|
type poller struct {
|
||||||
@@ -1369,10 +1365,8 @@ func (w *window) close(err error) {
|
|||||||
w.ProcessEvent(WaylandViewEvent{})
|
w.ProcessEvent(WaylandViewEvent{})
|
||||||
w.ProcessEvent(DestroyEvent{Err: err})
|
w.ProcessEvent(DestroyEvent{Err: err})
|
||||||
w.destroy()
|
w.destroy()
|
||||||
w.invMu.Lock()
|
|
||||||
w.disp.destroy()
|
w.disp.destroy()
|
||||||
w.disp = nil
|
w.disp = nil
|
||||||
w.invMu.Unlock()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) dispatch() {
|
func (w *window) dispatch() {
|
||||||
@@ -1416,11 +1410,7 @@ func (w *window) Invalidate() {
|
|||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
w.invMu.Lock()
|
w.disp.wakeup()
|
||||||
defer w.invMu.Unlock()
|
|
||||||
if w.disp != nil {
|
|
||||||
w.disp.wakeup()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) Run(f func()) {
|
func (w *window) Run(f func()) {
|
||||||
|
|||||||
@@ -54,9 +54,6 @@ type window struct {
|
|||||||
borderSize image.Point
|
borderSize image.Point
|
||||||
config Config
|
config Config
|
||||||
loop *eventLoop
|
loop *eventLoop
|
||||||
|
|
||||||
// invMu avoids the race between destroying the window and Invalidate.
|
|
||||||
invMu sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const _WM_WAKEUP = windows.WM_USER + iota
|
const _WM_WAKEUP = windows.WM_USER + iota
|
||||||
@@ -304,10 +301,8 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
|||||||
windows.ReleaseDC(w.hdc)
|
windows.ReleaseDC(w.hdc)
|
||||||
w.hdc = 0
|
w.hdc = 0
|
||||||
}
|
}
|
||||||
w.invMu.Lock()
|
|
||||||
// The system destroys the HWND for us.
|
// The system destroys the HWND for us.
|
||||||
w.hwnd = 0
|
w.hwnd = 0
|
||||||
w.invMu.Unlock()
|
|
||||||
windows.PostQuitMessage(0)
|
windows.PostQuitMessage(0)
|
||||||
case windows.WM_NCCALCSIZE:
|
case windows.WM_NCCALCSIZE:
|
||||||
if w.config.Decorated {
|
if w.config.Decorated {
|
||||||
@@ -620,13 +615,6 @@ func (w *window) Frame(frame *op.Ops) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) wakeup() {
|
func (w *window) wakeup() {
|
||||||
w.invMu.Lock()
|
|
||||||
defer w.invMu.Unlock()
|
|
||||||
if w.hwnd == 0 {
|
|
||||||
w.loop.Wakeup()
|
|
||||||
w.loop.FlushEvents()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if err := windows.PostMessage(w.hwnd, _WM_WAKEUP, 0, 0); err != nil {
|
if err := windows.PostMessage(w.hwnd, _WM_WAKEUP, 0, 0); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,9 +113,6 @@ type x11Window struct {
|
|||||||
wakeups chan struct{}
|
wakeups chan struct{}
|
||||||
handler x11EventHandler
|
handler x11EventHandler
|
||||||
buf [100]byte
|
buf [100]byte
|
||||||
|
|
||||||
// invMy avoids the race between destroy and Invalidate.
|
|
||||||
invMu sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -416,11 +413,6 @@ func (w *x11Window) Invalidate() {
|
|||||||
case w.wakeups <- struct{}{}:
|
case w.wakeups <- struct{}{}:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
w.invMu.Lock()
|
|
||||||
defer w.invMu.Unlock()
|
|
||||||
if w.x == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if _, err := syscall.Write(w.notify.write, x11OneByte); err != nil && err != syscall.EAGAIN {
|
if _, err := syscall.Write(w.notify.write, x11OneByte); err != nil && err != syscall.EAGAIN {
|
||||||
panic(fmt.Errorf("failed to write to pipe: %v", err))
|
panic(fmt.Errorf("failed to write to pipe: %v", err))
|
||||||
}
|
}
|
||||||
@@ -509,8 +501,6 @@ func (w *x11Window) dispatch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *x11Window) destroy() {
|
func (w *x11Window) destroy() {
|
||||||
w.invMu.Lock()
|
|
||||||
defer w.invMu.Unlock()
|
|
||||||
if w.notify.write != 0 {
|
if w.notify.write != 0 {
|
||||||
syscall.Close(w.notify.write)
|
syscall.Close(w.notify.write)
|
||||||
w.notify.write = 0
|
w.notify.write = 0
|
||||||
|
|||||||
+36
-17
@@ -9,6 +9,7 @@ import (
|
|||||||
"image/color"
|
"image/color"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
@@ -89,8 +90,11 @@ type Window struct {
|
|||||||
}
|
}
|
||||||
imeState editorState
|
imeState editorState
|
||||||
driver driver
|
driver driver
|
||||||
// basic is the driver interface that is needed even after the window is gone.
|
|
||||||
basic basicDriver
|
// invMu protects mayInvalidate.
|
||||||
|
invMu sync.Mutex
|
||||||
|
mayInvalidate bool
|
||||||
|
|
||||||
// coalesced tracks the most recent events waiting to be delivered
|
// coalesced tracks the most recent events waiting to be delivered
|
||||||
// to the client.
|
// to the client.
|
||||||
coalesced eventSummary
|
coalesced eventSummary
|
||||||
@@ -272,8 +276,11 @@ func (w *Window) updateState() {
|
|||||||
//
|
//
|
||||||
// Invalidate is safe for concurrent use.
|
// Invalidate is safe for concurrent use.
|
||||||
func (w *Window) Invalidate() {
|
func (w *Window) Invalidate() {
|
||||||
if w.basic != nil {
|
w.invMu.Lock()
|
||||||
w.basic.Invalidate()
|
defer w.invMu.Unlock()
|
||||||
|
if w.mayInvalidate {
|
||||||
|
w.mayInvalidate = false
|
||||||
|
w.driver.Invalidate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +290,7 @@ func (w *Window) Option(opts ...Option) {
|
|||||||
if len(opts) == 0 {
|
if len(opts) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if w.basic == nil {
|
if w.driver == nil {
|
||||||
w.initialOpts = append(w.initialOpts, opts...)
|
w.initialOpts = append(w.initialOpts, opts...)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -378,11 +385,8 @@ func (w *Window) setNextFrame(at time.Time) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *callbacks) SetDriver(d basicDriver) {
|
func (c *callbacks) SetDriver(d driver) {
|
||||||
c.w.basic = d
|
c.w.driver = d
|
||||||
if d, ok := d.(driver); ok {
|
|
||||||
c.w.driver = d
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *callbacks) ProcessFrame(frame *op.Ops, ack chan<- struct{}) {
|
func (c *callbacks) ProcessFrame(frame *op.Ops, ack chan<- struct{}) {
|
||||||
@@ -549,9 +553,15 @@ func (c *callbacks) Invalidate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *callbacks) nextEvent() (event.Event, bool) {
|
func (c *callbacks) nextEvent() (event.Event, bool) {
|
||||||
s := &c.w.coalesced
|
return c.w.nextEvent()
|
||||||
// Every event counts as a wakeup.
|
}
|
||||||
defer func() { s.wakeup = false }()
|
|
||||||
|
func (w *Window) nextEvent() (event.Event, bool) {
|
||||||
|
s := &w.coalesced
|
||||||
|
defer func() {
|
||||||
|
// Every event counts as a wakeup.
|
||||||
|
s.wakeup = false
|
||||||
|
}()
|
||||||
switch {
|
switch {
|
||||||
case s.view != nil:
|
case s.view != nil:
|
||||||
e := *s.view
|
e := *s.view
|
||||||
@@ -573,6 +583,9 @@ func (c *callbacks) nextEvent() (event.Event, bool) {
|
|||||||
case s.wakeup:
|
case s.wakeup:
|
||||||
return wakeupEvent{}, true
|
return wakeupEvent{}, true
|
||||||
}
|
}
|
||||||
|
w.invMu.Lock()
|
||||||
|
defer w.invMu.Unlock()
|
||||||
|
w.mayInvalidate = w.driver != nil
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,7 +630,6 @@ func (w *Window) processEvent(e event.Event) bool {
|
|||||||
case DestroyEvent:
|
case DestroyEvent:
|
||||||
w.destroyGPU()
|
w.destroyGPU()
|
||||||
w.driver = nil
|
w.driver = nil
|
||||||
w.basic = nil
|
|
||||||
if q := w.timer.quit; q != nil {
|
if q := w.timer.quit; q != nil {
|
||||||
q <- struct{}{}
|
q <- struct{}{}
|
||||||
<-q
|
<-q
|
||||||
@@ -688,10 +700,17 @@ func (w *Window) processEvent(e event.Event) bool {
|
|||||||
// [FrameEvent], or until [Invalidate] is called. The window is created
|
// [FrameEvent], or until [Invalidate] is called. The window is created
|
||||||
// and shown the first time Event is called.
|
// and shown the first time Event is called.
|
||||||
func (w *Window) Event() event.Event {
|
func (w *Window) Event() event.Event {
|
||||||
if w.basic == nil {
|
if w.driver == nil {
|
||||||
w.init()
|
w.init()
|
||||||
}
|
}
|
||||||
return w.basic.Event()
|
if w.driver == nil {
|
||||||
|
e, ok := w.nextEvent()
|
||||||
|
if !ok {
|
||||||
|
panic("window initializion failed without a DestroyEvent")
|
||||||
|
}
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
return w.driver.Event()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *Window) init() {
|
func (w *Window) init() {
|
||||||
@@ -832,7 +851,7 @@ func (w *Window) Perform(actions system.Action) {
|
|||||||
if acts == 0 {
|
if acts == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if w.basic == nil {
|
if w.driver == nil {
|
||||||
w.initialActions = append(w.initialActions, acts)
|
w.initialActions = append(w.initialActions, acts)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user