window.rs

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