window.rs

  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(&region));
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(&region));
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}