tiling: Animate tree changes
This commit is contained in:
parent
ea1b976076
commit
331b884f1e
23 changed files with 1641 additions and 395 deletions
959
Cargo.lock
generated
959
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -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" }
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}));
|
}));
|
||||||
|
|
|
||||||
|
|
@ -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!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
65
src/shell/layout/tiling/blocker.rs
Normal file
65
src/shell/layout/tiling/blocker.rs
Normal 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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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!();
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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),
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue