menu: Allow toggling sticky state
This commit is contained in:
parent
e0d207fbe1
commit
d2e394b957
7 changed files with 187 additions and 24 deletions
|
|
@ -14,8 +14,7 @@ window-menu-move-next-workspace = Move to next workspace
|
|||
window-menu-stack = Create window stack
|
||||
window-menu-unstack-all = Unstack windows
|
||||
window-menu-unstack = Unstack window
|
||||
window-menu-always-on-top = Always on top
|
||||
window-menu-always-on-visible-ws = Always on visible workspace
|
||||
window-menu-sticky = Sticky window
|
||||
window-menu-close = Close
|
||||
window-menu-close-all = Close all windows
|
||||
window-menu-resize-edge-top = Top
|
||||
|
|
|
|||
|
|
@ -108,6 +108,8 @@ pub struct CosmicMapped {
|
|||
pub last_geometry: Arc<Mutex<Option<Rectangle<i32, Local>>>>,
|
||||
pub moved_since_mapped: Arc<AtomicBool>,
|
||||
pub floating_tiled: Arc<Mutex<Option<TiledCorners>>>,
|
||||
//sticky
|
||||
pub previous_layer: Arc<Mutex<Option<ManagedLayer>>>,
|
||||
|
||||
#[cfg(feature = "debug")]
|
||||
debug: Arc<Mutex<Option<smithay_egui::EguiState>>>,
|
||||
|
|
@ -1118,6 +1120,7 @@ impl From<CosmicWindow> for CosmicMapped {
|
|||
last_geometry: Arc::new(Mutex::new(None)),
|
||||
moved_since_mapped: Arc::new(AtomicBool::new(false)),
|
||||
floating_tiled: Arc::new(Mutex::new(None)),
|
||||
previous_layer: Arc::new(Mutex::new(None)),
|
||||
#[cfg(feature = "debug")]
|
||||
debug: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
|
|
@ -1135,6 +1138,7 @@ impl From<CosmicStack> for CosmicMapped {
|
|||
last_geometry: Arc::new(Mutex::new(None)),
|
||||
moved_since_mapped: Arc::new(AtomicBool::new(false)),
|
||||
floating_tiled: Arc::new(Mutex::new(None)),
|
||||
previous_layer: Arc::new(Mutex::new(None)),
|
||||
#[cfg(feature = "debug")]
|
||||
debug: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -692,12 +692,27 @@ impl Program for CosmicStackInternal {
|
|||
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 position = workspace
|
||||
let position = if let Some((output, set)) =
|
||||
state.common.shell.workspaces.sets.iter().find(|(_, set)| {
|
||||
set.sticky_layer.mapped().any(|m| m == &mapped)
|
||||
}) {
|
||||
set.sticky_layer
|
||||
.element_geometry(&mapped)
|
||||
.unwrap()
|
||||
.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
|
||||
.get_pointer()
|
||||
.unwrap()
|
||||
|
|
@ -712,7 +727,6 @@ impl Program for CosmicStackInternal {
|
|||
cursor - position.as_logical(),
|
||||
true,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -292,12 +292,27 @@ impl Program for CosmicWindowInternal {
|
|||
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 position = workspace
|
||||
let position = if let Some((output, set)) =
|
||||
state.common.shell.workspaces.sets.iter().find(|(_, set)| {
|
||||
set.sticky_layer.mapped().any(|m| m == &mapped)
|
||||
}) {
|
||||
set.sticky_layer
|
||||
.element_geometry(&mapped)
|
||||
.unwrap()
|
||||
.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
|
||||
.get_pointer()
|
||||
.unwrap()
|
||||
|
|
@ -312,7 +327,6 @@ impl Program for CosmicWindowInternal {
|
|||
cursor - position.as_logical(),
|
||||
false,
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ impl<'a> FocusStackMut<'a> {
|
|||
self.0.insert(window.clone());
|
||||
}
|
||||
|
||||
pub fn remove(&mut self, window: &CosmicMapped) {
|
||||
self.0.retain(|w| w != window);
|
||||
}
|
||||
|
||||
pub fn last(&self) -> Option<&CosmicMapped> {
|
||||
self.0.iter().rev().find(|w| w.alive())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -167,13 +167,11 @@ pub fn window_items(
|
|||
window: &CosmicMapped,
|
||||
is_tiled: bool,
|
||||
is_stacked: bool,
|
||||
is_sticky: bool,
|
||||
tiling_enabled: bool,
|
||||
possible_resizes: ResizeEdge,
|
||||
config: &StaticConfig,
|
||||
) -> 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 tile_clone = window.clone();
|
||||
let move_prev_clone = window.clone();
|
||||
|
|
@ -186,6 +184,7 @@ pub fn window_items(
|
|||
let unstack_clone = window.clone();
|
||||
let screenshot_clone = window.clone();
|
||||
let stack_clone = window.clone();
|
||||
let sticky_clone = window.clone();
|
||||
let close_clone = window.clone();
|
||||
|
||||
vec![
|
||||
|
|
@ -275,14 +274,14 @@ pub fn window_items(
|
|||
.disabled(!possible_resizes.contains(ResizeEdge::BOTTOM)),
|
||||
],
|
||||
)),
|
||||
Some(
|
||||
(!is_sticky).then_some(
|
||||
Item::new(fl!("window-menu-move-prev-workspace"), move |handle| {
|
||||
let mapped = move_prev_clone.clone();
|
||||
let _ = handle.insert_idle(move |state| move_prev_workspace(state, &mapped));
|
||||
})
|
||||
.shortcut(config.get_shortcut_for_action(&Action::MoveToPreviousWorkspace)),
|
||||
),
|
||||
Some(
|
||||
(!is_sticky).then_some(
|
||||
Item::new(fl!("window-menu-move-next-workspace"), move |handle| {
|
||||
let mapped = move_next_clone.clone();
|
||||
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)),
|
||||
),
|
||||
Some(Item::Separator),
|
||||
//Some(Item::new(fl!("window-menu-always-on-top"), |handle| {}).toggled(is_always_on_top)),
|
||||
//Some(Item::new(fl!("window-menu-always-on-visible-ws"), |handle| {})
|
||||
// .toggled(is_always_on_visible_ws)),
|
||||
//Some(Item::Separator),
|
||||
Some(
|
||||
Item::new(fl!("window-menu-sticky"), move |handle| {
|
||||
let mapped = sticky_clone.clone();
|
||||
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 {
|
||||
Some(Item::new(fl!("window-menu-close-all"), move |_handle| {
|
||||
for (window, _) in close_clone.windows() {
|
||||
|
|
|
|||
128
src/shell/mod.rs
128
src/shell/mod.rs
|
|
@ -1970,13 +1970,37 @@ impl Shell {
|
|||
check_grab_preconditions(&seat, surface, serial, ReleaseMode::NoMouseButtons)
|
||||
{
|
||||
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
|
||||
.windows()
|
||||
.find(|(w, _)| w.wl_surface().as_ref() == Some(surface))
|
||||
.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
|
||||
+ relative_loc.as_local()
|
||||
+ location.as_local())
|
||||
|
|
@ -1998,8 +2022,19 @@ impl Shell {
|
|||
} else {
|
||||
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(
|
||||
start_data,
|
||||
seat,
|
||||
|
|
@ -2008,6 +2043,7 @@ impl Shell {
|
|||
&mapped,
|
||||
is_tiled,
|
||||
is_stacked,
|
||||
is_sticky,
|
||||
tiling_enabled,
|
||||
edge,
|
||||
&state.common.config.static_conf,
|
||||
|
|
@ -2034,7 +2070,6 @@ impl Shell {
|
|||
serial.unwrap_or_else(|| SERIAL_COUNTER.next_serial()),
|
||||
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) {
|
||||
self.theme = theme.clone();
|
||||
self.refresh();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue