1use std::any::Any;
2use std::cell::{Ref, RefCell, RefMut};
3use std::ffi::c_void;
4use std::num::NonZeroU32;
5use std::ops::{Deref, Range};
6use std::ptr::NonNull;
7use std::rc::{Rc, Weak};
8use std::sync::Arc;
9
10use blade_graphics as gpu;
11use collections::{HashMap, HashSet};
12use futures::channel::oneshot::Receiver;
13use parking_lot::Mutex;
14use raw_window_handle as rwh;
15use wayland_backend::client::ObjectId;
16use wayland_client::protocol::wl_region::WlRegion;
17use wayland_client::WEnum;
18use wayland_client::{protocol::wl_surface, Proxy};
19use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1;
20use wayland_protocols::wp::viewporter::client::wp_viewport;
21use wayland_protocols::xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1;
22use wayland_protocols::xdg::shell::client::xdg_surface;
23use wayland_protocols::xdg::shell::client::xdg_toplevel::{self, WmCapabilities};
24use wayland_protocols_plasma::blur::client::{org_kde_kwin_blur, org_kde_kwin_blur_manager};
25
26use crate::platform::blade::{BladeRenderer, BladeSurfaceConfig};
27use crate::platform::linux::wayland::display::WaylandDisplay;
28use crate::platform::linux::wayland::serial::SerialKind;
29use crate::platform::{PlatformAtlas, PlatformInputHandler, PlatformWindow};
30use crate::scene::Scene;
31use crate::{
32 px, size, Bounds, DevicePixels, Globals, Modifiers, Pixels, PlatformDisplay, PlatformInput,
33 Point, PromptLevel, Size, WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance,
34 WindowBounds, WindowParams,
35};
36
37#[derive(Default)]
38pub(crate) struct Callbacks {
39 request_frame: Option<Box<dyn FnMut()>>,
40 input: Option<Box<dyn FnMut(crate::PlatformInput) -> crate::DispatchEventResult>>,
41 active_status_change: Option<Box<dyn FnMut(bool)>>,
42 resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
43 moved: Option<Box<dyn FnMut()>>,
44 should_close: Option<Box<dyn FnMut() -> bool>>,
45 close: Option<Box<dyn FnOnce()>>,
46 appearance_changed: Option<Box<dyn FnMut()>>,
47}
48
49struct RawWindow {
50 window: *mut c_void,
51 display: *mut c_void,
52}
53
54impl rwh::HasWindowHandle for RawWindow {
55 fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
56 let window = NonNull::new(self.window).unwrap();
57 let handle = rwh::WaylandWindowHandle::new(window);
58 Ok(unsafe { rwh::WindowHandle::borrow_raw(handle.into()) })
59 }
60}
61impl rwh::HasDisplayHandle for RawWindow {
62 fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
63 let display = NonNull::new(self.display).unwrap();
64 let handle = rwh::WaylandDisplayHandle::new(display);
65 Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) })
66 }
67}
68
69pub struct WaylandWindowState {
70 xdg_surface: xdg_surface::XdgSurface,
71 acknowledged_first_configure: bool,
72 pub surface: wl_surface::WlSurface,
73 decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
74 appearance: WindowAppearance,
75 blur: Option<org_kde_kwin_blur::OrgKdeKwinBlur>,
76 toplevel: xdg_toplevel::XdgToplevel,
77 viewport: Option<wp_viewport::WpViewport>,
78 outputs: HashSet<ObjectId>,
79 globals: Globals,
80 renderer: BladeRenderer,
81 bounds: Bounds<u32>,
82 scale: f32,
83 input_handler: Option<PlatformInputHandler>,
84 decoration_state: WaylandDecorationState,
85 fullscreen: bool,
86 restore_bounds: Bounds<DevicePixels>,
87 maximized: bool,
88 client: WaylandClientStatePtr,
89 callbacks: Callbacks,
90}
91
92#[derive(Clone)]
93pub struct WaylandWindowStatePtr {
94 state: Rc<RefCell<WaylandWindowState>>,
95 callbacks: Rc<RefCell<Callbacks>>,
96}
97
98impl WaylandWindowState {
99 #[allow(clippy::too_many_arguments)]
100 pub(crate) fn new(
101 surface: wl_surface::WlSurface,
102 xdg_surface: xdg_surface::XdgSurface,
103 toplevel: xdg_toplevel::XdgToplevel,
104 decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
105 appearance: WindowAppearance,
106 viewport: Option<wp_viewport::WpViewport>,
107 client: WaylandClientStatePtr,
108 globals: Globals,
109 options: WindowParams,
110 ) -> Self {
111 let bounds = options.bounds.map(|p| p.0 as u32);
112
113 let raw = RawWindow {
114 window: surface.id().as_ptr().cast::<c_void>(),
115 display: surface
116 .backend()
117 .upgrade()
118 .unwrap()
119 .display_ptr()
120 .cast::<c_void>(),
121 };
122 let gpu = Arc::new(
123 unsafe {
124 gpu::Context::init_windowed(
125 &raw,
126 gpu::ContextDesc {
127 validation: false,
128 capture: false,
129 overlay: false,
130 },
131 )
132 }
133 .unwrap(),
134 );
135 let config = BladeSurfaceConfig {
136 size: gpu::Extent {
137 width: bounds.size.width,
138 height: bounds.size.height,
139 depth: 1,
140 },
141 transparent: options.window_background != WindowBackgroundAppearance::Opaque,
142 };
143
144 Self {
145 xdg_surface,
146 acknowledged_first_configure: false,
147 surface,
148 decoration,
149 blur: None,
150 toplevel,
151 viewport,
152 globals,
153 outputs: HashSet::default(),
154 renderer: BladeRenderer::new(gpu, config),
155 bounds,
156 scale: 1.0,
157 input_handler: None,
158 decoration_state: WaylandDecorationState::Client,
159 fullscreen: false,
160 restore_bounds: Bounds::default(),
161 maximized: false,
162 callbacks: Callbacks::default(),
163 client,
164 appearance,
165 }
166 }
167}
168
169pub(crate) struct WaylandWindow(pub WaylandWindowStatePtr);
170pub enum ImeInput {
171 InsertText(String),
172 SetMarkedText(String),
173 UnmarkText,
174 DeleteText,
175}
176
177impl Drop for WaylandWindow {
178 fn drop(&mut self) {
179 let mut state = self.0.state.borrow_mut();
180 let surface_id = state.surface.id();
181 let client = state.client.clone();
182
183 state.renderer.destroy();
184 if let Some(decoration) = &state.decoration {
185 decoration.destroy();
186 }
187 if let Some(blur) = &state.blur {
188 blur.release();
189 }
190 state.toplevel.destroy();
191 if let Some(viewport) = &state.viewport {
192 viewport.destroy();
193 }
194 state.xdg_surface.destroy();
195 state.surface.destroy();
196
197 let state_ptr = self.0.clone();
198 state
199 .globals
200 .executor
201 .spawn(async move {
202 state_ptr.close();
203 client.drop_window(&surface_id)
204 })
205 .detach();
206 drop(state);
207 }
208}
209
210impl WaylandWindow {
211 fn borrow(&self) -> Ref<WaylandWindowState> {
212 self.0.state.borrow()
213 }
214
215 fn borrow_mut(&self) -> RefMut<WaylandWindowState> {
216 self.0.state.borrow_mut()
217 }
218
219 pub fn new(
220 globals: Globals,
221 client: WaylandClientStatePtr,
222 params: WindowParams,
223 appearance: WindowAppearance,
224 ) -> (Self, ObjectId) {
225 let surface = globals.compositor.create_surface(&globals.qh, ());
226 let xdg_surface = globals
227 .wm_base
228 .get_xdg_surface(&surface, &globals.qh, surface.id());
229 let toplevel = xdg_surface.get_toplevel(&globals.qh, surface.id());
230
231 if let Some(fractional_scale_manager) = globals.fractional_scale_manager.as_ref() {
232 fractional_scale_manager.get_fractional_scale(&surface, &globals.qh, surface.id());
233 }
234
235 // Attempt to set up window decorations based on the requested configuration
236 let decoration = globals
237 .decoration_manager
238 .as_ref()
239 .map(|decoration_manager| {
240 let decoration = decoration_manager.get_toplevel_decoration(
241 &toplevel,
242 &globals.qh,
243 surface.id(),
244 );
245 decoration.set_mode(zxdg_toplevel_decoration_v1::Mode::ClientSide);
246 decoration
247 });
248
249 let viewport = globals
250 .viewporter
251 .as_ref()
252 .map(|viewporter| viewporter.get_viewport(&surface, &globals.qh, ()));
253
254 let this = Self(WaylandWindowStatePtr {
255 state: Rc::new(RefCell::new(WaylandWindowState::new(
256 surface.clone(),
257 xdg_surface,
258 toplevel,
259 decoration,
260 appearance,
261 viewport,
262 client,
263 globals,
264 params,
265 ))),
266 callbacks: Rc::new(RefCell::new(Callbacks::default())),
267 });
268
269 // Kick things off
270 surface.commit();
271
272 (this, surface.id())
273 }
274}
275
276impl WaylandWindowStatePtr {
277 pub fn surface(&self) -> wl_surface::WlSurface {
278 self.state.borrow().surface.clone()
279 }
280
281 pub fn ptr_eq(&self, other: &Self) -> bool {
282 Rc::ptr_eq(&self.state, &other.state)
283 }
284
285 pub fn frame(&self, request_frame_callback: bool) {
286 if request_frame_callback {
287 let state = self.state.borrow_mut();
288 state.surface.frame(&state.globals.qh, state.surface.id());
289 drop(state);
290 }
291 let mut cb = self.callbacks.borrow_mut();
292 if let Some(fun) = cb.request_frame.as_mut() {
293 fun();
294 }
295 }
296
297 pub fn handle_xdg_surface_event(&self, event: xdg_surface::Event) {
298 match event {
299 xdg_surface::Event::Configure { serial } => {
300 let mut state = self.state.borrow_mut();
301 state.xdg_surface.ack_configure(serial);
302 let request_frame_callback = !state.acknowledged_first_configure;
303 state.acknowledged_first_configure = true;
304 drop(state);
305 self.frame(request_frame_callback);
306 }
307 _ => {}
308 }
309 }
310
311 pub fn handle_toplevel_decoration_event(&self, event: zxdg_toplevel_decoration_v1::Event) {
312 match event {
313 zxdg_toplevel_decoration_v1::Event::Configure { mode } => match mode {
314 WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ServerSide) => {
315 self.set_decoration_state(WaylandDecorationState::Server)
316 }
317 WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ClientSide) => {
318 self.set_decoration_state(WaylandDecorationState::Client)
319 }
320 WEnum::Value(_) => {
321 log::warn!("Unknown decoration mode");
322 }
323 WEnum::Unknown(v) => {
324 log::warn!("Unknown decoration mode: {}", v);
325 }
326 },
327 _ => {}
328 }
329 }
330
331 pub fn handle_fractional_scale_event(&self, event: wp_fractional_scale_v1::Event) {
332 match event {
333 wp_fractional_scale_v1::Event::PreferredScale { scale } => {
334 self.rescale(scale as f32 / 120.0);
335 }
336 _ => {}
337 }
338 }
339
340 pub fn handle_toplevel_event(&self, event: xdg_toplevel::Event) -> bool {
341 match event {
342 xdg_toplevel::Event::Configure {
343 width,
344 height,
345 states,
346 } => {
347 let width = NonZeroU32::new(width as u32);
348 let height = NonZeroU32::new(height as u32);
349 let fullscreen = states.contains(&(xdg_toplevel::State::Fullscreen as u8));
350 let maximized = states.contains(&(xdg_toplevel::State::Maximized as u8));
351 let mut state = self.state.borrow_mut();
352 state.maximized = maximized;
353 state.fullscreen = fullscreen;
354 if fullscreen || maximized {
355 state.restore_bounds = state.bounds.map(|p| DevicePixels(p as i32));
356 }
357 drop(state);
358 self.resize(width, height);
359 self.set_fullscreen(fullscreen);
360
361 false
362 }
363 xdg_toplevel::Event::Close => {
364 let mut cb = self.callbacks.borrow_mut();
365 if let Some(mut should_close) = cb.should_close.take() {
366 let result = (should_close)();
367 cb.should_close = Some(should_close);
368 if result {
369 drop(cb);
370 self.close();
371 }
372 result
373 } else {
374 true
375 }
376 }
377 _ => false,
378 }
379 }
380
381 pub fn handle_surface_event(
382 &self,
383 event: wl_surface::Event,
384 output_scales: HashMap<ObjectId, i32>,
385 ) {
386 let mut state = self.state.borrow_mut();
387
388 // We use `WpFractionalScale` instead to set the scale if it's available
389 if state.globals.fractional_scale_manager.is_some() {
390 return;
391 }
392
393 match event {
394 wl_surface::Event::Enter { output } => {
395 // We use `PreferredBufferScale` instead to set the scale if it's available
396 if state.surface.version() >= wl_surface::EVT_PREFERRED_BUFFER_SCALE_SINCE {
397 return;
398 }
399
400 state.outputs.insert(output.id());
401
402 let mut scale = 1;
403 for output in state.outputs.iter() {
404 if let Some(s) = output_scales.get(output) {
405 scale = scale.max(*s)
406 }
407 }
408
409 state.surface.set_buffer_scale(scale);
410 drop(state);
411 self.rescale(scale as f32);
412 }
413 wl_surface::Event::Leave { output } => {
414 // We use `PreferredBufferScale` instead to set the scale if it's available
415 if state.surface.version() >= wl_surface::EVT_PREFERRED_BUFFER_SCALE_SINCE {
416 return;
417 }
418
419 state.outputs.remove(&output.id());
420
421 let mut scale = 1;
422 for output in state.outputs.iter() {
423 if let Some(s) = output_scales.get(output) {
424 scale = scale.max(*s)
425 }
426 }
427
428 state.surface.set_buffer_scale(scale);
429 drop(state);
430 self.rescale(scale as f32);
431 }
432 wl_surface::Event::PreferredBufferScale { factor } => {
433 state.surface.set_buffer_scale(factor);
434 drop(state);
435 self.rescale(factor as f32);
436 }
437 _ => {}
438 }
439 }
440
441 pub fn handle_ime(&self, ime: ImeInput) {
442 let mut state = self.state.borrow_mut();
443 if let Some(mut input_handler) = state.input_handler.take() {
444 drop(state);
445 match ime {
446 ImeInput::InsertText(text) => {
447 input_handler.replace_text_in_range(None, &text);
448 }
449 ImeInput::SetMarkedText(text) => {
450 input_handler.replace_and_mark_text_in_range(None, &text, None);
451 }
452 ImeInput::UnmarkText => {
453 input_handler.unmark_text();
454 }
455 ImeInput::DeleteText => {
456 if let Some(marked) = input_handler.marked_text_range() {
457 input_handler.replace_text_in_range(Some(marked), "");
458 }
459 }
460 }
461 self.state.borrow_mut().input_handler = Some(input_handler);
462 }
463 }
464
465 pub fn get_ime_area(&self) -> Option<Bounds<Pixels>> {
466 let mut state = self.state.borrow_mut();
467 let mut bounds: Option<Bounds<Pixels>> = None;
468 if let Some(mut input_handler) = state.input_handler.take() {
469 drop(state);
470 if let Some(range) = input_handler.selected_text_range() {
471 bounds = input_handler.bounds_for_range(range);
472 }
473 self.state.borrow_mut().input_handler = Some(input_handler);
474 }
475 bounds
476 }
477
478 pub fn set_size_and_scale(
479 &self,
480 width: Option<NonZeroU32>,
481 height: Option<NonZeroU32>,
482 scale: Option<f32>,
483 ) {
484 let (width, height, scale) = {
485 let mut state = self.state.borrow_mut();
486 if width.map_or(true, |width| width.get() == state.bounds.size.width)
487 && height.map_or(true, |height| height.get() == state.bounds.size.height)
488 && scale.map_or(true, |scale| scale == state.scale)
489 {
490 return;
491 }
492 if let Some(width) = width {
493 state.bounds.size.width = width.get();
494 }
495 if let Some(height) = height {
496 state.bounds.size.height = height.get();
497 }
498 if let Some(scale) = scale {
499 state.scale = scale;
500 }
501 let width = state.bounds.size.width;
502 let height = state.bounds.size.height;
503 let scale = state.scale;
504 state.renderer.update_drawable_size(size(
505 width as f64 * scale as f64,
506 height as f64 * scale as f64,
507 ));
508 (width, height, scale)
509 };
510
511 if let Some(ref mut fun) = self.callbacks.borrow_mut().resize {
512 fun(
513 Size {
514 width: px(width as f32),
515 height: px(height as f32),
516 },
517 scale,
518 );
519 }
520
521 {
522 let state = self.state.borrow();
523 if let Some(viewport) = &state.viewport {
524 viewport.set_destination(width as i32, height as i32);
525 }
526 }
527 }
528
529 pub fn resize(&self, width: Option<NonZeroU32>, height: Option<NonZeroU32>) {
530 self.set_size_and_scale(width, height, None);
531 }
532
533 pub fn rescale(&self, scale: f32) {
534 self.set_size_and_scale(None, None, Some(scale));
535 }
536
537 pub fn set_fullscreen(&self, fullscreen: bool) {
538 let mut state = self.state.borrow_mut();
539 state.fullscreen = fullscreen;
540 }
541
542 /// Notifies the window of the state of the decorations.
543 ///
544 /// # Note
545 ///
546 /// This API is indirectly called by the wayland compositor and
547 /// not meant to be called by a user who wishes to change the state
548 /// of the decorations. This is because the state of the decorations
549 /// is managed by the compositor and not the client.
550 pub fn set_decoration_state(&self, state: WaylandDecorationState) {
551 self.state.borrow_mut().decoration_state = state;
552 }
553
554 pub fn close(&self) {
555 let mut callbacks = self.callbacks.borrow_mut();
556 if let Some(fun) = callbacks.close.take() {
557 fun()
558 }
559 }
560
561 pub fn handle_input(&self, input: PlatformInput) {
562 if let Some(ref mut fun) = self.callbacks.borrow_mut().input {
563 if !fun(input.clone()).propagate {
564 return;
565 }
566 }
567 if let PlatformInput::KeyDown(event) = input {
568 if let Some(ime_key) = &event.keystroke.ime_key {
569 let mut state = self.state.borrow_mut();
570 if let Some(mut input_handler) = state.input_handler.take() {
571 drop(state);
572 input_handler.replace_text_in_range(None, ime_key);
573 self.state.borrow_mut().input_handler = Some(input_handler);
574 }
575 }
576 }
577 }
578
579 pub fn set_focused(&self, focus: bool) {
580 if let Some(ref mut fun) = self.callbacks.borrow_mut().active_status_change {
581 fun(focus);
582 }
583 }
584
585 pub fn set_appearance(&mut self, appearance: WindowAppearance) {
586 self.state.borrow_mut().appearance = appearance;
587
588 let mut callbacks = self.callbacks.borrow_mut();
589 if let Some(ref mut fun) = callbacks.appearance_changed {
590 (fun)()
591 }
592 }
593}
594
595impl rwh::HasWindowHandle for WaylandWindow {
596 fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
597 unimplemented!()
598 }
599}
600impl rwh::HasDisplayHandle for WaylandWindow {
601 fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
602 unimplemented!()
603 }
604}
605
606impl PlatformWindow for WaylandWindow {
607 fn bounds(&self) -> Bounds<DevicePixels> {
608 self.borrow().bounds.map(|p| DevicePixels(p as i32))
609 }
610
611 fn is_maximized(&self) -> bool {
612 self.borrow().maximized
613 }
614
615 // todo(linux)
616 // check if it is right
617 fn window_bounds(&self) -> WindowBounds {
618 let state = self.borrow();
619 if state.fullscreen {
620 WindowBounds::Fullscreen(state.restore_bounds)
621 } else if state.maximized {
622 WindowBounds::Maximized(state.restore_bounds)
623 } else {
624 WindowBounds::Windowed(state.bounds.map(|p| DevicePixels(p as i32)))
625 }
626 }
627
628 fn content_size(&self) -> Size<Pixels> {
629 let state = self.borrow();
630 Size {
631 width: Pixels(state.bounds.size.width as f32),
632 height: Pixels(state.bounds.size.height as f32),
633 }
634 }
635
636 fn scale_factor(&self) -> f32 {
637 self.borrow().scale
638 }
639
640 fn appearance(&self) -> WindowAppearance {
641 self.borrow().appearance
642 }
643
644 // todo(linux)
645 fn display(&self) -> Rc<dyn PlatformDisplay> {
646 Rc::new(WaylandDisplay {})
647 }
648
649 // todo(linux)
650 fn mouse_position(&self) -> Point<Pixels> {
651 Point::default()
652 }
653
654 // todo(linux)
655 fn modifiers(&self) -> Modifiers {
656 crate::Modifiers::default()
657 }
658
659 fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {
660 self.borrow_mut().input_handler = Some(input_handler);
661 }
662
663 fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
664 self.borrow_mut().input_handler.take()
665 }
666
667 fn prompt(
668 &self,
669 level: PromptLevel,
670 msg: &str,
671 detail: Option<&str>,
672 answers: &[&str],
673 ) -> Option<Receiver<usize>> {
674 None
675 }
676
677 fn activate(&self) {
678 // todo(linux)
679 }
680
681 // todo(linux)
682 fn is_active(&self) -> bool {
683 false
684 }
685
686 fn set_title(&mut self, title: &str) {
687 self.borrow().toplevel.set_title(title.to_string());
688 }
689
690 fn set_app_id(&mut self, app_id: &str) {
691 self.borrow().toplevel.set_app_id(app_id.to_owned());
692 }
693
694 fn set_background_appearance(&mut self, background_appearance: WindowBackgroundAppearance) {
695 let opaque = background_appearance == WindowBackgroundAppearance::Opaque;
696 let mut state = self.borrow_mut();
697 state.renderer.update_transparency(!opaque);
698
699 let region = state
700 .globals
701 .compositor
702 .create_region(&state.globals.qh, ());
703 region.add(0, 0, i32::MAX, i32::MAX);
704
705 if opaque {
706 // Promise the compositor that this region of the window surface
707 // contains no transparent pixels. This allows the compositor to
708 // do skip whatever is behind the surface for better performance.
709 state.surface.set_opaque_region(Some(®ion));
710 } else {
711 state.surface.set_opaque_region(None);
712 }
713
714 if let Some(ref blur_manager) = state.globals.blur_manager {
715 if (background_appearance == WindowBackgroundAppearance::Blurred) {
716 if (state.blur.is_none()) {
717 let blur = blur_manager.create(&state.surface, &state.globals.qh, ());
718 blur.set_region(Some(®ion));
719 state.blur = Some(blur);
720 }
721 state.blur.as_ref().unwrap().commit();
722 } else {
723 // It probably doesn't hurt to clear the blur for opaque windows
724 blur_manager.unset(&state.surface);
725 if let Some(b) = state.blur.take() {
726 b.release()
727 }
728 }
729 }
730
731 region.destroy();
732 }
733
734 fn set_edited(&mut self, edited: bool) {
735 // todo(linux)
736 }
737
738 fn show_character_palette(&self) {
739 // todo(linux)
740 }
741
742 fn minimize(&self) {
743 self.borrow().toplevel.set_minimized();
744 }
745
746 fn zoom(&self) {
747 let state = self.borrow();
748 if !state.maximized {
749 state.toplevel.set_maximized();
750 } else {
751 state.toplevel.unset_maximized();
752 }
753 }
754
755 fn toggle_fullscreen(&self) {
756 let mut state = self.borrow_mut();
757 state.restore_bounds = state.bounds.map(|p| DevicePixels(p as i32));
758 if !state.fullscreen {
759 state.toplevel.set_fullscreen(None);
760 } else {
761 state.toplevel.unset_fullscreen();
762 }
763 }
764
765 fn is_fullscreen(&self) -> bool {
766 self.borrow().fullscreen
767 }
768
769 fn on_request_frame(&self, callback: Box<dyn FnMut()>) {
770 self.0.callbacks.borrow_mut().request_frame = Some(callback);
771 }
772
773 fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> crate::DispatchEventResult>) {
774 self.0.callbacks.borrow_mut().input = Some(callback);
775 }
776
777 fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
778 self.0.callbacks.borrow_mut().active_status_change = Some(callback);
779 }
780
781 fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
782 self.0.callbacks.borrow_mut().resize = Some(callback);
783 }
784
785 fn on_moved(&self, callback: Box<dyn FnMut()>) {
786 self.0.callbacks.borrow_mut().moved = Some(callback);
787 }
788
789 fn on_should_close(&self, callback: Box<dyn FnMut() -> bool>) {
790 self.0.callbacks.borrow_mut().should_close = Some(callback);
791 }
792
793 fn on_close(&self, callback: Box<dyn FnOnce()>) {
794 self.0.callbacks.borrow_mut().close = Some(callback);
795 }
796
797 fn on_appearance_changed(&self, callback: Box<dyn FnMut()>) {
798 self.0.callbacks.borrow_mut().appearance_changed = Some(callback);
799 }
800
801 fn draw(&self, scene: &Scene) {
802 let mut state = self.borrow_mut();
803 state.renderer.draw(scene);
804 }
805
806 fn completed_frame(&self) {
807 let mut state = self.borrow_mut();
808 state.surface.commit();
809 }
810
811 fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
812 let state = self.borrow();
813 state.renderer.sprite_atlas().clone()
814 }
815
816 fn show_window_menu(&self, position: Point<Pixels>) {
817 let state = self.borrow();
818 let serial = state.client.get_serial(SerialKind::MousePress);
819 state.toplevel.show_window_menu(
820 &state.globals.seat,
821 serial,
822 position.x.0 as i32,
823 position.y.0 as i32,
824 );
825 }
826
827 fn start_system_move(&self) {
828 let state = self.borrow();
829 let serial = state.client.get_serial(SerialKind::MousePress);
830 state.toplevel._move(&state.globals.seat, serial);
831 }
832
833 fn should_render_window_controls(&self) -> bool {
834 self.borrow().decoration_state == WaylandDecorationState::Client
835 }
836}
837
838#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
839pub enum WaylandDecorationState {
840 /// Decorations are to be provided by the client
841 Client,
842
843 /// Decorations are provided by the server
844 Server,
845}