aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/niri.rs71
-rw-r--r--src/protocols/foreign_toplevel.rs2
2 files changed, 57 insertions, 16 deletions
diff --git a/src/niri.rs b/src/niri.rs
index fe14dca3..27d9d59d 100644
--- a/src/niri.rs
+++ b/src/niri.rs
@@ -193,10 +193,7 @@ pub struct Niri {
pub seat: Seat<State>,
/// Scancodes of the keys to suppress.
pub suppressed_keys: HashSet<u32>,
- // This is always a toplevel surface focused as far as niri's logic is concerned, even when
- // popup grabs are active (which means the real keyboard focus is on a popup descending from
- // this toplevel surface).
- pub keyboard_focus: Option<WlSurface>,
+ pub keyboard_focus: KeyboardFocus,
pub idle_inhibiting_surfaces: HashSet<WlSurface>,
pub is_fdo_idle_inhibited: Arc<AtomicBool>,
@@ -283,6 +280,18 @@ pub struct PopupGrabState {
pub grab: PopupGrab<State>,
}
+// The surfaces here are always toplevel surfaces focused as far as niri's logic is concerned, even
+// when popup grabs are active (which means the real keyboard focus is on a popup descending from
+// that toplevel surface).
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum KeyboardFocus {
+ // Layout is focused by default if there's nothing else to focus.
+ Layout { surface: Option<WlSurface> },
+ LayerShell { surface: WlSurface },
+ LockScreen { surface: Option<WlSurface> },
+ ScreenshotUi,
+}
+
#[derive(Clone, PartialEq, Eq)]
pub struct PointerFocus {
pub output: Output,
@@ -329,6 +338,30 @@ impl Default for SurfaceFrameThrottlingState {
}
}
+impl KeyboardFocus {
+ pub fn surface(&self) -> Option<&WlSurface> {
+ match self {
+ KeyboardFocus::Layout { surface } => surface.as_ref(),
+ KeyboardFocus::LayerShell { surface } => Some(surface),
+ KeyboardFocus::LockScreen { surface } => surface.as_ref(),
+ KeyboardFocus::ScreenshotUi => None,
+ }
+ }
+
+ pub fn into_surface(self) -> Option<WlSurface> {
+ match self {
+ KeyboardFocus::Layout { surface } => surface,
+ KeyboardFocus::LayerShell { surface } => Some(surface),
+ KeyboardFocus::LockScreen { surface } => surface,
+ KeyboardFocus::ScreenshotUi => None,
+ }
+ }
+
+ pub fn is_layout(&self) -> bool {
+ matches!(self, KeyboardFocus::Layout { .. })
+ }
+}
+
pub struct State {
pub backend: Backend,
pub niri: Niri,
@@ -562,9 +595,11 @@ impl State {
pub fn update_keyboard_focus(&mut self) {
let focus = if self.niri.is_locked() {
- self.niri.lock_surface_focus()
+ KeyboardFocus::LockScreen {
+ surface: self.niri.lock_surface_focus(),
+ }
} else if self.niri.screenshot_ui.is_open() {
- None
+ KeyboardFocus::ScreenshotUi
} else if let Some(output) = self.niri.layout.active_output() {
let mon = self.niri.layout.monitor_for_output(output).unwrap();
let layers = layer_map_for_output(output);
@@ -577,7 +612,9 @@ impl State {
.map(|l| (&g.root, l.layer()))
});
let grab_on_layer = |layer: Layer| {
- layer_grab.and_then(move |(s, l)| if l == layer { Some(s.clone()) } else { None })
+ layer_grab
+ .and_then(move |(s, l)| if l == layer { Some(s.clone()) } else { None })
+ .map(|surface| KeyboardFocus::LayerShell { surface })
};
let layout_focus = || {
@@ -585,11 +622,15 @@ impl State {
.layout
.focus()
.map(|win| win.toplevel().expect("no x11 support").wl_surface().clone())
+ .map(|surface| KeyboardFocus::Layout {
+ surface: Some(surface),
+ })
};
let layer_focus = |surface: &LayerSurface| {
surface
.can_receive_keyboard_focus()
.then(|| surface.wl_surface().clone())
+ .map(|surface| KeyboardFocus::LayerShell { surface })
};
let mut surface = grab_on_layer(Layer::Overlay);
@@ -608,9 +649,9 @@ impl State {
surface = surface.or_else(layout_focus);
}
- surface
+ surface.unwrap_or(KeyboardFocus::Layout { surface: None })
} else {
- None
+ KeyboardFocus::Layout { surface: None }
};
let keyboard = self.niri.seat.get_keyboard().unwrap();
@@ -622,7 +663,7 @@ impl State {
);
if let Some(grab) = self.niri.popup_grab.as_mut() {
- if Some(&grab.root) != focus.as_ref() {
+ if Some(&grab.root) != focus.surface() {
trace!(
"grab root {:?} is not the new focus {:?}, ungrabbing",
grab.root,
@@ -646,7 +687,7 @@ impl State {
let mut new_layout = current_layout;
// Store the currently active layout for the surface.
- if let Some(current_focus) = self.niri.keyboard_focus.as_ref() {
+ if let Some(current_focus) = self.niri.keyboard_focus.surface() {
with_states(current_focus, |data| {
let cell = data
.data_map
@@ -655,7 +696,7 @@ impl State {
});
}
- if let Some(focus) = focus.as_ref() {
+ if let Some(focus) = focus.surface() {
new_layout = with_states(focus, |data| {
let cell = data.data_map.get_or_insert::<Cell<KeyboardLayout>, _>(|| {
// The default layout is effectively the first layout in the
@@ -665,7 +706,7 @@ impl State {
cell.get()
});
}
- if new_layout != current_layout && focus.is_some() {
+ if new_layout != current_layout && focus.surface().is_some() {
keyboard.set_focus(self, None, SERIAL_COUNTER.next_serial());
keyboard.with_xkb_state(self, |mut context| {
context.set_layout(new_layout);
@@ -674,7 +715,7 @@ impl State {
}
self.niri.keyboard_focus.clone_from(&focus);
- keyboard.set_focus(self, focus, SERIAL_COUNTER.next_serial());
+ keyboard.set_focus(self, focus.into_surface(), SERIAL_COUNTER.next_serial());
// FIXME: can be more granular.
self.niri.queue_redraw_all();
@@ -1169,7 +1210,7 @@ impl Niri {
gamma_control_manager_state,
seat,
- keyboard_focus: None,
+ keyboard_focus: KeyboardFocus::Layout { surface: None },
idle_inhibiting_surfaces: HashSet::new(),
is_fdo_idle_inhibited: Arc::new(AtomicBool::new(false)),
cursor_manager,
diff --git a/src/protocols/foreign_toplevel.rs b/src/protocols/foreign_toplevel.rs
index 5366da1a..67dff830 100644
--- a/src/protocols/foreign_toplevel.rs
+++ b/src/protocols/foreign_toplevel.rs
@@ -106,7 +106,7 @@ pub fn refresh(state: &mut State) {
.lock()
.unwrap();
- if state.niri.keyboard_focus.as_ref() == Some(wl_surface) {
+ if state.niri.keyboard_focus.surface() == Some(wl_surface) {
focused = Some((window.clone(), output.cloned()));
} else {
refresh_toplevel(protocol_state, wl_surface, &role, output, false);