window.rs

  1use std::any::Any;
  2use std::ffi::c_void;
  3use std::rc::Rc;
  4use std::sync::Arc;
  5
  6use blade_graphics as gpu;
  7use blade_rwh::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle};
  8use futures::channel::oneshot::Receiver;
  9use parking_lot::Mutex;
 10use raw_window_handle::{
 11    DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, WindowHandle,
 12};
 13use wayland_client::{protocol::wl_surface, Proxy};
 14use wayland_protocols::xdg::shell::client::xdg_toplevel;
 15
 16use crate::platform::linux::blade_renderer::BladeRenderer;
 17use crate::platform::linux::wayland::display::WaylandDisplay;
 18use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow};
 19use crate::scene::Scene;
 20use crate::{
 21    px, Bounds, Modifiers, Pixels, PlatformDisplay, PlatformInput, Point, PromptLevel, Size,
 22    WindowAppearance, WindowBounds, WindowOptions,
 23};
 24
 25#[derive(Default)]
 26pub(crate) struct Callbacks {
 27    request_frame: Option<Box<dyn FnMut()>>,
 28    input: Option<Box<dyn FnMut(crate::PlatformInput) -> bool>>,
 29    active_status_change: Option<Box<dyn FnMut(bool)>>,
 30    resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
 31    fullscreen: Option<Box<dyn FnMut(bool)>>,
 32    moved: Option<Box<dyn FnMut()>>,
 33    should_close: Option<Box<dyn FnMut() -> bool>>,
 34    close: Option<Box<dyn FnOnce()>>,
 35    appearance_changed: Option<Box<dyn FnMut()>>,
 36}
 37
 38struct WaylandWindowInner {
 39    renderer: BladeRenderer,
 40    bounds: Bounds<i32>,
 41}
 42
 43struct RawWindow {
 44    window: *mut c_void,
 45    display: *mut c_void,
 46}
 47
 48unsafe impl HasRawWindowHandle for RawWindow {
 49    fn raw_window_handle(&self) -> RawWindowHandle {
 50        let mut wh = blade_rwh::WaylandWindowHandle::empty();
 51        wh.surface = self.window;
 52        wh.into()
 53    }
 54}
 55
 56unsafe impl HasRawDisplayHandle for RawWindow {
 57    fn raw_display_handle(&self) -> RawDisplayHandle {
 58        let mut dh = blade_rwh::WaylandDisplayHandle::empty();
 59        dh.display = self.display;
 60        dh.into()
 61    }
 62}
 63
 64impl WaylandWindowInner {
 65    fn new(
 66        conn: &Arc<wayland_client::Connection>,
 67        wl_surf: &Arc<wl_surface::WlSurface>,
 68        bounds: Bounds<i32>,
 69    ) -> Self {
 70        let raw = RawWindow {
 71            window: wl_surf.id().as_ptr() as *mut _,
 72            display: conn.backend().display_ptr() as *mut _,
 73        };
 74        let gpu = Arc::new(
 75            unsafe {
 76                gpu::Context::init_windowed(
 77                    &raw,
 78                    gpu::ContextDesc {
 79                        validation: false,
 80                        capture: false,
 81                    },
 82                )
 83            }
 84            .unwrap(),
 85        );
 86        let extent = gpu::Extent {
 87            width: bounds.size.width as u32,
 88            height: bounds.size.height as u32,
 89            depth: 1,
 90        };
 91        Self {
 92            renderer: BladeRenderer::new(gpu, extent),
 93            bounds,
 94        }
 95    }
 96}
 97
 98pub(crate) struct WaylandWindowState {
 99    conn: Arc<wayland_client::Connection>,
100    inner: Mutex<WaylandWindowInner>,
101    pub(crate) callbacks: Mutex<Callbacks>,
102    pub(crate) surface: Arc<wl_surface::WlSurface>,
103    pub(crate) toplevel: Arc<xdg_toplevel::XdgToplevel>,
104}
105
106impl WaylandWindowState {
107    pub(crate) fn new(
108        conn: &Arc<wayland_client::Connection>,
109        wl_surf: Arc<wl_surface::WlSurface>,
110        toplevel: Arc<xdg_toplevel::XdgToplevel>,
111        options: WindowOptions,
112    ) -> Self {
113        if options.bounds == WindowBounds::Maximized {
114            toplevel.set_maximized();
115        } else if options.bounds == WindowBounds::Fullscreen {
116            toplevel.set_fullscreen(None);
117        }
118
119        let bounds: Bounds<i32> = match options.bounds {
120            WindowBounds::Fullscreen | WindowBounds::Maximized => Bounds {
121                origin: Point::default(),
122                size: Size {
123                    width: 500,
124                    height: 500,
125                }, //todo!(implement)
126            },
127            WindowBounds::Fixed(bounds) => bounds.map(|p| p.0 as i32),
128        };
129
130        Self {
131            conn: Arc::clone(conn),
132            surface: Arc::clone(&wl_surf),
133            inner: Mutex::new(WaylandWindowInner::new(&Arc::clone(conn), &wl_surf, bounds)),
134            callbacks: Mutex::new(Callbacks::default()),
135            toplevel,
136        }
137    }
138
139    pub fn update(&self) {
140        let mut cb = self.callbacks.lock();
141        if let Some(mut fun) = cb.request_frame.take() {
142            drop(cb);
143            fun();
144            self.callbacks.lock().request_frame = Some(fun);
145        }
146    }
147
148    pub fn resize(&self, width: i32, height: i32) {
149        {
150            let mut inner = self.inner.lock();
151            inner.bounds.size.width = width;
152            inner.bounds.size.height = height;
153            inner.renderer.resize(gpu::Extent {
154                width: width as u32,
155                height: height as u32,
156                depth: 1,
157            });
158        }
159        let mut callbacks = self.callbacks.lock();
160        if let Some(ref mut fun) = callbacks.resize {
161            fun(
162                Size {
163                    width: px(width as f32),
164                    height: px(height as f32),
165                },
166                1.0,
167            );
168        }
169        if let Some(ref mut fun) = callbacks.moved {
170            fun()
171        }
172    }
173
174    pub fn close(&self) {
175        let mut callbacks = self.callbacks.lock();
176        if let Some(fun) = callbacks.close.take() {
177            fun()
178        }
179        self.toplevel.destroy();
180    }
181}
182
183#[derive(Clone)]
184pub(crate) struct WaylandWindow(pub(crate) Rc<WaylandWindowState>);
185
186impl HasWindowHandle for WaylandWindow {
187    fn window_handle(&self) -> Result<WindowHandle<'_>, HandleError> {
188        unimplemented!()
189    }
190}
191
192impl HasDisplayHandle for WaylandWindow {
193    fn display_handle(&self) -> Result<DisplayHandle<'_>, HandleError> {
194        unimplemented!()
195    }
196}
197
198impl PlatformWindow for WaylandWindow {
199    //todo!(linux)
200    fn bounds(&self) -> WindowBounds {
201        WindowBounds::Maximized
202    }
203
204    // todo!(linux)
205    fn content_size(&self) -> Size<Pixels> {
206        let inner = self.0.inner.lock();
207        Size {
208            width: Pixels(inner.bounds.size.width as f32),
209            height: Pixels(inner.bounds.size.height as f32),
210        }
211    }
212
213    // todo!(linux)
214    fn scale_factor(&self) -> f32 {
215        1f32
216    }
217
218    //todo!(linux)
219    fn titlebar_height(&self) -> Pixels {
220        unimplemented!()
221    }
222
223    // todo!(linux)
224    fn appearance(&self) -> WindowAppearance {
225        WindowAppearance::Light
226    }
227
228    // todo!(linux)
229    fn display(&self) -> Rc<dyn PlatformDisplay> {
230        Rc::new(WaylandDisplay {})
231    }
232
233    // todo!(linux)
234    fn mouse_position(&self) -> Point<Pixels> {
235        Point::default()
236    }
237
238    //todo!(linux)
239    fn modifiers(&self) -> Modifiers {
240        crate::Modifiers::default()
241    }
242
243    //todo!(linux)
244    fn as_any_mut(&mut self) -> &mut dyn Any {
245        unimplemented!()
246    }
247
248    fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {
249        //todo!(linux)
250    }
251
252    //todo!(linux)
253    fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
254        None
255    }
256
257    //todo!(linux)
258    fn prompt(
259        &self,
260        level: PromptLevel,
261        msg: &str,
262        detail: Option<&str>,
263        answers: &[&str],
264    ) -> Receiver<usize> {
265        unimplemented!()
266    }
267
268    fn activate(&self) {
269        //todo!(linux)
270    }
271
272    fn set_title(&mut self, title: &str) {
273        self.0.toplevel.set_title(title.to_string());
274    }
275
276    fn set_edited(&mut self, edited: bool) {
277        //todo!(linux)
278    }
279
280    fn show_character_palette(&self) {
281        //todo!(linux)
282    }
283
284    fn minimize(&self) {
285        //todo!(linux)
286    }
287
288    fn zoom(&self) {
289        //todo!(linux)
290    }
291
292    fn toggle_full_screen(&self) {
293        //todo!(linux)
294    }
295
296    fn on_request_frame(&self, callback: Box<dyn FnMut()>) {
297        self.0.callbacks.lock().request_frame = Some(callback);
298    }
299
300    fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> bool>) {
301        //todo!(linux)
302    }
303
304    fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
305        //todo!(linux)
306    }
307
308    fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
309        self.0.callbacks.lock().resize = Some(callback);
310    }
311
312    fn on_fullscreen(&self, callback: Box<dyn FnMut(bool)>) {
313        //todo!(linux)
314    }
315
316    fn on_moved(&self, callback: Box<dyn FnMut()>) {
317        self.0.callbacks.lock().moved = Some(callback);
318    }
319
320    fn on_should_close(&self, callback: Box<dyn FnMut() -> bool>) {
321        self.0.callbacks.lock().should_close = Some(callback);
322    }
323
324    fn on_close(&self, callback: Box<dyn FnOnce()>) {
325        self.0.callbacks.lock().close = Some(callback);
326    }
327
328    fn on_appearance_changed(&self, callback: Box<dyn FnMut()>) {
329        //todo!(linux)
330    }
331
332    // todo!(linux)
333    fn is_topmost_for_position(&self, position: Point<Pixels>) -> bool {
334        false
335    }
336
337    fn draw(&self, scene: &Scene) {
338        let mut inner = self.0.inner.lock();
339        inner.renderer.draw(scene);
340    }
341
342    fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
343        let inner = self.0.inner.lock();
344        inner.renderer.atlas().clone()
345    }
346
347    fn set_graphics_profiler_enabled(&self, enabled: bool) {
348        //todo!(linux)
349    }
350}