mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-24 02:01:18 +07:00
Add initial layer-shell implementation
Those surfaces never receive mouse focus and always keyboard focus, which may not be always good, but it'll do for now.
This commit is contained in:
@@ -112,6 +112,9 @@ impl CompositorHandler for Niri {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This might be a layer-shell surface.
|
||||||
|
self.layer_shell_handle_commit(surface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
use smithay::delegate_layer_shell;
|
||||||
|
use smithay::desktop::{layer_map_for_output, LayerSurface, WindowSurfaceType};
|
||||||
|
use smithay::output::Output;
|
||||||
|
use smithay::reexports::wayland_server::protocol::wl_output::WlOutput;
|
||||||
|
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
||||||
|
use smithay::wayland::compositor::with_states;
|
||||||
|
use smithay::wayland::shell::wlr_layer::{
|
||||||
|
Layer, LayerSurface as WlrLayerSurface, LayerSurfaceData, WlrLayerShellHandler,
|
||||||
|
WlrLayerShellState,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::niri::Niri;
|
||||||
|
|
||||||
|
impl WlrLayerShellHandler for Niri {
|
||||||
|
fn shell_state(&mut self) -> &mut WlrLayerShellState {
|
||||||
|
&mut self.layer_shell_state
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_layer_surface(
|
||||||
|
&mut self,
|
||||||
|
surface: WlrLayerSurface,
|
||||||
|
wl_output: Option<WlOutput>,
|
||||||
|
_layer: Layer,
|
||||||
|
namespace: String,
|
||||||
|
) {
|
||||||
|
let output = wl_output
|
||||||
|
.as_ref()
|
||||||
|
.and_then(Output::from_resource)
|
||||||
|
.or_else(|| self.monitor_set.active_output().cloned())
|
||||||
|
.unwrap();
|
||||||
|
let mut map = layer_map_for_output(&output);
|
||||||
|
map.map_layer(&LayerSurface::new(surface, namespace))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn layer_destroyed(&mut self, surface: WlrLayerSurface) {
|
||||||
|
let output = if let Some((output, mut map, layer)) =
|
||||||
|
self.monitor_set.outputs().find_map(|o| {
|
||||||
|
let map = layer_map_for_output(o);
|
||||||
|
let layer = map
|
||||||
|
.layers()
|
||||||
|
.find(|&layer| layer.layer_surface() == &surface)
|
||||||
|
.cloned();
|
||||||
|
layer.map(|layer| (o.clone(), map, layer))
|
||||||
|
}) {
|
||||||
|
map.unmap_layer(&layer);
|
||||||
|
Some(output)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if let Some(output) = output {
|
||||||
|
self.queue_redraw(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delegate_layer_shell!(Niri);
|
||||||
|
|
||||||
|
impl Niri {
|
||||||
|
pub fn layer_shell_handle_commit(&mut self, surface: &WlSurface) {
|
||||||
|
let Some(output) = self
|
||||||
|
.monitor_set
|
||||||
|
.outputs()
|
||||||
|
.find(|o| {
|
||||||
|
let map = layer_map_for_output(o);
|
||||||
|
map.layer_for_surface(surface, WindowSurfaceType::TOPLEVEL)
|
||||||
|
.is_some()
|
||||||
|
})
|
||||||
|
.cloned()
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let initial_configure_sent = with_states(surface, |states| {
|
||||||
|
states
|
||||||
|
.data_map
|
||||||
|
.get::<LayerSurfaceData>()
|
||||||
|
.unwrap()
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.initial_configure_sent
|
||||||
|
});
|
||||||
|
|
||||||
|
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
|
||||||
|
map.arrange();
|
||||||
|
// send the initial configure if relevant
|
||||||
|
if !initial_configure_sent {
|
||||||
|
let layer = map
|
||||||
|
.layer_for_surface(surface, WindowSurfaceType::TOPLEVEL)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
layer.layer_surface().send_configure();
|
||||||
|
}
|
||||||
|
drop(map);
|
||||||
|
|
||||||
|
self.queue_redraw(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
mod compositor;
|
mod compositor;
|
||||||
|
mod layer_shell;
|
||||||
mod xdg_shell;
|
mod xdg_shell;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -566,6 +566,16 @@ impl<W: LayoutElement> MonitorSet<W> {
|
|||||||
.find(|monitor| &monitor.output == output)
|
.find(|monitor| &monitor.output == output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn outputs(&self) -> impl Iterator<Item = &Output> + '_ {
|
||||||
|
let monitors = if let MonitorSet::Normal { monitors, .. } = self {
|
||||||
|
&monitors[..]
|
||||||
|
} else {
|
||||||
|
&[][..]
|
||||||
|
};
|
||||||
|
|
||||||
|
monitors.iter().map(|mon| &mon.output)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn move_left(&mut self) {
|
pub fn move_left(&mut self) {
|
||||||
let Some(monitor) = self.active_monitor() else {
|
let Some(monitor) = self.active_monitor() else {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+101
-18
@@ -3,10 +3,13 @@ use std::os::unix::io::AsRawFd;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use smithay::backend::renderer::element::render_elements;
|
|
||||||
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
use smithay::backend::renderer::element::solid::{SolidColorBuffer, SolidColorRenderElement};
|
||||||
|
use smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement;
|
||||||
|
use smithay::backend::renderer::element::{render_elements, AsRenderElements};
|
||||||
use smithay::backend::renderer::ImportAll;
|
use smithay::backend::renderer::ImportAll;
|
||||||
use smithay::desktop::{PopupManager, Space, Window, WindowSurfaceType};
|
use smithay::desktop::{
|
||||||
|
layer_map_for_output, LayerSurface, PopupManager, Space, Window, WindowSurfaceType,
|
||||||
|
};
|
||||||
use smithay::input::keyboard::XkbConfig;
|
use smithay::input::keyboard::XkbConfig;
|
||||||
use smithay::input::{Seat, SeatState};
|
use smithay::input::{Seat, SeatState};
|
||||||
use smithay::output::Output;
|
use smithay::output::Output;
|
||||||
@@ -18,10 +21,12 @@ use smithay::reexports::wayland_server::backend::{
|
|||||||
};
|
};
|
||||||
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
use smithay::reexports::wayland_server::protocol::wl_surface::WlSurface;
|
||||||
use smithay::reexports::wayland_server::{Display, DisplayHandle};
|
use smithay::reexports::wayland_server::{Display, DisplayHandle};
|
||||||
use smithay::utils::{Logical, Point, SERIAL_COUNTER};
|
use smithay::utils::{Logical, Point, Scale, SERIAL_COUNTER};
|
||||||
use smithay::wayland::compositor::{CompositorClientState, CompositorState};
|
use smithay::wayland::compositor::{CompositorClientState, CompositorState};
|
||||||
use smithay::wayland::data_device::DataDeviceState;
|
use smithay::wayland::data_device::DataDeviceState;
|
||||||
use smithay::wayland::output::OutputManagerState;
|
use smithay::wayland::output::OutputManagerState;
|
||||||
|
use smithay::wayland::seat::WaylandFocus;
|
||||||
|
use smithay::wayland::shell::wlr_layer::{Layer, WlrLayerShellState};
|
||||||
use smithay::wayland::shell::xdg::XdgShellState;
|
use smithay::wayland::shell::xdg::XdgShellState;
|
||||||
use smithay::wayland::shm::ShmState;
|
use smithay::wayland::shm::ShmState;
|
||||||
use smithay::wayland::socket::ListeningSocketSource;
|
use smithay::wayland::socket::ListeningSocketSource;
|
||||||
@@ -53,6 +58,7 @@ pub struct Niri {
|
|||||||
// Smithay state.
|
// Smithay state.
|
||||||
pub compositor_state: CompositorState,
|
pub compositor_state: CompositorState,
|
||||||
pub xdg_shell_state: XdgShellState,
|
pub xdg_shell_state: XdgShellState,
|
||||||
|
pub layer_shell_state: WlrLayerShellState,
|
||||||
pub shm_state: ShmState,
|
pub shm_state: ShmState,
|
||||||
pub output_manager_state: OutputManagerState,
|
pub output_manager_state: OutputManagerState,
|
||||||
pub seat_state: SeatState<Self>,
|
pub seat_state: SeatState<Self>,
|
||||||
@@ -95,6 +101,7 @@ impl Niri {
|
|||||||
WmCapabilities::WindowMenu,
|
WmCapabilities::WindowMenu,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
let layer_shell_state = WlrLayerShellState::new::<Self>(&display_handle);
|
||||||
let shm_state = ShmState::new::<Self>(&display_handle, vec![]);
|
let shm_state = ShmState::new::<Self>(&display_handle, vec![]);
|
||||||
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
|
let output_manager_state = OutputManagerState::new_with_xdg_output::<Self>(&display_handle);
|
||||||
let mut seat_state = SeatState::new();
|
let mut seat_state = SeatState::new();
|
||||||
@@ -155,6 +162,7 @@ impl Niri {
|
|||||||
|
|
||||||
compositor_state,
|
compositor_state,
|
||||||
xdg_shell_state,
|
xdg_shell_state,
|
||||||
|
layer_shell_state,
|
||||||
shm_state,
|
shm_state,
|
||||||
output_manager_state,
|
output_manager_state,
|
||||||
seat_state,
|
seat_state,
|
||||||
@@ -203,6 +211,7 @@ impl Niri {
|
|||||||
|
|
||||||
pub fn output_resized(&mut self, output: Output) {
|
pub fn output_resized(&mut self, output: Output) {
|
||||||
self.monitor_set.update_output(&output);
|
self.monitor_set.update_output(&output);
|
||||||
|
layer_map_for_output(&output).arrange();
|
||||||
self.queue_redraw(output);
|
self.queue_redraw(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,11 +265,23 @@ impl Niri {
|
|||||||
self.global_space.output_under(pos).next().cloned()
|
self.global_space.output_under(pos).next().cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn layer_surface_focus(&self) -> Option<WlSurface> {
|
||||||
|
let output = self.monitor_set.active_output()?;
|
||||||
|
let layers = layer_map_for_output(output);
|
||||||
|
let surface = layers
|
||||||
|
.layers_on(Layer::Overlay)
|
||||||
|
.chain(layers.layers_on(Layer::Top))
|
||||||
|
.find(|surface| surface.can_receive_keyboard_focus())?;
|
||||||
|
|
||||||
|
Some(surface.wl_surface().clone())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_focus(&mut self) {
|
pub fn update_focus(&mut self) {
|
||||||
let focus = self
|
let focus = self.layer_surface_focus().or_else(|| {
|
||||||
.monitor_set
|
self.monitor_set
|
||||||
.focus()
|
.focus()
|
||||||
.map(|win| win.toplevel().wl_surface().clone());
|
.map(|win| win.toplevel().wl_surface().clone())
|
||||||
|
});
|
||||||
let keyboard = self.seat.get_keyboard().unwrap();
|
let keyboard = self.seat.get_keyboard().unwrap();
|
||||||
if keyboard.current_focus() != focus {
|
if keyboard.current_focus() != focus {
|
||||||
keyboard.set_focus(self, focus, SERIAL_COUNTER.next_serial());
|
keyboard.set_focus(self, focus, SERIAL_COUNTER.next_serial());
|
||||||
@@ -306,38 +327,100 @@ impl Niri {
|
|||||||
assert!(state.queued_redraw.take().is_some());
|
assert!(state.queued_redraw.take().is_some());
|
||||||
assert!(!state.waiting_for_vblank);
|
assert!(!state.waiting_for_vblank);
|
||||||
|
|
||||||
|
let renderer = backend.renderer();
|
||||||
|
|
||||||
let mon = self.monitor_set.monitor_for_output_mut(output).unwrap();
|
let mon = self.monitor_set.monitor_for_output_mut(output).unwrap();
|
||||||
mon.advance_animations(presentation_time);
|
mon.advance_animations(presentation_time);
|
||||||
let elements = mon.render_elements(backend.renderer());
|
// Get monitor elements.
|
||||||
|
let monitor_elements = mon.render_elements(renderer);
|
||||||
|
|
||||||
let output_pos = self.global_space.output_geometry(output).unwrap().loc;
|
let output_pos = self.global_space.output_geometry(output).unwrap().loc;
|
||||||
let pointer_pos = self.seat.get_pointer().unwrap().current_location() - output_pos.to_f64();
|
let pointer_pos = self.seat.get_pointer().unwrap().current_location() - output_pos.to_f64();
|
||||||
|
|
||||||
let mut elements: Vec<_> = elements
|
// Get layer-shell elements.
|
||||||
.into_iter()
|
let layer_map = layer_map_for_output(output);
|
||||||
.map(OutputRenderElements::from)
|
let (lower, upper): (Vec<&LayerSurface>, Vec<&LayerSurface>) = layer_map
|
||||||
.collect();
|
.layers()
|
||||||
elements.insert(
|
.rev()
|
||||||
0,
|
.partition(|s| matches!(s.layer(), Layer::Background | Layer::Bottom));
|
||||||
OutputRenderElements::Pointer(SolidColorRenderElement::from_buffer(
|
|
||||||
|
// The pointer goes on the top.
|
||||||
|
let mut elements = vec![OutputRenderElements::Pointer(
|
||||||
|
SolidColorRenderElement::from_buffer(
|
||||||
&self.pointer_buffer,
|
&self.pointer_buffer,
|
||||||
pointer_pos.to_physical_precise_round(1.),
|
pointer_pos.to_physical_precise_round(1.),
|
||||||
1.,
|
1.,
|
||||||
1.,
|
1.,
|
||||||
)),
|
),
|
||||||
|
)];
|
||||||
|
|
||||||
|
// Then the upper layer-shell elements.
|
||||||
|
elements.extend(
|
||||||
|
upper
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|surface| {
|
||||||
|
layer_map
|
||||||
|
.layer_geometry(surface)
|
||||||
|
.map(|geo| (geo.loc, surface))
|
||||||
|
})
|
||||||
|
.flat_map(|(loc, surface)| {
|
||||||
|
surface
|
||||||
|
.render_elements(
|
||||||
|
renderer,
|
||||||
|
loc.to_physical_precise_round(1.),
|
||||||
|
Scale::from(1.),
|
||||||
|
1.,
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(OutputRenderElements::Wayland)
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Then the regular monitor elements.
|
||||||
|
elements.extend(monitor_elements.into_iter().map(OutputRenderElements::from));
|
||||||
|
|
||||||
|
// Then the lower layer-shell elements.
|
||||||
|
elements.extend(
|
||||||
|
lower
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|surface| {
|
||||||
|
layer_map
|
||||||
|
.layer_geometry(surface)
|
||||||
|
.map(|geo| (geo.loc, surface))
|
||||||
|
})
|
||||||
|
.flat_map(|(loc, surface)| {
|
||||||
|
surface
|
||||||
|
.render_elements(
|
||||||
|
renderer,
|
||||||
|
loc.to_physical_precise_round(1.),
|
||||||
|
Scale::from(1.),
|
||||||
|
1.,
|
||||||
|
)
|
||||||
|
.into_iter()
|
||||||
|
.map(OutputRenderElements::Wayland)
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Hand it over to the backend.
|
||||||
backend.render(self, output, &elements);
|
backend.render(self, output, &elements);
|
||||||
|
|
||||||
self.monitor_set
|
// Send frame callbacks.
|
||||||
.send_frame(output, self.start_time.elapsed());
|
let frame_callback_time = self.start_time.elapsed();
|
||||||
|
self.monitor_set.send_frame(output, frame_callback_time);
|
||||||
|
|
||||||
|
for surface in layer_map.layers() {
|
||||||
|
surface.send_frame(output, frame_callback_time, None, |_, _| {
|
||||||
|
Some(output.clone())
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render_elements! {
|
render_elements! {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub OutputRenderElements<R> where R: ImportAll;
|
pub OutputRenderElements<R> where R: ImportAll;
|
||||||
Wayland = MonitorRenderElement<R>,
|
Monitor = MonitorRenderElement<R>,
|
||||||
|
Wayland = WaylandSurfaceRenderElement<R>,
|
||||||
Pointer = SolidColorRenderElement,
|
Pointer = SolidColorRenderElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user