gpui: Implement support for wlr layer shell (#32651)
I was interested in potentially using gpui for a hobby project, but needed [layer shell](https://wayland.app/protocols/wlr-layer-shell-unstable-v1) support for it. Turns out gpui's (excellent!) architecture made that super easy to implement, so I went ahead and did it. Layer shell is a window role used for notification windows, lock screens, docks, backgrounds, etc. Supporting it in gpui opens the door to implementing applications like that using the framework. If this turns out interesting enough to merge - I'm also happy to provide a follow-up PR (when I have the time to) to implement some of the desirable window options for layer shell surfaces, such as: - namespace (currently always `""`) - keyboard interactivity (currently always `OnDemand`, which mimics normal keyboard interactivity) - anchor, exclusive zone, margins - popups Release Notes: - Added support for wayland layer shell surfaces in gpui --------- Co-authored-by: Mikayla Maki <mikayla.c.maki@gmail.com>
This commit is contained in:
parent
85b712c04e
commit
c110f78015
6 changed files with 296 additions and 78 deletions
38
Cargo.lock
generated
38
Cargo.lock
generated
|
@ -7354,8 +7354,9 @@ dependencies = [
|
|||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
"wayland-protocols 0.31.2",
|
||||
"wayland-protocols-plasma",
|
||||
"wayland-protocols-wlr",
|
||||
"windows 0.61.1",
|
||||
"windows-core 0.61.0",
|
||||
"windows-numerics",
|
||||
|
@ -18369,9 +18370,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wayland-backend"
|
||||
version = "0.3.8"
|
||||
version = "0.3.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b7208998eaa3870dad37ec8836979581506e0c5c64c20c9e79e9d2a10d6f47bf"
|
||||
checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"downcast-rs",
|
||||
|
@ -18383,9 +18384,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wayland-client"
|
||||
version = "0.31.8"
|
||||
version = "0.31.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f"
|
||||
checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"rustix 0.38.44",
|
||||
|
@ -18416,6 +18417,18 @@ dependencies = [
|
|||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols"
|
||||
version = "0.32.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols-plasma"
|
||||
version = "0.2.0"
|
||||
|
@ -18425,7 +18438,20 @@ dependencies = [
|
|||
"bitflags 2.9.0",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-protocols",
|
||||
"wayland-protocols 0.31.2",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-protocols-wlr"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cb6cdc73399c0e06504c437fe3cf886f25568dd5454473d565085b36d6a8bbf"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"wayland-backend",
|
||||
"wayland-client",
|
||||
"wayland-protocols 0.32.8",
|
||||
"wayland-scanner",
|
||||
]
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ wayland = [
|
|||
"wayland-cursor",
|
||||
"wayland-protocols",
|
||||
"wayland-protocols-plasma",
|
||||
"wayland-protocols-wlr",
|
||||
"filedescriptor",
|
||||
"xkbcommon",
|
||||
"open",
|
||||
|
@ -193,6 +194,9 @@ wayland-protocols = { version = "0.31.2", features = [
|
|||
wayland-protocols-plasma = { version = "0.2.0", features = [
|
||||
"client",
|
||||
], optional = true }
|
||||
wayland-protocols-wlr = { version = "0.3.8", features = [
|
||||
"client"
|
||||
], optional = true}
|
||||
|
||||
# X11
|
||||
as-raw-xcb-connection = { version = "1", optional = true }
|
||||
|
|
|
@ -1216,6 +1216,10 @@ pub enum WindowKind {
|
|||
/// A window that appears above all other windows, usually used for alerts or popups
|
||||
/// use sparingly!
|
||||
PopUp,
|
||||
/// An overlay such as a notification window, a launcher, ...
|
||||
///
|
||||
/// Only supported on wayland
|
||||
Overlay,
|
||||
}
|
||||
|
||||
/// The appearance of the window, as defined by the operating system.
|
||||
|
|
|
@ -61,6 +61,7 @@ use wayland_protocols::xdg::decoration::zv1::client::{
|
|||
};
|
||||
use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base};
|
||||
use wayland_protocols_plasma::blur::client::{org_kde_kwin_blur, org_kde_kwin_blur_manager};
|
||||
use wayland_protocols_wlr::layer_shell::v1::client::{zwlr_layer_shell_v1, zwlr_layer_surface_v1};
|
||||
use xkbcommon::xkb::ffi::XKB_KEYMAP_FORMAT_TEXT_V1;
|
||||
use xkbcommon::xkb::{self, KEYMAP_COMPILE_NO_FLAGS, Keycode};
|
||||
|
||||
|
@ -114,6 +115,7 @@ pub struct Globals {
|
|||
pub fractional_scale_manager:
|
||||
Option<wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1>,
|
||||
pub decoration_manager: Option<zxdg_decoration_manager_v1::ZxdgDecorationManagerV1>,
|
||||
pub layer_shell: Option<zwlr_layer_shell_v1::ZwlrLayerShellV1>,
|
||||
pub blur_manager: Option<org_kde_kwin_blur_manager::OrgKdeKwinBlurManager>,
|
||||
pub text_input_manager: Option<zwp_text_input_manager_v3::ZwpTextInputManagerV3>,
|
||||
pub executor: ForegroundExecutor,
|
||||
|
@ -151,6 +153,7 @@ impl Globals {
|
|||
viewporter: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
fractional_scale_manager: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
decoration_manager: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
layer_shell: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
blur_manager: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
text_input_manager: globals.bind(&qh, 1..=1, ()).ok(),
|
||||
executor,
|
||||
|
@ -929,6 +932,7 @@ delegate_noop!(WaylandClientStatePtr: ignore wl_buffer::WlBuffer);
|
|||
delegate_noop!(WaylandClientStatePtr: ignore wl_region::WlRegion);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore zxdg_decoration_manager_v1::ZxdgDecorationManagerV1);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore zwlr_layer_shell_v1::ZwlrLayerShellV1);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore org_kde_kwin_blur_manager::OrgKdeKwinBlurManager);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore zwp_text_input_manager_v3::ZwpTextInputManagerV3);
|
||||
delegate_noop!(WaylandClientStatePtr: ignore org_kde_kwin_blur::OrgKdeKwinBlur);
|
||||
|
@ -1074,6 +1078,31 @@ impl Dispatch<xdg_toplevel::XdgToplevel, ObjectId> for WaylandClientStatePtr {
|
|||
}
|
||||
}
|
||||
|
||||
impl Dispatch<zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, ObjectId> for WaylandClientStatePtr {
|
||||
fn event(
|
||||
this: &mut Self,
|
||||
_: &zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
||||
event: <zwlr_layer_surface_v1::ZwlrLayerSurfaceV1 as Proxy>::Event,
|
||||
surface_id: &ObjectId,
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
let client = this.get_client();
|
||||
let mut state = client.borrow_mut();
|
||||
let Some(window) = get_window(&mut state, surface_id) else {
|
||||
return;
|
||||
};
|
||||
drop(state);
|
||||
|
||||
let should_close = window.handle_layersurface_event(event);
|
||||
|
||||
if should_close {
|
||||
// The close logic will be handled in drop_window()
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<xdg_wm_base::XdgWmBase, ()> for WaylandClientStatePtr {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
use blade_graphics as gpu;
|
||||
use collections::HashMap;
|
||||
use futures::channel::oneshot::Receiver;
|
||||
use std::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
ffi::c_void,
|
||||
|
@ -6,9 +9,14 @@ use std::{
|
|||
sync::Arc,
|
||||
};
|
||||
|
||||
use blade_graphics as gpu;
|
||||
use collections::HashMap;
|
||||
use futures::channel::oneshot::Receiver;
|
||||
use crate::{
|
||||
Capslock,
|
||||
platform::{
|
||||
PlatformAtlas, PlatformInputHandler, PlatformWindow,
|
||||
blade::{BladeContext, BladeRenderer, BladeSurfaceConfig},
|
||||
linux::wayland::{display::WaylandDisplay, serial::SerialKind},
|
||||
},
|
||||
};
|
||||
|
||||
use raw_window_handle as rwh;
|
||||
use wayland_backend::client::ObjectId;
|
||||
|
@ -20,6 +28,8 @@ use wayland_protocols::xdg::decoration::zv1::client::zxdg_toplevel_decoration_v1
|
|||
use wayland_protocols::xdg::shell::client::xdg_surface;
|
||||
use wayland_protocols::xdg::shell::client::xdg_toplevel::{self};
|
||||
use wayland_protocols_plasma::blur::client::org_kde_kwin_blur;
|
||||
use wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::Layer;
|
||||
use wayland_protocols_wlr::layer_shell::v1::client::zwlr_layer_surface_v1;
|
||||
|
||||
use crate::scene::Scene;
|
||||
use crate::{
|
||||
|
@ -27,15 +37,7 @@ use crate::{
|
|||
PlatformDisplay, PlatformInput, Point, PromptButton, PromptLevel, RequestFrameOptions,
|
||||
ResizeEdge, ScaledPixels, Size, Tiling, WaylandClientStatePtr, WindowAppearance,
|
||||
WindowBackgroundAppearance, WindowBounds, WindowControlArea, WindowControls, WindowDecorations,
|
||||
WindowParams, px, size,
|
||||
};
|
||||
use crate::{
|
||||
Capslock,
|
||||
platform::{
|
||||
PlatformAtlas, PlatformInputHandler, PlatformWindow,
|
||||
blade::{BladeContext, BladeRenderer, BladeSurfaceConfig},
|
||||
linux::wayland::{display::WaylandDisplay, serial::SerialKind},
|
||||
},
|
||||
WindowKind, WindowParams, px, size,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -81,14 +83,12 @@ struct InProgressConfigure {
|
|||
}
|
||||
|
||||
pub struct WaylandWindowState {
|
||||
xdg_surface: xdg_surface::XdgSurface,
|
||||
surface_state: WaylandSurfaceState,
|
||||
acknowledged_first_configure: bool,
|
||||
pub surface: wl_surface::WlSurface,
|
||||
decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
|
||||
app_id: Option<String>,
|
||||
appearance: WindowAppearance,
|
||||
blur: Option<org_kde_kwin_blur::OrgKdeKwinBlur>,
|
||||
toplevel: xdg_toplevel::XdgToplevel,
|
||||
viewport: Option<wp_viewport::WpViewport>,
|
||||
outputs: HashMap<ObjectId, Output>,
|
||||
display: Option<(ObjectId, Output)>,
|
||||
|
@ -114,6 +114,78 @@ pub struct WaylandWindowState {
|
|||
client_inset: Option<Pixels>,
|
||||
}
|
||||
|
||||
pub enum WaylandSurfaceState {
|
||||
Xdg(WaylandXdgSurfaceState),
|
||||
LayerShell(WaylandLayerSurfaceState),
|
||||
}
|
||||
|
||||
pub struct WaylandXdgSurfaceState {
|
||||
xdg_surface: xdg_surface::XdgSurface,
|
||||
toplevel: xdg_toplevel::XdgToplevel,
|
||||
decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
|
||||
}
|
||||
|
||||
pub struct WaylandLayerSurfaceState {
|
||||
layer_surface: zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
||||
}
|
||||
|
||||
impl WaylandSurfaceState {
|
||||
fn ack_configure(&self, serial: u32) {
|
||||
match self {
|
||||
WaylandSurfaceState::Xdg(WaylandXdgSurfaceState { xdg_surface, .. }) => {
|
||||
xdg_surface.ack_configure(serial);
|
||||
}
|
||||
WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState { layer_surface, .. }) => {
|
||||
layer_surface.ack_configure(serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decoration(&self) -> Option<&zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1> {
|
||||
if let WaylandSurfaceState::Xdg(WaylandXdgSurfaceState { decoration, .. }) = self {
|
||||
decoration.as_ref()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn toplevel(&self) -> Option<&xdg_toplevel::XdgToplevel> {
|
||||
if let WaylandSurfaceState::Xdg(WaylandXdgSurfaceState { toplevel, .. }) = self {
|
||||
Some(toplevel)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn set_geometry(&self, x: i32, y: i32, width: i32, height: i32) {
|
||||
match self {
|
||||
WaylandSurfaceState::Xdg(WaylandXdgSurfaceState { xdg_surface, .. }) => {
|
||||
xdg_surface.set_window_geometry(x, y, width, height);
|
||||
}
|
||||
WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState { layer_surface, .. }) => {
|
||||
// cannot set window position of a layer surface
|
||||
layer_surface.set_size(width as u32, height as u32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn destroy(&mut self) {
|
||||
match self {
|
||||
WaylandSurfaceState::Xdg(WaylandXdgSurfaceState {
|
||||
xdg_surface,
|
||||
toplevel,
|
||||
decoration: _decoration,
|
||||
}) => {
|
||||
toplevel.destroy();
|
||||
xdg_surface.destroy();
|
||||
}
|
||||
WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState { layer_surface }) => {
|
||||
layer_surface.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct WaylandWindowStatePtr {
|
||||
state: Rc<RefCell<WaylandWindowState>>,
|
||||
|
@ -124,9 +196,7 @@ impl WaylandWindowState {
|
|||
pub(crate) fn new(
|
||||
handle: AnyWindowHandle,
|
||||
surface: wl_surface::WlSurface,
|
||||
xdg_surface: xdg_surface::XdgSurface,
|
||||
toplevel: xdg_toplevel::XdgToplevel,
|
||||
decoration: Option<zxdg_toplevel_decoration_v1::ZxdgToplevelDecorationV1>,
|
||||
surface_state: WaylandSurfaceState,
|
||||
appearance: WindowAppearance,
|
||||
viewport: Option<wp_viewport::WpViewport>,
|
||||
client: WaylandClientStatePtr,
|
||||
|
@ -156,13 +226,11 @@ impl WaylandWindowState {
|
|||
};
|
||||
|
||||
Ok(Self {
|
||||
xdg_surface,
|
||||
surface_state,
|
||||
acknowledged_first_configure: false,
|
||||
surface,
|
||||
decoration,
|
||||
app_id: None,
|
||||
blur: None,
|
||||
toplevel,
|
||||
viewport,
|
||||
globals,
|
||||
outputs: HashMap::default(),
|
||||
|
@ -235,17 +303,16 @@ impl Drop for WaylandWindow {
|
|||
let client = state.client.clone();
|
||||
|
||||
state.renderer.destroy();
|
||||
if let Some(decoration) = &state.decoration {
|
||||
if let Some(decoration) = &state.surface_state.decoration() {
|
||||
decoration.destroy();
|
||||
}
|
||||
if let Some(blur) = &state.blur {
|
||||
blur.release();
|
||||
}
|
||||
state.toplevel.destroy();
|
||||
state.surface_state.destroy();
|
||||
if let Some(viewport) = &state.viewport {
|
||||
viewport.destroy();
|
||||
}
|
||||
state.xdg_surface.destroy();
|
||||
state.surface.destroy();
|
||||
|
||||
let state_ptr = self.0.clone();
|
||||
|
@ -279,27 +346,65 @@ impl WaylandWindow {
|
|||
appearance: WindowAppearance,
|
||||
) -> anyhow::Result<(Self, ObjectId)> {
|
||||
let surface = globals.compositor.create_surface(&globals.qh, ());
|
||||
let xdg_surface = globals
|
||||
.wm_base
|
||||
.get_xdg_surface(&surface, &globals.qh, surface.id());
|
||||
let toplevel = xdg_surface.get_toplevel(&globals.qh, surface.id());
|
||||
|
||||
if let Some(size) = params.window_min_size {
|
||||
toplevel.set_min_size(size.width.0 as i32, size.height.0 as i32);
|
||||
}
|
||||
let surface_state = match (params.kind, globals.layer_shell.as_ref()) {
|
||||
// Matching on layer_shell here means that if kind is Overlay, but the compositor doesn't support layer_shell,
|
||||
// we end up defaulting to xdg_surface anyway
|
||||
(WindowKind::Overlay, Some(layer_shell)) => {
|
||||
let layer_surface = layer_shell.get_layer_surface(
|
||||
&surface,
|
||||
None,
|
||||
Layer::Overlay,
|
||||
"".to_string(),
|
||||
&globals.qh,
|
||||
surface.id(),
|
||||
);
|
||||
|
||||
let width = params.bounds.size.width.0;
|
||||
let height = params.bounds.size.height.0;
|
||||
layer_surface.set_size(width as u32, height as u32);
|
||||
layer_surface.set_keyboard_interactivity(
|
||||
zwlr_layer_surface_v1::KeyboardInteractivity::OnDemand,
|
||||
);
|
||||
|
||||
WaylandSurfaceState::LayerShell(WaylandLayerSurfaceState { layer_surface })
|
||||
}
|
||||
_ => {
|
||||
let xdg_surface =
|
||||
globals
|
||||
.wm_base
|
||||
.get_xdg_surface(&surface, &globals.qh, surface.id());
|
||||
|
||||
let toplevel = xdg_surface.get_toplevel(&globals.qh, surface.id());
|
||||
|
||||
if let Some(size) = params.window_min_size {
|
||||
toplevel.set_min_size(size.width.0 as i32, size.height.0 as i32);
|
||||
}
|
||||
|
||||
// Attempt to set up window decorations based on the requested configuration
|
||||
let decoration = globals
|
||||
.decoration_manager
|
||||
.as_ref()
|
||||
.map(|decoration_manager| {
|
||||
decoration_manager.get_toplevel_decoration(
|
||||
&toplevel,
|
||||
&globals.qh,
|
||||
surface.id(),
|
||||
)
|
||||
});
|
||||
|
||||
WaylandSurfaceState::Xdg(WaylandXdgSurfaceState {
|
||||
xdg_surface,
|
||||
toplevel,
|
||||
decoration,
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(fractional_scale_manager) = globals.fractional_scale_manager.as_ref() {
|
||||
fractional_scale_manager.get_fractional_scale(&surface, &globals.qh, surface.id());
|
||||
}
|
||||
|
||||
// Attempt to set up window decorations based on the requested configuration
|
||||
let decoration = globals
|
||||
.decoration_manager
|
||||
.as_ref()
|
||||
.map(|decoration_manager| {
|
||||
decoration_manager.get_toplevel_decoration(&toplevel, &globals.qh, surface.id())
|
||||
});
|
||||
|
||||
let viewport = globals
|
||||
.viewporter
|
||||
.as_ref()
|
||||
|
@ -309,9 +414,7 @@ impl WaylandWindow {
|
|||
state: Rc::new(RefCell::new(WaylandWindowState::new(
|
||||
handle,
|
||||
surface.clone(),
|
||||
xdg_surface,
|
||||
toplevel,
|
||||
decoration,
|
||||
surface_state,
|
||||
appearance,
|
||||
viewport,
|
||||
client,
|
||||
|
@ -403,7 +506,7 @@ impl WaylandWindowStatePtr {
|
|||
}
|
||||
}
|
||||
let mut state = self.state.borrow_mut();
|
||||
state.xdg_surface.ack_configure(serial);
|
||||
state.surface_state.ack_configure(serial);
|
||||
|
||||
let window_geometry = inset_by_tiling(
|
||||
state.bounds.map_origin(|_| px(0.0)),
|
||||
|
@ -413,7 +516,7 @@ impl WaylandWindowStatePtr {
|
|||
.map(|v| v.0 as i32)
|
||||
.map_size(|v| if v <= 0 { 1 } else { v });
|
||||
|
||||
state.xdg_surface.set_window_geometry(
|
||||
state.surface_state.set_geometry(
|
||||
window_geometry.origin.x,
|
||||
window_geometry.origin.y,
|
||||
window_geometry.size.width,
|
||||
|
@ -578,6 +681,42 @@ impl WaylandWindowStatePtr {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn handle_layersurface_event(&self, event: zwlr_layer_surface_v1::Event) -> bool {
|
||||
match event {
|
||||
zwlr_layer_surface_v1::Event::Configure {
|
||||
width,
|
||||
height,
|
||||
serial,
|
||||
} => {
|
||||
let mut size = if width == 0 || height == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(size(px(width as f32), px(height as f32)))
|
||||
};
|
||||
|
||||
let mut state = self.state.borrow_mut();
|
||||
state.in_progress_configure = Some(InProgressConfigure {
|
||||
size,
|
||||
fullscreen: false,
|
||||
maximized: false,
|
||||
resizing: false,
|
||||
tiling: Tiling::default(),
|
||||
});
|
||||
drop(state);
|
||||
|
||||
// just do the same thing we'd do as an xdg_surface
|
||||
self.handle_xdg_surface_event(xdg_surface::Event::Configure { serial });
|
||||
|
||||
false
|
||||
}
|
||||
zwlr_layer_surface_v1::Event::Closed => {
|
||||
// unlike xdg, we don't have a choice here: the surface is closing.
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::mutable_key_type)]
|
||||
pub fn handle_surface_event(
|
||||
&self,
|
||||
|
@ -840,7 +979,7 @@ impl PlatformWindow for WaylandWindow {
|
|||
let state_ptr = self.0.clone();
|
||||
let dp_size = size.to_device_pixels(self.scale_factor());
|
||||
|
||||
state.xdg_surface.set_window_geometry(
|
||||
state.surface_state.set_geometry(
|
||||
state.bounds.origin.x.0 as i32,
|
||||
state.bounds.origin.y.0 as i32,
|
||||
dp_size.width.0,
|
||||
|
@ -934,12 +1073,16 @@ impl PlatformWindow for WaylandWindow {
|
|||
}
|
||||
|
||||
fn set_title(&mut self, title: &str) {
|
||||
self.borrow().toplevel.set_title(title.to_string());
|
||||
if let Some(toplevel) = self.borrow().surface_state.toplevel() {
|
||||
toplevel.set_title(title.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
fn set_app_id(&mut self, app_id: &str) {
|
||||
let mut state = self.borrow_mut();
|
||||
state.toplevel.set_app_id(app_id.to_owned());
|
||||
if let Some(toplevel) = self.borrow().surface_state.toplevel() {
|
||||
toplevel.set_app_id(app_id.to_owned());
|
||||
}
|
||||
state.app_id = Some(app_id.to_owned());
|
||||
}
|
||||
|
||||
|
@ -950,24 +1093,30 @@ impl PlatformWindow for WaylandWindow {
|
|||
}
|
||||
|
||||
fn minimize(&self) {
|
||||
self.borrow().toplevel.set_minimized();
|
||||
if let Some(toplevel) = self.borrow().surface_state.toplevel() {
|
||||
toplevel.set_minimized();
|
||||
}
|
||||
}
|
||||
|
||||
fn zoom(&self) {
|
||||
let state = self.borrow();
|
||||
if !state.maximized {
|
||||
state.toplevel.set_maximized();
|
||||
} else {
|
||||
state.toplevel.unset_maximized();
|
||||
if let Some(toplevel) = state.surface_state.toplevel() {
|
||||
if !state.maximized {
|
||||
toplevel.set_maximized();
|
||||
} else {
|
||||
toplevel.unset_maximized();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn toggle_fullscreen(&self) {
|
||||
let mut state = self.borrow_mut();
|
||||
if !state.fullscreen {
|
||||
state.toplevel.set_fullscreen(None);
|
||||
} else {
|
||||
state.toplevel.unset_fullscreen();
|
||||
let mut state = self.borrow();
|
||||
if let Some(toplevel) = state.surface_state.toplevel() {
|
||||
if !state.fullscreen {
|
||||
toplevel.set_fullscreen(None);
|
||||
} else {
|
||||
toplevel.unset_fullscreen();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1032,27 +1181,33 @@ impl PlatformWindow for WaylandWindow {
|
|||
fn show_window_menu(&self, position: Point<Pixels>) {
|
||||
let state = self.borrow();
|
||||
let serial = state.client.get_serial(SerialKind::MousePress);
|
||||
state.toplevel.show_window_menu(
|
||||
&state.globals.seat,
|
||||
serial,
|
||||
position.x.0 as i32,
|
||||
position.y.0 as i32,
|
||||
);
|
||||
if let Some(toplevel) = state.surface_state.toplevel() {
|
||||
toplevel.show_window_menu(
|
||||
&state.globals.seat,
|
||||
serial,
|
||||
position.x.0 as i32,
|
||||
position.y.0 as i32,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn start_window_move(&self) {
|
||||
let state = self.borrow();
|
||||
let serial = state.client.get_serial(SerialKind::MousePress);
|
||||
state.toplevel._move(&state.globals.seat, serial);
|
||||
if let Some(toplevel) = state.surface_state.toplevel() {
|
||||
toplevel._move(&state.globals.seat, serial);
|
||||
}
|
||||
}
|
||||
|
||||
fn start_window_resize(&self, edge: crate::ResizeEdge) {
|
||||
let state = self.borrow();
|
||||
state.toplevel.resize(
|
||||
&state.globals.seat,
|
||||
state.client.get_serial(SerialKind::MousePress),
|
||||
edge.to_xdg(),
|
||||
)
|
||||
if let Some(toplevel) = state.surface_state.toplevel() {
|
||||
toplevel.resize(
|
||||
&state.globals.seat,
|
||||
state.client.get_serial(SerialKind::MousePress),
|
||||
edge.to_xdg(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn window_decorations(&self) -> Decorations {
|
||||
|
@ -1068,7 +1223,7 @@ impl PlatformWindow for WaylandWindow {
|
|||
fn request_decorations(&self, decorations: WindowDecorations) {
|
||||
let mut state = self.borrow_mut();
|
||||
state.decorations = decorations;
|
||||
if let Some(decoration) = state.decoration.as_ref() {
|
||||
if let Some(decoration) = state.surface_state.decoration() {
|
||||
decoration.set_mode(decorations.to_xdg());
|
||||
update_window(state);
|
||||
}
|
||||
|
|
|
@ -559,7 +559,7 @@ impl MacWindow {
|
|||
}
|
||||
|
||||
let native_window: id = match kind {
|
||||
WindowKind::Normal => msg_send![WINDOW_CLASS, alloc],
|
||||
WindowKind::Normal | WindowKind::Overlay => msg_send![WINDOW_CLASS, alloc],
|
||||
WindowKind::PopUp => {
|
||||
style_mask |= NSWindowStyleMaskNonactivatingPanel;
|
||||
msg_send![PANEL_CLASS, alloc]
|
||||
|
@ -711,7 +711,7 @@ impl MacWindow {
|
|||
native_window.makeFirstResponder_(native_view);
|
||||
|
||||
match kind {
|
||||
WindowKind::Normal => {
|
||||
WindowKind::Normal | WindowKind::Overlay => {
|
||||
native_window.setLevel_(NSNormalWindowLevel);
|
||||
native_window.setAcceptsMouseMovedEvents_(YES);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue