feat(surface): expose the wl_surface proxy for extension requests
Surface.WLSurface returns the surface's wl_surface proxy so an application can pass it to a protocol extension it bound with Conn.Bind, such as a compositor-specific request that takes a surface argument. The Surface keeps ownership: the caller must not destroy, attach or commit it.
- commit
- 1b50de6b7dff970785bdd5d2e0a97a0e612d2946
- author
- brice · · 2026-10-02 03:33 UTC
- committer
- brice · · 2026-10-02 08:25 UTC
- parent
- 8e152d1
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
2 files · +18 -0
M surface.go +6 -0
| @@ -162,6 +162,12 @@ func (f *frameCallback) Dispatch(ev *wl.Event) { | |||
| 162 | 162 | // ID returns the surface's identifier used in Handler callbacks. | |
| 163 | 163 | func (s *Surface) ID() SurfaceID { return s.id } | |
| 164 | 164 | ||
| 165 | + | // WLSurface returns the wl_surface proxy, for requests of protocol extensions | |
| 166 | + | // bound with [Conn.Bind] that take a surface argument. It is valid until | |
| 167 | + | // [Surface.Close]. The Surface owns it: do not destroy it, attach buffers or | |
| 168 | + | // commit it. Owner goroutine only. | |
| 169 | + | func (s *Surface) WLSurface() *wayland.Surface { return s.surf } | |
| 170 | + | ||
| 165 | 171 | // Size returns the current logical size and scale (1 until announced). Before | |
| 166 | 172 | // the first configure the size is the requested one (zero for lock surfaces). | |
| 167 | 173 | func (s *Surface) Size() (w, h int32, scale float64) { return s.width, s.height, s.scale } | |
| @@ -162,6 +162,12 @@ func (f *frameCallback) Dispatch(ev *wl.Event) { | |||||
| 162 | // ID returns the surface's identifier used in Handler callbacks. | 162 | // ID returns the surface's identifier used in Handler callbacks. | ||
| 163 | func (s *Surface) ID() SurfaceID { return s.id } | 163 | func (s *Surface) ID() SurfaceID { return s.id } | ||
| 164 | 164 | ||||
| 165 | + | // WLSurface returns the wl_surface proxy, for requests of protocol extensions | |||
| 166 | + | // bound with [Conn.Bind] that take a surface argument. It is valid until | |||
| 167 | + | // [Surface.Close]. The Surface owns it: do not destroy it, attach buffers or | |||
| 168 | + | // commit it. Owner goroutine only. | |||
| 169 | + | func (s *Surface) WLSurface() *wayland.Surface { return s.surf } | |||
| 170 | + | ||||
| 165 | // Size returns the current logical size and scale (1 until announced). Before | 171 | // Size returns the current logical size and scale (1 until announced). Before | ||
| 166 | // the first configure the size is the requested one (zero for lock surfaces). | 172 | // the first configure the size is the requested one (zero for lock surfaces). | ||
| 167 | func (s *Surface) Size() (w, h int32, scale float64) { return s.width, s.height, s.scale } | 173 | func (s *Surface) Size() (w, h int32, scale float64) { return s.width, s.height, s.scale } | ||
M surface_wire_test.go +12 -0
| @@ -126,6 +126,18 @@ func TestSetInputRegionCommitsOnlyOnceMapped(t *testing.T) { | |||
| 126 | 126 | require.Error(t, ls.SetInputRegion(nil), "lock surfaces take all input") | |
| 127 | 127 | } | |
| 128 | 128 | ||
| 129 | + | // WLSurface is the surface's own wl_surface, on the connection's context, so | |
| 130 | + | // an extension bound with Conn.Bind can pass it as a request argument. | |
| 131 | + | func TestWLSurfaceIsTheSurfaceProxy(t *testing.T) { | |
| 132 | + | c, _ := connectWire(t, surfaceGlobals, surfaceOutputs) | |
| 133 | + | s, err := c.NewToplevel("wl", 64, 48) | |
| 134 | + | require.NoError(t, err) | |
| 135 | + | p := s.WLSurface() | |
| 136 | + | require.NotNil(t, p) | |
| 137 | + | require.Equal(t, s.SurfaceObjectID(), p.ID()) | |
| 138 | + | require.Same(t, c.Context(), p.Context()) | |
| 139 | + | } | |
| 140 | + | ||
| 129 | 141 | // GO-007: one lock surface per output. | |
| 130 | 142 | func TestLockRefusesSecondSurfacePerOutput(t *testing.T) { | |
| 131 | 143 | c, _ := connectWire(t, surfaceGlobals, surfaceOutputs) | |
| @@ -126,6 +126,18 @@ func TestSetInputRegionCommitsOnlyOnceMapped(t *testing.T) { | |||||
| 126 | require.Error(t, ls.SetInputRegion(nil), "lock surfaces take all input") | 126 | require.Error(t, ls.SetInputRegion(nil), "lock surfaces take all input") | ||
| 127 | } | 127 | } | ||
| 128 | 128 | ||||
| 129 | + | // WLSurface is the surface's own wl_surface, on the connection's context, so | |||
| 130 | + | // an extension bound with Conn.Bind can pass it as a request argument. | |||
| 131 | + | func TestWLSurfaceIsTheSurfaceProxy(t *testing.T) { | |||
| 132 | + | c, _ := connectWire(t, surfaceGlobals, surfaceOutputs) | |||
| 133 | + | s, err := c.NewToplevel("wl", 64, 48) | |||
| 134 | + | require.NoError(t, err) | |||
| 135 | + | p := s.WLSurface() | |||
| 136 | + | require.NotNil(t, p) | |||
| 137 | + | require.Equal(t, s.SurfaceObjectID(), p.ID()) | |||
| 138 | + | require.Same(t, c.Context(), p.Context()) | |||
| 139 | + | } | |||
| 140 | + | ||||
| 129 | // GO-007: one lock surface per output. | 141 | // GO-007: one lock surface per output. | ||
| 130 | func TestLockRefusesSecondSurfacePerOutput(t *testing.T) { | 142 | func TestLockRefusesSecondSurfacePerOutput(t *testing.T) { | ||
| 131 | c, _ := connectWire(t, surfaceGlobals, surfaceOutputs) | 143 | c, _ := connectWire(t, surfaceGlobals, surfaceOutputs) | ||