focus: Allow sticky windows in focus_stacks, allow dialogs to stay on top
This commit is contained in:
parent
10c196a080
commit
e67e139e15
2 changed files with 91 additions and 17 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
shell::{element::CosmicMapped, Shell, Workspace},
|
shell::{element::CosmicMapped, Shell},
|
||||||
state::Common,
|
state::Common,
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
wayland::handlers::xdg_shell::PopupGrabData,
|
wayland::handlers::xdg_shell::PopupGrabData,
|
||||||
|
|
@ -71,8 +71,6 @@ impl<'a> FocusStackMut<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Workspace {}
|
|
||||||
|
|
||||||
pub struct ActiveFocus(RefCell<Option<KeyboardFocusTarget>>);
|
pub struct ActiveFocus(RefCell<Option<KeyboardFocusTarget>>);
|
||||||
|
|
||||||
impl ActiveFocus {
|
impl ActiveFocus {
|
||||||
|
|
@ -113,7 +111,16 @@ impl Shell {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(mapped) = element {
|
if let Some(mapped) = element {
|
||||||
if let Some(workspace) = state.common.shell.space_for_mut(&mapped) {
|
let workspace = state.common.shell.space_for_mut(&mapped);
|
||||||
|
let workspace = if workspace.is_none() {
|
||||||
|
state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.active_space_mut(&active_seat.active_output())
|
||||||
|
} else {
|
||||||
|
workspace.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
let mut focus_stack = workspace.focus_stack.get_mut(active_seat);
|
let mut focus_stack = workspace.focus_stack.get_mut(active_seat);
|
||||||
if Some(&mapped) != focus_stack.last() {
|
if Some(&mapped) != focus_stack.last() {
|
||||||
trace!(?mapped, "Focusing window.");
|
trace!(?mapped, "Focusing window.");
|
||||||
|
|
@ -126,7 +133,6 @@ impl Shell {
|
||||||
{
|
{
|
||||||
if !popup_grab.has_ended() {
|
if !popup_grab.has_ended() {
|
||||||
popup_grab.ungrab(PopupUngrabStrategy::All);
|
popup_grab.ungrab(PopupUngrabStrategy::All);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +179,15 @@ impl Shell {
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for output in self.outputs().cloned().collect::<Vec<_>>().into_iter() {
|
for output in self.outputs().cloned().collect::<Vec<_>>().into_iter() {
|
||||||
// TODO: Add self.workspaces.active_workspaces()
|
let set = self.workspaces.sets.get_mut(&output).unwrap();
|
||||||
|
for focused in focused_windows.iter() {
|
||||||
|
raise_with_children(&mut set.sticky_layer, focused);
|
||||||
|
}
|
||||||
|
for window in set.sticky_layer.mapped() {
|
||||||
|
window.set_activated(focused_windows.contains(&window));
|
||||||
|
window.configure();
|
||||||
|
}
|
||||||
|
|
||||||
let workspace = self.workspaces.active_mut(&output);
|
let workspace = self.workspaces.active_mut(&output);
|
||||||
for focused in focused_windows.iter() {
|
for focused in focused_windows.iter() {
|
||||||
raise_with_children(&mut workspace.floating_layer, focused);
|
raise_with_children(&mut workspace.floating_layer, focused);
|
||||||
|
|
@ -306,7 +320,7 @@ impl Common {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_target_is_valid(
|
fn focus_target_is_valid(
|
||||||
state: &State,
|
state: &mut State,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
target: KeyboardFocusTarget,
|
target: KeyboardFocusTarget,
|
||||||
|
|
@ -329,10 +343,27 @@ fn focus_target_is_valid(
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
KeyboardFocusTarget::Element(mapped) => {
|
KeyboardFocusTarget::Element(mapped) => {
|
||||||
|
let is_sticky = state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.workspaces
|
||||||
|
.sets
|
||||||
|
.get(output)
|
||||||
|
.unwrap()
|
||||||
|
.sticky_layer
|
||||||
|
.mapped()
|
||||||
|
.any(|m| m == &mapped);
|
||||||
|
|
||||||
let workspace = state.common.shell.active_space(&output);
|
let workspace = state.common.shell.active_space(&output);
|
||||||
let focus_stack = workspace.focus_stack.get(&seat);
|
let focus_stack = workspace.focus_stack.get(&seat);
|
||||||
focus_stack.last().map(|m| m == &mapped).unwrap_or(false)
|
let is_in_focus_stack = focus_stack.last().map(|m| m == &mapped).unwrap_or(false);
|
||||||
&& workspace.get_fullscreen().is_none()
|
let has_fullscreen = workspace.get_fullscreen().is_some();
|
||||||
|
|
||||||
|
if is_sticky && !is_in_focus_stack {
|
||||||
|
Shell::append_focus_stack(state, Some(&KeyboardFocusTarget::Element(mapped)), seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
(is_sticky || is_in_focus_stack) && !has_fullscreen
|
||||||
}
|
}
|
||||||
KeyboardFocusTarget::LayerSurface(layer) => {
|
KeyboardFocusTarget::LayerSurface(layer) => {
|
||||||
layer_map_for_output(&output).layers().any(|l| l == &layer)
|
layer_map_for_output(&output).layers().any(|l| l == &layer)
|
||||||
|
|
|
||||||
|
|
@ -1569,6 +1569,27 @@ impl Shell {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let (window, seat, output) = state.common.shell.pending_windows.remove(pos);
|
let (window, seat, output) = state.common.shell.pending_windows.remove(pos);
|
||||||
|
|
||||||
|
let parent_is_sticky = match window.clone() {
|
||||||
|
CosmicSurface::Wayland(toplevel) => {
|
||||||
|
if let Some(parent) = toplevel.toplevel().parent() {
|
||||||
|
if let Some(elem) = state.common.shell.element_for_wl_surface(&parent) {
|
||||||
|
state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.workspaces
|
||||||
|
.sets
|
||||||
|
.values()
|
||||||
|
.any(|set| set.sticky_layer.mapped().any(|m| m == elem))
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
let pending_activation = state
|
let pending_activation = state
|
||||||
.common
|
.common
|
||||||
.shell
|
.shell
|
||||||
|
|
@ -1678,7 +1699,7 @@ impl Shell {
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
{
|
{
|
||||||
workspace.unmaximize_request(&mapped.active_window());
|
workspace.unmaximize_request(&mapped);
|
||||||
}
|
}
|
||||||
let focus_stack = workspace.focus_stack.get(&seat);
|
let focus_stack = workspace.focus_stack.get(&seat);
|
||||||
workspace
|
workspace
|
||||||
|
|
@ -1686,17 +1707,39 @@ impl Shell {
|
||||||
.map(mapped.clone(), Some(focus_stack.iter()), None, true);
|
.map(mapped.clone(), Some(focus_stack.iter()), None, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if should_be_fullscreen {
|
if !parent_is_sticky && should_be_fullscreen {
|
||||||
workspace.fullscreen_request(&mapped.active_window(), None);
|
workspace.fullscreen_request(&mapped.active_window(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if workspace.output == seat.active_output() && active_handle == workspace.handle {
|
let was_activated = workspace_handle.is_some();
|
||||||
|
let workspace_handle = workspace.handle;
|
||||||
|
let workspace_output = workspace.output.clone();
|
||||||
|
|
||||||
|
if parent_is_sticky {
|
||||||
|
let seats = state.common.seats().cloned().collect::<Vec<_>>();
|
||||||
|
state
|
||||||
|
.common
|
||||||
|
.shell
|
||||||
|
.toggle_sticky(seats.iter(), &seat, &mapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspace_output == seat.active_output() && active_handle == workspace_handle)
|
||||||
|
|| parent_is_sticky
|
||||||
|
{
|
||||||
// TODO: enforce focus stealing prevention by also checking the same rules as for the else case.
|
// TODO: enforce focus stealing prevention by also checking the same rules as for the else case.
|
||||||
Shell::set_focus(state, Some(&KeyboardFocusTarget::from(mapped)), &seat, None);
|
Shell::set_focus(
|
||||||
} else if workspace_empty || workspace_handle.is_some() || should_be_fullscreen {
|
state,
|
||||||
let handle = workspace.handle;
|
Some(&KeyboardFocusTarget::from(mapped.clone())),
|
||||||
Shell::append_focus_stack(state, Some(&KeyboardFocusTarget::from(mapped)), &seat);
|
&seat,
|
||||||
state.common.shell.set_urgent(&handle);
|
None,
|
||||||
|
);
|
||||||
|
} else if workspace_empty || was_activated || should_be_fullscreen {
|
||||||
|
Shell::append_focus_stack(
|
||||||
|
state,
|
||||||
|
Some(&KeyboardFocusTarget::from(mapped.clone())),
|
||||||
|
&seat,
|
||||||
|
);
|
||||||
|
state.common.shell.set_urgent(&workspace_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
let active_space = state.common.shell.active_space(&output);
|
let active_space = state.common.shell.active_space(&output);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue