use crate::{ backend::render::element::{AsGlowRenderer, FromGlesError}, state::State, utils::{iced::IcedElementInternal, prelude::*}, }; use calloop::LoopHandle; use cosmic_comp_config::AppearanceConfig; use id_tree::NodeId; use smithay::{ backend::{ input::KeyState, renderer::{ element::{ Element, RenderElement, UnderlyingStorage, memory::MemoryRenderBufferRenderElement, utils::{CropRenderElement, RelocateRenderElement, RescaleRenderElement}, }, gles::element::PixelShaderElement, glow::GlowRenderer, utils::{DamageSet, OpaqueRegions}, }, }, desktop::{WindowSurfaceType, space::SpaceElement}, input::{ Seat, keyboard::{KeyboardTarget, KeysymHandle, ModifiersState}, }, 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::seat::WaylandFocus, xwayland::{X11Surface, xwm::X11Relatable}, }; use stack::CosmicStackInternal; use window::CosmicWindowInternal; use std::{ borrow::Cow, fmt, hash::Hash, sync::{Arc, Mutex, Weak, atomic::AtomicBool}, }; 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 smithay::desktop::WindowSurface; #[cfg(feature = "debug")] use tracing::debug; use super::{ ManagedLayer, focus::target::PointerFocusTarget, layout::{ floating::{ResizeState, TiledCorners}, tiling::NodeDesc, }, }; use cosmic_settings_config::shortcuts::action::{Direction, FocusDirection}; 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 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("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() } } #[derive(Clone)] pub struct CosmicMappedKey(CosmicMappedKeyInner); #[derive(Clone)] enum CosmicMappedKeyInner { Window(Weak>>), Stack(Weak>>), } impl Hash for CosmicMappedKey { fn hash(&self, state: &mut H) { match &self.0 { CosmicMappedKeyInner::Window(weak) => weak.as_ptr().hash(state), CosmicMappedKeyInner::Stack(weak) => weak.as_ptr().hash(state), } } } impl IsAlive for CosmicMappedKey { fn alive(&self) -> bool { match &self.0 { CosmicMappedKeyInner::Window(weak) => weak.strong_count() > 0, CosmicMappedKeyInner::Stack(weak) => weak.strong_count() > 0, } } } impl PartialEq for CosmicMappedKey { fn eq(&self, other: &Self) -> bool { match (&self.0, &other.0) { (CosmicMappedKeyInner::Window(weak1), CosmicMappedKeyInner::Window(weak2)) => { Weak::ptr_eq(weak1, weak2) } (CosmicMappedKeyInner::Stack(weak1), CosmicMappedKeyInner::Stack(weak2)) => { Weak::ptr_eq(weak1, weak2) } _ => false, } } } impl Eq for CosmicMappedKey {} 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::new(location, size) } CosmicMappedInternal::Window(win) => { let location = win.offset(); let size = win.geometry().size; Rectangle::new(location, size) } _ => unreachable!(), } } pub fn set_active(&self, window: &S) where CosmicSurface: PartialEq, { if let CosmicMappedInternal::Stack(stack) = &self.element { stack.set_active(window); } } pub fn focus_window(&self, window: &CosmicSurface) { if let CosmicMappedInternal::Stack(stack) = &self.element { stack.set_active(window) } } pub fn has_surface(&self, surface: &WlSurface, surface_type: WindowSurfaceType) -> bool { self.windows() .any(|(w, _)| w.has_surface(surface, surface_type)) } /// 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, surface_type: WindowSurfaceType, ) -> Option<(PointerFocusTarget, Point)> { match &self.element { CosmicMappedInternal::Stack(stack) => stack.focus_under(relative_pos, surface_type), CosmicMappedInternal::Window(window) => window.focus_under(relative_pos, surface_type), _ => 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, seat: &Seat, direction: FocusDirection, swap: Option, ) -> bool { if let CosmicMappedInternal::Stack(stack) = &self.element { stack.handle_focus(seat, 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) { match &self.element { CosmicMappedInternal::Stack(s) => s.set_tiled(tiled), CosmicMappedInternal::Window(w) => w.set_tiled(tiled), _ => unreachable!(), } } 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.min_size(), CosmicMappedInternal::Window(window) => window.min_size(), _ => unreachable!(), } } pub fn max_size(&self) -> Option> { match &self.element { CosmicMappedInternal::Stack(stack) => stack.max_size(), CosmicMappedInternal::Window(window) => window.max_size(), _ => unreachable!(), } } pub fn set_bounds(&self, size: impl Into>>) { let size = size.into(); for (surface, _) in self.windows() { surface.set_bounds(size) } } pub fn latest_size_committed(&self) -> bool { match &self.element { CosmicMappedInternal::Stack(s) => s.surfaces().any(|s| s.latest_size_committed()), CosmicMappedInternal::Window(w) => w.surface().latest_size_committed(), _ => unreachable!(), } } 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 { matches!(&self.element, CosmicMappedInternal::Window(_)) } pub fn is_stack(&self) -> bool { matches!(&self.element, CosmicMappedInternal::Stack(_)) } pub fn stack_ref(&self) -> Option<&CosmicStack> { match &self.element { CosmicMappedInternal::Stack(stack) => Some(stack), _ => None, } } pub fn convert_to_stack( &mut self, (output, overlap): (&Output, Rectangle), theme: cosmic::Theme, appearance: AppearanceConfig, ) { if let CosmicMappedInternal::Window(window) = &self.element { 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, appearance); if let Some(geo) = *self.last_geometry.lock().unwrap() { 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( &mut self, surface: CosmicSurface, (output, overlap): (&Output, Rectangle), theme: cosmic::Theme, appearance: AppearanceConfig, ) { let handle = self.loop_handle(); surface.try_force_undecorated(false); surface.set_tiled(false); let window = CosmicWindow::new(surface, handle, theme, appearance); if let Some(geo) = *self.last_geometry.lock().unwrap() { 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::new( (10, 10).into(), (100, 100).into(), ))); } else { debug.take(); } } pub fn popup_render_elements( &self, renderer: &mut R, location: smithay::utils::Point, scale: smithay::utils::Scale, alpha: f32, ) -> Vec where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, C: From>, { match &self.element { CosmicMappedInternal::Stack(s) => s .popup_render_elements::>( renderer, location, scale, alpha, ), CosmicMappedInternal::Window(w) => w .popup_render_elements::>( renderer, location, scale, alpha, ), _ => unreachable!(), } .into_iter() .map(C::from) .collect() } pub fn shadow_render_element( &self, renderer: &mut R, location: smithay::utils::Point, max_size: Option>, output_scale: smithay::utils::Scale, scale: f64, alpha: f32, ) -> Option where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, C: From>, { if !self.element.alive() { return None; } match &self.element { CosmicMappedInternal::Stack(s) => s .shadow_render_element::>( renderer, location, max_size, output_scale, scale, alpha, ) .map(Into::into), CosmicMappedInternal::Window(w) => w .shadow_render_element::>( renderer, location, max_size, output_scale, scale, alpha, ) .map(Into::into), _ => unreachable!(), } } pub fn render_elements( &self, renderer: &mut R, location: smithay::utils::Point, max_size: Option>, scale: smithay::utils::Scale, alpha: f32, scanout_override: Option, ) -> Vec where R: AsGlowRenderer, R::TextureId: Send + Clone + 'static, CosmicMappedRenderElement: RenderElement, C: From>, { #[cfg(feature = "debug")] let mut 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_without_ssd(), window.max_size_without_ssd(), window.geometry().size, ); let area = Rectangle::::new( 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".into()) .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) .corner_radius(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(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![CosmicMappedRenderElement::from(element)], Err(err) => { debug!(?err, "Error rendering debug overlay."); Vec::new() } } } else { Vec::new() }; #[cfg(not(feature = "debug"))] let mut elements = Vec::new(); #[cfg_attr(not(feature = "debug"), allow(unused_mut))] elements.extend(match &self.element { CosmicMappedInternal::Stack(s) => s.render_elements::>( renderer, location, max_size, scale, alpha, scanout_override, ), CosmicMappedInternal::Window(w) => w .render_elements::>( renderer, location, max_size, scale, alpha, scanout_override, ), _ => unreachable!(), }); 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 update_appearance_conf(&self, appearance: &AppearanceConfig) { match &self.element { CosmicMappedInternal::Window(w) => w.update_appearance_conf(appearance), CosmicMappedInternal::Stack(s) => s.update_appearance_conf(appearance), 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(_) => {} } } pub fn key(&self) -> CosmicMappedKey { CosmicMappedKey(match &self.element { CosmicMappedInternal::Stack(stack) => { CosmicMappedKeyInner::Stack(Arc::downgrade(&stack.0.0)) } CosmicMappedInternal::Window(window) => { CosmicMappedKeyInner::Window(Arc::downgrade(&window.0.0)) } _ => unreachable!(), }) } pub fn ssd_height(&self, pending: bool) -> Option { match &self.element { CosmicMappedInternal::Window(w) => (!w.surface().is_decorated(pending)) .then_some(crate::shell::element::window::SSD_HEIGHT), CosmicMappedInternal::Stack(_) => Some(crate::shell::element::stack::TAB_HEIGHT), _ => unreachable!(), } } pub fn corner_radius(&self, geometry_size: Size, default_radius: u8) -> [u8; 4] { match &self.element { CosmicMappedInternal::Window(w) => w.corner_radius(geometry_size, default_radius), CosmicMappedInternal::Stack(s) => s.corner_radius(geometry_size, default_radius), _ => unreachable!(), } } } 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().map(|s| Cow::Owned(s.into_owned())) } CosmicMappedInternal::Stack(s) => { s.active().wl_surface().map(|s| Cow::Owned(s.into_owned())) } _ => 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.active().same_client_as(object_id), _ => false, } } } impl From for CosmicMapped { fn from(w: CosmicWindow) -> Self { CosmicMapped { element: CosmicMappedInternal::Window(w), 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), 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: AsGlowRenderer, R::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: AsGlowRenderer, R::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) -> OpaqueRegions { 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 where R: AsGlowRenderer, R::TextureId: 'static, R::Error: FromGlesError, { fn draw( &self, frame: &mut R::Frame<'_, '_>, src: Rectangle, dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], ) -> Result<(), R::Error> { match self { CosmicMappedRenderElement::Stack(elem) => { elem.draw(frame, src, dst, damage, opaque_regions) } CosmicMappedRenderElement::Window(elem) => { elem.draw(frame, src, dst, damage, opaque_regions) } CosmicMappedRenderElement::TiledStack(elem) => { elem.draw(frame, src, dst, damage, opaque_regions) } CosmicMappedRenderElement::TiledWindow(elem) => { elem.draw(frame, src, dst, damage, opaque_regions) } CosmicMappedRenderElement::TiledOverlay(elem) => RenderElement::::draw( elem, R::glow_frame_mut(frame), src, dst, damage, opaque_regions, ) .map_err(FromGlesError::from_gles_error), CosmicMappedRenderElement::MovingStack(elem) => { elem.draw(frame, src, dst, damage, opaque_regions) } CosmicMappedRenderElement::MovingWindow(elem) => { elem.draw(frame, src, dst, damage, opaque_regions) } CosmicMappedRenderElement::GrabbedStack(elem) => { elem.draw(frame, src, dst, damage, opaque_regions) } CosmicMappedRenderElement::GrabbedWindow(elem) => { elem.draw(frame, src, dst, damage, opaque_regions) } CosmicMappedRenderElement::FocusIndicator(elem) => RenderElement::::draw( elem, R::glow_frame_mut(frame), src, dst, damage, opaque_regions, ) .map_err(FromGlesError::from_gles_error), CosmicMappedRenderElement::Overlay(elem) => RenderElement::::draw( elem, R::glow_frame_mut(frame), src, dst, damage, opaque_regions, ) .map_err(FromGlesError::from_gles_error), CosmicMappedRenderElement::StackHoverIndicator(elem) => { elem.draw(frame, src, dst, damage, opaque_regions) } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { let glow_frame = R::glow_frame_mut(frame); RenderElement::::draw( elem, glow_frame, src, dst, damage, opaque_regions, ) .map_err(FromGlesError::from_gles_error) } } } fn underlying_storage(&self, renderer: &mut R) -> 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(); elem.underlying_storage(glow_renderer) } } } } impl From> for CosmicMappedRenderElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: stack::CosmicStackRenderElement) -> Self { CosmicMappedRenderElement::Stack(elem) } } impl From> for CosmicMappedRenderElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: window::CosmicWindowRenderElement) -> Self { CosmicMappedRenderElement::Window(elem) } } impl From for CosmicMappedRenderElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: PixelShaderElement) -> Self { CosmicMappedRenderElement::FocusIndicator(elem) } } impl From> for CosmicMappedRenderElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: MemoryRenderBufferRenderElement) -> Self { CosmicMappedRenderElement::StackHoverIndicator(elem) } } #[cfg(feature = "debug")] impl From> for CosmicMappedRenderElement where R: AsGlowRenderer, R::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { fn from(elem: TextureRenderElement) -> Self { CosmicMappedRenderElement::Egui(elem) } }