use crate::{ backend::render::{ element::{AsGlowFrame, AsGlowRenderer}, GlMultiError, GlMultiFrame, GlMultiRenderer, }, state::State, utils::prelude::*, }; use calloop::LoopHandle; use id_tree::NodeId; use smithay::{ backend::{ input::KeyState, renderer::{ element::{ memory::MemoryRenderBufferRenderElement, utils::{CropRenderElement, RelocateRenderElement, RescaleRenderElement}, Element, RenderElement, UnderlyingStorage, }, gles::element::PixelShaderElement, glow::GlowRenderer, utils::DamageSet, ImportAll, ImportMem, Renderer, }, }, desktop::{space::SpaceElement, PopupManager, WindowSurfaceType}, input::{ keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, Seat, }, output::Output, reexports::wayland_server::{backend::ObjectId, protocol::wl_surface::WlSurface}, space_elements, utils::{ Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Serial, Size, }, wayland::{ compositor::{with_surface_tree_downward, TraversalAction}, seat::WaylandFocus, }, xwayland::{xwm::X11Relatable, X11Surface}, }; use std::{ collections::HashMap, fmt, hash::Hash, sync::{atomic::AtomicBool, Arc, Mutex}, }; pub mod surface; use self::stack::MoveResult; pub use self::surface::CosmicSurface; pub mod stack; pub use self::stack::CosmicStack; pub mod window; pub use self::window::CosmicWindow; pub mod resize_indicator; pub mod stack_hover; pub mod swap_indicator; #[cfg(feature = "debug")] use egui_plot::{Corner, Legend, Plot, PlotPoints, Polygon}; #[cfg(feature = "debug")] use smithay::backend::renderer::{element::texture::TextureRenderElement, gles::GlesTexture}; #[cfg(feature = "debug")] use tracing::debug; use super::{ focus::{target::PointerFocusTarget, FocusDirection}, layout::{ floating::{ResizeState, TiledCorners}, tiling::NodeDesc, }, Direction, ManagedLayer, }; space_elements! { #[derive(Debug, Clone, PartialEq, Eq, Hash)] CosmicMappedInternal; Window=CosmicWindow, Stack=CosmicStack, } #[derive(Debug, Clone)] pub struct MaximizedState { pub original_geometry: Rectangle, pub original_layer: ManagedLayer, } #[derive(Clone)] pub struct CosmicMapped { element: CosmicMappedInternal, // associated data last_cursor_position: Arc>>>, pub maximized_state: Arc>>, //tiling pub tiling_node_id: Arc>>, //floating pub(super) resize_state: Arc>>, pub last_geometry: Arc>>>, pub moved_since_mapped: Arc, pub floating_tiled: Arc>>, //sticky pub previous_layer: Arc>>, #[cfg(feature = "debug")] debug: Arc>>, } impl fmt::Debug for CosmicMapped { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("CosmicMapped") .field("element", &self.element) .field("last_cursor_position", &self.last_cursor_position) .field("maximized_state", &self.maximized_state) .field("tiling_node_id", &self.tiling_node_id) .field("resize_state", &self.resize_state) .field("last_geometry", &self.last_geometry) .field("moved_since_mapped", &self.moved_since_mapped) .field("floating_tiled", &self.floating_tiled) .finish() } } impl PartialEq for CosmicMapped { fn eq(&self, other: &Self) -> bool { self.element == other.element } } impl Eq for CosmicMapped {} impl Hash for CosmicMapped { fn hash(&self, state: &mut H) { self.element.hash(state) } } impl CosmicMapped { pub fn windows(&self) -> impl Iterator)> + '_ { match &self.element { CosmicMappedInternal::Stack(stack) => { Box::new(stack.surfaces().map(|w| (w, stack.offset()))) as Box)>> } CosmicMappedInternal::Window(window) => { Box::new(std::iter::once((window.surface(), window.offset()))) } _ => Box::new(std::iter::empty()), } } pub fn active_window(&self) -> CosmicSurface { match &self.element { CosmicMappedInternal::Stack(stack) => stack.active(), CosmicMappedInternal::Window(win) => win.surface(), _ => unreachable!(), } } pub fn has_active_window(&self, window: &CosmicSurface) -> bool { match &self.element { CosmicMappedInternal::Stack(stack) => stack.has_active(window), CosmicMappedInternal::Window(win) => win.contains_surface(window), _ => unreachable!(), } } pub fn active_window_offset(&self) -> Point { match &self.element { CosmicMappedInternal::Stack(stack) => stack.offset(), CosmicMappedInternal::Window(window) => window.offset(), _ => unreachable!(), } } pub fn active_window_geometry(&self) -> Rectangle { match &self.element { CosmicMappedInternal::Stack(stack) => { let win = stack.active(); let location = stack.offset(); let size = win.geometry().size; Rectangle::from_loc_and_size(location, size) } CosmicMappedInternal::Window(win) => { let location = win.offset(); let size = win.geometry().size; Rectangle::from_loc_and_size(location, size) } _ => unreachable!(), } } pub fn cursor_position(&self, seat: &Seat) -> Option> { self.last_cursor_position .lock() .unwrap() .get(&seat.id()) .cloned() } pub fn set_active(&self, window: &CosmicSurface) { if let CosmicMappedInternal::Stack(stack) = &self.element { stack.set_active(window); } } pub fn focus_window(&self, window: &CosmicSurface) { match &self.element { CosmicMappedInternal::Stack(stack) => stack.set_active(window), _ => {} } } pub fn has_surface(&self, surface: &WlSurface, surface_type: WindowSurfaceType) -> bool { self.windows().any(|(w, _)| { let Some(toplevel) = w.wl_surface() else { return false; }; if surface_type.contains(WindowSurfaceType::TOPLEVEL) { if toplevel == *surface { return true; } } if surface_type.contains(WindowSurfaceType::SUBSURFACE) { use std::sync::atomic::Ordering; let found = AtomicBool::new(false); with_surface_tree_downward( &toplevel, surface, |_, _, search| TraversalAction::DoChildren(search), |s, _, search| { found.fetch_or(s == *search, Ordering::SeqCst); }, |_, _, _| !found.load(Ordering::SeqCst), ); if found.load(Ordering::SeqCst) { return true; } } if surface_type.contains(WindowSurfaceType::POPUP) { PopupManager::popups_for_surface(&toplevel).any(|(p, _)| p.wl_surface() == surface) } else { false } }) } /// Give the pointer target under a relative offset into this element. /// /// Returns Target + Offset relative to the target pub fn focus_under( &self, relative_pos: Point, ) -> Option<(PointerFocusTarget, Point)> { match &self.element { CosmicMappedInternal::Stack(stack) => stack.focus_under(relative_pos), CosmicMappedInternal::Window(window) => window.focus_under(relative_pos), _ => unreachable!(), } } pub fn handle_move(&self, direction: Direction) -> MoveResult { if let CosmicMappedInternal::Stack(stack) = &self.element { stack.handle_move(direction) } else { MoveResult::Default } } pub fn handle_focus(&self, direction: FocusDirection, swap: Option) -> bool { if let CosmicMappedInternal::Stack(stack) = &self.element { stack.handle_focus(direction, swap) } else { false } } pub fn set_resizing(&self, resizing: bool) { for window in match &self.element { CosmicMappedInternal::Stack(s) => { Box::new(s.surfaces()) as Box> } CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())), _ => unreachable!(), } { window.set_resizing(resizing); } } pub fn is_resizing(&self, pending: bool) -> Option { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; window.is_resizing(pending) } pub fn set_tiled(&self, tiled: bool) { if let Some(window) = match &self.element { // we use the tiled state of stack windows anyway to get rid of decorations CosmicMappedInternal::Stack(_) => None, CosmicMappedInternal::Window(w) => Some(w.surface()), _ => unreachable!(), } { window.set_tiled(tiled) } } pub fn is_tiled(&self, pending: bool) -> Option { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; window.is_tiled(pending) } pub fn set_fullscreen(&self, fullscreen: bool) { for window in match &self.element { CosmicMappedInternal::Stack(s) => { Box::new(s.surfaces()) as Box> } CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())), _ => unreachable!(), } { window.set_fullscreen(fullscreen); } } pub fn is_fullscreen(&self, pending: bool) -> bool { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; window.is_fullscreen(pending) } pub fn set_maximized(&self, maximized: bool) { for window in match &self.element { CosmicMappedInternal::Stack(s) => { Box::new(s.surfaces()) as Box> } CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())), _ => unreachable!(), } { window.set_maximized(maximized) } } pub fn is_maximized(&self, pending: bool) -> bool { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; window.is_maximized(pending) } pub fn set_activated(&self, activated: bool) { match &self.element { CosmicMappedInternal::Stack(s) => s.set_activate(activated), CosmicMappedInternal::Window(w) => w.set_activate(activated), _ => unreachable!(), } } pub fn is_activated(&self, pending: bool) -> bool { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; window.is_activated(pending) } pub fn is_minimized(&self) -> bool { self.active_window().is_minimized() } pub fn set_minimized(&self, minimized: bool) { for (w, _) in self.windows() { w.set_minimized(minimized); } } pub fn pending_size(&self) -> Option> { match &self.element { CosmicMappedInternal::Stack(s) => s.pending_size(), CosmicMappedInternal::Window(w) => w.pending_size(), _ => unreachable!(), } } pub fn set_geometry(&self, geo: Rectangle) { match &self.element { CosmicMappedInternal::Stack(s) => s.set_geometry(geo), CosmicMappedInternal::Window(w) => w.set_geometry(geo), _ => {} } } pub fn on_commit(&self, surface: &WlSurface) { match &self.element { CosmicMappedInternal::Stack(s) => s.on_commit(surface), CosmicMappedInternal::Window(w) => w.on_commit(surface), _ => {} } } pub fn min_size(&self) -> Option> { match &self.element { CosmicMappedInternal::Stack(stack) => { stack.surfaces().fold(None, |min_size, window| { let win_min_size = window.min_size(); match (min_size, win_min_size) { (None, None) => None, (None, x) | (x, None) => x, (Some(min1), Some(min2)) => { Some((min1.w.max(min2.w), min1.h.max(min2.h)).into()) } } }) } CosmicMappedInternal::Window(window) => window.surface().min_size(), _ => unreachable!(), } } pub fn max_size(&self) -> Option> { match &self.element { CosmicMappedInternal::Stack(stack) => { let theoretical_max = stack.surfaces().fold(None, |max_size, window| { let win_max_size = window.max_size(); match (max_size, win_max_size) { (None, None) => None, (None, x) | (x, None) => x, (Some(max1), Some(max2)) => Some( ( if max1.w == 0 { max2.w } else if max2.w == 0 { max1.w } else { max1.w.min(max2.w) }, if max1.h == 0 { max2.h } else if max2.h == 0 { max1.h } else { max1.h.min(max2.h) }, ) .into(), ), } }); // The problem is, with accumulated sizes, the minimum size could be larger than our maximum... let min_size = self.min_size(); match (theoretical_max, min_size) { (None, _) => None, (Some(max), None) => Some(max), (Some(max), Some(min)) => Some((max.w.max(min.w), max.h.max(min.h)).into()), } } CosmicMappedInternal::Window(window) => window.surface().max_size(), _ => unreachable!(), } } pub fn set_bounds(&self, size: impl Into>>) { let size = size.into(); for (surface, _) in self.windows() { surface.set_bounds(size.clone()) } } pub fn configure(&self) -> Option { match &self.element { CosmicMappedInternal::Stack(s) => { let active = s.active(); for surface in s.surfaces().filter(|s| s != &active) { surface.send_configure(); } active.send_configure() } CosmicMappedInternal::Window(w) => w.surface().send_configure(), _ => unreachable!(), } } pub fn send_close(&self) { let window = match &self.element { CosmicMappedInternal::Stack(s) => s.active(), CosmicMappedInternal::Window(w) => w.surface(), _ => unreachable!(), }; window.close(); } pub fn is_window(&self) -> bool { match &self.element { CosmicMappedInternal::Window(_) => true, _ => false, } } pub fn is_stack(&self) -> bool { match &self.element { CosmicMappedInternal::Stack(_) => true, _ => false, } } pub fn stack_ref(&self) -> Option<&CosmicStack> { match &self.element { CosmicMappedInternal::Stack(stack) => Some(stack), _ => None, } } pub fn stack_ref_mut(&mut self) -> Option<&mut CosmicStack> { match &mut self.element { CosmicMappedInternal::Stack(stack) => Some(stack), _ => None, } } pub fn convert_to_stack<'a>( &mut self, (output, overlap): (&'a Output, Rectangle), theme: cosmic::Theme, ) { match &self.element { CosmicMappedInternal::Window(window) => { let surface = window.surface(); let activated = surface.is_activated(true); let handle = window.loop_handle(); let stack = CosmicStack::new(std::iter::once(surface), handle, theme); if let Some(geo) = self.last_geometry.lock().unwrap().clone() { stack.set_geometry(geo.to_global(&output)); } stack.output_enter(output, overlap); stack.set_activate(activated); stack.active().send_configure(); stack.refresh(); self.element = CosmicMappedInternal::Stack(stack); } _ => {} } } pub fn convert_to_surface<'a>( &mut self, surface: CosmicSurface, (output, overlap): (&'a Output, Rectangle), theme: cosmic::Theme, ) { let handle = self.loop_handle(); surface.try_force_undecorated(false); surface.set_tiled(false); let window = CosmicWindow::new(surface, handle, theme); if let Some(geo) = self.last_geometry.lock().unwrap().clone() { window.set_geometry(geo.to_global(&output)); } window.output_enter(output, overlap); window.set_activate(self.is_activated(true)); window.surface().send_configure(); window.refresh(); self.element = CosmicMappedInternal::Window(window); } pub(super) fn loop_handle(&self) -> LoopHandle<'static, crate::state::State> { match &self.element { CosmicMappedInternal::Stack(stack) => stack.loop_handle(), CosmicMappedInternal::Window(window) => window.loop_handle(), _ => unreachable!(), } } #[cfg(feature = "debug")] pub fn set_debug(&self, flag: bool) { let mut debug = self.debug.lock().unwrap(); if flag { *debug = Some(smithay_egui::EguiState::new(Rectangle::from_loc_and_size( (10, 10), (100, 100), ))); } else { debug.take(); } } pub fn split_render_elements( &self, renderer: &mut R, location: smithay::utils::Point, scale: smithay::utils::Scale, alpha: f32, ) -> (Vec, Vec) where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, C: From>, { #[cfg(feature = "debug")] let debug_elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() { let window = self.active_window(); let window_geo = window.geometry(); let (min_size, max_size, size) = (window.min_size(), window.max_size(), window.geometry().size); let area = Rectangle::::from_loc_and_size( location.to_f64().to_logical(scale).to_i32_round(), self.bbox().size, ); let glow_renderer = renderer.glow_renderer_mut(); match debug.render( |ctx| { egui::Area::new("window") .anchor( egui::Align2::RIGHT_TOP, [ -window_geo.loc.x as f32 - 10.0, window_geo.loc.y as f32 - 10.0, ], ) .show(ctx, |ui| { egui::Frame::none() .fill(egui::Color32::BLACK) .rounding(5.0) .inner_margin(10.0) .show(ui, |ui| { ui.heading(window.title()); ui.horizontal(|ui| { ui.label("App ID: "); ui.label(window.app_id()); }); ui.label(match window.0.underlying_surface() { WindowSurface::Wayland(_) => "Protocol: Wayland", WindowSurface::X11(_) => "Protocol: X11", }); if let WindowSurface::X11(ref surf) = window.0.underlying_surface() { let geo = surf.geometry(); ui.label(format!( "X11 Geo: {}x{}x{}x{}", geo.loc.x, geo.loc.y, geo.size.w, geo.size.h )); } ui.horizontal(|ui| { ui.label("States: "); if window.is_maximized(true) { ui.label("🗖"); } if window.is_fullscreen(true) { ui.label("⬜"); } if window.is_activated(true) { ui.label("🖱"); } if window.is_resizing(true).is_some() { ui.label("↔"); } }); let plot = Plot::new("Sizes") .legend(Legend::default().position(Corner::RightBottom)) .data_aspect(1.0) .view_aspect(1.0) .show_x(false) .show_y(false) .width(200.0) .height(200.0); plot.show(ui, |plot_ui| { let center = if let Some(max_size) = max_size { ((max_size.w + 20) / 2, (max_size.h + 20) / 2) } else { (100, 100) }; if let Some(max_size) = max_size { let max_size_rect = Polygon::new(PlotPoints::new(vec![ [10.0, 10.0], [max_size.w as f64 + 10.0, 10.0], [ max_size.w as f64 + 10.0, max_size.h as f64 + 10.0, ], [10.0, max_size.h as f64 + 10.0], [10.0, 10.0], ])); plot_ui.polygon( max_size_rect .name(format!("{}x{}", max_size.w, max_size.h)), ); } let size_rect = Polygon::new(PlotPoints::new(vec![ [ (center.0 - size.w / 2) as f64, (center.1 - size.h / 2) as f64, ], [ (center.0 + size.w / 2) as f64, (center.1 - size.h / 2) as f64, ], [ (center.0 + size.w / 2) as f64, (center.1 + size.h / 2) as f64, ], [ (center.0 - size.w / 2) as f64, (center.1 + size.h / 2) as f64, ], [ (center.0 - size.w / 2) as f64, (center.1 - size.h / 2) as f64, ], ])); plot_ui.polygon( size_rect.name(format!("{}x{}", size.w, size.h)), ); if let Some(min_size) = min_size { let min_size_rect = Polygon::new(PlotPoints::new(vec![ [ (center.0 - min_size.w / 2) as f64, (center.1 - min_size.h / 2) as f64, ], [ (center.0 + min_size.w / 2) as f64, (center.1 - min_size.h / 2) as f64, ], [ (center.0 + min_size.w / 2) as f64, (center.1 + min_size.h / 2) as f64, ], [ (center.0 - min_size.w / 2) as f64, (center.1 + min_size.h / 2) as f64, ], [ (center.0 - min_size.w / 2) as f64, (center.1 - min_size.h / 2) as f64, ], ])); plot_ui.polygon( min_size_rect .name(format!("{}x{}", min_size.w, min_size.h)), ); } }) }) }); }, glow_renderer, area, scale.x, 0.8, ) { Ok(element) => vec![element.into()], Err(err) => { debug!(?err, "Error rendering debug overlay."); Vec::new() } } } else { Vec::new() }; #[cfg(not(feature = "debug"))] let debug_elements = Vec::new(); #[cfg_attr(not(feature = "debug"), allow(unused_mut))] let (window_elements, popup_elements) = match &self.element { CosmicMappedInternal::Stack(s) => s .split_render_elements::>( renderer, location, scale, alpha, ), CosmicMappedInternal::Window(w) => w .split_render_elements::>( renderer, location, scale, alpha, ), _ => unreachable!(), }; ( debug_elements .into_iter() .map(C::from) .chain(window_elements.into_iter().map(C::from)) .collect(), popup_elements.into_iter().map(C::from).collect(), ) } pub(crate) fn update_theme(&self, theme: cosmic::Theme) { match &self.element { CosmicMappedInternal::Window(w) => w.set_theme(theme), CosmicMappedInternal::Stack(s) => s.set_theme(theme), CosmicMappedInternal::_GenericCatcher(_) => {} } } pub(crate) fn force_redraw(&self) { match &self.element { CosmicMappedInternal::Window(w) => w.force_redraw(), CosmicMappedInternal::Stack(s) => s.force_redraw(), CosmicMappedInternal::_GenericCatcher(_) => {} } } } impl IsAlive for CosmicMapped { fn alive(&self) -> bool { self.element.alive() } } impl SpaceElement for CosmicMapped { fn bbox(&self) -> Rectangle { SpaceElement::bbox(&self.element) } fn is_in_input_region(&self, point: &Point) -> bool { SpaceElement::is_in_input_region(&self.element, point) } fn set_activate(&self, activated: bool) { SpaceElement::set_activate(&self.element, activated) } fn output_enter(&self, output: &Output, overlap: Rectangle) { SpaceElement::output_enter(&self.element, output, overlap) } fn output_leave(&self, output: &Output) { SpaceElement::output_leave(&self.element, output) } fn geometry(&self) -> Rectangle { SpaceElement::geometry(&self.element) } fn z_index(&self) -> u8 { SpaceElement::z_index(&self.element) } #[profiling::function] fn refresh(&self) { SpaceElement::refresh(&self.element) } } impl X11Relatable for CosmicMapped { fn is_window(&self, window: &X11Surface) -> bool { self.active_window().x11_surface() == Some(window) } } impl KeyboardTarget for CosmicMapped { fn enter( &self, seat: &Seat, data: &mut State, keys: Vec>, serial: Serial, ) { match &self.element { CosmicMappedInternal::Stack(s) => KeyboardTarget::enter(s, seat, data, keys, serial), CosmicMappedInternal::Window(w) => KeyboardTarget::enter(w, seat, data, keys, serial), _ => {} } } fn leave(&self, seat: &Seat, data: &mut State, serial: Serial) { match &self.element { CosmicMappedInternal::Stack(s) => KeyboardTarget::leave(s, seat, data, serial), CosmicMappedInternal::Window(w) => KeyboardTarget::leave(w, seat, data, serial), _ => {} } } fn key( &self, seat: &Seat, data: &mut State, key: KeysymHandle<'_>, state: KeyState, serial: Serial, time: u32, ) { match &self.element { CosmicMappedInternal::Stack(s) => { KeyboardTarget::key(s, seat, data, key, state, serial, time) } CosmicMappedInternal::Window(w) => { KeyboardTarget::key(w, seat, data, key, state, serial, time) } _ => {} } } fn modifiers( &self, seat: &Seat, data: &mut State, modifiers: ModifiersState, serial: Serial, ) { match &self.element { CosmicMappedInternal::Stack(s) => { KeyboardTarget::modifiers(s, seat, data, modifiers, serial) } CosmicMappedInternal::Window(w) => { KeyboardTarget::modifiers(w, seat, data, modifiers, serial) } _ => {} } } } impl WaylandFocus for CosmicMapped { fn wl_surface(&self) -> Option { match &self.element { CosmicMappedInternal::Window(w) => w.surface().wl_surface().clone(), CosmicMappedInternal::Stack(s) => s.active().wl_surface().clone(), _ => None, } } fn same_client_as(&self, object_id: &ObjectId) -> bool { match &self.element { CosmicMappedInternal::Window(w) => w.surface().same_client_as(object_id), CosmicMappedInternal::Stack(s) => s.surfaces().any(|w| w.same_client_as(object_id)), _ => false, } } } impl From for CosmicMapped { fn from(w: CosmicWindow) -> Self { CosmicMapped { element: CosmicMappedInternal::Window(w), last_cursor_position: Arc::new(Mutex::new(HashMap::new())), maximized_state: Arc::new(Mutex::new(None)), tiling_node_id: Arc::new(Mutex::new(None)), resize_state: Arc::new(Mutex::new(None)), last_geometry: Arc::new(Mutex::new(None)), moved_since_mapped: Arc::new(AtomicBool::new(false)), floating_tiled: Arc::new(Mutex::new(None)), previous_layer: Arc::new(Mutex::new(None)), #[cfg(feature = "debug")] debug: Arc::new(Mutex::new(None)), } } } impl From for CosmicMapped { fn from(s: CosmicStack) -> Self { CosmicMapped { element: CosmicMappedInternal::Stack(s), last_cursor_position: Arc::new(Mutex::new(HashMap::new())), maximized_state: Arc::new(Mutex::new(None)), tiling_node_id: Arc::new(Mutex::new(None)), resize_state: Arc::new(Mutex::new(None)), last_geometry: Arc::new(Mutex::new(None)), moved_since_mapped: Arc::new(AtomicBool::new(false)), floating_tiled: Arc::new(Mutex::new(None)), previous_layer: Arc::new(Mutex::new(None)), #[cfg(feature = "debug")] debug: Arc::new(Mutex::new(None)), } } } pub enum CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem, ::TextureId: 'static, { Stack(self::stack::CosmicStackRenderElement), Window(self::window::CosmicWindowRenderElement), TiledStack( CropRenderElement< RelocateRenderElement>>, >, ), TiledWindow( CropRenderElement< RelocateRenderElement>>, >, ), TiledOverlay( CropRenderElement>>, ), MovingStack( RelocateRenderElement>>, ), MovingWindow( RelocateRenderElement>>, ), GrabbedStack(RescaleRenderElement>), GrabbedWindow(RescaleRenderElement>), FocusIndicator(PixelShaderElement), Overlay(PixelShaderElement), StackHoverIndicator(MemoryRenderBufferRenderElement), #[cfg(feature = "debug")] Egui(TextureRenderElement), } impl Element for CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem, ::TextureId: 'static, { fn id(&self) -> &smithay::backend::renderer::element::Id { match self { CosmicMappedRenderElement::Stack(elem) => elem.id(), CosmicMappedRenderElement::Window(elem) => elem.id(), CosmicMappedRenderElement::TiledStack(elem) => elem.id(), CosmicMappedRenderElement::TiledWindow(elem) => elem.id(), CosmicMappedRenderElement::TiledOverlay(elem) => elem.id(), CosmicMappedRenderElement::MovingStack(elem) => elem.id(), CosmicMappedRenderElement::MovingWindow(elem) => elem.id(), CosmicMappedRenderElement::GrabbedStack(elem) => elem.id(), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.id(), CosmicMappedRenderElement::FocusIndicator(elem) => elem.id(), CosmicMappedRenderElement::Overlay(elem) => elem.id(), CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.id(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.id(), } } fn current_commit(&self) -> smithay::backend::renderer::utils::CommitCounter { match self { CosmicMappedRenderElement::Stack(elem) => elem.current_commit(), CosmicMappedRenderElement::Window(elem) => elem.current_commit(), CosmicMappedRenderElement::TiledStack(elem) => elem.current_commit(), CosmicMappedRenderElement::TiledWindow(elem) => elem.current_commit(), CosmicMappedRenderElement::TiledOverlay(elem) => elem.current_commit(), CosmicMappedRenderElement::MovingStack(elem) => elem.current_commit(), CosmicMappedRenderElement::MovingWindow(elem) => elem.current_commit(), CosmicMappedRenderElement::GrabbedStack(elem) => elem.current_commit(), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.current_commit(), CosmicMappedRenderElement::FocusIndicator(elem) => elem.current_commit(), CosmicMappedRenderElement::Overlay(elem) => elem.current_commit(), CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.current_commit(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.current_commit(), } } fn src(&self) -> Rectangle { match self { CosmicMappedRenderElement::Stack(elem) => elem.src(), CosmicMappedRenderElement::Window(elem) => elem.src(), CosmicMappedRenderElement::TiledStack(elem) => elem.src(), CosmicMappedRenderElement::TiledWindow(elem) => elem.src(), CosmicMappedRenderElement::TiledOverlay(elem) => elem.src(), CosmicMappedRenderElement::MovingStack(elem) => elem.src(), CosmicMappedRenderElement::MovingWindow(elem) => elem.src(), CosmicMappedRenderElement::GrabbedStack(elem) => elem.src(), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.src(), CosmicMappedRenderElement::FocusIndicator(elem) => elem.src(), CosmicMappedRenderElement::Overlay(elem) => elem.src(), CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.src(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.src(), } } fn geometry(&self, scale: Scale) -> Rectangle { match self { CosmicMappedRenderElement::Stack(elem) => elem.geometry(scale), CosmicMappedRenderElement::Window(elem) => elem.geometry(scale), CosmicMappedRenderElement::TiledStack(elem) => elem.geometry(scale), CosmicMappedRenderElement::TiledWindow(elem) => elem.geometry(scale), CosmicMappedRenderElement::TiledOverlay(elem) => elem.geometry(scale), CosmicMappedRenderElement::MovingStack(elem) => elem.geometry(scale), CosmicMappedRenderElement::MovingWindow(elem) => elem.geometry(scale), CosmicMappedRenderElement::GrabbedStack(elem) => elem.geometry(scale), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.geometry(scale), CosmicMappedRenderElement::FocusIndicator(elem) => elem.geometry(scale), CosmicMappedRenderElement::Overlay(elem) => elem.geometry(scale), CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.geometry(scale), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.geometry(scale), } } fn location(&self, scale: Scale) -> Point { match self { CosmicMappedRenderElement::Stack(elem) => elem.location(scale), CosmicMappedRenderElement::Window(elem) => elem.location(scale), CosmicMappedRenderElement::TiledStack(elem) => elem.location(scale), CosmicMappedRenderElement::TiledWindow(elem) => elem.location(scale), CosmicMappedRenderElement::TiledOverlay(elem) => elem.location(scale), CosmicMappedRenderElement::MovingStack(elem) => elem.location(scale), CosmicMappedRenderElement::MovingWindow(elem) => elem.location(scale), CosmicMappedRenderElement::GrabbedStack(elem) => elem.location(scale), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.location(scale), CosmicMappedRenderElement::FocusIndicator(elem) => elem.location(scale), CosmicMappedRenderElement::Overlay(elem) => elem.location(scale), CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.location(scale), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.location(scale), } } fn transform(&self) -> smithay::utils::Transform { match self { CosmicMappedRenderElement::Stack(elem) => elem.transform(), CosmicMappedRenderElement::Window(elem) => elem.transform(), CosmicMappedRenderElement::TiledStack(elem) => elem.transform(), CosmicMappedRenderElement::TiledWindow(elem) => elem.transform(), CosmicMappedRenderElement::TiledOverlay(elem) => elem.transform(), CosmicMappedRenderElement::MovingStack(elem) => elem.transform(), CosmicMappedRenderElement::MovingWindow(elem) => elem.transform(), CosmicMappedRenderElement::GrabbedStack(elem) => elem.transform(), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.transform(), CosmicMappedRenderElement::FocusIndicator(elem) => elem.transform(), CosmicMappedRenderElement::Overlay(elem) => elem.transform(), CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.transform(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.transform(), } } fn damage_since( &self, scale: Scale, commit: Option, ) -> DamageSet { match self { CosmicMappedRenderElement::Stack(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::Window(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::TiledStack(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::TiledWindow(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::TiledOverlay(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::MovingStack(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::MovingWindow(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::GrabbedStack(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::FocusIndicator(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::Overlay(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::StackHoverIndicator(elem) => { elem.damage_since(scale, commit) } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.damage_since(scale, commit), } } fn opaque_regions(&self, scale: Scale) -> Vec> { match self { CosmicMappedRenderElement::Stack(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::Window(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::TiledStack(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::TiledWindow(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::TiledOverlay(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::MovingStack(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::MovingWindow(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::GrabbedStack(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::FocusIndicator(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::Overlay(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.opaque_regions(scale), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.opaque_regions(scale), } } fn alpha(&self) -> f32 { match self { CosmicMappedRenderElement::Stack(elem) => elem.alpha(), CosmicMappedRenderElement::Window(elem) => elem.alpha(), CosmicMappedRenderElement::TiledStack(elem) => elem.alpha(), CosmicMappedRenderElement::TiledWindow(elem) => elem.alpha(), CosmicMappedRenderElement::TiledOverlay(elem) => elem.alpha(), CosmicMappedRenderElement::MovingStack(elem) => elem.alpha(), CosmicMappedRenderElement::MovingWindow(elem) => elem.alpha(), CosmicMappedRenderElement::GrabbedStack(elem) => elem.alpha(), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.alpha(), CosmicMappedRenderElement::FocusIndicator(elem) => elem.alpha(), CosmicMappedRenderElement::Overlay(elem) => elem.alpha(), CosmicMappedRenderElement::StackHoverIndicator(elem) => elem.alpha(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.alpha(), } } } impl RenderElement for CosmicMappedRenderElement { fn draw<'frame>( &self, frame: &mut ::Frame<'frame>, src: Rectangle, dst: Rectangle, damage: &[Rectangle], ) -> Result<(), ::Error> { match self { CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::TiledStack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::TiledWindow(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::TiledOverlay(elem) => { RenderElement::::draw(elem, frame, src, dst, damage) } CosmicMappedRenderElement::MovingStack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::MovingWindow(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::GrabbedStack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::FocusIndicator(elem) => { RenderElement::::draw(elem, frame, src, dst, damage) } CosmicMappedRenderElement::Overlay(elem) => { RenderElement::::draw(elem, frame, src, dst, damage) } CosmicMappedRenderElement::StackHoverIndicator(elem) => { RenderElement::::draw(elem, frame, src, dst, damage) } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { RenderElement::::draw(elem, frame, src, dst, damage) } } } fn underlying_storage(&self, renderer: &mut GlowRenderer) -> Option { match self { CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::TiledStack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::TiledWindow(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::TiledOverlay(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::MovingStack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::MovingWindow(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::GrabbedStack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::FocusIndicator(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Overlay(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::StackHoverIndicator(elem) => { elem.underlying_storage(renderer) } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.underlying_storage(renderer), } } } impl<'a> RenderElement> for CosmicMappedRenderElement> { fn draw<'frame>( &self, frame: &mut GlMultiFrame<'a, 'frame>, src: Rectangle, dst: Rectangle, damage: &[Rectangle], ) -> Result<(), GlMultiError> { match self { CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::TiledStack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::TiledWindow(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::TiledOverlay(elem) => { RenderElement::::draw(elem, frame.glow_frame_mut(), src, dst, damage) .map_err(|err| GlMultiError::Render(err)) } CosmicMappedRenderElement::MovingStack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::MovingWindow(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::GrabbedStack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::FocusIndicator(elem) => { RenderElement::::draw(elem, frame.glow_frame_mut(), src, dst, damage) .map_err(|err| GlMultiError::Render(err)) } CosmicMappedRenderElement::Overlay(elem) => { RenderElement::::draw(elem, frame.glow_frame_mut(), src, dst, damage) .map_err(|err| GlMultiError::Render(err)) } CosmicMappedRenderElement::StackHoverIndicator(elem) => { elem.draw(frame, src, dst, damage) } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { let glow_frame = frame.glow_frame_mut(); RenderElement::::draw(elem, glow_frame, src, dst, damage) .map_err(|err| GlMultiError::Render(err)) } } } fn underlying_storage(&self, renderer: &mut GlMultiRenderer<'a>) -> Option { match self { CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::TiledStack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::TiledWindow(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::TiledOverlay(elem) => { elem.underlying_storage(renderer.glow_renderer_mut()) } CosmicMappedRenderElement::MovingStack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::MovingWindow(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::GrabbedStack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::GrabbedWindow(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::FocusIndicator(elem) => { elem.underlying_storage(renderer.glow_renderer_mut()) } CosmicMappedRenderElement::Overlay(elem) => { elem.underlying_storage(renderer.glow_renderer_mut()) } CosmicMappedRenderElement::StackHoverIndicator(elem) => { elem.underlying_storage(renderer) } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { let glow_renderer = renderer.glow_renderer_mut(); match elem.underlying_storage(glow_renderer) { Some(UnderlyingStorage::Wayland(buffer)) => { Some(UnderlyingStorage::Wayland(buffer)) } _ => None, } } } } } impl From> for CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: stack::CosmicStackRenderElement) -> Self { CosmicMappedRenderElement::Stack(elem) } } impl From> for CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: window::CosmicWindowRenderElement) -> Self { CosmicMappedRenderElement::Window(elem) } } impl From for CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: PixelShaderElement) -> Self { CosmicMappedRenderElement::FocusIndicator(elem) } } impl From> for CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: MemoryRenderBufferRenderElement) -> Self { CosmicMappedRenderElement::StackHoverIndicator(elem) } } #[cfg(feature = "debug")] impl From> for CosmicMappedRenderElement where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: TextureRenderElement) -> Self { CosmicMappedRenderElement::Egui(elem) } }