menu: Allow toggling sticky state

This commit is contained in:
Victoria Brekenfeld 2023-12-20 20:19:42 +00:00 committed by Victoria Brekenfeld
parent e0d207fbe1
commit d2e394b957
7 changed files with 187 additions and 24 deletions

View file

@ -14,8 +14,7 @@ window-menu-move-next-workspace = Move to next workspace
window-menu-stack = Create window stack window-menu-stack = Create window stack
window-menu-unstack-all = Unstack windows window-menu-unstack-all = Unstack windows
window-menu-unstack = Unstack window window-menu-unstack = Unstack window
window-menu-always-on-top = Always on top window-menu-sticky = Sticky window
window-menu-always-on-visible-ws = Always on visible workspace
window-menu-close = Close window-menu-close = Close
window-menu-close-all = Close all windows window-menu-close-all = Close all windows
window-menu-resize-edge-top = Top window-menu-resize-edge-top = Top

View file

@ -108,6 +108,8 @@ pub struct CosmicMapped {
pub last_geometry: Arc<Mutex<Option<Rectangle<i32, Local>>>>, pub last_geometry: Arc<Mutex<Option<Rectangle<i32, Local>>>>,
pub moved_since_mapped: Arc<AtomicBool>, pub moved_since_mapped: Arc<AtomicBool>,
pub floating_tiled: Arc<Mutex<Option<TiledCorners>>>, pub floating_tiled: Arc<Mutex<Option<TiledCorners>>>,
//sticky
pub previous_layer: Arc<Mutex<Option<ManagedLayer>>>,
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug: Arc<Mutex<Option<smithay_egui::EguiState>>>, debug: Arc<Mutex<Option<smithay_egui::EguiState>>>,
@ -1118,6 +1120,7 @@ impl From<CosmicWindow> for CosmicMapped {
last_geometry: Arc::new(Mutex::new(None)), last_geometry: Arc::new(Mutex::new(None)),
moved_since_mapped: Arc::new(AtomicBool::new(false)), moved_since_mapped: Arc::new(AtomicBool::new(false)),
floating_tiled: Arc::new(Mutex::new(None)), floating_tiled: Arc::new(Mutex::new(None)),
previous_layer: Arc::new(Mutex::new(None)),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug: Arc::new(Mutex::new(None)), debug: Arc::new(Mutex::new(None)),
} }
@ -1135,6 +1138,7 @@ impl From<CosmicStack> for CosmicMapped {
last_geometry: Arc::new(Mutex::new(None)), last_geometry: Arc::new(Mutex::new(None)),
moved_since_mapped: Arc::new(AtomicBool::new(false)), moved_since_mapped: Arc::new(AtomicBool::new(false)),
floating_tiled: Arc::new(Mutex::new(None)), floating_tiled: Arc::new(Mutex::new(None)),
previous_layer: Arc::new(Mutex::new(None)),
#[cfg(feature = "debug")] #[cfg(feature = "debug")]
debug: Arc::new(Mutex::new(None)), debug: Arc::new(Mutex::new(None)),
} }

View file

@ -692,12 +692,27 @@ impl Program for CosmicStackInternal {
if let Some(mapped) = if let Some(mapped) =
state.common.shell.element_for_wl_surface(&surface).cloned() state.common.shell.element_for_wl_surface(&surface).cloned()
{ {
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) { let position = if let Some((output, set)) =
let position = workspace state.common.shell.workspaces.sets.iter().find(|(_, set)| {
set.sticky_layer.mapped().any(|m| m == &mapped)
}) {
set.sticky_layer
.element_geometry(&mapped) .element_geometry(&mapped)
.unwrap() .unwrap()
.loc .loc
.to_global(&workspace.output); .to_global(output)
} else if let Some(workspace) =
state.common.shell.space_for_mut(&mapped)
{
workspace
.element_geometry(&mapped)
.unwrap()
.loc
.to_global(&workspace.output)
} else {
return;
};
let mut cursor = seat let mut cursor = seat
.get_pointer() .get_pointer()
.unwrap() .unwrap()
@ -712,7 +727,6 @@ impl Program for CosmicStackInternal {
cursor - position.as_logical(), cursor - position.as_logical(),
true, true,
); );
}
} }
}); });
} }

View file

@ -292,12 +292,27 @@ impl Program for CosmicWindowInternal {
if let Some(mapped) = if let Some(mapped) =
state.common.shell.element_for_wl_surface(&surface).cloned() state.common.shell.element_for_wl_surface(&surface).cloned()
{ {
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) { let position = if let Some((output, set)) =
let position = workspace state.common.shell.workspaces.sets.iter().find(|(_, set)| {
set.sticky_layer.mapped().any(|m| m == &mapped)
}) {
set.sticky_layer
.element_geometry(&mapped) .element_geometry(&mapped)
.unwrap() .unwrap()
.loc .loc
.to_global(&workspace.output); .to_global(output)
} else if let Some(workspace) =
state.common.shell.space_for_mut(&mapped)
{
workspace
.element_geometry(&mapped)
.unwrap()
.loc
.to_global(&workspace.output)
} else {
return;
};
let mut cursor = seat let mut cursor = seat
.get_pointer() .get_pointer()
.unwrap() .unwrap()
@ -312,7 +327,6 @@ impl Program for CosmicWindowInternal {
cursor - position.as_logical(), cursor - position.as_logical(),
false, false,
); );
}
} }
}); });
} }

View file

@ -58,6 +58,10 @@ impl<'a> FocusStackMut<'a> {
self.0.insert(window.clone()); self.0.insert(window.clone());
} }
pub fn remove(&mut self, window: &CosmicMapped) {
self.0.retain(|w| w != window);
}
pub fn last(&self) -> Option<&CosmicMapped> { pub fn last(&self) -> Option<&CosmicMapped> {
self.0.iter().rev().find(|w| w.alive()) self.0.iter().rev().find(|w| w.alive())
} }

View file

@ -167,13 +167,11 @@ pub fn window_items(
window: &CosmicMapped, window: &CosmicMapped,
is_tiled: bool, is_tiled: bool,
is_stacked: bool, is_stacked: bool,
is_sticky: bool,
tiling_enabled: bool, tiling_enabled: bool,
possible_resizes: ResizeEdge, possible_resizes: ResizeEdge,
config: &StaticConfig, config: &StaticConfig,
) -> impl Iterator<Item = Item> { ) -> impl Iterator<Item = Item> {
//let is_always_on_top = false; // TODO check window (potentially shell?)
//let is_always_on_visible_ws = false; // TODO check window (potentially shell?)
let maximize_clone = window.clone(); let maximize_clone = window.clone();
let tile_clone = window.clone(); let tile_clone = window.clone();
let move_prev_clone = window.clone(); let move_prev_clone = window.clone();
@ -186,6 +184,7 @@ pub fn window_items(
let unstack_clone = window.clone(); let unstack_clone = window.clone();
let screenshot_clone = window.clone(); let screenshot_clone = window.clone();
let stack_clone = window.clone(); let stack_clone = window.clone();
let sticky_clone = window.clone();
let close_clone = window.clone(); let close_clone = window.clone();
vec![ vec![
@ -275,14 +274,14 @@ pub fn window_items(
.disabled(!possible_resizes.contains(ResizeEdge::BOTTOM)), .disabled(!possible_resizes.contains(ResizeEdge::BOTTOM)),
], ],
)), )),
Some( (!is_sticky).then_some(
Item::new(fl!("window-menu-move-prev-workspace"), move |handle| { Item::new(fl!("window-menu-move-prev-workspace"), move |handle| {
let mapped = move_prev_clone.clone(); let mapped = move_prev_clone.clone();
let _ = handle.insert_idle(move |state| move_prev_workspace(state, &mapped)); let _ = handle.insert_idle(move |state| move_prev_workspace(state, &mapped));
}) })
.shortcut(config.get_shortcut_for_action(&Action::MoveToPreviousWorkspace)), .shortcut(config.get_shortcut_for_action(&Action::MoveToPreviousWorkspace)),
), ),
Some( (!is_sticky).then_some(
Item::new(fl!("window-menu-move-next-workspace"), move |handle| { Item::new(fl!("window-menu-move-next-workspace"), move |handle| {
let mapped = move_next_clone.clone(); let mapped = move_next_clone.clone();
let _ = handle.insert_idle(move |state| move_next_workspace(state, &mapped)); let _ = handle.insert_idle(move |state| move_next_workspace(state, &mapped));
@ -297,10 +296,21 @@ pub fn window_items(
.shortcut(config.get_shortcut_for_action(&Action::ToggleStacking)), .shortcut(config.get_shortcut_for_action(&Action::ToggleStacking)),
), ),
Some(Item::Separator), Some(Item::Separator),
//Some(Item::new(fl!("window-menu-always-on-top"), |handle| {}).toggled(is_always_on_top)), Some(
//Some(Item::new(fl!("window-menu-always-on-visible-ws"), |handle| {}) Item::new(fl!("window-menu-sticky"), move |handle| {
// .toggled(is_always_on_visible_ws)), let mapped = sticky_clone.clone();
//Some(Item::Separator), let _ = handle.insert_idle(move |state| {
let seat = state.common.last_active_seat().clone();
let seats = state.common.seats().cloned().collect::<Vec<_>>();
state
.common
.shell
.toggle_sticky(seats.iter(), &seat, &mapped);
});
})
.toggled(is_sticky),
),
Some(Item::Separator),
if is_stacked { if is_stacked {
Some(Item::new(fl!("window-menu-close-all"), move |_handle| { Some(Item::new(fl!("window-menu-close-all"), move |_handle| {
for (window, _) in close_clone.windows() { for (window, _) in close_clone.windows() {

View file

@ -1970,13 +1970,37 @@ impl Shell {
check_grab_preconditions(&seat, surface, serial, ReleaseMode::NoMouseButtons) check_grab_preconditions(&seat, surface, serial, ReleaseMode::NoMouseButtons)
{ {
if let Some(mapped) = state.common.shell.element_for_wl_surface(surface).cloned() { if let Some(mapped) = state.common.shell.element_for_wl_surface(surface).cloned() {
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
let output = seat.active_output();
let (_, relative_loc) = mapped let (_, relative_loc) = mapped
.windows() .windows()
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface)) .find(|(w, _)| w.wl_surface().as_ref() == Some(surface))
.unwrap(); .unwrap();
let (global_position, edge, is_tiled, is_stacked, is_sticky, tiling_enabled) =
if let Some(set) = state
.common
.shell
.workspaces
.sets
.values_mut()
.find(|set| set.sticky_layer.mapped().any(|m| m == &mapped))
{
let output = set.output.clone();
let global_position =
(set.sticky_layer.element_geometry(&mapped).unwrap().loc
+ relative_loc.as_local()
+ location.as_local())
.to_global(&output);
(
global_position,
ResizeEdge::all(),
false,
mapped.is_stack(),
true,
false,
)
} else if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
let output = seat.active_output();
let global_position = (workspace.element_geometry(&mapped).unwrap().loc let global_position = (workspace.element_geometry(&mapped).unwrap().loc
+ relative_loc.as_local() + relative_loc.as_local()
+ location.as_local()) + location.as_local())
@ -1998,8 +2022,19 @@ impl Shell {
} else { } else {
ResizeEdge::all() ResizeEdge::all()
}; };
let is_stacked = mapped.is_stack();
let tiling_enabled = workspace.tiling_enabled; (
global_position,
edge,
is_tiled,
mapped.is_stack(),
false,
workspace.tiling_enabled,
)
} else {
return;
};
let grab = MenuGrab::new( let grab = MenuGrab::new(
start_data, start_data,
seat, seat,
@ -2008,6 +2043,7 @@ impl Shell {
&mapped, &mapped,
is_tiled, is_tiled,
is_stacked, is_stacked,
is_sticky,
tiling_enabled, tiling_enabled,
edge, edge,
&state.common.config.static_conf, &state.common.config.static_conf,
@ -2034,7 +2070,6 @@ impl Shell {
serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()), serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()),
Focus::Keep, Focus::Keep,
); );
}
} }
} }
} }
@ -2242,6 +2277,89 @@ impl Shell {
} }
} }
pub fn toggle_sticky<'a>(
&mut self,
seats: impl Iterator<Item = &'a Seat<State>>,
seat: &Seat<State>,
mapped: &CosmicMapped,
) {
// clean from focus-stacks
let seats = seats.collect::<Vec<_>>();
for workspace in self.workspaces.spaces_mut() {
for seat in seats.iter() {
let mut stack = workspace.focus_stack.get_mut(seat);
stack.remove(mapped);
}
}
if let Some(workspace) = self.space_for_mut(mapped) {
if workspace.is_fullscreen(mapped) {
// we are making it sticky, we don't need to move it to it's previous workspace
let _ = workspace.remove_fullscreen();
}
let previous_layer = if workspace.is_tiled(mapped) {
workspace.toggle_floating_window(seat, mapped);
ManagedLayer::Tiling
} else {
ManagedLayer::Floating
};
let geometry = workspace.element_geometry(mapped).unwrap();
workspace.unmap(mapped);
*mapped.previous_layer.lock().unwrap() = Some(previous_layer);
let output = workspace.output().clone();
let handle = workspace.handle;
for (window, _) in mapped.windows() {
self.toplevel_info_state
.toplevel_leave_workspace(&window, &handle);
}
self.workspaces
.sets
.get_mut(&output)
.unwrap()
.sticky_layer
.map(mapped.clone(), geometry.loc);
} else if let Some(set) = self
.workspaces
.sets
.values_mut()
.find(|set| set.sticky_layer.mapped().any(|m| m == mapped))
{
let geometry = set.sticky_layer.element_geometry(mapped).unwrap();
set.sticky_layer.unmap(mapped);
let workspace = &mut set.workspaces[set.active];
for (window, _) in mapped.windows() {
self.toplevel_info_state
.toplevel_enter_workspace(&window, &workspace.handle);
}
match mapped
.previous_layer
.lock()
.unwrap()
.take()
.unwrap_or(ManagedLayer::Floating)
{
ManagedLayer::Floating => {
workspace.floating_layer.map(mapped.clone(), geometry.loc)
}
ManagedLayer::Tiling => {
let focus_stack = workspace.focus_stack.get(seat);
workspace.tiling_layer.map(
mapped.clone(),
Some(focus_stack.iter()),
None,
false,
);
}
ManagedLayer::Sticky => unreachable!(),
}
}
}
pub(crate) fn set_theme(&mut self, theme: cosmic::Theme) { pub(crate) fn set_theme(&mut self, theme: cosmic::Theme) {
self.theme = theme.clone(); self.theme = theme.clone();
self.refresh(); self.refresh();