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