1use super::{Component, StateMachine};
5use crate::component::ComponentWrap;
6use crate::input::{ModifierKeys, MouseState, RawEvent};
7use crate::layout::root;
8use crate::render::compositor::Compositor;
9use crate::rtree::Node;
10use crate::{
11 InputResult, PxDim, PxPoint, PxVector, RelDim, RelVector, SourceID, StateMachineChild,
12 StateManager, graphics, layout, rtree,
13};
14use alloc::sync::Arc;
15use core::f32;
16use eyre::{OptionExt, Result};
17use guillotiere::euclid::default::Rotation3D;
18use guillotiere::euclid::{Point3D, Size2D};
19use smallvec::SmallVec;
20use std::collections::HashMap;
21use std::convert::Infallible;
22use std::rc::{Rc, Weak};
23use winit::dpi::{PhysicalPosition, PhysicalSize};
24use winit::event::{DeviceId, WindowEvent};
25use winit::event_loop::ActiveEventLoop;
26use winit::window::{CursorIcon, WindowAttributes};
27
28#[derive(Debug, Copy, Clone, PartialEq, Eq)]
29#[repr(u8)]
30pub(crate) enum WindowNodeTrack {
31 Focus = 0,
32 Hover = 1,
33 Capture = 2,
34}
35
36pub struct WindowState {
38 pub surface: wgpu::Surface<'static>, pub window: Arc<winit::window::Window>,
40 pub config: wgpu::SurfaceConfiguration,
41 all_buttons: u16,
42 modifiers: u8,
43 last_mouse: PhysicalPosition<f32>,
44 pub dpi: crate::RelDim,
45 pub driver: Arc<graphics::Driver>,
46 trackers: [HashMap<DeviceId, RcNode>; 3],
47 lookup: HashMap<(Arc<SourceID>, u8), DeviceId>,
48 pub compositor: Compositor,
49 pub clipstack: Vec<crate::PxRect>, pub layers: Vec<std::sync::Weak<SourceID>>, }
52
53impl super::EventRouter for WindowState {
54 type Input = Infallible;
55 type Output = Infallible;
56}
57
58const BACKCOLOR: wgpu::Color = wgpu::Color {
59 r: 0.1,
60 g: 0.2,
61 b: 0.3,
62 a: 1.0,
63};
64
65impl WindowState {
66 pub(crate) fn nodes(&self, tracker: WindowNodeTrack) -> SmallVec<[Weak<Node>; 4]> {
67 self.trackers[tracker as usize]
68 .values()
69 .map(|RcNode(_, node)| node.clone())
70 .collect()
71 }
72
73 pub(crate) fn drain(&mut self, tracker: WindowNodeTrack) -> SmallVec<[Weak<Node>; 4]> {
74 self.trackers[tracker as usize]
75 .drain()
76 .map(|(_, RcNode(id, v))| {
77 self.lookup.remove(&(id, tracker as u8));
78 v
79 })
80 .collect()
81 }
82
83 pub(crate) fn set(
84 &mut self,
85 tracker: WindowNodeTrack,
86 device_id: DeviceId,
87 id: Arc<SourceID>,
88 node: Weak<Node>,
89 ) -> Option<Weak<Node>> {
90 let n = self.trackers[tracker as usize]
91 .insert(device_id, RcNode(id.clone(), node))
92 .map(|RcNode(id, v)| {
93 self.lookup.remove(&(id, tracker as u8));
94 v
95 });
96
97 self.lookup.insert((id, tracker as u8), device_id);
98 n
99 }
100
101 pub(crate) fn remove(
102 &mut self,
103 tracker: WindowNodeTrack,
104 device_id: &DeviceId,
105 ) -> Option<Weak<Node>> {
106 self.trackers[tracker as usize]
107 .remove(device_id)
108 .map(|RcNode(id, v)| {
109 self.lookup.remove(&(id, tracker as u8));
110 v
111 })
112 }
113
114 pub(crate) fn get(&self, tracker: WindowNodeTrack, device_id: &DeviceId) -> Option<Weak<Node>> {
115 self.trackers[tracker as usize]
116 .get(device_id)
117 .map(|RcNode(_, v)| v.clone())
118 }
119
120 pub(crate) fn update_node(&mut self, id: Arc<SourceID>, node: Weak<Node>) {
121 for i in 0..self.trackers.len() {
122 if let Some(device) = self.lookup.get(&(id.clone(), i as u8))
123 && let Some(RcNode(_, n)) = self.trackers[i].get_mut(device)
124 {
125 *n = node.clone();
126 }
127 }
128 }
129
130 pub(crate) fn draw(&mut self, mut encoder: wgpu::CommandEncoder) {
131 let frame = self.surface.get_current_texture().unwrap();
132 let view = frame
133 .texture
134 .create_view(&wgpu::TextureViewDescriptor::default());
135
136 self.compositor
137 .prepare(&self.driver, &mut encoder, self.surface_dim().to_f32());
138
139 {
140 let mut backcolor = BACKCOLOR;
141 if frame.texture.format().is_srgb() {
142 backcolor.r = crate::color::srgb_to_linear(backcolor.r);
143 backcolor.g = crate::color::srgb_to_linear(backcolor.g);
144 backcolor.b = crate::color::srgb_to_linear(backcolor.b);
145 }
146
147 let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
148 label: Some("Window Pass"),
149 color_attachments: &[Some(wgpu::RenderPassColorAttachment {
150 view: &view,
151 resolve_target: None,
152 depth_slice: None,
153 ops: wgpu::Operations {
154 load: wgpu::LoadOp::Clear(backcolor),
155 store: wgpu::StoreOp::Store,
156 },
157 })],
158 depth_stencil_attachment: None,
159 timestamp_writes: None,
160 occlusion_query_set: None,
161 });
162
163 let viewport_dim = self.surface_dim().to_f32();
164 pass.set_viewport(0.0, 0.0, viewport_dim.width, viewport_dim.height, 0.0, 1.0);
165
166 self.compositor.draw(&self.driver, &mut pass, 0, 0);
167 self.compositor.cleanup();
168 }
169
170 self.driver.queue.submit(Some(encoder.finish()));
171 frame.present();
172 }
173
174 pub fn surface_dim(&self) -> Size2D<u32, crate::Pixel> {
175 Size2D::<u32, crate::Pixel>::new(self.config.width, self.config.height)
176 }
177}
178
179pub(crate) struct RcNode(Arc<SourceID>, pub(crate) Weak<Node>);
180
181impl PartialEq for RcNode {
182 fn eq(&self, other: &Self) -> bool {
183 self.0 == other.0
184 }
185}
186
187impl PartialEq for WindowState {
188 fn eq(&self, other: &Self) -> bool {
189 self.surface == other.surface
190 && Arc::ptr_eq(&self.window, &other.window)
191 && self.config == other.config
192 && self.all_buttons == other.all_buttons
193 && self.modifiers == other.modifiers
194 && self.last_mouse == other.last_mouse
195 && self.dpi == other.dpi
196 && Arc::ptr_eq(&self.driver, &other.driver)
197 && self.trackers == other.trackers
198 }
199}
200
201pub type WindowStateMachine = StateMachine<WindowState, 0>;
202
203#[derive(Clone)]
209pub struct Window {
210 pub id: Arc<SourceID>,
211 attributes: WindowAttributes,
212 child: Box<dyn ComponentWrap<<dyn root::Prop as crate::component::Desc>::Child>>,
213}
214
215impl Component for Window {
216 type Props = PxDim;
217
218 fn layout(
219 &self,
220 manager: &mut crate::StateManager,
221 _: &graphics::Driver,
222 _: &Arc<SourceID>,
223 ) -> Box<dyn crate::layout::Layout<PxDim>> {
224 use crate::Convert;
225
226 let inner = &manager.get::<WindowStateMachine>(&self.id).unwrap().state;
227 let size = inner.window.inner_size();
228 let driver = inner.driver.clone();
229 Box::new(layout::Node::<PxDim, dyn root::Prop> {
230 props: Rc::new(size.to().to_f32()),
231 children: self.child.layout(manager, &driver, &self.id),
232 id: Arc::downgrade(&self.id),
233 renderable: None,
234 layer: None,
235 })
236 }
237}
238
239impl StateMachineChild for Window {
240 fn init(
241 &self,
242 _: &std::sync::Weak<graphics::Driver>,
243 ) -> Result<Box<dyn super::StateMachineWrapper>, crate::Error> {
244 Err(crate::Error::UnhandledEvent)
245 }
246
247 fn apply_children(
248 &self,
249 f: &mut dyn FnMut(&dyn StateMachineChild) -> eyre::Result<()>,
250 ) -> eyre::Result<()> {
251 f(self.child.as_ref())
252 }
253
254 fn id(&self) -> Arc<SourceID> {
255 self.id.clone()
256 }
257}
258
259impl Window {
260 pub(crate) fn init_custom(
261 &self,
262 manager: &mut StateManager,
263 driver_ref: &mut std::sync::Weak<graphics::Driver>,
264 instance: &wgpu::Instance,
265 event_loop: &ActiveEventLoop,
266 on_driver: &mut Option<Box<dyn FnOnce(std::sync::Weak<graphics::Driver>) + 'static>>,
267 ) -> Result<()> {
268 if manager.get::<WindowStateMachine>(&self.id).is_err() {
269 let attributes = self.attributes.clone();
270
271 let window = Arc::new(event_loop.create_window(attributes)?);
272
273 let surface: wgpu::Surface<'static> = instance.create_surface(window.clone())?;
274
275 let driver = futures_lite::future::block_on(crate::graphics::Driver::new(
276 driver_ref, instance, &surface, on_driver,
277 ))?;
278
279 let size = window.inner_size();
280 let mut config = surface
281 .get_default_config(&driver.adapter, size.width, size.height)
282 .ok_or_eyre("Failed to find a default configuration")?;
283 let view_format = config.format.add_srgb_suffix();
284 config.format = view_format;
286 config.view_formats.push(view_format);
287 surface.configure(&driver.device, &config);
288
289 let compositor = Compositor::new(
290 &driver.device,
291 &driver.shared,
292 &driver.atlas.read().view,
293 &driver.layer_atlas[0].read().view,
294 config.view_formats[0],
295 false,
296 );
297
298 let mut windowstate = WindowState {
299 modifiers: 0,
300 all_buttons: 0,
301 last_mouse: PhysicalPosition::new(f32::NAN, f32::NAN),
302 config,
303 dpi: RelDim::splat(window.scale_factor() as f32),
304 surface,
305 window,
306 driver: driver.clone(),
307 trackers: Default::default(),
308 lookup: Default::default(),
309 compositor,
310 clipstack: Vec::new(),
311 layers: Vec::new(),
312 };
313
314 Window::resize(size, &mut windowstate);
315
316 manager.init(
322 self.id.clone(),
323 Box::new(StateMachine::<WindowState, 0> {
324 state: windowstate,
325 output: [],
326 input_mask: 0,
327 changed: false,
328 }),
329 );
330 }
331
332 manager.init_child(self.child.as_ref(), driver_ref)?;
333 Ok(())
334 }
335
336 pub fn new(
337 id: Arc<SourceID>,
338 attributes: WindowAttributes,
339 child: Box<dyn ComponentWrap<dyn crate::layout::base::Empty>>,
340 ) -> Self {
341 Self {
342 id,
343 attributes,
344 child,
345 }
346 }
347
348 fn resize(size: PhysicalSize<u32>, state: &mut WindowState) {
349 state.config.width = size.width;
350 state.config.height = size.height;
351 state.surface.configure(&state.driver.device, &state.config);
352 }
353
354 #[allow(clippy::result_unit_err)]
355 pub fn on_window_event(
356 id: Arc<SourceID>,
357 rtree: Weak<rtree::Node>,
358 event: WindowEvent,
359 manager: &mut StateManager,
360 driver: std::sync::Weak<graphics::Driver>,
361 ) -> InputResult<()> {
362 use crate::Convert;
363
364 let state = match manager.get_mut::<WindowStateMachine>(&id) {
365 Ok(s) => s,
366 Err(e) => return InputResult::Error(e),
367 };
368 let window = &mut state.state;
369 let dpi = window.dpi;
370 let inner = window.window.clone();
371 match event {
372 WindowEvent::ScaleFactorChanged { scale_factor, .. } => {
373 window.dpi = RelDim::splat(scale_factor as f32);
374 window.window.request_redraw();
375 InputResult::Consume(())
376 }
377 WindowEvent::ModifiersChanged(m) => {
378 window.modifiers = if m.state().control_key() {
379 ModifierKeys::Control as u8
380 } else {
381 0
382 } | if m.state().alt_key() {
383 ModifierKeys::Alt as u8
384 } else {
385 0
386 } | if m.state().shift_key() {
387 ModifierKeys::Shift as u8
388 } else {
389 0
390 } | if m.state().super_key() {
391 ModifierKeys::Super as u8
392 } else {
393 0
394 };
395 InputResult::Consume(())
396 }
397 WindowEvent::Resized(new_size) => {
398 if new_size.height > 0 && new_size.width > 0 {
400 Self::resize(new_size, window);
401 }
402 window.window.request_redraw();
404 InputResult::Consume(())
405 }
406 WindowEvent::CloseRequested => {
407 InputResult::Consume(())
409 }
410 WindowEvent::RedrawRequested => {
411 panic!("Don't process this with on_window_event");
412 }
413 WindowEvent::Focused(acquired) => {
414 let evt = RawEvent::Focus {
417 acquired,
418 window: window.window.clone(),
419 };
420
421 let nodes: SmallVec<[Weak<Node>; 4]> = window.nodes(WindowNodeTrack::Focus);
423
424 for node in nodes.iter().filter_map(|x| x.upgrade()) {
425 let _ = node.inject_event(
426 &evt,
427 evt.kind(),
428 dpi,
429 PxVector::zero(),
430 id.clone(),
431 &driver,
432 manager,
433 );
434 }
435 InputResult::Consume(())
436 }
437 _ => {
438 let e = match event {
439 WindowEvent::Ime(winit::event::Ime::Commit(s)) => RawEvent::Key {
440 device_id: DeviceId::dummy(), physical_key: winit::keyboard::PhysicalKey::Unidentified(
442 winit::keyboard::NativeKeyCode::Unidentified,
443 ),
444 location: winit::keyboard::KeyLocation::Standard,
445 down: false,
446 logical_key: winit::keyboard::Key::Character(s.into()),
447 modifiers: 0,
448 },
449 WindowEvent::KeyboardInput {
450 device_id,
451 event,
452 is_synthetic: _,
453 } => RawEvent::Key {
454 device_id,
455 physical_key: event.physical_key,
456 location: event.location,
457 down: event.state.is_pressed(),
458 logical_key: event.logical_key,
459 modifiers: window.modifiers
460 | if event.repeat {
461 ModifierKeys::Held as u8
462 } else {
463 0
464 },
465 },
466 WindowEvent::CursorMoved {
467 device_id,
468 position,
469 } => {
470 window.last_mouse =
471 PhysicalPosition::new(position.x as f32, position.y as f32);
472 RawEvent::MouseMove {
473 device_id,
474 pos: window.last_mouse.to(),
475 all_buttons: window.all_buttons,
476 modifiers: window.modifiers,
477 }
478 }
479 WindowEvent::CursorEntered { device_id } => {
480 #[cfg(windows)]
481 {
482 let points = {
483 let mut p = unsafe { std::mem::zeroed() };
484 unsafe {
485 windows_sys::Win32::UI::WindowsAndMessaging::GetCursorPos(
486 &mut p,
487 )
488 };
489 p
490 };
491
492 window.last_mouse =
493 PhysicalPosition::new(points.x as f32, points.y as f32);
494 }
495
496 if window.all_buttons == 0 {
498 window.remove(WindowNodeTrack::Capture, &device_id);
500 }
501 RawEvent::MouseOn {
502 device_id,
503 pos: window.last_mouse.to(),
504 all_buttons: window.all_buttons,
505 modifiers: window.modifiers,
506 }
507 }
508 WindowEvent::CursorLeft { device_id } => {
509 window.last_mouse = PhysicalPosition::new(f32::NAN, f32::NAN);
510 RawEvent::MouseOff {
511 device_id,
512 all_buttons: window.all_buttons,
513 modifiers: window.modifiers,
514 }
515 }
516 WindowEvent::MouseWheel {
517 device_id,
518 delta,
519 phase,
520 } => match delta {
521 winit::event::MouseScrollDelta::LineDelta(x, y) => RawEvent::MouseScroll {
522 device_id,
523 state: phase.into(),
524 pos: window.last_mouse.to(),
525 delta: Err(RelVector::new(x, y)),
526 },
527 winit::event::MouseScrollDelta::PixelDelta(physical_position) => {
528 RawEvent::MouseScroll {
529 device_id,
530 state: phase.into(),
531 pos: window.last_mouse.to(),
532 delta: Ok(physical_position.to().to_f32().to_vector()),
533 }
534 }
535 },
536 WindowEvent::MouseInput {
537 device_id,
538 state,
539 button,
540 } => {
541 let b = button.into();
542
543 if state == winit::event::ElementState::Pressed {
544 window.all_buttons |= b as u16;
545 } else {
546 window.all_buttons &= !(b as u16);
547 }
548
549 RawEvent::Mouse {
550 device_id,
551 state: if state == winit::event::ElementState::Pressed {
552 MouseState::Down
553 } else {
554 MouseState::Up
555 },
556 pos: window.last_mouse.to(),
557 button: b,
558 all_buttons: window.all_buttons,
559 modifiers: window.modifiers,
560 }
561 }
562 WindowEvent::AxisMotion {
563 device_id,
564 axis,
565 value,
566 } => RawEvent::JoyAxis {
567 device_id,
568 value,
569 axis,
570 },
571 WindowEvent::Touch(touch) => RawEvent::Touch {
572 device_id: touch.device_id,
573 state: touch.phase.into(),
574 pos: touch.location.to().to_f32().to_3d(),
575 index: touch.id as u32,
576 angle: Rotation3D::<f32>::identity(),
577 pressure: match touch.force {
578 Some(winit::event::Force::Normalized(x)) => x,
579 Some(winit::event::Force::Calibrated {
580 force,
581 max_possible_force: _,
582 altitude_angle: _,
583 }) => force,
584 None => 0.0,
585 },
586 },
587 _ => return InputResult::Forward(()),
588 };
589
590 match e {
591 RawEvent::MouseMove { .. } | RawEvent::MouseOn { .. } => {
592 if let Some(d) = driver.upgrade() {
593 *d.cursor.write() = CursorIcon::Default;
594 }
595 }
596 _ => (),
597 }
598 let r = match e {
599 RawEvent::Drag => InputResult::Forward(()),
600 RawEvent::Focus { .. } => InputResult::Forward(()),
601 RawEvent::JoyAxis { device_id: _, .. }
602 | RawEvent::JoyButton { device_id: _, .. }
603 | RawEvent::JoyOrientation { device_id: _, .. }
604 | RawEvent::Key { device_id: _, .. } => {
605 let nodes: SmallVec<[Weak<Node>; 4]> = window.nodes(WindowNodeTrack::Focus);
607
608 if nodes.iter().fold(false, |ok, node| {
611 ok | node
612 .upgrade()
613 .map(|n| {
614 n.inject_event(
615 &e,
616 e.kind(),
617 dpi,
618 PxVector::zero(),
619 id.clone(),
620 &driver,
621 manager,
622 )
623 .is_accept()
624 })
625 .unwrap_or(false)
626 }) {
627 InputResult::Consume(())
628 } else {
629 InputResult::Forward(())
630 }
631 }
632 RawEvent::MouseOff { .. } => {
633 let nodes: SmallVec<[Weak<Node>; 4]> = window.drain(WindowNodeTrack::Hover);
635
636 let capture_nodes: SmallVec<[Weak<Node>; 4]> =
638 window.nodes(WindowNodeTrack::Capture);
639
640 for node in nodes.iter().filter_map(|x| x.upgrade()) {
641 let _ = node.inject_event(
642 &e,
643 e.kind(),
644 dpi,
645 PxVector::zero(),
646 id.clone(),
647 &driver,
648 manager,
649 );
650 }
651
652 for node in capture_nodes.iter().filter_map(|x| x.upgrade()) {
654 let _ = node.inject_event(
655 &e,
656 e.kind(),
657 dpi,
658 PxVector::zero(),
659 id.clone(),
660 &driver,
661 manager,
662 );
663 }
664
665 InputResult::Consume(())
666 }
667 RawEvent::Mouse {
668 device_id,
669 pos: PxPoint { x, y, .. },
670 ..
671 }
672 | RawEvent::MouseOn {
673 device_id,
674 pos: PxPoint { x, y, .. },
675 ..
676 }
677 | RawEvent::MouseMove {
678 device_id,
679 pos: PxPoint { x, y, .. },
680 ..
681 }
682 | RawEvent::Drop {
683 device_id,
684 pos: PhysicalPosition { x, y },
685 ..
686 }
687 | RawEvent::MouseScroll {
688 device_id,
689 pos: PxPoint { x, y, .. },
690 ..
691 }
692 | RawEvent::Touch {
693 device_id,
694 pos: Point3D::<f32, crate::Pixel> { x, y, .. },
695 ..
696 } => {
697 if let Some(node) = window
698 .get(WindowNodeTrack::Capture, &device_id)
699 .and_then(|x| x.upgrade())
700 {
701 let offset = Node::offset(node.clone());
702 return node
703 .clone()
704 .inject_event(
705 &e,
706 e.kind(),
707 dpi,
708 offset,
709 id.clone(),
710 &driver,
711 manager,
712 )
713 .map(|_| ());
714 }
715
716 if let Some(rt) = rtree.upgrade() {
717 rt.process(
718 &e,
719 e.kind(),
720 PxPoint::new(x, y),
721 PxVector::zero(),
722 dpi,
723 &driver,
724 manager,
725 id.clone(),
726 )
727 } else {
728 InputResult::Forward(())
729 }
730 }
731 };
732
733 if r.is_err() {
734 match e {
735 RawEvent::MouseMove {
737 device_id,
738 modifiers,
739 all_buttons,
740 ..
741 } => {
742 let state = match manager.get_mut::<WindowStateMachine>(&id) {
744 Ok(s) => s,
745 Err(e) => return InputResult::Error(e),
746 };
747 let evt = RawEvent::MouseOff {
748 device_id,
749 modifiers,
750 all_buttons,
751 };
752
753 let nodes: SmallVec<[Weak<Node>; 4]> =
755 state.state.drain(WindowNodeTrack::Hover);
756
757 for node in nodes.iter().filter_map(|x| x.upgrade()) {
758 let _ = node.inject_event(
759 &evt,
760 evt.kind(),
761 dpi,
762 PxVector::zero(),
763 id.clone(),
764 &driver,
765 manager,
766 );
767 }
768 }
769 RawEvent::Mouse {
771 state: MouseState::Down,
772 button: crate::input::MouseButton::Left,
773 ..
774 }
775 | RawEvent::Mouse {
776 state: MouseState::Down,
777 button: crate::input::MouseButton::Middle,
778 ..
779 }
780 | RawEvent::Mouse {
781 state: MouseState::Down,
782 button: crate::input::MouseButton::Right,
783 ..
784 } => {
785 let state = match manager.get_mut::<WindowStateMachine>(&id) {
787 Ok(s) => s,
788 Err(e) => return InputResult::Error(e),
789 };
790 let evt = RawEvent::Focus {
791 acquired: false,
792 window: state.state.window.clone(),
793 };
794
795 let nodes: SmallVec<[Weak<Node>; 4]> =
797 state.state.drain(WindowNodeTrack::Focus);
798
799 for node in nodes.iter().filter_map(|x| x.upgrade()) {
800 let _ = node.inject_event(
801 &evt,
802 evt.kind(),
803 dpi,
804 PxVector::zero(),
805 id.clone(),
806 &driver,
807 manager,
808 );
809 }
810 }
811 _ => (),
812 }
813 }
814
815 match e {
817 RawEvent::MouseMove { .. } | RawEvent::MouseOn { .. } => {
818 if let Some(d) = driver.upgrade() {
819 inner.set_cursor(*d.cursor.read());
820 }
821 }
822 _ => (),
823 }
824 r
825 }
826 }
827 }
828}