window.rs

   1use std::{
   2    cell::{Ref, RefCell, RefMut},
   3    ffi::c_void,
   4    ptr::NonNull,
   5    rc::Rc,
   6    sync::Arc,
   7};
   8
   9use collections::{FxHashSet, HashMap};
  10use futures::channel::oneshot::Receiver;
  11
  12use raw_window_handle as rwh;
  13use wayland_backend::client::ObjectId;
  14use wayland_client::WEnum;
  15use wayland_client::{Proxy, protocol::wl_surface};
  16use wayland_protocols::wp::viewporter::client::wp_viewport;
  17use wayland_protocols::xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1;
  18use wayland_protocols::xdg::shell::client::xdg_surface;
  19use wayland_protocols::xdg::shell::client::xdg_toplevel::{self};
  20use wayland_protocols::{
  21    wp::fractional_scale::v1::client::wp_fractional_scale_v1,
  22    xdg::dialog::v1::client::xdg_dialog_v1::XdgDialogV1,
  23};
  24use wayland_protocols_plasma::blur::client::org_kde_kwin_blur;
  25use wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1;
  26
  27use crate::{
  28    AnyWindowHandle, Bounds, Decorations, DevicePixels, Globals, GpuSpecs, Modifiers, Output,
  29    Pixels, PlatformDisplay, PlatformInput, Point, PromptButton, PromptLevel, RequestFrameOptions,
  30    ResizeEdge, Size, Tiling, WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance,
  31    WindowBounds, WindowControlArea, WindowControls, WindowDecorations, WindowParams, get_window,
  32    layer_shell::LayerShellNotSupportedError, px, size,
  33};
  34use crate::{
  35    Capslock,
  36    platform::{
  37        PlatformAtlas, PlatformInputHandler, PlatformWindow,
  38        linux::wayland::{display::WaylandDisplay, serial::SerialKind},
  39        wgpu::{CompositorGpuHint, WgpuContext, WgpuRenderer, WgpuSurfaceConfig},
  40    },
  41};
  42use crate::{WindowKind, scene::Scene};
  43
  44#[derive(Default)]
  45pub(crate) struct Callbacks {
  46    request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>,
  47    input: Option<Box<dyn FnMut(crate::PlatformInput) -> crate::DispatchEventResult>>,
  48    active_status_change: Option<Box<dyn FnMut(bool)>>,
  49    hover_status_change: Option<Box<dyn FnMut(bool)>>,
  50    resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
  51    moved: Option<Box<dyn FnMut()>>,
  52    should_close: Option<Box<dyn FnMut() -> bool>>,
  53    close: Option<Box<dyn FnOnce()>>,
  54    appearance_changed: Option<Box<dyn FnMut()>>,
  55}
  56
  57struct RawWindow {
  58    window: *mut c_void,
  59    display: *mut c_void,
  60}
  61
  62// Safety: The raw pointers in RawWindow point to Wayland surface/display
  63// which are valid for the window's lifetime. These are used only for
  64// passing to wgpu which needs Send+Sync for surface creation.
  65unsafe impl Send for RawWindow {}
  66unsafe impl Sync for RawWindow {}
  67
  68impl rwh::HasWindowHandle for RawWindow {
  69    fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
  70        let window = NonNull::new(self.window).unwrap();
  71        let handle = rwh::WaylandWindowHandle::new(window);
  72        Ok(unsafe { rwh::WindowHandle::borrow_raw(handle.into()) })
  73    }
  74}
  75impl rwh::HasDisplayHandle for RawWindow {
  76    fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
  77        let display = NonNull::new(self.display).unwrap();
  78        let handle = rwh::WaylandDisplayHandle::new(display);
  79        Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) })
  80    }
  81}
  82
  83#[derive(Debug)]
  84struct InProgressConfigure {
  85    size: Option<Size<Pixels>>,
  86    fullscreen: bool,
  87    maximized: bool,
  88    resizing: bool,
  89    tiling: Tiling,
  90}
  91
  92pub struct WaylandWindowState {
  93    surface_state: WaylandSurfaceState,
  94    acknowledged_first_configure: bool,
  95    parent: Option<WaylandWindowStatePtr>,
  96    children: FxHashSet<ObjectId>,
  97    pub surface: wl_surface::WlSurface,
  98    app_id: Option<String>,
  99    appearance: WindowAppearance,
 100    blur: Option<org_kde_kwin_blur::OrgKdeKwinBlur>,
 101    viewport: Option<wp_viewport::WpViewport>,
 102    outputs: HashMap<ObjectId, Output>,
 103    display: Option<(ObjectId, Output)>,
 104    globals: Globals,
 105    renderer: WgpuRenderer,
 106    bounds: Bounds<Pixels>,
 107    scale: f32,
 108    input_handler: Option<PlatformInputHandler>,
 109    decorations: WindowDecorations,
 110    background_appearance: WindowBackgroundAppearance,
 111    fullscreen: bool,
 112    maximized: bool,
 113    tiling: Tiling,
 114    window_bounds: Bounds<Pixels>,
 115    client: WaylandClientStatePtr,
 116    handle: AnyWindowHandle,
 117    active: bool,
 118    hovered: bool,
 119    in_progress_configure: Option<InProgressConfigure>,
 120    resize_throttle: bool,
 121    in_progress_window_controls: Option<WindowControls>,
 122    window_controls: WindowControls,
 123    client_inset: Option<Pixels>,
 124}
 125
 126pub enum WaylandSurfaceState {
 127    Xdg(WaylandXdgSurfaceState),
 128    LayerShell(WaylandLayerSurfaceState),
 129}
 130
 131impl WaylandSurfaceState {
 132    fn new(
 133        surface: &wl_surface::WlSurface,
 134        globals: &Globals,
 135        params: &WindowParams,
 136        parent: Option<WaylandWindowStatePtr>,
 137    ) -> anyhow::Result<Self> {
 138        // For layer_shell windows, create a layer surface instead of an xdg surface
 139        if let WindowKind::LayerShell(options) = &params.kind {
 140            let Some(layer_shell) = globals.layer_shell.as_ref() else {
 141                return Err(LayerShellNotSupportedError.into());
 142            };
 143
 144            let layer_surface = layer_shell.get_layer_surface(
 145                &surface,
 146                None,
 147                options.layer.into(),
 148                options.namespace.clone(),
 149                &globals.qh,
 150                surface.id(),
 151            );
 152
 153            let width = params.bounds.size.width.0;
 154            let height = params.bounds.size.height.0;
 155            layer_surface.set_size(width as u32, height as u32);
 156
 157            layer_surface.set_anchor(options.anchor.into());
 158            layer_surface.set_keyboard_interactivity(options.keyboard_interactivity.into());
 159
 160            if let Some(margin) = options.margin {
 161                layer_surface.set_margin(
 162                    margin.0.0 as i32,
 163                    margin.1.0 as i32,
 164                    margin.2.0 as i32,
 165                    margin.3.0 as i32,
 166                )
 167            }
 168
 169            if let Some(exclusive_zone) = options.exclusive_zone {
 170                layer_surface.set_exclusive_zone(exclusive_zone.0 as i32);
 171            }
 172
 173            if let Some(exclusive_edge) = options.exclusive_edge {
 174                layer_surface.set_exclusive_edge(exclusive_edge.into());
 175            }
 176
 177            return Ok(WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState {
 178                layer_surface,
 179            }));
 180        }
 181
 182        // All other WindowKinds result in a regular xdg surface
 183        let xdg_surface = globals
 184            .wm_base
 185            .get_xdg_surface(&surface, &globals.qh, surface.id());
 186
 187        let toplevel = xdg_surface.get_toplevel(&globals.qh, surface.id());
 188        let xdg_parent = parent.as_ref().and_then(|w| w.toplevel());
 189
 190        if params.kind == WindowKind::Floating || params.kind == WindowKind::Dialog {
 191            toplevel.set_parent(xdg_parent.as_ref());
 192        }
 193
 194        let dialog = if params.kind == WindowKind::Dialog {
 195            let dialog = globals.dialog.as_ref().map(|dialog| {
 196                let xdg_dialog = dialog.get_xdg_dialog(&toplevel, &globals.qh, ());
 197                xdg_dialog.set_modal();
 198                xdg_dialog
 199            });
 200
 201            if let Some(parent) = parent.as_ref() {
 202                parent.add_child(surface.id());
 203            }
 204
 205            dialog
 206        } else {
 207            None
 208        };
 209
 210        if let Some(size) = params.window_min_size {
 211            toplevel.set_min_size(size.width.0 as i32, size.height.0 as i32);
 212        }
 213
 214        // Attempt to set up window decorations based on the requested configuration
 215        let decoration = globals
 216            .decoration_manager
 217            .as_ref()
 218            .map(|decoration_manager| {
 219                decoration_manager.get_toplevel_decoration(&toplevel, &globals.qh, surface.id())
 220            });
 221
 222        Ok(WaylandSurfaceState::Xdg(WaylandXdgSurfaceState {
 223            xdg_surface,
 224            toplevel,
 225            decoration,
 226            dialog,
 227        }))
 228    }
 229}
 230
 231pub struct WaylandXdgSurfaceState {
 232    xdg_surface: xdg_surface::XdgSurface,
 233    toplevel: xdg_toplevel::XdgToplevel,
 234    decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
 235    dialog: Option<XdgDialogV1>,
 236}
 237
 238pub struct WaylandLayerSurfaceState {
 239    layer_surface: zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
 240}
 241
 242impl WaylandSurfaceState {
 243    fn ack_configure(&self, serial: u32) {
 244        match self {
 245            WaylandSurfaceState::Xdg(WaylandXdgSurfaceState { xdg_surface, .. }) => {
 246                xdg_surface.ack_configure(serial);
 247            }
 248            WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState { layer_surface, .. }) => {
 249                layer_surface.ack_configure(serial);
 250            }
 251        }
 252    }
 253
 254    fn decoration(&self) -> Option<&zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1> {
 255        if let WaylandSurfaceState::Xdg(WaylandXdgSurfaceState { decoration, .. }) = self {
 256            decoration.as_ref()
 257        } else {
 258            None
 259        }
 260    }
 261
 262    fn toplevel(&self) -> Option<&xdg_toplevel::XdgToplevel> {
 263        if let WaylandSurfaceState::Xdg(WaylandXdgSurfaceState { toplevel, .. }) = self {
 264            Some(toplevel)
 265        } else {
 266            None
 267        }
 268    }
 269
 270    fn set_geometry(&self, x: i32, y: i32, width: i32, height: i32) {
 271        match self {
 272            WaylandSurfaceState::Xdg(WaylandXdgSurfaceState { xdg_surface, .. }) => {
 273                xdg_surface.set_window_geometry(x, y, width, height);
 274            }
 275            WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState { layer_surface, .. }) => {
 276                // cannot set window position of a layer surface
 277                layer_surface.set_size(width as u32, height as u32);
 278            }
 279        }
 280    }
 281
 282    fn destroy(&mut self) {
 283        match self {
 284            WaylandSurfaceState::Xdg(WaylandXdgSurfaceState {
 285                xdg_surface,
 286                toplevel,
 287                decoration: _decoration,
 288                dialog,
 289            }) => {
 290                // drop the dialog before toplevel so compositor can explicitly unapply it's effects
 291                if let Some(dialog) = dialog {
 292                    dialog.destroy();
 293                }
 294
 295                // The role object (toplevel) must always be destroyed before the xdg_surface.
 296                // See https://wayland.app/protocols/xdg-shell#xdg_surface:request:destroy
 297                toplevel.destroy();
 298                xdg_surface.destroy();
 299            }
 300            WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState { layer_surface }) => {
 301                layer_surface.destroy();
 302            }
 303        }
 304    }
 305}
 306
 307#[derive(Clone)]
 308pub struct WaylandWindowStatePtr {
 309    state: Rc<RefCell<WaylandWindowState>>,
 310    callbacks: Rc<RefCell<Callbacks>>,
 311}
 312
 313impl WaylandWindowState {
 314    pub(crate) fn new(
 315        handle: AnyWindowHandle,
 316        surface: wl_surface::WlSurface,
 317        surface_state: WaylandSurfaceState,
 318        appearance: WindowAppearance,
 319        viewport: Option<wp_viewport::WpViewport>,
 320        client: WaylandClientStatePtr,
 321        globals: Globals,
 322        gpu_context: &mut Option<WgpuContext>,
 323        compositor_gpu: Option<CompositorGpuHint>,
 324        options: WindowParams,
 325        parent: Option<WaylandWindowStatePtr>,
 326    ) -> anyhow::Result<Self> {
 327        let renderer = {
 328            let raw_window = RawWindow {
 329                window: surface.id().as_ptr().cast::<c_void>(),
 330                display: surface
 331                    .backend()
 332                    .upgrade()
 333                    .unwrap()
 334                    .display_ptr()
 335                    .cast::<c_void>(),
 336            };
 337            let config = WgpuSurfaceConfig {
 338                size: Size {
 339                    width: DevicePixels(options.bounds.size.width.0 as i32),
 340                    height: DevicePixels(options.bounds.size.height.0 as i32),
 341                },
 342                transparent: true,
 343            };
 344            WgpuRenderer::new(gpu_context, &raw_window, config, compositor_gpu)?
 345        };
 346
 347        if let WaylandSurfaceState::Xdg(ref xdg_state) = surface_state {
 348            if let Some(title) = options.titlebar.and_then(|titlebar| titlebar.title) {
 349                xdg_state.toplevel.set_title(title.to_string());
 350            }
 351            // Set max window size based on the GPU's maximum texture dimension.
 352            // This prevents the window from being resized larger than what the GPU can render.
 353            let max_texture_size = renderer.max_texture_size() as i32;
 354            xdg_state
 355                .toplevel
 356                .set_max_size(max_texture_size, max_texture_size);
 357        }
 358
 359        Ok(Self {
 360            surface_state,
 361            acknowledged_first_configure: false,
 362            parent,
 363            children: FxHashSet::default(),
 364            surface,
 365            app_id: None,
 366            blur: None,
 367            viewport,
 368            globals,
 369            outputs: HashMap::default(),
 370            display: None,
 371            renderer,
 372            bounds: options.bounds,
 373            scale: 1.0,
 374            input_handler: None,
 375            decorations: WindowDecorations::Client,
 376            background_appearance: WindowBackgroundAppearance::Opaque,
 377            fullscreen: false,
 378            maximized: false,
 379            tiling: Tiling::default(),
 380            window_bounds: options.bounds,
 381            in_progress_configure: None,
 382            resize_throttle: false,
 383            client,
 384            appearance,
 385            handle,
 386            active: false,
 387            hovered: false,
 388            in_progress_window_controls: None,
 389            window_controls: WindowControls::default(),
 390            client_inset: None,
 391        })
 392    }
 393
 394    pub fn is_transparent(&self) -> bool {
 395        self.decorations == WindowDecorations::Client
 396            || self.background_appearance != WindowBackgroundAppearance::Opaque
 397    }
 398
 399    pub fn primary_output_scale(&mut self) -> i32 {
 400        let mut scale = 1;
 401        let mut current_output = self.display.take();
 402        for (id, output) in self.outputs.iter() {
 403            if let Some((_, output_data)) = &current_output {
 404                if output.scale > output_data.scale {
 405                    current_output = Some((id.clone(), output.clone()));
 406                }
 407            } else {
 408                current_output = Some((id.clone(), output.clone()));
 409            }
 410            scale = scale.max(output.scale);
 411        }
 412        self.display = current_output;
 413        scale
 414    }
 415
 416    pub fn inset(&self) -> Pixels {
 417        match self.decorations {
 418            WindowDecorations::Server => px(0.0),
 419            WindowDecorations::Client => self.client_inset.unwrap_or(px(0.0)),
 420        }
 421    }
 422}
 423
 424pub(crate) struct WaylandWindow(pub WaylandWindowStatePtr);
 425pub enum ImeInput {
 426    InsertText(String),
 427    SetMarkedText(String),
 428    UnmarkText,
 429    DeleteText,
 430}
 431
 432impl Drop for WaylandWindow {
 433    fn drop(&mut self) {
 434        let mut state = self.0.state.borrow_mut();
 435        let surface_id = state.surface.id();
 436        if let Some(parent) = state.parent.as_ref() {
 437            parent.state.borrow_mut().children.remove(&surface_id);
 438        }
 439
 440        let client = state.client.clone();
 441
 442        state.renderer.destroy();
 443
 444        // Destroy blur first, this has no dependencies.
 445        if let Some(blur) = &state.blur {
 446            blur.release();
 447        }
 448
 449        // Decorations must be destroyed before the xdg state.
 450        // See https://wayland.app/protocols/xdg-decoration-unstable-v1#zxdg_toplevel_decoration_v1
 451        if let Some(decoration) = &state.surface_state.decoration() {
 452            decoration.destroy();
 453        }
 454
 455        // Surface state might contain xdg_toplevel/xdg_surface which can be destroyed now that
 456        // decorations are gone. layer_surface has no dependencies.
 457        state.surface_state.destroy();
 458
 459        // Viewport must be destroyed before the wl_surface.
 460        // See https://wayland.app/protocols/viewporter#wp_viewport
 461        if let Some(viewport) = &state.viewport {
 462            viewport.destroy();
 463        }
 464
 465        // The wl_surface itself should always be destroyed last.
 466        state.surface.destroy();
 467
 468        let state_ptr = self.0.clone();
 469        state
 470            .globals
 471            .executor
 472            .spawn(async move {
 473                state_ptr.close();
 474                client.drop_window(&surface_id)
 475            })
 476            .detach();
 477        drop(state);
 478    }
 479}
 480
 481impl WaylandWindow {
 482    fn borrow(&self) -> Ref<'_, WaylandWindowState> {
 483        self.0.state.borrow()
 484    }
 485
 486    fn borrow_mut(&self) -> RefMut<'_, WaylandWindowState> {
 487        self.0.state.borrow_mut()
 488    }
 489
 490    pub fn new(
 491        handle: AnyWindowHandle,
 492        globals: Globals,
 493        gpu_context: &mut Option<WgpuContext>,
 494        compositor_gpu: Option<CompositorGpuHint>,
 495        client: WaylandClientStatePtr,
 496        params: WindowParams,
 497        appearance: WindowAppearance,
 498        parent: Option<WaylandWindowStatePtr>,
 499    ) -> anyhow::Result<(Self, ObjectId)> {
 500        let surface = globals.compositor.create_surface(&globals.qh, ());
 501        let surface_state = WaylandSurfaceState::new(&surface, &globals, &params, parent.clone())?;
 502
 503        if let Some(fractional_scale_manager) = globals.fractional_scale_manager.as_ref() {
 504            fractional_scale_manager.get_fractional_scale(&surface, &globals.qh, surface.id());
 505        }
 506
 507        let viewport = globals
 508            .viewporter
 509            .as_ref()
 510            .map(|viewporter| viewporter.get_viewport(&surface, &globals.qh, ()));
 511
 512        let this = Self(WaylandWindowStatePtr {
 513            state: Rc::new(RefCell::new(WaylandWindowState::new(
 514                handle,
 515                surface.clone(),
 516                surface_state,
 517                appearance,
 518                viewport,
 519                client,
 520                globals,
 521                gpu_context,
 522                compositor_gpu,
 523                params,
 524                parent,
 525            )?)),
 526            callbacks: Rc::new(RefCell::new(Callbacks::default())),
 527        });
 528
 529        // Kick things off
 530        surface.commit();
 531
 532        Ok((this, surface.id()))
 533    }
 534}
 535
 536impl WaylandWindowStatePtr {
 537    pub fn handle(&self) -> AnyWindowHandle {
 538        self.state.borrow().handle
 539    }
 540
 541    pub fn surface(&self) -> wl_surface::WlSurface {
 542        self.state.borrow().surface.clone()
 543    }
 544
 545    pub fn toplevel(&self) -> Option<xdg_toplevel::XdgToplevel> {
 546        self.state.borrow().surface_state.toplevel().cloned()
 547    }
 548
 549    pub fn ptr_eq(&self, other: &Self) -> bool {
 550        Rc::ptr_eq(&self.state, &other.state)
 551    }
 552
 553    pub fn add_child(&self, child: ObjectId) {
 554        let mut state = self.state.borrow_mut();
 555        state.children.insert(child);
 556    }
 557
 558    pub fn is_blocked(&self) -> bool {
 559        let state = self.state.borrow();
 560        !state.children.is_empty()
 561    }
 562
 563    pub fn frame(&self) {
 564        let mut state = self.state.borrow_mut();
 565        state.surface.frame(&state.globals.qh, state.surface.id());
 566        state.resize_throttle = false;
 567        drop(state);
 568
 569        let mut cb = self.callbacks.borrow_mut();
 570        if let Some(fun) = cb.request_frame.as_mut() {
 571            fun(Default::default());
 572        }
 573    }
 574
 575    pub fn handle_xdg_surface_event(&self, event: xdg_surface::Event) {
 576        if let xdg_surface::Event::Configure { serial } = event {
 577            {
 578                let mut state = self.state.borrow_mut();
 579                if let Some(window_controls) = state.in_progress_window_controls.take() {
 580                    state.window_controls = window_controls;
 581
 582                    drop(state);
 583                    let mut callbacks = self.callbacks.borrow_mut();
 584                    if let Some(appearance_changed) = callbacks.appearance_changed.as_mut() {
 585                        appearance_changed();
 586                    }
 587                }
 588            }
 589            {
 590                let mut state = self.state.borrow_mut();
 591
 592                if let Some(mut configure) = state.in_progress_configure.take() {
 593                    let got_unmaximized = state.maximized && !configure.maximized;
 594                    state.fullscreen = configure.fullscreen;
 595                    state.maximized = configure.maximized;
 596                    state.tiling = configure.tiling;
 597                    // Limit interactive resizes to once per vblank
 598                    if configure.resizing && state.resize_throttle {
 599                        return;
 600                    } else if configure.resizing {
 601                        state.resize_throttle = true;
 602                    }
 603                    if !configure.fullscreen && !configure.maximized {
 604                        configure.size = if got_unmaximized {
 605                            Some(state.window_bounds.size)
 606                        } else {
 607                            compute_outer_size(state.inset(), configure.size, state.tiling)
 608                        };
 609                        if let Some(size) = configure.size {
 610                            state.window_bounds = Bounds {
 611                                origin: Point::default(),
 612                                size,
 613                            };
 614                        }
 615                    }
 616                    drop(state);
 617                    if let Some(size) = configure.size {
 618                        self.resize(size);
 619                    }
 620                }
 621            }
 622            let mut state = self.state.borrow_mut();
 623            state.surface_state.ack_configure(serial);
 624
 625            let window_geometry = inset_by_tiling(
 626                state.bounds.map_origin(|_| px(0.0)),
 627                state.inset(),
 628                state.tiling,
 629            )
 630            .map(|v| v.0 as i32)
 631            .map_size(|v| if v <= 0 { 1 } else { v });
 632
 633            state.surface_state.set_geometry(
 634                window_geometry.origin.x,
 635                window_geometry.origin.y,
 636                window_geometry.size.width,
 637                window_geometry.size.height,
 638            );
 639
 640            let request_frame_callback = !state.acknowledged_first_configure;
 641            if request_frame_callback {
 642                state.acknowledged_first_configure = true;
 643                drop(state);
 644                self.frame();
 645            }
 646        }
 647    }
 648
 649    pub fn handle_toplevel_decoration_event(&self, event: zxdg_toplevel_decoration_v1::Event) {
 650        if let zxdg_toplevel_decoration_v1::Event::Configure { mode } = event {
 651            match mode {
 652                WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ServerSide) => {
 653                    self.state.borrow_mut().decorations = WindowDecorations::Server;
 654                    if let Some(mut appearance_changed) =
 655                        self.callbacks.borrow_mut().appearance_changed.as_mut()
 656                    {
 657                        appearance_changed();
 658                    }
 659                }
 660                WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ClientSide) => {
 661                    self.state.borrow_mut().decorations = WindowDecorations::Client;
 662                    // Update background to be transparent
 663                    if let Some(mut appearance_changed) =
 664                        self.callbacks.borrow_mut().appearance_changed.as_mut()
 665                    {
 666                        appearance_changed();
 667                    }
 668                }
 669                WEnum::Value(_) => {
 670                    log::warn!("Unknown decoration mode");
 671                }
 672                WEnum::Unknown(v) => {
 673                    log::warn!("Unknown decoration mode: {}", v);
 674                }
 675            }
 676        }
 677    }
 678
 679    pub fn handle_fractional_scale_event(&self, event: wp_fractional_scale_v1::Event) {
 680        if let wp_fractional_scale_v1::Event::PreferredScale { scale } = event {
 681            self.rescale(scale as f32 / 120.0);
 682        }
 683    }
 684
 685    pub fn handle_toplevel_event(&self, event: xdg_toplevel::Event) -> bool {
 686        match event {
 687            xdg_toplevel::Event::Configure {
 688                width,
 689                height,
 690                states,
 691            } => {
 692                let mut size = if width == 0 || height == 0 {
 693                    None
 694                } else {
 695                    Some(size(px(width as f32), px(height as f32)))
 696                };
 697
 698                let states = extract_states::<xdg_toplevel::State>(&states);
 699
 700                let mut tiling = Tiling::default();
 701                let mut fullscreen = false;
 702                let mut maximized = false;
 703                let mut resizing = false;
 704
 705                for state in states {
 706                    match state {
 707                        xdg_toplevel::State::Maximized => {
 708                            maximized = true;
 709                        }
 710                        xdg_toplevel::State::Fullscreen => {
 711                            fullscreen = true;
 712                        }
 713                        xdg_toplevel::State::Resizing => resizing = true,
 714                        xdg_toplevel::State::TiledTop => {
 715                            tiling.top = true;
 716                        }
 717                        xdg_toplevel::State::TiledLeft => {
 718                            tiling.left = true;
 719                        }
 720                        xdg_toplevel::State::TiledRight => {
 721                            tiling.right = true;
 722                        }
 723                        xdg_toplevel::State::TiledBottom => {
 724                            tiling.bottom = true;
 725                        }
 726                        _ => {
 727                            // noop
 728                        }
 729                    }
 730                }
 731
 732                if fullscreen || maximized {
 733                    tiling = Tiling::tiled();
 734                }
 735
 736                let mut state = self.state.borrow_mut();
 737                state.in_progress_configure = Some(InProgressConfigure {
 738                    size,
 739                    fullscreen,
 740                    maximized,
 741                    resizing,
 742                    tiling,
 743                });
 744
 745                false
 746            }
 747            xdg_toplevel::Event::Close => {
 748                let mut cb = self.callbacks.borrow_mut();
 749                if let Some(mut should_close) = cb.should_close.take() {
 750                    let result = (should_close)();
 751                    cb.should_close = Some(should_close);
 752                    if result {
 753                        drop(cb);
 754                        self.close();
 755                    }
 756                    result
 757                } else {
 758                    true
 759                }
 760            }
 761            xdg_toplevel::Event::WmCapabilities { capabilities } => {
 762                let mut window_controls = WindowControls::default();
 763
 764                let states = extract_states::<xdg_toplevel::WmCapabilities>(&capabilities);
 765
 766                for state in states {
 767                    match state {
 768                        xdg_toplevel::WmCapabilities::Maximize => {
 769                            window_controls.maximize = true;
 770                        }
 771                        xdg_toplevel::WmCapabilities::Minimize => {
 772                            window_controls.minimize = true;
 773                        }
 774                        xdg_toplevel::WmCapabilities::Fullscreen => {
 775                            window_controls.fullscreen = true;
 776                        }
 777                        xdg_toplevel::WmCapabilities::WindowMenu => {
 778                            window_controls.window_menu = true;
 779                        }
 780                        _ => {}
 781                    }
 782                }
 783
 784                let mut state = self.state.borrow_mut();
 785                state.in_progress_window_controls = Some(window_controls);
 786                false
 787            }
 788            _ => false,
 789        }
 790    }
 791
 792    pub fn handle_layersurface_event(&self, event: zwlr_layer_surface_v1::Event) -> bool {
 793        match event {
 794            zwlr_layer_surface_v1::Event::Configure {
 795                width,
 796                height,
 797                serial,
 798            } => {
 799                let mut size = if width == 0 || height == 0 {
 800                    None
 801                } else {
 802                    Some(size(px(width as f32), px(height as f32)))
 803                };
 804
 805                let mut state = self.state.borrow_mut();
 806                state.in_progress_configure = Some(InProgressConfigure {
 807                    size,
 808                    fullscreen: false,
 809                    maximized: false,
 810                    resizing: false,
 811                    tiling: Tiling::default(),
 812                });
 813                drop(state);
 814
 815                // just do the same thing we'd do as an xdg_surface
 816                self.handle_xdg_surface_event(xdg_surface::Event::Configure { serial });
 817
 818                false
 819            }
 820            zwlr_layer_surface_v1::Event::Closed => {
 821                // unlike xdg, we don't have a choice here: the surface is closing.
 822                true
 823            }
 824            _ => false,
 825        }
 826    }
 827
 828    #[allow(clippy::mutable_key_type)]
 829    pub fn handle_surface_event(
 830        &self,
 831        event: wl_surface::Event,
 832        outputs: HashMap<ObjectId, Output>,
 833    ) {
 834        let mut state = self.state.borrow_mut();
 835
 836        match event {
 837            wl_surface::Event::Enter { output } => {
 838                let id = output.id();
 839
 840                let Some(output) = outputs.get(&id) else {
 841                    return;
 842                };
 843
 844                state.outputs.insert(id, output.clone());
 845
 846                let scale = state.primary_output_scale();
 847
 848                // We use `PreferredBufferScale` instead to set the scale if it's available
 849                if state.surface.version() < wl_surface::EVT_PREFERRED_BUFFER_SCALE_SINCE {
 850                    state.surface.set_buffer_scale(scale);
 851                    drop(state);
 852                    self.rescale(scale as f32);
 853                }
 854            }
 855            wl_surface::Event::Leave { output } => {
 856                state.outputs.remove(&output.id());
 857
 858                let scale = state.primary_output_scale();
 859
 860                // We use `PreferredBufferScale` instead to set the scale if it's available
 861                if state.surface.version() < wl_surface::EVT_PREFERRED_BUFFER_SCALE_SINCE {
 862                    state.surface.set_buffer_scale(scale);
 863                    drop(state);
 864                    self.rescale(scale as f32);
 865                }
 866            }
 867            wl_surface::Event::PreferredBufferScale { factor } => {
 868                // We use `WpFractionalScale` instead to set the scale if it's available
 869                if state.globals.fractional_scale_manager.is_none() {
 870                    state.surface.set_buffer_scale(factor);
 871                    drop(state);
 872                    self.rescale(factor as f32);
 873                }
 874            }
 875            _ => {}
 876        }
 877    }
 878
 879    pub fn handle_ime(&self, ime: ImeInput) {
 880        if self.is_blocked() {
 881            return;
 882        }
 883        let mut state = self.state.borrow_mut();
 884        if let Some(mut input_handler) = state.input_handler.take() {
 885            drop(state);
 886            match ime {
 887                ImeInput::InsertText(text) => {
 888                    input_handler.replace_text_in_range(None, &text);
 889                }
 890                ImeInput::SetMarkedText(text) => {
 891                    input_handler.replace_and_mark_text_in_range(None, &text, None);
 892                }
 893                ImeInput::UnmarkText => {
 894                    input_handler.unmark_text();
 895                }
 896                ImeInput::DeleteText => {
 897                    if let Some(marked) = input_handler.marked_text_range() {
 898                        input_handler.replace_text_in_range(Some(marked), "");
 899                    }
 900                }
 901            }
 902            self.state.borrow_mut().input_handler = Some(input_handler);
 903        }
 904    }
 905
 906    pub fn get_ime_area(&self) -> Option<Bounds<Pixels>> {
 907        let mut state = self.state.borrow_mut();
 908        let mut bounds: Option<Bounds<Pixels>> = None;
 909        if let Some(mut input_handler) = state.input_handler.take() {
 910            drop(state);
 911            if let Some(selection) = input_handler.marked_text_range() {
 912                bounds = input_handler.bounds_for_range(selection.start..selection.start);
 913            }
 914            self.state.borrow_mut().input_handler = Some(input_handler);
 915        }
 916        bounds
 917    }
 918
 919    pub fn set_size_and_scale(&self, size: Option<Size<Pixels>>, scale: Option<f32>) {
 920        let (size, scale) = {
 921            let mut state = self.state.borrow_mut();
 922            if size.is_none_or(|size| size == state.bounds.size)
 923                && scale.is_none_or(|scale| scale == state.scale)
 924            {
 925                return;
 926            }
 927            if let Some(size) = size {
 928                state.bounds.size = size;
 929            }
 930            if let Some(scale) = scale {
 931                state.scale = scale;
 932            }
 933            let device_bounds = state.bounds.to_device_pixels(state.scale);
 934            state.renderer.update_drawable_size(device_bounds.size);
 935            (state.bounds.size, state.scale)
 936        };
 937
 938        if let Some(ref mut fun) = self.callbacks.borrow_mut().resize {
 939            fun(size, scale);
 940        }
 941
 942        {
 943            let state = self.state.borrow();
 944            if let Some(viewport) = &state.viewport {
 945                viewport.set_destination(size.width.0 as i32, size.height.0 as i32);
 946            }
 947        }
 948    }
 949
 950    pub fn resize(&self, size: Size<Pixels>) {
 951        self.set_size_and_scale(Some(size), None);
 952    }
 953
 954    pub fn rescale(&self, scale: f32) {
 955        self.set_size_and_scale(None, Some(scale));
 956    }
 957
 958    pub fn close(&self) {
 959        let state = self.state.borrow();
 960        let client = state.client.get_client();
 961        #[allow(clippy::mutable_key_type)]
 962        let children = state.children.clone();
 963        drop(state);
 964
 965        for child in children {
 966            let mut client_state = client.borrow_mut();
 967            let window = get_window(&mut client_state, &child);
 968            drop(client_state);
 969
 970            if let Some(child) = window {
 971                child.close();
 972            }
 973        }
 974        let mut callbacks = self.callbacks.borrow_mut();
 975        if let Some(fun) = callbacks.close.take() {
 976            fun()
 977        }
 978    }
 979
 980    pub fn handle_input(&self, input: PlatformInput) {
 981        if self.is_blocked() {
 982            return;
 983        }
 984        if let Some(ref mut fun) = self.callbacks.borrow_mut().input
 985            && !fun(input.clone()).propagate
 986        {
 987            return;
 988        }
 989        if let PlatformInput::KeyDown(event) = input
 990            && event.keystroke.modifiers.is_subset_of(&Modifiers::shift())
 991            && let Some(key_char) = &event.keystroke.key_char
 992        {
 993            let mut state = self.state.borrow_mut();
 994            if let Some(mut input_handler) = state.input_handler.take() {
 995                drop(state);
 996                input_handler.replace_text_in_range(None, key_char);
 997                self.state.borrow_mut().input_handler = Some(input_handler);
 998            }
 999        }
1000    }
1001
1002    pub fn set_focused(&self, focus: bool) {
1003        self.state.borrow_mut().active = focus;
1004        if let Some(ref mut fun) = self.callbacks.borrow_mut().active_status_change {
1005            fun(focus);
1006        }
1007    }
1008
1009    pub fn set_hovered(&self, focus: bool) {
1010        if let Some(ref mut fun) = self.callbacks.borrow_mut().hover_status_change {
1011            fun(focus);
1012        }
1013    }
1014
1015    pub fn set_appearance(&mut self, appearance: WindowAppearance) {
1016        self.state.borrow_mut().appearance = appearance;
1017
1018        let mut callbacks = self.callbacks.borrow_mut();
1019        if let Some(ref mut fun) = callbacks.appearance_changed {
1020            (fun)()
1021        }
1022    }
1023
1024    pub fn primary_output_scale(&self) -> i32 {
1025        self.state.borrow_mut().primary_output_scale()
1026    }
1027}
1028
1029fn extract_states<'a, S: TryFrom<u32> + 'a>(states: &'a [u8]) -> impl Iterator<Item = S> + 'a
1030where
1031    <S as TryFrom<u32>>::Error: 'a,
1032{
1033    states
1034        .chunks_exact(4)
1035        .flat_map(TryInto::<[u8; 4]>::try_into)
1036        .map(u32::from_ne_bytes)
1037        .flat_map(S::try_from)
1038}
1039
1040impl rwh::HasWindowHandle for WaylandWindow {
1041    fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> {
1042        let surface = self.0.surface().id().as_ptr() as *mut libc::c_void;
1043        let c_ptr = NonNull::new(surface).ok_or(rwh::HandleError::Unavailable)?;
1044        let handle = rwh::WaylandWindowHandle::new(c_ptr);
1045        let raw_handle = rwh::RawWindowHandle::Wayland(handle);
1046        Ok(unsafe { rwh::WindowHandle::borrow_raw(raw_handle) })
1047    }
1048}
1049
1050impl rwh::HasDisplayHandle for WaylandWindow {
1051    fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> {
1052        let display = self
1053            .0
1054            .surface()
1055            .backend()
1056            .upgrade()
1057            .ok_or(rwh::HandleError::Unavailable)?
1058            .display_ptr() as *mut libc::c_void;
1059
1060        let c_ptr = NonNull::new(display).ok_or(rwh::HandleError::Unavailable)?;
1061        let handle = rwh::WaylandDisplayHandle::new(c_ptr);
1062        let raw_handle = rwh::RawDisplayHandle::Wayland(handle);
1063        Ok(unsafe { rwh::DisplayHandle::borrow_raw(raw_handle) })
1064    }
1065}
1066
1067impl PlatformWindow for WaylandWindow {
1068    fn bounds(&self) -> Bounds<Pixels> {
1069        self.borrow().bounds
1070    }
1071
1072    fn is_maximized(&self) -> bool {
1073        self.borrow().maximized
1074    }
1075
1076    fn window_bounds(&self) -> WindowBounds {
1077        let state = self.borrow();
1078        if state.fullscreen {
1079            WindowBounds::Fullscreen(state.window_bounds)
1080        } else if state.maximized {
1081            WindowBounds::Maximized(state.window_bounds)
1082        } else {
1083            drop(state);
1084            WindowBounds::Windowed(self.bounds())
1085        }
1086    }
1087
1088    fn inner_window_bounds(&self) -> WindowBounds {
1089        let state = self.borrow();
1090        if state.fullscreen {
1091            WindowBounds::Fullscreen(state.window_bounds)
1092        } else if state.maximized {
1093            WindowBounds::Maximized(state.window_bounds)
1094        } else {
1095            let inset = state.inset();
1096            drop(state);
1097            WindowBounds::Windowed(self.bounds().inset(inset))
1098        }
1099    }
1100
1101    fn content_size(&self) -> Size<Pixels> {
1102        self.borrow().bounds.size
1103    }
1104
1105    fn resize(&mut self, size: Size<Pixels>) {
1106        let state = self.borrow();
1107        let state_ptr = self.0.clone();
1108
1109        // Keep window geometry consistent with configure handling. On Wayland, window geometry is
1110        // surface-local: resizing should not attempt to translate the window; the compositor
1111        // controls placement. We also account for client-side decoration insets and tiling.
1112        let window_geometry = inset_by_tiling(
1113            Bounds {
1114                origin: Point::default(),
1115                size,
1116            },
1117            state.inset(),
1118            state.tiling,
1119        )
1120        .map(|v| v.0 as i32)
1121        .map_size(|v| if v <= 0 { 1 } else { v });
1122
1123        state.surface_state.set_geometry(
1124            window_geometry.origin.x,
1125            window_geometry.origin.y,
1126            window_geometry.size.width,
1127            window_geometry.size.height,
1128        );
1129
1130        state
1131            .globals
1132            .executor
1133            .spawn(async move { state_ptr.resize(size) })
1134            .detach();
1135    }
1136
1137    fn scale_factor(&self) -> f32 {
1138        self.borrow().scale
1139    }
1140
1141    fn appearance(&self) -> WindowAppearance {
1142        self.borrow().appearance
1143    }
1144
1145    fn display(&self) -> Option<Rc<dyn PlatformDisplay>> {
1146        let state = self.borrow();
1147        state.display.as_ref().map(|(id, display)| {
1148            Rc::new(WaylandDisplay {
1149                id: id.clone(),
1150                name: display.name.clone(),
1151                bounds: display.bounds.to_pixels(state.scale),
1152            }) as Rc<dyn PlatformDisplay>
1153        })
1154    }
1155
1156    fn mouse_position(&self) -> Point<Pixels> {
1157        self.borrow()
1158            .client
1159            .get_client()
1160            .borrow()
1161            .mouse_location
1162            .unwrap_or_default()
1163    }
1164
1165    fn modifiers(&self) -> Modifiers {
1166        self.borrow().client.get_client().borrow().modifiers
1167    }
1168
1169    fn capslock(&self) -> Capslock {
1170        self.borrow().client.get_client().borrow().capslock
1171    }
1172
1173    fn set_input_handler(&mut self, input_handler: PlatformInputHandler) {
1174        self.borrow_mut().input_handler = Some(input_handler);
1175    }
1176
1177    fn take_input_handler(&mut self) -> Option<PlatformInputHandler> {
1178        self.borrow_mut().input_handler.take()
1179    }
1180
1181    fn prompt(
1182        &self,
1183        _level: PromptLevel,
1184        _msg: &str,
1185        _detail: Option<&str>,
1186        _answers: &[PromptButton],
1187    ) -> Option<Receiver<usize>> {
1188        None
1189    }
1190
1191    fn activate(&self) {
1192        // Try to request an activation token. Even though the activation is likely going to be rejected,
1193        // KWin and Mutter can use the app_id to visually indicate we're requesting attention.
1194        let state = self.borrow();
1195        if let (Some(activation), Some(app_id)) = (&state.globals.activation, state.app_id.clone())
1196        {
1197            state.client.set_pending_activation(state.surface.id());
1198            let token = activation.get_activation_token(&state.globals.qh, ());
1199            // The serial isn't exactly important here, since the activation is probably going to be rejected anyway.
1200            let serial = state.client.get_serial(SerialKind::MousePress);
1201            token.set_app_id(app_id);
1202            token.set_serial(serial, &state.globals.seat);
1203            token.set_surface(&state.surface);
1204            token.commit();
1205        }
1206    }
1207
1208    fn is_active(&self) -> bool {
1209        self.borrow().active
1210    }
1211
1212    fn is_hovered(&self) -> bool {
1213        self.borrow().hovered
1214    }
1215
1216    fn set_title(&mut self, title: &str) {
1217        if let Some(toplevel) = self.borrow().surface_state.toplevel() {
1218            toplevel.set_title(title.to_string());
1219        }
1220    }
1221
1222    fn set_app_id(&mut self, app_id: &str) {
1223        let mut state = self.borrow_mut();
1224        if let Some(toplevel) = state.surface_state.toplevel() {
1225            toplevel.set_app_id(app_id.to_owned());
1226        }
1227        state.app_id = Some(app_id.to_owned());
1228    }
1229
1230    fn set_background_appearance(&self, background_appearance: WindowBackgroundAppearance) {
1231        let mut state = self.borrow_mut();
1232        state.background_appearance = background_appearance;
1233        update_window(state);
1234    }
1235
1236    fn background_appearance(&self) -> WindowBackgroundAppearance {
1237        self.borrow().background_appearance
1238    }
1239
1240    fn is_subpixel_rendering_supported(&self) -> bool {
1241        let client = self.borrow().client.get_client();
1242        let state = client.borrow();
1243        state
1244            .gpu_context
1245            .as_ref()
1246            .is_some_and(|ctx| ctx.supports_dual_source_blending())
1247    }
1248
1249    fn minimize(&self) {
1250        if let Some(toplevel) = self.borrow().surface_state.toplevel() {
1251            toplevel.set_minimized();
1252        }
1253    }
1254
1255    fn zoom(&self) {
1256        let state = self.borrow();
1257        if let Some(toplevel) = state.surface_state.toplevel() {
1258            if !state.maximized {
1259                toplevel.set_maximized();
1260            } else {
1261                toplevel.unset_maximized();
1262            }
1263        }
1264    }
1265
1266    fn toggle_fullscreen(&self) {
1267        let mut state = self.borrow();
1268        if let Some(toplevel) = state.surface_state.toplevel() {
1269            if !state.fullscreen {
1270                toplevel.set_fullscreen(None);
1271            } else {
1272                toplevel.unset_fullscreen();
1273            }
1274        }
1275    }
1276
1277    fn is_fullscreen(&self) -> bool {
1278        self.borrow().fullscreen
1279    }
1280
1281    fn on_request_frame(&self, callback: Box<dyn FnMut(RequestFrameOptions)>) {
1282        self.0.callbacks.borrow_mut().request_frame = Some(callback);
1283    }
1284
1285    fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> crate::DispatchEventResult>) {
1286        self.0.callbacks.borrow_mut().input = Some(callback);
1287    }
1288
1289    fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
1290        self.0.callbacks.borrow_mut().active_status_change = Some(callback);
1291    }
1292
1293    fn on_hover_status_change(&self, callback: Box<dyn FnMut(bool)>) {
1294        self.0.callbacks.borrow_mut().hover_status_change = Some(callback);
1295    }
1296
1297    fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
1298        self.0.callbacks.borrow_mut().resize = Some(callback);
1299    }
1300
1301    fn on_moved(&self, callback: Box<dyn FnMut()>) {
1302        self.0.callbacks.borrow_mut().moved = Some(callback);
1303    }
1304
1305    fn on_should_close(&self, callback: Box<dyn FnMut() -> bool>) {
1306        self.0.callbacks.borrow_mut().should_close = Some(callback);
1307    }
1308
1309    fn on_close(&self, callback: Box<dyn FnOnce()>) {
1310        self.0.callbacks.borrow_mut().close = Some(callback);
1311    }
1312
1313    fn on_hit_test_window_control(&self, _callback: Box<dyn FnMut() -> Option<WindowControlArea>>) {
1314    }
1315
1316    fn on_appearance_changed(&self, callback: Box<dyn FnMut()>) {
1317        self.0.callbacks.borrow_mut().appearance_changed = Some(callback);
1318    }
1319
1320    fn draw(&self, scene: &Scene) {
1321        let mut state = self.borrow_mut();
1322        state.renderer.draw(scene);
1323    }
1324
1325    fn completed_frame(&self) {
1326        let state = self.borrow();
1327        state.surface.commit();
1328    }
1329
1330    fn sprite_atlas(&self) -> Arc<dyn PlatformAtlas> {
1331        let state = self.borrow();
1332        state.renderer.sprite_atlas().clone()
1333    }
1334
1335    fn show_window_menu(&self, position: Point<Pixels>) {
1336        let state = self.borrow();
1337        let serial = state.client.get_serial(SerialKind::MousePress);
1338        if let Some(toplevel) = state.surface_state.toplevel() {
1339            toplevel.show_window_menu(
1340                &state.globals.seat,
1341                serial,
1342                position.x.0 as i32,
1343                position.y.0 as i32,
1344            );
1345        }
1346    }
1347
1348    fn start_window_move(&self) {
1349        let state = self.borrow();
1350        let serial = state.client.get_serial(SerialKind::MousePress);
1351        if let Some(toplevel) = state.surface_state.toplevel() {
1352            toplevel._move(&state.globals.seat, serial);
1353        }
1354    }
1355
1356    fn start_window_resize(&self, edge: crate::ResizeEdge) {
1357        let state = self.borrow();
1358        if let Some(toplevel) = state.surface_state.toplevel() {
1359            toplevel.resize(
1360                &state.globals.seat,
1361                state.client.get_serial(SerialKind::MousePress),
1362                edge.to_xdg(),
1363            )
1364        }
1365    }
1366
1367    fn window_decorations(&self) -> Decorations {
1368        let state = self.borrow();
1369        match state.decorations {
1370            WindowDecorations::Server => Decorations::Server,
1371            WindowDecorations::Client => Decorations::Client {
1372                tiling: state.tiling,
1373            },
1374        }
1375    }
1376
1377    fn request_decorations(&self, decorations: WindowDecorations) {
1378        let mut state = self.borrow_mut();
1379        match state.surface_state.decoration().as_ref() {
1380            Some(decoration) => {
1381                decoration.set_mode(decorations.to_xdg());
1382                state.decorations = decorations;
1383                update_window(state);
1384            }
1385            None => {
1386                if matches!(decorations, WindowDecorations::Server) {
1387                    log::info!(
1388                        "Server-side decorations requested, but the Wayland server does not support them. Falling back to client-side decorations."
1389                    );
1390                }
1391                state.decorations = WindowDecorations::Client;
1392                update_window(state);
1393            }
1394        }
1395    }
1396
1397    fn window_controls(&self) -> WindowControls {
1398        self.borrow().window_controls
1399    }
1400
1401    fn set_client_inset(&self, inset: Pixels) {
1402        let mut state = self.borrow_mut();
1403        if Some(inset) != state.client_inset {
1404            state.client_inset = Some(inset);
1405            update_window(state);
1406        }
1407    }
1408
1409    fn update_ime_position(&self, bounds: Bounds<Pixels>) {
1410        let state = self.borrow();
1411        state.client.update_ime_position(bounds);
1412    }
1413
1414    fn gpu_specs(&self) -> Option<GpuSpecs> {
1415        self.borrow().renderer.gpu_specs().into()
1416    }
1417}
1418
1419fn update_window(mut state: RefMut<WaylandWindowState>) {
1420    let opaque = !state.is_transparent();
1421
1422    state.renderer.update_transparency(!opaque);
1423    let mut opaque_area = state.window_bounds.map(|v| v.0 as i32);
1424    opaque_area.inset(state.inset().0 as i32);
1425
1426    let region = state
1427        .globals
1428        .compositor
1429        .create_region(&state.globals.qh, ());
1430    region.add(
1431        opaque_area.origin.x,
1432        opaque_area.origin.y,
1433        opaque_area.size.width,
1434        opaque_area.size.height,
1435    );
1436
1437    // Note that rounded corners make this rectangle API hard to work with.
1438    // As this is common when using CSD, let's just disable this API.
1439    if state.background_appearance == WindowBackgroundAppearance::Opaque
1440        && state.decorations == WindowDecorations::Server
1441    {
1442        // Promise the compositor that this region of the window surface
1443        // contains no transparent pixels. This allows the compositor to skip
1444        // updating whatever is behind the surface for better performance.
1445        state.surface.set_opaque_region(Some(&region));
1446    } else {
1447        state.surface.set_opaque_region(None);
1448    }
1449
1450    if let Some(ref blur_manager) = state.globals.blur_manager {
1451        if state.background_appearance == WindowBackgroundAppearance::Blurred {
1452            if state.blur.is_none() {
1453                let blur = blur_manager.create(&state.surface, &state.globals.qh, ());
1454                state.blur = Some(blur);
1455            }
1456            state.blur.as_ref().unwrap().commit();
1457        } else {
1458            // It probably doesn't hurt to clear the blur for opaque windows
1459            blur_manager.unset(&state.surface);
1460            if let Some(b) = state.blur.take() {
1461                b.release()
1462            }
1463        }
1464    }
1465
1466    region.destroy();
1467}
1468
1469impl WindowDecorations {
1470    fn to_xdg(self) -> zxdg_toplevel_decoration_v1::Mode {
1471        match self {
1472            WindowDecorations::Client => zxdg_toplevel_decoration_v1::Mode::ClientSide,
1473            WindowDecorations::Server => zxdg_toplevel_decoration_v1::Mode::ServerSide,
1474        }
1475    }
1476}
1477
1478impl ResizeEdge {
1479    fn to_xdg(self) -> xdg_toplevel::ResizeEdge {
1480        match self {
1481            ResizeEdge::Top => xdg_toplevel::ResizeEdge::Top,
1482            ResizeEdge::TopRight => xdg_toplevel::ResizeEdge::TopRight,
1483            ResizeEdge::Right => xdg_toplevel::ResizeEdge::Right,
1484            ResizeEdge::BottomRight => xdg_toplevel::ResizeEdge::BottomRight,
1485            ResizeEdge::Bottom => xdg_toplevel::ResizeEdge::Bottom,
1486            ResizeEdge::BottomLeft => xdg_toplevel::ResizeEdge::BottomLeft,
1487            ResizeEdge::Left => xdg_toplevel::ResizeEdge::Left,
1488            ResizeEdge::TopLeft => xdg_toplevel::ResizeEdge::TopLeft,
1489        }
1490    }
1491}
1492
1493/// The configuration event is in terms of the window geometry, which we are constantly
1494/// updating to account for the client decorations. But that's not the area we want to render
1495/// to, due to our intrusize CSD. So, here we calculate the 'actual' size, by adding back in the insets
1496fn compute_outer_size(
1497    inset: Pixels,
1498    new_size: Option<Size<Pixels>>,
1499    tiling: Tiling,
1500) -> Option<Size<Pixels>> {
1501    new_size.map(|mut new_size| {
1502        if !tiling.top {
1503            new_size.height += inset;
1504        }
1505        if !tiling.bottom {
1506            new_size.height += inset;
1507        }
1508        if !tiling.left {
1509            new_size.width += inset;
1510        }
1511        if !tiling.right {
1512            new_size.width += inset;
1513        }
1514
1515        new_size
1516    })
1517}
1518
1519fn inset_by_tiling(mut bounds: Bounds<Pixels>, inset: Pixels, tiling: Tiling) -> Bounds<Pixels> {
1520    if !tiling.top {
1521        bounds.origin.y += inset;
1522        bounds.size.height -= inset;
1523    }
1524    if !tiling.bottom {
1525        bounds.size.height -= inset;
1526    }
1527    if !tiling.left {
1528        bounds.origin.x += inset;
1529        bounds.size.width -= inset;
1530    }
1531    if !tiling.right {
1532        bounds.size.width -= inset;
1533    }
1534
1535    bounds
1536}