use crate::backend::BackendConnectorState;
use crate::backend::Connector;
use crate::backend::Mode;
use crate::backend::transaction::ConnectorTransaction;
use crate::client::ClientCaps;
use crate::fixed::Fixed;
use crate::format::XRGB8888;
use crate::ifs::wl_seat::WlSeatGlobal;
use crate::it::test_backend::TestBackend;
use crate::it::test_backend::TestBackendKb;
use crate::it::test_backend::TestBackendMouse;
use crate::it::test_backend::TestConnector;
use crate::it::test_client::TestClient;
use crate::it::test_config::TestConfig;
use crate::it::test_error::TestError;
use crate::it::test_error::TestErrorExt;
use crate::security_context_acceptor::AcceptorMetadata;
use crate::state::State;
use crate::tree::OutputNode;
use crate::tree::VrrMode;
use crate::utils::stack::Stack;
use crate::virtual_output::VirtualOutput;
use arrayvec::ArrayVec;
use std::rc::Rc;
use uapi::c;
pub struct TestRun {
pub state: Rc<State>,
pub backend: Rc<TestBackend>,
pub errors: Stack<String>,
pub out_dir: String,
pub in_dir: String,
pub cfg: Rc<TestConfig>,
}
impl TestRun {
pub fn create_client(self: &Rc<Self>) -> Result<TestClient, TestError> {
self.create_client2()
.with_context(|| "Could not create a client")
}
fn create_client2(self: &Rc<Self>) -> Result<TestClient, TestError> {
let (client1, client2) = uapi::socketpair(c::AF_UNIX, c::SOCK_STREAM | c::SOCK_CLOEXEC, 0)
.with_context(|| "Could not create a unix socket")?;
let client = self.state.clients.spawn2(
self.state.clients.id(),
&self.state,
Rc::new(client2),
uapi::getuid(),
uapi::getpid(),
ClientCaps::all(),
true,
false,
&Rc::new(AcceptorMetadata::secure()),
);
client.send_jay_compositor_enable_symmetric_delete();
Ok(TestClient {
run: self.clone(),
_socket: client1,
client,
})
}
pub fn get_seat(&self, name: &str) -> Result<Rc<WlSeatGlobal>, TestError> {
let id = self.cfg.get_seat(name)?;
for seat in self.state.globals.seats.lock().values() {
if seat.id() == id {
return Ok(seat.clone());
}
}
bail!("Seat {} does not exist", id)
}
pub async fn create_default_setup(&self) -> Result<DefaultSetup, TestError> {
self.create_default_setup2(false).await
}
pub async fn create_default_setup2(&self, need_drm: bool) -> Result<DefaultSetup, TestError> {
self.backend.install_default2(need_drm).await?;
let seat = self.get_seat("default")?;
self.state.eng.yield_now().await;
let output = match self.state.root.outputs.lock().values().next() {
None => bail!("No output"),
Some(d) => d.clone(),
};
self.cfg
.set_input_device_seat(self.backend.default_kb.common.id, seat.id())?;
self.cfg
.set_input_device_seat(self.backend.default_mouse.common.id, seat.id())?;
self.backend.default_mouse.click(1);
self.state.eng.yield_now().await;
self.cfg.show_workspace(seat.id(), "")?;
Ok(DefaultSetup {
connector: self.backend.default_connector.clone(),
output,
kb: self.backend.default_kb.clone(),
mouse: self.backend.default_mouse.clone(),
seat,
})
}
async fn create_virtual_output(
&self,
name: &str,
) -> Result<(Rc<VirtualOutput>, Rc<OutputNode>), TestError> {
let vo = self.state.virtual_outputs.get_or_create(&self.state, name);
let mut ct = ConnectorTransaction::new(&self.state);
ct.add(
&(vo.clone() as _),
BackendConnectorState {
serial: self.state.backend_connector_state_serials.next(),
enabled: true,
active: true,
mode: Mode {
width: 800,
height: 600,
refresh_rate_millihz: 0,
},
non_desktop_override: None,
vrr: true,
tearing: false,
format: XRGB8888,
color_space: Default::default(),
eotf: Default::default(),
gamma_lut: Default::default(),
},
)?;
ct.prepare()?.apply()?.commit();
self.sync().await;
let Some(node) = self.state.root.outputs.get(&vo.id()) else {
bail!("no output node");
};
Ok((vo, node))
}
pub async fn create_session_management_setup(&self) -> Result<SmSetup, TestError> {
self.backend.install_render_context(false)?;
let mut outputs = ArrayVec::new();
for i in 0..outputs.capacity() {
let (vo, node) = self.create_virtual_output(&format!("o{i}")).await?;
node.set_position(i as i32 * 800, 0);
node.set_vrr_mode(&VrrMode::Always);
outputs.push(SmOutput { vo, node });
}
self.state.fallback_output.set(Some(outputs[0].vo.id()));
Ok(SmSetup { outputs })
}
pub async fn sync(&self) {
self.state.eng.yield_now().await;
}
}
pub struct DefaultSetup {
pub connector: Rc<TestConnector>,
pub output: Rc<OutputNode>,
pub kb: Rc<TestBackendKb>,
pub mouse: Rc<TestBackendMouse>,
pub seat: Rc<WlSeatGlobal>,
}
impl DefaultSetup {
pub fn move_to(&self, x: i32, y: i32) {
let (ox, oy) = self.seat.pointer_cursor().position();
let (nx, ny) = (Fixed::from_int(x), Fixed::from_int(y));
let (dx, dy) = (nx - ox, ny - oy);
self.mouse.rel(dx.to_f64(), dy.to_f64());
}
}
pub struct SmSetup {
pub outputs: ArrayVec<SmOutput, 2>,
}
pub struct SmOutput {
vo: Rc<VirtualOutput>,
pub node: Rc<OutputNode>,
}