Allow pop-up grabs for bottom and background layers

This commit is contained in:
Ivan Molodetskikh
2025-01-03 16:24:02 +03:00
parent 300701f44e
commit 8e16be9e11
2 changed files with 22 additions and 11 deletions
+20 -11
View File
@@ -289,6 +289,7 @@ impl XdgShellHandler for State {
let popup = PopupKind::Xdg(surface);
let Ok(root) = find_popup_root_surface(&popup) else {
trace!("ignoring popup grab because no root surface");
return;
};
@@ -297,30 +298,30 @@ impl XdgShellHandler for State {
// keyboard focus being at the wrong place.
if self.niri.is_locked() {
if Some(&root) != self.niri.lock_surface_focus().as_ref() {
trace!("ignoring popup grab because the session is locked");
let _ = PopupManager::dismiss_popup(&root, &popup);
return;
}
} else if self.niri.screenshot_ui.is_open() {
trace!("ignoring popup grab because the screenshot UI is open");
let _ = PopupManager::dismiss_popup(&root, &popup);
return;
} else if let Some(output) = self.niri.layout.active_output() {
let layers = layer_map_for_output(output);
if let Some(layer_surface) =
layers.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)
if layers
.layer_for_surface(&root, WindowSurfaceType::TOPLEVEL)
.is_none()
{
if !matches!(layer_surface.layer(), Layer::Overlay | Layer::Top) {
let _ = PopupManager::dismiss_popup(&root, &popup);
return;
}
// This is a grab for a regular window; check that there's no layer surface with a
// higher input priority.
// FIXME: popup grabs for on-demand bottom and background layers.
} else {
if layers.layers_on(Layer::Overlay).any(|l| {
l.cached_state().keyboard_interactivity
== wlr_layer::KeyboardInteractivity::Exclusive
|| Some(l) == self.niri.layer_shell_on_demand_focus.as_ref()
}) {
trace!("ignoring toplevel popup grab because the overlay layer has focus");
let _ = PopupManager::dismiss_popup(&root, &popup);
return;
}
@@ -333,28 +334,35 @@ impl XdgShellHandler for State {
|| Some(l) == self.niri.layer_shell_on_demand_focus.as_ref()
})
{
trace!("ignoring toplevel popup grab because the top layer has focus");
let _ = PopupManager::dismiss_popup(&root, &popup);
return;
}
let layout_focus = self.niri.layout.focus();
if Some(&root) != layout_focus.map(|win| win.toplevel().wl_surface()) {
trace!("ignoring toplevel popup grab because another window has focus");
let _ = PopupManager::dismiss_popup(&root, &popup);
return;
}
}
} else {
trace!("ignoring popup grab because no output is active");
let _ = PopupManager::dismiss_popup(&root, &popup);
return;
}
let seat = &self.niri.seat;
let Ok(mut grab) = self
let mut grab = match self
.niri
.popups
.grab_popup(root.clone(), popup, seat, serial)
else {
return;
{
Ok(grab) => grab,
Err(err) => {
trace!("ignoring popup grab: {err:?}");
return;
}
};
let keyboard = seat.get_keyboard().unwrap();
@@ -380,6 +388,7 @@ impl XdgShellHandler for State {
&& !(pointer.has_grab(serial)
|| grab.previous_serial().map_or(true, |s| pointer.has_grab(s)));
if (can_receive_keyboard_focus && keyboard_grab_mismatches) || pointer_grab_mismatches {
trace!("ignoring popup grab because of current grab mismatch");
grab.ungrab(PopupUngrabStrategy::All);
return;
}
+2
View File
@@ -920,6 +920,8 @@ impl State {
// fullscreen layout window. This will need tracking in grab() to avoid handing it out
// in the first place. Or a better way to structure this code.
surface = surface.or_else(|| grab_on_layer(Layer::Top));
surface = surface.or_else(|| grab_on_layer(Layer::Bottom));
surface = surface.or_else(|| grab_on_layer(Layer::Background));
surface = surface.or_else(|| focus_on_layer(Layer::Overlay));