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