1use crate::{
2 image_cache::RenderImageParams, px, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
3 BorrowAppContext, Bounds, Context, Corners, DevicePixels, DisplayId, Effect, Element, EntityId,
4 FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId, MainThread, MainThreadOnly,
5 MonochromeSprite, Pixels, PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Reference,
6 RenderGlyphParams, RenderSvgParams, ScaledPixels, Scene, SharedString, Size, StackingOrder,
7 Style, TaffyLayoutEngine, Task, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
8};
9use anyhow::Result;
10use smallvec::SmallVec;
11use std::{any::TypeId, borrow::Cow, future::Future, marker::PhantomData, mem, sync::Arc};
12use util::ResultExt;
13
14pub struct AnyWindow {}
15
16pub struct Window {
17 handle: AnyWindowHandle,
18 platform_window: MainThreadOnly<Box<dyn PlatformWindow>>,
19 pub(crate) display_id: DisplayId, // todo!("make private again?")
20 sprite_atlas: Arc<dyn PlatformAtlas>,
21 rem_size: Pixels,
22 content_size: Size<Pixels>,
23 layout_engine: TaffyLayoutEngine,
24 pub(crate) root_view: Option<AnyView<()>>,
25 mouse_position: Point<Pixels>,
26 current_stacking_order: StackingOrder,
27 content_mask_stack: Vec<ContentMask>,
28 pub(crate) scene: Scene,
29 pub(crate) dirty: bool,
30}
31
32impl Window {
33 pub fn new(
34 handle: AnyWindowHandle,
35 options: WindowOptions,
36 cx: &mut MainThread<AppContext>,
37 ) -> Self {
38 let platform_window = cx.platform().open_window(handle, options);
39 let display_id = platform_window.display().id();
40 let sprite_atlas = platform_window.sprite_atlas();
41 let mouse_position = platform_window.mouse_position();
42 let content_size = platform_window.content_size();
43 let scale_factor = platform_window.scale_factor();
44 platform_window.on_resize(Box::new({
45 let handle = handle;
46 let cx = cx.to_async();
47 move |content_size, scale_factor| {
48 cx.update_window(handle, |cx| {
49 cx.window.scene = Scene::new(scale_factor);
50 cx.window.content_size = content_size;
51 cx.window.display_id = cx
52 .window
53 .platform_window
54 .borrow_on_main_thread()
55 .display()
56 .id();
57 cx.window.dirty = true;
58 })
59 .log_err();
60 }
61 }));
62
63 let platform_window = MainThreadOnly::new(Arc::new(platform_window), cx.executor.clone());
64
65 Window {
66 handle,
67 platform_window,
68 display_id,
69 sprite_atlas,
70 rem_size: px(16.),
71 content_size,
72 layout_engine: TaffyLayoutEngine::new(),
73 root_view: None,
74 mouse_position,
75 current_stacking_order: SmallVec::new(),
76 content_mask_stack: Vec::new(),
77 scene: Scene::new(scale_factor),
78 dirty: true,
79 }
80 }
81}
82
83#[derive(Clone, Debug)]
84pub struct ContentMask {
85 pub bounds: Bounds<Pixels>,
86}
87
88impl ContentMask {
89 pub fn scale(&self, factor: f32) -> ScaledContentMask {
90 ScaledContentMask {
91 bounds: self.bounds.scale(factor),
92 }
93 }
94
95 pub fn intersect(&self, other: &Self) -> Self {
96 let bounds = self.bounds.intersect(&other.bounds);
97 ContentMask { bounds }
98 }
99}
100
101#[derive(Default, Clone, Debug, PartialEq, Eq)]
102#[repr(C)]
103pub struct ScaledContentMask {
104 bounds: Bounds<ScaledPixels>,
105}
106
107pub struct WindowContext<'a, 'w> {
108 app: Reference<'a, AppContext>,
109 window: Reference<'w, Window>,
110}
111
112impl<'a, 'w> WindowContext<'a, 'w> {
113 pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
114 Self {
115 app: Reference::Mutable(app),
116 window: Reference::Mutable(window),
117 }
118 }
119
120 pub fn notify(&mut self) {
121 self.window.dirty = true;
122 }
123
124 pub fn run_on_main<R>(
125 &mut self,
126 f: impl FnOnce(&mut MainThread<WindowContext<'_, '_>>) -> R + Send + 'static,
127 ) -> Task<Result<R>>
128 where
129 R: Send + 'static,
130 {
131 if self.executor.is_main_thread() {
132 Task::ready(Ok(f(unsafe {
133 mem::transmute::<&mut Self, &mut MainThread<Self>>(self)
134 })))
135 } else {
136 let id = self.window.handle.id;
137 self.app.run_on_main(move |cx| cx.update_window(id, f))
138 }
139 }
140
141 pub fn to_async(&self) -> AsyncWindowContext {
142 AsyncWindowContext::new(self.app.to_async(), self.window.handle)
143 }
144
145 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut WindowContext) + Send + 'static) {
146 let f = Box::new(f);
147 let display_id = self.window.display_id;
148 let async_cx = self.to_async();
149 let app_cx = self.app_mut();
150 match app_cx.next_frame_callbacks.entry(display_id) {
151 collections::hash_map::Entry::Occupied(mut entry) => {
152 if entry.get().is_empty() {
153 app_cx.display_linker.start(display_id);
154 }
155 entry.get_mut().push(f);
156 }
157 collections::hash_map::Entry::Vacant(entry) => {
158 app_cx.display_linker.set_output_callback(
159 display_id,
160 Box::new(move |_current_time, _output_time| {
161 let _ = async_cx.update(|cx| {
162 let callbacks = cx
163 .next_frame_callbacks
164 .get_mut(&display_id)
165 .unwrap()
166 .drain(..)
167 .collect::<Vec<_>>();
168 for callback in callbacks {
169 callback(cx);
170 }
171
172 if cx.next_frame_callbacks.get(&display_id).unwrap().is_empty() {
173 cx.display_linker.stop(display_id);
174 }
175 });
176 }),
177 );
178 app_cx.display_linker.start(display_id);
179 entry.insert(vec![f]);
180 }
181 }
182 }
183
184 pub fn spawn<Fut, R>(
185 &mut self,
186 f: impl FnOnce(AnyWindowHandle, AsyncWindowContext) -> Fut + Send + 'static,
187 ) -> Task<R>
188 where
189 R: Send + 'static,
190 Fut: Future<Output = R> + Send + 'static,
191 {
192 let window = self.window.handle;
193 self.app.spawn(move |app| {
194 let cx = AsyncWindowContext::new(app, window);
195 let future = f(window, cx);
196 async move { future.await }
197 })
198 }
199
200 pub fn request_layout(
201 &mut self,
202 style: Style,
203 children: impl IntoIterator<Item = LayoutId>,
204 ) -> Result<LayoutId> {
205 self.app.layout_id_buffer.clear();
206 self.app.layout_id_buffer.extend(children.into_iter());
207 let rem_size = self.rem_size();
208
209 self.window
210 .layout_engine
211 .request_layout(style, rem_size, &self.app.layout_id_buffer)
212 }
213
214 pub fn request_measured_layout<
215 F: Fn(Size<Option<Pixels>>, Size<AvailableSpace>) -> Size<Pixels> + Send + Sync + 'static,
216 >(
217 &mut self,
218 style: Style,
219 rem_size: Pixels,
220 measure: F,
221 ) -> Result<LayoutId> {
222 self.window
223 .layout_engine
224 .request_measured_layout(style, rem_size, measure)
225 }
226
227 pub fn layout_bounds(&mut self, layout_id: LayoutId) -> Result<Bounds<Pixels>> {
228 Ok(self
229 .window
230 .layout_engine
231 .layout_bounds(layout_id)
232 .map(Into::into)?)
233 }
234
235 pub fn scale_factor(&self) -> f32 {
236 self.window.scene.scale_factor
237 }
238
239 pub fn rem_size(&self) -> Pixels {
240 self.window.rem_size
241 }
242
243 pub fn mouse_position(&self) -> Point<Pixels> {
244 self.window.mouse_position
245 }
246
247 pub fn scene(&mut self) -> &mut Scene {
248 &mut self.window.scene
249 }
250
251 pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
252 self.window.current_stacking_order.push(order);
253 let result = f(self);
254 self.window.current_stacking_order.pop();
255 result
256 }
257
258 pub fn current_stacking_order(&self) -> StackingOrder {
259 self.window.current_stacking_order.clone()
260 }
261
262 pub fn paint_glyph(
263 &mut self,
264 origin: Point<Pixels>,
265 font_id: FontId,
266 glyph_id: GlyphId,
267 font_size: Pixels,
268 color: Hsla,
269 ) -> Result<()> {
270 let scale_factor = self.scale_factor();
271 let glyph_origin = origin.scale(scale_factor);
272 let subpixel_variant = Point {
273 x: (glyph_origin.x.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
274 y: (glyph_origin.y.0.fract() * SUBPIXEL_VARIANTS as f32).floor() as u8,
275 };
276 let params = RenderGlyphParams {
277 font_id,
278 glyph_id,
279 font_size,
280 subpixel_variant,
281 scale_factor,
282 is_emoji: false,
283 };
284
285 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
286 if !raster_bounds.is_zero() {
287 let layer_id = self.current_stacking_order();
288 let tile =
289 self.window
290 .sprite_atlas
291 .get_or_insert_with(¶ms.clone().into(), &mut || {
292 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
293 Ok((size, Cow::Owned(bytes)))
294 })?;
295 let bounds = Bounds {
296 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
297 size: tile.bounds.size.map(Into::into),
298 };
299 let content_mask = self.content_mask().scale(scale_factor);
300
301 self.window.scene.insert(
302 layer_id,
303 MonochromeSprite {
304 order: 0,
305 bounds,
306 content_mask,
307 color,
308 tile,
309 },
310 );
311 }
312 Ok(())
313 }
314
315 pub fn paint_emoji(
316 &mut self,
317 origin: Point<Pixels>,
318 font_id: FontId,
319 glyph_id: GlyphId,
320 font_size: Pixels,
321 ) -> Result<()> {
322 let scale_factor = self.scale_factor();
323 let glyph_origin = origin.scale(scale_factor);
324 let params = RenderGlyphParams {
325 font_id,
326 glyph_id,
327 font_size,
328 // We don't render emojis with subpixel variants.
329 subpixel_variant: Default::default(),
330 scale_factor,
331 is_emoji: true,
332 };
333
334 let raster_bounds = self.text_system().raster_bounds(¶ms)?;
335 if !raster_bounds.is_zero() {
336 let layer_id = self.current_stacking_order();
337 let tile =
338 self.window
339 .sprite_atlas
340 .get_or_insert_with(¶ms.clone().into(), &mut || {
341 let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
342 Ok((size, Cow::Owned(bytes)))
343 })?;
344 let bounds = Bounds {
345 origin: glyph_origin.map(|px| px.floor()) + raster_bounds.origin.map(Into::into),
346 size: tile.bounds.size.map(Into::into),
347 };
348 let content_mask = self.content_mask().scale(scale_factor);
349
350 self.window.scene.insert(
351 layer_id,
352 PolychromeSprite {
353 order: 0,
354 bounds,
355 corner_radii: Default::default(),
356 content_mask,
357 tile,
358 grayscale: false,
359 },
360 );
361 }
362 Ok(())
363 }
364
365 pub fn paint_svg(
366 &mut self,
367 bounds: Bounds<Pixels>,
368 path: SharedString,
369 color: Hsla,
370 ) -> Result<()> {
371 let scale_factor = self.scale_factor();
372 let bounds = bounds.scale(scale_factor);
373 // Render the SVG at twice the size to get a higher quality result.
374 let params = RenderSvgParams {
375 path,
376 size: bounds
377 .size
378 .map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
379 };
380
381 let layer_id = self.current_stacking_order();
382 let tile =
383 self.window
384 .sprite_atlas
385 .get_or_insert_with(¶ms.clone().into(), &mut || {
386 let bytes = self.svg_renderer.render(¶ms)?;
387 Ok((params.size, Cow::Owned(bytes)))
388 })?;
389 let content_mask = self.content_mask().scale(scale_factor);
390
391 self.window.scene.insert(
392 layer_id,
393 MonochromeSprite {
394 order: 0,
395 bounds,
396 content_mask,
397 color,
398 tile,
399 },
400 );
401
402 Ok(())
403 }
404
405 pub fn paint_image(
406 &mut self,
407 bounds: Bounds<Pixels>,
408 corner_radii: Corners<Pixels>,
409 data: Arc<ImageData>,
410 grayscale: bool,
411 ) -> Result<()> {
412 let scale_factor = self.scale_factor();
413 let bounds = bounds.scale(scale_factor);
414 let params = RenderImageParams { image_id: data.id };
415
416 let order = self.current_stacking_order();
417 let tile = self
418 .window
419 .sprite_atlas
420 .get_or_insert_with(¶ms.clone().into(), &mut || {
421 Ok((data.size(), Cow::Borrowed(data.as_bytes())))
422 })?;
423 let content_mask = self.content_mask().scale(scale_factor);
424 let corner_radii = corner_radii.scale(scale_factor);
425
426 self.window.scene.insert(
427 order,
428 PolychromeSprite {
429 order: 0,
430 bounds,
431 content_mask,
432 corner_radii,
433 tile,
434 grayscale,
435 },
436 );
437
438 Ok(())
439 }
440
441 pub(crate) fn draw(&mut self) -> Result<()> {
442 let unit_entity = self.unit_entity.clone();
443 self.update_entity(&unit_entity, |view, cx| {
444 let mut root_view = cx.window.root_view.take().unwrap();
445 let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
446 let available_space = cx.window.content_size.map(Into::into);
447
448 cx.window
449 .layout_engine
450 .compute_layout(root_layout_id, available_space)?;
451 let layout = cx.window.layout_engine.layout_bounds(root_layout_id)?;
452
453 root_view.paint(layout, &mut (), &mut frame_state, cx)?;
454 cx.window.root_view = Some(root_view);
455 let scene = cx.window.scene.take();
456
457 cx.run_on_main(view, |_, cx| {
458 cx.window
459 .platform_window
460 .borrow_on_main_thread()
461 .draw(scene);
462 cx.window.dirty = false;
463 })
464 .detach();
465
466 Ok(())
467 })
468 }
469}
470
471impl Context for WindowContext<'_, '_> {
472 type EntityContext<'a, 'w, T: 'static + Send + Sync> = ViewContext<'a, 'w, T>;
473 type Result<T> = T;
474
475 fn entity<T: Send + Sync + 'static>(
476 &mut self,
477 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
478 ) -> Handle<T> {
479 let slot = self.app.entities.reserve();
480 let entity = build_entity(&mut ViewContext::mutable(
481 &mut *self.app,
482 &mut self.window,
483 slot.id,
484 ));
485 self.entities.insert(slot, entity)
486 }
487
488 fn update_entity<T: Send + Sync + 'static, R>(
489 &mut self,
490 handle: &Handle<T>,
491 update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
492 ) -> R {
493 let mut entity = self.entities.lease(handle);
494 let result = update(
495 &mut *entity,
496 &mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
497 );
498 self.entities.end_lease(entity);
499 result
500 }
501}
502
503impl<'a, 'w> std::ops::Deref for WindowContext<'a, 'w> {
504 type Target = AppContext;
505
506 fn deref(&self) -> &Self::Target {
507 &self.app
508 }
509}
510
511impl<'a, 'w> std::ops::DerefMut for WindowContext<'a, 'w> {
512 fn deref_mut(&mut self) -> &mut Self::Target {
513 &mut self.app
514 }
515}
516
517impl BorrowAppContext for WindowContext<'_, '_> {
518 fn app_mut(&mut self) -> &mut AppContext {
519 &mut *self.app
520 }
521}
522
523pub trait BorrowWindow: BorrowAppContext {
524 fn window(&self) -> &Window;
525 fn window_mut(&mut self) -> &mut Window;
526
527 fn with_content_mask<R>(&mut self, mask: ContentMask, f: impl FnOnce(&mut Self) -> R) -> R {
528 let mask = mask.intersect(&self.content_mask());
529 self.window_mut().content_mask_stack.push(mask);
530 let result = f(self);
531 self.window_mut().content_mask_stack.pop();
532 result
533 }
534
535 fn content_mask(&self) -> ContentMask {
536 self.window()
537 .content_mask_stack
538 .last()
539 .cloned()
540 .unwrap_or_else(|| ContentMask {
541 bounds: Bounds {
542 origin: Point::default(),
543 size: self.window().content_size,
544 },
545 })
546 }
547
548 fn rem_size(&self) -> Pixels {
549 self.window().rem_size
550 }
551}
552
553impl BorrowWindow for WindowContext<'_, '_> {
554 fn window(&self) -> &Window {
555 &*self.window
556 }
557
558 fn window_mut(&mut self) -> &mut Window {
559 &mut *self.window
560 }
561}
562
563pub struct ViewContext<'a, 'w, S> {
564 window_cx: WindowContext<'a, 'w>,
565 entity_type: PhantomData<S>,
566 entity_id: EntityId,
567}
568
569impl<S> BorrowAppContext for ViewContext<'_, '_, S> {
570 fn app_mut(&mut self) -> &mut AppContext {
571 &mut *self.window_cx.app
572 }
573
574 fn with_text_style<F, R>(&mut self, style: crate::TextStyleRefinement, f: F) -> R
575 where
576 F: FnOnce(&mut Self) -> R,
577 {
578 self.window_cx.app.push_text_style(style);
579 let result = f(self);
580 self.window_cx.app.pop_text_style();
581 result
582 }
583
584 fn with_state<T: Send + Sync + 'static, F, R>(&mut self, state: T, f: F) -> R
585 where
586 F: FnOnce(&mut Self) -> R,
587 {
588 self.window_cx.app.push_state(state);
589 let result = f(self);
590 self.window_cx.app.pop_state::<T>();
591 result
592 }
593}
594
595impl<S> BorrowWindow for ViewContext<'_, '_, S> {
596 fn window(&self) -> &Window {
597 &self.window_cx.window
598 }
599
600 fn window_mut(&mut self) -> &mut Window {
601 &mut *self.window_cx.window
602 }
603}
604
605impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
606 fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
607 Self {
608 window_cx: WindowContext::mutable(app, window),
609 entity_id,
610 entity_type: PhantomData,
611 }
612 }
613
614 pub fn handle(&self) -> WeakHandle<S> {
615 self.entities.weak_handle(self.entity_id)
616 }
617
618 pub fn stack<R>(&mut self, order: u32, f: impl FnOnce(&mut Self) -> R) -> R {
619 self.window.current_stacking_order.push(order);
620 let result = f(self);
621 self.window.current_stacking_order.pop();
622 result
623 }
624
625 pub fn on_next_frame(&mut self, f: impl FnOnce(&mut S, &mut ViewContext<S>) + Send + 'static) {
626 let entity = self.handle();
627 self.window_cx.on_next_frame(move |cx| {
628 entity.update(cx, f).ok();
629 });
630 }
631
632 pub fn observe<E: Send + Sync + 'static>(
633 &mut self,
634 handle: &Handle<E>,
635 on_notify: impl Fn(&mut S, Handle<E>, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static,
636 ) {
637 let this = self.handle();
638 let handle = handle.downgrade();
639 let window_handle = self.window.handle;
640 self.app
641 .observers
642 .entry(handle.id)
643 .or_default()
644 .push(Arc::new(move |cx| {
645 cx.update_window(window_handle.id, |cx| {
646 if let Some(handle) = handle.upgrade(cx) {
647 this.update(cx, |this, cx| on_notify(this, handle, cx))
648 .is_ok()
649 } else {
650 false
651 }
652 })
653 .unwrap_or(false)
654 }));
655 }
656
657 pub fn notify(&mut self) {
658 self.window_cx.notify();
659 self.window_cx
660 .app
661 .pending_effects
662 .push_back(Effect::Notify(self.entity_id));
663 }
664
665 pub fn run_on_main<R>(
666 &mut self,
667 view: &mut S,
668 f: impl FnOnce(&mut S, &mut MainThread<ViewContext<'_, '_, S>>) -> R + Send + 'static,
669 ) -> Task<Result<R>>
670 where
671 R: Send + 'static,
672 {
673 if self.executor.is_main_thread() {
674 let cx = unsafe { mem::transmute::<&mut Self, &mut MainThread<Self>>(self) };
675 Task::ready(Ok(f(view, cx)))
676 } else {
677 let handle = self.handle().upgrade(self).unwrap();
678 self.window_cx.run_on_main(move |cx| handle.update(cx, f))
679 }
680 }
681
682 pub fn spawn<Fut, R>(
683 &mut self,
684 f: impl FnOnce(WeakHandle<S>, AsyncWindowContext) -> Fut + Send + 'static,
685 ) -> Task<R>
686 where
687 R: Send + 'static,
688 Fut: Future<Output = R> + Send + 'static,
689 {
690 let handle = self.handle();
691 self.window_cx.spawn(move |_, cx| {
692 let result = f(handle, cx);
693 async move { result.await }
694 })
695 }
696
697 pub(crate) fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
698 let entity_id = self.unit_entity.id;
699 let mut cx = ViewContext::mutable(
700 &mut *self.window_cx.app,
701 &mut *self.window_cx.window,
702 entity_id,
703 );
704 f(&mut cx)
705 }
706}
707
708impl<'a, 'w, S> Context for ViewContext<'a, 'w, S> {
709 type EntityContext<'b, 'c, U: 'static + Send + Sync> = ViewContext<'b, 'c, U>;
710 type Result<U> = U;
711
712 fn entity<T2: Send + Sync + 'static>(
713 &mut self,
714 build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
715 ) -> Handle<T2> {
716 self.window_cx.entity(build_entity)
717 }
718
719 fn update_entity<U: Send + Sync + 'static, R>(
720 &mut self,
721 handle: &Handle<U>,
722 update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
723 ) -> R {
724 self.window_cx.update_entity(handle, update)
725 }
726}
727
728impl<'a, 'w, S: 'static> std::ops::Deref for ViewContext<'a, 'w, S> {
729 type Target = WindowContext<'a, 'w>;
730
731 fn deref(&self) -> &Self::Target {
732 &self.window_cx
733 }
734}
735
736impl<'a, 'w, S: 'static> std::ops::DerefMut for ViewContext<'a, 'w, S> {
737 fn deref_mut(&mut self) -> &mut Self::Target {
738 &mut self.window_cx
739 }
740}
741
742// #[derive(Clone, Copy, Eq, PartialEq, Hash)]
743slotmap::new_key_type! { pub struct WindowId; }
744
745#[derive(PartialEq, Eq)]
746pub struct WindowHandle<S> {
747 id: WindowId,
748 state_type: PhantomData<S>,
749}
750
751impl<S> Copy for WindowHandle<S> {}
752
753impl<S> Clone for WindowHandle<S> {
754 fn clone(&self) -> Self {
755 WindowHandle {
756 id: self.id,
757 state_type: PhantomData,
758 }
759 }
760}
761
762impl<S> WindowHandle<S> {
763 pub fn new(id: WindowId) -> Self {
764 WindowHandle {
765 id,
766 state_type: PhantomData,
767 }
768 }
769}
770
771impl<S: 'static> Into<AnyWindowHandle> for WindowHandle<S> {
772 fn into(self) -> AnyWindowHandle {
773 AnyWindowHandle {
774 id: self.id,
775 state_type: TypeId::of::<S>(),
776 }
777 }
778}
779
780#[derive(Copy, Clone, PartialEq, Eq)]
781pub struct AnyWindowHandle {
782 pub(crate) id: WindowId,
783 state_type: TypeId,
784}