fix(server): read the id libwayland allocates for server-created resources
- commit
- 72a807532e3358cfb95e9a2a116c7c318f62d1c8
- author
- brice · · 2026-09-27 16:34 UTC
- committer
- brice · · 2026-09-27 18:47 UTC
- parent
- f0a709a
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +29 -2
M server/display.go +4 -0
| @@ -226,6 +226,10 @@ func (c Client) CreateResource(iface *Interface, version int32, id uint32, h Han | |||
| 226 | 226 | if rc == 0 { | |
| 227 | 227 | return nil, fmt.Errorf("purego-libwayland: wl_resource_create(%s) failed", iface.Name) | |
| 228 | 228 | } | |
| 229 | + | // id 0 asks libwayland to allocate a server-side ID. | |
| 230 | + | if id == 0 { | |
| 231 | + | id = wlResourceGetID(rc) | |
| 232 | + | } | |
| 229 | 233 | r := &Resource{c: rc, id: id, version: version, client: c.c, iface: iface, handler: h} | |
| 230 | 234 | live.resources[rc] = r | |
| 231 | 235 | wlResourceSetDispatcher(rc, cbDispatcher, implMarker(), 0, cbDestroy) | |
| @@ -226,6 +226,10 @@ func (c Client) CreateResource(iface *Interface, version int32, id uint32, h Han | |||||
| 226 | if rc == 0 { | 226 | if rc == 0 { | ||
| 227 | return nil, fmt.Errorf("purego-libwayland: wl_resource_create(%s) failed", iface.Name) | 227 | return nil, fmt.Errorf("purego-libwayland: wl_resource_create(%s) failed", iface.Name) | ||
| 228 | } | 228 | } | ||
| 229 | + | // id 0 asks libwayland to allocate a server-side ID. | |||
| 230 | + | if id == 0 { | |||
| 231 | + | id = wlResourceGetID(rc) | |||
| 232 | + | } | |||
| 229 | r := &Resource{c: rc, id: id, version: version, client: c.c, iface: iface, handler: h} | 233 | r := &Resource{c: rc, id: id, version: version, client: c.c, iface: iface, handler: h} | ||
| 230 | live.resources[rc] = r | 234 | live.resources[rc] = r | ||
| 231 | wlResourceSetDispatcher(rc, cbDispatcher, implMarker(), 0, cbDestroy) | 235 | wlResourceSetDispatcher(rc, cbDispatcher, implMarker(), 0, cbDestroy) | ||
M server/hotpath_test.go +17 -0
| @@ -64,6 +64,23 @@ func hotDisplay(t testing.TB, iface *Interface, h Handler) (*Display, *Resource) | |||
| 64 | 64 | return d, hotResource(t, d, iface, h) | |
| 65 | 65 | } | |
| 66 | 66 | ||
| 67 | + | func TestServerAllocatedResourceID(t *testing.T) { | |
| 68 | + | iface := &Interface{Name: "server_allocated_id_test", Version: 1} | |
| 69 | + | d, existing := hotDisplay(t, iface, nil) | |
| 70 | + | if !d.Do(func() { | |
| 71 | + | r, err := (Client{existing.client}).CreateResource(iface, 1, 0, nil) | |
| 72 | + | if err != nil { | |
| 73 | + | t.Errorf("create server-side resource: %v", err) | |
| 74 | + | return | |
| 75 | + | } | |
| 76 | + | if r.ID() == 0 || r.ID() != wlResourceGetID(r.c) { | |
| 77 | + | t.Errorf("resource ID = %d, libwayland ID = %d", r.ID(), wlResourceGetID(r.c)) | |
| 78 | + | } | |
| 79 | + | }) { | |
| 80 | + | t.Fatal("display stopped") | |
| 81 | + | } | |
| 82 | + | } | |
| 83 | + | ||
| 67 | 84 | func requestMessage(iface *Interface) unsafe.Pointer { | |
| 68 | 85 | return *(*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(&tables.mem[0]), iface.c-tables.base+16)) | |
| 69 | 86 | } | |
| @@ -64,6 +64,23 @@ func hotDisplay(t testing.TB, iface *Interface, h Handler) (*Display, *Resource) | |||||
| 64 | return d, hotResource(t, d, iface, h) | 64 | return d, hotResource(t, d, iface, h) | ||
| 65 | } | 65 | } | ||
| 66 | 66 | ||||
| 67 | + | func TestServerAllocatedResourceID(t *testing.T) { | |||
| 68 | + | iface := &Interface{Name: "server_allocated_id_test", Version: 1} | |||
| 69 | + | d, existing := hotDisplay(t, iface, nil) | |||
| 70 | + | if !d.Do(func() { | |||
| 71 | + | r, err := (Client{existing.client}).CreateResource(iface, 1, 0, nil) | |||
| 72 | + | if err != nil { | |||
| 73 | + | t.Errorf("create server-side resource: %v", err) | |||
| 74 | + | return | |||
| 75 | + | } | |||
| 76 | + | if r.ID() == 0 || r.ID() != wlResourceGetID(r.c) { | |||
| 77 | + | t.Errorf("resource ID = %d, libwayland ID = %d", r.ID(), wlResourceGetID(r.c)) | |||
| 78 | + | } | |||
| 79 | + | }) { | |||
| 80 | + | t.Fatal("display stopped") | |||
| 81 | + | } | |||
| 82 | + | } | |||
| 83 | + | ||||
| 67 | func requestMessage(iface *Interface) unsafe.Pointer { | 84 | func requestMessage(iface *Interface) unsafe.Pointer { | ||
| 68 | return *(*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(&tables.mem[0]), iface.c-tables.base+16)) | 85 | return *(*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(&tables.mem[0]), iface.c-tables.base+16)) | ||
| 69 | } | 86 | } | ||
M server/lib.go +8 -2
| @@ -28,8 +28,8 @@ var ( | |||
| 28 | 28 | loadOnce sync.Once | |
| 29 | 29 | loadErr error | |
| 30 | 30 | ||
| 31 | - | symDisplayFlushClients, symEventLoopDispatch, symResourceCreate uintptr | |
| 32 | - | symResourceSetDispatcher, symResourcePostEventArr, symResourceDestroy uintptr | |
| 31 | + | symDisplayFlushClients, symEventLoopDispatch, symResourceCreate uintptr | |
| 32 | + | symResourceSetDispatcher, symResourcePostEventArr, symResourceDestroy, symResourceGetID uintptr | |
| 33 | 33 | ||
| 34 | 34 | // Shared C callbacks. purego callbacks are never freed, so there is one | |
| 35 | 35 | // of each for the whole process. | |
| @@ -71,6 +71,7 @@ func load() error { | |||
| 71 | 71 | {"wl_display_flush_clients", &symDisplayFlushClients}, | |
| 72 | 72 | {"wl_event_loop_dispatch", &symEventLoopDispatch}, | |
| 73 | 73 | {"wl_resource_create", &symResourceCreate}, | |
| 74 | + | {"wl_resource_get_id", &symResourceGetID}, | |
| 74 | 75 | {"wl_resource_set_dispatcher", &symResourceSetDispatcher}, | |
| 75 | 76 | {"wl_resource_post_event_array", &symResourcePostEventArr}, | |
| 76 | 77 | {"wl_resource_destroy", &symResourceDestroy}, | |
| @@ -109,6 +110,11 @@ func wlResourceCreate(client, iface uintptr, version int32, id uint32) uintptr { | |||
| 109 | 110 | r, _, _ := purego.SyscallN(symResourceCreate, callArgs[:4]...) | |
| 110 | 111 | return r | |
| 111 | 112 | } | |
| 113 | + | func wlResourceGetID(resource uintptr) uint32 { | |
| 114 | + | callArgs[0] = resource | |
| 115 | + | r, _, _ := purego.SyscallN(symResourceGetID, callArgs[:1]...) | |
| 116 | + | return uint32(r) | |
| 117 | + | } | |
| 112 | 118 | func wlResourceSetDispatcher(resource, dispatcher, impl, data, destroy uintptr) { | |
| 113 | 119 | callArgs[0], callArgs[1], callArgs[2], callArgs[3], callArgs[4] = resource, dispatcher, impl, data, destroy | |
| 114 | 120 | purego.SyscallN(symResourceSetDispatcher, callArgs[:5]...) | |
| @@ -28,8 +28,8 @@ var ( | |||||
| 28 | loadOnce sync.Once | 28 | loadOnce sync.Once | ||
| 29 | loadErr error | 29 | loadErr error | ||
| 30 | 30 | ||||
| 31 | - | symDisplayFlushClients, symEventLoopDispatch, symResourceCreate uintptr | 31 | + | symDisplayFlushClients, symEventLoopDispatch, symResourceCreate uintptr |
| 32 | - | symResourceSetDispatcher, symResourcePostEventArr, symResourceDestroy uintptr | 32 | + | symResourceSetDispatcher, symResourcePostEventArr, symResourceDestroy, symResourceGetID uintptr |
| 33 | 33 | ||||
| 34 | // Shared C callbacks. purego callbacks are never freed, so there is one | 34 | // Shared C callbacks. purego callbacks are never freed, so there is one | ||
| 35 | // of each for the whole process. | 35 | // of each for the whole process. | ||
| @@ -71,6 +71,7 @@ func load() error { | |||||
| 71 | {"wl_display_flush_clients", &symDisplayFlushClients}, | 71 | {"wl_display_flush_clients", &symDisplayFlushClients}, | ||
| 72 | {"wl_event_loop_dispatch", &symEventLoopDispatch}, | 72 | {"wl_event_loop_dispatch", &symEventLoopDispatch}, | ||
| 73 | {"wl_resource_create", &symResourceCreate}, | 73 | {"wl_resource_create", &symResourceCreate}, | ||
| 74 | + | {"wl_resource_get_id", &symResourceGetID}, | |||
| 74 | {"wl_resource_set_dispatcher", &symResourceSetDispatcher}, | 75 | {"wl_resource_set_dispatcher", &symResourceSetDispatcher}, | ||
| 75 | {"wl_resource_post_event_array", &symResourcePostEventArr}, | 76 | {"wl_resource_post_event_array", &symResourcePostEventArr}, | ||
| 76 | {"wl_resource_destroy", &symResourceDestroy}, | 77 | {"wl_resource_destroy", &symResourceDestroy}, | ||
| @@ -109,6 +110,11 @@ func wlResourceCreate(client, iface uintptr, version int32, id uint32) uintptr { | |||||
| 109 | r, _, _ := purego.SyscallN(symResourceCreate, callArgs[:4]...) | 110 | r, _, _ := purego.SyscallN(symResourceCreate, callArgs[:4]...) | ||
| 110 | return r | 111 | return r | ||
| 111 | } | 112 | } | ||
| 113 | + | func wlResourceGetID(resource uintptr) uint32 { | |||
| 114 | + | callArgs[0] = resource | |||
| 115 | + | r, _, _ := purego.SyscallN(symResourceGetID, callArgs[:1]...) | |||
| 116 | + | return uint32(r) | |||
| 117 | + | } | |||
| 112 | func wlResourceSetDispatcher(resource, dispatcher, impl, data, destroy uintptr) { | 118 | func wlResourceSetDispatcher(resource, dispatcher, impl, data, destroy uintptr) { | ||
| 113 | callArgs[0], callArgs[1], callArgs[2], callArgs[3], callArgs[4] = resource, dispatcher, impl, data, destroy | 119 | callArgs[0], callArgs[1], callArgs[2], callArgs[3], callArgs[4] = resource, dispatcher, impl, data, destroy | ||
| 114 | purego.SyscallN(symResourceSetDispatcher, callArgs[:5]...) | 120 | purego.SyscallN(symResourceSetDispatcher, callArgs[:5]...) | ||