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