Skip to main content

aeth_window/
window.rs

1use crate::access_winit_window::AccessWinitWindow;
2use aeth_event::{Pub, Sub, new_pubsub};
3use indexed_bitmap::IndexedBitmap;
4use std::cell::RefCell;
5use std::collections::HashMap;
6use std::rc::{Rc, Weak};
7use winit::event::WindowEvent;
8use winit::window::{Window as WinitWindow, WindowId};
9
10pub(crate) struct WindowInner {
11    window: Box<dyn WinitWindow>,
12    window_event_pub: Pub<WindowEvent>,
13    win_id: WindowId,
14    slot_id: Rc<RefCell<usize>>,
15}
16
17impl WindowInner {
18    pub(crate) fn window_event_pub(&self) -> Pub<WindowEvent> {
19        self.window_event_pub.clone()
20    }
21}
22
23pub(crate) struct Windows {
24    windows: Vec<WindowInner>,
25    lookup: HashMap<WindowId, Rc<RefCell<usize>>>,
26    refreshing: IndexedBitmap,
27}
28
29impl Windows {
30    pub(crate) fn new() -> Self {
31        Self {
32            windows: Vec::new(),
33            lookup: HashMap::new(),
34            refreshing: IndexedBitmap::new(),
35        }
36    }
37
38    fn unlink(&mut self, id: usize) {
39        let evicted_id = self.windows[id].win_id;
40        self.lookup.remove(&evicted_id);
41        self.refreshing.bitset(id, false);
42    }
43
44    pub(crate) fn evict(&mut self, id: usize) {
45        // Since this is called from a window holder,
46        // who allocates a window.
47        assert!(self.windows.len() > 0);
48        self.unlink(id);
49        let last_id = self.windows.len() - 1;
50        if id < last_id {
51            let win_id = self.windows[last_id].win_id;
52            let slot_id = self.windows[last_id].slot_id.clone();
53            let last_refreshing = self.refreshing.bitget(last_id);
54            self.unlink(last_id);
55            self.windows.swap(id, last_id);
56            *slot_id.borrow_mut() = id;
57            self.refreshing.bitset(id, last_refreshing);
58            self.lookup.insert(win_id, slot_id);
59        }
60        // The node to index has been swapped to the
61        // last item, ready to remove.
62        self.windows.pop();
63        if self.windows.len() * 2 < self.windows.capacity() {
64            self.windows.shrink_to_fit();
65            self.refreshing.shrink_to(self.windows.capacity());
66        }
67    }
68
69    fn set_refreshing(&mut self, id: usize, enable: bool) {
70        self.refreshing.bitset(id, enable);
71    }
72
73    fn broadcast_refresh_option(&self) -> Option<()> {
74        let mut id = self.refreshing.lowest_one()?;
75        loop {
76            self.windows[id].window.request_redraw();
77            id = self.refreshing.next_one(id)?;
78        }
79    }
80
81    pub(crate) fn broadcast_refresh(&self) {
82        self.broadcast_refresh_option();
83    }
84
85    pub(crate) fn allocate(rc: &Rc<RefCell<Self>>, window: Box<dyn WinitWindow>) -> Window {
86        let mut this = rc.borrow_mut();
87        let win_id = window.id();
88        let slot_id = this.windows.len();
89        let slot_id = Rc::new(RefCell::new(slot_id));
90        let (window_event_pub, window_event_sub) = new_pubsub();
91        this.windows.push(WindowInner {
92            window,
93            window_event_pub,
94            win_id,
95            slot_id: slot_id.clone(),
96        });
97        this.lookup.insert(win_id, slot_id.clone());
98        Window {
99            windows: Rc::downgrade(rc),
100            window_event_sub,
101            slot_id: slot_id,
102        }
103    }
104
105    pub(crate) fn find_inner_by_window_id(
106        &mut self,
107        window_id: WindowId,
108    ) -> Option<&mut WindowInner> {
109        let slot_id = *self.lookup.get(&window_id)?.borrow();
110        Some(&mut self.windows[slot_id])
111    }
112}
113
114/// Managed window handle.
115///
116/// Things like redrawing a window,
117/// accepting a user interaction, are
118/// passed by window events. A graphical
119/// program runs an event loop to poll
120/// these events and handles them.
121/// The window subsystem mediates the
122/// interaction between the event loop
123/// and async task process. When a
124/// window event happens, it will need
125/// to locate the window to deliver
126/// the window event. This is impossible
127/// without getting the windows managed.
128///
129/// Therefore, we need such an object.
130/// It's built on the top of an
131/// `winit::window::Window`, registered
132/// to the window subsystem and expose
133/// a subscriber `window_event_sub` for
134/// receiving window events dedicated
135/// to this window.
136pub struct Window {
137    windows: Weak<RefCell<Windows>>,
138    window_event_sub: Sub<WindowEvent>,
139    slot_id: Rc<RefCell<usize>>,
140}
141
142impl Drop for Window {
143    fn drop(&mut self) {
144        self.drop_option();
145    }
146}
147
148impl Window {
149    fn id(&self) -> usize {
150        *self.slot_id.borrow()
151    }
152
153    fn drop_option(&mut self) -> Option<()> {
154        let rc = self.windows.upgrade()?;
155        rc.borrow_mut().evict(self.id());
156        Some(())
157    }
158
159    fn must_upgrade_windows(&self) -> Rc<RefCell<Windows>> {
160        self.windows
161            .upgrade()
162            .expect("Windows dropped, maybe not inside valid window subsystem context")
163    }
164
165    /// Set the window as being refreshing or not.
166    ///
167    /// By setting this window as being refreshing,
168    /// every time the event loop is about to sleep,
169    /// a redraw event is going to be queued for
170    /// this window. This is required for video
171    /// applications and games.
172    pub fn set_refreshing(&mut self, enable: bool) {
173        let rc = self.must_upgrade_windows();
174        let mut windows = rc.borrow_mut();
175        windows.set_refreshing(self.id(), enable);
176    }
177
178    /// Check if the window is refreshing or not.
179    pub fn is_refreshing(&self) -> bool {
180        let rc = self.must_upgrade_windows();
181        let windows = rc.borrow_mut();
182        windows.refreshing.bitget(self.id())
183    }
184
185    /// Obtain the window event subscriber dedicated
186    /// to this window.
187    pub fn window_event_sub(&self) -> Sub<WindowEvent> {
188        self.window_event_sub.clone()
189    }
190}
191
192impl AccessWinitWindow for Window {
193    fn map_winit_window<F, T>(&self, f: F) -> T
194    where
195        F: FnOnce(&Box<dyn WinitWindow>) -> T,
196    {
197        let rc = self.must_upgrade_windows();
198        let windows = rc.borrow();
199        let window = &windows.windows[self.id()].window;
200        f(window)
201    }
202
203    fn map_winit_window_mut<F, T>(&mut self, f: F) -> T
204    where
205        F: FnOnce(&mut Box<dyn WinitWindow>) -> T,
206    {
207        // XXX: on the exclusive access to the &mut Windows,
208        // since this is executed no the foreground thread,
209        // the function is sync and returns immediately,
210        // and the mutable reference will be dropped shortly,
211        // it's okay to do so. Also we require the exclusive
212        // ownership of Window to perform exclusive operations
213        // on the winit window.
214        let rc = self.must_upgrade_windows();
215        let mut windows = rc.borrow_mut();
216        let window = &mut windows.windows[self.id()].window;
217        f(window)
218    }
219}