shell: One workspace per output

This commit is contained in:
Victoria Brekenfeld 2023-10-25 19:40:26 +02:00
parent 42aaafe586
commit 72df9d07e6
21 changed files with 1561 additions and 1987 deletions

View file

@ -1507,7 +1507,6 @@ impl KmsState {
false
};
shell.refresh_outputs();
if recreated {
let sessions = output.pending_buffers().collect::<Vec<_>>();
if let Err(err) = self.schedule_render(

View file

@ -349,7 +349,6 @@ impl State {
output.change_current_state(Some(mode), None, None, None);
layer_map_for_output(output).arrange();
self.common.output_configuration_state.update();
self.common.shell.refresh_outputs();
render_ping.ping();
}
WinitEvent::Refresh => render_ping.ping(),

View file

@ -448,7 +448,6 @@ pub fn init_backend(
output.set_preferred(mode);
layer_map_for_output(output).arrange();
state.common.output_configuration_state.update();
state.common.shell.refresh_outputs();
surface.dirty = true;
if !surface.pending {
surface.render.ping();

View file

@ -350,7 +350,7 @@ impl State {
if let Some(old_workspace) = old_w.get_mut(0) {
if let Some(new_workspace) = other_w.iter_mut().find(|w| w.handle == new_workspace) {
if new_workspace.tiling_layer.windows().next().is_none() {
if let Some(focus) = TilingLayout::move_tree(&mut old_workspace.tiling_layer, &mut new_workspace.tiling_layer, &current_output, &new_workspace.handle, &seat, new_workspace.focus_stack.get(&seat).iter(), old_descriptor, &mut data.common.shell.toplevel_info_state) {
if let Some(focus) = TilingLayout::move_tree(&mut old_workspace.tiling_layer, &mut new_workspace.tiling_layer, &new_workspace.handle, &seat, new_workspace.focus_stack.get(&seat).iter(), old_descriptor, &mut data.common.shell.toplevel_info_state) {
let seat = seat.clone();
data.common.event_loop_handle.insert_idle(move |state| {
Common::set_focus(state, Some(&focus), &seat, None);
@ -1333,16 +1333,15 @@ impl State {
}
Action::NextOutput => {
let current_output = seat.active_output();
if let Some(next_output) = self
let next_output = self
.common
.shell
.outputs
.iter()
.outputs()
.skip_while(|o| *o != &current_output)
.skip(1)
.next()
.cloned()
{
.cloned();
if let Some(next_output) = next_output {
let idx = self.common.shell.workspaces.active_num(&next_output).1;
match self.common.shell.activate(&next_output, idx) {
Ok(Some(new_pos)) => {
@ -1369,17 +1368,16 @@ impl State {
}
Action::PreviousOutput => {
let current_output = seat.active_output();
if let Some(prev_output) = self
let prev_output = self
.common
.shell
.outputs
.iter()
.outputs()
.rev()
.skip_while(|o| *o != &current_output)
.skip(1)
.next()
.cloned()
{
.cloned();
if let Some(prev_output) = prev_output {
let idx = self.common.shell.workspaces.active_num(&prev_output).1;
match self.common.shell.activate(&prev_output, idx) {
Ok(Some(new_pos)) => {
@ -1406,16 +1404,15 @@ impl State {
}
x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => {
let current_output = seat.active_output();
if let Some(next_output) = self
let next_output = self
.common
.shell
.outputs
.iter()
.outputs()
.skip_while(|o| *o != &current_output)
.skip(1)
.next()
.cloned()
{
.cloned();
if let Some(next_output) = next_output {
if let Ok(Some(new_pos)) = Shell::move_current_window(
self,
seat,
@ -1441,17 +1438,16 @@ impl State {
}
x @ Action::MoveToPreviousOutput | x @ Action::SendToPreviousOutput => {
let current_output = seat.active_output();
if let Some(prev_output) = self
let prev_output = self
.common
.shell
.outputs
.iter()
.outputs()
.rev()
.skip_while(|o| *o != &current_output)
.skip(1)
.next()
.cloned()
{
.cloned();
if let Some(prev_output) = prev_output {
if let Ok(Some(new_pos)) = Shell::move_current_window(
self,
seat,

View file

@ -492,7 +492,7 @@ impl CosmicMapped {
pub fn convert_to_stack<'a>(
&mut self,
outputs: impl Iterator<Item = (&'a Output, Rectangle<i32, Logical>)>,
(output, overlap): (&'a Output, Rectangle<i32, Logical>),
) {
match &self.element {
CosmicMappedInternal::Window(window) => {
@ -518,7 +518,7 @@ impl CosmicMapped {
pub fn convert_to_surface<'a>(
&mut self,
surface: CosmicSurface,
outputs: impl Iterator<Item = (&'a Output, Rectangle<i32, Logical>)>,
(output, overlap): (&'a Output, Rectangle<i32, Logical>),
) {
let handle = self.loop_handle();
surface.try_force_undecorated(false);

View file

@ -154,7 +154,7 @@ impl Shell {
return None;
}
Some(self.outputs.iter().flat_map(|o| {
Some(self.outputs().flat_map(|o| {
let space = self.active_space(o);
let stack = space.focus_stack.get(seat);
stack.last().cloned()
@ -163,8 +163,9 @@ impl Shell {
.flatten()
.collect::<Vec<_>>();
for output in self.outputs.iter() {
let workspace = self.workspaces.active_mut(output);
for output in self.outputs().cloned().collect::<Vec<_>>().into_iter() {
// TODO: Add self.workspaces.active_workspaces()
let workspace = self.workspaces.active_mut(&output);
for focused in focused_windows.iter() {
if let CosmicSurface::X11(window) = focused.active_window() {
if let Some(xwm) = xwm.as_mut().and_then(|state| state.xwm.as_mut()) {
@ -223,8 +224,8 @@ impl Common {
let seats = state.common.seats().cloned().collect::<Vec<_>>();
for seat in seats {
let output = seat.active_output();
if !state.common.shell.outputs.contains(&output) {
seat.set_active_output(&state.common.shell.outputs[0]);
if !state.common.shell.outputs().any(|o| o == &output) {
seat.set_active_output(&state.common.shell.outputs().next().unwrap());
continue;
}
let last_known_focus = ActiveFocus::get(&seat);
@ -248,11 +249,16 @@ impl Common {
continue; // Focus is valid
}
}
KeyboardFocusTarget::Group(WindowGroup {
output: weak_output,
..
}) => {
if weak_output == output {
KeyboardFocusTarget::Group(WindowGroup { node, .. }) => {
if state
.common
.shell
.workspaces
.active(&output)
.1
.tiling_layer
.has_node(&node)
{
continue; // Focus is valid,
}
}

View file

@ -87,16 +87,13 @@ impl KeyboardFocusTarget {
#[derive(Debug, Clone)]
pub struct WindowGroup {
pub node: NodeId,
pub output: WeakOutput,
pub alive: Weak<()>,
pub focus_stack: Vec<NodeId>,
}
impl PartialEq for WindowGroup {
fn eq(&self, other: &Self) -> bool {
self.node == other.node
&& self.output == other.output
&& Weak::ptr_eq(&self.alive, &other.alive)
self.node == other.node && Weak::ptr_eq(&self.alive, &other.alive)
}
}

View file

@ -229,7 +229,7 @@ impl PointerGrab<State> for MoveGrab {
.workspaces
.active_mut(&self.cursor_output)
.tiling_layer
.cleanup_drag(&self.cursor_output);
.cleanup_drag();
self.cursor_output = current_output.clone();
}

View file

@ -11,7 +11,6 @@ use smithay::{
utils::{Logical, Point, Rectangle, Size},
wayland::seat::WaylandFocus,
};
use std::collections::HashMap;
use crate::{
backend::render::{element::AsGlowRenderer, IndicatorShader, Key, Usage},
@ -28,9 +27,7 @@ use crate::{
},
state::State,
utils::prelude::*,
wayland::{
handlers::xdg_shell::popup::get_popup_toplevel, protocols::toplevel_info::ToplevelInfoState,
},
wayland::handlers::xdg_shell::popup::get_popup_toplevel,
};
mod grabs;
@ -42,67 +39,53 @@ pub struct FloatingLayout {
}
impl FloatingLayout {
pub fn new() -> FloatingLayout {
Default::default()
pub fn new(output: &Output) -> FloatingLayout {
let mut layout = Self::default();
layout.space.map_output(output, (0, 0));
layout
}
pub fn map_output(&mut self, output: &Output, location: Point<i32, Logical>) {
self.space.map_output(output, location)
}
pub fn set_output(&mut self, output: &Output) {
let old_output = self.space.outputs().next().unwrap().clone();
self.space.unmap_output(&old_output);
self.space.map_output(output, (0, 0));
/*
TODO: rescale all positions? (evem rescale windows?)
*/
pub fn unmap_output(
&mut self,
output: &Output,
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
) {
let windows = self
.space
.elements_for_output(output)
.cloned()
.collect::<Vec<_>>();
for window in &windows {
for (toplevel, _) in window.windows() {
toplevel_info.toplevel_leave_output(&toplevel, output);
}
}
self.space.unmap_output(output);
self.refresh();
for window in &windows {
for output in self.space.outputs_for_element(&window) {
for (toplevel, _) in window.windows() {
toplevel_info.toplevel_enter_output(&toplevel, &output);
}
}
}
}
pub fn map(
&mut self,
mapped: impl Into<CosmicMapped>,
seat: &Seat<State>,
position: impl Into<Option<Point<i32, Logical>>>,
position: impl Into<Option<Point<i32, Local>>>,
) {
let mapped = mapped.into();
let output = seat.active_output();
let position = position.into();
self.map_internal(mapped, &output, position)
self.map_internal(mapped, position, None)
}
pub(in crate::shell) fn map_internal(
&mut self,
mapped: CosmicMapped,
output: &Output,
position: Option<Point<i32, Logical>>,
position: Option<Point<i32, Local>>,
size: Option<Size<i32, Logical>>,
) {
let mut win_geo = mapped.geometry();
let mut win_geo = mapped.geometry().as_local();
let output = self.space.outputs().next().unwrap().clone();
let layers = layer_map_for_output(&output);
let geometry = layers.non_exclusive_zone();
mapped.set_bounds(geometry.size);
let last_geometry = mapped.last_geometry.lock().unwrap().clone();
if let Some(size) = last_geometry.map(|g| g.size) {
if let Some(size) = size
.map(SizeExt::as_local)
.or(last_geometry.map(|g| g.size))
{
win_geo.size = size;
} else {
let (min_size, max_size) = (
@ -150,18 +133,10 @@ impl FloatingLayout {
});
mapped.set_tiled(false);
let offset = output.geometry().loc
- self
.space
.output_geometry(output)
.map(|g| g.loc)
.unwrap_or_default();
mapped.set_geometry(Rectangle::from_loc_and_size(
position + offset,
win_geo.size,
));
mapped
.set_geometry(Rectangle::from_loc_and_size(position, win_geo.size).to_global(&output));
mapped.configure();
self.space.map_element(mapped, position, false);
self.space.map_element(mapped, position.as_logical(), false);
}
pub fn unmap(&mut self, window: &CosmicMapped) -> bool {
@ -170,10 +145,8 @@ impl FloatingLayout {
if !is_maximized {
if let Some(location) = self.space.element_location(window) {
*window.last_geometry.lock().unwrap() = Some(Rectangle::from_loc_and_size(
location,
window.geometry().size,
));
*window.last_geometry.lock().unwrap() =
Some(Rectangle::from_loc_and_size(location, window.geometry().size).as_local());
}
}
@ -182,8 +155,8 @@ impl FloatingLayout {
was_unmaped
}
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Logical>> {
self.space.element_geometry(elem)
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Local>> {
self.space.element_geometry(elem).map(RectExt::as_local)
}
pub fn maximize_request(&mut self, window: &CosmicSurface) {
@ -339,13 +312,10 @@ impl FloatingLayout {
}));
mapped.set_resizing(true);
mapped.set_geometry(Rectangle::from_loc_and_size(
match mapped.active_window() {
CosmicSurface::X11(s) => s.geometry().loc,
_ => (0, 0).into(),
},
geo.size,
));
mapped.set_geometry(
geo.as_local()
.to_global(self.space.outputs().next().unwrap()),
);
mapped.configure();
true
@ -503,83 +473,26 @@ impl FloatingLayout {
{
// TODO what about windows leaving to the top with no headerbar to drag? can that happen? (Probably if the user is moving outputs down)
*element.last_geometry.lock().unwrap() = None;
let output = self.space.outputs().next().unwrap().clone();
self.map_internal(element, &output, None);
self.map_internal(element, None, None);
}
}
pub fn most_overlapped_output_for_element(&self, elem: &CosmicMapped) -> Option<Output> {
let elem_geo = self.space.element_geometry(elem)?;
if self.space.outputs().nth(1).is_none() {
return self.space.outputs().next().cloned();
}
Some(
self.space
.outputs_for_element(elem)
.into_iter()
.max_by_key(|o| {
let output_geo = self.space.output_geometry(o).unwrap();
if let Some(intersection) = output_geo.intersection(elem_geo) {
intersection.size.w * intersection.size.h
} else {
0
}
})
.unwrap_or(self.space.outputs().next().unwrap().clone()),
)
}
pub fn merge(&mut self, other: FloatingLayout) {
let mut output_pos_map = HashMap::new();
for output in self.space.outputs() {
output_pos_map.insert(
output.clone(),
self.space.output_geometry(output).unwrap().loc
- other
.space
.output_geometry(output)
.map(|geo| geo.loc)
.unwrap_or_else(|| (0, 0).into()),
);
}
for element in other.space.elements() {
let mut elem_geo = other.space.element_geometry(element).unwrap();
let output = other
let elem_loc = other
.space
.outputs_for_element(element)
.into_iter()
.filter(|o| self.space.outputs().any(|o2| o == o2))
.max_by_key(|o| {
let output_geo = other.space.output_geometry(o).unwrap();
let intersection = output_geo.intersection(elem_geo).unwrap();
intersection.size.w * intersection.size.h
})
.unwrap_or(self.space.outputs().next().unwrap().clone());
elem_geo.loc += output_pos_map
.get(&output)
.copied()
.unwrap_or_else(|| (0, 0).into());
let offset = output.geometry().loc
- self
.space
.output_geometry(&output)
.map(|g| g.loc)
.unwrap_or_default();
element.set_geometry(Rectangle::from_loc_and_size(
elem_geo.loc + offset,
elem_geo.size,
));
self.space.map_element(element.clone(), elem_geo.loc, false);
.element_geometry(element)
.unwrap()
.loc
.as_local();
self.map_internal(element.clone(), Some(elem_loc), None);
}
self.refresh(); //fixup any out of bounds elements
}
pub fn render_output<R>(
pub fn render<R>(
&self,
renderer: &mut R,
output: &Output,
focused: Option<&CosmicMapped>,
mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
indicator_thickness: u8,
@ -598,68 +511,65 @@ impl FloatingLayout {
#[cfg(feature = "debug")]
puffin::profile_function!();
let output = self.space.outputs().next().unwrap();
let output_scale = output.current_scale().fractional_scale();
let output_geo = self.space.output_geometry(output).unwrap();
let mut window_elements = Vec::new();
let mut popup_elements = Vec::new();
self.space
.elements_for_output(output)
.rev()
.for_each(|elem| {
let render_location = self.space.element_location(elem).unwrap()
- output_geo.loc
- elem.geometry().loc;
let (w_elements, p_elements) = elem.split_render_elements(
renderer,
render_location.to_physical_precise_round(output_scale),
output_scale.into(),
alpha,
);
self.space.elements().rev().for_each(|elem| {
let render_location = self.space.element_location(elem).unwrap() - elem.geometry().loc;
let (w_elements, p_elements) = elem.split_render_elements(
renderer,
render_location.to_physical_precise_round(output_scale),
output_scale.into(),
alpha,
);
if focused == Some(elem) {
let mut indicator_geometry = Rectangle::from_loc_and_size(
self.space.element_location(elem).unwrap() - output_geo.loc,
elem.geometry().size,
if focused == Some(elem) {
let mut indicator_geometry = Rectangle::from_loc_and_size(
self.space.element_location(elem).unwrap(),
elem.geometry().size,
)
.as_local();
if let Some((mode, resize)) = resize_indicator.as_mut() {
indicator_geometry.loc -= (18, 18).into();
indicator_geometry.size += (36, 36).into();
resize.resize(indicator_geometry.size.as_logical());
resize.output_enter(output, Rectangle::default() /* unused */);
window_elements.extend(
resize
.render_elements::<CosmicWindowRenderElement<R>>(
renderer,
indicator_geometry
.loc
.as_logical()
.to_physical_precise_round(output_scale),
output_scale.into(),
alpha * mode.alpha().unwrap_or(1.0),
)
.into_iter()
.map(CosmicMappedRenderElement::Window),
);
if let Some((mode, resize)) = resize_indicator.as_mut() {
indicator_geometry.loc -= (18, 18).into();
indicator_geometry.size += (36, 36).into();
resize.resize(indicator_geometry.size);
resize.output_enter(output, output_geo);
window_elements.extend(
resize
.render_elements::<CosmicWindowRenderElement<R>>(
renderer,
indicator_geometry
.loc
.to_physical_precise_round(output_scale),
output_scale.into(),
alpha * mode.alpha().unwrap_or(1.0),
)
.into_iter()
.map(CosmicMappedRenderElement::Window),
);
}
if indicator_thickness > 0 {
let element = IndicatorShader::focus_element(
renderer,
Key::Window(Usage::FocusIndicator, elem.clone()),
indicator_geometry,
indicator_thickness,
output_scale,
alpha,
);
window_elements.push(element.into());
}
}
window_elements.extend(w_elements);
popup_elements.extend(p_elements);
});
if indicator_thickness > 0 {
let element = IndicatorShader::focus_element(
renderer,
Key::Window(Usage::FocusIndicator, elem.clone()),
indicator_geometry,
indicator_thickness,
output_scale,
alpha,
);
window_elements.push(element.into());
}
}
window_elements.extend(w_elements);
popup_elements.extend(p_elements);
});
(window_elements, popup_elements)
}

View file

@ -137,67 +137,64 @@ impl PointerGrab<State> for ResizeForkGrab {
if let Some(output) = self.output.upgrade() {
let tiling_layer = &mut data.common.shell.active_space_mut(&output).tiling_layer;
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() {
let delta = match self.orientation {
Orientation::Vertical => delta.x,
Orientation::Horizontal => delta.y,
}
.round() as i32;
// check that we are still alive
let mut iter = tree
.children_ids(&self.node)
.unwrap()
.skip(self.left_up_idx);
let first_elem = iter.next();
let second_elem = iter.next();
if first_elem.is_none() || second_elem.is_none() {
return handle.unset_grab(data, event.serial, event.time);
};
match tree.get_mut(&self.node).unwrap().data_mut() {
Data::Group {
sizes, orientation, ..
} => {
if sizes[self.left_up_idx] + sizes[self.left_up_idx + 1]
< match orientation {
Orientation::Vertical => 720,
Orientation::Horizontal => 480,
}
{
return;
};
let old_size = sizes[self.left_up_idx];
sizes[self.left_up_idx] = (old_size + delta).max(
if self.orientation == Orientation::Vertical {
360
} else {
240
},
);
let diff = old_size - sizes[self.left_up_idx];
let next_size = sizes[self.left_up_idx + 1] + diff;
sizes[self.left_up_idx + 1] =
next_size.max(if self.orientation == Orientation::Vertical {
360
} else {
240
});
let next_diff = next_size - sizes[self.left_up_idx + 1];
sizes[self.left_up_idx] += next_diff;
}
_ => unreachable!(),
}
self.last_loc = event.location;
let blocker = TilingLayout::update_positions(&output, tree, tiling_layer.gaps);
tiling_layer.pending_blockers.extend(blocker);
} else {
handle.unset_grab(data, event.serial, event.time);
let tree = &mut tiling_layer.queue.trees.back_mut().unwrap().0;
if tree.get(&self.node).is_ok() {
let delta = match self.orientation {
Orientation::Vertical => delta.x,
Orientation::Horizontal => delta.y,
}
.round() as i32;
// check that we are still alive
let mut iter = tree
.children_ids(&self.node)
.unwrap()
.skip(self.left_up_idx);
let first_elem = iter.next();
let second_elem = iter.next();
if first_elem.is_none() || second_elem.is_none() {
return handle.unset_grab(data, event.serial, event.time);
};
match tree.get_mut(&self.node).unwrap().data_mut() {
Data::Group {
sizes, orientation, ..
} => {
if sizes[self.left_up_idx] + sizes[self.left_up_idx + 1]
< match orientation {
Orientation::Vertical => 720,
Orientation::Horizontal => 480,
}
{
return;
};
let old_size = sizes[self.left_up_idx];
sizes[self.left_up_idx] =
(old_size + delta).max(if self.orientation == Orientation::Vertical {
360
} else {
240
});
let diff = old_size - sizes[self.left_up_idx];
let next_size = sizes[self.left_up_idx + 1] + diff;
sizes[self.left_up_idx + 1] =
next_size.max(if self.orientation == Orientation::Vertical {
360
} else {
240
});
let next_diff = next_size - sizes[self.left_up_idx + 1];
sizes[self.left_up_idx] += next_diff;
}
_ => unreachable!(),
}
self.last_loc = event.location;
let blocker = TilingLayout::update_positions(&output, tree, tiling_layer.gaps);
tiling_layer.pending_blockers.extend(blocker);
} else {
handle.unset_grab(data, event.serial, event.time);
}
}
}

View file

@ -39,8 +39,7 @@ impl KeyboardGrab<State> for SwapWindowGrab {
serial: Serial,
time: u32,
) {
if self.desc.output.upgrade().is_none()
|| !matches!(&data.common.shell.overview_mode, OverviewMode::Started(Trigger::KeyboardSwap(_, d), _) if d == &self.desc)
if !matches!(&data.common.shell.overview_mode, OverviewMode::Started(Trigger::KeyboardSwap(_, d), _) if d == &self.desc)
{
handle.unset_grab(data, serial, false);
return;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -76,6 +76,7 @@ const FULLSCREEN_ANIMATION_DURATION: Duration = Duration::from_millis(200);
#[derive(Debug)]
pub struct Workspace {
pub output: Output,
pub tiling_layer: TilingLayout,
pub floating_layer: FloatingLayout,
pub tiling_enabled: bool,
@ -84,6 +85,7 @@ pub struct Workspace {
pub focus_stack: FocusStacks,
pub pending_buffers: Vec<(ScreencopySession, BufferParams)>,
pub screencopy_sessions: Vec<DropableSession>,
pub output_stack: VecDeque<String>,
pub(super) backdrop_id: Id,
pub dirty: AtomicBool,
}
@ -198,16 +200,26 @@ impl MoveResult {
}
impl Workspace {
pub fn new(handle: WorkspaceHandle, tiling_enabled: bool, gaps: (u8, u8)) -> Workspace {
pub fn new(
handle: WorkspaceHandle,
output: Output,
tiling_enabled: bool,
gaps: (u8, u8),
) -> Workspace {
let tiling_layer = TilingLayout::new(gaps, &output);
let floating_layer = FloatingLayout::new(&output);
Workspace {
tiling_layer: TilingLayout::new(gaps),
floating_layer: FloatingLayout::new(),
output,
tiling_layer,
floating_layer,
tiling_enabled,
fullscreen: HashMap::new(),
handle,
focus_stack: FocusStacks::default(),
pending_buffers: Vec::new(),
screencopy_sessions: Vec::new(),
output_stack: VecDeque::new(),
backdrop_id: Id::new(),
dirty: AtomicBool::new(false),
}
@ -299,27 +311,29 @@ impl Workspace {
}
}
pub fn map_output(&mut self, output: &Output, position: Point<i32, Logical>) {
self.tiling_layer.map_output(output, position);
self.floating_layer.map_output(output, position);
pub fn output(&self) -> &Output {
&self.output
}
pub fn unmap_output(
pub fn set_output(
&mut self,
output: &Output,
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
) {
if let Some(dead_output_fullscreen) = self.fullscreen.remove(output) {
self.unfullscreen_request(&dead_output_fullscreen.window.surface());
self.tiling_layer.set_output(output);
self.floating_layer.set_output(output);
for mapped in self.mapped() {
for (surface, _) in mapped.windows() {
toplevel_info.toplevel_leave_output(&surface, &self.output);
toplevel_info.toplevel_enter_output(&surface, output);
}
}
self.tiling_layer.unmap_output(output, toplevel_info);
self.floating_layer.unmap_output(output, toplevel_info);
self.refresh();
self.output = output.clone();
}
pub fn unmap(&mut self, mapped: &CosmicMapped) -> Option<ManagedState> {
let was_floating = self.floating_layer.unmap(&mapped);
let was_tiling = self.tiling_layer.unmap(&mapped).is_some();
let was_tiling = self.tiling_layer.unmap(&mapped);
if was_floating || was_tiling {
assert!(was_floating != was_tiling);
}
@ -363,67 +377,32 @@ impl Workspace {
.find(|e| {
e.windows()
.any(|(w, _)| w.wl_surface().as_ref() == Some(surface))
})
}
pub fn outputs_for_element(&self, elem: &CosmicMapped) -> impl Iterator<Item = Output> {
self.floating_layer
.space
.outputs_for_element(elem)
.into_iter()
.chain(self.tiling_layer.output_for_element(elem).cloned())
}
pub fn output_under(&self, point: Point<i32, Logical>) -> Option<&Output> {
let space = &self.floating_layer.space;
space.outputs().find(|o| {
let internal_output_geo = space.output_geometry(o).unwrap();
let external_output_geo = o.geometry();
internal_output_geo.contains(point - external_output_geo.loc + internal_output_geo.loc)
})
}
pub fn element_under(
&mut self,
location: Point<f64, Logical>,
location: Point<f64, Global>,
overview: OverviewMode,
) -> Option<(PointerFocusTarget, Point<i32, Logical>)> {
) -> Option<(PointerFocusTarget, Point<i32, Global>)> {
let location = location.to_local(&self.output);
self.floating_layer
.space
.element_under(location)
.map(|(mapped, p)| (mapped.clone().into(), p))
.element_under(location.as_logical())
.map(|(mapped, p)| (mapped.clone().into(), p.as_local()))
.or_else(|| self.tiling_layer.element_under(location, overview))
.map(|(m, p)| (m, p.to_global(&self.output)))
}
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Logical>> {
let space = &self.floating_layer.space;
let outputs = space.outputs().collect::<Vec<_>>();
let offset = if outputs.len() == 1
&& space.output_geometry(&outputs[0]).unwrap().loc == Point::from((0, 0))
{
outputs[0].geometry().loc
} else {
(0, 0).into()
};
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Local>> {
self.floating_layer
.space
.element_geometry(elem)
.or_else(|| self.tiling_layer.element_geometry(elem))
.map(|mut geo| {
geo.loc += offset;
geo
})
}
pub fn recalculate(&mut self, output: &Output) {
if let Some(f) = self.fullscreen.get(output) {
if !f.exclusive {
f.window
.set_geometry(layer_map_for_output(output).non_exclusive_zone());
}
}
self.tiling_layer.recalculate(output);
pub fn recalculate(&mut self) {
self.tiling_layer.recalculate();
self.floating_layer.refresh();
}
pub fn maximize_request(
@ -574,7 +553,7 @@ impl Workspace {
}
}
result
Some(f.original_geometry.size.as_logical())
} else {
None
}
@ -730,7 +709,7 @@ impl Workspace {
}
let was_floating = self.floating_layer.unmap(&mapped);
let was_tiled = self.tiling_layer.unmap_as_placeholder(&mapped);
let was_tiled = dbg!(self.tiling_layer.unmap_as_placeholder(&mapped));
assert!(was_floating != was_tiled.is_some());
Some(MoveGrab::new(
@ -754,7 +733,7 @@ impl Workspace {
.into_iter()
{
self.tiling_layer.unmap(&window);
self.floating_layer.map(window, seat, None);
self.floating_layer.map(window, None);
}
self.tiling_enabled = false;
} else {
@ -767,8 +746,7 @@ impl Workspace {
.into_iter()
{
self.floating_layer.unmap(&window);
self.tiling_layer
.map(window, seat, focus_stack.iter(), None)
self.tiling_layer.map(window, focus_stack.iter(), None)
}
self.tiling_enabled = true;
}
@ -779,12 +757,11 @@ impl Workspace {
if let Some(window) = self.focus_stack.get(seat).iter().next().cloned() {
if self.tiling_layer.mapped().any(|(_, m, _)| m == &window) {
self.tiling_layer.unmap(&window);
self.floating_layer.map(window, seat, None);
self.floating_layer.map(window, None);
} else if self.floating_layer.mapped().any(|w| w == &window) {
let focus_stack = self.focus_stack.get(seat);
self.floating_layer.unmap(&window);
self.tiling_layer
.map(window, seat, focus_stack.iter(), None)
self.tiling_layer.map(window, focus_stack.iter(), None)
}
}
}
@ -837,8 +814,8 @@ impl Workspace {
pub fn node_desc(&self, focus: KeyboardFocusTarget) -> Option<NodeDesc> {
match focus {
KeyboardFocusTarget::Element(mapped) => {
self.tiling_layer.mapped().find_map(|(output, m, _)| {
(m == &mapped).then_some(output.clone()).and_then(|output| {
self.tiling_layer.mapped().find_map(|(_, m, _)| {
if m == &mapped {
mapped
.tiling_node_id
.lock()
@ -846,7 +823,6 @@ impl Workspace {
.clone()
.map(|node_id| NodeDesc {
handle: self.handle.clone(),
output: output.downgrade(),
node: node_id,
stack_window: if mapped
.stack_ref()
@ -858,12 +834,13 @@ impl Workspace {
None
},
})
})
} else {
None
}
})
}
KeyboardFocusTarget::Group(WindowGroup { output, node, .. }) => Some(NodeDesc {
KeyboardFocusTarget::Group(WindowGroup { node, .. }) => Some(NodeDesc {
handle: self.handle.clone(),
output,
node,
stack_window: None,
}),
@ -904,10 +881,9 @@ impl Workspace {
}
}
pub fn render_output<'a, R>(
pub fn render<'a, R>(
&self,
renderer: &mut R,
output: &Output,
override_redirect_windows: &[X11Surface],
xwm_state: Option<&'a mut XWaylandState>,
draw_focus_indicator: Option<&Seat<State>>,
@ -1089,9 +1065,8 @@ impl Workspace {
OverviewMode::None => 1.0,
};
let (w_elements, p_elements) = self.floating_layer.render_output::<R>(
let (w_elements, p_elements) = self.floating_layer.render::<R>(
renderer,
output,
focused.as_ref(),
resize_indicator.clone(),
indicator_thickness,
@ -1113,11 +1088,10 @@ impl Workspace {
};
//tiling surfaces
let (w_elements, p_elements) = self.tiling_layer.render_output::<R>(
let (w_elements, p_elements) = self.tiling_layer.render::<R>(
renderer,
output,
draw_focus_indicator,
layer_map.non_exclusive_zone(),
zone,
overview,
resize_indicator,
indicator_thickness,

View file

@ -511,50 +511,34 @@ impl Common {
let active = self.shell.active_space(output);
active.mapped().for_each(|mapped| {
let outputs_for_element: Vec<_> = active.outputs_for_element(mapped).collect();
if outputs_for_element.contains(&output) {
let window = mapped.active_window();
window.with_surfaces(|surface, states| {
let primary_scanout_output = update_surface_primary_scanout_output(
surface,
output,
states,
render_element_states,
|current_output, current_state, next_output, next_state| {
if outputs_for_element.contains(current_output) {
default_primary_scanout_output_compare(
current_output,
current_state,
next_output,
next_state,
)
} else {
next_output
}
},
);
if let Some(output) = primary_scanout_output {
with_fractional_scale(states, |fraction_scale| {
fraction_scale
.set_preferred_scale(output.current_scale().fractional_scale());
});
}
});
window.send_frame(output, time, throttle, surface_primary_scanout_output);
if let Some(feedback) = window
.wl_surface()
.and_then(|wl_surface| {
source_node_for_surface(&wl_surface, &self.display_handle)
})
.and_then(|source| dmabuf_feedback(source))
{
window.send_dmabuf_feedback(
output,
&feedback,
render_element_states,
surface_primary_scanout_output,
);
let window = mapped.active_window();
window.with_surfaces(|surface, states| {
let primary_scanout_output = update_surface_primary_scanout_output(
surface,
output,
states,
render_element_states,
|_current_output, _current_state, next_output, _next_state| next_output,
);
if let Some(output) = primary_scanout_output {
with_fractional_scale(states, |fraction_scale| {
fraction_scale
.set_preferred_scale(output.current_scale().fractional_scale());
});
}
});
window.send_frame(output, time, throttle, surface_primary_scanout_output);
if let Some(feedback) = window
.wl_surface()
.and_then(|wl_surface| source_node_for_surface(&wl_surface, &self.display_handle))
.and_then(|source| dmabuf_feedback(source))
{
window.send_dmabuf_feedback(
output,
&feedback,
render_element_states,
surface_primary_scanout_output,
);
}
});
@ -565,10 +549,8 @@ impl Common {
.filter(|w| w.handle != active.handle)
{
space.mapped().for_each(|mapped| {
if space.outputs_for_element(mapped).any(|o| &o == output) {
let window = mapped.active_window();
window.send_frame(output, time, throttle, |_, _| None);
}
let window = mapped.active_window();
window.send_frame(space.output(), time, throttle, |_, _| None);
});
}

View file

@ -254,7 +254,7 @@ impl CompositorHandler for State {
let changed = layer_map_for_output(&output).arrange();
if changed {
for workspace in self.common.shell.workspaces.spaces_mut() {
workspace.recalculate(&output);
workspace.recalculate();
}
}
}

View file

@ -41,8 +41,7 @@ impl WlrLayerShellHandler for State {
}
fn new_popup(&mut self, _parent: WlrLayerSurface, popup: PopupSurface) {
let positioner = popup.with_pending_state(|state| state.positioner);
self.common.shell.unconstrain_popup(&popup, &positioner);
self.common.shell.unconstrain_popup(&popup);
if popup.send_configure().is_ok() {
self.common
@ -76,7 +75,7 @@ impl WlrLayerShellHandler for State {
}
for workspace in self.common.shell.workspaces.spaces_mut() {
workspace.recalculate(&output);
workspace.recalculate();
}
// collect screencopy sessions needing an update

View file

@ -1296,7 +1296,7 @@ pub fn schedule_offscreen_workspace_session(
if !session.alive() {
return;
}
if !state.common.shell.outputs.contains(&output) {
if !state.common.shell.outputs().any(|o| o == &output) {
return;
}
match render_workspace_to_buffer(

View file

@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::{
shell::WorkspaceMode,
state::ClientState,
utils::prelude::*,
wayland::protocols::workspace::{
@ -30,19 +29,12 @@ impl WorkspaceHandler for State {
for request in requests.into_iter() {
match request {
Request::Activate(handle) => {
let maybe = match &self.common.shell.workspaces {
WorkspaceMode::Global(set) => set
.workspaces
let maybe = self.common.shell.workspaces.iter().find_map(|(o, set)| {
set.workspaces
.iter()
.position(|w| w.handle == handle)
.map(|i| (self.common.last_active_seat().active_output(), i)),
WorkspaceMode::OutputBound(sets, _) => sets.iter().find_map(|(o, set)| {
set.workspaces
.iter()
.position(|w| w.handle == handle)
.map(|i| (o.clone(), i))
}),
};
.map(|i| (o.clone(), i))
});
if let Some((output, idx)) = maybe {
let _ = self.common.shell.activate(&output, idx); // TODO: move cursor?

View file

@ -50,7 +50,7 @@ impl XdgShellHandler for State {
if surface.get_parent_surface().is_some() {
// let other shells deal with their popups
self.common.shell.unconstrain_popup(&surface, &positioner);
self.common.shell.unconstrain_popup(&surface);
if surface.send_configure().is_ok() {
self.common
@ -123,7 +123,7 @@ impl XdgShellHandler for State {
state.positioner = positioner;
});
self.common.shell.unconstrain_popup(&surface, &positioner);
self.common.shell.unconstrain_popup(&surface);
surface.send_repositioned(token);
if let Err(err) = surface.send_configure() {
warn!(
@ -150,9 +150,6 @@ impl XdgShellHandler for State {
}
fn maximize_request(&mut self, surface: ToplevelSurface) {
let seat = self.common.last_active_seat();
let output = seat.active_output();
if let Some(mapped) = self
.common
.shell
@ -164,7 +161,7 @@ impl XdgShellHandler for State {
.windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
.unwrap();
workspace.maximize_request(&window, &output, self.common.event_loop_handle.clone())
workspace.maximize_request(&window)
}
}
}
@ -194,6 +191,7 @@ impl XdgShellHandler for State {
let seat = self.common.last_active_seat();
seat.active_output()
});
// TODO: If this is not the output? Do we move it?
if let Some(mapped) = self
.common
@ -206,11 +204,7 @@ impl XdgShellHandler for State {
.windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
.unwrap();
workspace.fullscreen_request(
&window,
&output,
self.common.event_loop_handle.clone(),
)
workspace.fullscreen_request(&window)
}
}
}

View file

@ -363,14 +363,11 @@ impl XwmHandler for State {
}
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
let seat = self.common.last_active_seat();
let output = seat.active_output();
let surface = CosmicSurface::X11(window);
if let Some(mapped) = self.common.shell.element_for_surface(&surface).cloned() {
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
let (window, _) = mapped.windows().find(|(w, _)| w == &surface).unwrap();
workspace.maximize_request(&window, &output, self.common.event_loop_handle.clone())
workspace.maximize_request(&window);
}
}
}
@ -386,18 +383,10 @@ impl XwmHandler for State {
}
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
let seat = self.common.last_active_seat();
let output = seat.active_output();
let surface = CosmicSurface::X11(window);
if let Some(mapped) = self.common.shell.element_for_surface(&surface).cloned() {
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
let (window, _) = mapped.windows().find(|(w, _)| w == &surface).unwrap();
workspace.fullscreen_request(
&window,
&output,
self.common.event_loop_handle.clone(),
)
workspace.fullscreen_request(&surface)
}
}
}