autocommit 2022-05-01 21:44:09 CEST
This commit is contained in:
parent
cca3850800
commit
04580c4aeb
38 changed files with 815 additions and 124 deletions
|
|
@ -2,26 +2,139 @@ use {
|
|||
crate::{
|
||||
async_engine::SpawnedFuture,
|
||||
backend::{
|
||||
Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, InputDevice,
|
||||
InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent,
|
||||
TransformMatrix,
|
||||
Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId,
|
||||
InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent,
|
||||
Mode, MonitorInfo, TransformMatrix,
|
||||
},
|
||||
compositor::TestFuture,
|
||||
render::{RenderContext, RenderError},
|
||||
state::State,
|
||||
utils::{clonecell::CloneCell, copyhashmap::CopyHashMap, syncqueue::SyncQueue},
|
||||
utils::{
|
||||
clonecell::CloneCell, copyhashmap::CopyHashMap, oserror::OsError, syncqueue::SyncQueue,
|
||||
},
|
||||
video::drm::{ConnectorType, Drm},
|
||||
},
|
||||
std::{any::Any, cell::Cell, error::Error, pin::Pin, rc::Rc},
|
||||
bstr::ByteSlice,
|
||||
std::{any::Any, cell::Cell, io, os::unix::ffi::OsStrExt, pin::Pin, rc::Rc},
|
||||
thiserror::Error,
|
||||
uapi::c,
|
||||
};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum TestBackendError {
|
||||
#[error("Could not read /dev/dri")]
|
||||
ReadDri(#[source] io::Error),
|
||||
#[error("There are no drm nodes in /dev/dri")]
|
||||
NoDrmNode,
|
||||
#[error("Could not open drm node {0}")]
|
||||
OpenDrmNode(String, #[source] OsError),
|
||||
#[error("Could not create a render context")]
|
||||
RenderContext(#[source] RenderError),
|
||||
}
|
||||
|
||||
pub struct TestBackend {
|
||||
pub state: Rc<State>,
|
||||
pub test_future: TestFuture,
|
||||
pub default_connector: Rc<TestConnector>,
|
||||
}
|
||||
|
||||
impl TestBackend {
|
||||
pub fn new(state: &Rc<State>, future: TestFuture) -> Self {
|
||||
let connector = Rc::new(TestConnector {
|
||||
id: state.connector_ids.next(),
|
||||
kernel_id: ConnectorKernelId {
|
||||
ty: ConnectorType::VGA,
|
||||
idx: 1,
|
||||
},
|
||||
events: Default::default(),
|
||||
on_change: Default::default(),
|
||||
});
|
||||
Self {
|
||||
state: state.clone(),
|
||||
test_future: future,
|
||||
default_connector: connector,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn install_default(&self) {
|
||||
self.state
|
||||
.backend_events
|
||||
.push(BackendEvent::NewConnector(self.default_connector.clone()));
|
||||
let mode = Mode {
|
||||
width: 800,
|
||||
height: 600,
|
||||
refresh_rate_millihz: 60_000,
|
||||
};
|
||||
self.default_connector
|
||||
.events
|
||||
.push(ConnectorEvent::Connected(MonitorInfo {
|
||||
modes: vec![mode],
|
||||
manufacturer: "jay".to_string(),
|
||||
product: "TestConnector".to_string(),
|
||||
serial_number: self.default_connector.id.to_string(),
|
||||
initial_mode: mode,
|
||||
width_mm: 80,
|
||||
height_mm: 60,
|
||||
}));
|
||||
}
|
||||
|
||||
fn create_render_context(&self) -> Result<(), TestBackendError> {
|
||||
let dri = match std::fs::read_dir("/dev/dri") {
|
||||
Ok(d) => d,
|
||||
Err(e) => return Err(TestBackendError::ReadDri(e)),
|
||||
};
|
||||
let mut files = vec![];
|
||||
for f in dri {
|
||||
let f = match f {
|
||||
Ok(f) => f,
|
||||
Err(e) => return Err(TestBackendError::ReadDri(e)),
|
||||
};
|
||||
files.push(f.path());
|
||||
}
|
||||
let node = 'node: {
|
||||
for f in &files {
|
||||
if let Some(file) = f.file_name() {
|
||||
if file.as_bytes().starts_with_str("renderD") {
|
||||
break 'node f;
|
||||
}
|
||||
}
|
||||
}
|
||||
for f in &files {
|
||||
if let Some(file) = f.file_name() {
|
||||
if file.as_bytes().starts_with_str("card") {
|
||||
break 'node f;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(TestBackendError::NoDrmNode);
|
||||
};
|
||||
let file = match uapi::open(node.as_path(), c::O_RDWR | c::O_CLOEXEC, 0) {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
return Err(TestBackendError::OpenDrmNode(
|
||||
node.as_os_str().as_bytes().as_bstr().to_string(),
|
||||
e.into(),
|
||||
))
|
||||
}
|
||||
};
|
||||
let drm = Drm::open_existing(file);
|
||||
let ctx = match RenderContext::from_drm_device(&drm) {
|
||||
Ok(ctx) => ctx,
|
||||
Err(e) => return Err(TestBackendError::RenderContext(e)),
|
||||
};
|
||||
self.state.set_render_ctx(&Rc::new(ctx));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Backend for TestBackend {
|
||||
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>> {
|
||||
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn std::error::Error>>> {
|
||||
let future = (self.test_future)(&self.state);
|
||||
let slf = self.clone();
|
||||
self.state.eng.spawn(async move {
|
||||
if let Err(e) = slf.create_render_context() {
|
||||
return Err(Box::new(e) as Box<_>);
|
||||
}
|
||||
let future: Pin<_> = future.into();
|
||||
future.await;
|
||||
Ok(())
|
||||
|
|
@ -72,7 +185,7 @@ impl Connector for TestConnector {
|
|||
}
|
||||
|
||||
fn damage(&self) {
|
||||
todo!()
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
use {
|
||||
crate::{
|
||||
cli::screenshot::buf_to_qoi,
|
||||
client::Client,
|
||||
it::{
|
||||
test_error::TestError,
|
||||
test_ifs::{
|
||||
test_compositor::TestCompositor, test_jay_compositor::TestJayCompositor,
|
||||
test_registry::TestRegistry, test_shm::TestShm,
|
||||
test_registry::TestRegistry, test_shm::TestShm, test_xdg_base::TestXdgWmBase,
|
||||
},
|
||||
test_transport::TestTransport,
|
||||
testrun::TestRun,
|
||||
|
|
@ -16,19 +18,32 @@ use {
|
|||
pub struct TestClient {
|
||||
pub run: Rc<TestRun>,
|
||||
pub server: Rc<Client>,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub registry: Rc<TestRegistry>,
|
||||
pub jc: Rc<TestJayCompositor>,
|
||||
pub comp: Rc<TestCompositor>,
|
||||
pub shm: Rc<TestShm>,
|
||||
pub xdg: Rc<TestXdgWmBase>,
|
||||
}
|
||||
|
||||
impl TestClient {
|
||||
pub fn error(&self, msg: &str) {
|
||||
self.transport.error(msg)
|
||||
self.tran.error(msg)
|
||||
}
|
||||
|
||||
pub async fn sync(self: &Rc<Self>) {
|
||||
self.transport.sync().await
|
||||
self.tran.sync().await
|
||||
}
|
||||
|
||||
pub async fn take_screenshot(&self) -> Result<Vec<u8>, TestError> {
|
||||
let dmabuf = self.jc.take_screenshot().await?;
|
||||
let qoi = buf_to_qoi(&dmabuf);
|
||||
Ok(qoi)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestClient {
|
||||
fn drop(&mut self) {
|
||||
self.tran.kill();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,11 @@ pub mod test_compositor;
|
|||
pub mod test_display;
|
||||
pub mod test_jay_compositor;
|
||||
pub mod test_registry;
|
||||
pub mod test_screenshot;
|
||||
pub mod test_shm;
|
||||
pub mod test_shm_buffer;
|
||||
pub mod test_shm_pool;
|
||||
pub mod test_surface;
|
||||
pub mod test_xdg_base;
|
||||
pub mod test_xdg_surface;
|
||||
pub mod test_xdg_toplevel;
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use {
|
|||
|
||||
pub struct TestCallback {
|
||||
pub id: WlCallbackId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub handler: Cell<Option<Box<dyn FnOnce()>>>,
|
||||
pub done: Cell<bool>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,38 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{test_object::TestObject, test_transport::TestTransport},
|
||||
wire::WlCompositorId,
|
||||
it::{
|
||||
test_error::TestError, test_ifs::test_surface::TestSurface, test_object::TestObject,
|
||||
test_transport::TestTransport,
|
||||
},
|
||||
wire::{wl_compositor::CreateSurface, WlCompositorId},
|
||||
},
|
||||
std::rc::Rc,
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestCompositor {
|
||||
pub id: WlCompositorId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub tran: Rc<TestTransport>,
|
||||
}
|
||||
|
||||
impl TestCompositor {
|
||||
pub async fn create_surface(&self) -> Result<Rc<TestSurface>, TestError> {
|
||||
let id = self.tran.id();
|
||||
self.tran.send(CreateSurface {
|
||||
self_id: self.id,
|
||||
id,
|
||||
});
|
||||
self.tran.sync().await;
|
||||
let client = self.tran.get_client()?;
|
||||
let server = client.lookup(id)?;
|
||||
let surface = Rc::new(TestSurface {
|
||||
id,
|
||||
tran: self.tran.clone(),
|
||||
server,
|
||||
destroyed: Cell::new(false),
|
||||
});
|
||||
self.tran.add_obj(surface.clone())?;
|
||||
Ok(surface)
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use {
|
|||
};
|
||||
|
||||
pub struct TestDisplay {
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub id: WlDisplayId,
|
||||
}
|
||||
|
||||
|
|
@ -20,25 +20,25 @@ impl TestDisplay {
|
|||
fn handle_error(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Error::parse_full(parser)?;
|
||||
let msg = format!("Compositor sent an error: {}", ev.message);
|
||||
self.transport.error(&msg);
|
||||
self.transport.kill();
|
||||
self.tran.error(&msg);
|
||||
self.tran.kill();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_delete_id(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = DeleteId::parse_full(parser)?;
|
||||
match self.transport.objects.remove(&ObjectId::from_raw(ev.id)) {
|
||||
match self.tran.objects.remove(&ObjectId::from_raw(ev.id)) {
|
||||
None => {
|
||||
let msg = format!(
|
||||
"Compositor sent delete_id for object {} which does not exist",
|
||||
ev.id
|
||||
);
|
||||
self.transport.error(&msg);
|
||||
self.transport.kill();
|
||||
self.tran.error(&msg);
|
||||
self.tran.kill();
|
||||
}
|
||||
Some(obj) => {
|
||||
obj.on_remove(&self.transport);
|
||||
self.transport.obj_ids.borrow_mut().release(ev.id);
|
||||
obj.on_remove(&self.tran);
|
||||
self.tran.obj_ids.borrow_mut().release(ev.id);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@ use {
|
|||
crate::{
|
||||
client::ClientId,
|
||||
it::{
|
||||
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
||||
testrun::ParseFull,
|
||||
test_error::TestError, test_ifs::test_screenshot::TestJayScreenshot,
|
||||
test_object::TestObject, test_transport::TestTransport, testrun::ParseFull,
|
||||
},
|
||||
utils::buffd::MsgParser,
|
||||
wire::{
|
||||
jay_compositor::{self, *},
|
||||
jay_screenshot::Dmabuf,
|
||||
JayCompositorId,
|
||||
},
|
||||
},
|
||||
|
|
@ -16,25 +17,44 @@ use {
|
|||
|
||||
pub struct TestJayCompositor {
|
||||
pub id: JayCompositorId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub client_id: Cell<Option<ClientId>>,
|
||||
}
|
||||
|
||||
impl TestJayCompositor {
|
||||
pub async fn get_client_id(&self) -> Result<ClientId, TestError> {
|
||||
if self.client_id.get().is_none() {
|
||||
self.transport.send(GetClientId { self_id: self.id });
|
||||
self.tran.send(GetClientId { self_id: self.id });
|
||||
}
|
||||
self.transport.sync().await;
|
||||
self.tran.sync().await;
|
||||
match self.client_id.get() {
|
||||
Some(c) => Ok(c),
|
||||
_ => bail!("Compositor did not send a client id"),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn take_screenshot(&self) -> Result<Dmabuf, TestError> {
|
||||
let js = Rc::new(TestJayScreenshot {
|
||||
id: self.tran.id(),
|
||||
result: Cell::new(None),
|
||||
});
|
||||
self.tran.send(TakeScreenshot {
|
||||
self_id: self.id,
|
||||
id: js.id,
|
||||
});
|
||||
self.tran.add_obj(js.clone())?;
|
||||
self.tran.sync().await;
|
||||
match js.result.take() {
|
||||
Some(Ok(res)) => Ok(res),
|
||||
Some(Err(res)) => bail!("Compositor could not take a screenshot: {}", res),
|
||||
None => bail!("Compositor did not send a screenshot"),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_client_id(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = jay_compositor::ClientId::parse_full(parser)?;
|
||||
self.client_id.set(Some(ClientId::from_raw(ev.client_id)));
|
||||
self.tran.client_id.set(ClientId::from_raw(ev.client_id));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ use {
|
|||
test_error::TestError,
|
||||
test_ifs::{
|
||||
test_compositor::TestCompositor, test_jay_compositor::TestJayCompositor,
|
||||
test_shm::TestShm,
|
||||
test_shm::TestShm, test_xdg_base::TestXdgWmBase,
|
||||
},
|
||||
test_object::TestObject,
|
||||
test_transport::TestTransport,
|
||||
|
|
@ -26,16 +26,18 @@ pub struct TestRegistrySingletons {
|
|||
pub jay_compositor: u32,
|
||||
pub wl_compositor: u32,
|
||||
pub wl_shm: u32,
|
||||
pub xdg_wm_base: u32,
|
||||
}
|
||||
|
||||
pub struct TestRegistry {
|
||||
pub id: WlRegistryId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub globals: CopyHashMap<u32, Rc<TestGlobal>>,
|
||||
pub singletons: CloneCell<Option<Rc<TestRegistrySingletons>>>,
|
||||
pub jay_compositor: CloneCell<Option<Rc<TestJayCompositor>>>,
|
||||
pub compositor: CloneCell<Option<Rc<TestCompositor>>>,
|
||||
pub shm: CloneCell<Option<Rc<TestShm>>>,
|
||||
pub xdg: CloneCell<Option<Rc<TestXdgWmBase>>>,
|
||||
}
|
||||
|
||||
macro_rules! singleton {
|
||||
|
|
@ -49,22 +51,22 @@ macro_rules! singleton {
|
|||
impl TestRegistry {
|
||||
pub async fn get_singletons(&self) -> Result<Rc<TestRegistrySingletons>, TestError> {
|
||||
singleton!(self.singletons);
|
||||
self.transport.sync().await;
|
||||
self.tran.sync().await;
|
||||
singleton!(self.singletons);
|
||||
let mut jay_compositor = 0;
|
||||
let mut wl_compositor = 0;
|
||||
let mut wl_shm = 0;
|
||||
for global in self.globals.lock().values() {
|
||||
match global.interface.as_str() {
|
||||
"jay_compositor" => jay_compositor = global.name,
|
||||
"wl_compositor" => wl_compositor = global.name,
|
||||
"wl_shm" => wl_shm = global.name,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
macro_rules! singleton {
|
||||
($($name:ident,)*) => {
|
||||
TestRegistrySingletons {
|
||||
($($name:ident,)*) => {{
|
||||
$(
|
||||
let mut $name = 0;
|
||||
)*
|
||||
for global in self.globals.lock().values() {
|
||||
match global.interface.as_str() {
|
||||
$(
|
||||
stringify!($name) => $name = global.name,
|
||||
)*
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Rc::new(TestRegistrySingletons {
|
||||
$(
|
||||
$name: {
|
||||
if $name == 0 {
|
||||
|
|
@ -73,14 +75,15 @@ impl TestRegistry {
|
|||
$name
|
||||
},
|
||||
)*
|
||||
}
|
||||
}
|
||||
})
|
||||
}}
|
||||
}
|
||||
let singletons = Rc::new(singleton! {
|
||||
let singletons = singleton! {
|
||||
jay_compositor,
|
||||
wl_compositor,
|
||||
wl_shm,
|
||||
});
|
||||
xdg_wm_base,
|
||||
};
|
||||
self.singletons.set(Some(singletons.clone()));
|
||||
Ok(singletons)
|
||||
}
|
||||
|
|
@ -90,8 +93,8 @@ impl TestRegistry {
|
|||
let singletons = self.get_singletons().await?;
|
||||
singleton!(self.jay_compositor);
|
||||
let jc = Rc::new(TestJayCompositor {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
id: self.tran.id(),
|
||||
tran: self.tran.clone(),
|
||||
client_id: Default::default(),
|
||||
});
|
||||
self.bind(&jc, singletons.jay_compositor, 1)?;
|
||||
|
|
@ -104,8 +107,8 @@ impl TestRegistry {
|
|||
let singletons = self.get_singletons().await?;
|
||||
singleton!(self.compositor);
|
||||
let jc = Rc::new(TestCompositor {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
id: self.tran.id(),
|
||||
tran: self.tran.clone(),
|
||||
});
|
||||
self.bind(&jc, singletons.wl_compositor, 4)?;
|
||||
self.compositor.set(Some(jc.clone()));
|
||||
|
|
@ -117,8 +120,8 @@ impl TestRegistry {
|
|||
let singletons = self.get_singletons().await?;
|
||||
singleton!(self.shm);
|
||||
let jc = Rc::new(TestShm {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
id: self.tran.id(),
|
||||
tran: self.tran.clone(),
|
||||
formats: Default::default(),
|
||||
formats_awaited: Cell::new(false),
|
||||
});
|
||||
|
|
@ -127,20 +130,34 @@ impl TestRegistry {
|
|||
Ok(jc)
|
||||
}
|
||||
|
||||
pub async fn get_xdg(&self) -> Result<Rc<TestXdgWmBase>, TestError> {
|
||||
singleton!(self.xdg);
|
||||
let singletons = self.get_singletons().await?;
|
||||
singleton!(self.xdg);
|
||||
let jc = Rc::new(TestXdgWmBase {
|
||||
id: self.tran.id(),
|
||||
tran: self.tran.clone(),
|
||||
destroyed: Cell::new(false),
|
||||
});
|
||||
self.bind(&jc, singletons.xdg_wm_base, 3)?;
|
||||
self.xdg.set(Some(jc.clone()));
|
||||
Ok(jc)
|
||||
}
|
||||
|
||||
pub fn bind<O: TestObject>(
|
||||
&self,
|
||||
obj: &Rc<O>,
|
||||
name: u32,
|
||||
version: u32,
|
||||
) -> Result<(), TestError> {
|
||||
self.transport.send(Bind {
|
||||
self.tran.send(Bind {
|
||||
self_id: self.id,
|
||||
name,
|
||||
interface: obj.interface().name(),
|
||||
version,
|
||||
id: obj.id().into(),
|
||||
});
|
||||
self.transport.add_obj(obj.clone())?;
|
||||
self.tran.add_obj(obj.clone())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +172,7 @@ impl TestRegistry {
|
|||
}),
|
||||
);
|
||||
if prev.is_some() {
|
||||
self.transport.error(&format!(
|
||||
self.tran.error(&format!(
|
||||
"Compositor sent global {} multiple times",
|
||||
ev.name
|
||||
));
|
||||
|
|
@ -166,7 +183,7 @@ impl TestRegistry {
|
|||
fn handle_global_remove(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = GlobalRemove::parse_full(parser)?;
|
||||
if self.globals.remove(&ev.name).is_none() {
|
||||
self.transport.error(&format!(
|
||||
self.tran.error(&format!(
|
||||
"Compositor sent global_remove for {} which does not exist",
|
||||
ev.name
|
||||
));
|
||||
|
|
|
|||
36
src/it/test_ifs/test_screenshot.rs
Normal file
36
src/it/test_ifs/test_screenshot.rs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{test_error::TestError, test_object::TestObject, testrun::ParseFull},
|
||||
utils::buffd::MsgParser,
|
||||
wire::{jay_screenshot::*, JayScreenshotId},
|
||||
},
|
||||
std::cell::Cell,
|
||||
};
|
||||
|
||||
pub struct TestJayScreenshot {
|
||||
pub id: JayScreenshotId,
|
||||
pub result: Cell<Option<Result<Dmabuf, String>>>,
|
||||
}
|
||||
|
||||
impl TestJayScreenshot {
|
||||
fn handle_dmabuf(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Dmabuf::parse_full(parser)?;
|
||||
self.result.set(Some(Ok(ev)));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_error(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Error::parse_full(parser)?;
|
||||
self.result.set(Some(Err(ev.msg.to_string())));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestJayScreenshot, JayScreenshot;
|
||||
|
||||
DMABUF => handle_dmabuf,
|
||||
ERROR => handle_error,
|
||||
}
|
||||
|
||||
impl TestObject for TestJayScreenshot {}
|
||||
|
|
@ -12,7 +12,7 @@ use {
|
|||
|
||||
pub struct TestShm {
|
||||
pub id: WlShmId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub formats: CopyHashMap<u32, ()>,
|
||||
pub formats_awaited: Cell<bool>,
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@ pub struct TestShm {
|
|||
impl TestShm {
|
||||
pub async fn formats(&self) -> &CopyHashMap<u32, ()> {
|
||||
if !self.formats_awaited.replace(true) {
|
||||
self.transport.sync().await;
|
||||
self.tran.sync().await;
|
||||
}
|
||||
&self.formats
|
||||
}
|
||||
|
|
@ -28,18 +28,18 @@ impl TestShm {
|
|||
pub fn create_pool(&self, size: usize) -> Result<Rc<TestShmPool>, TestError> {
|
||||
let mem = TestMem::new(size)?;
|
||||
let pool = Rc::new(TestShmPool {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
id: self.tran.id(),
|
||||
tran: self.tran.clone(),
|
||||
mem: CloneCell::new(mem.clone()),
|
||||
destroyed: Cell::new(false),
|
||||
});
|
||||
self.transport.send(CreatePool {
|
||||
self.tran.send(CreatePool {
|
||||
self_id: self.id,
|
||||
id: pool.id,
|
||||
fd: mem.fd.clone(),
|
||||
size: size as _,
|
||||
});
|
||||
self.transport.add_obj(pool.clone())?;
|
||||
self.tran.add_obj(pool.clone())?;
|
||||
Ok(pool)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ use {
|
|||
test_error::TestError, test_mem::TestMem, test_object::TestObject,
|
||||
test_transport::TestTransport, testrun::ParseFull,
|
||||
},
|
||||
utils::buffd::MsgParser,
|
||||
theme::Color,
|
||||
utils::{buffd::MsgParser, windows::WindowsExt},
|
||||
wire::{wl_buffer::*, WlBufferId},
|
||||
},
|
||||
std::{
|
||||
|
|
@ -16,7 +17,7 @@ use {
|
|||
|
||||
pub struct TestShmBuffer {
|
||||
pub id: WlBufferId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub range: Range<usize>,
|
||||
pub mem: Rc<TestMem>,
|
||||
pub released: Cell<bool>,
|
||||
|
|
@ -24,11 +25,21 @@ pub struct TestShmBuffer {
|
|||
}
|
||||
|
||||
impl TestShmBuffer {
|
||||
pub fn fill(&self, color: Color) {
|
||||
let [cr, cg, cb, ca] = color.to_rgba_premultiplied();
|
||||
for [b, g, r, a] in self.deref().array_chunks_ext::<4>() {
|
||||
r.set(cr);
|
||||
g.set(cg);
|
||||
b.set(cb);
|
||||
a.set(ca);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn destroy(&self) {
|
||||
if self.destroyed.replace(true) {
|
||||
return;
|
||||
}
|
||||
self.transport.send(Destroy { self_id: self.id });
|
||||
self.tran.send(Destroy { self_id: self.id });
|
||||
}
|
||||
|
||||
fn handle_release(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ use {
|
|||
|
||||
pub struct TestShmPool {
|
||||
pub id: WlShmPoolId,
|
||||
pub transport: Rc<TestTransport>,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub mem: CloneCell<Rc<TestMem>>,
|
||||
pub destroyed: Cell<bool>,
|
||||
}
|
||||
|
|
@ -35,15 +35,15 @@ impl TestShmPool {
|
|||
bail!("Out-of-bounds buffer");
|
||||
}
|
||||
let buffer = Rc::new(TestShmBuffer {
|
||||
id: self.transport.id(),
|
||||
transport: self.transport.clone(),
|
||||
id: self.tran.id(),
|
||||
tran: self.tran.clone(),
|
||||
range: start..end,
|
||||
mem,
|
||||
released: Cell::new(true),
|
||||
destroyed: Cell::new(false),
|
||||
});
|
||||
self.transport.add_obj(buffer.clone())?;
|
||||
self.transport.send(CreateBuffer {
|
||||
self.tran.add_obj(buffer.clone())?;
|
||||
self.tran.send(CreateBuffer {
|
||||
self_id: self.id,
|
||||
id: buffer.id,
|
||||
offset,
|
||||
|
|
@ -58,7 +58,7 @@ impl TestShmPool {
|
|||
pub fn resize(&self, size: usize) -> Result<(), TestError> {
|
||||
let mem = self.mem.get().grow(size)?;
|
||||
self.mem.set(mem);
|
||||
self.transport.send(Resize {
|
||||
self.tran.send(Resize {
|
||||
self_id: self.id,
|
||||
size: size as _,
|
||||
});
|
||||
|
|
@ -69,7 +69,7 @@ impl TestShmPool {
|
|||
if self.destroyed.replace(true) {
|
||||
return;
|
||||
}
|
||||
self.transport.send(Destroy { self_id: self.id });
|
||||
self.tran.send(Destroy { self_id: self.id });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
65
src/it/test_ifs/test_surface.rs
Normal file
65
src/it/test_ifs/test_surface.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
use {
|
||||
crate::{
|
||||
ifs::wl_surface::WlSurface,
|
||||
it::{
|
||||
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
||||
testrun::ParseFull,
|
||||
},
|
||||
utils::buffd::MsgParser,
|
||||
wire::{wl_surface::*, WlBufferId, WlSurfaceId},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestSurface {
|
||||
pub id: WlSurfaceId,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub server: Rc<WlSurface>,
|
||||
pub destroyed: Cell<bool>,
|
||||
}
|
||||
|
||||
impl TestSurface {
|
||||
pub fn destroy(&self) {
|
||||
if !self.destroyed.replace(true) {
|
||||
self.tran.send(Destroy { self_id: self.id });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn attach(&self, buffer_id: WlBufferId) {
|
||||
self.tran.send(Attach {
|
||||
self_id: self.id,
|
||||
buffer: buffer_id,
|
||||
x: 0,
|
||||
y: 0,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn commit(&self) {
|
||||
self.tran.send(Commit { self_id: self.id });
|
||||
}
|
||||
|
||||
fn handle_enter(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let _ev = Enter::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_leave(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let _ev = Leave::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestSurface {
|
||||
fn drop(&mut self) {
|
||||
self.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestSurface, WlSurface;
|
||||
|
||||
ENTER => handle_enter,
|
||||
LEAVE => handle_leave,
|
||||
}
|
||||
|
||||
impl TestObject for TestSurface {}
|
||||
68
src/it/test_ifs/test_xdg_base.rs
Normal file
68
src/it/test_ifs/test_xdg_base.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
use {
|
||||
crate::{
|
||||
it::{
|
||||
test_error::TestError, test_ifs::test_xdg_surface::TestXdgSurface,
|
||||
test_object::TestObject, test_transport::TestTransport, testrun::ParseFull,
|
||||
},
|
||||
utils::buffd::MsgParser,
|
||||
wire::{xdg_wm_base::*, WlSurfaceId, XdgWmBaseId},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestXdgWmBase {
|
||||
pub id: XdgWmBaseId,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub destroyed: Cell<bool>,
|
||||
}
|
||||
|
||||
impl TestXdgWmBase {
|
||||
pub fn destroy(&self) {
|
||||
if !self.destroyed.replace(true) {
|
||||
self.tran.send(Destroy { self_id: self.id });
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_xdg_surface(
|
||||
&self,
|
||||
surface: WlSurfaceId,
|
||||
) -> Result<Rc<TestXdgSurface>, TestError> {
|
||||
let id = self.tran.id();
|
||||
self.tran.send(GetXdgSurface {
|
||||
self_id: self.id,
|
||||
id,
|
||||
surface,
|
||||
});
|
||||
self.tran.sync().await;
|
||||
let client = self.tran.get_client()?;
|
||||
let server = client.lookup(id)?;
|
||||
let xdg = Rc::new(TestXdgSurface {
|
||||
id,
|
||||
tran: self.tran.clone(),
|
||||
server,
|
||||
destroyed: Cell::new(false),
|
||||
last_serial: Cell::new(0),
|
||||
});
|
||||
self.tran.add_obj(xdg.clone())?;
|
||||
Ok(xdg)
|
||||
}
|
||||
|
||||
fn handle_ping(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let _ev = Ping::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestXdgWmBase, XdgWmBase;
|
||||
|
||||
PING => handle_ping,
|
||||
}
|
||||
|
||||
impl TestObject for TestXdgWmBase {}
|
||||
|
||||
impl Drop for TestXdgWmBase {
|
||||
fn drop(&mut self) {
|
||||
self.destroy();
|
||||
}
|
||||
}
|
||||
78
src/it/test_ifs/test_xdg_surface.rs
Normal file
78
src/it/test_ifs/test_xdg_surface.rs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
use {
|
||||
crate::{
|
||||
ifs::wl_surface::xdg_surface::XdgSurface,
|
||||
it::{
|
||||
test_error::TestError, test_ifs::test_xdg_toplevel::TestXdgToplevel,
|
||||
test_object::TestObject, test_transport::TestTransport, testrun::ParseFull,
|
||||
},
|
||||
utils::buffd::MsgParser,
|
||||
wire::{xdg_surface::*, XdgSurfaceId},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestXdgSurface {
|
||||
pub id: XdgSurfaceId,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub server: Rc<XdgSurface>,
|
||||
pub destroyed: Cell<bool>,
|
||||
pub last_serial: Cell<u32>,
|
||||
}
|
||||
|
||||
impl TestXdgSurface {
|
||||
pub fn destroy(&self) {
|
||||
if !self.destroyed.replace(true) {
|
||||
self.tran.send(Destroy { self_id: self.id });
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_toplevel(&self) -> Result<Rc<TestXdgToplevel>, TestError> {
|
||||
let id = self.tran.id();
|
||||
self.tran.send(GetToplevel {
|
||||
self_id: self.id,
|
||||
id,
|
||||
});
|
||||
self.tran.sync().await;
|
||||
let client = self.tran.get_client()?;
|
||||
let server = client.lookup(id)?;
|
||||
let tl = Rc::new(TestXdgToplevel {
|
||||
id,
|
||||
tran: self.tran.clone(),
|
||||
destroyed: Cell::new(false),
|
||||
server,
|
||||
width: Cell::new(0),
|
||||
height: Cell::new(0),
|
||||
states: Default::default(),
|
||||
close_requested: Cell::new(false),
|
||||
});
|
||||
self.tran.add_obj(tl.clone())?;
|
||||
Ok(tl)
|
||||
}
|
||||
|
||||
pub fn ack_configure(&self, serial: u32) {
|
||||
self.tran.send(AckConfigure {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Configure::parse_full(parser)?;
|
||||
self.last_serial.set(ev.serial);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestXdgSurface {
|
||||
fn drop(&mut self) {
|
||||
self.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestXdgSurface, XdgSurface;
|
||||
|
||||
CONFIGURE => handle_configure,
|
||||
}
|
||||
|
||||
impl TestObject for TestXdgSurface {}
|
||||
72
src/it/test_ifs/test_xdg_toplevel.rs
Normal file
72
src/it/test_ifs/test_xdg_toplevel.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
use {
|
||||
crate::{
|
||||
ifs::wl_surface::xdg_surface::xdg_toplevel::XdgToplevel,
|
||||
it::{
|
||||
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
||||
testrun::ParseFull,
|
||||
},
|
||||
utils::buffd::MsgParser,
|
||||
wire::{xdg_toplevel::*, XdgToplevelId},
|
||||
},
|
||||
ahash::AHashSet,
|
||||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
rc::Rc,
|
||||
},
|
||||
};
|
||||
|
||||
pub struct TestXdgToplevel {
|
||||
pub id: XdgToplevelId,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub destroyed: Cell<bool>,
|
||||
pub server: Rc<XdgToplevel>,
|
||||
|
||||
pub width: Cell<i32>,
|
||||
pub height: Cell<i32>,
|
||||
pub states: RefCell<AHashSet<u32>>,
|
||||
|
||||
pub close_requested: Cell<bool>,
|
||||
}
|
||||
|
||||
impl TestXdgToplevel {
|
||||
pub fn destroy(&self) {
|
||||
if !self.destroyed.replace(true) {
|
||||
self.tran.send(Destroy { self_id: self.id });
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Configure::parse_full(parser)?;
|
||||
self.width.set(ev.width);
|
||||
self.height.set(ev.height);
|
||||
*self.states.borrow_mut() = ev.states.iter().copied().collect();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_close(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let _ev = Close::parse_full(parser)?;
|
||||
self.close_requested.set(true);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_configure_bounds(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let _ev = ConfigureBounds::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestXdgToplevel {
|
||||
fn drop(&mut self) {
|
||||
self.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestXdgToplevel, XdgToplevel;
|
||||
|
||||
CONFIGURE => handle_configure,
|
||||
CLOSE => handle_close,
|
||||
CONFIGURE_BOUNDS => handle_configure_bounds,
|
||||
}
|
||||
|
||||
impl TestObject for TestXdgToplevel {}
|
||||
|
|
@ -46,6 +46,9 @@ impl Deref for TestMem {
|
|||
}
|
||||
|
||||
fn map(fd: c::c_int, size: usize) -> Result<*const [Cell<u8>], TestError> {
|
||||
if size == 0 {
|
||||
return Ok(&[]);
|
||||
}
|
||||
unsafe {
|
||||
let res = c::mmap(
|
||||
ptr::null_mut(),
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ macro_rules! test_object {
|
|||
$(
|
||||
$code => $oname::$f(&self, parser).with_context(|| format!("While handling a `{}` event", stringify!($f))),
|
||||
)*
|
||||
_ => Err(crate::it::test_error::TestError::new("Unknown event {}")),
|
||||
_ => Err(crate::it::test_error::TestError::new(format!("Unknown event {}", request))),
|
||||
};
|
||||
res.with_context(|| format!("In object {} of type `{}`", self.id(), self.interface().name()))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use {
|
||||
crate::{
|
||||
async_engine::{AsyncFd, SpawnedFuture},
|
||||
client::{ClientId, EventFormatter},
|
||||
client::{Client, ClientId, EventFormatter},
|
||||
it::{
|
||||
test_error::{StdError, TestError},
|
||||
test_ifs::{test_callback::TestCallback, test_registry::TestRegistry},
|
||||
|
|
@ -47,12 +47,13 @@ impl TestTransport {
|
|||
pub fn get_registry(self: &Rc<Self>) -> Rc<TestRegistry> {
|
||||
let reg = Rc::new(TestRegistry {
|
||||
id: self.id(),
|
||||
transport: self.clone(),
|
||||
tran: self.clone(),
|
||||
globals: Default::default(),
|
||||
singletons: Default::default(),
|
||||
jay_compositor: Default::default(),
|
||||
compositor: Default::default(),
|
||||
shm: Default::default(),
|
||||
xdg: Default::default(),
|
||||
});
|
||||
self.send(wl_display::GetRegistry {
|
||||
self_id: WL_DISPLAY_ID,
|
||||
|
|
@ -62,6 +63,14 @@ impl TestTransport {
|
|||
reg
|
||||
}
|
||||
|
||||
pub fn get_client(&self) -> Result<Rc<Client>, TestError> {
|
||||
self.run
|
||||
.state
|
||||
.clients
|
||||
.get(self.client_id.get())
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn add_obj(&self, obj: Rc<dyn TestObject>) -> Result<(), TestError> {
|
||||
if self.killed.get() {
|
||||
bail!("Transport has already been killed");
|
||||
|
|
@ -84,7 +93,7 @@ impl TestTransport {
|
|||
pub fn sync(self: &Rc<Self>) -> impl Future<Output = ()> {
|
||||
let cb = Rc::new(TestCallback {
|
||||
id: self.id(),
|
||||
transport: self.clone(),
|
||||
tran: self.clone(),
|
||||
handler: Cell::new(None),
|
||||
done: Cell::new(self.killed.get()),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ pub struct TestRun {
|
|||
pub backend: Rc<TestBackend>,
|
||||
pub errors: Stack<String>,
|
||||
pub server_addr: c::sockaddr_un,
|
||||
pub dir: String,
|
||||
}
|
||||
|
||||
impl TestRun {
|
||||
|
|
@ -53,7 +54,7 @@ impl TestRun {
|
|||
let mut obj_ids = Bitfield::default();
|
||||
obj_ids.take(0);
|
||||
obj_ids.take(1);
|
||||
let transport = Rc::new(TestTransport {
|
||||
let tran = Rc::new(TestTransport {
|
||||
run: self.clone(),
|
||||
fd,
|
||||
client_id: Cell::new(ClientId::from_raw(0)),
|
||||
|
|
@ -66,22 +67,23 @@ impl TestRun {
|
|||
obj_ids: RefCell::new(obj_ids),
|
||||
killed: Cell::new(false),
|
||||
});
|
||||
transport.add_obj(Rc::new(TestDisplay {
|
||||
transport: transport.clone(),
|
||||
tran.add_obj(Rc::new(TestDisplay {
|
||||
tran: tran.clone(),
|
||||
id: WL_DISPLAY_ID,
|
||||
}))?;
|
||||
transport.init();
|
||||
let registry = transport.get_registry();
|
||||
tran.init();
|
||||
let registry = tran.get_registry();
|
||||
let jc = registry.get_jay_compositor().await?;
|
||||
let client_id = jc.get_client_id().await?;
|
||||
let client = self.state.clients.get(client_id)?;
|
||||
Ok(Rc::new(TestClient {
|
||||
run: self.clone(),
|
||||
server: client,
|
||||
transport,
|
||||
tran,
|
||||
jc,
|
||||
comp: registry.get_compositor().await?,
|
||||
shm: registry.get_shm().await?,
|
||||
xdg: registry.get_xdg().await?,
|
||||
registry,
|
||||
}))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,26 @@ macro_rules! tassert {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! tassert_eq {
|
||||
($left:expr, $right:expr) => {{
|
||||
let left = $left;
|
||||
let right = $right;
|
||||
if left != right {
|
||||
bail!(
|
||||
"Assert `{} = {:?} = {:?} = {}` failed ({}:{})",
|
||||
stringify!($left),
|
||||
left,
|
||||
right,
|
||||
stringify!($right),
|
||||
file!(),
|
||||
line!()
|
||||
);
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
mod t0001_shm_formats;
|
||||
mod t0002_window;
|
||||
|
||||
pub trait TestCase {
|
||||
fn name(&self) -> &'static str;
|
||||
|
|
@ -43,5 +62,5 @@ pub trait TestCase {
|
|||
}
|
||||
|
||||
pub fn tests() -> Vec<&'static dyn TestCase> {
|
||||
vec![&t0001_shm_formats::Test]
|
||||
vec![&t0001_shm_formats::Test, &t0002_window::Test]
|
||||
}
|
||||
|
|
|
|||
56
src/it/tests/t0002_window.rs
Normal file
56
src/it/tests/t0002_window.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
use {
|
||||
crate::{
|
||||
format::ARGB8888,
|
||||
it::{test_error::TestError, testrun::TestRun},
|
||||
theme::Color,
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
testcase!();
|
||||
|
||||
/// Create and map a single surface
|
||||
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||
run.backend.install_default();
|
||||
|
||||
let client = run.create_client().await?;
|
||||
let surface = client.comp.create_surface().await?;
|
||||
let xdg_surface = client.xdg.create_xdg_surface(surface.id).await?;
|
||||
let xdg_toplevel = xdg_surface.create_toplevel().await?;
|
||||
surface.commit();
|
||||
client.sync().await;
|
||||
|
||||
{
|
||||
let pool = client.shm.create_pool(0)?;
|
||||
let buffer = pool.create_buffer(0, 0, 0, 0, ARGB8888)?;
|
||||
xdg_surface.ack_configure(xdg_surface.last_serial.get());
|
||||
surface.attach(buffer.id);
|
||||
surface.commit();
|
||||
client.sync().await;
|
||||
}
|
||||
|
||||
tassert_eq!(xdg_toplevel.width.get(), 800);
|
||||
tassert!(xdg_toplevel.height.get() >= 500);
|
||||
|
||||
{
|
||||
let pool = client
|
||||
.shm
|
||||
.create_pool((xdg_toplevel.width.get() * xdg_toplevel.height.get() * 4) as _)?;
|
||||
let buffer = pool.create_buffer(
|
||||
0,
|
||||
xdg_toplevel.width.get(),
|
||||
xdg_toplevel.height.get(),
|
||||
xdg_toplevel.width.get() * 4,
|
||||
ARGB8888,
|
||||
)?;
|
||||
buffer.fill(Color::from_rgba_straight(255, 0, 0, 100));
|
||||
xdg_surface.ack_configure(xdg_surface.last_serial.get());
|
||||
surface.attach(buffer.id);
|
||||
surface.commit();
|
||||
}
|
||||
|
||||
let screenshot = client.take_screenshot().await?;
|
||||
std::fs::write(format!("{}/screenshot.qoi", run.dir), screenshot)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue