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