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