Skip to content

Commit

Permalink
Merge pull request #212 from pop-os/exclusive-keyboard_jammy
Browse files Browse the repository at this point in the history
Fix handling of layer shell surface with exclusive interactivity
  • Loading branch information
jackpot51 authored Nov 2, 2023
2 parents a8632f5 + 3bec008 commit f3a8ff8
Showing 1 changed file with 45 additions and 3 deletions.
48 changes: 45 additions & 3 deletions src/shell/focus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use smithay::{
input::Seat,
output::Output,
utils::{IsAlive, Serial, SERIAL_COUNTER},
wayland::seat::WaylandFocus,
wayland::{
seat::WaylandFocus,
shell::wlr_layer::{KeyboardInteractivity, Layer},
},
};
use std::cell::RefCell;
use tracing::{debug, trace};
Expand Down Expand Up @@ -291,15 +294,27 @@ impl Common {
}

fn focus_target_is_valid(
state: &mut State,
state: &State,
seat: &Seat<State>,
output: &Output,
target: KeyboardFocusTarget,
) -> bool {
// If a session lock is active, only lock surfaces can be focused
if state.common.session_lock.is_some() {
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 {
KeyboardFocusTarget::Element(mapped) => {
let workspace = state.common.shell.active_space(&output);
Expand Down Expand Up @@ -334,7 +349,7 @@ fn focus_target_is_valid(
}

fn update_focus_target(
state: &mut State,
state: &State,
seat: &Seat<State>,
output: &Output,
) -> Option<KeyboardFocusTarget> {
Expand All @@ -344,6 +359,16 @@ fn update_focus_target(
.get(output)
.cloned()
.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() {
Some(KeyboardFocusTarget::Fullscreen(surface.clone()))
} else {
Expand All @@ -358,3 +383,20 @@ fn update_focus_target(
.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
}

0 comments on commit f3a8ff8

Please sign in to comment.