feather_ui/component/
window.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: 2025 Fundament Research Institute <https://fundament.institute>
3
4use 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
36/// Holds our internal mutable state for this window
37pub struct WindowState {
38    pub surface: wgpu::Surface<'static>, // Ensure surface get dropped before window
39    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>, // Current clipping rectangle stack. These only get added to the GPU clip list if something is rotated
50    pub layers: Vec<std::sync::Weak<SourceID>>, // All layers that render directly to the final compositor
51}
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/// Represents an OS window. All outline functions must return a set of windows as a result of their evaluation,
204/// which represents all the windows that are currently open as part of the application. The ID of the window that
205/// a particular component belongs to is propagated down the outline evaluation phase, because this is needed to
206/// acquire window-specific information that depends on which monitor the OS thinks the window belongs to, like DPI
207/// or orientation.
208#[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            //let view_format = config.format.remove_srgb_suffix();
285            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            // This causes an unwanted flash, but makes it easier to capture the initial frame for debugging, so it's left here
317            // to be uncommented for debugging purposes
318            //let frame = windowstate.surface.get_current_texture()?;
319            //frame.present();
320
321            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                // Resize events can sometimes give empty sizes if the window is minimized
399                if new_size.height > 0 && new_size.width > 0 {
400                    Self::resize(new_size, window);
401                }
402                // On macos the window needs to be redrawn manually after resizing
403                window.window.request_redraw();
404                InputResult::Consume(())
405            }
406            WindowEvent::CloseRequested => {
407                // If this returns Reject(data), the close request will be ignored
408                InputResult::Consume(())
409            }
410            WindowEvent::RedrawRequested => {
411                panic!("Don't process this with on_window_event");
412            }
413            WindowEvent::Focused(acquired) => {
414                // When the window loses or gains focus, we send a focus event to our children that had
415                // focus, but we don't forget or change which children have focus.
416                let evt = RawEvent::Focus {
417                    acquired,
418                    window: window.window.clone(),
419                };
420
421                // We have to collect this map so we aren't borrowing manager twice
422                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(), // TODO: No way to derive originating keyboard from IME event????
441                        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 the cursor enters and no buttons are pressed, ensure any captured state is reset
497                        if window.all_buttons == 0 {
498                            // No need to inject a mousemove event here, as MouseOn is already being sent.
499                            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                        // We have to collect this map so we aren't borrowing manager twice
606                        let nodes: SmallVec<[Weak<Node>; 4]> = window.nodes(WindowNodeTrack::Focus);
607
608                        // Currently, we always duplicate key/joystick events to all focused elements. Later, we may map specific
609                        // keyboards to specific mouse input device IDs. We use a fold instead of any() to avoid short-circuiting.
610                        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                        // We have to collect this map so we aren't borrowing manager twice
634                        let nodes: SmallVec<[Weak<Node>; 4]> = window.drain(WindowNodeTrack::Hover);
635
636                        // Send a mouseoff event to all captures, but don't drain the captures so we have a chance to recover.
637                        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                        // While we could recover the offset here, we don't so we can be consistent about MouseOff not having offset.
653                        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                        // If everything rejected the mousemove, remove hover from all elements
736                        RawEvent::MouseMove {
737                            device_id,
738                            modifiers,
739                            all_buttons,
740                            ..
741                        } => {
742                            // We reborrow everything here or rust gets upset
743                            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                            // Drain() holds a reference, so we still have to collect these to avoid borrowing manager twice
754                            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                        // If everything rejected a mousedown, remove all focused elements
770                        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                            // We reborrow everything here or rust gets upset
786                            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                            // Drain() holds a reference, so we still have to collect these to avoid borrowing manager twice
796                            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                // After finishing all processing, if we were processing a mousemove or mouseon event, update our cursor
816                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}