From 55c96adb913f97c546ed33901d0a49b05b1914de Mon Sep 17 00:00:00 2001 From: Chris Waldon Date: Fri, 17 Jun 2022 16:24:58 -0400 Subject: [PATCH] app: [Wayland] handle multiple global registry event orders Not all wayland compositors advertise the global registry events in the same order. In particular, river and sway differ in that sway advertises the data_device_manager before the seat, and river does it after. This commit updates our code to correctly bind the data_device so that we can work with the clipboard regardless of the registry event order. Special thanks to Isaac Freund (river maintainer) for helping me find the root of this problem. You can see Isaac's extremely helpful and detailed analysis here: https://github.com/riverwm/river/issues/554#issuecomment-1059750874 Signed-off-by: Chris Waldon --- app/os_wayland.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/os_wayland.go b/app/os_wayland.go index 696d7107..98d02b65 100644 --- a/app/os_wayland.go +++ b/app/os_wayland.go @@ -628,15 +628,7 @@ func gio_onRegistryGlobal(data unsafe.Pointer, reg *C.struct_wl_registry, name C } callbackStore(unsafe.Pointer(s), d.seat) C.wl_seat_add_listener(s, &C.gio_seat_listener, unsafe.Pointer(s)) - if d.dataDeviceManager == nil { - break - } - d.seat.dataDev = C.wl_data_device_manager_get_data_device(d.dataDeviceManager, s) - if d.seat.dataDev == nil { - break - } - callbackStore(unsafe.Pointer(d.seat.dataDev), d.seat) - C.wl_data_device_add_listener(d.seat.dataDev, &C.gio_data_device_listener, unsafe.Pointer(d.seat.dataDev)) + d.bindDataDevice() case "wl_shm": d.shm = (*C.struct_wl_shm)(C.wl_registry_bind(reg, name, &C.wl_shm_interface, 1)) case "xdg_wm_base": @@ -648,6 +640,7 @@ func gio_onRegistryGlobal(data unsafe.Pointer, reg *C.struct_wl_registry, name C d.imm = (*C.struct_zwp_text_input_manager_v3)(C.wl_registry_bind(reg, name, &C.zwp_text_input_manager_v3_interface, 1))*/ case "wl_data_device_manager": d.dataDeviceManager = (*C.struct_wl_data_device_manager)(C.wl_registry_bind(reg, name, &C.wl_data_device_manager_interface, 3)) + d.bindDataDevice() } } @@ -1303,6 +1296,19 @@ func (w *window) loop() error { return nil } +// bindDataDevice initializes the dataDev field if and only if both +// the seat and dataDeviceManager fields are initialized. +func (d *wlDisplay) bindDataDevice() { + if d.seat != nil && d.dataDeviceManager != nil { + d.seat.dataDev = C.wl_data_device_manager_get_data_device(d.dataDeviceManager, d.seat.seat) + if d.seat.dataDev == nil { + return + } + callbackStore(unsafe.Pointer(d.seat.dataDev), d.seat) + C.wl_data_device_add_listener(d.seat.dataDev, &C.gio_data_device_listener, unsafe.Pointer(d.seat.dataDev)) + } +} + func (d *wlDisplay) dispatch(p *poller) error { dispfd := C.wl_display_get_fd(d.disp) // Poll for events and notifications.