1use raw_window_handle::{HasDisplayHandle, HasWindowHandle};
2use shared::channel_to_stream;
3use std::{fmt::Debug, future::Future, marker::PhantomData, pin::Pin, sync::Arc};
4use wasi_gfx::surface::surface;
5pub use wasi_gfx::surface::surface::{
6 FrameEvent, KeyEvent, PointerEvent, {CreateDesc as SurfaceDesc, ResizeEvent},
7};
8use wasmtime::component::{Access, HasData, Resource, StreamReader};
9
10wasmtime::component::bindgen!({
11 world: "wasi-gfx:surface/imports",
12 require_store_data_send: true,
13 imports: {
14 "wasi-gfx:surface/surface.[method]surface.on-pointer-down": store | trappable,
15 "wasi-gfx:surface/surface.[method]surface.on-pointer-move": store | trappable,
16 "wasi-gfx:surface/surface.[method]surface.on-key-up": store | trappable,
17 "wasi-gfx:surface/surface.[method]surface.on-pointer-up": store | trappable,
18 "wasi-gfx:surface/surface.[method]surface.on-key-down": store | trappable,
19 "wasi-gfx:surface/surface.[method]surface.on-resize": store | trappable,
20 "wasi-gfx:surface/surface.[method]surface.on-frame": store | trappable,
21 default: trappable,
22 },
23 with: {
24 "wasi-gfx:surface/surface.surface": Surface,
25 },
26});
27
28pub trait GfxWindow: HasDisplayHandle + HasWindowHandle {
32 fn height(&self) -> u32;
33 fn width(&self) -> u32;
34 fn request_set_size(&self, width: Option<u32>, height: Option<u32>);
35}
36
37#[derive(Clone, Debug)]
38pub struct Surface(Arc<SurfaceInner>);
39
40impl Surface {
41 pub fn new(window: Box<dyn GfxWindow + Send + Sync + 'static>) -> Self {
42 let (mut pointer_up_sender, pointer_up_receiver) = async_broadcast::broadcast(5);
43 let pointer_up_receiver = pointer_up_receiver.deactivate();
44 pointer_up_sender.set_overflow(true);
45 let (mut pointer_down_sender, pointer_down_receiver) = async_broadcast::broadcast(5);
46 let pointer_down_receiver = pointer_down_receiver.deactivate();
47 pointer_down_sender.set_overflow(true);
48 let (mut pointer_move_sender, pointer_move_receiver) = async_broadcast::broadcast(1);
49 let pointer_move_receiver = pointer_move_receiver.deactivate();
50 pointer_move_sender.set_overflow(true);
51 let (mut key_up_sender, key_up_receiver) = async_broadcast::broadcast(5);
52 let key_up_receiver = key_up_receiver.deactivate();
53 key_up_sender.set_overflow(true);
54 let (mut key_down_sender, key_down_receiver) = async_broadcast::broadcast(5);
55 let key_down_receiver = key_down_receiver.deactivate();
56 key_down_sender.set_overflow(true);
57 let (mut resize_sender, resize_receiver) = async_broadcast::broadcast(5);
58 let resize_receiver = resize_receiver.deactivate();
59 resize_sender.set_overflow(true);
60 let (mut frame_sender, frame_receiver) = async_broadcast::broadcast(1);
61 let frame_receiver = frame_receiver.deactivate();
62 frame_sender.set_overflow(true);
63 Surface(Arc::new(SurfaceInner {
64 window,
65 pointer_up_sender,
66 _pointer_up_receiver: pointer_up_receiver,
67 pointer_down_sender,
68 _pointer_down_receiver: pointer_down_receiver,
69 pointer_move_sender,
70 _pointer_move_receiver: pointer_move_receiver,
71 key_up_sender,
72 _key_up_receiver: key_up_receiver,
73 key_down_sender,
74 _key_down_receiver: key_down_receiver,
75 resize_sender,
76 _resize_receiver: resize_receiver,
77 frame_sender,
78 _frame_receiver: frame_receiver,
79 }))
80 }
81
82 pub fn height(&self) -> u32 {
83 self.0.window.height()
84 }
85
86 pub fn width(&self) -> u32 {
87 self.0.window.width()
88 }
89
90 pub fn request_set_size(&self, width: Option<u32>, height: Option<u32>) {
91 self.0.window.request_set_size(width, height);
92 }
93
94 pub fn arc_clone(&self) -> Self {
96 Surface(Arc::clone(&self.0))
97 }
98
99 pub fn pointer_up(&self, event: PointerEvent) {
100 shared::unwrap_unless_inactive(self.0.pointer_up_sender.try_broadcast(event));
101 }
102 pub fn pointer_down(&self, event: PointerEvent) {
103 shared::unwrap_unless_inactive(self.0.pointer_down_sender.try_broadcast(event));
104 }
105 pub fn pointer_move(&self, event: PointerEvent) {
106 shared::unwrap_unless_inactive_or_full(self.0.pointer_move_sender.try_broadcast(event));
107 }
108 pub fn key_up(&self, event: KeyEvent) {
109 shared::unwrap_unless_inactive(self.0.key_up_sender.try_broadcast(event));
110 }
111 pub fn key_down(&self, event: KeyEvent) {
112 shared::unwrap_unless_inactive(self.0.key_down_sender.try_broadcast(event));
113 }
114 pub fn canvas_resize(&self, event: ResizeEvent) {
115 shared::unwrap_unless_inactive(self.0.resize_sender.try_broadcast(event));
116 }
117 pub fn animation_frame(&self) {
118 shared::unwrap_unless_inactive_or_full(
119 self.0
120 .frame_sender
121 .try_broadcast(FrameEvent { nothing: true }),
122 );
123 }
124}
125
126impl HasDisplayHandle for Surface {
127 fn display_handle(
128 &self,
129 ) -> Result<raw_window_handle::DisplayHandle<'_>, raw_window_handle::HandleError> {
130 self.0.window.display_handle()
131 }
132}
133impl HasWindowHandle for Surface {
134 fn window_handle(
135 &self,
136 ) -> Result<raw_window_handle::WindowHandle<'_>, raw_window_handle::HandleError> {
137 self.0.window.window_handle()
138 }
139}
140
141struct SurfaceInner {
142 pub window: Box<dyn GfxWindow + Send + Sync + 'static>,
143
144 pointer_up_sender: async_broadcast::Sender<PointerEvent>,
147 _pointer_up_receiver: async_broadcast::InactiveReceiver<PointerEvent>,
148 pointer_down_sender: async_broadcast::Sender<PointerEvent>,
149 _pointer_down_receiver: async_broadcast::InactiveReceiver<PointerEvent>,
150 pointer_move_sender: async_broadcast::Sender<PointerEvent>,
151 _pointer_move_receiver: async_broadcast::InactiveReceiver<PointerEvent>,
152 key_up_sender: async_broadcast::Sender<KeyEvent>,
153 _key_up_receiver: async_broadcast::InactiveReceiver<KeyEvent>,
154 key_down_sender: async_broadcast::Sender<KeyEvent>,
155 _key_down_receiver: async_broadcast::InactiveReceiver<KeyEvent>,
156 resize_sender: async_broadcast::Sender<ResizeEvent>,
157 _resize_receiver: async_broadcast::InactiveReceiver<ResizeEvent>,
158 frame_sender: async_broadcast::Sender<FrameEvent>,
159 _frame_receiver: async_broadcast::InactiveReceiver<FrameEvent>,
160}
161
162impl Debug for SurfaceInner {
163 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164 f.debug_struct("Surface")
165 .field("window", &"<Boxed window>")
166 .field("pointer_up_sender", &self.pointer_up_sender)
167 .field("_pointer_up_receiver", &self._pointer_up_receiver)
168 .field("pointer_down_sender", &self.pointer_down_sender)
169 .field("_pointer_down_receiver", &self._pointer_down_receiver)
170 .field("pointer_move_sender", &self.pointer_move_sender)
171 .field("_pointer_move_receiver", &self._pointer_move_receiver)
172 .field("key_up_sender", &self.key_up_sender)
173 .field("_key_up_receiver", &self._key_up_receiver)
174 .field("key_down_sender", &self.key_down_sender)
175 .field("_key_down_receiver", &self._key_down_receiver)
176 .field("resize_sender", &self.resize_sender)
177 .field("_resize_receiver", &self._resize_receiver)
178 .field("frame_sender", &self.frame_sender)
179 .field("_frame_receiver", &self._frame_receiver)
180 .finish()
181 }
182}
183
184pub fn add_to_linker<T>(l: &mut wasmtime::component::Linker<T>) -> wasmtime::Result<()>
186where
187 T: SurfaceCtxView,
188{
189 wasi_gfx::surface::surface::add_to_linker::<_, HasSurfaceCtx<T::Spawner>>(l, T::surface_ctx)?;
190 Ok(())
191}
192
193pub trait SurfaceCtxView: Send {
194 type Spawner: MainThreadSpawner;
196 fn surface_ctx(&mut self) -> SurfaceCtx<'_, Self::Spawner>;
199}
200
201pub struct SurfaceCtx<'a, S: MainThreadSpawner> {
202 pub table: &'a mut wasmtime_wasi::ResourceTable,
203 pub main_thread_spawner: &'a S,
204}
205
206struct HasSurfaceCtx<S>(PhantomData<S>);
207
208impl<S: MainThreadSpawner> HasData for HasSurfaceCtx<S> {
209 type Data<'a> = SurfaceCtx<'a, S>;
210}
211
212pub trait MainThreadSpawner: Send + Sync + 'static {
215 fn spawn<F, T>(&self, f: F) -> impl Future<Output = T>
217 where
218 F: FnOnce() -> T + Send + 'static,
219 T: Send + 'static;
220
221 fn create_surface(&self, desc: SurfaceDesc) -> Pin<Box<dyn Future<Output = Surface> + Send>>;
223}
224
225impl<'a, S: MainThreadSpawner> surface::Host for SurfaceCtx<'a, S> {}
227
228impl<'a, S: MainThreadSpawner> surface::HostSurface for SurfaceCtx<'a, S> {
229 fn new(&mut self, desc: SurfaceDesc) -> wasmtime::Result<Resource<Surface>> {
230 let surface = futures::executor::block_on(self.main_thread_spawner.create_surface(desc));
231 Ok(self.table.push(surface)?)
232 }
233
234 fn height(&mut self, surface: Resource<Surface>) -> wasmtime::Result<u32> {
235 let surface = self.table.get(&surface)?;
236 Ok(surface.height())
237 }
238
239 fn width(&mut self, surface: Resource<Surface>) -> wasmtime::Result<u32> {
240 let surface = self.table.get(&surface)?;
241 Ok(surface.width())
242 }
243
244 fn request_set_size(
245 &mut self,
246 surface: Resource<Surface>,
247 width: Option<u32>,
248 height: Option<u32>,
249 ) -> wasmtime::Result<()> {
250 let surface = self.table.get(&surface)?;
251 surface.request_set_size(width, height);
252 Ok(())
253 }
254
255 fn drop(&mut self, surface: Resource<Surface>) -> wasmtime::Result<()> {
256 self.table.delete(surface)?;
257 Ok(())
258 }
259}
260
261impl<T, S: MainThreadSpawner> surface::HostSurfaceWithStore<T> for HasSurfaceCtx<S> {
262 fn on_pointer_down(
263 mut access: Access<T, Self>,
264 surface: Resource<surface::Surface>,
265 ) -> wasmtime::Result<StreamReader<PointerEvent>> {
266 let ctx = access.get();
267 let surface = ctx.table.get(&surface)?;
268 let receiver = surface.0.pointer_down_sender.new_receiver();
269 Ok(channel_to_stream(access, receiver))
270 }
271
272 fn on_pointer_move(
273 mut access: Access<T, Self>,
274 surface: Resource<surface::Surface>,
275 ) -> wasmtime::Result<StreamReader<PointerEvent>> {
276 let ctx = access.get();
277 let surface = ctx.table.get(&surface)?;
278 let receiver = surface.0.pointer_move_sender.new_receiver();
279 Ok(channel_to_stream(access, receiver))
280 }
281
282 fn on_pointer_up(
283 mut access: Access<T, Self>,
284 surface: Resource<surface::Surface>,
285 ) -> wasmtime::Result<StreamReader<PointerEvent>> {
286 let ctx = access.get();
287 let surface = ctx.table.get(&surface)?;
288 let receiver = surface.0.pointer_up_sender.new_receiver();
289 Ok(channel_to_stream(access, receiver))
290 }
291
292 fn on_key_up(
293 mut access: Access<T, Self>,
294 surface: Resource<surface::Surface>,
295 ) -> wasmtime::Result<StreamReader<KeyEvent>> {
296 let ctx = access.get();
297 let surface = ctx.table.get(&surface)?;
298 let receiver = surface.0.key_up_sender.new_receiver();
299 Ok(channel_to_stream(access, receiver))
300 }
301
302 fn on_key_down(
303 mut access: Access<T, Self>,
304 surface: Resource<surface::Surface>,
305 ) -> wasmtime::Result<StreamReader<KeyEvent>> {
306 let ctx = access.get();
307 let surface = ctx.table.get(&surface)?;
308 let receiver = surface.0.key_down_sender.new_receiver();
309 Ok(channel_to_stream(access, receiver))
310 }
311
312 fn on_resize(
313 mut access: Access<T, Self>,
314 surface: Resource<surface::Surface>,
315 ) -> wasmtime::Result<StreamReader<ResizeEvent>> {
316 let ctx = access.get();
317 let surface = ctx.table.get(&surface)?;
318 let receiver = surface.0.resize_sender.new_receiver();
319 Ok(channel_to_stream(access, receiver))
320 }
321
322 fn on_frame(
323 mut access: Access<T, Self>,
324 surface: Resource<surface::Surface>,
325 ) -> wasmtime::Result<StreamReader<FrameEvent>> {
326 let ctx = access.get();
327 let surface = ctx.table.get(&surface)?;
328 let receiver = surface.0.frame_sender.new_receiver();
329 Ok(channel_to_stream(access, receiver))
330 }
331}