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,7 +2,7 @@ mod generate;
|
|||
mod idle;
|
||||
mod log;
|
||||
mod quit;
|
||||
mod screenshot;
|
||||
pub mod screenshot;
|
||||
mod set_log_level;
|
||||
|
||||
use {
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ async fn run(screenshot: Rc<Screenshot>) {
|
|||
}
|
||||
}
|
||||
|
||||
fn buf_to_qoi(buf: &Dmabuf) -> Vec<u8> {
|
||||
pub fn buf_to_qoi(buf: &Dmabuf) -> Vec<u8> {
|
||||
let drm = match Drm::reopen(buf.drm_dev.raw(), false) {
|
||||
Ok(drm) => drm,
|
||||
Err(e) => {
|
||||
|
|
|
|||
|
|
@ -42,19 +42,23 @@ impl ClientMem {
|
|||
}
|
||||
}
|
||||
}
|
||||
let data = unsafe {
|
||||
let data = c::mmap64(
|
||||
ptr::null_mut(),
|
||||
len,
|
||||
c::PROT_READ | c::PROT_WRITE,
|
||||
c::MAP_SHARED,
|
||||
fd,
|
||||
0,
|
||||
);
|
||||
if data == c::MAP_FAILED {
|
||||
return Err(ClientMemError::MmapFailed(uapi::Errno::default().into()));
|
||||
let data = if len == 0 {
|
||||
&mut [][..]
|
||||
} else {
|
||||
unsafe {
|
||||
let data = c::mmap64(
|
||||
ptr::null_mut(),
|
||||
len,
|
||||
c::PROT_READ | c::PROT_WRITE,
|
||||
c::MAP_SHARED,
|
||||
fd,
|
||||
0,
|
||||
);
|
||||
if data == c::MAP_FAILED {
|
||||
return Err(ClientMemError::MmapFailed(uapi::Errno::default().into()));
|
||||
}
|
||||
std::slice::from_raw_parts_mut(data as *mut Cell<u8>, len)
|
||||
}
|
||||
std::slice::from_raw_parts_mut(data as *mut Cell<u8>, len)
|
||||
};
|
||||
Ok(Self {
|
||||
failed: Cell::new(false),
|
||||
|
|
|
|||
|
|
@ -185,10 +185,10 @@ fn start_compositor2(
|
|||
for (key, val) in STATIC_VARS {
|
||||
forker.setenv(key.as_bytes(), val.as_bytes());
|
||||
}
|
||||
let _compositor = engine.spawn(start_compositor3(state.clone(), test_future));
|
||||
let compositor = engine.spawn(start_compositor3(state.clone(), test_future));
|
||||
el.run()?;
|
||||
state.xwayland.handler.borrow_mut().take();
|
||||
state.clients.clear();
|
||||
drop(compositor);
|
||||
state.clear();
|
||||
for (_, seat) in state.globals.seats.lock().deref() {
|
||||
seat.clear();
|
||||
}
|
||||
|
|
@ -254,10 +254,7 @@ async fn create_backend(
|
|||
) -> Option<Rc<dyn Backend>> {
|
||||
#[cfg(feature = "it")]
|
||||
if let Some(tf) = test_future {
|
||||
return Some(Rc::new(TestBackend {
|
||||
state: state.clone(),
|
||||
test_future: tf,
|
||||
}));
|
||||
return Some(Rc::new(TestBackend::new(state, tf)));
|
||||
}
|
||||
let mut backends = &state.run_args.backends[..];
|
||||
if backends.is_empty() {
|
||||
|
|
|
|||
|
|
@ -591,9 +591,28 @@ impl WlSeatGlobal {
|
|||
self.cursor.get()
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
pub fn clear(self: &Rc<Self>) {
|
||||
mem::take(self.pointer_stack.borrow_mut().deref_mut());
|
||||
mem::take(self.found_tree.borrow_mut().deref_mut());
|
||||
self.keyboard_node.set(self.state.root.clone());
|
||||
self.state
|
||||
.root
|
||||
.clone()
|
||||
.node_visit(&mut generic_node_visitor(|node| {
|
||||
node.node_seat_state().on_seat_remove(self);
|
||||
}));
|
||||
self.bindings.borrow_mut().clear();
|
||||
self.data_devices.borrow_mut().clear();
|
||||
self.primary_selection_devices.borrow_mut().clear();
|
||||
self.cursor.set(None);
|
||||
self.selection.set(None);
|
||||
self.primary_selection.set(None);
|
||||
self.pointer_owner.clear();
|
||||
self.kb_owner.clear();
|
||||
*self.dropped_dnd.borrow_mut() = None;
|
||||
self.queue_link.set(None);
|
||||
self.tree_changed_handler.set(None);
|
||||
self.output.set(self.state.dummy_output.get().unwrap());
|
||||
}
|
||||
|
||||
pub fn id(&self) -> SeatId {
|
||||
|
|
|
|||
|
|
@ -149,6 +149,13 @@ impl NodeSeatState {
|
|||
self.destroy_node2(node, false);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_seat_remove(&self, seat: &WlSeatGlobal) {
|
||||
self.kb_foci.remove(&seat.id);
|
||||
self.pointer_foci.remove(&seat.id);
|
||||
self.dnd_targets.remove(&seat.id);
|
||||
self.pointer_grabs.remove(&seat.id);
|
||||
}
|
||||
}
|
||||
|
||||
impl WlSeatGlobal {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ impl KbOwnerHolder {
|
|||
pub fn set_kb_node(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>) {
|
||||
self.owner.get().set_kb_node(seat, node);
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.owner.set(self.default.clone());
|
||||
}
|
||||
}
|
||||
|
||||
struct DefaultKbOwner;
|
||||
|
|
|
|||
|
|
@ -115,6 +115,10 @@ impl PointerOwnerHolder {
|
|||
pub fn remove_dnd_icon(&self) {
|
||||
self.owner.get().remove_dnd_icon()
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.owner.set(self.default.clone());
|
||||
}
|
||||
}
|
||||
|
||||
trait PointerOwner {
|
||||
|
|
|
|||
12
src/it.rs
12
src/it.rs
|
|
@ -1,5 +1,8 @@
|
|||
use {
|
||||
crate::it::{test_backend::TestBackend, testrun::TestRun, tests::TestCase},
|
||||
crate::{
|
||||
it::{test_backend::TestBackend, testrun::TestRun, tests::TestCase},
|
||||
utils::errorfmt::ErrorFmt,
|
||||
},
|
||||
ahash::AHashMap,
|
||||
isnt::std_1::collections::IsntHashMapExt,
|
||||
log::Level,
|
||||
|
|
@ -86,6 +89,7 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase) {
|
|||
backend,
|
||||
errors: Default::default(),
|
||||
server_addr,
|
||||
dir: dir.clone(),
|
||||
});
|
||||
let errors = errors2.clone();
|
||||
Box::new(async move {
|
||||
|
|
@ -98,7 +102,10 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase) {
|
|||
pending().await
|
||||
})
|
||||
}));
|
||||
let errors = errors.take();
|
||||
let mut errors = errors.take();
|
||||
if let Err(e) = res {
|
||||
errors.push(format!("The compositor failed: {}", ErrorFmt(e)));
|
||||
}
|
||||
if errors.len() > 0 {
|
||||
log::error!("The following errors occurred:");
|
||||
for e in &errors {
|
||||
|
|
@ -107,5 +114,4 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase) {
|
|||
it_run.failed.borrow_mut().insert(test.name(), errors);
|
||||
}
|
||||
test_logger::unset_file();
|
||||
let _ = res;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
|
@ -230,7 +230,7 @@ mod leaks {
|
|||
res
|
||||
}
|
||||
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
if INITIALIZED {
|
||||
ALLOCATIONS.deref_mut().remove(&ptr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ impl Renderer<'_> {
|
|||
let pos = placeholder.tl_data().pos.get();
|
||||
self.fill_boxes(
|
||||
std::slice::from_ref(&pos.at_point(x, y)),
|
||||
&Color::from_rgba(20, 20, 20, 255),
|
||||
&Color::from_rgba_straight(20, 20, 20, 255),
|
||||
);
|
||||
if let Some(tex) = placeholder.texture() {
|
||||
let x = x + (pos.width() - tex.width()) / 2;
|
||||
|
|
|
|||
16
src/state.rs
16
src/state.rs
|
|
@ -6,6 +6,7 @@ use {
|
|||
Backend, BackendEvent, Connector, ConnectorId, ConnectorIds, InputDevice,
|
||||
InputDeviceId, InputDeviceIds, MonitorInfo,
|
||||
},
|
||||
backends::dummy::DummyBackend,
|
||||
cli::RunArgs,
|
||||
client::{Client, Clients, SerialRange, NUM_CACHED_SERIAL_RANGES},
|
||||
config::ConfigProxy,
|
||||
|
|
@ -43,7 +44,9 @@ use {
|
|||
std::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt::{Debug, Formatter},
|
||||
mem,
|
||||
num::Wrapping,
|
||||
ops::DerefMut,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
|
|
@ -397,4 +400,17 @@ impl State {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.xwayland.handler.borrow_mut().take();
|
||||
self.clients.clear();
|
||||
self.config.set(None);
|
||||
self.backend.set(Rc::new(DummyBackend));
|
||||
{
|
||||
let seats = mem::take(self.globals.seats.lock().deref_mut());
|
||||
for seat in seats.values() {
|
||||
seat.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
31
src/theme.rs
31
src/theme.rs
|
|
@ -28,15 +28,24 @@ fn to_f32(c: u8) -> f32 {
|
|||
c as f32 / 255f32
|
||||
}
|
||||
|
||||
fn to_u8(c: f32) -> u8 {
|
||||
(c * 255f32) as u8
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn from_rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
pub fn from_rgba_straight(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
let alpha = to_f32(a);
|
||||
Self {
|
||||
r: to_f32(r),
|
||||
g: to_f32(g),
|
||||
b: to_f32(b),
|
||||
a: to_f32(a),
|
||||
r: to_f32(r) * alpha,
|
||||
g: to_f32(g) * alpha,
|
||||
b: to_f32(b) * alpha,
|
||||
a: alpha,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_rgba_premultiplied(self) -> [u8; 4] {
|
||||
[to_u8(self.r), to_u8(self.g), to_u8(self.b), to_u8(self.a)]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<jay_config::theme::Color> for Color {
|
||||
|
|
@ -65,12 +74,12 @@ pub struct Theme {
|
|||
impl Default for Theme {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
background_color: Cell::new(Color::from_rgba(0x00, 0x10, 0x19, 255)),
|
||||
last_active_color: Cell::new(Color::from_rgba(0x5f, 0x67, 0x6a, 255)),
|
||||
title_color: Cell::new(Color::from_rgba(0x22, 0x22, 0x22, 255)),
|
||||
active_title_color: Cell::new(Color::from_rgba(0x28, 0x55, 0x77, 255)),
|
||||
underline_color: Cell::new(Color::from_rgba(0x33, 0x33, 0x33, 255)),
|
||||
border_color: Cell::new(Color::from_rgba(0x3f, 0x47, 0x4a, 255)),
|
||||
background_color: Cell::new(Color::from_rgba_straight(0x00, 0x10, 0x19, 255)),
|
||||
last_active_color: Cell::new(Color::from_rgba_straight(0x5f, 0x67, 0x6a, 255)),
|
||||
title_color: Cell::new(Color::from_rgba_straight(0x22, 0x22, 0x22, 255)),
|
||||
active_title_color: Cell::new(Color::from_rgba_straight(0x28, 0x55, 0x77, 255)),
|
||||
underline_color: Cell::new(Color::from_rgba_straight(0x33, 0x33, 0x33, 255)),
|
||||
border_color: Cell::new(Color::from_rgba_straight(0x3f, 0x47, 0x4a, 255)),
|
||||
title_height: Cell::new(17),
|
||||
border_width: Cell::new(4),
|
||||
font: RefCell::new("monospace 8".to_string()),
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ pub mod errorfmt;
|
|||
pub mod fdcloser;
|
||||
pub mod hex;
|
||||
pub mod linkedlist;
|
||||
pub mod log_on_drop;
|
||||
pub mod nonblock;
|
||||
pub mod numcell;
|
||||
pub mod oserror;
|
||||
|
|
|
|||
7
src/utils/log_on_drop.rs
Normal file
7
src/utils/log_on_drop.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
pub struct LogOnDrop(pub &'static str);
|
||||
|
||||
impl Drop for LogOnDrop {
|
||||
fn drop(&mut self) {
|
||||
log::info!("{}", self.0);
|
||||
}
|
||||
}
|
||||
|
|
@ -135,6 +135,10 @@ pub struct Drm {
|
|||
}
|
||||
|
||||
impl Drm {
|
||||
pub fn open_existing(fd: OwnedFd) -> Self {
|
||||
Self { fd: Rc::new(fd) }
|
||||
}
|
||||
|
||||
pub fn reopen(fd: c::c_int, need_primary: bool) -> Result<Self, DrmError> {
|
||||
Ok(Self {
|
||||
fd: reopen(fd, need_primary)?,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue