tiling: Animate tree changes

This commit is contained in:
Victoria Brekenfeld 2023-05-12 20:01:37 +02:00
parent ea1b976076
commit 331b884f1e
23 changed files with 1641 additions and 395 deletions

959
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -22,7 +22,6 @@ log-panics = { version = "2", features = ["with-backtrace"] }
thiserror = "1.0.26" thiserror = "1.0.26"
regex = "1" regex = "1"
xcursor = "0.3.3" xcursor = "0.3.3"
id_tree = "1.8.0"
xkbcommon = "0.4" xkbcommon = "0.4"
indexmap = "1.8.0" indexmap = "1.8.0"
xdg = "^2.1" xdg = "^2.1"
@ -40,6 +39,11 @@ tracing-journald = "0.3.0"
tracing = { version = "0.1.37", features = ["max_level_debug", "release_max_level_info"] } tracing = { version = "0.1.37", features = ["max_level_debug", "release_max_level_info"] }
puffin = { version = "0.14.3", optional = true } puffin = { version = "0.14.3", optional = true }
puffin_egui = { version = "0.21.0", optional = true } puffin_egui = { version = "0.21.0", optional = true }
cosmic-time = "0.2.0"
[dependencies.id_tree]
git = "https://github.com/Drakulix/id-tree.git"
branch = "feature/copy_clone"
[dependencies.smithay] [dependencies.smithay]
version = "0.3" version = "0.3"
@ -70,4 +74,4 @@ debug = true
lto = "fat" lto = "fat"
[patch."https://github.com/Smithay/smithay.git"] [patch."https://github.com/Smithay/smithay.git"]
smithay = { git = "https://github.com/smithay//smithay", rev = "25d1176484" } smithay = { git = "https://github.com/pop-os/smithay", branch = "tiling_rework" }

View file

@ -485,7 +485,9 @@ impl State {
} }
surface.pending = false; surface.pending = false;
surface.dirty.then(|| { (surface.dirty
|| data.state.common.shell.animations_going())
.then(|| {
(surface.output.clone(), surface.fps.avg_rendertime(5)) (surface.output.clone(), surface.fps.avg_rendertime(5))
}) })
} }

View file

@ -162,6 +162,7 @@ where
surface, surface,
position.to_physical_precise_round(scale), position.to_physical_precise_round(scale),
scale, scale,
1.0,
) )
} }
@ -190,6 +191,7 @@ where
surface, surface,
location.into().to_physical_precise_round(scale), location.into().to_physical_precise_round(scale),
scale, scale,
1.0,
) )
} }

View file

@ -118,6 +118,16 @@ where
CosmicElement::Egui(elem) => elem.opaque_regions(scale), CosmicElement::Egui(elem) => elem.opaque_regions(scale),
} }
} }
fn alpha(&self) -> f32 {
match self {
CosmicElement::Workspace(elem) => elem.alpha(),
CosmicElement::Cursor(elem) => elem.alpha(),
CosmicElement::MoveGrab(elem) => elem.alpha(),
#[cfg(feature = "debug")]
CosmicElement::Egui(elem) => elem.alpha(),
}
}
} }
impl RenderElement<GlowRenderer> for CosmicElement<GlowRenderer> { impl RenderElement<GlowRenderer> for CosmicElement<GlowRenderer> {

View file

@ -66,7 +66,7 @@ pub type GlMultiFrame<'a, 'b, 'frame> =
MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>; MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend<GlowRenderer>, GbmGlesBackend<GlowRenderer>>;
pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0]; pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0];
pub static FOCUS_INDICATOR_COLOR: [f32; 4] = [0.580, 0.921, 0.921, 1.0]; pub static FOCUS_INDICATOR_COLOR: [f32; 3] = [0.580, 0.921, 0.921];
pub static FOCUS_INDICATOR_SHADER: &str = include_str!("./shaders/focus_indicator.frag"); pub static FOCUS_INDICATOR_SHADER: &str = include_str!("./shaders/focus_indicator.frag");
pub struct IndicatorShader(pub GlesPixelProgram); pub struct IndicatorShader(pub GlesPixelProgram);
@ -87,6 +87,7 @@ impl IndicatorShader {
renderer: &R, renderer: &R,
geo: Rectangle<i32, Logical>, geo: Rectangle<i32, Logical>,
thickness: u8, thickness: u8,
alpha: f32,
) -> PixelShaderElement { ) -> PixelShaderElement {
let thickness: f32 = thickness as f32; let thickness: f32 = thickness as f32;
let thickness_loc = (thickness as i32, thickness as i32); let thickness_loc = (thickness as i32, thickness as i32);
@ -110,15 +111,14 @@ impl IndicatorShader {
} }
None => { None => {
let shader = Self::get(renderer); let shader = Self::get(renderer);
let color = FOCUS_INDICATOR_COLOR;
let elem = PixelShaderElement::new( let elem = PixelShaderElement::new(
shader, shader,
dbg!(geo), geo,
None, //TODO None, //TODO
color[3], alpha,
vec![ vec![
Uniform::new("color", [color[0], color[1], color[2]]), Uniform::new("color", FOCUS_INDICATOR_COLOR),
Uniform::new("thickness", thickness), Uniform::new("thickness", thickness),
Uniform::new("radius", thickness * 2.0), Uniform::new("radius", thickness * 2.0),
], ],
@ -283,6 +283,11 @@ where
} }
} }
state
.shell
.space_for_handle_mut(&handle)
.ok_or(OutputNoMode)?
.update_animations(&state.event_loop_handle);
let workspace = state.shell.space_for_handle(&handle).ok_or(OutputNoMode)?; let workspace = state.shell.space_for_handle(&handle).ok_or(OutputNoMode)?;
let last_active_seat = state.last_active_seat().clone(); let last_active_seat = state.last_active_seat().clone();
let move_active = last_active_seat let move_active = last_active_seat

View file

@ -95,7 +95,7 @@ impl WinitState {
.unwrap_or_default(), .unwrap_or_default(),
0, 0,
wp_presentation_feedback::Kind::Vsync, wp_presentation_feedback::Kind::Vsync,
) );
} }
} }
Err(err) => { Err(err) => {

View file

@ -66,6 +66,10 @@ fn main() -> Result<()> {
} }
// trigger routines // trigger routines
data.state
.common
.shell
.update_animations(&data.state.common.event_loop_handle);
data.state.common.shell.refresh(); data.state.common.shell.refresh();
state::Common::refresh_focus(&mut data.state); state::Common::refresh_focus(&mut data.state);

View file

@ -11,7 +11,10 @@ use smithay::{
backend::{ backend::{
input::KeyState, input::KeyState,
renderer::{ renderer::{
element::{AsRenderElements, Element, RenderElement, UnderlyingStorage}, element::{
utils::CropRenderElement, AsRenderElements, Element, RenderElement,
UnderlyingStorage,
},
gles::element::PixelShaderElement, gles::element::PixelShaderElement,
glow::GlowRenderer, glow::GlowRenderer,
multigpu::Error as MultiError, multigpu::Error as MultiError,
@ -418,15 +421,17 @@ impl CosmicMapped {
} }
} }
pub fn configure(&self) { pub fn configure(&self) -> Option<Serial> {
for window in match &self.element { match &self.element {
CosmicMappedInternal::Stack(s) => { CosmicMappedInternal::Stack(s) => {
Box::new(s.surfaces()) as Box<dyn Iterator<Item = CosmicSurface>> let active = s.active();
for surface in s.surfaces().filter(|s| s != &active) {
surface.send_configure();
} }
CosmicMappedInternal::Window(w) => Box::new(std::iter::once(w.surface())), active.send_configure()
}
CosmicMappedInternal::Window(w) => w.surface().send_configure(),
_ => unreachable!(), _ => unreachable!(),
} {
window.send_configure();
} }
} }
@ -676,6 +681,8 @@ where
{ {
Stack(self::stack::CosmicStackRenderElement<R>), Stack(self::stack::CosmicStackRenderElement<R>),
Window(self::window::CosmicWindowRenderElement<R>), Window(self::window::CosmicWindowRenderElement<R>),
CroppedStack(CropRenderElement<self::stack::CosmicStackRenderElement<R>>),
CroppedWindow(CropRenderElement<self::window::CosmicWindowRenderElement<R>>),
Indicator(PixelShaderElement), Indicator(PixelShaderElement),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
Egui(TextureRenderElement<GlesTexture>), Egui(TextureRenderElement<GlesTexture>),
@ -690,6 +697,8 @@ where
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.id(), CosmicMappedRenderElement::Stack(elem) => elem.id(),
CosmicMappedRenderElement::Window(elem) => elem.id(), CosmicMappedRenderElement::Window(elem) => elem.id(),
CosmicMappedRenderElement::CroppedStack(elem) => elem.id(),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.id(),
CosmicMappedRenderElement::Indicator(elem) => elem.id(), CosmicMappedRenderElement::Indicator(elem) => elem.id(),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.id(), CosmicMappedRenderElement::Egui(elem) => elem.id(),
@ -700,6 +709,8 @@ where
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.current_commit(), CosmicMappedRenderElement::Stack(elem) => elem.current_commit(),
CosmicMappedRenderElement::Window(elem) => elem.current_commit(), CosmicMappedRenderElement::Window(elem) => elem.current_commit(),
CosmicMappedRenderElement::CroppedStack(elem) => elem.current_commit(),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.current_commit(),
CosmicMappedRenderElement::Indicator(elem) => elem.current_commit(), CosmicMappedRenderElement::Indicator(elem) => elem.current_commit(),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.current_commit(), CosmicMappedRenderElement::Egui(elem) => elem.current_commit(),
@ -710,6 +721,8 @@ where
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.src(), CosmicMappedRenderElement::Stack(elem) => elem.src(),
CosmicMappedRenderElement::Window(elem) => elem.src(), CosmicMappedRenderElement::Window(elem) => elem.src(),
CosmicMappedRenderElement::CroppedStack(elem) => elem.src(),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.src(),
CosmicMappedRenderElement::Indicator(elem) => elem.src(), CosmicMappedRenderElement::Indicator(elem) => elem.src(),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.src(), CosmicMappedRenderElement::Egui(elem) => elem.src(),
@ -720,6 +733,8 @@ where
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.geometry(scale), CosmicMappedRenderElement::Stack(elem) => elem.geometry(scale),
CosmicMappedRenderElement::Window(elem) => elem.geometry(scale), CosmicMappedRenderElement::Window(elem) => elem.geometry(scale),
CosmicMappedRenderElement::CroppedStack(elem) => elem.geometry(scale),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.geometry(scale),
CosmicMappedRenderElement::Indicator(elem) => elem.geometry(scale), CosmicMappedRenderElement::Indicator(elem) => elem.geometry(scale),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.geometry(scale), CosmicMappedRenderElement::Egui(elem) => elem.geometry(scale),
@ -730,6 +745,8 @@ where
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.location(scale), CosmicMappedRenderElement::Stack(elem) => elem.location(scale),
CosmicMappedRenderElement::Window(elem) => elem.location(scale), CosmicMappedRenderElement::Window(elem) => elem.location(scale),
CosmicMappedRenderElement::CroppedStack(elem) => elem.location(scale),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.location(scale),
CosmicMappedRenderElement::Indicator(elem) => elem.location(scale), CosmicMappedRenderElement::Indicator(elem) => elem.location(scale),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.location(scale), CosmicMappedRenderElement::Egui(elem) => elem.location(scale),
@ -740,6 +757,8 @@ where
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.transform(), CosmicMappedRenderElement::Stack(elem) => elem.transform(),
CosmicMappedRenderElement::Window(elem) => elem.transform(), CosmicMappedRenderElement::Window(elem) => elem.transform(),
CosmicMappedRenderElement::CroppedStack(elem) => elem.transform(),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.transform(),
CosmicMappedRenderElement::Indicator(elem) => elem.transform(), CosmicMappedRenderElement::Indicator(elem) => elem.transform(),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.transform(), CosmicMappedRenderElement::Egui(elem) => elem.transform(),
@ -754,6 +773,8 @@ where
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::Stack(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::Window(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::Window(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::CroppedStack(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.damage_since(scale, commit),
CosmicMappedRenderElement::Indicator(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::Indicator(elem) => elem.damage_since(scale, commit),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::Egui(elem) => elem.damage_since(scale, commit),
@ -764,11 +785,25 @@ where
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::Stack(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::Window(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::Window(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::CroppedStack(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.opaque_regions(scale),
CosmicMappedRenderElement::Indicator(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::Indicator(elem) => elem.opaque_regions(scale),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::Egui(elem) => elem.opaque_regions(scale),
} }
} }
fn alpha(&self) -> f32 {
match self {
CosmicMappedRenderElement::Stack(elem) => elem.alpha(),
CosmicMappedRenderElement::Window(elem) => elem.alpha(),
CosmicMappedRenderElement::CroppedStack(elem) => elem.alpha(),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.alpha(),
CosmicMappedRenderElement::Indicator(elem) => elem.alpha(),
#[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.alpha(),
}
}
} }
impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> { impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
@ -782,6 +817,8 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::CroppedStack(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::Indicator(elem) => { CosmicMappedRenderElement::Indicator(elem) => {
RenderElement::<GlowRenderer>::draw(elem, frame, src, dst, damage) RenderElement::<GlowRenderer>::draw(elem, frame, src, dst, damage)
} }
@ -796,6 +833,8 @@ impl RenderElement<GlowRenderer> for CosmicMappedRenderElement<GlowRenderer> {
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::CroppedStack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::Indicator(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Indicator(elem) => elem.underlying_storage(renderer),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
CosmicMappedRenderElement::Egui(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Egui(elem) => elem.underlying_storage(renderer),
@ -816,6 +855,8 @@ impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::CroppedStack(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.draw(frame, src, dst, damage),
CosmicMappedRenderElement::Indicator(elem) => { CosmicMappedRenderElement::Indicator(elem) => {
RenderElement::<GlowRenderer>::draw(elem, frame.glow_frame_mut(), src, dst, damage) RenderElement::<GlowRenderer>::draw(elem, frame.glow_frame_mut(), src, dst, damage)
.map_err(|err| MultiError::Render(err)) .map_err(|err| MultiError::Render(err))
@ -836,6 +877,8 @@ impl<'a, 'b> RenderElement<GlMultiRenderer<'a, 'b>>
match self { match self {
CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::CroppedStack(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::CroppedWindow(elem) => elem.underlying_storage(renderer),
CosmicMappedRenderElement::Indicator(elem) => { CosmicMappedRenderElement::Indicator(elem) => {
elem.underlying_storage(renderer.glow_renderer_mut()) elem.underlying_storage(renderer.glow_renderer_mut())
} }
@ -910,6 +953,7 @@ where
renderer: &mut R, renderer: &mut R,
location: Point<i32, Physical>, location: Point<i32, Physical>,
scale: Scale<f64>, scale: Scale<f64>,
alpha: f32,
) -> Vec<C> { ) -> Vec<C> {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
let mut elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() { let mut elements = if let Some(debug) = self.debug.lock().unwrap().as_mut() {
@ -1080,12 +1124,12 @@ where
CosmicMappedInternal::Stack(s) => { CosmicMappedInternal::Stack(s) => {
elements.extend(AsRenderElements::<R>::render_elements::< elements.extend(AsRenderElements::<R>::render_elements::<
CosmicMappedRenderElement<R>, CosmicMappedRenderElement<R>,
>(s, renderer, location, scale)) >(s, renderer, location, scale, alpha))
} }
CosmicMappedInternal::Window(w) => { CosmicMappedInternal::Window(w) => {
elements.extend(AsRenderElements::<R>::render_elements::< elements.extend(AsRenderElements::<R>::render_elements::<
CosmicMappedRenderElement<R>, CosmicMappedRenderElement<R>,
>(w, renderer, location, scale)) >(w, renderer, location, scale, alpha))
} }
_ => {} _ => {}
}; };

View file

@ -604,9 +604,10 @@ where
renderer: &mut R, renderer: &mut R,
mut location: Point<i32, Physical>, mut location: Point<i32, Physical>,
scale: Scale<f64>, scale: Scale<f64>,
alpha: f32,
) -> Vec<C> { ) -> Vec<C> {
let mut elements = AsRenderElements::<R>::render_elements::<CosmicStackRenderElement<R>>( let mut elements = AsRenderElements::<R>::render_elements::<CosmicStackRenderElement<R>>(
&self.0, renderer, location, scale, &self.0, renderer, location, scale, alpha,
); );
location.y += TAB_HEIGHT; location.y += TAB_HEIGHT;
@ -616,6 +617,7 @@ where
renderer, renderer,
location, location,
scale, scale,
alpha,
); );
elements elements
})); }));

View file

@ -29,7 +29,7 @@ use smithay::{
wayland_server::protocol::wl_surface::WlSurface, wayland_server::protocol::wl_surface::WlSurface,
}, },
space_elements, space_elements,
utils::{user_data::UserDataMap, Logical, Rectangle, Size}, utils::{user_data::UserDataMap, Logical, Rectangle, Serial, Size},
wayland::{ wayland::{
compositor::{with_states, SurfaceData}, compositor::{with_states, SurfaceData},
seat::WaylandFocus, seat::WaylandFocus,
@ -345,11 +345,44 @@ impl CosmicSurface {
}) })
} }
pub fn send_configure(&self) { pub fn serial_acked(&self, serial: &Serial) -> bool {
match self { match self {
CosmicSurface::Wayland(window) => window.toplevel().send_configure(), CosmicSurface::Wayland(window) => {
with_states(window.toplevel().wl_surface(), |states| {
let attrs = states
.data_map
.get::<XdgToplevelSurfaceData>()
.unwrap()
.lock()
.unwrap();
attrs
.configure_serial
.as_ref()
.map(|s| s >= serial)
.unwrap_or(false)
})
}
_ => true,
}
}
pub fn force_configure(&self) -> Option<Serial> {
match self {
CosmicSurface::Wayland(window) => Some(window.toplevel().send_configure()),
CosmicSurface::X11(surface) => { CosmicSurface::X11(surface) => {
let _ = surface.configure(None); let _ = surface.configure(None);
None
}
_ => unreachable!(),
}
}
pub fn send_configure(&self) -> Option<Serial> {
match self {
CosmicSurface::Wayland(window) => window.toplevel().send_pending_configure(),
CosmicSurface::X11(surface) => {
let _ = surface.configure(None);
None
} }
_ => unreachable!(), _ => unreachable!(),
} }
@ -675,10 +708,15 @@ where
renderer: &mut R, renderer: &mut R,
location: smithay::utils::Point<i32, smithay::utils::Physical>, location: smithay::utils::Point<i32, smithay::utils::Physical>,
scale: smithay::utils::Scale<f64>, scale: smithay::utils::Scale<f64>,
alpha: f32,
) -> Vec<C> { ) -> Vec<C> {
match self { match self {
CosmicSurface::Wayland(window) => window.render_elements(renderer, location, scale), CosmicSurface::Wayland(window) => {
CosmicSurface::X11(surface) => surface.render_elements(renderer, location, scale), window.render_elements(renderer, location, scale, alpha)
}
CosmicSurface::X11(surface) => {
surface.render_elements(renderer, location, scale, alpha)
}
_ => unreachable!(), _ => unreachable!(),
} }
} }

View file

@ -640,6 +640,13 @@ where
CosmicWindowRenderElement::Window(w) => w.opaque_regions(scale), CosmicWindowRenderElement::Window(w) => w.opaque_regions(scale),
} }
} }
fn alpha(&self) -> f32 {
match self {
CosmicWindowRenderElement::Header(h) => h.alpha(),
CosmicWindowRenderElement::Window(w) => w.alpha(),
}
}
} }
impl RenderElement<GlowRenderer> for CosmicWindowRenderElement<GlowRenderer> { impl RenderElement<GlowRenderer> for CosmicWindowRenderElement<GlowRenderer> {
@ -710,6 +717,7 @@ where
renderer: &mut R, renderer: &mut R,
location: Point<i32, Physical>, location: Point<i32, Physical>,
scale: Scale<f64>, scale: Scale<f64>,
alpha: f32,
) -> Vec<C> { ) -> Vec<C> {
let has_ssd = self.0.with_program(|p| p.has_ssd()); let has_ssd = self.0.with_program(|p| p.has_ssd());
@ -721,14 +729,18 @@ where
let mut elements = self.0.with_program(|p| { let mut elements = self.0.with_program(|p| {
AsRenderElements::<R>::render_elements::<CosmicWindowRenderElement<R>>( AsRenderElements::<R>::render_elements::<CosmicWindowRenderElement<R>>(
&p.window, renderer, window_loc, scale, &p.window, renderer, window_loc, scale, alpha,
) )
}); });
if has_ssd { if has_ssd {
elements.extend(AsRenderElements::<GlowRenderer>::render_elements::< elements.extend(AsRenderElements::<GlowRenderer>::render_elements::<
CosmicWindowRenderElement<R>, CosmicWindowRenderElement<R>,
>( >(
&self.0, renderer.glow_renderer_mut(), location, scale &self.0,
renderer.glow_renderer_mut(),
location,
scale,
alpha,
)) ))
} }

View file

@ -68,6 +68,7 @@ impl MoveGrabState {
renderer, renderer,
Rectangle::from_loc_and_size(render_location, self.window.geometry().size), Rectangle::from_loc_and_size(render_location, self.window.geometry().size),
self.indicator_thickness, self.indicator_thickness,
1.0,
)) ))
.into(), .into(),
); );
@ -77,6 +78,7 @@ impl MoveGrabState {
renderer, renderer,
(render_location - self.window.geometry().loc).to_physical_precise_round(scale), (render_location - self.window.geometry().loc).to_physical_precise_round(scale),
scale, scale,
1.0,
)); ));
elements elements
} }
@ -282,7 +284,10 @@ impl MoveSurfaceGrab {
if let Some(position) = position { if let Some(position) = position {
handle.motion( handle.motion(
state, state,
Some((PointerFocusTarget::from(self.window.clone()), position - self.window.geometry().loc)), Some((
PointerFocusTarget::from(self.window.clone()),
position - self.window.geometry().loc,
)),
&MotionEvent { &MotionEvent {
location: handle.current_location(), location: handle.current_location(),
serial: serial, serial: serial,

View file

@ -374,6 +374,7 @@ impl FloatingLayout {
renderer, renderer,
render_location.to_physical_precise_round(output_scale), render_location.to_physical_precise_round(output_scale),
output_scale.into(), output_scale.into(),
1.0,
); );
if focused == Some(elem) { if focused == Some(elem) {
if indicator_thickness > 0 { if indicator_thickness > 0 {
@ -384,6 +385,7 @@ impl FloatingLayout {
elem.geometry().size, elem.geometry().size,
), ),
indicator_thickness, indicator_thickness,
1.0,
); );
elements.insert(0, element.into()); elements.insert(0, element.into());
} }

View file

@ -0,0 +1,65 @@
use crate::{
shell::element::CosmicSurface, state::Data,
wayland::handlers::compositor::client_compositor_state,
};
use calloop::LoopHandle;
use smithay::{
reexports::wayland_server::{backend::ClientId, Client, Resource},
utils::Serial,
wayland::{
compositor::{Blocker, BlockerState},
seat::WaylandFocus,
},
};
use std::{
collections::HashMap,
time::{Duration, Instant},
};
#[derive(Debug, Clone)]
pub struct TilingBlocker {
pub necessary_acks: Vec<(CosmicSurface, Serial)>,
start: Instant,
}
impl Blocker for TilingBlocker {
fn state(&self) -> BlockerState {
if self.is_ready() {
BlockerState::Released
} else {
BlockerState::Pending
}
}
}
impl TilingBlocker {
pub fn new(configures: impl IntoIterator<Item = (CosmicSurface, Serial)>) -> Self {
TilingBlocker {
necessary_acks: configures.into_iter().collect(),
start: Instant::now(),
}
}
pub fn is_ready(&self) -> bool {
Instant::now().duration_since(self.start) >= Duration::from_millis(200)
|| self
.necessary_acks
.iter()
.all(|(surf, serial)| surf.serial_acked(serial))
}
pub fn signal_ready(&self, handle: &LoopHandle<'static, Data>) {
let clients = self
.necessary_acks
.iter()
.flat_map(|(surface, _)| surface.wl_surface().and_then(|s| s.client()))
.map(|client| (client.id(), client))
.collect::<HashMap<ClientId, Client>>();
handle.insert_idle(move |data| {
let dh = data.display.handle();
for client in clients.values() {
client_compositor_state(&client).blocker_cleared(&mut data.state, &dh);
}
});
}
}

View file

@ -64,7 +64,8 @@ impl PointerGrab<State> for ResizeForkGrab {
if let Some(output) = self.output.upgrade() { if let Some(output) = self.output.upgrade() {
let tiling_layer = &mut data.common.shell.active_space_mut(&output).tiling_layer; let tiling_layer = &mut data.common.shell.active_space_mut(&output).tiling_layer;
if let Some(tree) = tiling_layer.trees.get_mut(&output) { if let Some(queue) = tiling_layer.queues.get_mut(&output) {
let tree = &mut queue.trees.back_mut().unwrap().0;
if tree.get(&self.node).is_ok() { if tree.get(&self.node).is_ok() {
let orientation = tree.get(&self.node).unwrap().data().orientation(); let orientation = tree.get(&self.node).unwrap().data().orientation();
let delta = match orientation { let delta = match orientation {

View file

@ -18,24 +18,36 @@ use crate::{
}, },
}; };
use calloop::LoopHandle;
use cosmic_time::{Cubic, Ease, Tween};
use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree}; use id_tree::{InsertBehavior, MoveBehavior, Node, NodeId, NodeIdError, RemoveBehavior, Tree};
use smithay::{ use smithay::{
backend::renderer::{ backend::renderer::{
element::{AsRenderElements, RenderElement}, element::{utils::CropRenderElement, AsRenderElements, RenderElement},
ImportAll, ImportMem, Renderer, ImportAll, ImportMem, Renderer,
}, },
desktop::{layer_map_for_output, space::SpaceElement, PopupKind}, desktop::{layer_map_for_output, space::SpaceElement, PopupKind},
input::{pointer::GrabStartData as PointerGrabStartData, Seat}, input::{pointer::GrabStartData as PointerGrabStartData, Seat},
output::Output, output::Output,
utils::{IsAlive, Logical, Point, Rectangle, Scale}, utils::{IsAlive, Logical, Point, Rectangle, Scale},
wayland::seat::WaylandFocus, wayland::{compositor::add_blocker, seat::WaylandFocus},
};
use std::{
borrow::Borrow,
collections::{HashMap, VecDeque},
hash::Hash,
sync::Arc,
time::{Duration, Instant},
}; };
use std::{borrow::Borrow, collections::HashMap, hash::Hash, sync::Arc};
use tracing::trace; use tracing::trace;
mod blocker;
mod grabs; mod grabs;
pub use self::blocker::*;
pub use self::grabs::*; pub use self::grabs::*;
const ANIMATION_DURATION: Duration = Duration::from_millis(200);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct OutputData { struct OutputData {
output: Output, output: Output,
@ -83,10 +95,24 @@ pub enum FocusResult {
Some(KeyboardFocusTarget), Some(KeyboardFocusTarget),
} }
#[derive(Debug, Clone, Default)]
struct TreeQueue {
trees: VecDeque<(Tree<Data>, Option<TilingBlocker>)>,
animation_start: Option<Instant>,
}
impl TreeQueue {
pub fn push_tree(&mut self, tree: Tree<Data>, blocker: Option<TilingBlocker>) {
self.trees.push_back((tree, blocker))
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TilingLayout { pub struct TilingLayout {
gaps: (i32, i32), gaps: (i32, i32),
trees: HashMap<OutputData, Tree<Data>>, queues: HashMap<OutputData, TreeQueue>,
standby_tree: Option<Tree<Data>>,
pending_blockers: Vec<TilingBlocker>,
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -251,24 +277,33 @@ impl TilingLayout {
pub fn new(gaps: (u8, u8)) -> TilingLayout { pub fn new(gaps: (u8, u8)) -> TilingLayout {
TilingLayout { TilingLayout {
gaps: (gaps.0 as i32, gaps.1 as i32), gaps: (gaps.0 as i32, gaps.1 as i32),
trees: HashMap::new(), queues: HashMap::new(),
standby_tree: None,
pending_blockers: Vec::new(),
} }
} }
} }
impl TilingLayout { impl TilingLayout {
pub fn map_output(&mut self, output: &Output, location: Point<i32, Logical>) { pub fn map_output(&mut self, output: &Output, location: Point<i32, Logical>) {
if !self.trees.contains_key(output) { if !self.queues.contains_key(output) {
self.trees.insert( self.queues.insert(
OutputData { OutputData {
output: output.clone(), output: output.clone(),
location, location,
}, },
Tree::new(), TreeQueue {
trees: {
let mut queue = VecDeque::new();
queue.push_back((self.standby_tree.take().unwrap_or_else(Tree::new), None));
queue
},
animation_start: None,
},
); );
} else { } else {
let tree = self.trees.remove(output).unwrap(); let tree = self.queues.remove(output).unwrap();
self.trees.insert( self.queues.insert(
OutputData { OutputData {
output: output.clone(), output: output.clone(),
location, location,
@ -283,9 +318,19 @@ impl TilingLayout {
output: &Output, output: &Output,
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>, toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
) { ) {
if let Some(src) = self.trees.remove(output) { if let Some(mut src) = self.queues.remove(output) {
// TODO: expects last remaining output // Operate on last pending tree & unblock queue
let Some((new_output, dst)) = self.trees.iter_mut().next() else { return; }; for blocker in src.trees.iter_mut().flat_map(|(_, blocker)| blocker.take()) {
self.pending_blockers.push(blocker);
}
let (src, _) = src.trees.pop_back().expect("No tree in queue");
let Some((new_output, dst_queue)) = self.queues.iter_mut().next() else {
self.standby_tree = Some(src);
return;
};
let mut dst = dst_queue.trees.back().unwrap().0.copy_clone();
let orientation = match new_output.output.geometry().size { let orientation = match new_output.output.geometry().size {
x if x.w >= x.h => Orientation::Vertical, x if x.w >= x.h => Orientation::Vertical,
_ => Orientation::Horizontal, _ => Orientation::Horizontal,
@ -309,8 +354,10 @@ impl TilingLayout {
mapped.output_enter(&new_output.output, mapped.bbox()); mapped.output_enter(&new_output.output, mapped.bbox());
} }
} }
TilingLayout::merge_trees(src, dst, orientation); TilingLayout::merge_trees(src, &mut dst, orientation);
self.refresh()
let blocker = TilingLayout::update_positions(output, &mut dst, self.gaps);
dst_queue.push_tree(dst, blocker);
} }
} }
@ -324,7 +371,6 @@ impl TilingLayout {
window.output_enter(&output, window.bbox()); window.output_enter(&output, window.bbox());
window.set_bounds(output.geometry().size); window.set_bounds(output.geometry().size);
self.map_internal(window, &output, Some(focus_stack)); self.map_internal(window, &output, Some(focus_stack));
self.refresh();
} }
fn map_internal<'a>( fn map_internal<'a>(
@ -333,15 +379,17 @@ impl TilingLayout {
output: &Output, output: &Output,
focus_stack: Option<impl Iterator<Item = &'a CosmicMapped> + 'a>, focus_stack: Option<impl Iterator<Item = &'a CosmicMapped> + 'a>,
) { ) {
let tree = self.trees.get_mut(output).expect("Output not mapped?"); let queue = self.queues.get_mut(output).expect("Output not mapped?");
let mut tree = queue.trees.back().unwrap().0.copy_clone();
let window = window.into(); let window = window.into();
let new_window = Node::new(Data::Mapped { let new_window = Node::new(Data::Mapped {
mapped: window.clone(), mapped: window.clone(),
last_geometry: Rectangle::from_loc_and_size((0, 0), (100, 100)), last_geometry: Rectangle::from_loc_and_size((0, 0), (100, 100)),
}); });
let last_active = let last_active = focus_stack
focus_stack.and_then(|focus_stack| TilingLayout::last_active_window(tree, focus_stack)); .and_then(|focus_stack| TilingLayout::last_active_window(&mut tree, focus_stack));
let window_id = if let Some((_last_active_window, ref node_id)) = last_active { let window_id = if let Some((_last_active_window, ref node_id)) = last_active {
let orientation = { let orientation = {
@ -353,7 +401,7 @@ impl TilingLayout {
} }
}; };
let new_id = tree.insert(new_window, InsertBehavior::AsRoot).unwrap(); let new_id = tree.insert(new_window, InsertBehavior::AsRoot).unwrap();
TilingLayout::new_group(tree, &node_id, &new_id, orientation).unwrap(); TilingLayout::new_group(&mut tree, &node_id, &new_id, orientation).unwrap();
new_id new_id
} else { } else {
// nothing? then we add to the root // nothing? then we add to the root
@ -367,7 +415,7 @@ impl TilingLayout {
} }
}; };
let new_id = tree.insert(new_window, InsertBehavior::AsRoot).unwrap(); let new_id = tree.insert(new_window, InsertBehavior::AsRoot).unwrap();
TilingLayout::new_group(tree, &root_id, &new_id, orientation).unwrap(); TilingLayout::new_group(&mut tree, &root_id, &new_id, orientation).unwrap();
new_id new_id
} else { } else {
tree.insert(new_window, InsertBehavior::AsRoot).unwrap() tree.insert(new_window, InsertBehavior::AsRoot).unwrap()
@ -375,15 +423,23 @@ impl TilingLayout {
}; };
*window.tiling_node_id.lock().unwrap() = Some(window_id); *window.tiling_node_id.lock().unwrap() = Some(window_id);
let blocker = TilingLayout::update_positions(output, &mut tree, self.gaps);
queue.push_tree(tree, blocker);
} }
pub fn unmap(&mut self, window: &CosmicMapped) -> Option<Output> { pub fn unmap(&mut self, window: &CosmicMapped) -> Option<Output> {
let output = { let output = {
let node_id = window.tiling_node_id.lock().unwrap().clone()?; let node_id = window.tiling_node_id.lock().unwrap().clone()?;
self.trees self.queues
.iter() .iter()
.find(|(_, tree)| { .find(|(_, queue)| {
tree.get(&node_id) queue
.trees
.back()
.unwrap()
.0
.get(&node_id)
.map(|node| node.data().is_mapped(Some(window))) .map(|node| node.data().is_mapped(Some(window)))
.unwrap_or(false) .unwrap_or(false)
}) })
@ -391,19 +447,23 @@ impl TilingLayout {
}; };
self.unmap_window_internal(window); self.unmap_window_internal(window);
window.output_leave(&output); window.output_leave(&output);
window.set_tiled(false); window.set_tiled(false);
self.refresh();
Some(output) Some(output)
} }
fn unmap_window_internal(&mut self, mapped: &CosmicMapped) { fn unmap_window_internal(&mut self, mapped: &CosmicMapped) {
if let Some(node_id) = mapped.tiling_node_id.lock().unwrap().as_ref() { let tiling_node_id = mapped.tiling_node_id.lock().unwrap().as_ref().cloned();
if let Some(tree) = self.trees.values_mut().find(|tree| { if let Some(node_id) = tiling_node_id {
tree.get(node_id) if let Some((output, queue)) = self.queues.iter_mut().find(|(_, queue)| {
let tree = &queue.trees.back().unwrap().0;
tree.get(&node_id)
.map(|node| node.data().is_mapped(Some(mapped))) .map(|node| node.data().is_mapped(Some(mapped)))
.unwrap_or(false) .unwrap_or(false)
}) { }) {
let mut tree = queue.trees.back().unwrap().0.copy_clone();
let parent_id = tree let parent_id = tree
.get(&node_id) .get(&node_id)
.ok() .ok()
@ -412,7 +472,7 @@ impl TilingLayout {
let position = parent_id.as_ref().and_then(|parent_id| { let position = parent_id.as_ref().and_then(|parent_id| {
tree.children_ids(&parent_id) tree.children_ids(&parent_id)
.unwrap() .unwrap()
.position(|id| id == node_id) .position(|id| id == &node_id)
}); });
let parent_parent_id = parent_id.as_ref().and_then(|parent_id| { let parent_parent_id = parent_id.as_ref().and_then(|parent_id| {
tree.get(parent_id) tree.get(parent_id)
@ -423,7 +483,7 @@ impl TilingLayout {
// remove self // remove self
trace!(?mapped, "Remove window."); trace!(?mapped, "Remove window.");
let _ = tree.remove_node(node_id.clone(), RemoveBehavior::DropChildren); let _ = tree.remove_node(node_id, RemoveBehavior::DropChildren);
// fixup parent node // fixup parent node
match parent_id { match parent_id {
@ -457,6 +517,9 @@ impl TilingLayout {
} }
None => {} // root None => {} // root
} }
let blocker = TilingLayout::update_positions(&output.output, &mut tree, self.gaps);
queue.push_tree(tree, blocker);
} }
} }
} }
@ -465,11 +528,12 @@ impl TilingLayout {
self.mapped().find_map(|(o, m, _)| (m == elem).then_some(o)) self.mapped().find_map(|(o, m, _)| (m == elem).then_some(o))
} }
// TODO: Move would needs this to be accurate during animations
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Logical>> { pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Logical>> {
if let Some(id) = elem.tiling_node_id.lock().unwrap().as_ref() { if let Some(id) = elem.tiling_node_id.lock().unwrap().as_ref() {
if let Some(output) = self.output_for_element(elem) { if let Some(output) = self.output_for_element(elem) {
let (output_data, tree) = self.trees.get_key_value(output).unwrap(); let (output_data, queue) = self.queues.get_key_value(output).unwrap();
let node = tree.get(id).ok()?; let node = queue.trees.back().unwrap().0.get(id).ok()?;
let data = node.data(); let data = node.data();
assert!(data.is_mapped(Some(elem))); assert!(data.is_mapped(Some(elem)));
let mut geo = *data.geometry(); let mut geo = *data.geometry();
@ -486,9 +550,10 @@ impl TilingLayout {
seat: &Seat<State>, seat: &Seat<State>,
) -> Option<CosmicMapped /*TODO move window groups across screens?*/> { ) -> Option<CosmicMapped /*TODO move window groups across screens?*/> {
let output = seat.active_output(); let output = seat.active_output();
let tree = self.trees.get_mut(&output).unwrap(); let queue = self.queues.get_mut(&output).unwrap();
let mut tree = queue.trees.back().unwrap().0.copy_clone();
let node_id = match TilingLayout::currently_focused_node(tree, seat) { let node_id = match TilingLayout::currently_focused_node(&mut tree, seat) {
Some(node_id) => node_id, Some(node_id) => node_id,
None => { None => {
return None; return None;
@ -533,7 +598,7 @@ impl TilingLayout {
| (Orientation::Vertical, Direction::Down) | (Orientation::Vertical, Direction::Down)
) { ) {
TilingLayout::new_group( TilingLayout::new_group(
tree, &mut tree,
&parent, &parent,
&node_id, &node_id,
match direction { match direction {
@ -556,7 +621,9 @@ impl TilingLayout {
.unwrap() .unwrap()
.data_mut() .data_mut()
.remove_window(og_idx); .remove_window(og_idx);
self.refresh();
let blocker = TilingLayout::update_positions(&output, &mut tree, self.gaps);
queue.push_tree(tree, blocker);
return None; return None;
} }
@ -580,7 +647,9 @@ impl TilingLayout {
.unwrap() .unwrap()
.data_mut() .data_mut()
.remove_window(og_idx); .remove_window(og_idx);
self.refresh();
let blocker = TilingLayout::update_positions(&output, &mut tree, self.gaps);
queue.push_tree(tree, blocker);
return None; return None;
} }
@ -646,7 +715,7 @@ impl TilingLayout {
.unwrap() .unwrap()
.clone(); .clone();
TilingLayout::new_group( TilingLayout::new_group(
tree, &mut tree,
&old_id, &old_id,
&node_id, &node_id,
!group_orientation, !group_orientation,
@ -678,7 +747,8 @@ impl TilingLayout {
.swap_windows(idx, next_idx); .swap_windows(idx, next_idx);
} else { } else {
// else we make a new fork // else we make a new fork
TilingLayout::new_group(tree, &next_child_id, &node_id, orientation).unwrap(); TilingLayout::new_group(&mut tree, &next_child_id, &node_id, orientation)
.unwrap();
tree.make_nth_sibling( tree.make_nth_sibling(
&node_id, &node_id,
if direction == Direction::Left || direction == Direction::Up { if direction == Direction::Left || direction == Direction::Up {
@ -693,7 +763,9 @@ impl TilingLayout {
.data_mut() .data_mut()
.remove_window(og_idx); .remove_window(og_idx);
} }
self.refresh();
let blocker = TilingLayout::update_positions(&output, &mut tree, self.gaps);
queue.push_tree(tree, blocker);
return None; return None;
} }
@ -715,7 +787,7 @@ impl TilingLayout {
focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a, focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a,
) -> FocusResult { ) -> FocusResult {
let output = seat.active_output(); let output = seat.active_output();
let tree = self.trees.get_mut(&output).unwrap(); let tree = &self.queues.get(&output).unwrap().trees.back().unwrap().0;
// TODO: Rather use something like seat.current_keyboard_focus // TODO: Rather use something like seat.current_keyboard_focus
// TODO https://github.com/Smithay/smithay/pull/777 // TODO https://github.com/Smithay/smithay/pull/777
@ -860,8 +932,10 @@ impl TilingLayout {
focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a, focus_stack: impl Iterator<Item = &'a CosmicMapped> + 'a,
) { ) {
let output = seat.active_output(); let output = seat.active_output();
let tree = self.trees.get_mut(&output).unwrap(); let Some(queue) = self.queues.get_mut(&output) else { return };
if let Some((_, last_active)) = TilingLayout::last_active_window(tree, focus_stack) { let mut tree = queue.trees.back().unwrap().0.copy_clone();
if let Some((_, last_active)) = TilingLayout::last_active_window(&tree, focus_stack) {
if let Some(group) = tree.get(&last_active).unwrap().parent().cloned() { if let Some(group) = tree.get(&last_active).unwrap().parent().cloned() {
if let &mut Data::Group { if let &mut Data::Group {
ref mut orientation, ref mut orientation,
@ -890,13 +964,15 @@ impl TilingLayout {
} }
*orientation = new_orientation; *orientation = new_orientation;
let blocker = TilingLayout::update_positions(&output, &mut tree, self.gaps);
queue.push_tree(tree, blocker);
} }
} }
} }
self.refresh();
} }
pub fn refresh<'a>(&mut self) { pub fn refresh(&mut self) {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
puffin::profile_function!(); puffin::profile_function!();
@ -908,53 +984,47 @@ impl TilingLayout {
for dead_window in dead_windows.iter() { for dead_window in dead_windows.iter() {
self.unmap_window_internal(&dead_window); self.unmap_window_internal(&dead_window);
} }
// flatten trees
for tree in self.trees.values_mut() {
let root_id = match tree.root_node_id() {
Some(root) => root,
None => {
continue;
}
};
for node_id in tree
.traverse_pre_order_ids(root_id)
.unwrap()
.collect::<Vec<_>>()
.into_iter()
{
let node = tree.get(&node_id).unwrap();
let data = node.data();
if data.is_group() && data.len() == 1 {
// RemoveBehavior::LiftChildren sadly does not what we want: lifting them into the same place.
// So we need to fix that manually..
let child_id = tree
.children_ids(&node_id)
.unwrap()
.cloned()
.next()
.unwrap();
let idx = node.parent().map(|parent_id| {
tree.children_ids(&parent_id)
.unwrap()
.position(|id| id == &node_id)
.unwrap()
});
tree.remove_node(node_id, RemoveBehavior::LiftChildren)
.unwrap();
if let Some(idx) = idx {
tree.make_nth_sibling(&child_id, idx).unwrap();
} else {
// additionally `RemoveBehavior::LiftChildren` doesn't work, when removing the root-node,
// even with just one child. *sigh*
tree.move_node(&child_id, MoveBehavior::ToRoot).unwrap();
}
}
}
}
for (_, mapped, _) in self.mapped() { for (_, mapped, _) in self.mapped() {
mapped.refresh(); mapped.refresh();
} }
TilingLayout::update_space_positions(&mut self.trees, self.gaps); }
pub fn animations_going(&self) -> bool {
self.queues
.values()
.any(|queue| queue.animation_start.is_some())
}
pub fn update_animation_state(&mut self, handle: &LoopHandle<'static, crate::state::Data>) {
for blocker in self.pending_blockers.drain(..) {
blocker.signal_ready(handle);
}
for queue in self.queues.values_mut() {
if let Some(start) = queue.animation_start {
let duration_since_start = Instant::now().duration_since(start);
if duration_since_start > ANIMATION_DURATION {
assert!(queue.trees.len() >= 2);
let _ = queue.animation_start.take();
let _ = queue.trees.pop_front();
let _ = queue.trees.front_mut().unwrap().1.take();
} else {
continue;
}
}
if let Some((_, blocker)) = queue.trees.get(1) {
if blocker
.as_ref()
.map(TilingBlocker::is_ready)
.unwrap_or(true)
{
queue.animation_start = Some(Instant::now());
if let Some(blocker) = blocker.as_ref() {
blocker.signal_ready(handle)
}
}
}
}
} }
pub fn resize_request( pub fn resize_request(
@ -964,7 +1034,8 @@ impl TilingLayout {
start_data: PointerGrabStartData<State>, start_data: PointerGrabStartData<State>,
edges: ResizeEdge, edges: ResizeEdge,
) -> Option<ResizeForkGrab> { ) -> Option<ResizeForkGrab> {
let (output, mut node_id) = self.trees.iter().find_map(|(output, tree)| { let (output, mut node_id) = self.queues.iter().find_map(|(output, queue)| {
let tree = &queue.trees.back().unwrap().0;
let root_id = tree.root_node_id()?; let root_id = tree.root_node_id()?;
tree.traverse_pre_order_ids(root_id) tree.traverse_pre_order_ids(root_id)
.unwrap() .unwrap()
@ -972,7 +1043,8 @@ impl TilingLayout {
.map(|id| (&output.output, id)) .map(|id| (&output.output, id))
})?; })?;
let tree = self.trees.get(output).unwrap(); let queue = self.queues.get(output).unwrap();
let tree = &queue.trees.back().unwrap().0;
while let Some(group_id) = tree.get(&node_id).unwrap().parent() { while let Some(group_id) = tree.get(&node_id).unwrap().parent() {
let orientation = tree.get(group_id).unwrap().data().orientation(); let orientation = tree.get(group_id).unwrap().data().orientation();
if !((orientation == Orientation::Vertical if !((orientation == Orientation::Vertical
@ -1010,7 +1082,7 @@ impl TilingLayout {
} }
fn last_active_window<'a>( fn last_active_window<'a>(
tree: &mut Tree<Data>, tree: &Tree<Data>,
mut focus_stack: impl Iterator<Item = &'a CosmicMapped>, mut focus_stack: impl Iterator<Item = &'a CosmicMapped>,
) -> Option<(CosmicMapped, NodeId)> { ) -> Option<(CosmicMapped, NodeId)> {
focus_stack focus_stack
@ -1110,16 +1182,18 @@ impl TilingLayout {
Ok(group_id) Ok(group_id)
} }
fn update_space_positions(trees: &mut HashMap<OutputData, Tree<Data>>, gaps: (i32, i32)) { fn update_positions(
output: &Output,
tree: &mut Tree<Data>,
gaps: (i32, i32),
) -> Option<TilingBlocker> {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
puffin::profile_function!(); puffin::profile_function!();
if let Some(root_id) = tree.root_node_id() {
let mut configures = Vec::new();
let (outer, inner) = gaps; let (outer, inner) = gaps;
for (output, tree) in trees
.iter_mut()
.map(|(output_data, tree)| (&output_data.output, tree))
{
if let Some(root) = tree.root_node_id() {
let mut geo = layer_map_for_output(&output).non_exclusive_zone(); let mut geo = layer_map_for_output(&output).non_exclusive_zone();
geo.loc.x += outer; geo.loc.x += outer;
geo.loc.y += outer; geo.loc.y += outer;
@ -1128,19 +1202,56 @@ impl TilingLayout {
let mut stack = vec![geo]; let mut stack = vec![geo];
for node_id in tree for node_id in tree
.traverse_pre_order_ids(root) .traverse_pre_order_ids(root_id)
.unwrap() .unwrap()
.collect::<Vec<_>>() .collect::<Vec<_>>()
.into_iter() .into_iter()
{ {
let node = tree.get_mut(&node_id).unwrap(); let node = tree.get_mut(&node_id).unwrap();
if let Some(mut geo) = stack.pop() {
let data = node.data_mut(); let data = node.data_mut();
// flatten tree
if data.is_group() && data.len() == 1 {
// RemoveBehavior::LiftChildren sadly does not what we want: lifting them into the same place.
// So we need to fix that manually..
let idx = node.parent().cloned().map(|parent_id| {
tree.children_ids(&parent_id)
.unwrap()
.position(|id| id == &node_id)
.unwrap()
});
let child_id = tree
.children_ids(&node_id)
.unwrap()
.cloned()
.next()
.unwrap();
tree.remove_node(node_id, RemoveBehavior::LiftChildren)
.unwrap();
if let Some(idx) = idx {
tree.make_nth_sibling(&child_id, idx).unwrap();
} else {
// additionally `RemoveBehavior::LiftChildren` doesn't work, when removing the root-node,
// even with just one child. *sigh*
tree.move_node(&child_id, MoveBehavior::ToRoot).unwrap();
}
continue;
}
if let Some(mut geo) = stack.pop() {
let node = tree.get_mut(&node_id).unwrap();
let data = node.data_mut();
if data.is_mapped(None) {
geo.loc += (inner, inner).into();
geo.size -= (inner * 2, inner * 2).into();
}
data.update_geometry(geo);
match data { match data {
Data::Group { Data::Group {
orientation, sizes, .. orientation, sizes, ..
} => { } => match orientation {
match orientation {
Orientation::Horizontal => { Orientation::Horizontal => {
let mut previous: i32 = sizes.iter().sum(); let mut previous: i32 = sizes.iter().sum();
for size in sizes.iter().rev() { for size in sizes.iter().rev() {
@ -1161,24 +1272,18 @@ impl TilingLayout {
)); ));
} }
} }
} },
data.update_geometry(geo);
}
Data::Mapped { mapped, .. } => { Data::Mapped { mapped, .. } => {
geo.loc += (inner, inner).into();
if !(mapped.is_fullscreen() || mapped.is_maximized()) { if !(mapped.is_fullscreen() || mapped.is_maximized()) {
mapped.set_tiled(true); mapped.set_tiled(true);
let size = (geo.size.w - inner * 2, geo.size.h - inner * 2);
let internal_geometry = Rectangle::from_loc_and_size( let internal_geometry = Rectangle::from_loc_and_size(
geo.loc + output.geometry().loc, geo.loc + output.geometry().loc,
size, geo.size,
); );
if mapped.geometry() != internal_geometry { if mapped.geometry() != internal_geometry {
mapped.set_geometry(internal_geometry); mapped.set_geometry(internal_geometry);
mapped.configure(); if let Some(serial) = mapped.configure() {
} configures.push((mapped.active_window(), serial));
}
data.update_geometry(geo);
} }
} }
} }
@ -1187,10 +1292,25 @@ impl TilingLayout {
} }
} }
if !configures.is_empty() {
let blocker = TilingBlocker::new(configures);
for (surface, _) in &blocker.necessary_acks {
if let Some(surface) = surface.wl_surface() {
add_blocker(&surface, blocker.clone());
}
}
return Some(blocker);
}
}
None
}
pub fn mapped(&self) -> impl Iterator<Item = (&Output, &CosmicMapped, Point<i32, Logical>)> { pub fn mapped(&self) -> impl Iterator<Item = (&Output, &CosmicMapped, Point<i32, Logical>)> {
self.trees self.queues
.iter() .iter()
.flat_map(|(output_data, tree)| { .flat_map(|(output_data, queue)| {
let tree = &queue.trees.back().unwrap().0;
if let Some(root) = tree.root_node_id() { if let Some(root) = tree.root_node_id() {
Some( Some(
tree.traverse_pre_order(root) tree.traverse_pre_order(root)
@ -1252,15 +1372,20 @@ impl TilingLayout {
} }
pub fn merge(&mut self, other: TilingLayout) { pub fn merge(&mut self, other: TilingLayout) {
for (output_data, src) in other.trees { for (output_data, mut src_queue) in other.queues {
let mut dst = self.trees.entry(output_data.clone()).or_default(); let src = src_queue.trees.pop_back().unwrap().0;
let dst_queue = self.queues.entry(output_data.clone()).or_default();
let mut dst = dst_queue.trees.back().unwrap().0.copy_clone();
let orientation = match output_data.output.geometry().size { let orientation = match output_data.output.geometry().size {
x if x.w >= x.h => Orientation::Vertical, x if x.w >= x.h => Orientation::Vertical,
_ => Orientation::Horizontal, _ => Orientation::Horizontal,
}; };
TilingLayout::merge_trees(src, &mut dst, orientation); TilingLayout::merge_trees(src, &mut dst, orientation);
let blocker = TilingLayout::update_positions(&output_data.output, &mut dst, self.gaps);
dst_queue.push_tree(dst, blocker);
} }
self.refresh();
} }
fn merge_trees(src: Tree<Data>, dst: &mut Tree<Data>, orientation: Orientation) { fn merge_trees(src: Tree<Data>, dst: &mut Tree<Data>, orientation: Orientation) {
@ -1320,21 +1445,103 @@ impl TilingLayout {
let output_scale = output.current_scale().fractional_scale(); let output_scale = output.current_scale().fractional_scale();
if !self.trees.contains_key(output) { if !self.queues.contains_key(output) {
return Err(OutputNotMapped); return Err(OutputNotMapped);
} }
Ok(self let queue = self.queues.get(output).unwrap();
let (target_tree, _) = if queue.animation_start.is_some() {
queue
.trees .trees
.iter() .get(1)
.flat_map(|(output_data, tree)| { .expect("Animation ongoing, should have two trees")
if &output_data.output != output { } else {
return None; queue.trees.front().unwrap()
};
let reference_tree = queue
.animation_start
.is_some()
.then(|| &queue.trees.front().unwrap().0);
let percentage = if let Some(animation_start) = queue.animation_start {
let percentage = Instant::now().duration_since(animation_start).as_millis() as f32
/ ANIMATION_DURATION.as_millis() as f32;
Ease::Cubic(Cubic::Out).tween(percentage)
} else {
1.0
};
let mut elements = Vec::new();
// all old windows and fade them out
if let Some(reference_tree) = reference_tree.as_ref() {
if let Some(root) = reference_tree.root_node_id() {
elements.extend(
reference_tree
.traverse_pre_order(root)
.unwrap()
.filter(|node| node.data().is_mapped(None))
.map(|node| match node.data() {
Data::Mapped {
mapped,
last_geometry,
..
} => (mapped, last_geometry),
_ => unreachable!(),
})
.filter(|(mapped, _)| {
if let Some(root) = target_tree.root_node_id() {
!target_tree
.traverse_pre_order(root)
.unwrap()
.any(|node| node.data().is_mapped(Some(mapped)))
} else {
true
}
})
.flat_map(|(mapped, geo)| {
let crop_rect = geo.clone();
AsRenderElements::<R>::render_elements::<CosmicMappedRenderElement<R>>(
mapped,
renderer,
geo.loc.to_physical_precise_round(output_scale)
- mapped
.geometry()
.loc
.to_physical_precise_round(output_scale),
Scale::from(output_scale),
1.0 - percentage,
)
.into_iter()
.flat_map(|element| match element {
CosmicMappedRenderElement::Stack(elem) => {
CropRenderElement::from_element(
elem,
output_scale,
crop_rect.to_physical_precise_round(output_scale),
)
.map(CosmicMappedRenderElement::CroppedStack)
}
CosmicMappedRenderElement::Window(elem) => {
CropRenderElement::from_element(
elem,
output_scale,
crop_rect.to_physical_precise_round(output_scale),
)
.map(CosmicMappedRenderElement::CroppedWindow)
}
x => Some(x),
})
.collect::<Vec<_>>()
}),
)
}
} }
if let Some(root) = tree.root_node_id() { if let Some(root) = target_tree.root_node_id() {
Some( elements.extend(
tree.traverse_pre_order(root) target_tree
.traverse_pre_order(root)
.unwrap() .unwrap()
.filter(|node| node.data().is_mapped(None)) .filter(|node| node.data().is_mapped(None))
.filter(|node| match node.data() { .filter(|node| match node.data() {
@ -1346,11 +1553,12 @@ impl TilingLayout {
mapped, mapped,
last_geometry, last_geometry,
.. ..
} => (mapped, last_geometry.loc), } => (mapped, last_geometry),
_ => unreachable!(), _ => unreachable!(),
}) })
.chain( .chain(
tree.traverse_pre_order(root) target_tree
.traverse_pre_order(root)
.unwrap() .unwrap()
.filter(|node| node.data().is_mapped(None)) .filter(|node| node.data().is_mapped(None))
.filter(|node| match node.data() { .filter(|node| match node.data() {
@ -1362,40 +1570,116 @@ impl TilingLayout {
mapped, mapped,
last_geometry, last_geometry,
.. ..
} => (mapped, last_geometry.loc), } => (mapped, last_geometry),
_ => unreachable!(), _ => unreachable!(),
}), }),
),
) )
.flat_map(|(mapped, new_geo)| {
let old_geo = if let Some(reference_tree) = reference_tree.as_ref() {
if let Some(root) = reference_tree.root_node_id() {
reference_tree
.traverse_pre_order(root)
.unwrap()
.find(|node| node.data().is_mapped(Some(mapped)))
.map(|node| match node.data() {
Data::Mapped { last_geometry, .. } => last_geometry,
_ => unreachable!(),
})
} else { } else {
None None
} }
}) } else {
.flatten() None
.flat_map(|(mapped, loc)| { };
let (geo, alpha) = if let Some(old_geo) = old_geo {
(
Rectangle::from_loc_and_size(
(
old_geo.loc.x
+ ((new_geo.loc.x - old_geo.loc.x) as f32 * percentage)
.round()
as i32,
old_geo.loc.y
+ ((new_geo.loc.y - old_geo.loc.y) as f32 * percentage)
.round()
as i32,
),
(
old_geo.size.w
+ ((new_geo.size.w - old_geo.size.w) as f32
* percentage)
.round()
as i32,
old_geo.size.h
+ ((new_geo.size.h - old_geo.size.h) as f32
* percentage)
.round()
as i32,
),
),
1.0,
)
} else {
// TODO: If old_geo.is_none() animate alpha - fade in
(*new_geo, percentage)
};
if alpha < 1.0 {
dbg!(alpha);
}
let crop_rect = geo.clone();
let mut elements = let mut elements =
AsRenderElements::<R>::render_elements::<CosmicMappedRenderElement<R>>( AsRenderElements::<R>::render_elements::<CosmicMappedRenderElement<R>>(
mapped, mapped,
renderer, renderer,
loc.to_physical_precise_round(output_scale) geo.loc.to_physical_precise_round(output_scale)
- mapped - mapped
.geometry() .geometry()
.loc .loc
.to_physical_precise_round(output_scale), .to_physical_precise_round(output_scale),
Scale::from(output_scale), Scale::from(output_scale),
); alpha,
)
.into_iter()
.flat_map(|element| match element {
CosmicMappedRenderElement::Stack(elem) => {
CropRenderElement::from_element(
elem,
output_scale,
crop_rect.to_physical_precise_round(output_scale),
)
.map(CosmicMappedRenderElement::CroppedStack)
}
CosmicMappedRenderElement::Window(elem) => {
CropRenderElement::from_element(
elem,
output_scale,
crop_rect.to_physical_precise_round(output_scale),
)
.map(CosmicMappedRenderElement::CroppedWindow)
}
x => Some(x),
})
.collect::<Vec<_>>();
if focused == Some(mapped) { if focused == Some(mapped) {
if indicator_thickness > 0 { if indicator_thickness > 0 {
let element = IndicatorShader::element( let element = IndicatorShader::element(
renderer, renderer,
Rectangle::from_loc_and_size(loc, mapped.geometry().size), geo,
indicator_thickness, indicator_thickness,
1.0,
); );
elements.insert(0, element.into()); elements.insert(0, element.into());
} }
} }
elements elements
}) }),
.collect::<Vec<_>>()) )
}
Ok(elements)
} }
} }

View file

@ -1,3 +1,4 @@
use calloop::LoopHandle;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{cell::RefCell, collections::HashMap}; use std::{cell::RefCell, collections::HashMap};
use tracing::warn; use tracing::warn;
@ -1036,6 +1037,18 @@ impl Shell {
} }
} }
pub fn animations_going(&self) -> bool {
self.workspaces
.spaces()
.any(|workspace| workspace.animations_going())
}
pub fn update_animations(&mut self, handle: &LoopHandle<'static, crate::state::Data>) {
for workspace in self.workspaces.spaces_mut() {
workspace.update_animations(handle)
}
}
pub fn refresh(&mut self) { pub fn refresh(&mut self) {
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
puffin::profile_function!(); puffin::profile_function!();

View file

@ -17,6 +17,7 @@ use crate::{
xwayland::XWaylandState, xwayland::XWaylandState,
}; };
use calloop::LoopHandle;
use indexmap::IndexSet; use indexmap::IndexSet;
use smithay::{ use smithay::{
backend::renderer::{ backend::renderer::{
@ -85,6 +86,14 @@ impl Workspace {
self.tiling_layer.refresh(); self.tiling_layer.refresh();
} }
pub fn animations_going(&self) -> bool {
self.tiling_layer.animations_going()
}
pub fn update_animations(&mut self, handle: &LoopHandle<'static, crate::state::Data>) {
self.tiling_layer.update_animation_state(handle)
}
pub fn commit(&mut self, surface: &WlSurface) { pub fn commit(&mut self, surface: &WlSurface) {
if let Some(mapped) = self.element_for_wl_surface(surface) { if let Some(mapped) = self.element_for_wl_surface(surface) {
mapped mapped
@ -484,6 +493,7 @@ impl Workspace {
renderer, renderer,
loc.to_physical_precise_round(output_scale), loc.to_physical_precise_round(output_scale),
Scale::from(output_scale), Scale::from(output_scale),
1.0,
) )
}), }),
); );
@ -499,6 +509,7 @@ impl Workspace {
(or.geometry().loc - output.geometry().loc) (or.geometry().loc - output.geometry().loc)
.to_physical_precise_round(output_scale), .to_physical_precise_round(output_scale),
Scale::from(output_scale), Scale::from(output_scale),
1.0,
) )
}), }),
); );
@ -507,7 +518,11 @@ impl Workspace {
render_elements.extend(AsRenderElements::<R>::render_elements::< render_elements.extend(AsRenderElements::<R>::render_elements::<
WorkspaceRenderElement<R>, WorkspaceRenderElement<R>,
>( >(
fullscreen, renderer, (0, 0).into(), output_scale.into() fullscreen,
renderer,
(0, 0).into(),
output_scale.into(),
1.0,
)); ));
if let Some(xwm) = xwm_state.and_then(|state| state.xwm.as_mut()) { if let Some(xwm) = xwm_state.and_then(|state| state.xwm.as_mut()) {
@ -551,6 +566,7 @@ impl Workspace {
renderer, renderer,
loc.to_physical_precise_round(output_scale), loc.to_physical_precise_round(output_scale),
Scale::from(output_scale), Scale::from(output_scale),
1.0,
) )
}), }),
); );
@ -570,6 +586,7 @@ impl Workspace {
(or.geometry().loc - output.geometry().loc) (or.geometry().loc - output.geometry().loc)
.to_physical_precise_round(output_scale), .to_physical_precise_round(output_scale),
Scale::from(output_scale), Scale::from(output_scale),
1.0,
) )
}), }),
); );
@ -620,6 +637,7 @@ impl Workspace {
renderer, renderer,
loc.to_physical_precise_round(output_scale), loc.to_physical_precise_round(output_scale),
Scale::from(output_scale), Scale::from(output_scale),
1.0,
) )
}), }),
); );
@ -715,6 +733,13 @@ where
WorkspaceRenderElement::Window(elem) => elem.opaque_regions(scale), WorkspaceRenderElement::Window(elem) => elem.opaque_regions(scale),
} }
} }
fn alpha(&self) -> f32 {
match self {
WorkspaceRenderElement::Wayland(elem) => elem.alpha(),
WorkspaceRenderElement::Window(elem) => elem.alpha(),
}
}
} }
impl<R> RenderElement<R> for WorkspaceRenderElement<R> impl<R> RenderElement<R> for WorkspaceRenderElement<R>

View file

@ -50,7 +50,7 @@ use smithay::{
}, },
utils::{Clock, IsAlive, Monotonic}, utils::{Clock, IsAlive, Monotonic},
wayland::{ wayland::{
compositor::CompositorState, compositor::{CompositorClientState, CompositorState},
data_device::DataDeviceState, data_device::DataDeviceState,
dmabuf::{DmabufFeedback, DmabufState}, dmabuf::{DmabufFeedback, DmabufState},
keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState, keyboard_shortcuts_inhibit::KeyboardShortcutsInhibitState,
@ -69,6 +69,7 @@ use std::{cell::RefCell, ffi::OsString, time::Duration};
use std::{collections::VecDeque, time::Instant}; use std::{collections::VecDeque, time::Instant};
pub struct ClientState { pub struct ClientState {
pub compositor_client_state: CompositorClientState,
pub workspace_client_state: WorkspaceClientState, pub workspace_client_state: WorkspaceClientState,
pub drm_node: Option<DrmNode>, pub drm_node: Option<DrmNode>,
pub privileged: bool, pub privileged: bool,
@ -312,6 +313,7 @@ impl State {
pub fn new_client_state(&self) -> ClientState { pub fn new_client_state(&self) -> ClientState {
ClientState { ClientState {
compositor_client_state: CompositorClientState::default(),
workspace_client_state: WorkspaceClientState::default(), workspace_client_state: WorkspaceClientState::default(),
drm_node: match &self.backend { drm_node: match &self.backend {
BackendData::Kms(kms_state) => { BackendData::Kms(kms_state) => {
@ -334,6 +336,7 @@ impl State {
pub fn new_client_state_with_node(&self, drm_node: DrmNode) -> ClientState { pub fn new_client_state_with_node(&self, drm_node: DrmNode) -> ClientState {
ClientState { ClientState {
compositor_client_state: CompositorClientState::default(),
workspace_client_state: WorkspaceClientState::default(), workspace_client_state: WorkspaceClientState::default(),
drm_node: Some(drm_node), drm_node: Some(drm_node),
privileged: false, privileged: false,
@ -342,6 +345,7 @@ impl State {
pub fn new_privileged_client_state(&self) -> ClientState { pub fn new_privileged_client_state(&self) -> ClientState {
ClientState { ClientState {
compositor_client_state: CompositorClientState::default(),
workspace_client_state: WorkspaceClientState::default(), workspace_client_state: WorkspaceClientState::default(),
drm_node: match &self.backend { drm_node: match &self.backend {
BackendData::Kms(kms_state) => Some(kms_state.primary), BackendData::Kms(kms_state) => Some(kms_state.primary),

View file

@ -567,6 +567,7 @@ where
renderer: &mut R, renderer: &mut R,
location: Point<i32, Physical>, location: Point<i32, Physical>,
scale: Scale<f64>, scale: Scale<f64>,
alpha: f32,
) -> Vec<C> { ) -> Vec<C> {
let mut internal = self.0.lock().unwrap(); let mut internal = self.0.lock().unwrap();
@ -633,7 +634,7 @@ where
renderer, renderer,
location.to_f64(), location.to_f64(),
&buffer, &buffer,
None, Some(alpha),
Some(Rectangle::from_loc_and_size( Some(Rectangle::from_loc_and_size(
(0., 0.), (0., 0.),
size.to_f64().to_logical(1.0, Transform::Normal), size.to_f64().to_logical(1.0, Transform::Normal),

View file

@ -2,17 +2,22 @@
use crate::{ use crate::{
shell::CosmicSurface, shell::CosmicSurface,
state::{BackendData, Data}, state::{BackendData, ClientState, Data},
utils::prelude::*, utils::prelude::*,
wayland::protocols::screencopy::SessionType, wayland::protocols::screencopy::SessionType,
}; };
use calloop::Interest;
use smithay::{ use smithay::{
backend::renderer::utils::{on_commit_buffer_handler, with_renderer_surface_state}, backend::renderer::utils::{on_commit_buffer_handler, with_renderer_surface_state},
delegate_compositor, delegate_compositor,
desktop::{layer_map_for_output, LayerSurface, PopupKind, WindowSurfaceType}, desktop::{layer_map_for_output, LayerSurface, PopupKind, WindowSurfaceType},
reexports::wayland_server::protocol::wl_surface::WlSurface, reexports::wayland_server::{protocol::wl_surface::WlSurface, Client, Resource},
wayland::{ wayland::{
compositor::{with_states, CompositorHandler, CompositorState}, compositor::{
add_blocker, add_pre_commit_hook, with_states, BufferAssignment, CompositorClientState,
CompositorHandler, CompositorState, SurfaceAttributes,
},
dmabuf::get_dmabuf,
seat::WaylandFocus, seat::WaylandFocus,
shell::{ shell::{
wlr_layer::LayerSurfaceAttributes, wlr_layer::LayerSurfaceAttributes,
@ -21,7 +26,7 @@ use smithay::{
}, },
}, },
}, },
xwayland::X11Wm, xwayland::{X11Wm, XWaylandClientData},
}; };
use std::sync::Mutex; use std::sync::Mutex;
@ -105,15 +110,63 @@ impl State {
} }
} }
pub fn client_compositor_state<'a>(client: &'a Client) -> &'a CompositorClientState {
if let Some(state) = client.get_data::<XWaylandClientData>() {
return &state.compositor_state;
}
if let Some(state) = client.get_data::<ClientState>() {
return &state.compositor_client_state;
}
panic!("Unknown client data type")
}
impl CompositorHandler for State { impl CompositorHandler for State {
fn compositor_state(&mut self) -> &mut CompositorState { fn compositor_state(&mut self) -> &mut CompositorState {
&mut self.common.compositor_state &mut self.common.compositor_state
} }
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
client_compositor_state(client)
}
fn new_surface(&mut self, surface: &WlSurface) {
add_pre_commit_hook::<Self, _>(surface, move |state, _dh, surface| {
let maybe_dmabuf = with_states(surface, |surface_data| {
surface_data
.cached_state
.pending::<SurfaceAttributes>()
.buffer
.as_ref()
.and_then(|assignment| match assignment {
BufferAssignment::NewBuffer(buffer) => get_dmabuf(buffer).ok(),
_ => None,
})
});
if let Some(dmabuf) = maybe_dmabuf {
if let Ok((blocker, source)) = dmabuf.generate_blocker(Interest::READ) {
let client = surface.client().unwrap();
let res =
state
.common
.event_loop_handle
.insert_source(source, move |_, _, data| {
data.state
.client_compositor_state(&client)
.blocker_cleared(&mut data.state, &data.display.handle());
Ok(())
});
if res.is_ok() {
add_blocker(surface, blocker);
}
}
}
})
}
fn commit(&mut self, surface: &WlSurface) { fn commit(&mut self, surface: &WlSurface) {
X11Wm::commit_hook::<Data>(surface); X11Wm::commit_hook::<Data>(surface);
// first load the buffer for various smithay helper functions // first load the buffer for various smithay helper functions
on_commit_buffer_handler(surface); on_commit_buffer_handler::<Self>(surface);
// then handle initial configure events and map windows if necessary // then handle initial configure events and map windows if necessary
if let Some((window, seat)) = self if let Some((window, seat)) = self

View file

@ -947,6 +947,7 @@ pub fn render_window_to_buffer(
renderer, renderer,
(-geometry.loc.x, -geometry.loc.y).into(), (-geometry.loc.x, -geometry.loc.y).into(),
Scale::from(1.0), Scale::from(1.0),
1.0,
); );
for seat in common.seats() { for seat in common.seats() {