mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
Give focus to on-demand layer surfaces on map
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
use smithay::backend::renderer::utils::with_renderer_surface_state;
|
||||
use smithay::delegate_layer_shell;
|
||||
use smithay::desktop::{layer_map_for_output, LayerSurface, PopupKind, WindowSurfaceType};
|
||||
use smithay::output::Output;
|
||||
@@ -5,7 +6,7 @@ use smithay::reexports::wayland_server::protocol::wl_output::WlOutput;
|
||||
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
||||
use smithay::wayland::compositor::{get_parent, with_states};
|
||||
use smithay::wayland::shell::wlr_layer::{
|
||||
Layer, LayerSurface as WlrLayerSurface, LayerSurfaceData, WlrLayerShellHandler,
|
||||
self, Layer, LayerSurface as WlrLayerSurface, LayerSurfaceData, WlrLayerShellHandler,
|
||||
WlrLayerShellState,
|
||||
};
|
||||
use smithay::wayland::shell::xdg::PopupSurface;
|
||||
@@ -36,12 +37,19 @@ impl WlrLayerShellHandler for State {
|
||||
return;
|
||||
};
|
||||
|
||||
let wl_surface = surface.wl_surface().clone();
|
||||
let is_new = self.niri.unmapped_layer_surfaces.insert(wl_surface);
|
||||
assert!(is_new);
|
||||
|
||||
let mut map = layer_map_for_output(&output);
|
||||
map.map_layer(&LayerSurface::new(surface, namespace))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn layer_destroyed(&mut self, surface: WlrLayerSurface) {
|
||||
let wl_surface = surface.wl_surface();
|
||||
self.niri.unmapped_layer_surfaces.remove(wl_surface);
|
||||
|
||||
let output = if let Some((output, mut map, layer)) =
|
||||
self.niri.layout.outputs().find_map(|o| {
|
||||
let map = layer_map_for_output(o);
|
||||
@@ -101,15 +109,51 @@ impl State {
|
||||
|
||||
let mut map = layer_map_for_output(&output);
|
||||
|
||||
// arrange the layers before sending the initial configure
|
||||
// to respect any size the client may have sent
|
||||
// Arrange the layers before sending the initial configure to respect any size the
|
||||
// client may have sent.
|
||||
map.arrange();
|
||||
// send the initial configure if relevant
|
||||
if !initial_configure_sent {
|
||||
let layer = map
|
||||
.layer_for_surface(surface, WindowSurfaceType::TOPLEVEL)
|
||||
.unwrap();
|
||||
|
||||
let layer = map
|
||||
.layer_for_surface(surface, WindowSurfaceType::TOPLEVEL)
|
||||
.unwrap();
|
||||
|
||||
if initial_configure_sent {
|
||||
let is_mapped =
|
||||
with_renderer_surface_state(surface, |state| state.buffer().is_some())
|
||||
.unwrap_or_else(|| {
|
||||
error!("no renderer surface state even though we use commit handler");
|
||||
false
|
||||
});
|
||||
|
||||
if is_mapped {
|
||||
let was_unmapped = self.niri.unmapped_layer_surfaces.remove(surface);
|
||||
|
||||
// Give focus to newly mapped on-demand surfaces. Some launchers like
|
||||
// lxqt-runner rely on this behavior. While this behavior doesn't make much
|
||||
// sense for other clients like panels, the consensus seems to be that it's not
|
||||
// a big deal since panels generally only open once at the start of the
|
||||
// session.
|
||||
//
|
||||
// Note that:
|
||||
// 1) Exclusive layer surfaces already get focus automatically in
|
||||
// update_keyboard_focus().
|
||||
// 2) Same-layer exclusive layer surfaces are already preferred to on-demand
|
||||
// surfaces in update_keyboard_focus(), so we don't need to check for that
|
||||
// here.
|
||||
//
|
||||
// https://github.com/YaLTeR/niri/issues/641
|
||||
let on_demand = layer.cached_state().keyboard_interactivity
|
||||
== wlr_layer::KeyboardInteractivity::OnDemand;
|
||||
if was_unmapped && on_demand {
|
||||
// I guess it'd make sense to check that no higher-layer on-demand surface
|
||||
// has focus, but Smithay's Layer doesn't implement Ord so this would be a
|
||||
// little annoying.
|
||||
self.niri.layer_shell_on_demand_focus = Some(layer.clone());
|
||||
}
|
||||
} else {
|
||||
self.niri.unmapped_layer_surfaces.insert(surface.clone());
|
||||
}
|
||||
} else {
|
||||
let scale = output.current_scale();
|
||||
let transform = output.current_transform();
|
||||
with_states(surface, |data| {
|
||||
|
||||
@@ -186,6 +186,9 @@ pub struct Niri {
|
||||
// Windows which don't have a buffer attached yet.
|
||||
pub unmapped_windows: HashMap<WlSurface, Unmapped>,
|
||||
|
||||
/// Layer surfaces which don't have a buffer attached yet.
|
||||
pub unmapped_layer_surfaces: HashSet<WlSurface>,
|
||||
|
||||
// Cached root surface for every surface, so that we can access it in destroyed() where the
|
||||
// normal get_parent() is cleared out.
|
||||
pub root_surface: HashMap<WlSurface, WlSurface>,
|
||||
@@ -1788,6 +1791,7 @@ impl Niri {
|
||||
global_space: Space::default(),
|
||||
output_state: HashMap::new(),
|
||||
unmapped_windows: HashMap::new(),
|
||||
unmapped_layer_surfaces: HashSet::new(),
|
||||
root_surface: HashMap::new(),
|
||||
dmabuf_pre_commit_hook: HashMap::new(),
|
||||
blocker_cleared_tx,
|
||||
|
||||
Reference in New Issue
Block a user