From cf72e684b62dac59051d3022698c7b57b78c0e49 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 15 May 2020 16:25:00 +0200 Subject: [PATCH] app/internal/window: use a sync.Map for callback references Multiple Wayland windows are now separate, except for the global callback reference map. Use a sync.Map to support multiple concurrent windows. Signed-off-by: Elias Naur --- app/internal/window/os_wayland.go | 106 +++++++++++++++++------------- 1 file changed, 60 insertions(+), 46 deletions(-) diff --git a/app/internal/window/os_wayland.go b/app/internal/window/os_wayland.go index 2de443db..7adbc04d 100644 --- a/app/internal/window/os_wayland.go +++ b/app/internal/window/os_wayland.go @@ -159,13 +159,11 @@ type wlOutput struct { windows []*window } -var ( - // callbackMap maps Wayland native handles to corresponding Go - // references. It is necessary because the the Wayland client API - // forces the use of callbacks and storing pointers to Go values - // in C is forbidden. - callbackMap = make(map[unsafe.Pointer]interface{}) -) +// callbackMap maps Wayland native handles to corresponding Go +// references. It is necessary because the the Wayland client API +// forces the use of callbacks and storing pointers to Go values +// in C is forbidden. +var callbackMap sync.Map func init() { wlDriver = newWLWindow @@ -220,7 +218,7 @@ func (d *wlDisplay) createNativeWindow(opts *Options) (*window, error) { w.destroy() return nil, errors.New("wayland: wl_compositor_create_surface failed") } - callbackMap[unsafe.Pointer(w.surf)] = w + callbackStore(unsafe.Pointer(w.surf), w) w.wmSurf = C.xdg_wm_base_get_xdg_surface(d.wm, w.surf) if w.wmSurf == nil { w.destroy() @@ -252,9 +250,25 @@ func (d *wlDisplay) createNativeWindow(opts *Options) (*window, error) { return w, nil } +func callbackDelete(k unsafe.Pointer) { + callbackMap.Delete(k) +} + +func callbackStore(k unsafe.Pointer, v interface{}) { + callbackMap.Store(k, v) +} + +func callbackLoad(k unsafe.Pointer) interface{} { + v, exists := callbackMap.Load(k) + if !exists { + panic("missing callback entry") + } + return v +} + //export gio_onSeatCapabilities func gio_onSeatCapabilities(data unsafe.Pointer, seat *C.struct_wl_seat, caps C.uint32_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) s.updateCaps(caps) } @@ -273,7 +287,7 @@ func (s *wlSeat) destroy() { C.wl_keyboard_release(s.keyboard) } if s.seat != nil { - delete(callbackMap, unsafe.Pointer(s.seat)) + callbackDelete(unsafe.Pointer(s.seat)) C.wl_seat_release(s.seat) } } @@ -315,7 +329,7 @@ func gio_onSeatName(data unsafe.Pointer, seat *C.struct_wl_seat, name *C.char) { //export gio_onXdgSurfaceConfigure func gio_onXdgSurfaceConfigure(data unsafe.Pointer, wmSurf *C.struct_xdg_surface, serial C.uint32_t) { - w := callbackMap[data].(*window) + w := callbackLoad(data).(*window) w.mu.Lock() w.serial = serial w.needAck = true @@ -326,13 +340,13 @@ func gio_onXdgSurfaceConfigure(data unsafe.Pointer, wmSurf *C.struct_xdg_surface //export gio_onToplevelClose func gio_onToplevelClose(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel) { - w := callbackMap[data].(*window) + w := callbackLoad(data).(*window) w.dead = true } //export gio_onToplevelConfigure func gio_onToplevelConfigure(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel, width, height C.int32_t, states *C.struct_wl_array) { - w := callbackMap[data].(*window) + w := callbackLoad(data).(*window) if width != 0 && height != 0 { w.mu.Lock() defer w.mu.Unlock() @@ -347,7 +361,7 @@ func gio_onOutputMode(data unsafe.Pointer, output *C.struct_wl_output, flags C.u if flags&C.WL_OUTPUT_MODE_CURRENT == 0 { return } - d := callbackMap[data].(*wlDisplay) + d := callbackLoad(data).(*wlDisplay) c := d.outputConfig[output] c.width = int(width) c.height = int(height) @@ -355,7 +369,7 @@ func gio_onOutputMode(data unsafe.Pointer, output *C.struct_wl_output, flags C.u //export gio_onOutputGeometry func gio_onOutputGeometry(data unsafe.Pointer, output *C.struct_wl_output, x, y, physWidth, physHeight, subpixel C.int32_t, make, model *C.char, transform C.int32_t) { - d := callbackMap[data].(*wlDisplay) + d := callbackLoad(data).(*wlDisplay) c := d.outputConfig[output] c.transform = transform c.physWidth = int(physWidth) @@ -364,14 +378,14 @@ func gio_onOutputGeometry(data unsafe.Pointer, output *C.struct_wl_output, x, y, //export gio_onOutputScale func gio_onOutputScale(data unsafe.Pointer, output *C.struct_wl_output, scale C.int32_t) { - d := callbackMap[data].(*wlDisplay) + d := callbackLoad(data).(*wlDisplay) c := d.outputConfig[output] c.scale = int(scale) } //export gio_onOutputDone func gio_onOutputDone(data unsafe.Pointer, output *C.struct_wl_output) { - d := callbackMap[data].(*wlDisplay) + d := callbackLoad(data).(*wlDisplay) conf := d.outputConfig[output] for _, w := range conf.windows { w.draw(true) @@ -380,7 +394,7 @@ func gio_onOutputDone(data unsafe.Pointer, output *C.struct_wl_output) { //export gio_onSurfaceEnter func gio_onSurfaceEnter(data unsafe.Pointer, surf *C.struct_wl_surface, output *C.struct_wl_output) { - w := callbackMap[data].(*window) + w := callbackLoad(data).(*window) conf := w.disp.outputConfig[output] var found bool for _, w2 := range conf.windows { @@ -397,7 +411,7 @@ func gio_onSurfaceEnter(data unsafe.Pointer, surf *C.struct_wl_surface, output * //export gio_onSurfaceLeave func gio_onSurfaceLeave(data unsafe.Pointer, surf *C.struct_wl_surface, output *C.struct_wl_output) { - w := callbackMap[data].(*window) + w := callbackLoad(data).(*window) conf := w.disp.outputConfig[output] for i, w2 := range conf.windows { if w2 == w { @@ -410,7 +424,7 @@ func gio_onSurfaceLeave(data unsafe.Pointer, surf *C.struct_wl_surface, output * //export gio_onRegistryGlobal func gio_onRegistryGlobal(data unsafe.Pointer, reg *C.struct_wl_registry, name C.uint32_t, cintf *C.char, version C.uint32_t) { - d := callbackMap[data].(*wlDisplay) + d := callbackLoad(data).(*wlDisplay) switch C.GoString(cintf) { case "wl_compositor": d.compositor = (*C.struct_wl_compositor)(C.wl_registry_bind(reg, name, &C.wl_compositor_interface, 3)) @@ -427,7 +441,7 @@ func gio_onRegistryGlobal(data unsafe.Pointer, reg *C.struct_wl_registry, name C name: name, seat: s, } - callbackMap[unsafe.Pointer(s)] = d.seat + callbackStore(unsafe.Pointer(s), d.seat) C.gio_wl_seat_add_listener(d.seat.seat, unsafe.Pointer(d.seat.seat)) } case "wl_shm": @@ -444,7 +458,7 @@ func gio_onRegistryGlobal(data unsafe.Pointer, reg *C.struct_wl_registry, name C //export gio_onRegistryGlobalRemove func gio_onRegistryGlobalRemove(data unsafe.Pointer, reg *C.struct_wl_registry, name C.uint32_t) { - d := callbackMap[data].(*wlDisplay) + d := callbackLoad(data).(*wlDisplay) if s := d.seat; s != nil && name == s.name { s.destroy() d.seat = nil @@ -458,8 +472,8 @@ func gio_onRegistryGlobalRemove(data unsafe.Pointer, reg *C.struct_wl_registry, //export gio_onTouchDown func gio_onTouchDown(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.uint32_t, surf *C.struct_wl_surface, id C.int32_t, x, y C.wl_fixed_t) { - s := callbackMap[data].(*wlSeat) - w := callbackMap[unsafe.Pointer(surf)].(*window) + s := callbackLoad(data).(*wlSeat) + w := callbackLoad(unsafe.Pointer(surf)).(*window) s.touchFoci[id] = w w.lastTouch = f32.Point{ X: fromFixed(x) * float32(w.scale), @@ -476,7 +490,7 @@ func gio_onTouchDown(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C. //export gio_onTouchUp func gio_onTouchUp(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.uint32_t, id C.int32_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) w := s.touchFoci[id] delete(s.touchFoci, id) w.w.Event(pointer.Event{ @@ -490,7 +504,7 @@ func gio_onTouchUp(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.ui //export gio_onTouchMotion func gio_onTouchMotion(data unsafe.Pointer, touch *C.struct_wl_touch, t C.uint32_t, id C.int32_t, x, y C.wl_fixed_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) w := s.touchFoci[id] w.lastTouch = f32.Point{ X: fromFixed(x) * float32(w.scale), @@ -511,7 +525,7 @@ func gio_onTouchFrame(data unsafe.Pointer, touch *C.struct_wl_touch) { //export gio_onTouchCancel func gio_onTouchCancel(data unsafe.Pointer, touch *C.struct_wl_touch) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) for id, w := range s.touchFoci { delete(s.touchFoci, id) w.w.Event(pointer.Event{ @@ -523,8 +537,8 @@ func gio_onTouchCancel(data unsafe.Pointer, touch *C.struct_wl_touch) { //export gio_onPointerEnter func gio_onPointerEnter(data unsafe.Pointer, pointer *C.struct_wl_pointer, serial C.uint32_t, surf *C.struct_wl_surface, x, y C.wl_fixed_t) { - s := callbackMap[data].(*wlSeat) - w := callbackMap[unsafe.Pointer(surf)].(*window) + s := callbackLoad(data).(*wlSeat) + w := callbackLoad(unsafe.Pointer(surf)).(*window) s.pointerFocus = w // Get images[0]. img := *s.disp.cursor.cursor.images @@ -545,7 +559,7 @@ func gio_onPointerLeave(data unsafe.Pointer, p *C.struct_wl_pointer, serial C.ui //export gio_onPointerMotion func gio_onPointerMotion(data unsafe.Pointer, p *C.struct_wl_pointer, t C.uint32_t, x, y C.wl_fixed_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) w := s.pointerFocus w.resetFling() w.onPointerMotion(x, y, t) @@ -553,7 +567,7 @@ func gio_onPointerMotion(data unsafe.Pointer, p *C.struct_wl_pointer, t C.uint32 //export gio_onPointerButton func gio_onPointerButton(data unsafe.Pointer, p *C.struct_wl_pointer, serial, t, wbtn, state C.uint32_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) w := s.pointerFocus // From linux-event-codes.h. const ( @@ -594,7 +608,7 @@ func gio_onPointerButton(data unsafe.Pointer, p *C.struct_wl_pointer, serial, t, //export gio_onPointerAxis func gio_onPointerAxis(data unsafe.Pointer, p *C.struct_wl_pointer, t, axis C.uint32_t, value C.wl_fixed_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) w := s.pointerFocus v := fromFixed(value) w.resetFling() @@ -611,7 +625,7 @@ func gio_onPointerAxis(data unsafe.Pointer, p *C.struct_wl_pointer, t, axis C.ui //export gio_onPointerFrame func gio_onPointerFrame(data unsafe.Pointer, p *C.struct_wl_pointer) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) w := s.pointerFocus w.flushScroll() w.flushFling() @@ -643,14 +657,14 @@ func gio_onPointerAxisSource(data unsafe.Pointer, pointer *C.struct_wl_pointer, //export gio_onPointerAxisStop func gio_onPointerAxisStop(data unsafe.Pointer, p *C.struct_wl_pointer, t, axis C.uint32_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) w := s.pointerFocus w.fling.start = true } //export gio_onPointerAxisDiscrete func gio_onPointerAxisDiscrete(data unsafe.Pointer, p *C.struct_wl_pointer, axis C.uint32_t, discrete C.int32_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) w := s.pointerFocus w.resetFling() switch axis { @@ -669,7 +683,7 @@ func (w *window) resetFling() { //export gio_onKeyboardKeymap func gio_onKeyboardKeymap(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, format C.uint32_t, fd C.int32_t, size C.uint32_t) { defer syscall.Close(int(fd)) - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) s.disp.repeat.Stop(0) s.disp.xkb.DestroyKeymapState() if format != C.WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 { @@ -683,8 +697,8 @@ func gio_onKeyboardKeymap(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, f //export gio_onKeyboardEnter func gio_onKeyboardEnter(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial C.uint32_t, surf *C.struct_wl_surface, keys *C.struct_wl_array) { - s := callbackMap[data].(*wlSeat) - w := callbackMap[unsafe.Pointer(surf)].(*window) + s := callbackLoad(data).(*wlSeat) + w := callbackLoad(unsafe.Pointer(surf)).(*window) s.keyboardFocus = w s.disp.repeat.Stop(0) w.w.Event(key.FocusEvent{Focus: true}) @@ -692,7 +706,7 @@ func gio_onKeyboardEnter(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, se //export gio_onKeyboardLeave func gio_onKeyboardLeave(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial C.uint32_t, surf *C.struct_wl_surface) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) s.disp.repeat.Stop(0) w := s.keyboardFocus w.w.Event(key.FocusEvent{Focus: false}) @@ -700,7 +714,7 @@ func gio_onKeyboardLeave(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, se //export gio_onKeyboardKey func gio_onKeyboardKey(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial, timestamp, keyCode, state C.uint32_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) w := s.keyboardFocus t := time.Duration(timestamp) * time.Millisecond s.disp.repeat.Stop(t) @@ -797,7 +811,7 @@ func (r *repeatState) Repeat(d *wlDisplay) { //export gio_onFrameDone func gio_onFrameDone(data unsafe.Pointer, callback *C.struct_wl_callback, t C.uint32_t) { C.wl_callback_destroy(callback) - w := callbackMap[data].(*window) + w := callbackLoad(data).(*window) if w.lastFrameCallback == callback { w.lastFrameCallback = nil w.draw(false) @@ -902,12 +916,12 @@ func (w *window) destroy() { if w.decor != nil { C.zxdg_toplevel_decoration_v1_destroy(w.decor) } - delete(callbackMap, unsafe.Pointer(w.surf)) + callbackDelete(unsafe.Pointer(w.surf)) } //export gio_onKeyboardModifiers func gio_onKeyboardModifiers(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial, depressed, latched, locked, group C.uint32_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) d := s.disp d.repeat.Stop(0) if d.xkb == nil { @@ -918,7 +932,7 @@ func gio_onKeyboardModifiers(data unsafe.Pointer, keyboard *C.struct_wl_keyboard //export gio_onKeyboardRepeatInfo func gio_onKeyboardRepeatInfo(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, rate, delay C.int32_t) { - s := callbackMap[data].(*wlSeat) + s := callbackLoad(data).(*wlSeat) d := s.disp d.repeat.Stop(0) d.repeat.rate = int(rate) @@ -1134,7 +1148,7 @@ func newWLDisplay() (*wlDisplay, error) { d.destroy() return nil, fmt.Errorf("wayland: wl_display_connect failed: %v", err) } - callbackMap[unsafe.Pointer(d.disp)] = d + callbackMap.Store(unsafe.Pointer(d.disp), d) d.reg = C.wl_display_get_registry(d.disp) if d.reg == nil { d.destroy() @@ -1223,7 +1237,7 @@ func (d *wlDisplay) destroy() { } if d.disp != nil { C.wl_display_disconnect(d.disp) - delete(callbackMap, unsafe.Pointer(d.disp)) + callbackDelete(unsafe.Pointer(d.disp)) } }