element: Introduce CosmicMappedKey for safely hashing windows across threads

This commit is contained in:
Victoria Brekenfeld 2024-06-07 19:15:16 +02:00 committed by Victoria Brekenfeld
parent f481112cf9
commit bd58481d19
8 changed files with 75 additions and 20 deletions

View file

@ -4,7 +4,7 @@ use std::{
borrow::{Borrow, BorrowMut}, borrow::{Borrow, BorrowMut},
cell::RefCell, cell::RefCell,
collections::HashMap, collections::HashMap,
sync::Weak, sync::{Arc, RwLock, Weak},
time::Instant, time::Instant,
}; };
@ -14,6 +14,7 @@ use crate::{
backend::render::element::DamageElement, backend::render::element::DamageElement,
config::Config, config::Config,
shell::{ shell::{
element::CosmicMappedKey,
focus::target::WindowGroup, focus::target::WindowGroup,
grabs::{SeatMenuGrabState, SeatMoveGrabState}, grabs::{SeatMenuGrabState, SeatMoveGrabState},
layout::tiling::ANIMATION_DURATION, layout::tiling::ANIMATION_DURATION,
@ -112,7 +113,7 @@ pub enum Usage {
pub enum Key { pub enum Key {
Static(Id), Static(Id),
Group(Weak<()>), Group(Weak<()>),
Window(Usage, CosmicMapped), Window(Usage, CosmicMappedKey),
} }
impl std::hash::Hash for Key { impl std::hash::Hash for Key {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {

View file

@ -4,7 +4,7 @@ use crate::{
GlMultiError, GlMultiFrame, GlMultiRenderer, GlMultiError, GlMultiFrame, GlMultiRenderer,
}, },
state::State, state::State,
utils::prelude::*, utils::{iced::IcedElementInternal, prelude::*},
}; };
use calloop::LoopHandle; use calloop::LoopHandle;
use id_tree::NodeId; use id_tree::NodeId;
@ -40,13 +40,15 @@ use smithay::{
}, },
xwayland::{xwm::X11Relatable, X11Surface}, xwayland::{xwm::X11Relatable, X11Surface},
}; };
use stack::CosmicStackInternal;
use window::CosmicWindowInternal;
use std::{ use std::{
borrow::Cow, borrow::Cow,
collections::HashMap, collections::HashMap,
fmt, fmt,
hash::Hash, hash::Hash,
sync::{atomic::AtomicBool, Arc, Mutex}, sync::{atomic::AtomicBool, Arc, Mutex, Weak},
}; };
pub mod surface; pub mod surface;
@ -126,6 +128,46 @@ impl fmt::Debug for CosmicMapped {
} }
} }
#[derive(Clone)]
pub struct CosmicMappedKey(CosmicMappedKeyInner);
#[derive(Clone)]
enum CosmicMappedKeyInner {
Window(Weak<Mutex<IcedElementInternal<CosmicWindowInternal>>>),
Stack(Weak<Mutex<IcedElementInternal<CosmicStackInternal>>>),
}
impl Hash for CosmicMappedKey {
fn hash<H: std::hash::Hasher>(&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 PartialEq for CosmicMapped { impl PartialEq for CosmicMapped {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.element == other.element self.element == other.element
@ -835,6 +877,18 @@ impl CosmicMapped {
CosmicMappedInternal::_GenericCatcher(_) => {} 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!(),
})
}
} }
impl IsAlive for CosmicMapped { impl IsAlive for CosmicMapped {

View file

@ -77,7 +77,7 @@ use self::{
static SCROLLABLE_ID: Lazy<Id> = Lazy::new(|| Id::new("scrollable")); static SCROLLABLE_ID: Lazy<Id> = Lazy::new(|| Id::new("scrollable"));
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub struct CosmicStack(IcedElement<CosmicStackInternal>); pub struct CosmicStack(pub(super) IcedElement<CosmicStackInternal>);
impl fmt::Debug for CosmicStack { impl fmt::Debug for CosmicStack {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View file

@ -62,7 +62,7 @@ use super::{
}; };
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub struct CosmicWindow(IcedElement<CosmicWindowInternal>); pub struct CosmicWindow(pub(super) IcedElement<CosmicWindowInternal>);
impl fmt::Debug for CosmicWindow { impl fmt::Debug for CosmicWindow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

View file

@ -111,7 +111,7 @@ impl MoveGrabState {
Some( Some(
CosmicMappedRenderElement::from(IndicatorShader::focus_element( CosmicMappedRenderElement::from(IndicatorShader::focus_element(
renderer, renderer,
Key::Window(Usage::MoveGrabIndicator, self.window.clone()), Key::Window(Usage::MoveGrabIndicator, self.window.key()),
Rectangle::from_loc_and_size( Rectangle::from_loc_and_size(
render_location, render_location,
self.window self.window
@ -151,7 +151,7 @@ impl MoveGrabState {
vec![ vec![
CosmicMappedRenderElement::from(IndicatorShader::element( CosmicMappedRenderElement::from(IndicatorShader::element(
renderer, renderer,
Key::Window(Usage::SnappingIndicator, self.window.clone()), Key::Window(Usage::SnappingIndicator, self.window.key()),
overlay_geometry, overlay_geometry,
3, 3,
theme.radius_s()[0] as u8, // TODO: Fix once shaders support 4 corner radii customization theme.radius_s()[0] as u8, // TODO: Fix once shaders support 4 corner radii customization
@ -166,7 +166,7 @@ impl MoveGrabState {
.into(), .into(),
CosmicMappedRenderElement::from(BackdropShader::element( CosmicMappedRenderElement::from(BackdropShader::element(
renderer, renderer,
Key::Window(Usage::SnappingIndicator, self.window.clone()), Key::Window(Usage::SnappingIndicator, self.window.key()),
t.overlay_geometry(non_exclusive_geometry, gaps), t.overlay_geometry(non_exclusive_geometry, gaps),
theme.radius_s()[0], // TODO: Fix once shaders support 4 corner radii customization theme.radius_s()[0], // TODO: Fix once shaders support 4 corner radii customization
0.4, 0.4,

View file

@ -1375,7 +1375,7 @@ impl FloatingLayout {
if indicator_thickness > 0 { if indicator_thickness > 0 {
let element = IndicatorShader::focus_element( let element = IndicatorShader::focus_element(
renderer, renderer,
Key::Window(Usage::FocusIndicator, elem.clone()), Key::Window(Usage::FocusIndicator, elem.key()),
geometry, geometry,
indicator_thickness, indicator_thickness,
output_scale, output_scale,

View file

@ -4549,7 +4549,7 @@ where
elements.push( elements.push(
IndicatorShader::element( IndicatorShader::element(
*renderer, *renderer,
Key::Window(Usage::PotentialGroupIndicator, mapped.clone()), Key::Window(Usage::PotentialGroupIndicator, mapped.key()),
geo, geo,
4, 4,
8, 8,
@ -4589,7 +4589,7 @@ where
elements.push( elements.push(
BackdropShader::element( BackdropShader::element(
*renderer, *renderer,
Key::Window(Usage::OverviewBackdrop, mapped.clone()), Key::Window(Usage::OverviewBackdrop, mapped.key()),
geo, geo,
8., 8.,
alpha alpha
@ -4800,7 +4800,7 @@ where
window_elements.push(CosmicMappedRenderElement::FocusIndicator( window_elements.push(CosmicMappedRenderElement::FocusIndicator(
IndicatorShader::focus_element( IndicatorShader::focus_element(
renderer, renderer,
Key::Window(Usage::FocusIndicator, mapped.clone().into()), Key::Window(Usage::FocusIndicator, mapped.clone().key()),
geo, geo,
indicator_thickness, indicator_thickness,
output_scale, output_scale,
@ -5133,7 +5133,7 @@ where
renderer, renderer,
match data { match data {
Data::Mapped { mapped, .. } => { Data::Mapped { mapped, .. } => {
Key::Window(Usage::FocusIndicator, mapped.clone().into()) Key::Window(Usage::FocusIndicator, mapped.clone().key())
} }
Data::Group { alive, .. } => Key::Group(Arc::downgrade(alive)), Data::Group { alive, .. } => Key::Group(Arc::downgrade(alive)),
_ => unreachable!(), _ => unreachable!(),
@ -5250,7 +5250,7 @@ where
.stack_ref() .stack_ref()
.map(|stack| &stack.active() == stack_window) .map(|stack| &stack.active() == stack_window)
.unwrap_or(false), .unwrap_or(false),
_ => unreachable!(), _ => unreachable!(), // TODO: We could swap with a group
}) })
.unwrap_or(false) .unwrap_or(false)
}) })
@ -5262,7 +5262,7 @@ where
0, 0,
CosmicMappedRenderElement::Overlay(BackdropShader::element( CosmicMappedRenderElement::Overlay(BackdropShader::element(
renderer, renderer,
Key::Window(Usage::Overlay, mapped.clone()), Key::Window(Usage::Overlay, mapped.key()),
geo, geo,
0.0, 0.0,
0.3, 0.3,

View file

@ -67,7 +67,7 @@ use smithay::{
}, },
}; };
pub struct IcedElement<P: Program + Send + 'static>(Arc<Mutex<IcedElementInternal<P>>>); pub struct IcedElement<P: Program + Send + 'static>(pub(crate) Arc<Mutex<IcedElementInternal<P>>>);
impl<P: Program + Send + 'static> fmt::Debug for IcedElement<P> { impl<P: Program + Send + 'static> fmt::Debug for IcedElement<P> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -75,8 +75,8 @@ impl<P: Program + Send + 'static> fmt::Debug for IcedElement<P> {
} }
} }
// SAFETY: We cannot really be sure about `iced_native::program::State` sadly, // SAFETY: It is not, we need to make sure we never move this into another thread and drop it there,
// but the rest should be fine. // as on drop it could trigger RefCells in calloop.
unsafe impl<P: Program + Send + 'static> Send for IcedElementInternal<P> {} unsafe impl<P: Program + Send + 'static> Send for IcedElementInternal<P> {}
impl<P: Program + Send + 'static> Clone for IcedElement<P> { impl<P: Program + Send + 'static> Clone for IcedElement<P> {
@ -139,7 +139,7 @@ impl<P: Program> IcedProgram for ProgramWrapper<P> {
} }
} }
struct IcedElementInternal<P: Program + Send + 'static> { pub(crate) struct IcedElementInternal<P: Program + Send + 'static> {
// draw buffer // draw buffer
outputs: HashSet<Output>, outputs: HashSet<Output>,
buffers: HashMap<OrderedFloat<f64>, (MemoryRenderBuffer, Option<(Vec<Primitive>, Color)>)>, buffers: HashMap<OrderedFloat<f64>, (MemoryRenderBuffer, Option<(Vec<Primitive>, Color)>)>,