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
50                                        * to the GPU clip list if something is rotated */
51    pub layers: Vec<std::sync::Weak<SourceID>>, /* All layers that render directly to the final
52                                                 * compositor */
53}
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/// Represents an OS window. All outline functions must return a set of windows
206/// as a result of their evaluation, which represents all the windows that are
207/// currently open as part of the application. The ID of the window that
208/// a particular component belongs to is propagated down the outline evaluation
209/// phase, because this is needed to acquire window-specific information that
210/// depends on which monitor the OS thinks the window belongs to, like DPI
211/// or orientation.
212#[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            //let view_format = config.format.remove_srgb_suffix();
289            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            // This causes an unwanted flash, but makes it easier to capture the initial
321            // frame for debugging, so it's left here to be uncommented for
322            // debugging purposes let frame =
323            // windowstate.surface.get_current_texture()?; frame.present();
324
325            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                // Resize events can sometimes give empty sizes if the window is minimized
403                if new_size.height > 0 && new_size.width > 0 {
404                    Self::resize(new_size, window);
405                }
406                // On macos the window needs to be redrawn manually after resizing
407                window.window.request_redraw();
408                InputResult::Consume(())
409            }
410            WindowEvent::CloseRequested => {
411                // If this returns Reject(data), the close request will be ignored
412                InputResult::Consume(())
413            }
414            WindowEvent::RedrawRequested => {
415                panic!("Don't process this with on_window_event");
416            }
417            WindowEvent::Focused(acquired) => {
418                // When the window loses or gains focus, we send a focus event to our children
419                // that had focus, but we don't forget or change which children
420                // have focus.
421                let evt = RawEvent::Focus {
422                    acquired,
423                    window: window.window.clone(),
424                };
425
426                // We have to collect this map so we aren't borrowing manager twice
427                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(), /* TODO: No way to derive originating
446                                                       * keyboard from IME event???? */
447                        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 the cursor enters and no buttons are pressed, ensure any captured
503                        // state is reset
504                        if window.all_buttons == 0 {
505                            // No need to inject a mousemove event here, as MouseOn is already being
506                            // sent.
507                            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                        // We have to collect this map so we aren't borrowing manager twice
614                        let nodes: SmallVec<[Weak<Node>; 4]> = window.nodes(WindowNodeTrack::Focus);
615
616                        // Currently, we always duplicate key/joystick events to all focused
617                        // elements. Later, we may map specific keyboards to
618                        // specific mouse input device IDs. We use a fold instead of any() to avoid
619                        // short-circuiting.
620                        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                        // We have to collect this map so we aren't borrowing manager twice
644                        let nodes: SmallVec<[Weak<Node>; 4]> = window.drain(WindowNodeTrack::Hover);
645
646                        // Send a mouseoff event to all captures, but don't drain the captures so we
647                        // have a chance to recover.
648                        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                        // While we could recover the offset here, we don't so we can be consistent
664                        // about MouseOff not having offset.
665                        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                        // If everything rejected the mousemove, remove hover from all elements
748                        RawEvent::MouseMove {
749                            device_id,
750                            modifiers,
751                            all_buttons,
752                            ..
753                        } => {
754                            // We reborrow everything here or rust gets upset
755                            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                            // Drain() holds a reference, so we still have to collect these to avoid
766                            // borrowing manager twice
767                            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                        // If everything rejected a mousedown, remove all focused elements
783                        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                            // We reborrow everything here or rust gets upset
799                            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                            // Drain() holds a reference, so we still have to collect these to avoid
809                            // borrowing manager twice
810                            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                // After finishing all processing, if we were processing a mousemove or mouseon
830                // event, update our cursor
831                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}