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 idle;
|
||||||
mod log;
|
mod log;
|
||||||
mod quit;
|
mod quit;
|
||||||
mod screenshot;
|
pub mod screenshot;
|
||||||
mod set_log_level;
|
mod set_log_level;
|
||||||
|
|
||||||
use {
|
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) {
|
let drm = match Drm::reopen(buf.drm_dev.raw(), false) {
|
||||||
Ok(drm) => drm,
|
Ok(drm) => drm,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
|
||||||
|
|
@ -42,19 +42,23 @@ impl ClientMem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let data = unsafe {
|
let data = if len == 0 {
|
||||||
let data = c::mmap64(
|
&mut [][..]
|
||||||
ptr::null_mut(),
|
} else {
|
||||||
len,
|
unsafe {
|
||||||
c::PROT_READ | c::PROT_WRITE,
|
let data = c::mmap64(
|
||||||
c::MAP_SHARED,
|
ptr::null_mut(),
|
||||||
fd,
|
len,
|
||||||
0,
|
c::PROT_READ | c::PROT_WRITE,
|
||||||
);
|
c::MAP_SHARED,
|
||||||
if data == c::MAP_FAILED {
|
fd,
|
||||||
return Err(ClientMemError::MmapFailed(uapi::Errno::default().into()));
|
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 {
|
Ok(Self {
|
||||||
failed: Cell::new(false),
|
failed: Cell::new(false),
|
||||||
|
|
|
||||||
|
|
@ -185,10 +185,10 @@ fn start_compositor2(
|
||||||
for (key, val) in STATIC_VARS {
|
for (key, val) in STATIC_VARS {
|
||||||
forker.setenv(key.as_bytes(), val.as_bytes());
|
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()?;
|
el.run()?;
|
||||||
state.xwayland.handler.borrow_mut().take();
|
drop(compositor);
|
||||||
state.clients.clear();
|
state.clear();
|
||||||
for (_, seat) in state.globals.seats.lock().deref() {
|
for (_, seat) in state.globals.seats.lock().deref() {
|
||||||
seat.clear();
|
seat.clear();
|
||||||
}
|
}
|
||||||
|
|
@ -254,10 +254,7 @@ async fn create_backend(
|
||||||
) -> Option<Rc<dyn Backend>> {
|
) -> Option<Rc<dyn Backend>> {
|
||||||
#[cfg(feature = "it")]
|
#[cfg(feature = "it")]
|
||||||
if let Some(tf) = test_future {
|
if let Some(tf) = test_future {
|
||||||
return Some(Rc::new(TestBackend {
|
return Some(Rc::new(TestBackend::new(state, tf)));
|
||||||
state: state.clone(),
|
|
||||||
test_future: tf,
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
let mut backends = &state.run_args.backends[..];
|
let mut backends = &state.run_args.backends[..];
|
||||||
if backends.is_empty() {
|
if backends.is_empty() {
|
||||||
|
|
|
||||||
|
|
@ -591,9 +591,28 @@ impl WlSeatGlobal {
|
||||||
self.cursor.get()
|
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.pointer_stack.borrow_mut().deref_mut());
|
||||||
mem::take(self.found_tree.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 {
|
pub fn id(&self) -> SeatId {
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,13 @@ impl NodeSeatState {
|
||||||
self.destroy_node2(node, false);
|
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 {
|
impl WlSeatGlobal {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,10 @@ impl KbOwnerHolder {
|
||||||
pub fn set_kb_node(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>) {
|
pub fn set_kb_node(&self, seat: &Rc<WlSeatGlobal>, node: Rc<dyn Node>) {
|
||||||
self.owner.get().set_kb_node(seat, node);
|
self.owner.get().set_kb_node(seat, node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.owner.set(self.default.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DefaultKbOwner;
|
struct DefaultKbOwner;
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,10 @@ impl PointerOwnerHolder {
|
||||||
pub fn remove_dnd_icon(&self) {
|
pub fn remove_dnd_icon(&self) {
|
||||||
self.owner.get().remove_dnd_icon()
|
self.owner.get().remove_dnd_icon()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.owner.set(self.default.clone());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
trait PointerOwner {
|
trait PointerOwner {
|
||||||
|
|
|
||||||
12
src/it.rs
12
src/it.rs
|
|
@ -1,5 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::it::{test_backend::TestBackend, testrun::TestRun, tests::TestCase},
|
crate::{
|
||||||
|
it::{test_backend::TestBackend, testrun::TestRun, tests::TestCase},
|
||||||
|
utils::errorfmt::ErrorFmt,
|
||||||
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
isnt::std_1::collections::IsntHashMapExt,
|
isnt::std_1::collections::IsntHashMapExt,
|
||||||
log::Level,
|
log::Level,
|
||||||
|
|
@ -86,6 +89,7 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase) {
|
||||||
backend,
|
backend,
|
||||||
errors: Default::default(),
|
errors: Default::default(),
|
||||||
server_addr,
|
server_addr,
|
||||||
|
dir: dir.clone(),
|
||||||
});
|
});
|
||||||
let errors = errors2.clone();
|
let errors = errors2.clone();
|
||||||
Box::new(async move {
|
Box::new(async move {
|
||||||
|
|
@ -98,7 +102,10 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase) {
|
||||||
pending().await
|
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 {
|
if errors.len() > 0 {
|
||||||
log::error!("The following errors occurred:");
|
log::error!("The following errors occurred:");
|
||||||
for e in &errors {
|
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);
|
it_run.failed.borrow_mut().insert(test.name(), errors);
|
||||||
}
|
}
|
||||||
test_logger::unset_file();
|
test_logger::unset_file();
|
||||||
let _ = res;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,139 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
backend::{
|
backend::{
|
||||||
Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, InputDevice,
|
Backend, BackendEvent, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId,
|
||||||
InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent,
|
InputDevice, InputDeviceAccelProfile, InputDeviceCapability, InputDeviceId, InputEvent,
|
||||||
TransformMatrix,
|
Mode, MonitorInfo, TransformMatrix,
|
||||||
},
|
},
|
||||||
compositor::TestFuture,
|
compositor::TestFuture,
|
||||||
|
render::{RenderContext, RenderError},
|
||||||
state::State,
|
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 struct TestBackend {
|
||||||
pub state: Rc<State>,
|
pub state: Rc<State>,
|
||||||
pub test_future: TestFuture,
|
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 {
|
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 future = (self.test_future)(&self.state);
|
||||||
|
let slf = self.clone();
|
||||||
self.state.eng.spawn(async move {
|
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();
|
let future: Pin<_> = future.into();
|
||||||
future.await;
|
future.await;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -72,7 +185,7 @@ impl Connector for TestConnector {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn damage(&self) {
|
fn damage(&self) {
|
||||||
todo!()
|
// nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
cli::screenshot::buf_to_qoi,
|
||||||
client::Client,
|
client::Client,
|
||||||
it::{
|
it::{
|
||||||
|
test_error::TestError,
|
||||||
test_ifs::{
|
test_ifs::{
|
||||||
test_compositor::TestCompositor, test_jay_compositor::TestJayCompositor,
|
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,
|
test_transport::TestTransport,
|
||||||
testrun::TestRun,
|
testrun::TestRun,
|
||||||
|
|
@ -16,19 +18,32 @@ use {
|
||||||
pub struct TestClient {
|
pub struct TestClient {
|
||||||
pub run: Rc<TestRun>,
|
pub run: Rc<TestRun>,
|
||||||
pub server: Rc<Client>,
|
pub server: Rc<Client>,
|
||||||
pub transport: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub registry: Rc<TestRegistry>,
|
pub registry: Rc<TestRegistry>,
|
||||||
pub jc: Rc<TestJayCompositor>,
|
pub jc: Rc<TestJayCompositor>,
|
||||||
pub comp: Rc<TestCompositor>,
|
pub comp: Rc<TestCompositor>,
|
||||||
pub shm: Rc<TestShm>,
|
pub shm: Rc<TestShm>,
|
||||||
|
pub xdg: Rc<TestXdgWmBase>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestClient {
|
impl TestClient {
|
||||||
pub fn error(&self, msg: &str) {
|
pub fn error(&self, msg: &str) {
|
||||||
self.transport.error(msg)
|
self.tran.error(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn sync(self: &Rc<Self>) {
|
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_display;
|
||||||
pub mod test_jay_compositor;
|
pub mod test_jay_compositor;
|
||||||
pub mod test_registry;
|
pub mod test_registry;
|
||||||
|
pub mod test_screenshot;
|
||||||
pub mod test_shm;
|
pub mod test_shm;
|
||||||
pub mod test_shm_buffer;
|
pub mod test_shm_buffer;
|
||||||
pub mod test_shm_pool;
|
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 struct TestCallback {
|
||||||
pub id: WlCallbackId,
|
pub id: WlCallbackId,
|
||||||
pub transport: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub handler: Cell<Option<Box<dyn FnOnce()>>>,
|
pub handler: Cell<Option<Box<dyn FnOnce()>>>,
|
||||||
pub done: Cell<bool>,
|
pub done: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,38 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
it::{test_object::TestObject, test_transport::TestTransport},
|
it::{
|
||||||
wire::WlCompositorId,
|
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 struct TestCompositor {
|
||||||
pub id: WlCompositorId,
|
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! {
|
test_object! {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TestDisplay {
|
pub struct TestDisplay {
|
||||||
pub transport: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub id: WlDisplayId,
|
pub id: WlDisplayId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,25 +20,25 @@ impl TestDisplay {
|
||||||
fn handle_error(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
fn handle_error(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
let ev = Error::parse_full(parser)?;
|
let ev = Error::parse_full(parser)?;
|
||||||
let msg = format!("Compositor sent an error: {}", ev.message);
|
let msg = format!("Compositor sent an error: {}", ev.message);
|
||||||
self.transport.error(&msg);
|
self.tran.error(&msg);
|
||||||
self.transport.kill();
|
self.tran.kill();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_delete_id(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
fn handle_delete_id(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
let ev = DeleteId::parse_full(parser)?;
|
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 => {
|
None => {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
"Compositor sent delete_id for object {} which does not exist",
|
"Compositor sent delete_id for object {} which does not exist",
|
||||||
ev.id
|
ev.id
|
||||||
);
|
);
|
||||||
self.transport.error(&msg);
|
self.tran.error(&msg);
|
||||||
self.transport.kill();
|
self.tran.kill();
|
||||||
}
|
}
|
||||||
Some(obj) => {
|
Some(obj) => {
|
||||||
obj.on_remove(&self.transport);
|
obj.on_remove(&self.tran);
|
||||||
self.transport.obj_ids.borrow_mut().release(ev.id);
|
self.tran.obj_ids.borrow_mut().release(ev.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,13 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
client::ClientId,
|
client::ClientId,
|
||||||
it::{
|
it::{
|
||||||
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
test_error::TestError, test_ifs::test_screenshot::TestJayScreenshot,
|
||||||
testrun::ParseFull,
|
test_object::TestObject, test_transport::TestTransport, testrun::ParseFull,
|
||||||
},
|
},
|
||||||
utils::buffd::MsgParser,
|
utils::buffd::MsgParser,
|
||||||
wire::{
|
wire::{
|
||||||
jay_compositor::{self, *},
|
jay_compositor::{self, *},
|
||||||
|
jay_screenshot::Dmabuf,
|
||||||
JayCompositorId,
|
JayCompositorId,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -16,25 +17,44 @@ use {
|
||||||
|
|
||||||
pub struct TestJayCompositor {
|
pub struct TestJayCompositor {
|
||||||
pub id: JayCompositorId,
|
pub id: JayCompositorId,
|
||||||
pub transport: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub client_id: Cell<Option<ClientId>>,
|
pub client_id: Cell<Option<ClientId>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestJayCompositor {
|
impl TestJayCompositor {
|
||||||
pub async fn get_client_id(&self) -> Result<ClientId, TestError> {
|
pub async fn get_client_id(&self) -> Result<ClientId, TestError> {
|
||||||
if self.client_id.get().is_none() {
|
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() {
|
match self.client_id.get() {
|
||||||
Some(c) => Ok(c),
|
Some(c) => Ok(c),
|
||||||
_ => bail!("Compositor did not send a client id"),
|
_ => 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> {
|
fn handle_client_id(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
let ev = jay_compositor::ClientId::parse_full(parser)?;
|
let ev = jay_compositor::ClientId::parse_full(parser)?;
|
||||||
self.client_id.set(Some(ClientId::from_raw(ev.client_id)));
|
self.client_id.set(Some(ClientId::from_raw(ev.client_id)));
|
||||||
|
self.tran.client_id.set(ClientId::from_raw(ev.client_id));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ use {
|
||||||
test_error::TestError,
|
test_error::TestError,
|
||||||
test_ifs::{
|
test_ifs::{
|
||||||
test_compositor::TestCompositor, test_jay_compositor::TestJayCompositor,
|
test_compositor::TestCompositor, test_jay_compositor::TestJayCompositor,
|
||||||
test_shm::TestShm,
|
test_shm::TestShm, test_xdg_base::TestXdgWmBase,
|
||||||
},
|
},
|
||||||
test_object::TestObject,
|
test_object::TestObject,
|
||||||
test_transport::TestTransport,
|
test_transport::TestTransport,
|
||||||
|
|
@ -26,16 +26,18 @@ pub struct TestRegistrySingletons {
|
||||||
pub jay_compositor: u32,
|
pub jay_compositor: u32,
|
||||||
pub wl_compositor: u32,
|
pub wl_compositor: u32,
|
||||||
pub wl_shm: u32,
|
pub wl_shm: u32,
|
||||||
|
pub xdg_wm_base: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestRegistry {
|
pub struct TestRegistry {
|
||||||
pub id: WlRegistryId,
|
pub id: WlRegistryId,
|
||||||
pub transport: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub globals: CopyHashMap<u32, Rc<TestGlobal>>,
|
pub globals: CopyHashMap<u32, Rc<TestGlobal>>,
|
||||||
pub singletons: CloneCell<Option<Rc<TestRegistrySingletons>>>,
|
pub singletons: CloneCell<Option<Rc<TestRegistrySingletons>>>,
|
||||||
pub jay_compositor: CloneCell<Option<Rc<TestJayCompositor>>>,
|
pub jay_compositor: CloneCell<Option<Rc<TestJayCompositor>>>,
|
||||||
pub compositor: CloneCell<Option<Rc<TestCompositor>>>,
|
pub compositor: CloneCell<Option<Rc<TestCompositor>>>,
|
||||||
pub shm: CloneCell<Option<Rc<TestShm>>>,
|
pub shm: CloneCell<Option<Rc<TestShm>>>,
|
||||||
|
pub xdg: CloneCell<Option<Rc<TestXdgWmBase>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! singleton {
|
macro_rules! singleton {
|
||||||
|
|
@ -49,22 +51,22 @@ macro_rules! singleton {
|
||||||
impl TestRegistry {
|
impl TestRegistry {
|
||||||
pub async fn get_singletons(&self) -> Result<Rc<TestRegistrySingletons>, TestError> {
|
pub async fn get_singletons(&self) -> Result<Rc<TestRegistrySingletons>, TestError> {
|
||||||
singleton!(self.singletons);
|
singleton!(self.singletons);
|
||||||
self.transport.sync().await;
|
self.tran.sync().await;
|
||||||
singleton!(self.singletons);
|
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 {
|
macro_rules! singleton {
|
||||||
($($name:ident,)*) => {
|
($($name:ident,)*) => {{
|
||||||
TestRegistrySingletons {
|
$(
|
||||||
|
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: {
|
$name: {
|
||||||
if $name == 0 {
|
if $name == 0 {
|
||||||
|
|
@ -73,14 +75,15 @@ impl TestRegistry {
|
||||||
$name
|
$name
|
||||||
},
|
},
|
||||||
)*
|
)*
|
||||||
}
|
})
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
let singletons = Rc::new(singleton! {
|
let singletons = singleton! {
|
||||||
jay_compositor,
|
jay_compositor,
|
||||||
wl_compositor,
|
wl_compositor,
|
||||||
wl_shm,
|
wl_shm,
|
||||||
});
|
xdg_wm_base,
|
||||||
|
};
|
||||||
self.singletons.set(Some(singletons.clone()));
|
self.singletons.set(Some(singletons.clone()));
|
||||||
Ok(singletons)
|
Ok(singletons)
|
||||||
}
|
}
|
||||||
|
|
@ -90,8 +93,8 @@ impl TestRegistry {
|
||||||
let singletons = self.get_singletons().await?;
|
let singletons = self.get_singletons().await?;
|
||||||
singleton!(self.jay_compositor);
|
singleton!(self.jay_compositor);
|
||||||
let jc = Rc::new(TestJayCompositor {
|
let jc = Rc::new(TestJayCompositor {
|
||||||
id: self.transport.id(),
|
id: self.tran.id(),
|
||||||
transport: self.transport.clone(),
|
tran: self.tran.clone(),
|
||||||
client_id: Default::default(),
|
client_id: Default::default(),
|
||||||
});
|
});
|
||||||
self.bind(&jc, singletons.jay_compositor, 1)?;
|
self.bind(&jc, singletons.jay_compositor, 1)?;
|
||||||
|
|
@ -104,8 +107,8 @@ impl TestRegistry {
|
||||||
let singletons = self.get_singletons().await?;
|
let singletons = self.get_singletons().await?;
|
||||||
singleton!(self.compositor);
|
singleton!(self.compositor);
|
||||||
let jc = Rc::new(TestCompositor {
|
let jc = Rc::new(TestCompositor {
|
||||||
id: self.transport.id(),
|
id: self.tran.id(),
|
||||||
transport: self.transport.clone(),
|
tran: self.tran.clone(),
|
||||||
});
|
});
|
||||||
self.bind(&jc, singletons.wl_compositor, 4)?;
|
self.bind(&jc, singletons.wl_compositor, 4)?;
|
||||||
self.compositor.set(Some(jc.clone()));
|
self.compositor.set(Some(jc.clone()));
|
||||||
|
|
@ -117,8 +120,8 @@ impl TestRegistry {
|
||||||
let singletons = self.get_singletons().await?;
|
let singletons = self.get_singletons().await?;
|
||||||
singleton!(self.shm);
|
singleton!(self.shm);
|
||||||
let jc = Rc::new(TestShm {
|
let jc = Rc::new(TestShm {
|
||||||
id: self.transport.id(),
|
id: self.tran.id(),
|
||||||
transport: self.transport.clone(),
|
tran: self.tran.clone(),
|
||||||
formats: Default::default(),
|
formats: Default::default(),
|
||||||
formats_awaited: Cell::new(false),
|
formats_awaited: Cell::new(false),
|
||||||
});
|
});
|
||||||
|
|
@ -127,20 +130,34 @@ impl TestRegistry {
|
||||||
Ok(jc)
|
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>(
|
pub fn bind<O: TestObject>(
|
||||||
&self,
|
&self,
|
||||||
obj: &Rc<O>,
|
obj: &Rc<O>,
|
||||||
name: u32,
|
name: u32,
|
||||||
version: u32,
|
version: u32,
|
||||||
) -> Result<(), TestError> {
|
) -> Result<(), TestError> {
|
||||||
self.transport.send(Bind {
|
self.tran.send(Bind {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
name,
|
name,
|
||||||
interface: obj.interface().name(),
|
interface: obj.interface().name(),
|
||||||
version,
|
version,
|
||||||
id: obj.id().into(),
|
id: obj.id().into(),
|
||||||
});
|
});
|
||||||
self.transport.add_obj(obj.clone())?;
|
self.tran.add_obj(obj.clone())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,7 +172,7 @@ impl TestRegistry {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
if prev.is_some() {
|
if prev.is_some() {
|
||||||
self.transport.error(&format!(
|
self.tran.error(&format!(
|
||||||
"Compositor sent global {} multiple times",
|
"Compositor sent global {} multiple times",
|
||||||
ev.name
|
ev.name
|
||||||
));
|
));
|
||||||
|
|
@ -166,7 +183,7 @@ impl TestRegistry {
|
||||||
fn handle_global_remove(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
fn handle_global_remove(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
let ev = GlobalRemove::parse_full(parser)?;
|
let ev = GlobalRemove::parse_full(parser)?;
|
||||||
if self.globals.remove(&ev.name).is_none() {
|
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",
|
"Compositor sent global_remove for {} which does not exist",
|
||||||
ev.name
|
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 struct TestShm {
|
||||||
pub id: WlShmId,
|
pub id: WlShmId,
|
||||||
pub transport: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub formats: CopyHashMap<u32, ()>,
|
pub formats: CopyHashMap<u32, ()>,
|
||||||
pub formats_awaited: Cell<bool>,
|
pub formats_awaited: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
@ -20,7 +20,7 @@ pub struct TestShm {
|
||||||
impl TestShm {
|
impl TestShm {
|
||||||
pub async fn formats(&self) -> &CopyHashMap<u32, ()> {
|
pub async fn formats(&self) -> &CopyHashMap<u32, ()> {
|
||||||
if !self.formats_awaited.replace(true) {
|
if !self.formats_awaited.replace(true) {
|
||||||
self.transport.sync().await;
|
self.tran.sync().await;
|
||||||
}
|
}
|
||||||
&self.formats
|
&self.formats
|
||||||
}
|
}
|
||||||
|
|
@ -28,18 +28,18 @@ impl TestShm {
|
||||||
pub fn create_pool(&self, size: usize) -> Result<Rc<TestShmPool>, TestError> {
|
pub fn create_pool(&self, size: usize) -> Result<Rc<TestShmPool>, TestError> {
|
||||||
let mem = TestMem::new(size)?;
|
let mem = TestMem::new(size)?;
|
||||||
let pool = Rc::new(TestShmPool {
|
let pool = Rc::new(TestShmPool {
|
||||||
id: self.transport.id(),
|
id: self.tran.id(),
|
||||||
transport: self.transport.clone(),
|
tran: self.tran.clone(),
|
||||||
mem: CloneCell::new(mem.clone()),
|
mem: CloneCell::new(mem.clone()),
|
||||||
destroyed: Cell::new(false),
|
destroyed: Cell::new(false),
|
||||||
});
|
});
|
||||||
self.transport.send(CreatePool {
|
self.tran.send(CreatePool {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
id: pool.id,
|
id: pool.id,
|
||||||
fd: mem.fd.clone(),
|
fd: mem.fd.clone(),
|
||||||
size: size as _,
|
size: size as _,
|
||||||
});
|
});
|
||||||
self.transport.add_obj(pool.clone())?;
|
self.tran.add_obj(pool.clone())?;
|
||||||
Ok(pool)
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ use {
|
||||||
test_error::TestError, test_mem::TestMem, test_object::TestObject,
|
test_error::TestError, test_mem::TestMem, test_object::TestObject,
|
||||||
test_transport::TestTransport, testrun::ParseFull,
|
test_transport::TestTransport, testrun::ParseFull,
|
||||||
},
|
},
|
||||||
utils::buffd::MsgParser,
|
theme::Color,
|
||||||
|
utils::{buffd::MsgParser, windows::WindowsExt},
|
||||||
wire::{wl_buffer::*, WlBufferId},
|
wire::{wl_buffer::*, WlBufferId},
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -16,7 +17,7 @@ use {
|
||||||
|
|
||||||
pub struct TestShmBuffer {
|
pub struct TestShmBuffer {
|
||||||
pub id: WlBufferId,
|
pub id: WlBufferId,
|
||||||
pub transport: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub range: Range<usize>,
|
pub range: Range<usize>,
|
||||||
pub mem: Rc<TestMem>,
|
pub mem: Rc<TestMem>,
|
||||||
pub released: Cell<bool>,
|
pub released: Cell<bool>,
|
||||||
|
|
@ -24,11 +25,21 @@ pub struct TestShmBuffer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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) {
|
pub fn destroy(&self) {
|
||||||
if self.destroyed.replace(true) {
|
if self.destroyed.replace(true) {
|
||||||
return;
|
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> {
|
fn handle_release(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ use {
|
||||||
|
|
||||||
pub struct TestShmPool {
|
pub struct TestShmPool {
|
||||||
pub id: WlShmPoolId,
|
pub id: WlShmPoolId,
|
||||||
pub transport: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub mem: CloneCell<Rc<TestMem>>,
|
pub mem: CloneCell<Rc<TestMem>>,
|
||||||
pub destroyed: Cell<bool>,
|
pub destroyed: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
@ -35,15 +35,15 @@ impl TestShmPool {
|
||||||
bail!("Out-of-bounds buffer");
|
bail!("Out-of-bounds buffer");
|
||||||
}
|
}
|
||||||
let buffer = Rc::new(TestShmBuffer {
|
let buffer = Rc::new(TestShmBuffer {
|
||||||
id: self.transport.id(),
|
id: self.tran.id(),
|
||||||
transport: self.transport.clone(),
|
tran: self.tran.clone(),
|
||||||
range: start..end,
|
range: start..end,
|
||||||
mem,
|
mem,
|
||||||
released: Cell::new(true),
|
released: Cell::new(true),
|
||||||
destroyed: Cell::new(false),
|
destroyed: Cell::new(false),
|
||||||
});
|
});
|
||||||
self.transport.add_obj(buffer.clone())?;
|
self.tran.add_obj(buffer.clone())?;
|
||||||
self.transport.send(CreateBuffer {
|
self.tran.send(CreateBuffer {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
id: buffer.id,
|
id: buffer.id,
|
||||||
offset,
|
offset,
|
||||||
|
|
@ -58,7 +58,7 @@ impl TestShmPool {
|
||||||
pub fn resize(&self, size: usize) -> Result<(), TestError> {
|
pub fn resize(&self, size: usize) -> Result<(), TestError> {
|
||||||
let mem = self.mem.get().grow(size)?;
|
let mem = self.mem.get().grow(size)?;
|
||||||
self.mem.set(mem);
|
self.mem.set(mem);
|
||||||
self.transport.send(Resize {
|
self.tran.send(Resize {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
size: size as _,
|
size: size as _,
|
||||||
});
|
});
|
||||||
|
|
@ -69,7 +69,7 @@ impl TestShmPool {
|
||||||
if self.destroyed.replace(true) {
|
if self.destroyed.replace(true) {
|
||||||
return;
|
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> {
|
fn map(fd: c::c_int, size: usize) -> Result<*const [Cell<u8>], TestError> {
|
||||||
|
if size == 0 {
|
||||||
|
return Ok(&[]);
|
||||||
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
let res = c::mmap(
|
let res = c::mmap(
|
||||||
ptr::null_mut(),
|
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))),
|
$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()))
|
res.with_context(|| format!("In object {} of type `{}`", self.id(), self.interface().name()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::{AsyncFd, SpawnedFuture},
|
async_engine::{AsyncFd, SpawnedFuture},
|
||||||
client::{ClientId, EventFormatter},
|
client::{Client, ClientId, EventFormatter},
|
||||||
it::{
|
it::{
|
||||||
test_error::{StdError, TestError},
|
test_error::{StdError, TestError},
|
||||||
test_ifs::{test_callback::TestCallback, test_registry::TestRegistry},
|
test_ifs::{test_callback::TestCallback, test_registry::TestRegistry},
|
||||||
|
|
@ -47,12 +47,13 @@ impl TestTransport {
|
||||||
pub fn get_registry(self: &Rc<Self>) -> Rc<TestRegistry> {
|
pub fn get_registry(self: &Rc<Self>) -> Rc<TestRegistry> {
|
||||||
let reg = Rc::new(TestRegistry {
|
let reg = Rc::new(TestRegistry {
|
||||||
id: self.id(),
|
id: self.id(),
|
||||||
transport: self.clone(),
|
tran: self.clone(),
|
||||||
globals: Default::default(),
|
globals: Default::default(),
|
||||||
singletons: Default::default(),
|
singletons: Default::default(),
|
||||||
jay_compositor: Default::default(),
|
jay_compositor: Default::default(),
|
||||||
compositor: Default::default(),
|
compositor: Default::default(),
|
||||||
shm: Default::default(),
|
shm: Default::default(),
|
||||||
|
xdg: Default::default(),
|
||||||
});
|
});
|
||||||
self.send(wl_display::GetRegistry {
|
self.send(wl_display::GetRegistry {
|
||||||
self_id: WL_DISPLAY_ID,
|
self_id: WL_DISPLAY_ID,
|
||||||
|
|
@ -62,6 +63,14 @@ impl TestTransport {
|
||||||
reg
|
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> {
|
pub fn add_obj(&self, obj: Rc<dyn TestObject>) -> Result<(), TestError> {
|
||||||
if self.killed.get() {
|
if self.killed.get() {
|
||||||
bail!("Transport has already been killed");
|
bail!("Transport has already been killed");
|
||||||
|
|
@ -84,7 +93,7 @@ impl TestTransport {
|
||||||
pub fn sync(self: &Rc<Self>) -> impl Future<Output = ()> {
|
pub fn sync(self: &Rc<Self>) -> impl Future<Output = ()> {
|
||||||
let cb = Rc::new(TestCallback {
|
let cb = Rc::new(TestCallback {
|
||||||
id: self.id(),
|
id: self.id(),
|
||||||
transport: self.clone(),
|
tran: self.clone(),
|
||||||
handler: Cell::new(None),
|
handler: Cell::new(None),
|
||||||
done: Cell::new(self.killed.get()),
|
done: Cell::new(self.killed.get()),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ pub struct TestRun {
|
||||||
pub backend: Rc<TestBackend>,
|
pub backend: Rc<TestBackend>,
|
||||||
pub errors: Stack<String>,
|
pub errors: Stack<String>,
|
||||||
pub server_addr: c::sockaddr_un,
|
pub server_addr: c::sockaddr_un,
|
||||||
|
pub dir: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestRun {
|
impl TestRun {
|
||||||
|
|
@ -53,7 +54,7 @@ impl TestRun {
|
||||||
let mut obj_ids = Bitfield::default();
|
let mut obj_ids = Bitfield::default();
|
||||||
obj_ids.take(0);
|
obj_ids.take(0);
|
||||||
obj_ids.take(1);
|
obj_ids.take(1);
|
||||||
let transport = Rc::new(TestTransport {
|
let tran = Rc::new(TestTransport {
|
||||||
run: self.clone(),
|
run: self.clone(),
|
||||||
fd,
|
fd,
|
||||||
client_id: Cell::new(ClientId::from_raw(0)),
|
client_id: Cell::new(ClientId::from_raw(0)),
|
||||||
|
|
@ -66,22 +67,23 @@ impl TestRun {
|
||||||
obj_ids: RefCell::new(obj_ids),
|
obj_ids: RefCell::new(obj_ids),
|
||||||
killed: Cell::new(false),
|
killed: Cell::new(false),
|
||||||
});
|
});
|
||||||
transport.add_obj(Rc::new(TestDisplay {
|
tran.add_obj(Rc::new(TestDisplay {
|
||||||
transport: transport.clone(),
|
tran: tran.clone(),
|
||||||
id: WL_DISPLAY_ID,
|
id: WL_DISPLAY_ID,
|
||||||
}))?;
|
}))?;
|
||||||
transport.init();
|
tran.init();
|
||||||
let registry = transport.get_registry();
|
let registry = tran.get_registry();
|
||||||
let jc = registry.get_jay_compositor().await?;
|
let jc = registry.get_jay_compositor().await?;
|
||||||
let client_id = jc.get_client_id().await?;
|
let client_id = jc.get_client_id().await?;
|
||||||
let client = self.state.clients.get(client_id)?;
|
let client = self.state.clients.get(client_id)?;
|
||||||
Ok(Rc::new(TestClient {
|
Ok(Rc::new(TestClient {
|
||||||
run: self.clone(),
|
run: self.clone(),
|
||||||
server: client,
|
server: client,
|
||||||
transport,
|
tran,
|
||||||
jc,
|
jc,
|
||||||
comp: registry.get_compositor().await?,
|
comp: registry.get_compositor().await?,
|
||||||
shm: registry.get_shm().await?,
|
shm: registry.get_shm().await?,
|
||||||
|
xdg: registry.get_xdg().await?,
|
||||||
registry,
|
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 t0001_shm_formats;
|
||||||
|
mod t0002_window;
|
||||||
|
|
||||||
pub trait TestCase {
|
pub trait TestCase {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
@ -43,5 +62,5 @@ pub trait TestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tests() -> Vec<&'static dyn 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
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
|
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||||
if INITIALIZED {
|
if INITIALIZED {
|
||||||
ALLOCATIONS.deref_mut().remove(&ptr);
|
ALLOCATIONS.deref_mut().remove(&ptr);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ impl Renderer<'_> {
|
||||||
let pos = placeholder.tl_data().pos.get();
|
let pos = placeholder.tl_data().pos.get();
|
||||||
self.fill_boxes(
|
self.fill_boxes(
|
||||||
std::slice::from_ref(&pos.at_point(x, y)),
|
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() {
|
if let Some(tex) = placeholder.texture() {
|
||||||
let x = x + (pos.width() - tex.width()) / 2;
|
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,
|
Backend, BackendEvent, Connector, ConnectorId, ConnectorIds, InputDevice,
|
||||||
InputDeviceId, InputDeviceIds, MonitorInfo,
|
InputDeviceId, InputDeviceIds, MonitorInfo,
|
||||||
},
|
},
|
||||||
|
backends::dummy::DummyBackend,
|
||||||
cli::RunArgs,
|
cli::RunArgs,
|
||||||
client::{Client, Clients, SerialRange, NUM_CACHED_SERIAL_RANGES},
|
client::{Client, Clients, SerialRange, NUM_CACHED_SERIAL_RANGES},
|
||||||
config::ConfigProxy,
|
config::ConfigProxy,
|
||||||
|
|
@ -43,7 +44,9 @@ use {
|
||||||
std::{
|
std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
fmt::{Debug, Formatter},
|
fmt::{Debug, Formatter},
|
||||||
|
mem,
|
||||||
num::Wrapping,
|
num::Wrapping,
|
||||||
|
ops::DerefMut,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::Duration,
|
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
|
c as f32 / 255f32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn to_u8(c: f32) -> u8 {
|
||||||
|
(c * 255f32) as u8
|
||||||
|
}
|
||||||
|
|
||||||
impl Color {
|
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 {
|
Self {
|
||||||
r: to_f32(r),
|
r: to_f32(r) * alpha,
|
||||||
g: to_f32(g),
|
g: to_f32(g) * alpha,
|
||||||
b: to_f32(b),
|
b: to_f32(b) * alpha,
|
||||||
a: to_f32(a),
|
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 {
|
impl From<jay_config::theme::Color> for Color {
|
||||||
|
|
@ -65,12 +74,12 @@ pub struct Theme {
|
||||||
impl Default for Theme {
|
impl Default for Theme {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
background_color: Cell::new(Color::from_rgba(0x00, 0x10, 0x19, 255)),
|
background_color: Cell::new(Color::from_rgba_straight(0x00, 0x10, 0x19, 255)),
|
||||||
last_active_color: Cell::new(Color::from_rgba(0x5f, 0x67, 0x6a, 255)),
|
last_active_color: Cell::new(Color::from_rgba_straight(0x5f, 0x67, 0x6a, 255)),
|
||||||
title_color: Cell::new(Color::from_rgba(0x22, 0x22, 0x22, 255)),
|
title_color: Cell::new(Color::from_rgba_straight(0x22, 0x22, 0x22, 255)),
|
||||||
active_title_color: Cell::new(Color::from_rgba(0x28, 0x55, 0x77, 255)),
|
active_title_color: Cell::new(Color::from_rgba_straight(0x28, 0x55, 0x77, 255)),
|
||||||
underline_color: Cell::new(Color::from_rgba(0x33, 0x33, 0x33, 255)),
|
underline_color: Cell::new(Color::from_rgba_straight(0x33, 0x33, 0x33, 255)),
|
||||||
border_color: Cell::new(Color::from_rgba(0x3f, 0x47, 0x4a, 255)),
|
border_color: Cell::new(Color::from_rgba_straight(0x3f, 0x47, 0x4a, 255)),
|
||||||
title_height: Cell::new(17),
|
title_height: Cell::new(17),
|
||||||
border_width: Cell::new(4),
|
border_width: Cell::new(4),
|
||||||
font: RefCell::new("monospace 8".to_string()),
|
font: RefCell::new("monospace 8".to_string()),
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ pub mod errorfmt;
|
||||||
pub mod fdcloser;
|
pub mod fdcloser;
|
||||||
pub mod hex;
|
pub mod hex;
|
||||||
pub mod linkedlist;
|
pub mod linkedlist;
|
||||||
|
pub mod log_on_drop;
|
||||||
pub mod nonblock;
|
pub mod nonblock;
|
||||||
pub mod numcell;
|
pub mod numcell;
|
||||||
pub mod oserror;
|
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 {
|
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> {
|
pub fn reopen(fd: c::c_int, need_primary: bool) -> Result<Self, DrmError> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
fd: reopen(fd, need_primary)?,
|
fd: reopen(fd, need_primary)?,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue