Merge pull request #212 from pop-os/exclusive-keyboard_jammy
Fix handling of layer shell surface with exclusive interactivity
This commit is contained in:
commit
f3a8ff8600
1 changed files with 45 additions and 3 deletions
|
|
@ -10,7 +10,10 @@ use smithay::{
|
||||||
input::Seat,
|
input::Seat,
|
||||||
output::Output,
|
output::Output,
|
||||||
utils::{IsAlive, Serial, SERIAL_COUNTER},
|
utils::{IsAlive, Serial, SERIAL_COUNTER},
|
||||||
wayland::seat::WaylandFocus,
|
wayland::{
|
||||||
|
seat::WaylandFocus,
|
||||||
|
shell::wlr_layer::{KeyboardInteractivity, Layer},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use tracing::{debug, trace};
|
use tracing::{debug, trace};
|
||||||
|
|
@ -291,15 +294,27 @@ impl Common {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus_target_is_valid(
|
fn focus_target_is_valid(
|
||||||
state: &mut State,
|
state: &State,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
target: KeyboardFocusTarget,
|
target: KeyboardFocusTarget,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
|
// If a session lock is active, only lock surfaces can be focused
|
||||||
if state.common.session_lock.is_some() {
|
if state.common.session_lock.is_some() {
|
||||||
return matches!(target, KeyboardFocusTarget::LockSurface(_));
|
return matches!(target, KeyboardFocusTarget::LockSurface(_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If an exclusive layer shell surface exists (on any output), only exclusive
|
||||||
|
// shell surfaces can have focus, on the highest layer with exclusive surfaces.
|
||||||
|
if let Some(layer) = exclusive_layer_surface_layer(state) {
|
||||||
|
return if let KeyboardFocusTarget::LayerSurface(layer_surface) = target {
|
||||||
|
let data = layer_surface.cached_state();
|
||||||
|
(data.keyboard_interactivity, data.layer) == (KeyboardInteractivity::Exclusive, layer)
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
match target {
|
match target {
|
||||||
KeyboardFocusTarget::Element(mapped) => {
|
KeyboardFocusTarget::Element(mapped) => {
|
||||||
let workspace = state.common.shell.active_space(&output);
|
let workspace = state.common.shell.active_space(&output);
|
||||||
|
|
@ -334,7 +349,7 @@ fn focus_target_is_valid(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_focus_target(
|
fn update_focus_target(
|
||||||
state: &mut State,
|
state: &State,
|
||||||
seat: &Seat<State>,
|
seat: &Seat<State>,
|
||||||
output: &Output,
|
output: &Output,
|
||||||
) -> Option<KeyboardFocusTarget> {
|
) -> Option<KeyboardFocusTarget> {
|
||||||
|
|
@ -344,6 +359,16 @@ fn update_focus_target(
|
||||||
.get(output)
|
.get(output)
|
||||||
.cloned()
|
.cloned()
|
||||||
.map(KeyboardFocusTarget::from)
|
.map(KeyboardFocusTarget::from)
|
||||||
|
} else if let Some(layer) = exclusive_layer_surface_layer(state) {
|
||||||
|
layer_map_for_output(output)
|
||||||
|
.layers()
|
||||||
|
.find(|layer_surface| {
|
||||||
|
let data = layer_surface.cached_state();
|
||||||
|
(data.keyboard_interactivity, data.layer)
|
||||||
|
== (KeyboardInteractivity::Exclusive, layer)
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
.map(KeyboardFocusTarget::from)
|
||||||
} else if let Some(surface) = state.common.shell.active_space(&output).get_fullscreen() {
|
} else if let Some(surface) = state.common.shell.active_space(&output).get_fullscreen() {
|
||||||
Some(KeyboardFocusTarget::Fullscreen(surface.clone()))
|
Some(KeyboardFocusTarget::Fullscreen(surface.clone()))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -358,3 +383,20 @@ fn update_focus_target(
|
||||||
.map(KeyboardFocusTarget::from)
|
.map(KeyboardFocusTarget::from)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the top-most layer, if any, with at least one surface with exclusive keyboard interactivity.
|
||||||
|
// Only considers surface in `Top` or `Overlay` layer.
|
||||||
|
fn exclusive_layer_surface_layer(state: &State) -> Option<Layer> {
|
||||||
|
let mut layer = None;
|
||||||
|
for output in state.common.shell.outputs() {
|
||||||
|
for layer_surface in layer_map_for_output(output).layers() {
|
||||||
|
let data = layer_surface.cached_state();
|
||||||
|
if data.keyboard_interactivity == KeyboardInteractivity::Exclusive {
|
||||||
|
if data.layer as u32 >= layer.unwrap_or(Layer::Top) as u32 {
|
||||||
|
layer = Some(data.layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layer
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue