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