render: Implement workspace transitions
This commit is contained in:
parent
0d1894e08f
commit
7b3ac7fa77
8 changed files with 320 additions and 126 deletions
|
|
@ -1041,13 +1041,20 @@ impl Surface {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let handle = state.shell.workspaces.active(&self.output).handle;
|
let (previous_workspace, workspace) = state.shell.workspaces.active(&self.output);
|
||||||
|
let (previous_idx, idx) = state.shell.workspaces.active_num(&self.output);
|
||||||
|
let previous_workspace = previous_workspace
|
||||||
|
.zip(previous_idx)
|
||||||
|
.map(|((w, start), idx)| (w.handle, idx, start));
|
||||||
|
let workspace = (workspace.handle, idx);
|
||||||
|
|
||||||
let elements = workspace_elements(
|
let elements = workspace_elements(
|
||||||
Some(&render_node),
|
Some(&render_node),
|
||||||
&mut renderer,
|
&mut renderer,
|
||||||
state,
|
state,
|
||||||
&self.output,
|
&self.output,
|
||||||
&handle,
|
previous_workspace,
|
||||||
|
workspace,
|
||||||
CursorMode::All,
|
CursorMode::All,
|
||||||
&mut Some(&mut self.fps),
|
&mut Some(&mut self.fps),
|
||||||
false,
|
false,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@ use crate::shell::{CosmicMappedRenderElement, WorkspaceRenderElement};
|
||||||
|
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::renderer::{
|
backend::renderer::{
|
||||||
element::{Element, RenderElement, UnderlyingStorage},
|
element::{
|
||||||
|
utils::{Relocate, RelocateRenderElement},
|
||||||
|
Element, RenderElement, UnderlyingStorage,
|
||||||
|
},
|
||||||
glow::{GlowFrame, GlowRenderer},
|
glow::{GlowFrame, GlowRenderer},
|
||||||
Frame, ImportAll, ImportMem, Renderer,
|
Frame, ImportAll, ImportMem, Renderer,
|
||||||
},
|
},
|
||||||
|
|
@ -20,7 +23,7 @@ where
|
||||||
<R as Renderer>::TextureId: 'static,
|
<R as Renderer>::TextureId: 'static,
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
Workspace(WorkspaceRenderElement<R>),
|
Workspace(RelocateRenderElement<WorkspaceRenderElement<R>>),
|
||||||
Cursor(CursorRenderElement<R>),
|
Cursor(CursorRenderElement<R>),
|
||||||
MoveGrab(CosmicMappedRenderElement<R>),
|
MoveGrab(CosmicMappedRenderElement<R>),
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
|
|
@ -211,7 +214,11 @@ where
|
||||||
CosmicMappedRenderElement<R>: RenderElement<R>,
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
{
|
{
|
||||||
fn from(elem: WorkspaceRenderElement<R>) -> Self {
|
fn from(elem: WorkspaceRenderElement<R>) -> Self {
|
||||||
Self::Workspace(elem)
|
Self::Workspace(RelocateRenderElement::from_element(
|
||||||
|
elem,
|
||||||
|
(0, 0),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,23 +5,24 @@ use std::{
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
sync::Weak,
|
sync::Weak,
|
||||||
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "debug")]
|
|
||||||
use crate::{
|
|
||||||
debug::{fps_ui, profiler_ui},
|
|
||||||
utils::prelude::*,
|
|
||||||
};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
config::WorkspaceLayout,
|
||||||
shell::{
|
shell::{
|
||||||
element::window::CosmicWindowRenderElement, focus::target::WindowGroup,
|
element::window::CosmicWindowRenderElement,
|
||||||
layout::floating::SeatMoveGrabState, CosmicMapped, CosmicMappedRenderElement,
|
focus::target::WindowGroup,
|
||||||
WorkspaceRenderElement,
|
layout::{floating::SeatMoveGrabState, tiling::ANIMATION_DURATION},
|
||||||
|
CosmicMapped, CosmicMappedRenderElement, WorkspaceRenderElement,
|
||||||
},
|
},
|
||||||
state::{Common, Fps},
|
state::{Common, Fps},
|
||||||
utils::prelude::SeatExt,
|
utils::prelude::{OutputExt, SeatExt},
|
||||||
wayland::{
|
wayland::{
|
||||||
handlers::{data_device::get_dnd_icon, screencopy::render_session},
|
handlers::{
|
||||||
|
data_device::get_dnd_icon,
|
||||||
|
screencopy::{render_session, WORKSPACE_OVERVIEW_NAMESPACE},
|
||||||
|
},
|
||||||
protocols::{
|
protocols::{
|
||||||
screencopy::{
|
screencopy::{
|
||||||
BufferParams, CursorMode as ScreencopyCursorMode, Session as ScreencopySession,
|
BufferParams, CursorMode as ScreencopyCursorMode, Session as ScreencopySession,
|
||||||
|
|
@ -30,8 +31,14 @@ use crate::{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
#[cfg(feature = "debug")]
|
||||||
|
use crate::{
|
||||||
|
debug::{fps_ui, profiler_ui},
|
||||||
|
utils::prelude::*,
|
||||||
|
};
|
||||||
|
|
||||||
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::FailureReason;
|
use cosmic_protocols::screencopy::v1::server::zcosmic_screencopy_session_v1::FailureReason;
|
||||||
|
use cosmic_time::{Cubic, Ease, Tween};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::{
|
backend::{
|
||||||
allocator::dmabuf::Dmabuf,
|
allocator::dmabuf::Dmabuf,
|
||||||
|
|
@ -39,7 +46,10 @@ use smithay::{
|
||||||
renderer::{
|
renderer::{
|
||||||
buffer_dimensions,
|
buffer_dimensions,
|
||||||
damage::{Error as RenderError, OutputDamageTracker, OutputNoMode},
|
damage::{Error as RenderError, OutputDamageTracker, OutputNoMode},
|
||||||
element::{Element, RenderElement, RenderElementStates},
|
element::{
|
||||||
|
utils::{Relocate, RelocateRenderElement},
|
||||||
|
AsRenderElements, Element, RenderElement, RenderElementStates,
|
||||||
|
},
|
||||||
gles::{
|
gles::{
|
||||||
element::PixelShaderElement, GlesError, GlesPixelProgram, GlesRenderer, Uniform,
|
element::PixelShaderElement, GlesError, GlesPixelProgram, GlesRenderer, Uniform,
|
||||||
UniformName, UniformType,
|
UniformName, UniformType,
|
||||||
|
|
@ -49,10 +59,12 @@ use smithay::{
|
||||||
Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter,
|
Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
desktop::layer_map_for_output,
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{IsAlive, Logical, Physical, Point, Rectangle, Size},
|
utils::{IsAlive, Logical, Physical, Point, Rectangle, Scale, Size},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::get_dmabuf,
|
dmabuf::get_dmabuf,
|
||||||
|
shell::wlr_layer::Layer,
|
||||||
shm::{shm_format_to_fourcc, with_buffer_contents},
|
shm::{shm_format_to_fourcc, with_buffer_contents},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
@ -289,7 +301,8 @@ pub fn workspace_elements<R>(
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
state: &mut Common,
|
state: &mut Common,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
handle: &WorkspaceHandle,
|
previous: Option<(WorkspaceHandle, usize, Instant)>,
|
||||||
|
current: (WorkspaceHandle, usize),
|
||||||
cursor_mode: CursorMode,
|
cursor_mode: CursorMode,
|
||||||
_fps: &mut Option<&mut Fps>,
|
_fps: &mut Option<&mut Fps>,
|
||||||
exclude_workspace_overview: bool,
|
exclude_workspace_overview: bool,
|
||||||
|
|
@ -346,11 +359,17 @@ where
|
||||||
|
|
||||||
state
|
state
|
||||||
.shell
|
.shell
|
||||||
.space_for_handle_mut(&handle)
|
.space_for_handle_mut(¤t.0)
|
||||||
.ok_or(OutputNoMode)?
|
.ok_or(OutputNoMode)?
|
||||||
.update_animations(&state.event_loop_handle);
|
.update_animations(&state.event_loop_handle);
|
||||||
|
if let Some((previous, _, _)) = previous.as_ref() {
|
||||||
|
state
|
||||||
|
.shell
|
||||||
|
.space_for_handle_mut(&previous)
|
||||||
|
.ok_or(OutputNoMode)?
|
||||||
|
.update_animations(&state.event_loop_handle);
|
||||||
|
}
|
||||||
let overview = state.shell.overview_mode();
|
let overview = state.shell.overview_mode();
|
||||||
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
|
||||||
.user_data()
|
.user_data()
|
||||||
|
|
@ -359,6 +378,96 @@ where
|
||||||
.borrow()
|
.borrow()
|
||||||
.is_some();
|
.is_some();
|
||||||
let active_output = last_active_seat.active_output();
|
let active_output = last_active_seat.active_output();
|
||||||
|
let output_size = output.geometry().size;
|
||||||
|
let output_scale = output.current_scale().fractional_scale();
|
||||||
|
|
||||||
|
let workspace = state
|
||||||
|
.shell
|
||||||
|
.space_for_handle(¤t.0)
|
||||||
|
.ok_or(OutputNoMode)?;
|
||||||
|
let has_fullscreen = workspace.fullscreen.contains_key(output);
|
||||||
|
|
||||||
|
// foreground layers are static
|
||||||
|
elements.extend(
|
||||||
|
foreground_layer_elements(renderer, output, has_fullscreen, exclude_workspace_overview)
|
||||||
|
.into_iter()
|
||||||
|
.map(Into::into),
|
||||||
|
);
|
||||||
|
|
||||||
|
let offset = match previous.as_ref() {
|
||||||
|
Some((previous, previous_idx, start)) => {
|
||||||
|
let layout = WorkspaceLayout::Vertical;
|
||||||
|
|
||||||
|
let workspace = state
|
||||||
|
.shell
|
||||||
|
.space_for_handle(&previous)
|
||||||
|
.ok_or(OutputNoMode)?;
|
||||||
|
let is_active_space = workspace.outputs().any(|o| o == &active_output);
|
||||||
|
|
||||||
|
let percentage = {
|
||||||
|
let percentage = Instant::now().duration_since(*start).as_millis() as f32
|
||||||
|
/ ANIMATION_DURATION.as_millis() as f32;
|
||||||
|
Ease::Cubic(Cubic::InOut).tween(percentage)
|
||||||
|
};
|
||||||
|
let offset = Point::<i32, Logical>::from(match (layout, *previous_idx < current.1) {
|
||||||
|
(WorkspaceLayout::Vertical, true) => {
|
||||||
|
(0, (-output_size.h as f32 * percentage).round() as i32)
|
||||||
|
}
|
||||||
|
(WorkspaceLayout::Vertical, false) => {
|
||||||
|
(0, (output_size.h as f32 * percentage).round() as i32)
|
||||||
|
}
|
||||||
|
(WorkspaceLayout::Horizontal, true) => {
|
||||||
|
((-output_size.w as f32 * percentage).round() as i32, 0)
|
||||||
|
}
|
||||||
|
(WorkspaceLayout::Horizontal, false) => {
|
||||||
|
((output_size.w as f32 * percentage).round() as i32, 0)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
elements.extend(
|
||||||
|
workspace
|
||||||
|
.render_output::<R>(
|
||||||
|
renderer,
|
||||||
|
output,
|
||||||
|
&state.shell.override_redirect_windows,
|
||||||
|
state.xwayland_state.as_mut(),
|
||||||
|
(!move_active && is_active_space).then_some(&last_active_seat),
|
||||||
|
overview.clone(),
|
||||||
|
state.config.static_conf.active_hint,
|
||||||
|
)
|
||||||
|
.map_err(|_| OutputNoMode)?
|
||||||
|
.into_iter()
|
||||||
|
.map(|w_element| {
|
||||||
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
||||||
|
w_element,
|
||||||
|
offset.to_physical_precise_round(output_scale),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
elements.extend(
|
||||||
|
background_layer_elements(renderer, output, exclude_workspace_overview)
|
||||||
|
.into_iter()
|
||||||
|
.map(|w_element| {
|
||||||
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
||||||
|
w_element,
|
||||||
|
offset.to_physical_precise_round(output_scale),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
Point::<i32, Logical>::from(match (layout, *previous_idx < current.1) {
|
||||||
|
(WorkspaceLayout::Vertical, true) => (0, output_size.h + offset.y),
|
||||||
|
(WorkspaceLayout::Vertical, false) => (0, -(output_size.h - offset.y)),
|
||||||
|
(WorkspaceLayout::Horizontal, true) => (output_size.w + offset.x, 0),
|
||||||
|
(WorkspaceLayout::Horizontal, false) => (-(output_size.w - offset.y), 0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
None => (0, 0).into(),
|
||||||
|
};
|
||||||
|
|
||||||
let is_active_space = workspace.outputs().any(|o| o == &active_output);
|
let is_active_space = workspace.outputs().any(|o| o == &active_output);
|
||||||
|
|
||||||
elements.extend(
|
elements.extend(
|
||||||
|
|
@ -371,16 +480,118 @@ where
|
||||||
(!move_active && is_active_space).then_some(&last_active_seat),
|
(!move_active && is_active_space).then_some(&last_active_seat),
|
||||||
overview,
|
overview,
|
||||||
state.config.static_conf.active_hint,
|
state.config.static_conf.active_hint,
|
||||||
exclude_workspace_overview,
|
|
||||||
)
|
)
|
||||||
.map_err(|_| OutputNoMode)?
|
.map_err(|_| OutputNoMode)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(Into::into),
|
.map(|w_element| {
|
||||||
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
||||||
|
w_element,
|
||||||
|
offset.to_physical_precise_round(output_scale),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
elements.extend(
|
||||||
|
background_layer_elements(renderer, output, exclude_workspace_overview)
|
||||||
|
.into_iter()
|
||||||
|
.map(|w_element| {
|
||||||
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
||||||
|
w_element,
|
||||||
|
offset.to_physical_precise_round(output_scale),
|
||||||
|
Relocate::Relative,
|
||||||
|
))
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(elements)
|
Ok(elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bottom and background layer surfaces
|
||||||
|
pub fn foreground_layer_elements<R>(
|
||||||
|
renderer: &mut R,
|
||||||
|
output: &Output,
|
||||||
|
has_fullscreen: bool,
|
||||||
|
exclude_workspace_overview: bool,
|
||||||
|
) -> Vec<WorkspaceRenderElement<R>>
|
||||||
|
where
|
||||||
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
|
<R as Renderer>::TextureId: Clone + 'static,
|
||||||
|
<R as Renderer>::Error: From<GlesError>,
|
||||||
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
|
CosmicWindowRenderElement<R>: RenderElement<R>,
|
||||||
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
||||||
|
{
|
||||||
|
let layer_map = layer_map_for_output(output);
|
||||||
|
let output_scale = output.current_scale().fractional_scale();
|
||||||
|
|
||||||
|
layer_map
|
||||||
|
.layers()
|
||||||
|
.rev()
|
||||||
|
.filter(|s| !(exclude_workspace_overview && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE))
|
||||||
|
.filter(|s| {
|
||||||
|
if has_fullscreen {
|
||||||
|
matches!(s.layer(), Layer::Overlay)
|
||||||
|
} else {
|
||||||
|
matches!(s.layer(), Layer::Top | Layer::Overlay)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter_map(|surface| {
|
||||||
|
layer_map
|
||||||
|
.layer_geometry(surface)
|
||||||
|
.map(|geo| (geo.loc, surface))
|
||||||
|
})
|
||||||
|
.flat_map(|(loc, surface)| {
|
||||||
|
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>(
|
||||||
|
surface,
|
||||||
|
renderer,
|
||||||
|
loc.to_physical_precise_round(output_scale),
|
||||||
|
Scale::from(output_scale),
|
||||||
|
1.0,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom and background layer surfaces
|
||||||
|
pub fn background_layer_elements<R>(
|
||||||
|
renderer: &mut R,
|
||||||
|
output: &Output,
|
||||||
|
exclude_workspace_overview: bool,
|
||||||
|
) -> Vec<WorkspaceRenderElement<R>>
|
||||||
|
where
|
||||||
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
|
<R as Renderer>::TextureId: Clone + 'static,
|
||||||
|
<R as Renderer>::Error: From<GlesError>,
|
||||||
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
||||||
|
CosmicWindowRenderElement<R>: RenderElement<R>,
|
||||||
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
||||||
|
{
|
||||||
|
let layer_map = layer_map_for_output(output);
|
||||||
|
let output_scale = output.current_scale().fractional_scale();
|
||||||
|
|
||||||
|
layer_map
|
||||||
|
.layers()
|
||||||
|
.rev()
|
||||||
|
.filter(|s| !(exclude_workspace_overview && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE))
|
||||||
|
.filter(|s| matches!(s.layer(), Layer::Background | Layer::Bottom))
|
||||||
|
.filter_map(|surface| {
|
||||||
|
layer_map
|
||||||
|
.layer_geometry(surface)
|
||||||
|
.map(|geo| (geo.loc, surface))
|
||||||
|
})
|
||||||
|
.flat_map(|(loc, surface)| {
|
||||||
|
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>(
|
||||||
|
surface,
|
||||||
|
renderer,
|
||||||
|
loc.to_physical_precise_round(output_scale),
|
||||||
|
Scale::from(output_scale),
|
||||||
|
1.0,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render_output<R, Target, OffTarget, Source>(
|
pub fn render_output<R, Target, OffTarget, Source>(
|
||||||
gpu: Option<&DrmNode>,
|
gpu: Option<&DrmNode>,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
|
|
@ -411,7 +622,13 @@ where
|
||||||
WorkspaceRenderElement<R>: RenderElement<R>,
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
||||||
Source: Clone,
|
Source: Clone,
|
||||||
{
|
{
|
||||||
let handle = state.shell.workspaces.active(output).handle;
|
let (previous_workspace, workspace) = state.shell.workspaces.active(output);
|
||||||
|
let (previous_idx, idx) = state.shell.workspaces.active_num(output);
|
||||||
|
let previous_workspace = previous_workspace
|
||||||
|
.zip(previous_idx)
|
||||||
|
.map(|((w, start), idx)| (w.handle, idx, start));
|
||||||
|
let workspace = (workspace.handle, idx);
|
||||||
|
|
||||||
let result = render_workspace(
|
let result = render_workspace(
|
||||||
gpu,
|
gpu,
|
||||||
renderer,
|
renderer,
|
||||||
|
|
@ -420,7 +637,8 @@ where
|
||||||
age,
|
age,
|
||||||
state,
|
state,
|
||||||
output,
|
output,
|
||||||
&handle,
|
previous_workspace,
|
||||||
|
workspace,
|
||||||
cursor_mode,
|
cursor_mode,
|
||||||
screencopy,
|
screencopy,
|
||||||
fps,
|
fps,
|
||||||
|
|
@ -438,7 +656,8 @@ pub fn render_workspace<R, Target, OffTarget, Source>(
|
||||||
age: usize,
|
age: usize,
|
||||||
state: &mut Common,
|
state: &mut Common,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
handle: &WorkspaceHandle,
|
previous: Option<(WorkspaceHandle, usize, Instant)>,
|
||||||
|
current: (WorkspaceHandle, usize),
|
||||||
mut cursor_mode: CursorMode,
|
mut cursor_mode: CursorMode,
|
||||||
screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>,
|
screencopy: Option<(Source, &[(ScreencopySession, BufferParams)])>,
|
||||||
mut fps: Option<&mut Fps>,
|
mut fps: Option<&mut Fps>,
|
||||||
|
|
@ -496,7 +715,8 @@ where
|
||||||
renderer,
|
renderer,
|
||||||
state,
|
state,
|
||||||
output,
|
output,
|
||||||
handle,
|
previous,
|
||||||
|
current,
|
||||||
cursor_mode,
|
cursor_mode,
|
||||||
&mut fps,
|
&mut fps,
|
||||||
exclude_workspace_overview,
|
exclude_workspace_overview,
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,12 @@ pub enum WorkspaceMode {
|
||||||
Global,
|
Global,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum WorkspaceLayout {
|
||||||
|
Vertical,
|
||||||
|
Horizontal,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DynamicConfig {
|
pub struct DynamicConfig {
|
||||||
outputs: (Option<PathBuf>, OutputsConfig),
|
outputs: (Option<PathBuf>, OutputsConfig),
|
||||||
inputs: (Option<PathBuf>, InputsConfig),
|
inputs: (Option<PathBuf>, InputsConfig),
|
||||||
|
|
|
||||||
|
|
@ -708,6 +708,7 @@ impl State {
|
||||||
.shell
|
.shell
|
||||||
.workspaces
|
.workspaces
|
||||||
.active_num(¤t_output)
|
.active_num(¤t_output)
|
||||||
|
.1
|
||||||
.saturating_add(1);
|
.saturating_add(1);
|
||||||
// TODO: Possibly move to next output, if idx to large
|
// TODO: Possibly move to next output, if idx to large
|
||||||
let _ = self.common.shell.activate(¤t_output, workspace);
|
let _ = self.common.shell.activate(¤t_output, workspace);
|
||||||
|
|
@ -719,6 +720,7 @@ impl State {
|
||||||
.shell
|
.shell
|
||||||
.workspaces
|
.workspaces
|
||||||
.active_num(¤t_output)
|
.active_num(¤t_output)
|
||||||
|
.1
|
||||||
.saturating_sub(1);
|
.saturating_sub(1);
|
||||||
// TODO: Possibly move to prev output, if idx < 0
|
// TODO: Possibly move to prev output, if idx < 0
|
||||||
let _ = self.common.shell.activate(¤t_output, workspace);
|
let _ = self.common.shell.activate(¤t_output, workspace);
|
||||||
|
|
@ -756,6 +758,7 @@ impl State {
|
||||||
.shell
|
.shell
|
||||||
.workspaces
|
.workspaces
|
||||||
.active_num(¤t_output)
|
.active_num(¤t_output)
|
||||||
|
.1
|
||||||
.saturating_add(1);
|
.saturating_add(1);
|
||||||
// TODO: Possibly move to next output, if idx too large
|
// TODO: Possibly move to next output, if idx too large
|
||||||
Shell::move_current_window(
|
Shell::move_current_window(
|
||||||
|
|
@ -773,6 +776,7 @@ impl State {
|
||||||
.shell
|
.shell
|
||||||
.workspaces
|
.workspaces
|
||||||
.active_num(¤t_output)
|
.active_num(¤t_output)
|
||||||
|
.1
|
||||||
.saturating_sub(1);
|
.saturating_sub(1);
|
||||||
// TODO: Possibly move to prev output, if idx < 0
|
// TODO: Possibly move to prev output, if idx < 0
|
||||||
Shell::move_current_window(
|
Shell::move_current_window(
|
||||||
|
|
@ -811,7 +815,7 @@ impl State {
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
let idx = self.common.shell.workspaces.active_num(&next_output);
|
let idx = self.common.shell.workspaces.active_num(&next_output).1;
|
||||||
if let Some(new_pos) = self.common.shell.activate(&next_output, idx) {
|
if let Some(new_pos) = self.common.shell.activate(&next_output, idx) {
|
||||||
seat.set_active_output(&next_output);
|
seat.set_active_output(&next_output);
|
||||||
if let Some(ptr) = seat.get_pointer() {
|
if let Some(ptr) = seat.get_pointer() {
|
||||||
|
|
@ -841,7 +845,7 @@ impl State {
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned()
|
||||||
{
|
{
|
||||||
let idx = self.common.shell.workspaces.active_num(&prev_output);
|
let idx = self.common.shell.workspaces.active_num(&prev_output).1;
|
||||||
if let Some(new_pos) = self.common.shell.activate(&prev_output, idx) {
|
if let Some(new_pos) = self.common.shell.activate(&prev_output, idx) {
|
||||||
seat.set_active_output(&prev_output);
|
seat.set_active_output(&prev_output);
|
||||||
if let Some(ptr) = seat.get_pointer() {
|
if let Some(ptr) = seat.get_pointer() {
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,7 @@ pub struct Shell {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WorkspaceSet {
|
pub struct WorkspaceSet {
|
||||||
|
previously_active: Option<(usize, Instant)>,
|
||||||
active: usize,
|
active: usize,
|
||||||
amount: WorkspaceAmount,
|
amount: WorkspaceAmount,
|
||||||
group: WorkspaceGroupHandle,
|
group: WorkspaceGroupHandle,
|
||||||
|
|
@ -155,6 +156,7 @@ impl WorkspaceSet {
|
||||||
};
|
};
|
||||||
|
|
||||||
WorkspaceSet {
|
WorkspaceSet {
|
||||||
|
previously_active: None,
|
||||||
active: 0,
|
active: 0,
|
||||||
amount,
|
amount,
|
||||||
group: group_handle,
|
group: group_handle,
|
||||||
|
|
@ -170,6 +172,7 @@ impl WorkspaceSet {
|
||||||
let old_active = self.active;
|
let old_active = self.active;
|
||||||
state.remove_workspace_state(&self.workspaces[old_active].handle, WState::Active);
|
state.remove_workspace_state(&self.workspaces[old_active].handle, WState::Active);
|
||||||
state.add_workspace_state(&self.workspaces[idx].handle, WState::Active);
|
state.add_workspace_state(&self.workspaces[idx].handle, WState::Active);
|
||||||
|
self.previously_active = Some((old_active, Instant::now()));
|
||||||
self.active = idx;
|
self.active = idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -180,12 +183,19 @@ impl WorkspaceSet {
|
||||||
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
|
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
|
||||||
outputs: impl Iterator<Item = (&'a Output, Point<i32, Logical>)>,
|
outputs: impl Iterator<Item = (&'a Output, Point<i32, Logical>)>,
|
||||||
) {
|
) {
|
||||||
|
if let Some((_, start)) = self.previously_active {
|
||||||
|
if Instant::now().duration_since(start).as_millis() >= ANIMATION_DURATION.as_millis() {
|
||||||
|
self.previously_active = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match self.amount {
|
match self.amount {
|
||||||
WorkspaceAmount::Dynamic => self.ensure_last_empty(state, outputs),
|
WorkspaceAmount::Dynamic => self.ensure_last_empty(state, outputs),
|
||||||
WorkspaceAmount::Static(len) => {
|
WorkspaceAmount::Static(len) => {
|
||||||
self.ensure_static(len as usize, state, toplevel_info, outputs)
|
self.ensure_static(len as usize, state, toplevel_info, outputs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.workspaces[self.active].refresh();
|
self.workspaces[self.active].refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -371,12 +381,20 @@ impl WorkspaceMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active(&self, output: &Output) -> &Workspace {
|
pub fn active(&self, output: &Output) -> (Option<(&Workspace, Instant)>, &Workspace) {
|
||||||
match self {
|
match self {
|
||||||
WorkspaceMode::Global(set) => &set.workspaces[set.active],
|
WorkspaceMode::Global(set) => (
|
||||||
|
set.previously_active
|
||||||
|
.map(|(idx, start)| (&set.workspaces[idx], start)),
|
||||||
|
&set.workspaces[set.active],
|
||||||
|
),
|
||||||
WorkspaceMode::OutputBound(sets, _) => {
|
WorkspaceMode::OutputBound(sets, _) => {
|
||||||
let set = sets.get(output).unwrap();
|
let set = sets.get(output).unwrap();
|
||||||
&set.workspaces[set.active]
|
(
|
||||||
|
set.previously_active
|
||||||
|
.map(|(idx, start)| (&set.workspaces[idx], start)),
|
||||||
|
&set.workspaces[set.active],
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -391,12 +409,12 @@ impl WorkspaceMode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn active_num(&self, output: &Output) -> usize {
|
pub fn active_num(&self, output: &Output) -> (Option<usize>, usize) {
|
||||||
match self {
|
match self {
|
||||||
WorkspaceMode::Global(set) => set.active,
|
WorkspaceMode::Global(set) => (set.previously_active.map(|(idx, _)| idx), set.active),
|
||||||
WorkspaceMode::OutputBound(sets, _) => {
|
WorkspaceMode::OutputBound(sets, _) => {
|
||||||
let set = sets.get(output).unwrap();
|
let set = sets.get(output).unwrap();
|
||||||
set.active
|
(set.previously_active.map(|(idx, _)| idx), set.active)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1050,7 +1068,12 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn animations_going(&self) -> bool {
|
pub fn animations_going(&self) -> bool {
|
||||||
matches!(self.overview_mode, OverviewMode::None)
|
(match &self.workspaces {
|
||||||
|
WorkspaceMode::Global(set) => set.previously_active.is_some(),
|
||||||
|
WorkspaceMode::OutputBound(sets, _) => {
|
||||||
|
sets.values().any(|set| set.previously_active.is_some())
|
||||||
|
}
|
||||||
|
}) || matches!(self.overview_mode, OverviewMode::None)
|
||||||
|| self
|
|| self
|
||||||
.workspaces
|
.workspaces
|
||||||
.spaces()
|
.spaces()
|
||||||
|
|
@ -1233,7 +1256,7 @@ impl Shell {
|
||||||
follow: bool,
|
follow: bool,
|
||||||
) -> Option<Point<i32, Logical>> {
|
) -> Option<Point<i32, Logical>> {
|
||||||
let (to_output, to_idx) = to;
|
let (to_output, to_idx) = to;
|
||||||
let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output));
|
let to_idx = to_idx.unwrap_or(state.common.shell.workspaces.active_num(to_output).1);
|
||||||
if state
|
if state
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
|
|
@ -1245,7 +1268,7 @@ impl Shell {
|
||||||
}
|
}
|
||||||
|
|
||||||
if from_output == to_output
|
if from_output == to_output
|
||||||
&& to_idx == state.common.shell.workspaces.active_num(from_output)
|
&& to_idx == state.common.shell.workspaces.active_num(from_output).1
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use crate::{
|
||||||
state::State,
|
state::State,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::{
|
wayland::{
|
||||||
handlers::screencopy::{DropableSession, WORKSPACE_OVERVIEW_NAMESPACE},
|
handlers::screencopy::DropableSession,
|
||||||
protocols::{
|
protocols::{
|
||||||
screencopy::{BufferParams, Session as ScreencopySession},
|
screencopy::{BufferParams, Session as ScreencopySession},
|
||||||
toplevel_info::ToplevelInfoState,
|
toplevel_info::ToplevelInfoState,
|
||||||
|
|
@ -38,12 +38,12 @@ use smithay::{
|
||||||
ImportAll, ImportMem, Renderer,
|
ImportAll, ImportMem, Renderer,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
desktop::{layer_map_for_output, space::SpaceElement, LayerSurface},
|
desktop::{layer_map_for_output, space::SpaceElement},
|
||||||
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
input::{pointer::GrabStartData as PointerGrabStartData, Seat},
|
||||||
output::Output,
|
output::Output,
|
||||||
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
reexports::wayland_server::protocol::wl_surface::WlSurface,
|
||||||
utils::{Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Size},
|
utils::{Buffer as BufferCoords, IsAlive, Logical, Physical, Point, Rectangle, Scale, Size},
|
||||||
wayland::{seat::WaylandFocus, shell::wlr_layer::Layer},
|
wayland::seat::WaylandFocus,
|
||||||
xwayland::X11Surface,
|
xwayland::X11Surface,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, time::Instant};
|
use std::{collections::HashMap, time::Instant};
|
||||||
|
|
@ -470,7 +470,6 @@ impl Workspace {
|
||||||
draw_focus_indicator: Option<&Seat<State>>,
|
draw_focus_indicator: Option<&Seat<State>>,
|
||||||
overview: OverviewMode,
|
overview: OverviewMode,
|
||||||
indicator_thickness: u8,
|
indicator_thickness: u8,
|
||||||
exclude_workspace_overview: bool,
|
|
||||||
) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
|
) -> Result<Vec<WorkspaceRenderElement<R>>, OutputNotMapped>
|
||||||
where
|
where
|
||||||
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
||||||
|
|
@ -488,32 +487,6 @@ impl Workspace {
|
||||||
let layer_map = layer_map_for_output(output);
|
let layer_map = layer_map_for_output(output);
|
||||||
|
|
||||||
if let Some(fullscreen) = self.fullscreen.get(output) {
|
if let Some(fullscreen) = self.fullscreen.get(output) {
|
||||||
// overlay layer surfaces
|
|
||||||
render_elements.extend(
|
|
||||||
layer_map
|
|
||||||
.layers()
|
|
||||||
.rev()
|
|
||||||
.filter(|s| {
|
|
||||||
s.layer() == Layer::Overlay
|
|
||||||
&& !(exclude_workspace_overview
|
|
||||||
&& s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE)
|
|
||||||
})
|
|
||||||
.filter_map(|surface| {
|
|
||||||
layer_map
|
|
||||||
.layer_geometry(surface)
|
|
||||||
.map(|geo| (geo.loc, surface))
|
|
||||||
})
|
|
||||||
.flat_map(|(loc, surface)| {
|
|
||||||
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>(
|
|
||||||
surface,
|
|
||||||
renderer,
|
|
||||||
loc.to_physical_precise_round(output_scale),
|
|
||||||
Scale::from(output_scale),
|
|
||||||
1.0,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
render_elements.extend(
|
render_elements.extend(
|
||||||
override_redirect_windows
|
override_redirect_windows
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -557,39 +530,6 @@ impl Workspace {
|
||||||
// - keyboard window swapping
|
// - keyboard window swapping
|
||||||
// - resizing in tiling
|
// - resizing in tiling
|
||||||
|
|
||||||
// overlay and top layer surfaces
|
|
||||||
let lower = {
|
|
||||||
let (lower, upper): (Vec<&LayerSurface>, Vec<&LayerSurface>) = layer_map
|
|
||||||
.layers()
|
|
||||||
.rev()
|
|
||||||
.filter(|s| {
|
|
||||||
!(exclude_workspace_overview
|
|
||||||
&& s.namespace() == "cosmic-workspace-overview")
|
|
||||||
})
|
|
||||||
.partition(|s| matches!(s.layer(), Layer::Background | Layer::Bottom));
|
|
||||||
|
|
||||||
render_elements.extend(
|
|
||||||
upper
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|surface| {
|
|
||||||
layer_map
|
|
||||||
.layer_geometry(surface)
|
|
||||||
.map(|geo| (geo.loc, surface))
|
|
||||||
})
|
|
||||||
.flat_map(|(loc, surface)| {
|
|
||||||
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>(
|
|
||||||
surface,
|
|
||||||
renderer,
|
|
||||||
loc.to_physical_precise_round(output_scale),
|
|
||||||
Scale::from(output_scale),
|
|
||||||
1.0,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
lower
|
|
||||||
};
|
|
||||||
|
|
||||||
// OR windows above all
|
// OR windows above all
|
||||||
render_elements.extend(
|
render_elements.extend(
|
||||||
override_redirect_windows
|
override_redirect_windows
|
||||||
|
|
@ -609,6 +549,7 @@ impl Workspace {
|
||||||
|
|
||||||
let focused =
|
let focused =
|
||||||
draw_focus_indicator.and_then(|seat| self.focus_stack.get(seat).last().cloned());
|
draw_focus_indicator.and_then(|seat| self.focus_stack.get(seat).last().cloned());
|
||||||
|
|
||||||
// floating surfaces
|
// floating surfaces
|
||||||
let alpha = match &overview {
|
let alpha = match &overview {
|
||||||
OverviewMode::Started(_, started) => {
|
OverviewMode::Started(_, started) => {
|
||||||
|
|
@ -716,28 +657,6 @@ impl Workspace {
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// bottom and background layer surfaces
|
|
||||||
{
|
|
||||||
render_elements.extend(
|
|
||||||
lower
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|surface| {
|
|
||||||
layer_map
|
|
||||||
.layer_geometry(surface)
|
|
||||||
.map(|geo| (geo.loc, surface))
|
|
||||||
})
|
|
||||||
.flat_map(|(loc, surface)| {
|
|
||||||
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>(
|
|
||||||
surface,
|
|
||||||
renderer,
|
|
||||||
loc.to_physical_precise_round(output_scale),
|
|
||||||
Scale::from(output_scale),
|
|
||||||
1.0,
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(render_elements)
|
Ok(render_elements)
|
||||||
|
|
|
||||||
|
|
@ -372,7 +372,13 @@ impl ScreencopyHandler for State {
|
||||||
render_output_to_buffer(self, &session, params, &output)
|
render_output_to_buffer(self, &session, params, &output)
|
||||||
}
|
}
|
||||||
SessionType::Workspace(output, handle) => {
|
SessionType::Workspace(output, handle) => {
|
||||||
render_workspace_to_buffer(self, &session, params, &output, &handle)
|
render_workspace_to_buffer(
|
||||||
|
self,
|
||||||
|
&session,
|
||||||
|
params,
|
||||||
|
&output,
|
||||||
|
(handle, 0), /* TODO: hack, we should have the index */
|
||||||
|
)
|
||||||
}
|
}
|
||||||
SessionType::Window(window) => {
|
SessionType::Window(window) => {
|
||||||
render_window_to_buffer(self, &session, params, &window)
|
render_window_to_buffer(self, &session, params, &window)
|
||||||
|
|
@ -764,7 +770,7 @@ pub fn render_workspace_to_buffer(
|
||||||
session: &Session,
|
session: &Session,
|
||||||
params: BufferParams,
|
params: BufferParams,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
handle: &WorkspaceHandle,
|
handle: (WorkspaceHandle, usize),
|
||||||
) -> Result<bool, (FailureReason, anyhow::Error)> {
|
) -> Result<bool, (FailureReason, anyhow::Error)> {
|
||||||
let mode = output
|
let mode = output
|
||||||
.current_mode()
|
.current_mode()
|
||||||
|
|
@ -783,7 +789,7 @@ pub fn render_workspace_to_buffer(
|
||||||
common: &mut Common,
|
common: &mut Common,
|
||||||
session: &Session,
|
session: &Session,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
handle: &WorkspaceHandle,
|
handle: (WorkspaceHandle, usize),
|
||||||
) -> Result<(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates), DTError<R>>
|
) -> Result<(Option<Vec<Rectangle<i32, Physical>>>, RenderElementStates), DTError<R>>
|
||||||
where
|
where
|
||||||
R: Renderer
|
R: Renderer
|
||||||
|
|
@ -814,6 +820,7 @@ pub fn render_workspace_to_buffer(
|
||||||
age,
|
age,
|
||||||
common,
|
common,
|
||||||
&output,
|
&output,
|
||||||
|
None,
|
||||||
handle,
|
handle,
|
||||||
cursor_mode,
|
cursor_mode,
|
||||||
None,
|
None,
|
||||||
|
|
@ -837,6 +844,7 @@ pub fn render_workspace_to_buffer(
|
||||||
age,
|
age,
|
||||||
common,
|
common,
|
||||||
&output,
|
&output,
|
||||||
|
None,
|
||||||
handle,
|
handle,
|
||||||
cursor_mode,
|
cursor_mode,
|
||||||
None,
|
None,
|
||||||
|
|
@ -1304,7 +1312,7 @@ pub fn schedule_offscreen_workspace_session(
|
||||||
&session,
|
&session,
|
||||||
params.clone(),
|
params.clone(),
|
||||||
&output,
|
&output,
|
||||||
&handle,
|
(handle, 0), /* TODO: Hack, we should know the idx */
|
||||||
) {
|
) {
|
||||||
Ok(false) => {
|
Ok(false) => {
|
||||||
// rendering yielded no new damage, buffer still pending
|
// rendering yielded no new damage, buffer still pending
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue