mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-21 02:01:55 +07:00
Add a Headless backend for tests
Rendering and stuff is unimplemented.
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
//! Headless backend for tests.
|
||||
//!
|
||||
//! This can eventually grow into a more complete backend if needed, but for now it's missing some
|
||||
//! crucial parts like rendering.
|
||||
|
||||
use std::mem;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use niri_config::OutputName;
|
||||
use smithay::backend::allocator::dmabuf::Dmabuf;
|
||||
use smithay::backend::renderer::element::RenderElementStates;
|
||||
use smithay::backend::renderer::gles::GlesRenderer;
|
||||
use smithay::output::{Mode, Output, PhysicalProperties, Subpixel};
|
||||
use smithay::reexports::wayland_protocols::wp::presentation_time::server::wp_presentation_feedback;
|
||||
use smithay::utils::Size;
|
||||
|
||||
use super::{IpcOutputMap, OutputId, RenderResult};
|
||||
use crate::niri::{Niri, RedrawState};
|
||||
use crate::utils::{get_monotonic_time, logical_output};
|
||||
|
||||
pub struct Headless {
|
||||
ipc_outputs: Arc<Mutex<IpcOutputMap>>,
|
||||
}
|
||||
|
||||
impl Headless {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
ipc_outputs: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self, _niri: &mut Niri) {}
|
||||
|
||||
pub fn add_output(&mut self, niri: &mut Niri, n: u8, size: (u16, u16)) {
|
||||
let connector = format!("headless-{n}");
|
||||
let make = "niri".to_string();
|
||||
let model = "headless".to_string();
|
||||
let serial = n.to_string();
|
||||
|
||||
let output = Output::new(
|
||||
connector.clone(),
|
||||
PhysicalProperties {
|
||||
size: (0, 0).into(),
|
||||
subpixel: Subpixel::Unknown,
|
||||
make: make.clone(),
|
||||
model: model.clone(),
|
||||
},
|
||||
);
|
||||
|
||||
let mode = Mode {
|
||||
size: Size::from((i32::from(size.0), i32::from(size.1))),
|
||||
refresh: 60_000,
|
||||
};
|
||||
output.change_current_state(Some(mode), None, None, None);
|
||||
output.set_preferred(mode);
|
||||
|
||||
output.user_data().insert_if_missing(|| OutputName {
|
||||
connector,
|
||||
make: Some(make),
|
||||
model: Some(model),
|
||||
serial: Some(serial),
|
||||
});
|
||||
|
||||
let physical_properties = output.physical_properties();
|
||||
self.ipc_outputs.lock().unwrap().insert(
|
||||
OutputId::next(),
|
||||
niri_ipc::Output {
|
||||
name: output.name(),
|
||||
make: physical_properties.make,
|
||||
model: physical_properties.model,
|
||||
serial: None,
|
||||
physical_size: None,
|
||||
modes: vec![niri_ipc::Mode {
|
||||
width: size.0,
|
||||
height: size.1,
|
||||
refresh_rate: 60_000,
|
||||
is_preferred: true,
|
||||
}],
|
||||
current_mode: Some(0),
|
||||
vrr_supported: false,
|
||||
vrr_enabled: false,
|
||||
logical: Some(logical_output(&output)),
|
||||
},
|
||||
);
|
||||
|
||||
niri.add_output(output, None, false);
|
||||
}
|
||||
|
||||
pub fn seat_name(&self) -> String {
|
||||
"headless".to_owned()
|
||||
}
|
||||
|
||||
pub fn with_primary_renderer<T>(
|
||||
&mut self,
|
||||
_f: impl FnOnce(&mut GlesRenderer) -> T,
|
||||
) -> Option<T> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn render(&mut self, niri: &mut Niri, output: &Output) -> RenderResult {
|
||||
let states = RenderElementStates::default();
|
||||
let mut presentation_feedbacks = niri.take_presentation_feedbacks(output, &states);
|
||||
presentation_feedbacks.presented::<_, smithay::utils::Monotonic>(
|
||||
get_monotonic_time(),
|
||||
std::time::Duration::ZERO,
|
||||
0,
|
||||
wp_presentation_feedback::Kind::empty(),
|
||||
);
|
||||
|
||||
let output_state = niri.output_state.get_mut(output).unwrap();
|
||||
match mem::replace(&mut output_state.redraw_state, RedrawState::Idle) {
|
||||
RedrawState::Idle => unreachable!(),
|
||||
RedrawState::Queued => (),
|
||||
RedrawState::WaitingForVBlank { .. } => unreachable!(),
|
||||
RedrawState::WaitingForEstimatedVBlank(_) => unreachable!(),
|
||||
RedrawState::WaitingForEstimatedVBlankAndQueued(_) => unreachable!(),
|
||||
}
|
||||
|
||||
output_state.frame_callback_sequence = output_state.frame_callback_sequence.wrapping_add(1);
|
||||
|
||||
// FIXME: request redraw on unfinished animations remain
|
||||
|
||||
RenderResult::Submitted
|
||||
}
|
||||
|
||||
pub fn import_dmabuf(&mut self, _dmabuf: &Dmabuf) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
pub fn ipc_outputs(&self) -> Arc<Mutex<IpcOutputMap>> {
|
||||
self.ipc_outputs.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Headless {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,13 @@ pub use tty::Tty;
|
||||
pub mod winit;
|
||||
pub use winit::Winit;
|
||||
|
||||
pub mod headless;
|
||||
pub use headless::Headless;
|
||||
|
||||
pub enum Backend {
|
||||
Tty(Tty),
|
||||
Winit(Winit),
|
||||
Headless(Headless),
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
@@ -54,6 +58,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.init(niri),
|
||||
Backend::Winit(winit) => winit.init(niri),
|
||||
Backend::Headless(headless) => headless.init(niri),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +66,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.seat_name(),
|
||||
Backend::Winit(winit) => winit.seat_name(),
|
||||
Backend::Headless(headless) => headless.seat_name(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +77,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.with_primary_renderer(f),
|
||||
Backend::Winit(winit) => winit.with_primary_renderer(f),
|
||||
Backend::Headless(headless) => headless.with_primary_renderer(f),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,6 +90,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.render(niri, output, target_presentation_time),
|
||||
Backend::Winit(winit) => winit.render(niri, output),
|
||||
Backend::Headless(headless) => headless.render(niri, output),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,6 +98,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(_) => CompositorMod::Super,
|
||||
Backend::Winit(_) => CompositorMod::Alt,
|
||||
Backend::Headless(_) => CompositorMod::Super,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +106,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.change_vt(vt),
|
||||
Backend::Winit(_) => (),
|
||||
Backend::Headless(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,6 +114,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.suspend(),
|
||||
Backend::Winit(_) => (),
|
||||
Backend::Headless(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +122,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.toggle_debug_tint(),
|
||||
Backend::Winit(winit) => winit.toggle_debug_tint(),
|
||||
Backend::Headless(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +130,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.import_dmabuf(dmabuf),
|
||||
Backend::Winit(winit) => winit.import_dmabuf(dmabuf),
|
||||
Backend::Headless(headless) => headless.import_dmabuf(dmabuf),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +138,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.early_import(surface),
|
||||
Backend::Winit(_) => (),
|
||||
Backend::Headless(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,6 +146,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.ipc_outputs(),
|
||||
Backend::Winit(winit) => winit.ipc_outputs(),
|
||||
Backend::Headless(headless) => headless.ipc_outputs(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +158,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.primary_gbm_device(),
|
||||
Backend::Winit(_) => None,
|
||||
Backend::Headless(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,6 +166,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.set_monitors_active(active),
|
||||
Backend::Winit(_) => (),
|
||||
Backend::Headless(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +174,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.set_output_on_demand_vrr(niri, output, enable_vrr),
|
||||
Backend::Winit(_) => (),
|
||||
Backend::Headless(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +182,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.on_output_config_changed(niri),
|
||||
Backend::Winit(_) => (),
|
||||
Backend::Headless(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,6 +190,7 @@ impl Backend {
|
||||
match self {
|
||||
Backend::Tty(tty) => tty.on_debug_config_changed(),
|
||||
Backend::Winit(_) => (),
|
||||
Backend::Headless(_) => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,4 +217,12 @@ impl Backend {
|
||||
panic!("backend is not Winit")
|
||||
}
|
||||
}
|
||||
|
||||
pub fn headless(&mut self) -> &mut Headless {
|
||||
if let Self::Headless(v) = self {
|
||||
v
|
||||
} else {
|
||||
panic!("backend is not Headless")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,6 +176,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
event_loop.handle(),
|
||||
event_loop.get_signal(),
|
||||
display,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
+6
-2
@@ -102,7 +102,7 @@ use smithay::wayland::xdg_foreign::XdgForeignState;
|
||||
|
||||
use crate::animation::Clock;
|
||||
use crate::backend::tty::SurfaceDmabufFeedback;
|
||||
use crate::backend::{Backend, RenderResult, Tty, Winit};
|
||||
use crate::backend::{Backend, Headless, RenderResult, Tty, Winit};
|
||||
use crate::cursor::{CursorManager, CursorTextureCache, RenderCursor, XCursor};
|
||||
#[cfg(feature = "dbus")]
|
||||
use crate::dbus::gnome_shell_introspect::{self, IntrospectToNiri, NiriToIntrospect};
|
||||
@@ -520,6 +520,7 @@ impl State {
|
||||
event_loop: LoopHandle<'static, State>,
|
||||
stop_signal: LoopSignal,
|
||||
display: Display<State>,
|
||||
headless: bool,
|
||||
) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
let _span = tracy_client::span!("State::new");
|
||||
|
||||
@@ -528,7 +529,10 @@ impl State {
|
||||
let has_display =
|
||||
env::var_os("WAYLAND_DISPLAY").is_some() || env::var_os("DISPLAY").is_some();
|
||||
|
||||
let mut backend = if has_display {
|
||||
let mut backend = if headless {
|
||||
let headless = Headless::new();
|
||||
Backend::Headless(headless)
|
||||
} else if has_display {
|
||||
let winit = Winit::new(config.clone(), event_loop.clone())?;
|
||||
Backend::Winit(winit)
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user