shell: One workspace per output
This commit is contained in:
parent
42aaafe586
commit
72df9d07e6
21 changed files with 1561 additions and 1987 deletions
|
|
@ -1507,7 +1507,6 @@ impl KmsState {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
shell.refresh_outputs();
|
|
||||||
if recreated {
|
if recreated {
|
||||||
let sessions = output.pending_buffers().collect::<Vec<_>>();
|
let sessions = output.pending_buffers().collect::<Vec<_>>();
|
||||||
if let Err(err) = self.schedule_render(
|
if let Err(err) = self.schedule_render(
|
||||||
|
|
|
||||||
|
|
@ -349,7 +349,6 @@ impl State {
|
||||||
output.change_current_state(Some(mode), None, None, None);
|
output.change_current_state(Some(mode), None, None, None);
|
||||||
layer_map_for_output(output).arrange();
|
layer_map_for_output(output).arrange();
|
||||||
self.common.output_configuration_state.update();
|
self.common.output_configuration_state.update();
|
||||||
self.common.shell.refresh_outputs();
|
|
||||||
render_ping.ping();
|
render_ping.ping();
|
||||||
}
|
}
|
||||||
WinitEvent::Refresh => render_ping.ping(),
|
WinitEvent::Refresh => render_ping.ping(),
|
||||||
|
|
|
||||||
|
|
@ -448,7 +448,6 @@ pub fn init_backend(
|
||||||
output.set_preferred(mode);
|
output.set_preferred(mode);
|
||||||
layer_map_for_output(output).arrange();
|
layer_map_for_output(output).arrange();
|
||||||
state.common.output_configuration_state.update();
|
state.common.output_configuration_state.update();
|
||||||
state.common.shell.refresh_outputs();
|
|
||||||
surface.dirty = true;
|
surface.dirty = true;
|
||||||
if !surface.pending {
|
if !surface.pending {
|
||||||
surface.render.ping();
|
surface.render.ping();
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,7 @@ impl State {
|
||||||
if let Some(old_workspace) = old_w.get_mut(0) {
|
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 let Some(new_workspace) = other_w.iter_mut().find(|w| w.handle == new_workspace) {
|
||||||
if new_workspace.tiling_layer.windows().next().is_none() {
|
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, ¤t_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();
|
let seat = seat.clone();
|
||||||
data.common.event_loop_handle.insert_idle(move |state| {
|
data.common.event_loop_handle.insert_idle(move |state| {
|
||||||
Common::set_focus(state, Some(&focus), &seat, None);
|
Common::set_focus(state, Some(&focus), &seat, None);
|
||||||
|
|
@ -1333,16 +1333,15 @@ impl State {
|
||||||
}
|
}
|
||||||
Action::NextOutput => {
|
Action::NextOutput => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
if let Some(next_output) = self
|
let next_output = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.outputs
|
.outputs()
|
||||||
.iter()
|
|
||||||
.skip_while(|o| *o != ¤t_output)
|
.skip_while(|o| *o != ¤t_output)
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned();
|
||||||
{
|
if let Some(next_output) = next_output {
|
||||||
let idx = self.common.shell.workspaces.active_num(&next_output).1;
|
let idx = self.common.shell.workspaces.active_num(&next_output).1;
|
||||||
match self.common.shell.activate(&next_output, idx) {
|
match self.common.shell.activate(&next_output, idx) {
|
||||||
Ok(Some(new_pos)) => {
|
Ok(Some(new_pos)) => {
|
||||||
|
|
@ -1369,17 +1368,16 @@ impl State {
|
||||||
}
|
}
|
||||||
Action::PreviousOutput => {
|
Action::PreviousOutput => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
if let Some(prev_output) = self
|
let prev_output = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.outputs
|
.outputs()
|
||||||
.iter()
|
|
||||||
.rev()
|
.rev()
|
||||||
.skip_while(|o| *o != ¤t_output)
|
.skip_while(|o| *o != ¤t_output)
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned();
|
||||||
{
|
if let Some(prev_output) = prev_output {
|
||||||
let idx = self.common.shell.workspaces.active_num(&prev_output).1;
|
let idx = self.common.shell.workspaces.active_num(&prev_output).1;
|
||||||
match self.common.shell.activate(&prev_output, idx) {
|
match self.common.shell.activate(&prev_output, idx) {
|
||||||
Ok(Some(new_pos)) => {
|
Ok(Some(new_pos)) => {
|
||||||
|
|
@ -1406,16 +1404,15 @@ impl State {
|
||||||
}
|
}
|
||||||
x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => {
|
x @ Action::MoveToNextOutput | x @ Action::SendToNextOutput => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
if let Some(next_output) = self
|
let next_output = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.outputs
|
.outputs()
|
||||||
.iter()
|
|
||||||
.skip_while(|o| *o != ¤t_output)
|
.skip_while(|o| *o != ¤t_output)
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned();
|
||||||
{
|
if let Some(next_output) = next_output {
|
||||||
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
||||||
self,
|
self,
|
||||||
seat,
|
seat,
|
||||||
|
|
@ -1441,17 +1438,16 @@ impl State {
|
||||||
}
|
}
|
||||||
x @ Action::MoveToPreviousOutput | x @ Action::SendToPreviousOutput => {
|
x @ Action::MoveToPreviousOutput | x @ Action::SendToPreviousOutput => {
|
||||||
let current_output = seat.active_output();
|
let current_output = seat.active_output();
|
||||||
if let Some(prev_output) = self
|
let prev_output = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
.outputs
|
.outputs()
|
||||||
.iter()
|
|
||||||
.rev()
|
.rev()
|
||||||
.skip_while(|o| *o != ¤t_output)
|
.skip_while(|o| *o != ¤t_output)
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.next()
|
.next()
|
||||||
.cloned()
|
.cloned();
|
||||||
{
|
if let Some(prev_output) = prev_output {
|
||||||
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
if let Ok(Some(new_pos)) = Shell::move_current_window(
|
||||||
self,
|
self,
|
||||||
seat,
|
seat,
|
||||||
|
|
|
||||||
|
|
@ -492,7 +492,7 @@ impl CosmicMapped {
|
||||||
|
|
||||||
pub fn convert_to_stack<'a>(
|
pub fn convert_to_stack<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
outputs: impl Iterator<Item = (&'a Output, Rectangle<i32, Logical>)>,
|
(output, overlap): (&'a Output, Rectangle<i32, Logical>),
|
||||||
) {
|
) {
|
||||||
match &self.element {
|
match &self.element {
|
||||||
CosmicMappedInternal::Window(window) => {
|
CosmicMappedInternal::Window(window) => {
|
||||||
|
|
@ -518,7 +518,7 @@ impl CosmicMapped {
|
||||||
pub fn convert_to_surface<'a>(
|
pub fn convert_to_surface<'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
surface: CosmicSurface,
|
surface: CosmicSurface,
|
||||||
outputs: impl Iterator<Item = (&'a Output, Rectangle<i32, Logical>)>,
|
(output, overlap): (&'a Output, Rectangle<i32, Logical>),
|
||||||
) {
|
) {
|
||||||
let handle = self.loop_handle();
|
let handle = self.loop_handle();
|
||||||
surface.try_force_undecorated(false);
|
surface.try_force_undecorated(false);
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ impl Shell {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(self.outputs.iter().flat_map(|o| {
|
Some(self.outputs().flat_map(|o| {
|
||||||
let space = self.active_space(o);
|
let space = self.active_space(o);
|
||||||
let stack = space.focus_stack.get(seat);
|
let stack = space.focus_stack.get(seat);
|
||||||
stack.last().cloned()
|
stack.last().cloned()
|
||||||
|
|
@ -163,8 +163,9 @@ impl Shell {
|
||||||
.flatten()
|
.flatten()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for output in self.outputs.iter() {
|
for output in self.outputs().cloned().collect::<Vec<_>>().into_iter() {
|
||||||
let workspace = self.workspaces.active_mut(output);
|
// TODO: Add self.workspaces.active_workspaces()
|
||||||
|
let workspace = self.workspaces.active_mut(&output);
|
||||||
for focused in focused_windows.iter() {
|
for focused in focused_windows.iter() {
|
||||||
if let CosmicSurface::X11(window) = focused.active_window() {
|
if let CosmicSurface::X11(window) = focused.active_window() {
|
||||||
if let Some(xwm) = xwm.as_mut().and_then(|state| state.xwm.as_mut()) {
|
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<_>>();
|
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
||||||
for seat in seats {
|
for seat in seats {
|
||||||
let output = seat.active_output();
|
let output = seat.active_output();
|
||||||
if !state.common.shell.outputs.contains(&output) {
|
if !state.common.shell.outputs().any(|o| o == &output) {
|
||||||
seat.set_active_output(&state.common.shell.outputs[0]);
|
seat.set_active_output(&state.common.shell.outputs().next().unwrap());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let last_known_focus = ActiveFocus::get(&seat);
|
let last_known_focus = ActiveFocus::get(&seat);
|
||||||
|
|
@ -248,11 +249,16 @@ impl Common {
|
||||||
continue; // Focus is valid
|
continue; // Focus is valid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyboardFocusTarget::Group(WindowGroup {
|
KeyboardFocusTarget::Group(WindowGroup { node, .. }) => {
|
||||||
output: weak_output,
|
if state
|
||||||
..
|
.common
|
||||||
}) => {
|
.shell
|
||||||
if weak_output == output {
|
.workspaces
|
||||||
|
.active(&output)
|
||||||
|
.1
|
||||||
|
.tiling_layer
|
||||||
|
.has_node(&node)
|
||||||
|
{
|
||||||
continue; // Focus is valid,
|
continue; // Focus is valid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,16 +87,13 @@ impl KeyboardFocusTarget {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct WindowGroup {
|
pub struct WindowGroup {
|
||||||
pub node: NodeId,
|
pub node: NodeId,
|
||||||
pub output: WeakOutput,
|
|
||||||
pub alive: Weak<()>,
|
pub alive: Weak<()>,
|
||||||
pub focus_stack: Vec<NodeId>,
|
pub focus_stack: Vec<NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for WindowGroup {
|
impl PartialEq for WindowGroup {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.node == other.node
|
self.node == other.node && Weak::ptr_eq(&self.alive, &other.alive)
|
||||||
&& self.output == other.output
|
|
||||||
&& Weak::ptr_eq(&self.alive, &other.alive)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ impl PointerGrab<State> for MoveGrab {
|
||||||
.workspaces
|
.workspaces
|
||||||
.active_mut(&self.cursor_output)
|
.active_mut(&self.cursor_output)
|
||||||
.tiling_layer
|
.tiling_layer
|
||||||
.cleanup_drag(&self.cursor_output);
|
.cleanup_drag();
|
||||||
self.cursor_output = current_output.clone();
|
self.cursor_output = current_output.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ use smithay::{
|
||||||
utils::{Logical, Point, Rectangle, Size},
|
utils::{Logical, Point, Rectangle, Size},
|
||||||
wayland::seat::WaylandFocus,
|
wayland::seat::WaylandFocus,
|
||||||
};
|
};
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::render::{element::AsGlowRenderer, IndicatorShader, Key, Usage},
|
backend::render::{element::AsGlowRenderer, IndicatorShader, Key, Usage},
|
||||||
|
|
@ -28,9 +27,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
state::State,
|
state::State,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::{
|
wayland::handlers::xdg_shell::popup::get_popup_toplevel,
|
||||||
handlers::xdg_shell::popup::get_popup_toplevel, protocols::toplevel_info::ToplevelInfoState,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod grabs;
|
mod grabs;
|
||||||
|
|
@ -42,67 +39,53 @@ pub struct FloatingLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatingLayout {
|
impl FloatingLayout {
|
||||||
pub fn new() -> FloatingLayout {
|
pub fn new(output: &Output) -> FloatingLayout {
|
||||||
Default::default()
|
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>) {
|
pub fn set_output(&mut self, output: &Output) {
|
||||||
self.space.map_output(output, location)
|
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();
|
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(
|
pub fn map(
|
||||||
&mut self,
|
&mut self,
|
||||||
mapped: impl Into<CosmicMapped>,
|
mapped: impl Into<CosmicMapped>,
|
||||||
seat: &Seat<State>,
|
position: impl Into<Option<Point<i32, Local>>>,
|
||||||
position: impl Into<Option<Point<i32, Logical>>>,
|
|
||||||
) {
|
) {
|
||||||
let mapped = mapped.into();
|
let mapped = mapped.into();
|
||||||
let output = seat.active_output();
|
|
||||||
let position = position.into();
|
let position = position.into();
|
||||||
|
|
||||||
self.map_internal(mapped, &output, position)
|
self.map_internal(mapped, position, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(in crate::shell) fn map_internal(
|
pub(in crate::shell) fn map_internal(
|
||||||
&mut self,
|
&mut self,
|
||||||
mapped: CosmicMapped,
|
mapped: CosmicMapped,
|
||||||
output: &Output,
|
position: Option<Point<i32, Local>>,
|
||||||
position: Option<Point<i32, Logical>>,
|
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 layers = layer_map_for_output(&output);
|
||||||
let geometry = layers.non_exclusive_zone();
|
let geometry = layers.non_exclusive_zone();
|
||||||
mapped.set_bounds(geometry.size);
|
mapped.set_bounds(geometry.size);
|
||||||
let last_geometry = mapped.last_geometry.lock().unwrap().clone();
|
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;
|
win_geo.size = size;
|
||||||
} else {
|
} else {
|
||||||
let (min_size, max_size) = (
|
let (min_size, max_size) = (
|
||||||
|
|
@ -150,18 +133,10 @@ impl FloatingLayout {
|
||||||
});
|
});
|
||||||
|
|
||||||
mapped.set_tiled(false);
|
mapped.set_tiled(false);
|
||||||
let offset = output.geometry().loc
|
mapped
|
||||||
- self
|
.set_geometry(Rectangle::from_loc_and_size(position, win_geo.size).to_global(&output));
|
||||||
.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.configure();
|
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 {
|
pub fn unmap(&mut self, window: &CosmicMapped) -> bool {
|
||||||
|
|
@ -170,10 +145,8 @@ impl FloatingLayout {
|
||||||
|
|
||||||
if !is_maximized {
|
if !is_maximized {
|
||||||
if let Some(location) = self.space.element_location(window) {
|
if let Some(location) = self.space.element_location(window) {
|
||||||
*window.last_geometry.lock().unwrap() = Some(Rectangle::from_loc_and_size(
|
*window.last_geometry.lock().unwrap() =
|
||||||
location,
|
Some(Rectangle::from_loc_and_size(location, window.geometry().size).as_local());
|
||||||
window.geometry().size,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -182,8 +155,8 @@ impl FloatingLayout {
|
||||||
was_unmaped
|
was_unmaped
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Logical>> {
|
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Local>> {
|
||||||
self.space.element_geometry(elem)
|
self.space.element_geometry(elem).map(RectExt::as_local)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maximize_request(&mut self, window: &CosmicSurface) {
|
pub fn maximize_request(&mut self, window: &CosmicSurface) {
|
||||||
|
|
@ -339,13 +312,10 @@ impl FloatingLayout {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
mapped.set_resizing(true);
|
mapped.set_resizing(true);
|
||||||
mapped.set_geometry(Rectangle::from_loc_and_size(
|
mapped.set_geometry(
|
||||||
match mapped.active_window() {
|
geo.as_local()
|
||||||
CosmicSurface::X11(s) => s.geometry().loc,
|
.to_global(self.space.outputs().next().unwrap()),
|
||||||
_ => (0, 0).into(),
|
);
|
||||||
},
|
|
||||||
geo.size,
|
|
||||||
));
|
|
||||||
mapped.configure();
|
mapped.configure();
|
||||||
|
|
||||||
true
|
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)
|
// 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;
|
*element.last_geometry.lock().unwrap() = None;
|
||||||
let output = self.space.outputs().next().unwrap().clone();
|
self.map_internal(element, None, None);
|
||||||
self.map_internal(element, &output, 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) {
|
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() {
|
for element in other.space.elements() {
|
||||||
let mut elem_geo = other.space.element_geometry(element).unwrap();
|
let elem_loc = other
|
||||||
let output = other
|
|
||||||
.space
|
.space
|
||||||
.outputs_for_element(element)
|
.element_geometry(element)
|
||||||
.into_iter()
|
.unwrap()
|
||||||
.filter(|o| self.space.outputs().any(|o2| o == o2))
|
.loc
|
||||||
.max_by_key(|o| {
|
.as_local();
|
||||||
let output_geo = other.space.output_geometry(o).unwrap();
|
self.map_internal(element.clone(), Some(elem_loc), None);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
self.refresh(); //fixup any out of bounds elements
|
self.refresh(); //fixup any out of bounds elements
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_output<R>(
|
pub fn render<R>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
output: &Output,
|
|
||||||
focused: Option<&CosmicMapped>,
|
focused: Option<&CosmicMapped>,
|
||||||
mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
|
mut resize_indicator: Option<(ResizeMode, ResizeIndicator)>,
|
||||||
indicator_thickness: u8,
|
indicator_thickness: u8,
|
||||||
|
|
@ -598,68 +511,65 @@ impl FloatingLayout {
|
||||||
#[cfg(feature = "debug")]
|
#[cfg(feature = "debug")]
|
||||||
puffin::profile_function!();
|
puffin::profile_function!();
|
||||||
|
|
||||||
|
let output = self.space.outputs().next().unwrap();
|
||||||
let output_scale = output.current_scale().fractional_scale();
|
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 window_elements = Vec::new();
|
||||||
let mut popup_elements = Vec::new();
|
let mut popup_elements = Vec::new();
|
||||||
|
|
||||||
self.space
|
self.space.elements().rev().for_each(|elem| {
|
||||||
.elements_for_output(output)
|
let render_location = self.space.element_location(elem).unwrap() - elem.geometry().loc;
|
||||||
.rev()
|
let (w_elements, p_elements) = elem.split_render_elements(
|
||||||
.for_each(|elem| {
|
renderer,
|
||||||
let render_location = self.space.element_location(elem).unwrap()
|
render_location.to_physical_precise_round(output_scale),
|
||||||
- output_geo.loc
|
output_scale.into(),
|
||||||
- elem.geometry().loc;
|
alpha,
|
||||||
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) {
|
if focused == Some(elem) {
|
||||||
let mut indicator_geometry = Rectangle::from_loc_and_size(
|
let mut indicator_geometry = Rectangle::from_loc_and_size(
|
||||||
self.space.element_location(elem).unwrap() - output_geo.loc,
|
self.space.element_location(elem).unwrap(),
|
||||||
elem.geometry().size,
|
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);
|
if indicator_thickness > 0 {
|
||||||
popup_elements.extend(p_elements);
|
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)
|
(window_elements, popup_elements)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,67 +137,64 @@ 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(queue) = tiling_layer.queues.get_mut(&output) {
|
let tree = &mut tiling_layer.queue.trees.back_mut().unwrap().0;
|
||||||
let tree = &mut queue.trees.back_mut().unwrap().0;
|
if tree.get(&self.node).is_ok() {
|
||||||
if tree.get(&self.node).is_ok() {
|
let delta = match self.orientation {
|
||||||
let delta = match self.orientation {
|
Orientation::Vertical => delta.x,
|
||||||
Orientation::Vertical => delta.x,
|
Orientation::Horizontal => delta.y,
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,7 @@ impl KeyboardGrab<State> for SwapWindowGrab {
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
time: u32,
|
time: u32,
|
||||||
) {
|
) {
|
||||||
if self.desc.output.upgrade().is_none()
|
if !matches!(&data.common.shell.overview_mode, OverviewMode::Started(Trigger::KeyboardSwap(_, d), _) if d == &self.desc)
|
||||||
|| !matches!(&data.common.shell.overview_mode, OverviewMode::Started(Trigger::KeyboardSwap(_, d), _) if d == &self.desc)
|
|
||||||
{
|
{
|
||||||
handle.unset_grab(data, serial, false);
|
handle.unset_grab(data, serial, false);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
747
src/shell/mod.rs
747
src/shell/mod.rs
File diff suppressed because it is too large
Load diff
|
|
@ -76,6 +76,7 @@ const FULLSCREEN_ANIMATION_DURATION: Duration = Duration::from_millis(200);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Workspace {
|
pub struct Workspace {
|
||||||
|
pub output: Output,
|
||||||
pub tiling_layer: TilingLayout,
|
pub tiling_layer: TilingLayout,
|
||||||
pub floating_layer: FloatingLayout,
|
pub floating_layer: FloatingLayout,
|
||||||
pub tiling_enabled: bool,
|
pub tiling_enabled: bool,
|
||||||
|
|
@ -84,6 +85,7 @@ pub struct Workspace {
|
||||||
pub focus_stack: FocusStacks,
|
pub focus_stack: FocusStacks,
|
||||||
pub pending_buffers: Vec<(ScreencopySession, BufferParams)>,
|
pub pending_buffers: Vec<(ScreencopySession, BufferParams)>,
|
||||||
pub screencopy_sessions: Vec<DropableSession>,
|
pub screencopy_sessions: Vec<DropableSession>,
|
||||||
|
pub output_stack: VecDeque<String>,
|
||||||
pub(super) backdrop_id: Id,
|
pub(super) backdrop_id: Id,
|
||||||
pub dirty: AtomicBool,
|
pub dirty: AtomicBool,
|
||||||
}
|
}
|
||||||
|
|
@ -198,16 +200,26 @@ impl MoveResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Workspace {
|
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 {
|
Workspace {
|
||||||
tiling_layer: TilingLayout::new(gaps),
|
output,
|
||||||
floating_layer: FloatingLayout::new(),
|
tiling_layer,
|
||||||
|
floating_layer,
|
||||||
tiling_enabled,
|
tiling_enabled,
|
||||||
fullscreen: HashMap::new(),
|
fullscreen: HashMap::new(),
|
||||||
handle,
|
handle,
|
||||||
focus_stack: FocusStacks::default(),
|
focus_stack: FocusStacks::default(),
|
||||||
pending_buffers: Vec::new(),
|
pending_buffers: Vec::new(),
|
||||||
screencopy_sessions: Vec::new(),
|
screencopy_sessions: Vec::new(),
|
||||||
|
output_stack: VecDeque::new(),
|
||||||
backdrop_id: Id::new(),
|
backdrop_id: Id::new(),
|
||||||
dirty: AtomicBool::new(false),
|
dirty: AtomicBool::new(false),
|
||||||
}
|
}
|
||||||
|
|
@ -299,27 +311,29 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_output(&mut self, output: &Output, position: Point<i32, Logical>) {
|
pub fn output(&self) -> &Output {
|
||||||
self.tiling_layer.map_output(output, position);
|
&self.output
|
||||||
self.floating_layer.map_output(output, position);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmap_output(
|
pub fn set_output(
|
||||||
&mut self,
|
&mut self,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
|
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
|
||||||
) {
|
) {
|
||||||
if let Some(dead_output_fullscreen) = self.fullscreen.remove(output) {
|
self.tiling_layer.set_output(output);
|
||||||
self.unfullscreen_request(&dead_output_fullscreen.window.surface());
|
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.output = output.clone();
|
||||||
self.floating_layer.unmap_output(output, toplevel_info);
|
|
||||||
self.refresh();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmap(&mut self, mapped: &CosmicMapped) -> Option<ManagedState> {
|
pub fn unmap(&mut self, mapped: &CosmicMapped) -> Option<ManagedState> {
|
||||||
let was_floating = self.floating_layer.unmap(&mapped);
|
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 {
|
if was_floating || was_tiling {
|
||||||
assert!(was_floating != was_tiling);
|
assert!(was_floating != was_tiling);
|
||||||
}
|
}
|
||||||
|
|
@ -363,67 +377,32 @@ impl Workspace {
|
||||||
.find(|e| {
|
.find(|e| {
|
||||||
e.windows()
|
e.windows()
|
||||||
.any(|(w, _)| w.wl_surface().as_ref() == Some(surface))
|
.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(
|
pub fn element_under(
|
||||||
&mut self,
|
&mut self,
|
||||||
location: Point<f64, Logical>,
|
location: Point<f64, Global>,
|
||||||
overview: OverviewMode,
|
overview: OverviewMode,
|
||||||
) -> Option<(PointerFocusTarget, Point<i32, Logical>)> {
|
) -> Option<(PointerFocusTarget, Point<i32, Global>)> {
|
||||||
|
let location = location.to_local(&self.output);
|
||||||
self.floating_layer
|
self.floating_layer
|
||||||
.space
|
.space
|
||||||
.element_under(location)
|
.element_under(location.as_logical())
|
||||||
.map(|(mapped, p)| (mapped.clone().into(), p))
|
.map(|(mapped, p)| (mapped.clone().into(), p.as_local()))
|
||||||
.or_else(|| self.tiling_layer.element_under(location, overview))
|
.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>> {
|
pub fn element_geometry(&self, elem: &CosmicMapped) -> Option<Rectangle<i32, Local>> {
|
||||||
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()
|
|
||||||
};
|
|
||||||
|
|
||||||
self.floating_layer
|
self.floating_layer
|
||||||
.space
|
|
||||||
.element_geometry(elem)
|
.element_geometry(elem)
|
||||||
.or_else(|| self.tiling_layer.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) {
|
pub fn recalculate(&mut self) {
|
||||||
if let Some(f) = self.fullscreen.get(output) {
|
self.tiling_layer.recalculate();
|
||||||
if !f.exclusive {
|
self.floating_layer.refresh();
|
||||||
f.window
|
|
||||||
.set_geometry(layer_map_for_output(output).non_exclusive_zone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.tiling_layer.recalculate(output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn maximize_request(
|
pub fn maximize_request(
|
||||||
|
|
@ -574,7 +553,7 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
Some(f.original_geometry.size.as_logical())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -730,7 +709,7 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
|
|
||||||
let was_floating = self.floating_layer.unmap(&mapped);
|
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());
|
assert!(was_floating != was_tiled.is_some());
|
||||||
|
|
||||||
Some(MoveGrab::new(
|
Some(MoveGrab::new(
|
||||||
|
|
@ -754,7 +733,7 @@ impl Workspace {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
{
|
{
|
||||||
self.tiling_layer.unmap(&window);
|
self.tiling_layer.unmap(&window);
|
||||||
self.floating_layer.map(window, seat, None);
|
self.floating_layer.map(window, None);
|
||||||
}
|
}
|
||||||
self.tiling_enabled = false;
|
self.tiling_enabled = false;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -767,8 +746,7 @@ impl Workspace {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
{
|
{
|
||||||
self.floating_layer.unmap(&window);
|
self.floating_layer.unmap(&window);
|
||||||
self.tiling_layer
|
self.tiling_layer.map(window, focus_stack.iter(), None)
|
||||||
.map(window, seat, focus_stack.iter(), None)
|
|
||||||
}
|
}
|
||||||
self.tiling_enabled = true;
|
self.tiling_enabled = true;
|
||||||
}
|
}
|
||||||
|
|
@ -779,12 +757,11 @@ impl Workspace {
|
||||||
if let Some(window) = self.focus_stack.get(seat).iter().next().cloned() {
|
if let Some(window) = self.focus_stack.get(seat).iter().next().cloned() {
|
||||||
if self.tiling_layer.mapped().any(|(_, m, _)| m == &window) {
|
if self.tiling_layer.mapped().any(|(_, m, _)| m == &window) {
|
||||||
self.tiling_layer.unmap(&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) {
|
} else if self.floating_layer.mapped().any(|w| w == &window) {
|
||||||
let focus_stack = self.focus_stack.get(seat);
|
let focus_stack = self.focus_stack.get(seat);
|
||||||
self.floating_layer.unmap(&window);
|
self.floating_layer.unmap(&window);
|
||||||
self.tiling_layer
|
self.tiling_layer.map(window, focus_stack.iter(), None)
|
||||||
.map(window, seat, focus_stack.iter(), None)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -837,8 +814,8 @@ impl Workspace {
|
||||||
pub fn node_desc(&self, focus: KeyboardFocusTarget) -> Option<NodeDesc> {
|
pub fn node_desc(&self, focus: KeyboardFocusTarget) -> Option<NodeDesc> {
|
||||||
match focus {
|
match focus {
|
||||||
KeyboardFocusTarget::Element(mapped) => {
|
KeyboardFocusTarget::Element(mapped) => {
|
||||||
self.tiling_layer.mapped().find_map(|(output, m, _)| {
|
self.tiling_layer.mapped().find_map(|(_, m, _)| {
|
||||||
(m == &mapped).then_some(output.clone()).and_then(|output| {
|
if m == &mapped {
|
||||||
mapped
|
mapped
|
||||||
.tiling_node_id
|
.tiling_node_id
|
||||||
.lock()
|
.lock()
|
||||||
|
|
@ -846,7 +823,6 @@ impl Workspace {
|
||||||
.clone()
|
.clone()
|
||||||
.map(|node_id| NodeDesc {
|
.map(|node_id| NodeDesc {
|
||||||
handle: self.handle.clone(),
|
handle: self.handle.clone(),
|
||||||
output: output.downgrade(),
|
|
||||||
node: node_id,
|
node: node_id,
|
||||||
stack_window: if mapped
|
stack_window: if mapped
|
||||||
.stack_ref()
|
.stack_ref()
|
||||||
|
|
@ -858,12 +834,13 @@ impl Workspace {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
KeyboardFocusTarget::Group(WindowGroup { output, node, .. }) => Some(NodeDesc {
|
KeyboardFocusTarget::Group(WindowGroup { node, .. }) => Some(NodeDesc {
|
||||||
handle: self.handle.clone(),
|
handle: self.handle.clone(),
|
||||||
output,
|
|
||||||
node,
|
node,
|
||||||
stack_window: None,
|
stack_window: None,
|
||||||
}),
|
}),
|
||||||
|
|
@ -904,10 +881,9 @@ impl Workspace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_output<'a, R>(
|
pub fn render<'a, R>(
|
||||||
&self,
|
&self,
|
||||||
renderer: &mut R,
|
renderer: &mut R,
|
||||||
output: &Output,
|
|
||||||
override_redirect_windows: &[X11Surface],
|
override_redirect_windows: &[X11Surface],
|
||||||
xwm_state: Option<&'a mut XWaylandState>,
|
xwm_state: Option<&'a mut XWaylandState>,
|
||||||
draw_focus_indicator: Option<&Seat<State>>,
|
draw_focus_indicator: Option<&Seat<State>>,
|
||||||
|
|
@ -1089,9 +1065,8 @@ impl Workspace {
|
||||||
OverviewMode::None => 1.0,
|
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,
|
renderer,
|
||||||
output,
|
|
||||||
focused.as_ref(),
|
focused.as_ref(),
|
||||||
resize_indicator.clone(),
|
resize_indicator.clone(),
|
||||||
indicator_thickness,
|
indicator_thickness,
|
||||||
|
|
@ -1113,11 +1088,10 @@ impl Workspace {
|
||||||
};
|
};
|
||||||
|
|
||||||
//tiling surfaces
|
//tiling surfaces
|
||||||
let (w_elements, p_elements) = self.tiling_layer.render_output::<R>(
|
let (w_elements, p_elements) = self.tiling_layer.render::<R>(
|
||||||
renderer,
|
renderer,
|
||||||
output,
|
|
||||||
draw_focus_indicator,
|
draw_focus_indicator,
|
||||||
layer_map.non_exclusive_zone(),
|
zone,
|
||||||
overview,
|
overview,
|
||||||
resize_indicator,
|
resize_indicator,
|
||||||
indicator_thickness,
|
indicator_thickness,
|
||||||
|
|
|
||||||
76
src/state.rs
76
src/state.rs
|
|
@ -511,50 +511,34 @@ impl Common {
|
||||||
|
|
||||||
let active = self.shell.active_space(output);
|
let active = self.shell.active_space(output);
|
||||||
active.mapped().for_each(|mapped| {
|
active.mapped().for_each(|mapped| {
|
||||||
let outputs_for_element: Vec<_> = active.outputs_for_element(mapped).collect();
|
let window = mapped.active_window();
|
||||||
if outputs_for_element.contains(&output) {
|
window.with_surfaces(|surface, states| {
|
||||||
let window = mapped.active_window();
|
let primary_scanout_output = update_surface_primary_scanout_output(
|
||||||
window.with_surfaces(|surface, states| {
|
surface,
|
||||||
let primary_scanout_output = update_surface_primary_scanout_output(
|
output,
|
||||||
surface,
|
states,
|
||||||
output,
|
render_element_states,
|
||||||
states,
|
|_current_output, _current_state, next_output, _next_state| next_output,
|
||||||
render_element_states,
|
);
|
||||||
|current_output, current_state, next_output, next_state| {
|
if let Some(output) = primary_scanout_output {
|
||||||
if outputs_for_element.contains(current_output) {
|
with_fractional_scale(states, |fraction_scale| {
|
||||||
default_primary_scanout_output_compare(
|
fraction_scale
|
||||||
current_output,
|
.set_preferred_scale(output.current_scale().fractional_scale());
|
||||||
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,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
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)
|
.filter(|w| w.handle != active.handle)
|
||||||
{
|
{
|
||||||
space.mapped().for_each(|mapped| {
|
space.mapped().for_each(|mapped| {
|
||||||
if space.outputs_for_element(mapped).any(|o| &o == output) {
|
let window = mapped.active_window();
|
||||||
let window = mapped.active_window();
|
window.send_frame(space.output(), time, throttle, |_, _| None);
|
||||||
window.send_frame(output, time, throttle, |_, _| None);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ impl CompositorHandler for State {
|
||||||
let changed = layer_map_for_output(&output).arrange();
|
let changed = layer_map_for_output(&output).arrange();
|
||||||
if changed {
|
if changed {
|
||||||
for workspace in self.common.shell.workspaces.spaces_mut() {
|
for workspace in self.common.shell.workspaces.spaces_mut() {
|
||||||
workspace.recalculate(&output);
|
workspace.recalculate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,8 +41,7 @@ impl WlrLayerShellHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_popup(&mut self, _parent: WlrLayerSurface, popup: PopupSurface) {
|
fn new_popup(&mut self, _parent: WlrLayerSurface, popup: PopupSurface) {
|
||||||
let positioner = popup.with_pending_state(|state| state.positioner);
|
self.common.shell.unconstrain_popup(&popup);
|
||||||
self.common.shell.unconstrain_popup(&popup, &positioner);
|
|
||||||
|
|
||||||
if popup.send_configure().is_ok() {
|
if popup.send_configure().is_ok() {
|
||||||
self.common
|
self.common
|
||||||
|
|
@ -76,7 +75,7 @@ impl WlrLayerShellHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
for workspace in self.common.shell.workspaces.spaces_mut() {
|
for workspace in self.common.shell.workspaces.spaces_mut() {
|
||||||
workspace.recalculate(&output);
|
workspace.recalculate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// collect screencopy sessions needing an update
|
// collect screencopy sessions needing an update
|
||||||
|
|
|
||||||
|
|
@ -1296,7 +1296,7 @@ pub fn schedule_offscreen_workspace_session(
|
||||||
if !session.alive() {
|
if !session.alive() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if !state.common.shell.outputs.contains(&output) {
|
if !state.common.shell.outputs().any(|o| o == &output) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
match render_workspace_to_buffer(
|
match render_workspace_to_buffer(
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
shell::WorkspaceMode,
|
|
||||||
state::ClientState,
|
state::ClientState,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::protocols::workspace::{
|
wayland::protocols::workspace::{
|
||||||
|
|
@ -30,19 +29,12 @@ impl WorkspaceHandler for State {
|
||||||
for request in requests.into_iter() {
|
for request in requests.into_iter() {
|
||||||
match request {
|
match request {
|
||||||
Request::Activate(handle) => {
|
Request::Activate(handle) => {
|
||||||
let maybe = match &self.common.shell.workspaces {
|
let maybe = self.common.shell.workspaces.iter().find_map(|(o, set)| {
|
||||||
WorkspaceMode::Global(set) => set
|
set.workspaces
|
||||||
.workspaces
|
|
||||||
.iter()
|
.iter()
|
||||||
.position(|w| w.handle == handle)
|
.position(|w| w.handle == handle)
|
||||||
.map(|i| (self.common.last_active_seat().active_output(), i)),
|
.map(|i| (o.clone(), i))
|
||||||
WorkspaceMode::OutputBound(sets, _) => sets.iter().find_map(|(o, set)| {
|
});
|
||||||
set.workspaces
|
|
||||||
.iter()
|
|
||||||
.position(|w| w.handle == handle)
|
|
||||||
.map(|i| (o.clone(), i))
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some((output, idx)) = maybe {
|
if let Some((output, idx)) = maybe {
|
||||||
let _ = self.common.shell.activate(&output, idx); // TODO: move cursor?
|
let _ = self.common.shell.activate(&output, idx); // TODO: move cursor?
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ impl XdgShellHandler for State {
|
||||||
|
|
||||||
if surface.get_parent_surface().is_some() {
|
if surface.get_parent_surface().is_some() {
|
||||||
// let other shells deal with their popups
|
// 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() {
|
if surface.send_configure().is_ok() {
|
||||||
self.common
|
self.common
|
||||||
|
|
@ -123,7 +123,7 @@ impl XdgShellHandler for State {
|
||||||
state.positioner = positioner;
|
state.positioner = positioner;
|
||||||
});
|
});
|
||||||
|
|
||||||
self.common.shell.unconstrain_popup(&surface, &positioner);
|
self.common.shell.unconstrain_popup(&surface);
|
||||||
surface.send_repositioned(token);
|
surface.send_repositioned(token);
|
||||||
if let Err(err) = surface.send_configure() {
|
if let Err(err) = surface.send_configure() {
|
||||||
warn!(
|
warn!(
|
||||||
|
|
@ -150,9 +150,6 @@ impl XdgShellHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
fn maximize_request(&mut self, surface: ToplevelSurface) {
|
||||||
let seat = self.common.last_active_seat();
|
|
||||||
let output = seat.active_output();
|
|
||||||
|
|
||||||
if let Some(mapped) = self
|
if let Some(mapped) = self
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
|
|
@ -164,7 +161,7 @@ impl XdgShellHandler for State {
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
||||||
.unwrap();
|
.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();
|
let seat = self.common.last_active_seat();
|
||||||
seat.active_output()
|
seat.active_output()
|
||||||
});
|
});
|
||||||
|
// TODO: If this is not the output? Do we move it?
|
||||||
|
|
||||||
if let Some(mapped) = self
|
if let Some(mapped) = self
|
||||||
.common
|
.common
|
||||||
|
|
@ -206,11 +204,7 @@ impl XdgShellHandler for State {
|
||||||
.windows()
|
.windows()
|
||||||
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface.wl_surface()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
workspace.fullscreen_request(
|
workspace.fullscreen_request(&window)
|
||||||
&window,
|
|
||||||
&output,
|
|
||||||
self.common.event_loop_handle.clone(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -363,14 +363,11 @@ impl XwmHandler for State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
|
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);
|
let surface = CosmicSurface::X11(window);
|
||||||
|
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(&surface).cloned() {
|
if let Some(mapped) = self.common.shell.element_for_surface(&surface).cloned() {
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
let (window, _) = mapped.windows().find(|(w, _)| w == &surface).unwrap();
|
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) {
|
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);
|
let surface = CosmicSurface::X11(window);
|
||||||
|
|
||||||
if let Some(mapped) = self.common.shell.element_for_surface(&surface).cloned() {
|
if let Some(mapped) = self.common.shell.element_for_surface(&surface).cloned() {
|
||||||
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
if let Some(workspace) = self.common.shell.space_for_mut(&mapped) {
|
||||||
let (window, _) = mapped.windows().find(|(w, _)| w == &surface).unwrap();
|
workspace.fullscreen_request(&surface)
|
||||||
workspace.fullscreen_request(
|
|
||||||
&window,
|
|
||||||
&output,
|
|
||||||
self.common.event_loop_handle.clone(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue