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}