window.rs

  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(&params)?;
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(&params.clone().into(), &mut || {
292                        let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
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(&params)?;
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(&params.clone().into(), &mut || {
341                        let (size, bytes) = self.text_system().rasterize_glyph(&params)?;
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(&params.clone().into(), &mut || {
386                    let bytes = self.svg_renderer.render(&params)?;
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(&params.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}