forked from joejulian/gio
app: replace Window.Config with ConfigEvent
Unlike Raise, Close and other fire-and-forget methods on Window, Config calls driverRun because it needs to wait for the result. However, driverRun isn't guaranteed to block in all contexts. This change avoids the synchronization dance altogether by removing the Config method and introducing a ConfigEvent event. The event also makes it clear when the configuration changes. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -46,6 +46,11 @@ type Config struct {
|
||||
CustomRenderer bool
|
||||
}
|
||||
|
||||
// ConfigEvent is sent whenever the configuration of a Window changes.
|
||||
type ConfigEvent struct {
|
||||
Config Config
|
||||
}
|
||||
|
||||
func (c *Config) apply(m unit.Metric, options []Option) {
|
||||
for _, o := range options {
|
||||
o(m, c)
|
||||
@@ -135,9 +140,6 @@ type driver interface {
|
||||
// Configure the window.
|
||||
Configure([]Option)
|
||||
|
||||
// Config returns the current configuration.
|
||||
Config() Config
|
||||
|
||||
// SetCursor updates the current cursor to name.
|
||||
SetCursor(name pointer.CursorName)
|
||||
|
||||
@@ -187,4 +189,5 @@ func newWindowRendezvous() *windowRendezvous {
|
||||
return wr
|
||||
}
|
||||
|
||||
func (_ wakeupEvent) ImplementsEvent() {}
|
||||
func (wakeupEvent) ImplementsEvent() {}
|
||||
func (ConfigEvent) ImplementsEvent() {}
|
||||
|
||||
+11
-11
@@ -507,19 +507,20 @@ func (w *window) SetAnimating(anim bool) {
|
||||
}
|
||||
|
||||
func (w *window) draw(sync bool) {
|
||||
width, height := C.ANativeWindow_getWidth(w.win), C.ANativeWindow_getHeight(w.win)
|
||||
if width == 0 || height == 0 {
|
||||
size := image.Pt(int(C.ANativeWindow_getWidth(w.win)), int(C.ANativeWindow_getHeight(w.win)))
|
||||
if size != w.config.Size {
|
||||
w.config.Size = size
|
||||
w.callbacks.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
if size.X == 0 || size.Y == 0 {
|
||||
return
|
||||
}
|
||||
const inchPrDp = 1.0 / 160
|
||||
ppdp := float32(w.dpi) * inchPrDp
|
||||
w.callbacks.Event(frameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Now: time.Now(),
|
||||
Size: image.Point{
|
||||
X: int(width),
|
||||
Y: int(height),
|
||||
},
|
||||
Now: time.Now(),
|
||||
Size: w.config.Size,
|
||||
Insets: w.insets,
|
||||
Metric: unit.Metric{
|
||||
PxPerDp: ppdp,
|
||||
@@ -815,13 +816,12 @@ func (w *window) Configure(options []Option) {
|
||||
w.config.Mode = Windowed
|
||||
}
|
||||
}
|
||||
if w.config != prev {
|
||||
w.callbacks.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (w *window) Config() Config {
|
||||
return w.config
|
||||
}
|
||||
|
||||
func (w *window) Raise() {}
|
||||
|
||||
func (w *window) SetCursor(name pointer.CursorName) {
|
||||
|
||||
@@ -95,7 +95,6 @@ type window struct {
|
||||
|
||||
visible bool
|
||||
cursor pointer.CursorName
|
||||
config Config
|
||||
|
||||
pointerMap []C.CFTypeRef
|
||||
}
|
||||
@@ -271,10 +270,6 @@ func (w *window) WriteClipboard(s string) {
|
||||
|
||||
func (w *window) Configure([]Option) {}
|
||||
|
||||
func (w *window) Config() Config {
|
||||
return w.config
|
||||
}
|
||||
|
||||
func (w *window) Raise() {}
|
||||
|
||||
func (w *window) SetAnimating(anim bool) {
|
||||
|
||||
+18
-17
@@ -94,12 +94,12 @@ func newWindow(win *callbacks, options []Option) error {
|
||||
})
|
||||
w.addEventListeners()
|
||||
w.addHistory()
|
||||
w.Configure(options)
|
||||
w.w = win
|
||||
|
||||
go func() {
|
||||
defer w.cleanup()
|
||||
w.w.SetDriver(w)
|
||||
w.Configure(options)
|
||||
w.blur()
|
||||
w.w.Event(system.StageEvent{Stage: system.StageRunning})
|
||||
w.resize()
|
||||
@@ -528,10 +528,9 @@ func (w *window) Configure(options []Option) {
|
||||
w.config.Orientation = cnf.Orientation
|
||||
w.orientation(cnf.Orientation)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) Config() Config {
|
||||
return w.config
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) Raise() {}
|
||||
@@ -571,8 +570,14 @@ func (w *window) resize() {
|
||||
w.scale = float32(w.window.Get("devicePixelRatio").Float())
|
||||
|
||||
rect := w.cnv.Call("getBoundingClientRect")
|
||||
w.config.Size.X = int(rect.Get("width").Float()) * int(w.scale)
|
||||
w.config.Size.Y = int(rect.Get("height").Float()) * int(w.scale)
|
||||
size := image.Point{
|
||||
X: int(float32(rect.Get("width").Float()) * w.scale),
|
||||
Y: int(float32(rect.Get("height").Float()) * w.scale),
|
||||
}
|
||||
if size != w.config.Size {
|
||||
w.config.Size = size
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
|
||||
if vx, vy := w.visualViewport.Get("width"), w.visualViewport.Get("height"); !vx.IsUndefined() && !vy.IsUndefined() {
|
||||
w.inset.X = float32(w.config.Size.X) - float32(vx.Float())*w.scale
|
||||
@@ -588,18 +593,14 @@ func (w *window) resize() {
|
||||
}
|
||||
|
||||
func (w *window) draw(sync bool) {
|
||||
width, height, insets, metric := w.getConfig()
|
||||
if metric == (unit.Metric{}) || width == 0 || height == 0 {
|
||||
size, insets, metric := w.getConfig()
|
||||
if metric == (unit.Metric{}) || size.X == 0 || size.Y == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
w.w.Event(frameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Now: time.Now(),
|
||||
Size: image.Point{
|
||||
X: width,
|
||||
Y: height,
|
||||
},
|
||||
Now: time.Now(),
|
||||
Size: size,
|
||||
Insets: insets,
|
||||
Metric: metric,
|
||||
},
|
||||
@@ -607,8 +608,8 @@ func (w *window) draw(sync bool) {
|
||||
})
|
||||
}
|
||||
|
||||
func (w *window) getConfig() (int, int, system.Insets, unit.Metric) {
|
||||
return w.config.Size.X, w.config.Size.Y, system.Insets{
|
||||
func (w *window) getConfig() (image.Point, system.Insets, unit.Metric) {
|
||||
return image.Pt(w.config.Size.X, w.config.Size.Y), system.Insets{
|
||||
Bottom: unit.Px(w.inset.Y),
|
||||
Right: unit.Px(w.inset.X),
|
||||
}, unit.Metric{
|
||||
|
||||
+14
-12
@@ -252,10 +252,9 @@ func (w *window) Configure(options []Option) {
|
||||
C.toggleFullScreen(w.window)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) Config() Config {
|
||||
return w.config
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) SetCursor(name pointer.CursorName) {
|
||||
@@ -389,20 +388,23 @@ func gio_onChangeScreen(view C.CFTypeRef, did uint64) {
|
||||
func (w *window) draw() {
|
||||
w.scale = float32(C.getViewBackingScale(w.view))
|
||||
wf, hf := float32(C.viewWidth(w.view)), float32(C.viewHeight(w.view))
|
||||
if wf == 0 || hf == 0 {
|
||||
sz := image.Point{
|
||||
X: int(wf*w.scale + .5),
|
||||
Y: int(hf*w.scale + .5),
|
||||
}
|
||||
if sz != w.config.Size {
|
||||
w.config.Size = sz
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
if sz.X == 0 || sz.Y == 0 {
|
||||
return
|
||||
}
|
||||
width := int(wf*w.scale + .5)
|
||||
height := int(hf*w.scale + .5)
|
||||
cfg := configFor(w.scale)
|
||||
w.setStage(system.StageRunning)
|
||||
w.w.Event(frameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Now: time.Now(),
|
||||
Size: image.Point{
|
||||
X: width,
|
||||
Y: height,
|
||||
},
|
||||
Now: time.Now(),
|
||||
Size: w.config.Size,
|
||||
Metric: cfg,
|
||||
},
|
||||
Sync: true,
|
||||
|
||||
+30
-27
@@ -187,7 +187,9 @@ type window struct {
|
||||
serial C.uint32_t
|
||||
newScale bool
|
||||
scale int
|
||||
config Config
|
||||
// size is the unscaled window size (unlike config.Size which is scaled).
|
||||
size image.Point
|
||||
config Config
|
||||
|
||||
wakeups chan struct{}
|
||||
}
|
||||
@@ -222,7 +224,7 @@ func init() {
|
||||
wlDriver = newWLWindow
|
||||
}
|
||||
|
||||
func newWLWindow(window *callbacks, options []Option) error {
|
||||
func newWLWindow(callbacks *callbacks, options []Option) error {
|
||||
d, err := newWLDisplay()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -232,10 +234,14 @@ func newWLWindow(window *callbacks, options []Option) error {
|
||||
d.destroy()
|
||||
return err
|
||||
}
|
||||
w.w = window
|
||||
w.w = callbacks
|
||||
go func() {
|
||||
defer d.destroy()
|
||||
defer w.destroy()
|
||||
// Finish and commit setup from createNativeWindow.
|
||||
w.Configure(options)
|
||||
C.wl_surface_commit(w.surf)
|
||||
|
||||
w.w.SetDriver(w)
|
||||
if err := w.loop(); err != nil {
|
||||
panic(err)
|
||||
@@ -356,15 +362,12 @@ func (d *wlDisplay) createNativeWindow(options []Option) (*window, error) {
|
||||
C.xdg_surface_add_listener(w.wmSurf, &C.gio_xdg_surface_listener, unsafe.Pointer(w.surf))
|
||||
C.xdg_toplevel_add_listener(w.topLvl, &C.gio_xdg_toplevel_listener, unsafe.Pointer(w.surf))
|
||||
|
||||
w.Configure(options)
|
||||
|
||||
if d.decor != nil {
|
||||
// Request server side decorations.
|
||||
w.decor = C.zxdg_decoration_manager_v1_get_toplevel_decoration(d.decor, w.topLvl)
|
||||
C.zxdg_toplevel_decoration_v1_set_mode(w.decor, C.ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
|
||||
}
|
||||
w.updateOpaqueRegion()
|
||||
C.wl_surface_commit(w.surf)
|
||||
return w, nil
|
||||
}
|
||||
|
||||
@@ -487,8 +490,7 @@ func gio_onToplevelClose(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel) {
|
||||
func gio_onToplevelConfigure(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel, width, height C.int32_t, states *C.struct_wl_array) {
|
||||
w := callbackLoad(data).(*window)
|
||||
if width != 0 && height != 0 {
|
||||
w.config.Size.X = int(width)
|
||||
w.config.Size.Y = int(height)
|
||||
w.size = image.Pt(int(width), int(height))
|
||||
w.updateOpaqueRegion()
|
||||
}
|
||||
}
|
||||
@@ -855,7 +857,7 @@ func (w *window) flushFling() {
|
||||
w.fling.xExtrapolation = fling.Extrapolation{}
|
||||
w.fling.yExtrapolation = fling.Extrapolation{}
|
||||
vel := float32(math.Sqrt(float64(estx.Velocity*estx.Velocity + esty.Velocity*esty.Velocity)))
|
||||
_, _, c := w.getConfig()
|
||||
_, c := w.getConfig()
|
||||
if !w.fling.anim.Start(c, time.Now(), vel) {
|
||||
return
|
||||
}
|
||||
@@ -908,11 +910,12 @@ func (w *window) WriteClipboard(s string) {
|
||||
}
|
||||
|
||||
func (w *window) Configure(options []Option) {
|
||||
_, _, cfg := w.getConfig()
|
||||
_, cfg := w.getConfig()
|
||||
prev := w.config
|
||||
cnf := w.config
|
||||
cnf.apply(cfg, options)
|
||||
if prev.Size != cnf.Size {
|
||||
w.size = image.Pt(cnf.Size.X/w.scale, cnf.Size.Y/w.scale)
|
||||
w.config.Size = cnf.Size
|
||||
}
|
||||
if prev.Title != cnf.Title {
|
||||
@@ -921,10 +924,9 @@ func (w *window) Configure(options []Option) {
|
||||
C.xdg_toplevel_set_title(w.topLvl, title)
|
||||
C.free(unsafe.Pointer(title))
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) Config() Config {
|
||||
return w.config
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) Raise() {}
|
||||
@@ -1374,7 +1376,7 @@ func (w *window) onPointerMotion(x, y C.wl_fixed_t, t C.uint32_t) {
|
||||
|
||||
func (w *window) updateOpaqueRegion() {
|
||||
reg := C.wl_compositor_create_region(w.disp.compositor)
|
||||
C.wl_region_add(reg, 0, 0, C.int32_t(w.config.Size.X), C.int32_t(w.config.Size.Y))
|
||||
C.wl_region_add(reg, 0, 0, C.int32_t(w.size.X), C.int32_t(w.size.Y))
|
||||
C.wl_surface_set_opaque_region(w.surf, reg)
|
||||
C.wl_region_destroy(reg)
|
||||
}
|
||||
@@ -1404,9 +1406,9 @@ func (w *window) updateOutputs() {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) getConfig() (int, int, unit.Metric) {
|
||||
width, height := w.config.Size.X*w.scale, w.config.Size.Y*w.scale
|
||||
return width, height, unit.Metric{
|
||||
func (w *window) getConfig() (image.Point, unit.Metric) {
|
||||
size := w.size.Mul(w.scale)
|
||||
return size, unit.Metric{
|
||||
PxPerDp: w.ppdp * float32(w.scale),
|
||||
PxPerSp: w.ppsp * float32(w.scale),
|
||||
}
|
||||
@@ -1419,7 +1421,11 @@ func (w *window) draw(sync bool) {
|
||||
if dead || (!anim && !sync) {
|
||||
return
|
||||
}
|
||||
width, height, cfg := w.getConfig()
|
||||
size, cfg := w.getConfig()
|
||||
if size != w.config.Size {
|
||||
w.config.Size = size
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
if cfg == (unit.Metric{}) {
|
||||
return
|
||||
}
|
||||
@@ -1430,11 +1436,8 @@ func (w *window) draw(sync bool) {
|
||||
}
|
||||
w.w.Event(frameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Now: time.Now(),
|
||||
Size: image.Point{
|
||||
X: width,
|
||||
Y: height,
|
||||
},
|
||||
Now: time.Now(),
|
||||
Size: w.config.Size,
|
||||
Metric: cfg,
|
||||
},
|
||||
Sync: sync,
|
||||
@@ -1458,12 +1461,12 @@ func (w *window) surface() (*C.struct_wl_surface, int, int) {
|
||||
C.xdg_surface_ack_configure(w.wmSurf, w.serial)
|
||||
w.needAck = false
|
||||
}
|
||||
width, height, scale := w.config.Size.X, w.config.Size.Y, w.scale
|
||||
if w.newScale {
|
||||
C.wl_surface_set_buffer_scale(w.surf, C.int32_t(scale))
|
||||
C.wl_surface_set_buffer_scale(w.surf, C.int32_t(w.scale))
|
||||
w.newScale = false
|
||||
}
|
||||
return w.surf, width * scale, height * scale
|
||||
sz, _ := w.getConfig()
|
||||
return w.surf, sz.X, sz.Y
|
||||
}
|
||||
|
||||
func (w *window) ShowTextInput(show bool) {}
|
||||
|
||||
+13
-11
@@ -428,20 +428,23 @@ func (w *window) setStage(s system.Stage) {
|
||||
func (w *window) draw(sync bool) {
|
||||
var r windows.Rect
|
||||
windows.GetClientRect(w.hwnd, &r)
|
||||
w.config.Size.X = int(r.Right - r.Left)
|
||||
w.config.Size.Y = int(r.Bottom - r.Top)
|
||||
size := image.Point{
|
||||
X: int(r.Right - r.Left),
|
||||
Y: int(r.Bottom - r.Top),
|
||||
}
|
||||
if w.config.Size.X == 0 || w.config.Size.Y == 0 {
|
||||
return
|
||||
}
|
||||
if size != w.config.Size {
|
||||
w.config.Size = size
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
dpi := windows.GetWindowDPI(w.hwnd)
|
||||
cfg := configForDPI(dpi)
|
||||
w.w.Event(frameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Now: time.Now(),
|
||||
Size: image.Point{
|
||||
X: w.config.Size.X,
|
||||
Y: w.config.Size.Y,
|
||||
},
|
||||
Now: time.Now(),
|
||||
Size: w.config.Size,
|
||||
Metric: cfg,
|
||||
},
|
||||
Sync: sync,
|
||||
@@ -531,10 +534,9 @@ func (w *window) Configure(options []Option) {
|
||||
if prev.Mode != cnf.Mode {
|
||||
w.SetWindowMode(cnf.Mode)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) Config() Config {
|
||||
return w.config
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *window) SetWindowMode(mode WindowMode) {
|
||||
|
||||
+9
-10
@@ -161,10 +161,9 @@ func (w *x11Window) Configure(options []Option) {
|
||||
if prev.Mode != cnf.Mode {
|
||||
w.SetWindowMode(cnf.Mode)
|
||||
}
|
||||
}
|
||||
|
||||
func (w *x11Window) Config() Config {
|
||||
return w.config
|
||||
if w.config != prev {
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
}
|
||||
|
||||
func (w *x11Window) Raise() {
|
||||
@@ -355,11 +354,8 @@ loop:
|
||||
if (anim || syn) && w.config.Size.X != 0 && w.config.Size.Y != 0 {
|
||||
w.w.Event(frameEvent{
|
||||
FrameEvent: system.FrameEvent{
|
||||
Now: time.Now(),
|
||||
Size: image.Point{
|
||||
X: w.config.Size.X,
|
||||
Y: w.config.Size.Y,
|
||||
},
|
||||
Now: time.Now(),
|
||||
Size: w.config.Size,
|
||||
Metric: w.metric,
|
||||
},
|
||||
Sync: syn,
|
||||
@@ -516,7 +512,10 @@ func (h *x11EventHandler) handleEvents() bool {
|
||||
w.w.Event(key.FocusEvent{Focus: false})
|
||||
case C.ConfigureNotify: // window configuration change
|
||||
cevt := (*C.XConfigureEvent)(unsafe.Pointer(xev))
|
||||
w.config.Size = image.Pt(int(cevt.width), int(cevt.height))
|
||||
if sz := image.Pt(int(cevt.width), int(cevt.height)); sz != w.config.Size {
|
||||
w.config.Size = sz
|
||||
w.w.Event(ConfigEvent{Config: w.config})
|
||||
}
|
||||
// redraw will be done by a later expose event
|
||||
case C.SelectionNotify:
|
||||
cevt := (*C.XSelectionEvent)(unsafe.Pointer(xev))
|
||||
|
||||
@@ -263,17 +263,6 @@ func (w *Window) Option(opts ...Option) {
|
||||
})
|
||||
}
|
||||
|
||||
// Config returns the Window configuration.
|
||||
//
|
||||
// A FrameEvent will occur whenever the configuration changes.
|
||||
func (w *Window) Config() Config {
|
||||
var cnf Config
|
||||
w.driverRun(func(d driver) {
|
||||
cnf = d.Config()
|
||||
})
|
||||
return cnf
|
||||
}
|
||||
|
||||
// ReadClipboard initiates a read of the clipboard in the form
|
||||
// of a clipboard.Event. Multiple reads may be coalesced
|
||||
// to a single event.
|
||||
|
||||
Reference in New Issue
Block a user