use std::{ cell::{Ref, RefCell, RefMut}, ffi::c_void, ptr::NonNull, rc::Rc, sync::Arc,}; use blade_graphics as gpu;use collections::HashMap;use futures::channel::oneshot::Receiver; use raw_window_handle as rwh;use wayland_backend::client::ObjectId;use wayland_client::WEnum;use wayland_client::{protocol::wl_surface, Proxy};use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1;use wayland_protocols::wp::viewporter::client::wp_viewport;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 crate::platform::{ blade::{BladeContext, BladeRenderer, BladeSurfaceConfig}, linux::wayland::{display::WaylandDisplay, serial::SerialKind}, PlatformAtlas, PlatformInputHandler, PlatformWindow,};use crate::scene::Scene;use crate::{ px, size, AnyWindowHandle, Bounds, Decorations, Globals, GpuSpecs, Modifiers, Output, Pixels, PlatformDisplay, PlatformInput, Point, PromptLevel, RequestFrameOptions, ResizeEdge, ScaledPixels, Size, Tiling, WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControls, WindowDecorations, WindowParams,}; #[derive(Default)]pub(crate) struct Callbacks { request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>, input: Option<Box<dyn FnMut(crate::PlatformInput) -> crate::DispatchEventResult>>, active_status_change: Option<Box<dyn FnMut(bool)>>, hover_status_change: Option<Box<dyn FnMut(bool)>>, resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>, moved: Option<Box<dyn FnMut()>>, should_close: Option<Box<dyn FnMut() -> bool>>, close: Option<Box<dyn FnOnce()>>, appearance_changed: Option<Box<dyn FnMut()>>,} struct RawWindow { window: *mut c_void, display: *mut c_void,} impl rwh::HasWindowHandle for RawWindow { fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> { let window = NonNull::new(self.window).unwrap(); let handle = rwh::WaylandWindowHandle::new(window); Ok(unsafe { rwh::WindowHandle::borrow_raw(handle.into()) }) }}impl rwh::HasDisplayHandle for RawWindow { fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> { let display = NonNull::new(self.display).unwrap(); let handle = rwh::WaylandDisplayHandle::new(display); Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) }) }} #[derive(Debug)]struct InProgressConfigure { size: Option<Size<Pixels>>, fullscreen: bool, maximized: bool, tiling: Tiling,} pub struct WaylandWindowState { xdg_surface: xdg_surface::XdgSurface, 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)>, globals: Globals, renderer: BladeRenderer, bounds: Bounds<Pixels>, scale: f32, input_handler: Option<PlatformInputHandler>, decorations: WindowDecorations, background_appearance: WindowBackgroundAppearance, fullscreen: bool, maximized: bool, tiling: Tiling, window_bounds: Bounds<Pixels>, client: WaylandClientStatePtr, handle: AnyWindowHandle, active: bool, hovered: bool, in_progress_configure: Option<InProgressConfigure>, in_progress_window_controls: Option<WindowControls>, window_controls: WindowControls, inset: Option<Pixels>,} #[derive(Clone)]pub struct WaylandWindowStatePtr { state: Rc<RefCell<WaylandWindowState>>, callbacks: Rc<RefCell<Callbacks>>,} impl WaylandWindowState { #[allow(clippy::too_many_arguments)] 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>, appearance: WindowAppearance, viewport: Option<wp_viewport::WpViewport>, client: WaylandClientStatePtr, globals: Globals, gpu_context: &BladeContext, options: WindowParams, ) -> anyhow::Result<Self> { let renderer = { let raw_window = RawWindow { window: surface.id().as_ptr().cast::<c_void>(), display: surface .backend() .upgrade() .unwrap() .display_ptr() .cast::<c_void>(), }; let config = BladeSurfaceConfig { size: gpu::Extent { width: options.bounds.size.width.0 as u32, height: options.bounds.size.height.0 as u32, depth: 1, }, transparent: true, }; BladeRenderer::new(gpu_context, &raw_window, config)? }; Ok(Self { xdg_surface, acknowledged_first_configure: false, surface, decoration, app_id: None, blur: None, toplevel, viewport, globals, outputs: HashMap::default(), display: None, renderer, bounds: options.bounds, scale: 1.0, input_handler: None, decorations: WindowDecorations::Client, background_appearance: WindowBackgroundAppearance::Opaque, fullscreen: false, maximized: false, tiling: Tiling::default(), window_bounds: options.bounds, in_progress_configure: None, client, appearance, handle, active: false, hovered: false, in_progress_window_controls: None, window_controls: WindowControls::default(), inset: None, }) } pub fn is_transparent(&self) -> bool { self.decorations == WindowDecorations::Client || self.background_appearance != WindowBackgroundAppearance::Opaque } pub fn primary_output_scale(&mut self) -> i32 { let mut scale = 1; let mut current_output = self.display.take(); for (id, output) in self.outputs.iter() { if let Some((_, output_data)) = ¤t_output { if output.scale > output_data.scale { current_output = Some((id.clone(), output.clone())); } } else { current_output = Some((id.clone(), output.clone())); } scale = scale.max(output.scale); } self.display = current_output; scale }} pub(crate) struct WaylandWindow(pub WaylandWindowStatePtr);pub enum ImeInput { InsertText(String), SetMarkedText(String), UnmarkText, DeleteText,} impl Drop for WaylandWindow { fn drop(&mut self) { let mut state = self.0.state.borrow_mut(); let surface_id = state.surface.id(); let client = state.client.clone(); state.renderer.destroy(); if let Some(decoration) = &state.decoration { decoration.destroy(); } if let Some(blur) = &state.blur { blur.release(); } state.toplevel.destroy(); if let Some(viewport) = &state.viewport { viewport.destroy(); } state.xdg_surface.destroy(); state.surface.destroy(); let state_ptr = self.0.clone(); state .globals .executor .spawn(async move { state_ptr.close(); client.drop_window(&surface_id) }) .detach(); drop(state); }} impl WaylandWindow { fn borrow(&self) -> Ref<WaylandWindowState> { self.0.state.borrow() } fn borrow_mut(&self) -> RefMut<WaylandWindowState> { self.0.state.borrow_mut() } pub fn new( handle: AnyWindowHandle, globals: Globals, gpu_context: &BladeContext, client: WaylandClientStatePtr, params: WindowParams, 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); } 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() .map(|viewporter| viewporter.get_viewport(&surface, &globals.qh, ())); let this = Self(WaylandWindowStatePtr { state: Rc::new(RefCell::new(WaylandWindowState::new( handle, surface.clone(), xdg_surface, toplevel, decoration, appearance, viewport, client, globals, gpu_context, params, )?)), callbacks: Rc::new(RefCell::new(Callbacks::default())), }); // Kick things off surface.commit(); Ok((this, surface.id())) }} impl WaylandWindowStatePtr { pub fn handle(&self) -> AnyWindowHandle { self.state.borrow().handle } pub fn surface(&self) -> wl_surface::WlSurface { self.state.borrow().surface.clone() } pub fn ptr_eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.state, &other.state) } pub fn frame(&self) { let mut state = self.state.borrow_mut(); state.surface.frame(&state.globals.qh, state.surface.id()); drop(state); let mut cb = self.callbacks.borrow_mut(); if let Some(fun) = cb.request_frame.as_mut() { fun(Default::default()); } } pub fn handle_xdg_surface_event(&self, event: xdg_surface::Event) { match event { xdg_surface::Event::Configure { serial } => { { let mut state = self.state.borrow_mut(); if let Some(window_controls) = state.in_progress_window_controls.take() { state.window_controls = window_controls; drop(state); let mut callbacks = self.callbacks.borrow_mut(); if let Some(appearance_changed) = callbacks.appearance_changed.as_mut() { appearance_changed(); } } } { let mut state = self.state.borrow_mut(); if let Some(mut configure) = state.in_progress_configure.take() { let got_unmaximized = state.maximized && !configure.maximized; state.fullscreen = configure.fullscreen; state.maximized = configure.maximized; state.tiling = configure.tiling; if !configure.fullscreen && !configure.maximized { configure.size = if got_unmaximized { Some(state.window_bounds.size) } else { compute_outer_size(state.inset, configure.size, state.tiling) }; if let Some(size) = configure.size { state.window_bounds = Bounds { origin: Point::default(), size, }; } } drop(state); if let Some(size) = configure.size { self.resize(size); } } } let mut state = self.state.borrow_mut(); state.xdg_surface.ack_configure(serial); let window_geometry = inset_by_tiling( state.bounds.map_origin(|_| px(0.0)), state.inset.unwrap_or(px(0.0)), state.tiling, ) .map(|v| v.0 as i32) .map_size(|v| if v <= 0 { 1 } else { v }); state.xdg_surface.set_window_geometry( window_geometry.origin.x, window_geometry.origin.y, window_geometry.size.width, window_geometry.size.height, ); let request_frame_callback = !state.acknowledged_first_configure; if request_frame_callback { state.acknowledged_first_configure = true; drop(state); self.frame(); } } _ => {} } } pub fn handle_toplevel_decoration_event(&self, event: zxdg_toplevel_decoration_v1::Event) { match event { zxdg_toplevel_decoration_v1::Event::Configure { mode } => match mode { WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ServerSide) => { self.state.borrow_mut().decorations = WindowDecorations::Server; if let Some(mut appearance_changed) = self.callbacks.borrow_mut().appearance_changed.as_mut() { appearance_changed(); } } WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ClientSide) => { self.state.borrow_mut().decorations = WindowDecorations::Client; // Update background to be transparent if let Some(mut appearance_changed) = self.callbacks.borrow_mut().appearance_changed.as_mut() { appearance_changed(); } } WEnum::Value(_) => { log::warn!("Unknown decoration mode"); } WEnum::Unknown(v) => { log::warn!("Unknown decoration mode: {}", v); } }, _ => {} } } pub fn handle_fractional_scale_event(&self, event: wp_fractional_scale_v1::Event) { match event { wp_fractional_scale_v1::Event::PreferredScale { scale } => { self.rescale(scale as f32 / 120.0); } _ => {} } } pub fn handle_toplevel_event(&self, event: xdg_toplevel::Event) -> bool { match event { xdg_toplevel::Event::Configure { width, height, states, } => { let mut size = if width == 0 || height == 0 { None } else { Some(size(px(width as f32), px(height as f32))) }; let states = extract_states::<xdg_toplevel::State>(&states); let mut tiling = Tiling::default(); let mut fullscreen = false; let mut maximized = false; for state in states { match state { xdg_toplevel::State::Maximized => { maximized = true; } xdg_toplevel::State::Fullscreen => { fullscreen = true; } xdg_toplevel::State::TiledTop => { tiling.top = true; } xdg_toplevel::State::TiledLeft => { tiling.left = true; } xdg_toplevel::State::TiledRight => { tiling.right = true; } xdg_toplevel::State::TiledBottom => { tiling.bottom = true; } _ => { // noop } } } if fullscreen || maximized { tiling = Tiling::tiled();Lines 1–500 of 1157. Load more
use std::{ cell::{Ref, RefCell, RefMut}, ffi::c_void, ptr::NonNull, rc::Rc, sync::Arc, }; use blade_graphics as gpu; use collections::HashMap; use futures::channel::oneshot::Receiver; use raw_window_handle as rwh; use wayland_backend::client::ObjectId; use wayland_client::WEnum; use wayland_client::{protocol::wl_surface, Proxy}; use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_v1; use wayland_protocols::wp::viewporter::client::wp_viewport; 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 crate::platform::{ blade::{BladeContext, BladeRenderer, BladeSurfaceConfig}, linux::wayland::{display::WaylandDisplay, serial::SerialKind}, PlatformAtlas, PlatformInputHandler, PlatformWindow, }; use crate::scene::Scene; use crate::{ px, size, AnyWindowHandle, Bounds, Decorations, Globals, GpuSpecs, Modifiers, Output, Pixels, PlatformDisplay, PlatformInput, Point, PromptLevel, RequestFrameOptions, ResizeEdge, ScaledPixels, Size, Tiling, WaylandClientStatePtr, WindowAppearance, WindowBackgroundAppearance, WindowBounds, WindowControls, WindowDecorations, WindowParams, }; #[derive(Default)] pub(crate) struct Callbacks { request_frame: Option<Box<dyn FnMut(RequestFrameOptions)>>, input: Option<Box<dyn FnMut(crate::PlatformInput) -> crate::DispatchEventResult>>, active_status_change: Option<Box<dyn FnMut(bool)>>, hover_status_change: Option<Box<dyn FnMut(bool)>>, resize: Option<Box<dyn FnMut(Size<Pixels>, f32)>>, moved: Option<Box<dyn FnMut()>>, should_close: Option<Box<dyn FnMut() -> bool>>, close: Option<Box<dyn FnOnce()>>, appearance_changed: Option<Box<dyn FnMut()>>, } struct RawWindow { window: *mut c_void, display: *mut c_void, } impl rwh::HasWindowHandle for RawWindow { fn window_handle(&self) -> Result<rwh::WindowHandle<'_>, rwh::HandleError> { let window = NonNull::new(self.window).unwrap(); let handle = rwh::WaylandWindowHandle::new(window); Ok(unsafe { rwh::WindowHandle::borrow_raw(handle.into()) }) } } impl rwh::HasDisplayHandle for RawWindow { fn display_handle(&self) -> Result<rwh::DisplayHandle<'_>, rwh::HandleError> { let display = NonNull::new(self.display).unwrap(); let handle = rwh::WaylandDisplayHandle::new(display); Ok(unsafe { rwh::DisplayHandle::borrow_raw(handle.into()) }) } } #[derive(Debug)] struct InProgressConfigure { size: Option<Size<Pixels>>, fullscreen: bool, maximized: bool, tiling: Tiling, } pub struct WaylandWindowState { xdg_surface: xdg_surface::XdgSurface, 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)>, globals: Globals, renderer: BladeRenderer, bounds: Bounds<Pixels>, scale: f32, input_handler: Option<PlatformInputHandler>, decorations: WindowDecorations, background_appearance: WindowBackgroundAppearance, fullscreen: bool, maximized: bool, tiling: Tiling, window_bounds: Bounds<Pixels>, client: WaylandClientStatePtr, handle: AnyWindowHandle, active: bool, hovered: bool, in_progress_configure: Option<InProgressConfigure>, in_progress_window_controls: Option<WindowControls>, window_controls: WindowControls, inset: Option<Pixels>, } #[derive(Clone)] pub struct WaylandWindowStatePtr { state: Rc<RefCell<WaylandWindowState>>, callbacks: Rc<RefCell<Callbacks>>, } impl WaylandWindowState { #[allow(clippy::too_many_arguments)] 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>, appearance: WindowAppearance, viewport: Option<wp_viewport::WpViewport>, client: WaylandClientStatePtr, globals: Globals, gpu_context: &BladeContext, options: WindowParams, ) -> anyhow::Result<Self> { let renderer = { let raw_window = RawWindow { window: surface.id().as_ptr().cast::<c_void>(), display: surface .backend() .upgrade() .unwrap() .display_ptr() .cast::<c_void>(), }; let config = BladeSurfaceConfig { size: gpu::Extent { width: options.bounds.size.width.0 as u32, height: options.bounds.size.height.0 as u32, depth: 1, }, transparent: true, }; BladeRenderer::new(gpu_context, &raw_window, config)? }; Ok(Self { xdg_surface, acknowledged_first_configure: false, surface, decoration, app_id: None, blur: None, toplevel, viewport, globals, outputs: HashMap::default(), display: None, renderer, bounds: options.bounds, scale: 1.0, input_handler: None, decorations: WindowDecorations::Client, background_appearance: WindowBackgroundAppearance::Opaque, fullscreen: false, maximized: false, tiling: Tiling::default(), window_bounds: options.bounds, in_progress_configure: None, client, appearance, handle, active: false, hovered: false, in_progress_window_controls: None, window_controls: WindowControls::default(), inset: None, }) } pub fn is_transparent(&self) -> bool { self.decorations == WindowDecorations::Client || self.background_appearance != WindowBackgroundAppearance::Opaque } pub fn primary_output_scale(&mut self) -> i32 { let mut scale = 1; let mut current_output = self.display.take(); for (id, output) in self.outputs.iter() { if let Some((_, output_data)) = ¤t_output { if output.scale > output_data.scale { current_output = Some((id.clone(), output.clone())); } } else { current_output = Some((id.clone(), output.clone())); } scale = scale.max(output.scale); } self.display = current_output; scale } } pub(crate) struct WaylandWindow(pub WaylandWindowStatePtr); pub enum ImeInput { InsertText(String), SetMarkedText(String), UnmarkText, DeleteText, } impl Drop for WaylandWindow { fn drop(&mut self) { let mut state = self.0.state.borrow_mut(); let surface_id = state.surface.id(); let client = state.client.clone(); state.renderer.destroy(); if let Some(decoration) = &state.decoration { decoration.destroy(); } if let Some(blur) = &state.blur { blur.release(); } state.toplevel.destroy(); if let Some(viewport) = &state.viewport { viewport.destroy(); } state.xdg_surface.destroy(); state.surface.destroy(); let state_ptr = self.0.clone(); state .globals .executor .spawn(async move { state_ptr.close(); client.drop_window(&surface_id) }) .detach(); drop(state); } } impl WaylandWindow { fn borrow(&self) -> Ref<WaylandWindowState> { self.0.state.borrow() } fn borrow_mut(&self) -> RefMut<WaylandWindowState> { self.0.state.borrow_mut() } pub fn new( handle: AnyWindowHandle, globals: Globals, gpu_context: &BladeContext, client: WaylandClientStatePtr, params: WindowParams, 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); } 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() .map(|viewporter| viewporter.get_viewport(&surface, &globals.qh, ())); let this = Self(WaylandWindowStatePtr { state: Rc::new(RefCell::new(WaylandWindowState::new( handle, surface.clone(), xdg_surface, toplevel, decoration, appearance, viewport, client, globals, gpu_context, params, )?)), callbacks: Rc::new(RefCell::new(Callbacks::default())), }); // Kick things off surface.commit(); Ok((this, surface.id())) } } impl WaylandWindowStatePtr { pub fn handle(&self) -> AnyWindowHandle { self.state.borrow().handle } pub fn surface(&self) -> wl_surface::WlSurface { self.state.borrow().surface.clone() } pub fn ptr_eq(&self, other: &Self) -> bool { Rc::ptr_eq(&self.state, &other.state) } pub fn frame(&self) { let mut state = self.state.borrow_mut(); state.surface.frame(&state.globals.qh, state.surface.id()); drop(state); let mut cb = self.callbacks.borrow_mut(); if let Some(fun) = cb.request_frame.as_mut() { fun(Default::default()); } } pub fn handle_xdg_surface_event(&self, event: xdg_surface::Event) { match event { xdg_surface::Event::Configure { serial } => { { let mut state = self.state.borrow_mut(); if let Some(window_controls) = state.in_progress_window_controls.take() { state.window_controls = window_controls; drop(state); let mut callbacks = self.callbacks.borrow_mut(); if let Some(appearance_changed) = callbacks.appearance_changed.as_mut() { appearance_changed(); } } } { let mut state = self.state.borrow_mut(); if let Some(mut configure) = state.in_progress_configure.take() { let got_unmaximized = state.maximized && !configure.maximized; state.fullscreen = configure.fullscreen; state.maximized = configure.maximized; state.tiling = configure.tiling; if !configure.fullscreen && !configure.maximized { configure.size = if got_unmaximized { Some(state.window_bounds.size) } else { compute_outer_size(state.inset, configure.size, state.tiling) }; if let Some(size) = configure.size { state.window_bounds = Bounds { origin: Point::default(), size, }; } } drop(state); if let Some(size) = configure.size { self.resize(size); } } } let mut state = self.state.borrow_mut(); state.xdg_surface.ack_configure(serial); let window_geometry = inset_by_tiling( state.bounds.map_origin(|_| px(0.0)), state.inset.unwrap_or(px(0.0)), state.tiling, ) .map(|v| v.0 as i32) .map_size(|v| if v <= 0 { 1 } else { v }); state.xdg_surface.set_window_geometry( window_geometry.origin.x, window_geometry.origin.y, window_geometry.size.width, window_geometry.size.height, ); let request_frame_callback = !state.acknowledged_first_configure; if request_frame_callback { state.acknowledged_first_configure = true; drop(state); self.frame(); } } _ => {} } } pub fn handle_toplevel_decoration_event(&self, event: zxdg_toplevel_decoration_v1::Event) { match event { zxdg_toplevel_decoration_v1::Event::Configure { mode } => match mode { WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ServerSide) => { self.state.borrow_mut().decorations = WindowDecorations::Server; if let Some(mut appearance_changed) = self.callbacks.borrow_mut().appearance_changed.as_mut() { appearance_changed(); } } WEnum::Value(zxdg_toplevel_decoration_v1::Mode::ClientSide) => { self.state.borrow_mut().decorations = WindowDecorations::Client; // Update background to be transparent if let Some(mut appearance_changed) = self.callbacks.borrow_mut().appearance_changed.as_mut() { appearance_changed(); } } WEnum::Value(_) => { log::warn!("Unknown decoration mode"); } WEnum::Unknown(v) => { log::warn!("Unknown decoration mode: {}", v); } }, _ => {} } } pub fn handle_fractional_scale_event(&self, event: wp_fractional_scale_v1::Event) { match event { wp_fractional_scale_v1::Event::PreferredScale { scale } => { self.rescale(scale as f32 / 120.0); } _ => {} } } pub fn handle_toplevel_event(&self, event: xdg_toplevel::Event) -> bool { match event { xdg_toplevel::Event::Configure { width, height, states, } => { let mut size = if width == 0 || height == 0 { None } else { Some(size(px(width as f32), px(height as f32))) }; let states = extract_states::<xdg_toplevel::State>(&states); let mut tiling = Tiling::default(); let mut fullscreen = false; let mut maximized = false; for state in states { match state { xdg_toplevel::State::Maximized => { maximized = true; } xdg_toplevel::State::Fullscreen => { fullscreen = true; } xdg_toplevel::State::TiledTop => { tiling.top = true; } xdg_toplevel::State::TiledLeft => { tiling.left = true; } xdg_toplevel::State::TiledRight => { tiling.right = true; } xdg_toplevel::State::TiledBottom => { tiling.bottom = true; } _ => { // noop } } } if fullscreen || maximized { tiling = Tiling::tiled();