Repository navigation
Expand file tree
/
Copy pathstartup_window_gate.go
More file actions
121 lines (110 loc) · 2.28 KB
/
Copy pathstartup_window_gate.go
File metadata and controls
121 lines (110 loc) · 2.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package main
import (
"sync"
"time"
)
const (
startupFrontendReadyEvent = "gonavi:frontend-ready"
startupWindowShowFallback = 4 * time.Second
)
// startupWindowGate keeps the main window hidden until either the frontend has
// painted its final startup geometry or a fallback timer fires. Showing on
// DOMContentLoaded used to present Wails' empty white client area because
// bootstrap.ts still had to load catalogs and React had not hydrated; on macOS
// it also exposed the remembered-bounds/maximise transition as a visible
// "small window then full screen" animation.
type startupWindowGate struct {
mu sync.Mutex
iconReady bool
frontendReady bool
timedOut bool
presented bool
show func()
fallback *time.Timer
}
func newStartupWindowGate() *startupWindowGate {
return &startupWindowGate{}
}
func shouldShowStartupWindow(iconReady, frontendReady, timedOut, showBound bool) bool {
return showBound && iconReady && (frontendReady || timedOut)
}
func (g *startupWindowGate) bindShow(show func()) {
if g == nil {
return
}
g.mu.Lock()
g.show = show
g.mu.Unlock()
g.tryShow()
}
func (g *startupWindowGate) markIconReady() {
if g == nil {
return
}
g.mu.Lock()
g.iconReady = true
g.mu.Unlock()
g.tryShow()
}
func (g *startupWindowGate) markFrontendReady() {
if g == nil {
return
}
g.mu.Lock()
g.frontendReady = true
g.mu.Unlock()
g.tryShow()
}
func (g *startupWindowGate) markTimedOut() {
if g == nil {
return
}
g.mu.Lock()
g.timedOut = true
g.mu.Unlock()
g.tryShow()
}
func (g *startupWindowGate) startFallback(timeout time.Duration, onTimeout func()) {
if g == nil {
return
}
if timeout <= 0 {
if onTimeout != nil {
onTimeout()
} else {
g.markTimedOut()
}
return
}
g.mu.Lock()
if g.fallback != nil {
g.fallback.Stop()
}
g.fallback = time.AfterFunc(timeout, func() {
if onTimeout != nil {
onTimeout()
return
}
g.markTimedOut()
})
g.mu.Unlock()
}
func (g *startupWindowGate) tryShow() {
if g == nil {
return
}
g.mu.Lock()
show := g.show
ready := shouldShowStartupWindow(g.iconReady, g.frontendReady, g.timedOut, show != nil)
if !ready || g.presented {
g.mu.Unlock()
return
}
g.presented = true
if g.fallback != nil {
g.fallback.Stop()
g.fallback = nil
}
g.mu.Unlock()
show()
}