Merge pull request #147 from mahkoh/jorth/tests2
Add more integration tests
This commit is contained in:
commit
9d78231cac
110 changed files with 3651 additions and 319 deletions
|
|
@ -22,7 +22,7 @@ use {
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
|
asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell,
|
||||||
copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell,
|
copyhashmap::CopyHashMap, debug_fn::debug_fn, errorfmt::ErrorFmt, numcell::NumCell,
|
||||||
opaque_cell::OpaqueCell, oserror::OsError, syncqueue::SyncQueue,
|
on_change::OnChange, opaque_cell::OpaqueCell, oserror::OsError,
|
||||||
transform_ext::TransformExt,
|
transform_ext::TransformExt,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
|
|
@ -320,38 +320,6 @@ impl Debug for ConnectorFutures {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OnChange<T> {
|
|
||||||
pub on_change: CloneCell<Option<Rc<dyn Fn()>>>,
|
|
||||||
pub events: SyncQueue<T>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> OnChange<T> {
|
|
||||||
pub fn send_event(&self, event: T) {
|
|
||||||
self.events.push(event);
|
|
||||||
if let Some(cb) = self.on_change.get() {
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for OnChange<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
on_change: Default::default(),
|
|
||||||
events: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Debug for OnChange<T> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self.on_change.get() {
|
|
||||||
None => f.write_str("None"),
|
|
||||||
Some(_) => f.write_str("Some"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct DirectScanoutCache {
|
pub struct DirectScanoutCache {
|
||||||
tex: Weak<dyn GfxTexture>,
|
tex: Weak<dyn GfxTexture>,
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ use {
|
||||||
clonecell::CloneCell,
|
clonecell::CloneCell,
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
},
|
},
|
||||||
wire::{jay_compositor::*, JayCompositorId},
|
wire::{jay_compositor::*, JayCompositorId, JayScreenshotId},
|
||||||
},
|
},
|
||||||
bstr::ByteSlice,
|
bstr::ByteSlice,
|
||||||
log::Level,
|
log::Level,
|
||||||
|
|
@ -125,14 +125,27 @@ impl JayCompositor {
|
||||||
|
|
||||||
fn take_screenshot(&self, parser: MsgParser<'_, '_>) -> Result<(), JayCompositorError> {
|
fn take_screenshot(&self, parser: MsgParser<'_, '_>) -> Result<(), JayCompositorError> {
|
||||||
let req: TakeScreenshot = self.client.parse(self, parser)?;
|
let req: TakeScreenshot = self.client.parse(self, parser)?;
|
||||||
|
self.take_screenshot_impl(req.id, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_screenshot2(&self, parser: MsgParser<'_, '_>) -> Result<(), JayCompositorError> {
|
||||||
|
let req: TakeScreenshot2 = self.client.parse(self, parser)?;
|
||||||
|
self.take_screenshot_impl(req.id, req.include_cursor != 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_screenshot_impl(
|
||||||
|
&self,
|
||||||
|
id: JayScreenshotId,
|
||||||
|
include_cursor: bool,
|
||||||
|
) -> Result<(), JayCompositorError> {
|
||||||
let ss = Rc::new(JayScreenshot {
|
let ss = Rc::new(JayScreenshot {
|
||||||
id: req.id,
|
id,
|
||||||
client: self.client.clone(),
|
client: self.client.clone(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
});
|
});
|
||||||
track!(self.client, ss);
|
track!(self.client, ss);
|
||||||
self.client.add_client_obj(&ss)?;
|
self.client.add_client_obj(&ss)?;
|
||||||
match take_screenshot(&self.client.state) {
|
match take_screenshot(&self.client.state, include_cursor) {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
let dmabuf = s.bo.dmabuf();
|
let dmabuf = s.bo.dmabuf();
|
||||||
let plane = &dmabuf.planes[0];
|
let plane = &dmabuf.planes[0];
|
||||||
|
|
@ -347,6 +360,7 @@ object_base! {
|
||||||
CREATE_SCREENCAST => create_screencast,
|
CREATE_SCREENCAST => create_screencast,
|
||||||
GET_RANDR => get_randr,
|
GET_RANDR => get_randr,
|
||||||
GET_INPUT => get_input,
|
GET_INPUT => get_input,
|
||||||
|
TAKE_SCREENSHOT2 => take_screenshot2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Object for JayCompositor {}
|
impl Object for JayCompositor {}
|
||||||
|
|
|
||||||
|
|
@ -909,6 +909,11 @@ impl WlSeatGlobal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(feature = "it"), allow(dead_code))]
|
||||||
|
pub fn get_desired_known_cursor(&self) -> Option<KnownCursor> {
|
||||||
|
self.desired_known_cursor.get()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_known_cursor(&self, cursor: KnownCursor) {
|
pub fn set_known_cursor(&self, cursor: KnownCursor) {
|
||||||
self.desired_known_cursor.set(Some(cursor));
|
self.desired_known_cursor.set(Some(cursor));
|
||||||
let cursors = match self.state.cursors.get() {
|
let cursors = match self.state.cursors.get() {
|
||||||
|
|
|
||||||
|
|
@ -246,7 +246,7 @@ pub struct WlSurface {
|
||||||
tearing: Cell<bool>,
|
tearing: Cell<bool>,
|
||||||
version: u32,
|
version: u32,
|
||||||
pub has_content_type_manager: Cell<bool>,
|
pub has_content_type_manager: Cell<bool>,
|
||||||
content_type: Cell<Option<ContentType>>,
|
pub content_type: Cell<Option<ContentType>>,
|
||||||
pub drm_feedback: CopyHashMap<ZwpLinuxDmabufFeedbackV1Id, Rc<ZwpLinuxDmabufFeedbackV1>>,
|
pub drm_feedback: CopyHashMap<ZwpLinuxDmabufFeedbackV1Id, Rc<ZwpLinuxDmabufFeedbackV1>>,
|
||||||
sync_obj_surface: CloneCell<Option<Rc<WpLinuxDrmSyncobjSurfaceV1>>>,
|
sync_obj_surface: CloneCell<Option<Rc<WpLinuxDrmSyncobjSurfaceV1>>>,
|
||||||
destroyed: Cell<bool>,
|
destroyed: Cell<bool>,
|
||||||
|
|
@ -553,6 +553,11 @@ impl WlSurface {
|
||||||
Ok(ext.into_xsurface().unwrap())
|
Ok(ext.into_xsurface().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg_attr(not(feature = "it"), allow(dead_code))]
|
||||||
|
pub fn get_output(&self) -> Rc<OutputNode> {
|
||||||
|
self.output.get()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_output(&self, output: &Rc<OutputNode>) {
|
pub fn set_output(&self, output: &Rc<OutputNode>) {
|
||||||
let old = self.output.set(output.clone());
|
let old = self.output.set(output.clone());
|
||||||
if old.id == output.id {
|
if old.id == output.id {
|
||||||
|
|
@ -910,14 +915,6 @@ impl WlSurface {
|
||||||
release,
|
release,
|
||||||
};
|
};
|
||||||
self.buffer.set(Some(Rc::new(surface_buffer)));
|
self.buffer.set(Some(Rc::new(surface_buffer)));
|
||||||
self.buf_x.fetch_add(dx);
|
|
||||||
self.buf_y.fetch_add(dy);
|
|
||||||
if (dx, dy) != (0, 0) {
|
|
||||||
self.need_extents_update.set(true);
|
|
||||||
for (_, cursor) in &self.cursors {
|
|
||||||
cursor.dec_hotspot(dx, dy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
self.buf_x.set(0);
|
self.buf_x.set(0);
|
||||||
self.buf_y.set(0);
|
self.buf_y.set(0);
|
||||||
|
|
@ -926,6 +923,14 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if self.buffer.is_some() && (dx, dy) != (0, 0) {
|
||||||
|
self.buf_x.fetch_add(dx);
|
||||||
|
self.buf_y.fetch_add(dy);
|
||||||
|
self.need_extents_update.set(true);
|
||||||
|
for (_, cursor) in &self.cursors {
|
||||||
|
cursor.dec_hotspot(dx, dy);
|
||||||
|
}
|
||||||
|
}
|
||||||
let transform_changed = viewport_changed || scale_changed || buffer_transform_changed;
|
let transform_changed = viewport_changed || scale_changed || buffer_transform_changed;
|
||||||
if buffer_changed || transform_changed {
|
if buffer_changed || transform_changed {
|
||||||
let mut buffer_points = self.buffer_points.borrow_mut();
|
let mut buffer_points = self.buffer_points.borrow_mut();
|
||||||
|
|
@ -1019,6 +1024,7 @@ impl WlSurface {
|
||||||
{
|
{
|
||||||
if let Some(region) = pending.input_region.take() {
|
if let Some(region) = pending.input_region.take() {
|
||||||
self.input_region.set(region);
|
self.input_region.set(region);
|
||||||
|
self.client.state.tree_changed();
|
||||||
}
|
}
|
||||||
if let Some(region) = pending.opaque_region.take() {
|
if let Some(region) = pending.opaque_region.take() {
|
||||||
self.opaque_region.set(region);
|
self.opaque_region.set(region);
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ const STATE_TILED_LEFT: u32 = 5;
|
||||||
const STATE_TILED_RIGHT: u32 = 6;
|
const STATE_TILED_RIGHT: u32 = 6;
|
||||||
const STATE_TILED_TOP: u32 = 7;
|
const STATE_TILED_TOP: u32 = 7;
|
||||||
const STATE_TILED_BOTTOM: u32 = 8;
|
const STATE_TILED_BOTTOM: u32 = 8;
|
||||||
const STATE_SUSPENDED: u32 = 9;
|
pub const STATE_SUSPENDED: u32 = 9;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
const CAP_WINDOW_MENU: u32 = 1;
|
const CAP_WINDOW_MENU: u32 = 1;
|
||||||
|
|
|
||||||
10
src/it.rs
10
src/it.rs
|
|
@ -42,6 +42,10 @@ mod tests;
|
||||||
const SINGLE_THREAD: bool = false;
|
const SINGLE_THREAD: bool = false;
|
||||||
|
|
||||||
pub fn run_tests() {
|
pub fn run_tests() {
|
||||||
|
run_tests_(tests::tests());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_tests_(tests: Vec<&'static dyn TestCase>) {
|
||||||
leaks::init();
|
leaks::init();
|
||||||
test_logger::install();
|
test_logger::install();
|
||||||
test_logger::set_level(Level::Trace);
|
test_logger::set_level(Level::Trace);
|
||||||
|
|
@ -54,13 +58,13 @@ pub fn run_tests() {
|
||||||
failed: Default::default(),
|
failed: Default::default(),
|
||||||
});
|
});
|
||||||
if SINGLE_THREAD {
|
if SINGLE_THREAD {
|
||||||
for test in tests::tests() {
|
for test in tests {
|
||||||
with_test_config(|cfg| {
|
with_test_config(|cfg| {
|
||||||
run_test(&it_run, test, cfg);
|
run_test(&it_run, test, cfg);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let queue = Arc::new(Mutex::new(VecDeque::from_iter(tests::tests())));
|
let queue = Arc::new(Mutex::new(VecDeque::from_iter(tests)));
|
||||||
let mut threads = vec![];
|
let mut threads = vec![];
|
||||||
let num_cpus = match num_cpus() {
|
let num_cpus = match num_cpus() {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
|
|
@ -139,7 +143,7 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase, cfg: Rc<TestConfig>) {
|
||||||
Box::new(async move {
|
Box::new(async move {
|
||||||
let future: Pin<_> = test.run(testrun.clone()).into();
|
let future: Pin<_> = test.run(testrun.clone()).into();
|
||||||
let future = state.eng.spawn2(Phase::Present, future);
|
let future = state.eng.spawn2(Phase::Present, future);
|
||||||
let timeout = state.wheel.timeout(5000);
|
let timeout = state.wheel.timeout(500000);
|
||||||
match future::select(future, timeout).await {
|
match future::select(future, timeout).await {
|
||||||
Either::Left((Ok(..), _)) => {}
|
Either::Left((Ok(..), _)) => {}
|
||||||
Either::Left((Err(e), _)) => {
|
Either::Left((Err(e), _)) => {
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,15 @@ use {
|
||||||
ScrollAxis, TransformMatrix,
|
ScrollAxis, TransformMatrix,
|
||||||
},
|
},
|
||||||
compositor::TestFuture,
|
compositor::TestFuture,
|
||||||
|
drm_feedback::DrmFeedback,
|
||||||
fixed::Fixed,
|
fixed::Fixed,
|
||||||
gfx_api::GfxError,
|
gfx_api::GfxError,
|
||||||
it::test_error::TestResult,
|
it::{test_error::TestResult, test_utils::test_expected_event::TEEH},
|
||||||
state::State,
|
state::State,
|
||||||
time::now_usec,
|
time::now_usec,
|
||||||
utils::{
|
utils::{
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, oserror::OsError, syncqueue::SyncQueue,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, on_change::OnChange, oserror::OsError,
|
||||||
|
syncqueue::SyncQueue,
|
||||||
},
|
},
|
||||||
video::drm::{ConnectorType, Drm},
|
video::drm::{ConnectorType, Drm},
|
||||||
},
|
},
|
||||||
|
|
@ -39,10 +41,12 @@ pub enum TestBackendError {
|
||||||
pub struct TestBackend {
|
pub struct TestBackend {
|
||||||
pub state: Rc<State>,
|
pub state: Rc<State>,
|
||||||
pub test_future: TestFuture,
|
pub test_future: TestFuture,
|
||||||
|
pub default_monitor_info: MonitorInfo,
|
||||||
pub default_connector: Rc<TestConnector>,
|
pub default_connector: Rc<TestConnector>,
|
||||||
pub default_mouse: Rc<TestBackendMouse>,
|
pub default_mouse: Rc<TestBackendMouse>,
|
||||||
pub default_kb: Rc<TestBackendKb>,
|
pub default_kb: Rc<TestBackendKb>,
|
||||||
pub render_context_installed: Cell<bool>,
|
pub render_context_installed: Cell<bool>,
|
||||||
|
pub idle: TEEH<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestBackend {
|
impl TestBackend {
|
||||||
|
|
@ -55,7 +59,7 @@ impl TestBackend {
|
||||||
idx: 1,
|
idx: 1,
|
||||||
},
|
},
|
||||||
events: Default::default(),
|
events: Default::default(),
|
||||||
on_change: Default::default(),
|
feedback: Default::default(),
|
||||||
});
|
});
|
||||||
let default_mouse = Rc::new(TestBackendMouse {
|
let default_mouse = Rc::new(TestBackendMouse {
|
||||||
common: TestInputDeviceCommon {
|
common: TestInputDeviceCommon {
|
||||||
|
|
@ -89,13 +93,29 @@ impl TestBackend {
|
||||||
name: Rc::new("default-keyboard".to_string()),
|
name: Rc::new("default-keyboard".to_string()),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
let mode = Mode {
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
refresh_rate_millihz: 60_000,
|
||||||
|
};
|
||||||
|
let default_monitor_info = MonitorInfo {
|
||||||
|
modes: vec![mode],
|
||||||
|
manufacturer: "jay".to_string(),
|
||||||
|
product: "TestConnector".to_string(),
|
||||||
|
serial_number: default_connector.id.to_string(),
|
||||||
|
initial_mode: mode,
|
||||||
|
width_mm: 80,
|
||||||
|
height_mm: 60,
|
||||||
|
};
|
||||||
Self {
|
Self {
|
||||||
state: state.clone(),
|
state: state.clone(),
|
||||||
test_future: future,
|
test_future: future,
|
||||||
|
default_monitor_info,
|
||||||
default_connector,
|
default_connector,
|
||||||
default_mouse,
|
default_mouse,
|
||||||
default_kb,
|
default_kb,
|
||||||
render_context_installed: Cell::new(false),
|
render_context_installed: Cell::new(false),
|
||||||
|
idle: Rc::new(Default::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,22 +133,9 @@ impl TestBackend {
|
||||||
self.state
|
self.state
|
||||||
.backend_events
|
.backend_events
|
||||||
.push(BackendEvent::NewConnector(self.default_connector.clone()));
|
.push(BackendEvent::NewConnector(self.default_connector.clone()));
|
||||||
let mode = Mode {
|
|
||||||
width: 800,
|
|
||||||
height: 600,
|
|
||||||
refresh_rate_millihz: 60_000,
|
|
||||||
};
|
|
||||||
self.default_connector
|
self.default_connector
|
||||||
.events
|
.events
|
||||||
.push(ConnectorEvent::Connected(MonitorInfo {
|
.send_event(ConnectorEvent::Connected(self.default_monitor_info.clone()));
|
||||||
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,
|
|
||||||
}));
|
|
||||||
self.state
|
self.state
|
||||||
.backend_events
|
.backend_events
|
||||||
.push(BackendEvent::NewInputDevice(self.default_kb.clone()));
|
.push(BackendEvent::NewInputDevice(self.default_kb.clone()));
|
||||||
|
|
@ -205,7 +212,9 @@ impl Backend for TestBackend {
|
||||||
let _ = vtnr;
|
let _ = vtnr;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_idle(&self, _idle: bool) {}
|
fn set_idle(&self, idle: bool) {
|
||||||
|
self.idle.push(idle);
|
||||||
|
}
|
||||||
|
|
||||||
fn supports_presentation_feedback(&self) -> bool {
|
fn supports_presentation_feedback(&self) -> bool {
|
||||||
true
|
true
|
||||||
|
|
@ -215,8 +224,8 @@ impl Backend for TestBackend {
|
||||||
pub struct TestConnector {
|
pub struct TestConnector {
|
||||||
pub id: ConnectorId,
|
pub id: ConnectorId,
|
||||||
pub kernel_id: ConnectorKernelId,
|
pub kernel_id: ConnectorKernelId,
|
||||||
pub events: SyncQueue<ConnectorEvent>,
|
pub events: OnChange<ConnectorEvent>,
|
||||||
pub on_change: CloneCell<Option<Rc<dyn Fn()>>>,
|
pub feedback: CloneCell<Option<Rc<DrmFeedback>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connector for TestConnector {
|
impl Connector for TestConnector {
|
||||||
|
|
@ -229,11 +238,11 @@ impl Connector for TestConnector {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn event(&self) -> Option<ConnectorEvent> {
|
fn event(&self) -> Option<ConnectorEvent> {
|
||||||
self.events.pop()
|
self.events.events.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||||
self.on_change.set(Some(cb));
|
self.events.on_change.set(Some(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn damage(&self) {
|
fn damage(&self) {
|
||||||
|
|
@ -247,6 +256,10 @@ impl Connector for TestConnector {
|
||||||
fn set_mode(&self, _mode: Mode) {
|
fn set_mode(&self, _mode: Mode) {
|
||||||
// todo
|
// todo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn drm_feedback(&self) -> Option<Rc<DrmFeedback>> {
|
||||||
|
self.feedback.get()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestMouseClick {
|
pub struct TestMouseClick {
|
||||||
|
|
@ -319,13 +332,17 @@ impl TestBackendMouse {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scroll_px(&self, dy: i32) {
|
pub fn scroll_px(&self, dy: i32) {
|
||||||
|
self.scroll_px2(dy, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll_px2(&self, dy: i32, inverted: bool) {
|
||||||
self.common.event(InputEvent::AxisSource {
|
self.common.event(InputEvent::AxisSource {
|
||||||
source: AxisSource::Finger,
|
source: AxisSource::Finger,
|
||||||
});
|
});
|
||||||
self.common.event(InputEvent::AxisPx {
|
self.common.event(InputEvent::AxisPx {
|
||||||
dist: Fixed::from_int(dy),
|
dist: Fixed::from_int(dy),
|
||||||
axis: ScrollAxis::Vertical,
|
axis: ScrollAxis::Vertical,
|
||||||
inverted: false,
|
inverted,
|
||||||
});
|
});
|
||||||
self.common.event(InputEvent::AxisFrame {
|
self.common.event(InputEvent::AxisFrame {
|
||||||
time_usec: now_usec(),
|
time_usec: now_usec(),
|
||||||
|
|
|
||||||
|
|
@ -2,22 +2,23 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
cli::screenshot::buf_to_qoi,
|
cli::screenshot::buf_to_qoi,
|
||||||
client::Client,
|
client::Client,
|
||||||
format::ARGB8888,
|
|
||||||
globals::GlobalBase,
|
globals::GlobalBase,
|
||||||
it::{
|
it::{
|
||||||
test_error::{TestError, TestResult},
|
test_error::{TestError, TestResult},
|
||||||
test_ifs::{
|
test_ifs::{
|
||||||
test_compositor::TestCompositor, test_jay_compositor::TestJayCompositor,
|
test_compositor::TestCompositor, test_cursor_shape_manager::TestCursorShapeManager,
|
||||||
test_keyboard::TestKeyboard, test_pointer::TestPointer,
|
test_data_device_manager::TestDataDeviceManager,
|
||||||
test_registry::TestRegistry, test_seat::TestSeat, test_shm::TestShm,
|
test_jay_compositor::TestJayCompositor, test_keyboard::TestKeyboard,
|
||||||
test_subcompositor::TestSubcompositor, test_xdg_base::TestXdgWmBase,
|
test_pointer::TestPointer, test_registry::TestRegistry, test_seat::TestSeat,
|
||||||
|
test_shm::TestShm, test_single_pixel_buffer_manager::TestSinglePixelBufferManager,
|
||||||
|
test_subcompositor::TestSubcompositor, test_viewporter::TestViewporter,
|
||||||
|
test_xdg_activation::TestXdgActivation, test_xdg_base::TestXdgWmBase,
|
||||||
},
|
},
|
||||||
test_transport::TestTransport,
|
test_transport::TestTransport,
|
||||||
test_utils::test_window::TestWindow,
|
test_utils::test_window::TestWindow,
|
||||||
testrun::TestRun,
|
testrun::TestRun,
|
||||||
},
|
},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
utils::clonecell::CloneCell,
|
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -31,7 +32,12 @@ pub struct TestClient {
|
||||||
pub comp: Rc<TestCompositor>,
|
pub comp: Rc<TestCompositor>,
|
||||||
pub sub: Rc<TestSubcompositor>,
|
pub sub: Rc<TestSubcompositor>,
|
||||||
pub shm: Rc<TestShm>,
|
pub shm: Rc<TestShm>,
|
||||||
|
pub spbm: Rc<TestSinglePixelBufferManager>,
|
||||||
|
pub viewporter: Rc<TestViewporter>,
|
||||||
pub xdg: Rc<TestXdgWmBase>,
|
pub xdg: Rc<TestXdgWmBase>,
|
||||||
|
pub activation: Rc<TestXdgActivation>,
|
||||||
|
pub data_device_manager: Rc<TestDataDeviceManager>,
|
||||||
|
pub cursor_shape_manager: Rc<TestCursorShapeManager>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DefaultSeat {
|
pub struct DefaultSeat {
|
||||||
|
|
@ -65,7 +71,7 @@ impl TestClient {
|
||||||
caps: Cell::new(0),
|
caps: Cell::new(0),
|
||||||
name: Default::default(),
|
name: Default::default(),
|
||||||
});
|
});
|
||||||
self.registry.bind(&tseat, seat.name().raw(), 7)?;
|
self.registry.bind(&tseat, seat.name().raw(), 9)?;
|
||||||
self.tran.sync().await;
|
self.tran.sync().await;
|
||||||
let server = self.tran.get_server_obj(tseat.id)?;
|
let server = self.tran.get_server_obj(tseat.id)?;
|
||||||
tseat.server.set(Some(server));
|
tseat.server.set(Some(server));
|
||||||
|
|
@ -79,26 +85,32 @@ impl TestClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn sync(&self) {
|
pub async fn sync(&self) {
|
||||||
|
self.run.state.eng.yield_now().await;
|
||||||
self.run.sync().await;
|
self.run.sync().await;
|
||||||
self.tran.sync().await;
|
self.tran.sync().await;
|
||||||
|
self.run.state.eng.yield_now().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn take_screenshot(&self) -> Result<Vec<u8>, TestError> {
|
pub async fn take_screenshot(&self, include_cursor: bool) -> Result<Vec<u8>, TestError> {
|
||||||
let dmabuf = self.jc.take_screenshot().await?;
|
let dmabuf = self.jc.take_screenshot(include_cursor).await?;
|
||||||
let qoi = buf_to_qoi(&self.server.state.dma_buf_ids, &dmabuf);
|
let qoi = buf_to_qoi(&self.server.state.dma_buf_ids, &dmabuf);
|
||||||
Ok(qoi)
|
Ok(qoi)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub async fn save_screenshot(&self, name: &str) -> Result<(), TestError> {
|
pub async fn save_screenshot(&self, name: &str, include_cursor: bool) -> Result<(), TestError> {
|
||||||
let qoi = self.take_screenshot().await?;
|
let qoi = self.take_screenshot(include_cursor).await?;
|
||||||
let path = format!("{}/screenshot_{}.qoi", self.run.out_dir, name);
|
let path = format!("{}/screenshot_{}.qoi", self.run.out_dir, name);
|
||||||
std::fs::write(path, qoi)?;
|
std::fs::write(path, qoi)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn compare_screenshot(&self, name: &str) -> Result<(), TestError> {
|
pub async fn compare_screenshot(
|
||||||
let actual = self.take_screenshot().await?;
|
&self,
|
||||||
|
name: &str,
|
||||||
|
include_cursor: bool,
|
||||||
|
) -> Result<(), TestError> {
|
||||||
|
let actual = self.take_screenshot(include_cursor).await?;
|
||||||
let expected_path = format!("{}/screenshot_{}.qoi", self.run.in_dir, name);
|
let expected_path = format!("{}/screenshot_{}.qoi", self.run.in_dir, name);
|
||||||
let expected = std::fs::read(expected_path)?;
|
let expected = std::fs::read(expected_path)?;
|
||||||
if actual != expected {
|
if actual != expected {
|
||||||
|
|
@ -114,19 +126,18 @@ impl TestClient {
|
||||||
|
|
||||||
pub async fn create_window(&self) -> Result<Rc<TestWindow>, TestError> {
|
pub async fn create_window(&self) -> Result<Rc<TestWindow>, TestError> {
|
||||||
let surface = self.comp.create_surface().await?;
|
let surface = self.comp.create_surface().await?;
|
||||||
let shm = self.shm.create_pool(0)?;
|
let viewport = self.viewporter.get_viewport(&surface)?;
|
||||||
let buffer = shm.create_buffer(0, 0, 0, 0, ARGB8888)?;
|
|
||||||
let xdg = self.xdg.create_xdg_surface(surface.id).await?;
|
let xdg = self.xdg.create_xdg_surface(surface.id).await?;
|
||||||
let tl = xdg.create_toplevel().await?;
|
let tl = xdg.create_toplevel().await?;
|
||||||
surface.commit()?;
|
surface.commit()?;
|
||||||
self.sync().await;
|
self.sync().await;
|
||||||
Ok(Rc::new(TestWindow {
|
Ok(Rc::new(TestWindow {
|
||||||
surface,
|
surface,
|
||||||
|
spbm: self.spbm.clone(),
|
||||||
|
viewport,
|
||||||
xdg,
|
xdg,
|
||||||
tl,
|
tl,
|
||||||
shm,
|
color: Cell::new(Color::SOLID_BLACK),
|
||||||
buffer: CloneCell::new(buffer),
|
|
||||||
color: Cell::new(Color::from_rgba_straight(0, 0, 0, 0)),
|
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use {
|
||||||
backend::InputDeviceId,
|
backend::InputDeviceId,
|
||||||
ifs::wl_seat::SeatId,
|
ifs::wl_seat::SeatId,
|
||||||
it::test_error::{TestError, TestResult},
|
it::test_error::{TestError, TestResult},
|
||||||
|
tree::OutputNode,
|
||||||
utils::{copyhashmap::CopyHashMap, stack::Stack},
|
utils::{copyhashmap::CopyHashMap, stack::Stack},
|
||||||
},
|
},
|
||||||
bincode::Options,
|
bincode::Options,
|
||||||
|
|
@ -15,9 +16,10 @@ use {
|
||||||
},
|
},
|
||||||
input::{InputDevice, Seat},
|
input::{InputDevice, Seat},
|
||||||
keyboard::{Keymap, ModifiedKeySym},
|
keyboard::{Keymap, ModifiedKeySym},
|
||||||
|
video::{Connector, Transform},
|
||||||
Axis, Direction,
|
Axis, Direction,
|
||||||
},
|
},
|
||||||
std::{cell::Cell, ops::Deref, ptr, rc::Rc},
|
std::{cell::Cell, ops::Deref, ptr, rc::Rc, time::Duration},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub static TEST_CONFIG_ENTRY: ConfigEntry = ConfigEntry {
|
pub static TEST_CONFIG_ENTRY: ConfigEntry = ConfigEntry {
|
||||||
|
|
@ -244,6 +246,17 @@ impl TestConfig {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_idle(&self, timeout: Duration) -> TestResult {
|
||||||
|
self.send(ClientMessage::SetIdle { timeout })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_floating(&self, seat: SeatId, floating: bool) -> TestResult {
|
||||||
|
self.send(ClientMessage::SetFloating {
|
||||||
|
seat: Seat(seat.raw() as _),
|
||||||
|
floating,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn clear(&self) {
|
fn clear(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if let Some(srv) = self.srv.take() {
|
if let Some(srv) = self.srv.take() {
|
||||||
|
|
@ -251,6 +264,20 @@ impl TestConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_scale(&self, output: &OutputNode, scale: f64) -> TestResult {
|
||||||
|
self.send(ClientMessage::ConnectorSetScale {
|
||||||
|
connector: Connector(output.global.connector.connector.id().raw() as _),
|
||||||
|
scale,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_output_transform(&self, output: &OutputNode, transform: Transform) -> TestResult {
|
||||||
|
self.send(ClientMessage::ConnectorSetTransform {
|
||||||
|
connector: Connector(output.global.connector.connector.id().raw() as _),
|
||||||
|
transform,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TestConfig {
|
impl Drop for TestConfig {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,23 @@
|
||||||
|
mod test_buffer;
|
||||||
pub mod test_callback;
|
pub mod test_callback;
|
||||||
pub mod test_compositor;
|
pub mod test_compositor;
|
||||||
|
pub mod test_content_type;
|
||||||
|
pub mod test_content_type_manager;
|
||||||
|
pub mod test_cursor_shape_device;
|
||||||
|
pub mod test_cursor_shape_manager;
|
||||||
|
pub mod test_data_control_device;
|
||||||
|
pub mod test_data_control_manager;
|
||||||
|
pub mod test_data_control_offer;
|
||||||
|
pub mod test_data_control_source;
|
||||||
|
pub mod test_data_device;
|
||||||
|
pub mod test_data_device_manager;
|
||||||
|
pub mod test_data_offer;
|
||||||
|
pub mod test_data_source;
|
||||||
pub mod test_display;
|
pub mod test_display;
|
||||||
|
pub mod test_dmabuf;
|
||||||
|
pub mod test_dmabuf_feedback;
|
||||||
|
pub mod test_ext_foreign_toplevel_handle;
|
||||||
|
pub mod test_ext_foreign_toplevel_list;
|
||||||
pub mod test_jay_compositor;
|
pub mod test_jay_compositor;
|
||||||
pub mod test_keyboard;
|
pub mod test_keyboard;
|
||||||
pub mod test_pointer;
|
pub mod test_pointer;
|
||||||
|
|
@ -11,9 +28,19 @@ pub mod test_seat;
|
||||||
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_single_pixel_buffer_manager;
|
||||||
pub mod test_subcompositor;
|
pub mod test_subcompositor;
|
||||||
pub mod test_subsurface;
|
pub mod test_subsurface;
|
||||||
pub mod test_surface;
|
pub mod test_surface;
|
||||||
|
pub mod test_syncobj_manager;
|
||||||
|
pub mod test_syncobj_surface;
|
||||||
|
pub mod test_syncobj_timeline;
|
||||||
|
pub mod test_toplevel_drag;
|
||||||
|
pub mod test_toplevel_drag_manager;
|
||||||
|
pub mod test_viewport;
|
||||||
|
pub mod test_viewporter;
|
||||||
|
pub mod test_xdg_activation;
|
||||||
|
pub mod test_xdg_activation_token;
|
||||||
pub mod test_xdg_base;
|
pub mod test_xdg_base;
|
||||||
pub mod test_xdg_surface;
|
pub mod test_xdg_surface;
|
||||||
pub mod test_xdg_toplevel;
|
pub mod test_xdg_toplevel;
|
||||||
|
|
|
||||||
48
src/it/test_ifs/test_buffer.rs
Normal file
48
src/it/test_ifs/test_buffer.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
||||||
|
testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{wl_buffer::*, WlBufferId},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestBuffer {
|
||||||
|
pub id: WlBufferId,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub released: Cell<bool>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestBuffer {
|
||||||
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
|
if self.destroyed.replace(true) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_release(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let _ev = Release::parse_full(parser)?;
|
||||||
|
self.released.set(true);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestBuffer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestBuffer, WlBuffer;
|
||||||
|
|
||||||
|
RELEASE => handle_release,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestBuffer {}
|
||||||
|
|
@ -20,6 +20,13 @@ pub struct TestCompositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestCompositor {
|
impl TestCompositor {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn create_surface(&self) -> Result<Rc<TestSurface>, TestError> {
|
pub async fn create_surface(&self) -> Result<Rc<TestSurface>, TestError> {
|
||||||
let id = self.tran.id();
|
let id = self.tran.id();
|
||||||
self.tran.send(CreateSurface {
|
self.tran.send(CreateSurface {
|
||||||
|
|
@ -34,6 +41,8 @@ impl TestCompositor {
|
||||||
tran: self.tran.clone(),
|
tran: self.tran.clone(),
|
||||||
server,
|
server,
|
||||||
destroyed: Cell::new(false),
|
destroyed: Cell::new(false),
|
||||||
|
preferred_buffer_scale: Rc::new(Default::default()),
|
||||||
|
preferred_buffer_transform: Rc::new(Default::default()),
|
||||||
});
|
});
|
||||||
self.tran.add_obj(surface.clone())?;
|
self.tran.add_obj(surface.clone())?;
|
||||||
Ok(surface)
|
Ok(surface)
|
||||||
|
|
|
||||||
42
src/it/test_ifs/test_content_type.rs
Normal file
42
src/it/test_ifs/test_content_type.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{test_error::TestError, test_object::TestObject, test_transport::TestTransport},
|
||||||
|
wire::{wp_content_type_v1::*, WpContentTypeV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestContentType {
|
||||||
|
pub id: WpContentTypeV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestContentType {
|
||||||
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_content_type(&self, content_type: u32) -> Result<(), TestError> {
|
||||||
|
self.tran.send(SetContentType {
|
||||||
|
self_id: self.id,
|
||||||
|
content_type,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestContentType {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestContentType, WpContentTypeV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestContentType {}
|
||||||
65
src/it/test_ifs/test_content_type_manager.rs
Normal file
65
src/it/test_ifs/test_content_type_manager.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::{TestError, TestResult},
|
||||||
|
test_ifs::{test_content_type::TestContentType, test_surface::TestSurface},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{wp_content_type_manager_v1::*, WpContentTypeManagerV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestContentTypeManager {
|
||||||
|
pub id: WpContentTypeManagerV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestContentTypeManager {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_surface_content_type(
|
||||||
|
&self,
|
||||||
|
surface: &TestSurface,
|
||||||
|
) -> TestResult<Rc<TestContentType>> {
|
||||||
|
let obj = Rc::new(TestContentType {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
self.tran.send(GetSurfaceContentType {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
surface: surface.id,
|
||||||
|
})?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestContentTypeManager {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestContentTypeManager, WpContentTypeManagerV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestContentTypeManager {}
|
||||||
38
src/it/test_ifs/test_cursor_shape_device.rs
Normal file
38
src/it/test_ifs/test_cursor_shape_device.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{test_error::TestResult, test_object::TestObject, test_transport::TestTransport},
|
||||||
|
wire::{wp_cursor_shape_device_v1::*, WpCursorShapeDeviceV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestCursorShapeDevice {
|
||||||
|
pub id: WpCursorShapeDeviceV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCursorShapeDevice {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_shape(&self, serial: u32, shape: u32) -> TestResult {
|
||||||
|
self.tran.send(SetShape {
|
||||||
|
self_id: self.id,
|
||||||
|
serial,
|
||||||
|
shape,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestCursorShapeDevice, WpCursorShapeDeviceV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestCursorShapeDevice {}
|
||||||
59
src/it/test_ifs/test_cursor_shape_manager.rs
Normal file
59
src/it/test_ifs/test_cursor_shape_manager.rs
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_ifs::{
|
||||||
|
test_cursor_shape_device::TestCursorShapeDevice, test_pointer::TestPointer,
|
||||||
|
},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{wp_cursor_shape_manager_v1::*, WpCursorShapeManagerV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestCursorShapeManager {
|
||||||
|
pub id: WpCursorShapeManagerV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestCursorShapeManager {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_pointer(&self, pointer: &TestPointer) -> TestResult<Rc<TestCursorShapeDevice>> {
|
||||||
|
let obj = Rc::new(TestCursorShapeDevice {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
self.tran.send(GetPointer {
|
||||||
|
self_id: self.id,
|
||||||
|
cursor_shape_device: obj.id,
|
||||||
|
pointer: pointer.id,
|
||||||
|
})?;
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestCursorShapeManager, WpCursorShapeManagerV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestCursorShapeManager {}
|
||||||
111
src/it/test_ifs/test_data_control_device.rs
Normal file
111
src/it/test_ifs/test_data_control_device.rs
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::{TestError, TestResult},
|
||||||
|
test_ifs::{
|
||||||
|
test_data_control_offer::TestDataControlOffer,
|
||||||
|
test_data_control_source::TestDataControlSource,
|
||||||
|
},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
test_utils::test_expected_event::TEEH,
|
||||||
|
testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::{buffd::MsgParser, copyhashmap::CopyHashMap},
|
||||||
|
wire::{
|
||||||
|
zwlr_data_control_device_v1::*, ZwlrDataControlDeviceV1Id, ZwlrDataControlOfferV1Id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDataControlDevice {
|
||||||
|
pub id: ZwlrDataControlDeviceV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
pub pending_offer: CopyHashMap<ZwlrDataControlOfferV1Id, Rc<TestDataControlOffer>>,
|
||||||
|
pub selection: TEEH<Option<Rc<TestDataControlOffer>>>,
|
||||||
|
pub primary_selection: TEEH<Option<Rc<TestDataControlOffer>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDataControlDevice {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_selection(&self, source: &TestDataControlSource) -> TestResult {
|
||||||
|
self.tran.send(SetSelection {
|
||||||
|
self_id: self.id,
|
||||||
|
source: source.id,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_primary_selection(&self, source: &TestDataControlSource) -> TestResult {
|
||||||
|
self.tran.send(SetPrimarySelection {
|
||||||
|
self_id: self.id,
|
||||||
|
source: source.id,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_data_offer(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = DataOffer::parse_full(parser)?;
|
||||||
|
let obj = Rc::new(TestDataControlOffer {
|
||||||
|
id: ev.id,
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
offers: Default::default(),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
self.pending_offer.set(obj.id, obj);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_offer(
|
||||||
|
&self,
|
||||||
|
id: ZwlrDataControlOfferV1Id,
|
||||||
|
) -> TestResult<Option<Rc<TestDataControlOffer>>> {
|
||||||
|
if id.is_none() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
match self.pending_offer.remove(&id) {
|
||||||
|
Some(o) => Ok(Some(o)),
|
||||||
|
_ => bail!("Unknown offer {}", id),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_selection(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = Selection::parse_full(parser)?;
|
||||||
|
self.selection.push(self.take_offer(ev.id)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_primary_selection(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = PrimarySelection::parse_full(parser)?;
|
||||||
|
self.primary_selection.push(self.take_offer(ev.id)?);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_finished(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let _ev = Finished::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDataControlDevice, ZwlrDataControlDeviceV1;
|
||||||
|
|
||||||
|
DATA_OFFER => handle_data_offer,
|
||||||
|
SELECTION => handle_selection,
|
||||||
|
FINISHED => handle_finished,
|
||||||
|
PRIMARY_SELECTION => handle_primary_selection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDataControlDevice {}
|
||||||
84
src/it/test_ifs/test_data_control_manager.rs
Normal file
84
src/it/test_ifs/test_data_control_manager.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_ifs::{
|
||||||
|
test_data_control_device::TestDataControlDevice,
|
||||||
|
test_data_control_source::TestDataControlSource, test_seat::TestSeat,
|
||||||
|
},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{zwlr_data_control_manager_v1::*, ZwlrDataControlManagerV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDataControlManager {
|
||||||
|
pub id: ZwlrDataControlManagerV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDataControlManager {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_data_source(&self) -> TestResult<Rc<TestDataControlSource>> {
|
||||||
|
let obj = Rc::new(TestDataControlSource {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
cancelled: Cell::new(false),
|
||||||
|
sends: Default::default(),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
self.tran.send(CreateDataSource {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
})?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_data_device(&self, seat: &TestSeat) -> TestResult<Rc<TestDataControlDevice>> {
|
||||||
|
let obj = Rc::new(TestDataControlDevice {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
pending_offer: Default::default(),
|
||||||
|
selection: Default::default(),
|
||||||
|
primary_selection: Default::default(),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
self.tran.send(GetDataDevice {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
seat: seat.id,
|
||||||
|
})?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestDataControlManager {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDataControlManager, ZwlrDataControlManagerV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDataControlManager {}
|
||||||
64
src/it/test_ifs/test_data_control_offer.rs
Normal file
64
src/it/test_ifs/test_data_control_offer.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::{TestError, TestResult},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{zwlr_data_control_offer_v1::*, ZwlrDataControlOfferV1Id},
|
||||||
|
},
|
||||||
|
ahash::AHashSet,
|
||||||
|
std::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
uapi::{c, OwnedFd},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDataControlOffer {
|
||||||
|
pub id: ZwlrDataControlOfferV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
pub offers: RefCell<AHashSet<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDataControlOffer {
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn receive(&self, mime_type: &str) -> TestResult<Rc<OwnedFd>> {
|
||||||
|
let (read, write) = uapi::pipe2(c::O_CLOEXEC)?;
|
||||||
|
self.tran.send(Receive {
|
||||||
|
self_id: self.id,
|
||||||
|
mime_type,
|
||||||
|
fd: Rc::new(write),
|
||||||
|
})?;
|
||||||
|
Ok(Rc::new(read))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_offer(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = Offer::parse_full(parser)?;
|
||||||
|
self.offers.borrow_mut().insert(ev.mime_type.to_string());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestDataControlOffer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDataControlOffer, ZwlrDataControlOfferV1;
|
||||||
|
|
||||||
|
OFFER => handle_offer,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDataControlOffer {}
|
||||||
67
src/it/test_ifs/test_data_control_source.rs
Normal file
67
src/it/test_ifs/test_data_control_source.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::{TestError, TestResult},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
test_utils::test_expected_event::TEEH,
|
||||||
|
testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{zwlr_data_control_source_v1::*, ZwlrDataControlSourceV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
uapi::OwnedFd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDataControlSource {
|
||||||
|
pub id: ZwlrDataControlSourceV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
pub cancelled: Cell<bool>,
|
||||||
|
pub sends: TEEH<(String, Rc<OwnedFd>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDataControlSource {
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offer(&self, mime_type: &str) -> TestResult {
|
||||||
|
self.tran.send(Offer {
|
||||||
|
self_id: self.id,
|
||||||
|
mime_type,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_send(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = Send::parse_full(parser)?;
|
||||||
|
self.sends.push((ev.mime_type.to_string(), ev.fd));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_cancelled(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let _ev = Cancelled::parse_full(parser)?;
|
||||||
|
self.cancelled.set(true);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestDataControlSource {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDataControlSource, ZwlrDataControlSourceV1;
|
||||||
|
|
||||||
|
SEND => handle_send,
|
||||||
|
CANCELLED => handle_cancelled,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDataControlSource {}
|
||||||
115
src/it/test_ifs/test_data_device.rs
Normal file
115
src/it/test_ifs/test_data_device.rs
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_ifs::{
|
||||||
|
test_data_offer::TestDataOffer, test_data_source::TestDataSource,
|
||||||
|
test_surface::TestSurface,
|
||||||
|
},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{wl_data_device::*, WlDataDeviceId, WlSurfaceId},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDataDevice {
|
||||||
|
pub id: WlDataDeviceId,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDataDevice {
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Release { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_drag(
|
||||||
|
&self,
|
||||||
|
source: &TestDataSource,
|
||||||
|
origin: &TestSurface,
|
||||||
|
icon: Option<&TestSurface>,
|
||||||
|
serial: u32,
|
||||||
|
) -> TestResult {
|
||||||
|
self.tran.send(StartDrag {
|
||||||
|
self_id: self.id,
|
||||||
|
source: source.id,
|
||||||
|
origin: origin.id,
|
||||||
|
icon: icon.map(|i| i.id).unwrap_or(WlSurfaceId::NONE),
|
||||||
|
serial,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_selection(&self, source: &TestDataSource, serial: u32) -> TestResult {
|
||||||
|
self.tran.send(SetSelection {
|
||||||
|
self_id: self.id,
|
||||||
|
source: source.id,
|
||||||
|
serial,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_data_offer(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let ev = DataOffer::parse_full(parser)?;
|
||||||
|
let offer = Rc::new(TestDataOffer {
|
||||||
|
id: ev.id,
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(offer.clone())?;
|
||||||
|
offer.destroy()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_enter(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Enter::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_leave(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Leave::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_motion(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Motion::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_drop(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Drop::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_selection(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Selection::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Drop for TestDataDevice {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDataDevice, WlDataDevice;
|
||||||
|
|
||||||
|
DATA_OFFER => handle_data_offer,
|
||||||
|
ENTER => handle_enter,
|
||||||
|
LEAVE => handle_leave,
|
||||||
|
MOTION => handle_motion,
|
||||||
|
DROP => handle_drop,
|
||||||
|
SELECTION => handle_selection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDataDevice {}
|
||||||
65
src/it/test_ifs/test_data_device_manager.rs
Normal file
65
src/it/test_ifs/test_data_device_manager.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_ifs::{
|
||||||
|
test_data_device::TestDataDevice, test_data_source::TestDataSource,
|
||||||
|
test_seat::TestSeat,
|
||||||
|
},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{wl_data_device_manager::*, WlDataDeviceManagerId},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDataDeviceManager {
|
||||||
|
pub id: WlDataDeviceManagerId,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDataDeviceManager {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_data_source(&self) -> TestResult<Rc<TestDataSource>> {
|
||||||
|
let data_source = Rc::new(TestDataSource {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
sends: Rc::new(Default::default()),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(data_source.clone())?;
|
||||||
|
self.tran.send(CreateDataSource {
|
||||||
|
self_id: self.id,
|
||||||
|
id: data_source.id,
|
||||||
|
})?;
|
||||||
|
Ok(data_source)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_data_device(&self, seat: &TestSeat) -> TestResult<Rc<TestDataDevice>> {
|
||||||
|
let data_device = Rc::new(TestDataDevice {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(data_device.clone())?;
|
||||||
|
self.tran.send(GetDataDevice {
|
||||||
|
self_id: self.id,
|
||||||
|
id: data_device.id,
|
||||||
|
seat: seat.id,
|
||||||
|
})?;
|
||||||
|
Ok(data_device)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDataDeviceManager, WlDataDeviceManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDataDeviceManager {}
|
||||||
57
src/it/test_ifs/test_data_offer.rs
Normal file
57
src/it/test_ifs/test_data_offer.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult, test_object::TestObject, test_transport::TestTransport,
|
||||||
|
testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{wl_data_offer::*, WlDataOfferId},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDataOffer {
|
||||||
|
pub id: WlDataOfferId,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDataOffer {
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_offer(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Offer::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_source_actions(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = SourceActions::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_action(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Action::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestDataOffer {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDataOffer, WlDataOffer;
|
||||||
|
|
||||||
|
OFFER => handle_offer,
|
||||||
|
SOURCE_ACTIONS => handle_source_actions,
|
||||||
|
ACTION => handle_action,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDataOffer {}
|
||||||
96
src/it/test_ifs/test_data_source.rs
Normal file
96
src/it/test_ifs/test_data_source.rs
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult, test_object::TestObject, test_transport::TestTransport,
|
||||||
|
test_utils::test_expected_event::TEEH, testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{wl_data_source::*, WlDataSourceId},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
uapi::OwnedFd,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDataSource {
|
||||||
|
pub id: WlDataSourceId,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
pub sends: TEEH<(String, Rc<OwnedFd>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDataSource {
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn offer(&self, mime_type: &str) -> TestResult {
|
||||||
|
self.tran.send(Offer {
|
||||||
|
self_id: self.id,
|
||||||
|
mime_type,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn set_actions(&self, actions: u32) -> TestResult {
|
||||||
|
self.tran.send(SetActions {
|
||||||
|
self_id: self.id,
|
||||||
|
dnd_actions: actions,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_target(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Target::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_send(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let ev = Send::parse_full(parser)?;
|
||||||
|
self.sends.push((ev.mime_type.to_string(), ev.fd));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_cancelled(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Cancelled::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_dnd_drop_performed(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = DndDropPerformed::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_dnd_finished(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = DndFinished::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_action(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Action::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestDataSource {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDataSource, WlDataSource;
|
||||||
|
|
||||||
|
TARGET => handle_target,
|
||||||
|
SEND => handle_send,
|
||||||
|
CANCELLED => handle_cancelled,
|
||||||
|
DND_DROP_PERFORMED => handle_dnd_drop_performed,
|
||||||
|
DND_FINISHED => handle_dnd_finished,
|
||||||
|
ACTION => handle_action,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDataSource {}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
client::MIN_SERVER_ID,
|
||||||
it::{
|
it::{
|
||||||
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
||||||
testrun::ParseFull,
|
testrun::ParseFull,
|
||||||
|
|
@ -36,7 +37,9 @@ impl TestDisplay {
|
||||||
}
|
}
|
||||||
Some(obj) => {
|
Some(obj) => {
|
||||||
obj.on_remove(&self.tran);
|
obj.on_remove(&self.tran);
|
||||||
self.tran.obj_ids.borrow_mut().release(ev.id);
|
if ev.id < MIN_SERVER_ID {
|
||||||
|
self.tran.obj_ids.borrow_mut().release(ev.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
72
src/it/test_ifs/test_dmabuf.rs
Normal file
72
src/it/test_ifs/test_dmabuf.rs
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_ifs::{test_dmabuf_feedback::TestDmabufFeedback, test_surface::TestSurface},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{zwp_linux_dmabuf_v1::*, ZwpLinuxDmabufV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDmabuf {
|
||||||
|
pub id: ZwpLinuxDmabufV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDmabuf {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn get_default_feedback(&self) -> TestResult<Rc<TestDmabufFeedback>> {
|
||||||
|
let obj = Rc::new(TestDmabufFeedback::new(&self.tran));
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
self.tran.send(GetDefaultFeedback {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
})?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_surface_feedback(
|
||||||
|
&self,
|
||||||
|
surface: &TestSurface,
|
||||||
|
) -> TestResult<Rc<TestDmabufFeedback>> {
|
||||||
|
let obj = Rc::new(TestDmabufFeedback::new(&self.tran));
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
self.tran.send(GetSurfaceFeedback {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
surface: surface.id,
|
||||||
|
})?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestDmabuf {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDmabuf, ZwpLinuxDmabufV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDmabuf {}
|
||||||
147
src/it/test_ifs/test_dmabuf_feedback.rs
Normal file
147
src/it/test_ifs/test_dmabuf_feedback.rs
Normal file
|
|
@ -0,0 +1,147 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult, test_object::TestObject, test_transport::TestTransport,
|
||||||
|
test_utils::test_expected_event::TEEH, testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{zwp_linux_dmabuf_feedback_v1::*, ZwpLinuxDmabufFeedbackV1Id},
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
mem,
|
||||||
|
ops::DerefMut,
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
uapi::{c, OwnedFd},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestDmabufFeedback {
|
||||||
|
pub id: ZwpLinuxDmabufFeedbackV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
pub feedback: TEEH<Feedback>,
|
||||||
|
pub pending_feedback: RefCell<PendingFeedback>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct PendingFeedback {
|
||||||
|
pub format_table: Option<Rc<OwnedFd>>,
|
||||||
|
pub format_table_size: usize,
|
||||||
|
pub main_device: c::dev_t,
|
||||||
|
pub tranches: Vec<Tranche>,
|
||||||
|
pub pending_tranche: Tranche,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Feedback {
|
||||||
|
pub format_table: Rc<OwnedFd>,
|
||||||
|
pub format_table_size: usize,
|
||||||
|
pub main_device: c::dev_t,
|
||||||
|
pub tranches: Vec<Tranche>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct Tranche {
|
||||||
|
pub target_device: c::dev_t,
|
||||||
|
pub formats: Vec<usize>,
|
||||||
|
pub flags: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDmabufFeedback {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
feedback: Rc::new(Default::default()),
|
||||||
|
pending_feedback: RefCell::new(Default::default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_done(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = Done::parse_full(parser)?;
|
||||||
|
let mut pending = mem::take(self.pending_feedback.borrow_mut().deref_mut());
|
||||||
|
self.feedback.push(Feedback {
|
||||||
|
format_table: match pending.format_table.take() {
|
||||||
|
None => bail!("compositor did not send format table"),
|
||||||
|
Some(ft) => ft,
|
||||||
|
},
|
||||||
|
format_table_size: pending.format_table_size,
|
||||||
|
main_device: pending.main_device,
|
||||||
|
tranches: pending.tranches,
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_format_table(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let ev = FormatTable::parse_full(parser)?;
|
||||||
|
let pending = &mut *self.pending_feedback.borrow_mut();
|
||||||
|
pending.format_table = Some(ev.fd);
|
||||||
|
pending.format_table_size = ev.size as _;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_main_device(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let ev = MainDevice::parse_full(parser)?;
|
||||||
|
let pending = &mut *self.pending_feedback.borrow_mut();
|
||||||
|
pending.main_device = ev.device;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_tranche_done(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let _ev = TrancheDone::parse_full(parser)?;
|
||||||
|
let pending = &mut *self.pending_feedback.borrow_mut();
|
||||||
|
pending
|
||||||
|
.tranches
|
||||||
|
.push(mem::take(&mut pending.pending_tranche));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_tranche_target_device(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let ev = TrancheTargetDevice::parse_full(parser)?;
|
||||||
|
let pending = &mut *self.pending_feedback.borrow_mut();
|
||||||
|
pending.pending_tranche.target_device = ev.device;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_tranche_formats(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let ev = TrancheFormats::parse_full(parser)?;
|
||||||
|
let pending = &mut *self.pending_feedback.borrow_mut();
|
||||||
|
pending.pending_tranche.formats = ev.indices.iter().copied().map(|v| v as usize).collect();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_tranche_flags(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let ev = TrancheFlags::parse_full(parser)?;
|
||||||
|
let pending = &mut *self.pending_feedback.borrow_mut();
|
||||||
|
pending.pending_tranche.flags = ev.flags;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestDmabufFeedback {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestDmabufFeedback, ZwpLinuxDmabufFeedbackV1;
|
||||||
|
|
||||||
|
DONE => handle_done,
|
||||||
|
FORMAT_TABLE => handle_format_table,
|
||||||
|
MAIN_DEVICE => handle_main_device,
|
||||||
|
TRANCHE_DONE => handle_tranche_done,
|
||||||
|
TRANCHE_TARGET_DEVICE => handle_tranche_target_device,
|
||||||
|
TRANCHE_FORMATS => handle_tranche_formats,
|
||||||
|
TRANCHE_FLAGS => handle_tranche_flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestDmabufFeedback {}
|
||||||
74
src/it/test_ifs/test_ext_foreign_toplevel_handle.rs
Normal file
74
src/it/test_ifs/test_ext_foreign_toplevel_handle.rs
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::{TestError, TestResult},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{ext_foreign_toplevel_handle_v1::*, ExtForeignToplevelHandleV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestExtForeignToplevelHandle {
|
||||||
|
pub id: ExtForeignToplevelHandleV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
pub closed: Cell<bool>,
|
||||||
|
pub title: Cell<Option<String>>,
|
||||||
|
pub app_id: Cell<Option<String>>,
|
||||||
|
pub identifier: Cell<Option<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestExtForeignToplevelHandle {
|
||||||
|
fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_closed(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let _ev = Closed::parse_full(parser)?;
|
||||||
|
self.closed.set(true);
|
||||||
|
self.destroy()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_done(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let _ev = Done::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_title(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = Title::parse_full(parser)?;
|
||||||
|
self.title.set(Some(ev.title.to_string()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_app_id(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = AppId::parse_full(parser)?;
|
||||||
|
self.app_id.set(Some(ev.app_id.to_string()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_identifier(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = Identifier::parse_full(parser)?;
|
||||||
|
self.identifier.set(Some(ev.identifier.to_string()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestExtForeignToplevelHandle, ExtForeignToplevelHandleV1;
|
||||||
|
|
||||||
|
CLOSED => handle_closed,
|
||||||
|
DONE => handle_done,
|
||||||
|
TITLE => handle_title,
|
||||||
|
APP_ID => handle_app_id,
|
||||||
|
IDENTIFIER => handle_identifier,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestExtForeignToplevelHandle {}
|
||||||
79
src/it/test_ifs/test_ext_foreign_toplevel_list.rs
Normal file
79
src/it/test_ifs/test_ext_foreign_toplevel_list.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::{TestError, TestResult},
|
||||||
|
test_ifs::test_ext_foreign_toplevel_handle::TestExtForeignToplevelHandle,
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{ext_foreign_toplevel_list_v1::*, ExtForeignToplevelListV1Id},
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
cell::{Cell, RefCell},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestExtForeignToplevelList {
|
||||||
|
pub id: ExtForeignToplevelListV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
pub toplevels: RefCell<Vec<Rc<TestExtForeignToplevelHandle>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestExtForeignToplevelList {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
toplevels: RefCell::new(vec![]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn stop(&self) -> TestResult {
|
||||||
|
self.tran.send(Stop { self_id: self.id })?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_toplevel(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = Toplevel::parse_full(parser)?;
|
||||||
|
let tl = Rc::new(TestExtForeignToplevelHandle {
|
||||||
|
id: ev.toplevel,
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
closed: Cell::new(false),
|
||||||
|
title: Cell::new(None),
|
||||||
|
app_id: Cell::new(None),
|
||||||
|
identifier: Cell::new(None),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(tl.clone())?;
|
||||||
|
self.toplevels.borrow_mut().push(tl);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_finished(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let _ev = Finished::parse_full(parser)?;
|
||||||
|
self.destroy()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestExtForeignToplevelList, ExtForeignToplevelListV1;
|
||||||
|
|
||||||
|
TOPLEVEL => handle_toplevel,
|
||||||
|
FINISHED => handle_finished,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestExtForeignToplevelList {}
|
||||||
|
|
@ -2,8 +2,11 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
client::ClientId,
|
client::ClientId,
|
||||||
it::{
|
it::{
|
||||||
test_error::TestError, test_ifs::test_screenshot::TestJayScreenshot,
|
test_error::{TestError, TestResult},
|
||||||
test_object::TestObject, test_transport::TestTransport, testrun::ParseFull,
|
test_ifs::test_screenshot::TestJayScreenshot,
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
testrun::ParseFull,
|
||||||
},
|
},
|
||||||
utils::{buffd::MsgParser, cell_ext::CellExt},
|
utils::{buffd::MsgParser, cell_ext::CellExt},
|
||||||
wire::{
|
wire::{
|
||||||
|
|
@ -22,6 +25,14 @@ pub struct TestJayCompositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestJayCompositor {
|
impl TestJayCompositor {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
client_id: Cell::new(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_client_id(&self) -> Result<ClientId, TestError> {
|
pub async fn get_client_id(&self) -> Result<ClientId, TestError> {
|
||||||
if self.client_id.is_none() {
|
if self.client_id.is_none() {
|
||||||
self.tran.send(GetClientId { self_id: self.id })?;
|
self.tran.send(GetClientId { self_id: self.id })?;
|
||||||
|
|
@ -33,14 +44,20 @@ impl TestJayCompositor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn take_screenshot(&self) -> Result<Dmabuf, TestError> {
|
pub fn enable_symmetric_delete(&self) -> TestResult {
|
||||||
|
self.tran.send(EnableSymmetricDelete { self_id: self.id })?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn take_screenshot(&self, include_cursor: bool) -> Result<Dmabuf, TestError> {
|
||||||
let js = Rc::new(TestJayScreenshot {
|
let js = Rc::new(TestJayScreenshot {
|
||||||
id: self.tran.id(),
|
id: self.tran.id(),
|
||||||
result: Cell::new(None),
|
result: Cell::new(None),
|
||||||
});
|
});
|
||||||
self.tran.send(TakeScreenshot {
|
self.tran.send(TakeScreenshot2 {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
id: js.id,
|
id: js.id,
|
||||||
|
include_cursor: include_cursor as _,
|
||||||
})?;
|
})?;
|
||||||
self.tran.add_obj(js.clone())?;
|
self.tran.add_obj(js.clone())?;
|
||||||
self.tran.sync().await;
|
self.tran.sync().await;
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,12 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
ifs::wl_seat::wl_pointer::WlPointer,
|
ifs::wl_seat::wl_pointer::WlPointer,
|
||||||
it::{
|
it::{
|
||||||
test_error::TestResult, test_object::TestObject, test_transport::TestTransport,
|
test_error::TestResult, test_ifs::test_surface::TestSurface, test_object::TestObject,
|
||||||
test_utils::test_expected_event::TEEH, testrun::ParseFull,
|
test_transport::TestTransport, test_utils::test_expected_event::TEEH,
|
||||||
|
testrun::ParseFull,
|
||||||
},
|
},
|
||||||
utils::{buffd::MsgParser, clonecell::CloneCell},
|
utils::{buffd::MsgParser, clonecell::CloneCell},
|
||||||
wire::{wl_pointer::*, WlPointerId},
|
wire::{wl_pointer::*, WlPointerId, WlSurfaceId},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
@ -19,6 +20,8 @@ pub struct TestPointer {
|
||||||
pub leave: TEEH<Leave>,
|
pub leave: TEEH<Leave>,
|
||||||
pub enter: TEEH<Enter>,
|
pub enter: TEEH<Enter>,
|
||||||
pub motion: TEEH<Motion>,
|
pub motion: TEEH<Motion>,
|
||||||
|
pub button: TEEH<Button>,
|
||||||
|
pub axis_relative_direction: TEEH<AxisRelativeDirection>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestPointer {
|
impl TestPointer {
|
||||||
|
|
@ -29,6 +32,23 @@ impl TestPointer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_cursor(
|
||||||
|
&self,
|
||||||
|
serial: u32,
|
||||||
|
surface: Option<&TestSurface>,
|
||||||
|
hotspot_x: i32,
|
||||||
|
hotspot_y: i32,
|
||||||
|
) -> TestResult {
|
||||||
|
self.tran.send(SetCursor {
|
||||||
|
self_id: self.id,
|
||||||
|
serial,
|
||||||
|
surface: surface.map(|s| s.id).unwrap_or(WlSurfaceId::NONE),
|
||||||
|
hotspot_x,
|
||||||
|
hotspot_y,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_enter(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
fn handle_enter(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
let ev = Enter::parse_full(parser)?;
|
let ev = Enter::parse_full(parser)?;
|
||||||
self.enter.push(ev);
|
self.enter.push(ev);
|
||||||
|
|
@ -48,7 +68,8 @@ impl TestPointer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_button(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
fn handle_button(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
let _ev = Button::parse_full(parser)?;
|
let ev = Button::parse_full(parser)?;
|
||||||
|
self.button.push(ev);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,6 +97,12 @@ impl TestPointer {
|
||||||
let _ev = AxisDiscrete::parse_full(parser)?;
|
let _ev = AxisDiscrete::parse_full(parser)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_axis_relative_direction(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||||
|
let ev = AxisRelativeDirection::parse_full(parser)?;
|
||||||
|
self.axis_relative_direction.push(ev);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TestPointer {
|
impl Drop for TestPointer {
|
||||||
|
|
@ -96,6 +123,7 @@ test_object! {
|
||||||
AXIS_SOURCE => handle_axis_source,
|
AXIS_SOURCE => handle_axis_source,
|
||||||
AXIS_STOP => handle_axis_stop,
|
AXIS_STOP => handle_axis_stop,
|
||||||
AXIS_DISCRETE => handle_axis_discrete,
|
AXIS_DISCRETE => handle_axis_discrete,
|
||||||
|
AXIS_RELATIVE_DIRECTION => handle_axis_relative_direction,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestObject for TestPointer {}
|
impl TestObject for TestPointer {}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,16 @@ use {
|
||||||
it::{
|
it::{
|
||||||
test_error::TestError,
|
test_error::TestError,
|
||||||
test_ifs::{
|
test_ifs::{
|
||||||
test_compositor::TestCompositor, test_jay_compositor::TestJayCompositor,
|
test_compositor::TestCompositor, test_content_type_manager::TestContentTypeManager,
|
||||||
test_shm::TestShm, test_subcompositor::TestSubcompositor,
|
test_cursor_shape_manager::TestCursorShapeManager,
|
||||||
|
test_data_control_manager::TestDataControlManager,
|
||||||
|
test_data_device_manager::TestDataDeviceManager, test_dmabuf::TestDmabuf,
|
||||||
|
test_ext_foreign_toplevel_list::TestExtForeignToplevelList,
|
||||||
|
test_jay_compositor::TestJayCompositor, test_shm::TestShm,
|
||||||
|
test_single_pixel_buffer_manager::TestSinglePixelBufferManager,
|
||||||
|
test_subcompositor::TestSubcompositor, test_syncobj_manager::TestSyncobjManager,
|
||||||
|
test_toplevel_drag_manager::TestToplevelDragManager,
|
||||||
|
test_viewporter::TestViewporter, test_xdg_activation::TestXdgActivation,
|
||||||
test_xdg_base::TestXdgWmBase,
|
test_xdg_base::TestXdgWmBase,
|
||||||
},
|
},
|
||||||
test_object::TestObject,
|
test_object::TestObject,
|
||||||
|
|
@ -16,7 +24,7 @@ use {
|
||||||
utils::{buffd::MsgParser, clonecell::CloneCell, copyhashmap::CopyHashMap},
|
utils::{buffd::MsgParser, clonecell::CloneCell, copyhashmap::CopyHashMap},
|
||||||
wire::{wl_registry::*, WlRegistryId, WlSeat},
|
wire::{wl_registry::*, WlRegistryId, WlSeat},
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TestGlobal {
|
pub struct TestGlobal {
|
||||||
|
|
@ -31,6 +39,17 @@ pub struct TestRegistrySingletons {
|
||||||
pub wl_subcompositor: u32,
|
pub wl_subcompositor: u32,
|
||||||
pub wl_shm: u32,
|
pub wl_shm: u32,
|
||||||
pub xdg_wm_base: u32,
|
pub xdg_wm_base: u32,
|
||||||
|
pub wp_single_pixel_buffer_manager_v1: u32,
|
||||||
|
pub wp_viewporter: u32,
|
||||||
|
pub xdg_activation_v1: u32,
|
||||||
|
pub ext_foreign_toplevel_list_v1: u32,
|
||||||
|
pub wl_data_device_manager: u32,
|
||||||
|
pub wp_cursor_shape_manager_v1: u32,
|
||||||
|
pub wp_linux_drm_syncobj_manager_v1: u32,
|
||||||
|
pub wp_content_type_manager_v1: u32,
|
||||||
|
pub zwlr_data_control_manager_v1: u32,
|
||||||
|
pub zwp_linux_dmabuf_v1: u32,
|
||||||
|
pub xdg_toplevel_drag_manager_v1: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestRegistry {
|
pub struct TestRegistry {
|
||||||
|
|
@ -42,7 +61,18 @@ pub struct TestRegistry {
|
||||||
pub compositor: CloneCell<Option<Rc<TestCompositor>>>,
|
pub compositor: CloneCell<Option<Rc<TestCompositor>>>,
|
||||||
pub subcompositor: CloneCell<Option<Rc<TestSubcompositor>>>,
|
pub subcompositor: CloneCell<Option<Rc<TestSubcompositor>>>,
|
||||||
pub shm: CloneCell<Option<Rc<TestShm>>>,
|
pub shm: CloneCell<Option<Rc<TestShm>>>,
|
||||||
|
pub spbm: CloneCell<Option<Rc<TestSinglePixelBufferManager>>>,
|
||||||
|
pub viewporter: CloneCell<Option<Rc<TestViewporter>>>,
|
||||||
pub xdg: CloneCell<Option<Rc<TestXdgWmBase>>>,
|
pub xdg: CloneCell<Option<Rc<TestXdgWmBase>>>,
|
||||||
|
pub activation: CloneCell<Option<Rc<TestXdgActivation>>>,
|
||||||
|
pub foreign_toplevel_list: CloneCell<Option<Rc<TestExtForeignToplevelList>>>,
|
||||||
|
pub data_device_manager: CloneCell<Option<Rc<TestDataDeviceManager>>>,
|
||||||
|
pub cursor_shape_manager: CloneCell<Option<Rc<TestCursorShapeManager>>>,
|
||||||
|
pub syncobj_manager: CloneCell<Option<Rc<TestSyncobjManager>>>,
|
||||||
|
pub content_type_manager: CloneCell<Option<Rc<TestContentTypeManager>>>,
|
||||||
|
pub data_control_manager: CloneCell<Option<Rc<TestDataControlManager>>>,
|
||||||
|
pub dmabuf: CloneCell<Option<Rc<TestDmabuf>>>,
|
||||||
|
pub drag_manager: CloneCell<Option<Rc<TestToplevelDragManager>>>,
|
||||||
pub seats: CopyHashMap<GlobalName, Rc<WlSeatGlobal>>,
|
pub seats: CopyHashMap<GlobalName, Rc<WlSeatGlobal>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,6 +84,20 @@ macro_rules! singleton {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! create_singleton {
|
||||||
|
($fn:ident, $field:ident, $name:ident, $ver:expr, $ty:ident) => {
|
||||||
|
pub async fn $fn(&self) -> Result<Rc<$ty>, TestError> {
|
||||||
|
singleton!(self.$field);
|
||||||
|
let singletons = self.get_singletons().await?;
|
||||||
|
singleton!(self.$field);
|
||||||
|
let jc = Rc::new($ty::new(&self.tran));
|
||||||
|
self.bind(&jc, singletons.$name, $ver)?;
|
||||||
|
self.$field.set(Some(jc.clone()));
|
||||||
|
Ok(jc)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
|
@ -62,7 +106,7 @@ impl TestRegistry {
|
||||||
macro_rules! singleton {
|
macro_rules! singleton {
|
||||||
($($name:ident,)*) => {{
|
($($name:ident,)*) => {{
|
||||||
$(
|
$(
|
||||||
let mut $name = 0;
|
let mut $name = u32::MAX;
|
||||||
)*
|
)*
|
||||||
for global in self.globals.lock().values() {
|
for global in self.globals.lock().values() {
|
||||||
match global.interface.as_str() {
|
match global.interface.as_str() {
|
||||||
|
|
@ -74,12 +118,7 @@ impl TestRegistry {
|
||||||
}
|
}
|
||||||
Rc::new(TestRegistrySingletons {
|
Rc::new(TestRegistrySingletons {
|
||||||
$(
|
$(
|
||||||
$name: {
|
$name,
|
||||||
if $name == 0 {
|
|
||||||
bail!("Compositor did not send {} singleton", stringify!($name));
|
|
||||||
}
|
|
||||||
$name
|
|
||||||
},
|
|
||||||
)*
|
)*
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
|
|
@ -90,80 +129,104 @@ impl TestRegistry {
|
||||||
wl_subcompositor,
|
wl_subcompositor,
|
||||||
wl_shm,
|
wl_shm,
|
||||||
xdg_wm_base,
|
xdg_wm_base,
|
||||||
|
wp_single_pixel_buffer_manager_v1,
|
||||||
|
wp_viewporter,
|
||||||
|
xdg_activation_v1,
|
||||||
|
ext_foreign_toplevel_list_v1,
|
||||||
|
wl_data_device_manager,
|
||||||
|
wp_cursor_shape_manager_v1,
|
||||||
|
wp_linux_drm_syncobj_manager_v1,
|
||||||
|
wp_content_type_manager_v1,
|
||||||
|
zwlr_data_control_manager_v1,
|
||||||
|
zwp_linux_dmabuf_v1,
|
||||||
|
xdg_toplevel_drag_manager_v1,
|
||||||
};
|
};
|
||||||
self.singletons.set(Some(singletons.clone()));
|
self.singletons.set(Some(singletons.clone()));
|
||||||
Ok(singletons)
|
Ok(singletons)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_jay_compositor(&self) -> Result<Rc<TestJayCompositor>, TestError> {
|
create_singleton!(
|
||||||
singleton!(self.jay_compositor);
|
get_jay_compositor,
|
||||||
let singletons = self.get_singletons().await?;
|
jay_compositor,
|
||||||
singleton!(self.jay_compositor);
|
jay_compositor,
|
||||||
let jc = Rc::new(TestJayCompositor {
|
1,
|
||||||
id: self.tran.id(),
|
TestJayCompositor
|
||||||
tran: self.tran.clone(),
|
);
|
||||||
client_id: Default::default(),
|
create_singleton!(get_compositor, compositor, wl_compositor, 6, TestCompositor);
|
||||||
});
|
create_singleton!(
|
||||||
self.bind(&jc, singletons.jay_compositor, 1)?;
|
get_subcompositor,
|
||||||
self.jay_compositor.set(Some(jc.clone()));
|
subcompositor,
|
||||||
Ok(jc)
|
wl_subcompositor,
|
||||||
}
|
1,
|
||||||
|
TestSubcompositor
|
||||||
pub async fn get_compositor(&self) -> Result<Rc<TestCompositor>, TestError> {
|
);
|
||||||
singleton!(self.compositor);
|
create_singleton!(get_shm, shm, wl_shm, 1, TestShm);
|
||||||
let singletons = self.get_singletons().await?;
|
create_singleton!(
|
||||||
singleton!(self.compositor);
|
get_spbm,
|
||||||
let jc = Rc::new(TestCompositor {
|
spbm,
|
||||||
id: self.tran.id(),
|
wp_single_pixel_buffer_manager_v1,
|
||||||
tran: self.tran.clone(),
|
1,
|
||||||
});
|
TestSinglePixelBufferManager
|
||||||
self.bind(&jc, singletons.wl_compositor, 4)?;
|
);
|
||||||
self.compositor.set(Some(jc.clone()));
|
create_singleton!(get_viewporter, viewporter, wp_viewporter, 1, TestViewporter);
|
||||||
Ok(jc)
|
create_singleton!(
|
||||||
}
|
get_activation,
|
||||||
|
activation,
|
||||||
pub async fn get_subcompositor(&self) -> Result<Rc<TestSubcompositor>, TestError> {
|
xdg_activation_v1,
|
||||||
singleton!(self.subcompositor);
|
1,
|
||||||
let singletons = self.get_singletons().await?;
|
TestXdgActivation
|
||||||
singleton!(self.subcompositor);
|
);
|
||||||
let jc = Rc::new(TestSubcompositor {
|
create_singleton!(get_xdg, xdg, xdg_wm_base, 6, TestXdgWmBase);
|
||||||
id: self.tran.id(),
|
create_singleton!(
|
||||||
tran: self.tran.clone(),
|
get_foreign_toplevel_list,
|
||||||
destroyed: Cell::new(false),
|
foreign_toplevel_list,
|
||||||
});
|
ext_foreign_toplevel_list_v1,
|
||||||
self.bind(&jc, singletons.wl_subcompositor, 1)?;
|
1,
|
||||||
self.subcompositor.set(Some(jc.clone()));
|
TestExtForeignToplevelList
|
||||||
Ok(jc)
|
);
|
||||||
}
|
create_singleton!(
|
||||||
|
get_data_device_manager,
|
||||||
pub async fn get_shm(&self) -> Result<Rc<TestShm>, TestError> {
|
data_device_manager,
|
||||||
singleton!(self.shm);
|
wl_data_device_manager,
|
||||||
let singletons = self.get_singletons().await?;
|
3,
|
||||||
singleton!(self.shm);
|
TestDataDeviceManager
|
||||||
let jc = Rc::new(TestShm {
|
);
|
||||||
id: self.tran.id(),
|
create_singleton!(
|
||||||
tran: self.tran.clone(),
|
get_cursor_shape_manager,
|
||||||
formats: Default::default(),
|
cursor_shape_manager,
|
||||||
formats_awaited: Cell::new(false),
|
wp_cursor_shape_manager_v1,
|
||||||
});
|
1,
|
||||||
self.bind(&jc, singletons.wl_shm, 1)?;
|
TestCursorShapeManager
|
||||||
self.shm.set(Some(jc.clone()));
|
);
|
||||||
Ok(jc)
|
create_singleton!(
|
||||||
}
|
get_syncobj_manager,
|
||||||
|
syncobj_manager,
|
||||||
pub async fn get_xdg(&self) -> Result<Rc<TestXdgWmBase>, TestError> {
|
wp_linux_drm_syncobj_manager_v1,
|
||||||
singleton!(self.xdg);
|
1,
|
||||||
let singletons = self.get_singletons().await?;
|
TestSyncobjManager
|
||||||
singleton!(self.xdg);
|
);
|
||||||
let jc = Rc::new(TestXdgWmBase {
|
create_singleton!(
|
||||||
id: self.tran.id(),
|
get_content_type_manager,
|
||||||
tran: self.tran.clone(),
|
content_type_manager,
|
||||||
destroyed: Cell::new(false),
|
wp_content_type_manager_v1,
|
||||||
});
|
1,
|
||||||
self.bind(&jc, singletons.xdg_wm_base, 3)?;
|
TestContentTypeManager
|
||||||
self.xdg.set(Some(jc.clone()));
|
);
|
||||||
Ok(jc)
|
create_singleton!(
|
||||||
}
|
get_data_control_manager,
|
||||||
|
data_control_manager,
|
||||||
|
zwlr_data_control_manager_v1,
|
||||||
|
2,
|
||||||
|
TestDataControlManager
|
||||||
|
);
|
||||||
|
create_singleton!(get_dmabuf, dmabuf, zwp_linux_dmabuf_v1, 5, TestDmabuf);
|
||||||
|
create_singleton!(
|
||||||
|
get_drag_manager,
|
||||||
|
drag_manager,
|
||||||
|
xdg_toplevel_drag_manager_v1,
|
||||||
|
1,
|
||||||
|
TestToplevelDragManager
|
||||||
|
);
|
||||||
|
|
||||||
pub fn bind<O: TestObject>(
|
pub fn bind<O: TestObject>(
|
||||||
&self,
|
&self,
|
||||||
|
|
@ -176,7 +239,7 @@ impl TestRegistry {
|
||||||
name,
|
name,
|
||||||
interface: obj.interface().name(),
|
interface: obj.interface().name(),
|
||||||
version,
|
version,
|
||||||
id: obj.id().into(),
|
id: obj.id(),
|
||||||
})?;
|
})?;
|
||||||
self.tran.add_obj(obj.clone())?;
|
self.tran.add_obj(obj.clone())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ impl TestSeat {
|
||||||
leave: Rc::new(Default::default()),
|
leave: Rc::new(Default::default()),
|
||||||
enter: Rc::new(Default::default()),
|
enter: Rc::new(Default::default()),
|
||||||
motion: Rc::new(Default::default()),
|
motion: Rc::new(Default::default()),
|
||||||
|
button: Rc::new(Default::default()),
|
||||||
|
axis_relative_direction: Rc::new(Default::default()),
|
||||||
});
|
});
|
||||||
self.tran.add_obj(pointer.clone())?;
|
self.tran.add_obj(pointer.clone())?;
|
||||||
self.tran.sync().await;
|
self.tran.sync().await;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,15 @@ pub struct TestShm {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestShm {
|
impl TestShm {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
formats: Default::default(),
|
||||||
|
formats_awaited: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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.tran.sync().await;
|
self.tran.sync().await;
|
||||||
|
|
@ -30,6 +39,7 @@ impl TestShm {
|
||||||
&self.formats
|
&self.formats
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
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 {
|
||||||
|
|
@ -48,6 +58,7 @@ impl TestShm {
|
||||||
Ok(pool)
|
Ok(pool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn create_buffer(&self, width: i32, height: i32) -> TestResult<Rc<TestShmBuffer>> {
|
pub fn create_buffer(&self, width: i32, height: i32) -> TestResult<Rc<TestShmBuffer>> {
|
||||||
let pool = self.create_pool((width * height * 4) as _)?;
|
let pool = self.create_pool((width * height * 4) as _)?;
|
||||||
pool.create_buffer(0, width, height, width * 4, ARGB8888)
|
pool.create_buffer(0, width, height, width * 4, ARGB8888)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
it::{
|
it::{test_ifs::test_buffer::TestBuffer, test_mem::TestMem},
|
||||||
test_error::TestError, test_mem::TestMem, test_object::TestObject,
|
|
||||||
test_transport::TestTransport, testrun::ParseFull,
|
|
||||||
},
|
|
||||||
theme::Color,
|
theme::Color,
|
||||||
utils::{buffd::MsgParser, windows::WindowsExt},
|
utils::windows::WindowsExt,
|
||||||
wire::{wl_buffer::*, WlBufferId},
|
|
||||||
},
|
},
|
||||||
std::{
|
std::{
|
||||||
cell::Cell,
|
cell::Cell,
|
||||||
|
|
@ -16,15 +12,13 @@ use {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TestShmBuffer {
|
pub struct TestShmBuffer {
|
||||||
pub id: WlBufferId,
|
pub buffer: Rc<TestBuffer>,
|
||||||
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 destroyed: Cell<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestShmBuffer {
|
impl TestShmBuffer {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn fill(&self, color: Color) {
|
pub fn fill(&self, color: Color) {
|
||||||
let [cr, cg, cb, ca] = color.to_rgba_premultiplied();
|
let [cr, cg, cb, ca] = color.to_rgba_premultiplied();
|
||||||
for [b, g, r, a] in self.deref().array_chunks_ext::<4>() {
|
for [b, g, r, a] in self.deref().array_chunks_ext::<4>() {
|
||||||
|
|
@ -34,20 +28,6 @@ impl TestShmBuffer {
|
||||||
a.set(ca);
|
a.set(ca);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(&self) -> Result<(), TestError> {
|
|
||||||
if self.destroyed.replace(true) {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
self.tran.send(Destroy { self_id: self.id })?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_release(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
|
||||||
let _ev = Release::parse_full(parser)?;
|
|
||||||
self.released.set(true);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for TestShmBuffer {
|
impl Deref for TestShmBuffer {
|
||||||
|
|
@ -57,17 +37,3 @@ impl Deref for TestShmBuffer {
|
||||||
&self.mem[self.range.clone()]
|
&self.mem[self.range.clone()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TestShmBuffer {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let _ = self.destroy();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test_object! {
|
|
||||||
TestShmBuffer, WlBuffer;
|
|
||||||
|
|
||||||
RELEASE => handle_release,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestObject for TestShmBuffer {}
|
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
format::Format,
|
format::Format,
|
||||||
it::{
|
it::{
|
||||||
test_error::TestError, test_ifs::test_shm_buffer::TestShmBuffer, test_mem::TestMem,
|
test_error::TestError,
|
||||||
test_object::TestObject, test_transport::TestTransport,
|
test_ifs::{test_buffer::TestBuffer, test_shm_buffer::TestShmBuffer},
|
||||||
|
test_mem::TestMem,
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
},
|
},
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
wire::{wl_shm_pool::*, WlShmPoolId},
|
wire::{wl_shm_pool::*, WlShmPoolId},
|
||||||
|
|
@ -19,6 +22,7 @@ pub struct TestShmPool {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestShmPool {
|
impl TestShmPool {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn create_buffer(
|
pub fn create_buffer(
|
||||||
&self,
|
&self,
|
||||||
offset: i32,
|
offset: i32,
|
||||||
|
|
@ -35,17 +39,19 @@ impl TestShmPool {
|
||||||
bail!("Out-of-bounds buffer");
|
bail!("Out-of-bounds buffer");
|
||||||
}
|
}
|
||||||
let buffer = Rc::new(TestShmBuffer {
|
let buffer = Rc::new(TestShmBuffer {
|
||||||
id: self.tran.id(),
|
buffer: Rc::new(TestBuffer {
|
||||||
tran: self.tran.clone(),
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
released: Cell::new(true),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}),
|
||||||
range: start..end,
|
range: start..end,
|
||||||
mem,
|
mem,
|
||||||
released: Cell::new(true),
|
|
||||||
destroyed: Cell::new(false),
|
|
||||||
});
|
});
|
||||||
self.tran.add_obj(buffer.clone())?;
|
self.tran.add_obj(buffer.buffer.clone())?;
|
||||||
self.tran.send(CreateBuffer {
|
self.tran.send(CreateBuffer {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
id: buffer.id,
|
id: buffer.buffer.id,
|
||||||
offset,
|
offset,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
|
|
@ -55,6 +61,7 @@ impl TestShmPool {
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
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);
|
||||||
|
|
|
||||||
51
src/it/test_ifs/test_single_pixel_buffer_manager.rs
Normal file
51
src/it/test_ifs/test_single_pixel_buffer_manager.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult, test_ifs::test_buffer::TestBuffer, test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
theme::Color,
|
||||||
|
wire::{wp_single_pixel_buffer_manager_v1::*, WpSinglePixelBufferManagerV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestSinglePixelBufferManager {
|
||||||
|
pub id: WpSinglePixelBufferManagerV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestSinglePixelBufferManager {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create_buffer(&self, color: Color) -> TestResult<Rc<TestBuffer>> {
|
||||||
|
let obj = Rc::new(TestBuffer {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
released: Cell::new(true),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
let map = |c: f32| (c as f64 * u32::MAX as f64) as u32;
|
||||||
|
self.tran.send(CreateU32RgbaBuffer {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
r: map(color.r),
|
||||||
|
g: map(color.g),
|
||||||
|
b: map(color.b),
|
||||||
|
a: map(color.a),
|
||||||
|
})?;
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestSinglePixelBufferManager, WpSinglePixelBufferManagerV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestSinglePixelBufferManager {}
|
||||||
|
|
@ -16,6 +16,14 @@ pub struct TestSubcompositor {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestSubcompositor {
|
impl TestSubcompositor {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn destroy(&self) -> Result<(), TestError> {
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
if !self.destroyed.replace(true) {
|
if !self.destroyed.replace(true) {
|
||||||
self.tran.send(Destroy { self_id: self.id })?;
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,11 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
ifs::wl_surface::WlSurface,
|
ifs::wl_surface::WlSurface,
|
||||||
it::{
|
it::{
|
||||||
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
test_error::{TestError, TestResult},
|
||||||
|
test_ifs::test_region::TestRegion,
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
test_utils::test_expected_event::TEEH,
|
||||||
testrun::ParseFull,
|
testrun::ParseFull,
|
||||||
},
|
},
|
||||||
utils::buffd::MsgParser,
|
utils::buffd::MsgParser,
|
||||||
|
|
@ -16,6 +20,8 @@ pub struct TestSurface {
|
||||||
pub tran: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub server: Rc<WlSurface>,
|
pub server: Rc<WlSurface>,
|
||||||
pub destroyed: Cell<bool>,
|
pub destroyed: Cell<bool>,
|
||||||
|
pub preferred_buffer_scale: TEEH<i32>,
|
||||||
|
pub preferred_buffer_transform: TEEH<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestSurface {
|
impl TestSurface {
|
||||||
|
|
@ -36,6 +42,23 @@ impl TestSurface {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn offset(&self, dx: i32, dy: i32) -> Result<(), TestError> {
|
||||||
|
self.tran.send(Offset {
|
||||||
|
self_id: self.id,
|
||||||
|
x: dx,
|
||||||
|
y: dy,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_input_region(&self, region: &TestRegion) -> TestResult {
|
||||||
|
self.tran.send(SetInputRegion {
|
||||||
|
self_id: self.id,
|
||||||
|
region: region.id,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn commit(&self) -> Result<(), TestError> {
|
pub fn commit(&self) -> Result<(), TestError> {
|
||||||
self.tran.send(Commit { self_id: self.id })?;
|
self.tran.send(Commit { self_id: self.id })?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -50,6 +73,21 @@ impl TestSurface {
|
||||||
let _ev = Leave::parse_full(parser)?;
|
let _ev = Leave::parse_full(parser)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_preferred_buffer_scale(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = PreferredBufferScale::parse_full(parser)?;
|
||||||
|
self.preferred_buffer_scale.push(ev.factor);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_preferred_buffer_transform(
|
||||||
|
&self,
|
||||||
|
parser: MsgParser<'_, '_>,
|
||||||
|
) -> Result<(), TestError> {
|
||||||
|
let ev = PreferredBufferTransform::parse_full(parser)?;
|
||||||
|
self.preferred_buffer_transform.push(ev.transform);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TestSurface {
|
impl Drop for TestSurface {
|
||||||
|
|
@ -63,6 +101,8 @@ test_object! {
|
||||||
|
|
||||||
ENTER => handle_enter,
|
ENTER => handle_enter,
|
||||||
LEAVE => handle_leave,
|
LEAVE => handle_leave,
|
||||||
|
PREFERRED_BUFFER_SCALE => handle_preferred_buffer_scale,
|
||||||
|
PREFERRED_BUFFER_TRANSFORM => handle_preferred_buffer_transform,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestObject for TestSurface {}
|
impl TestObject for TestSurface {}
|
||||||
|
|
|
||||||
81
src/it/test_ifs/test_syncobj_manager.rs
Normal file
81
src/it/test_ifs/test_syncobj_manager.rs
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_ifs::{
|
||||||
|
test_surface::TestSurface, test_syncobj_surface::TestSyncobjSurface,
|
||||||
|
test_syncobj_timeline::TestSyncobjTimeline,
|
||||||
|
},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
video::drm::sync_obj::SyncObj,
|
||||||
|
wire::{wp_linux_drm_syncobj_manager_v1::*, WpLinuxDrmSyncobjManagerV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestSyncobjManager {
|
||||||
|
pub id: WpLinuxDrmSyncobjManagerV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestSyncobjManager {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_surface(&self, surface: &TestSurface) -> TestResult<Rc<TestSyncobjSurface>> {
|
||||||
|
let obj = Rc::new(TestSyncobjSurface {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
self.tran.send(GetSurface {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
surface: surface.id,
|
||||||
|
})?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn import_timeline(&self, syncobj: &SyncObj) -> TestResult<Rc<TestSyncobjTimeline>> {
|
||||||
|
let obj = Rc::new(TestSyncobjTimeline {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
self.tran.send(ImportTimeline {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
fd: syncobj.fd().clone(),
|
||||||
|
})?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestSyncobjManager {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestSyncobjManager, WpLinuxDrmSyncobjManagerV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestSyncobjManager {}
|
||||||
57
src/it/test_ifs/test_syncobj_surface.rs
Normal file
57
src/it/test_ifs/test_syncobj_surface.rs
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult, test_ifs::test_syncobj_timeline::TestSyncobjTimeline,
|
||||||
|
test_object::TestObject, test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{wp_linux_drm_syncobj_surface_v1::*, WpLinuxDrmSyncobjSurfaceV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestSyncobjSurface {
|
||||||
|
pub id: WpLinuxDrmSyncobjSurfaceV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestSyncobjSurface {
|
||||||
|
pub fn destroy(&self) -> TestResult {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_acquire_point(&self, tl: &TestSyncobjTimeline, point: u64) -> TestResult {
|
||||||
|
self.tran.send(SetAcquirePoint {
|
||||||
|
self_id: self.id,
|
||||||
|
timeline: tl.id,
|
||||||
|
point_hi: (point >> 32) as _,
|
||||||
|
point_lo: point as _,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_release_point(&self, tl: &TestSyncobjTimeline, point: u64) -> TestResult {
|
||||||
|
self.tran.send(SetReleasePoint {
|
||||||
|
self_id: self.id,
|
||||||
|
timeline: tl.id,
|
||||||
|
point_hi: (point >> 32) as _,
|
||||||
|
point_lo: point as _,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestSyncobjSurface {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestSyncobjSurface, WpLinuxDrmSyncobjSurfaceV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestSyncobjSurface {}
|
||||||
34
src/it/test_ifs/test_syncobj_timeline.rs
Normal file
34
src/it/test_ifs/test_syncobj_timeline.rs
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{test_error::TestError, test_object::TestObject, test_transport::TestTransport},
|
||||||
|
wire::{wp_linux_drm_syncobj_timeline_v1::*, WpLinuxDrmSyncobjTimelineV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestSyncobjTimeline {
|
||||||
|
pub id: WpLinuxDrmSyncobjTimelineV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestSyncobjTimeline {
|
||||||
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestSyncobjTimeline {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestSyncobjTimeline, WpLinuxDrmSyncobjTimelineV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestSyncobjTimeline {}
|
||||||
52
src/it/test_ifs/test_toplevel_drag.rs
Normal file
52
src/it/test_ifs/test_toplevel_drag.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestError, test_ifs::test_xdg_toplevel::TestXdgToplevel,
|
||||||
|
test_object::TestObject, test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{xdg_toplevel_drag_v1::*, XdgToplevelDragV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestToplevelDrag {
|
||||||
|
pub id: XdgToplevelDragV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestToplevelDrag {
|
||||||
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attach(
|
||||||
|
&self,
|
||||||
|
toplevel: &TestXdgToplevel,
|
||||||
|
x_offset: i32,
|
||||||
|
y_offset: i32,
|
||||||
|
) -> Result<(), TestError> {
|
||||||
|
self.tran.send(Attach {
|
||||||
|
self_id: self.id,
|
||||||
|
toplevel: toplevel.core.id,
|
||||||
|
x_offset,
|
||||||
|
y_offset,
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestToplevelDrag {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestToplevelDrag, XdgToplevelDragV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestToplevelDrag {}
|
||||||
65
src/it/test_ifs/test_toplevel_drag_manager.rs
Normal file
65
src/it/test_ifs/test_toplevel_drag_manager.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::{TestError, TestResult},
|
||||||
|
test_ifs::{test_data_source::TestDataSource, test_toplevel_drag::TestToplevelDrag},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{xdg_toplevel_drag_manager_v1::*, XdgToplevelDragManagerV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestToplevelDragManager {
|
||||||
|
pub id: XdgToplevelDragManagerV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestToplevelDragManager {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_xdg_toplevel_drag(
|
||||||
|
&self,
|
||||||
|
data_source: &TestDataSource,
|
||||||
|
) -> TestResult<Rc<TestToplevelDrag>> {
|
||||||
|
let obj = Rc::new(TestToplevelDrag {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
self.tran.send(GetXdgToplevelDrag {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
data_source: data_source.id,
|
||||||
|
})?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestToplevelDragManager {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestToplevelDragManager, XdgToplevelDragManagerV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestToplevelDragManager {}
|
||||||
52
src/it/test_ifs/test_viewport.rs
Normal file
52
src/it/test_ifs/test_viewport.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
fixed::Fixed,
|
||||||
|
it::{test_error::TestError, test_object::TestObject, test_transport::TestTransport},
|
||||||
|
wire::{wp_viewport::*, WpViewportId},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestViewport {
|
||||||
|
pub id: WpViewportId,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestViewport {
|
||||||
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_source(&self, x: i32, y: i32, width: i32, height: i32) -> Result<(), TestError> {
|
||||||
|
self.tran.send(SetSource {
|
||||||
|
self_id: self.id,
|
||||||
|
x: Fixed::from_int(x),
|
||||||
|
y: Fixed::from_int(y),
|
||||||
|
width: Fixed::from_int(width),
|
||||||
|
height: Fixed::from_int(height),
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_destination(&self, width: i32, height: i32) -> Result<(), TestError> {
|
||||||
|
self.tran.send(SetDestination {
|
||||||
|
self_id: self.id,
|
||||||
|
width: width.max(1),
|
||||||
|
height: height.max(1),
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for TestViewport {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestViewport, WpViewport;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestViewport {}
|
||||||
46
src/it/test_ifs/test_viewporter.rs
Normal file
46
src/it/test_ifs/test_viewporter.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_ifs::{test_surface::TestSurface, test_viewport::TestViewport},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{wp_viewporter::*, WpViewporterId},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestViewporter {
|
||||||
|
pub id: WpViewporterId,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestViewporter {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_viewport(&self, surface: &TestSurface) -> TestResult<Rc<TestViewport>> {
|
||||||
|
let obj = Rc::new(TestViewport {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
});
|
||||||
|
self.tran.send(GetViewport {
|
||||||
|
self_id: self.id,
|
||||||
|
id: obj.id,
|
||||||
|
surface: surface.id,
|
||||||
|
})?;
|
||||||
|
self.tran.add_obj(obj.clone())?;
|
||||||
|
Ok(obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestViewporter, WpViewporter;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestViewporter {}
|
||||||
74
src/it/test_ifs/test_xdg_activation.rs
Normal file
74
src/it/test_ifs/test_xdg_activation.rs
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::{TestError, TestResult},
|
||||||
|
test_ifs::{
|
||||||
|
test_surface::TestSurface, test_xdg_activation_token::TestXdgActivationToken,
|
||||||
|
},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
},
|
||||||
|
wire::{xdg_activation_v1::*, XdgActivationV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestXdgActivation {
|
||||||
|
pub id: XdgActivationV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestXdgActivation {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_token(&self) -> Result<String, TestError> {
|
||||||
|
let token = Rc::new(TestXdgActivationToken {
|
||||||
|
id: self.tran.id(),
|
||||||
|
tran: self.tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
token: Cell::new(None),
|
||||||
|
});
|
||||||
|
self.tran.add_obj(token.clone())?;
|
||||||
|
self.tran.send(GetActivationToken {
|
||||||
|
self_id: self.id,
|
||||||
|
id: token.id,
|
||||||
|
})?;
|
||||||
|
let res = token.commit().await?;
|
||||||
|
token.destroy()?;
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn activate(&self, tl: &TestSurface, token: &str) -> TestResult {
|
||||||
|
self.tran.send(Activate {
|
||||||
|
self_id: self.id,
|
||||||
|
token,
|
||||||
|
surface: tl.id,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestXdgActivation, XdgActivationV1;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestXdgActivation {}
|
||||||
|
|
||||||
|
impl Drop for TestXdgActivation {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
56
src/it/test_ifs/test_xdg_activation_token.rs
Normal file
56
src/it/test_ifs/test_xdg_activation_token.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestError, test_object::TestObject, test_transport::TestTransport,
|
||||||
|
testrun::ParseFull,
|
||||||
|
},
|
||||||
|
utils::buffd::MsgParser,
|
||||||
|
wire::{xdg_activation_token_v1::*, XdgActivationTokenV1Id},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct TestXdgActivationToken {
|
||||||
|
pub id: XdgActivationTokenV1Id,
|
||||||
|
pub tran: Rc<TestTransport>,
|
||||||
|
pub destroyed: Cell<bool>,
|
||||||
|
pub token: Cell<Option<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestXdgActivationToken {
|
||||||
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
|
if !self.destroyed.replace(true) {
|
||||||
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn commit(&self) -> Result<String, TestError> {
|
||||||
|
self.tran.send(Commit { self_id: self.id })?;
|
||||||
|
self.tran.sync().await;
|
||||||
|
match self.token.take() {
|
||||||
|
Some(t) => Ok(t),
|
||||||
|
_ => bail!("Server did not send a token"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_done(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let ev = Done::parse_full(parser)?;
|
||||||
|
self.token.set(Some(ev.token.to_string()));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test_object! {
|
||||||
|
TestXdgActivationToken, XdgActivationTokenV1;
|
||||||
|
|
||||||
|
DONE => handle_done,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestObject for TestXdgActivationToken {}
|
||||||
|
|
||||||
|
impl Drop for TestXdgActivationToken {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = self.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,6 +17,14 @@ pub struct TestXdgWmBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestXdgWmBase {
|
impl TestXdgWmBase {
|
||||||
|
pub fn new(tran: &Rc<TestTransport>) -> Self {
|
||||||
|
Self {
|
||||||
|
id: tran.id(),
|
||||||
|
tran: tran.clone(),
|
||||||
|
destroyed: Cell::new(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn destroy(&self) -> Result<(), TestError> {
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
if !self.destroyed.replace(true) {
|
if !self.destroyed.replace(true) {
|
||||||
self.tran.send(Destroy { self_id: self.id })?;
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,11 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
ifs::wl_surface::xdg_surface::XdgSurface,
|
ifs::wl_surface::xdg_surface::XdgSurface,
|
||||||
it::{
|
it::{
|
||||||
test_error::TestError, test_ifs::test_xdg_toplevel::TestXdgToplevel,
|
test_error::TestError,
|
||||||
test_object::TestObject, test_transport::TestTransport, testrun::ParseFull,
|
test_ifs::test_xdg_toplevel::{TestXdgToplevel, TestXdgToplevelCore},
|
||||||
|
test_object::TestObject,
|
||||||
|
test_transport::TestTransport,
|
||||||
|
testrun::ParseFull,
|
||||||
},
|
},
|
||||||
utils::buffd::MsgParser,
|
utils::buffd::MsgParser,
|
||||||
wire::{xdg_surface::*, XdgSurfaceId},
|
wire::{xdg_surface::*, XdgSurfaceId},
|
||||||
|
|
@ -33,20 +36,20 @@ impl TestXdgSurface {
|
||||||
self_id: self.id,
|
self_id: self.id,
|
||||||
id,
|
id,
|
||||||
})?;
|
})?;
|
||||||
self.tran.sync().await;
|
let core = Rc::new(TestXdgToplevelCore {
|
||||||
let client = self.tran.get_client()?;
|
|
||||||
let server = client.lookup(id)?;
|
|
||||||
let tl = Rc::new(TestXdgToplevel {
|
|
||||||
id,
|
id,
|
||||||
tran: self.tran.clone(),
|
tran: self.tran.clone(),
|
||||||
destroyed: Cell::new(false),
|
destroyed: Cell::new(false),
|
||||||
server,
|
|
||||||
width: Cell::new(0),
|
width: Cell::new(0),
|
||||||
height: Cell::new(0),
|
height: Cell::new(0),
|
||||||
states: Default::default(),
|
states: Default::default(),
|
||||||
close_requested: Cell::new(false),
|
close_requested: Cell::new(false),
|
||||||
});
|
});
|
||||||
self.tran.add_obj(tl.clone())?;
|
self.tran.add_obj(core.clone())?;
|
||||||
|
self.tran.sync().await;
|
||||||
|
let client = self.tran.get_client()?;
|
||||||
|
let server = client.lookup(id)?;
|
||||||
|
let tl = Rc::new(TestXdgToplevel { core, server });
|
||||||
Ok(tl)
|
Ok(tl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use {
|
||||||
test_transport::TestTransport,
|
test_transport::TestTransport,
|
||||||
testrun::ParseFull,
|
testrun::ParseFull,
|
||||||
},
|
},
|
||||||
tree::{ContainerNode, ToplevelNodeBase},
|
tree::{ContainerNode, ContainingNode, FloatNode, ToplevelNodeBase},
|
||||||
utils::buffd::MsgParser,
|
utils::buffd::MsgParser,
|
||||||
wire::{xdg_toplevel::*, XdgToplevelId},
|
wire::{xdg_toplevel::*, XdgToplevelId},
|
||||||
},
|
},
|
||||||
|
|
@ -18,11 +18,10 @@ use {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TestXdgToplevel {
|
pub struct TestXdgToplevelCore {
|
||||||
pub id: XdgToplevelId,
|
pub id: XdgToplevelId,
|
||||||
pub tran: Rc<TestTransport>,
|
pub tran: Rc<TestTransport>,
|
||||||
pub destroyed: Cell<bool>,
|
pub destroyed: Cell<bool>,
|
||||||
pub server: Rc<XdgToplevel>,
|
|
||||||
|
|
||||||
pub width: Cell<i32>,
|
pub width: Cell<i32>,
|
||||||
pub height: Cell<i32>,
|
pub height: Cell<i32>,
|
||||||
|
|
@ -31,7 +30,37 @@ pub struct TestXdgToplevel {
|
||||||
pub close_requested: Cell<bool>,
|
pub close_requested: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct TestXdgToplevel {
|
||||||
|
pub core: Rc<TestXdgToplevelCore>,
|
||||||
|
pub server: Rc<XdgToplevel>,
|
||||||
|
}
|
||||||
|
|
||||||
impl TestXdgToplevel {
|
impl TestXdgToplevel {
|
||||||
|
pub fn parent(&self) -> TestResult<Rc<dyn ContainingNode>> {
|
||||||
|
match self.server.tl_data().parent.get() {
|
||||||
|
Some(p) => Ok(p),
|
||||||
|
_ => bail!("toplevel has no parent"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn container_parent(&self) -> TestResult<Rc<ContainerNode>> {
|
||||||
|
let parent = self.parent()?;
|
||||||
|
match parent.node_into_container() {
|
||||||
|
Some(p) => Ok(p),
|
||||||
|
_ => bail!("toplevel parent is not a container"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn float_parent(&self) -> TestResult<Rc<FloatNode>> {
|
||||||
|
let parent = self.parent()?;
|
||||||
|
match parent.node_into_float() {
|
||||||
|
Some(p) => Ok(p),
|
||||||
|
_ => bail!("toplevel parent is not a float"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestXdgToplevelCore {
|
||||||
pub fn destroy(&self) -> Result<(), TestError> {
|
pub fn destroy(&self) -> Result<(), TestError> {
|
||||||
if !self.destroyed.replace(true) {
|
if !self.destroyed.replace(true) {
|
||||||
self.tran.send(Destroy { self_id: self.id })?;
|
self.tran.send(Destroy { self_id: self.id })?;
|
||||||
|
|
@ -39,15 +68,12 @@ impl TestXdgToplevel {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn container_parent(&self) -> TestResult<Rc<ContainerNode>> {
|
pub fn set_title(&self, title: &str) -> Result<(), TestError> {
|
||||||
let parent = match self.server.tl_data().parent.get() {
|
self.tran.send(SetTitle {
|
||||||
Some(p) => p,
|
self_id: self.id,
|
||||||
_ => bail!("toplevel has no parent"),
|
title,
|
||||||
};
|
})?;
|
||||||
match parent.node_into_container() {
|
Ok(())
|
||||||
Some(p) => Ok(p),
|
|
||||||
_ => bail!("toplevel parent is not a container"),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
fn handle_configure(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
|
@ -68,20 +94,26 @@ impl TestXdgToplevel {
|
||||||
let _ev = ConfigureBounds::parse_full(parser)?;
|
let _ev = ConfigureBounds::parse_full(parser)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_wm_capabilities(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||||
|
let _ev = WmCapabilities::parse_full(parser)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for TestXdgToplevel {
|
impl Drop for TestXdgToplevelCore {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.destroy();
|
let _ = self.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test_object! {
|
test_object! {
|
||||||
TestXdgToplevel, XdgToplevel;
|
TestXdgToplevelCore, XdgToplevel;
|
||||||
|
|
||||||
CONFIGURE => handle_configure,
|
CONFIGURE => handle_configure,
|
||||||
CLOSE => handle_close,
|
CLOSE => handle_close,
|
||||||
CONFIGURE_BOUNDS => handle_configure_bounds,
|
CONFIGURE_BOUNDS => handle_configure_bounds,
|
||||||
|
WM_CAPABILITIES => handle_wm_capabilities,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestObject for TestXdgToplevel {}
|
impl TestObject for TestXdgToplevelCore {}
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ use {
|
||||||
static LEVEL: AtomicUsize = AtomicUsize::new(Level::Info as usize);
|
static LEVEL: AtomicUsize = AtomicUsize::new(Level::Info as usize);
|
||||||
|
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static FILE: CloneCell<Option<Rc<OwnedFd>>> = CloneCell::new(None);
|
static FILE: CloneCell<Option<Rc<OwnedFd>>> = const { CloneCell::new(None) };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn install() {
|
pub fn install() {
|
||||||
|
|
|
||||||
|
|
@ -13,18 +13,20 @@ macro_rules! tassert {
|
||||||
|
|
||||||
macro_rules! tassert_eq {
|
macro_rules! tassert_eq {
|
||||||
($left:expr, $right:expr) => {{
|
($left:expr, $right:expr) => {{
|
||||||
let left = $left;
|
match ($left, $right) {
|
||||||
let right = $right;
|
(left, right) => {
|
||||||
if left != right {
|
if left != right {
|
||||||
bail!(
|
bail!(
|
||||||
"Assert `{} = {:?} = {:?} = {}` failed ({}:{})",
|
"Assert `{} = {:?} = {:?} = {}` failed ({}:{})",
|
||||||
stringify!($left),
|
stringify!($left),
|
||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
stringify!($right),
|
stringify!($right),
|
||||||
file!(),
|
file!(),
|
||||||
line!()
|
line!()
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ pub struct TestMem {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestMem {
|
impl TestMem {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn new(size: usize) -> Result<Rc<Self>, TestError> {
|
pub fn new(size: usize) -> Result<Rc<Self>, TestError> {
|
||||||
let fd = uapi::memfd_create("test_pool", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING)?;
|
let fd = uapi::memfd_create("test_pool", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING)?;
|
||||||
uapi::fcntl_add_seals(fd.raw(), c::F_SEAL_SHRINK)?;
|
uapi::fcntl_add_seals(fd.raw(), c::F_SEAL_SHRINK)?;
|
||||||
|
|
@ -24,6 +25,7 @@ impl TestMem {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn grow(&self, size: usize) -> Result<Rc<Self>, TestError> {
|
pub fn grow(&self, size: usize) -> Result<Rc<Self>, TestError> {
|
||||||
let cur_len = uapi::fstat(self.fd.raw())?;
|
let cur_len = uapi::fstat(self.fd.raw())?;
|
||||||
if size > cur_len.st_size as _ {
|
if size > cur_len.st_size as _ {
|
||||||
|
|
@ -45,6 +47,7 @@ impl Deref for TestMem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
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 {
|
if size == 0 {
|
||||||
return Ok(&[]);
|
return Ok(&[]);
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,18 @@ impl TestTransport {
|
||||||
compositor: Default::default(),
|
compositor: Default::default(),
|
||||||
subcompositor: Default::default(),
|
subcompositor: Default::default(),
|
||||||
shm: Default::default(),
|
shm: Default::default(),
|
||||||
|
spbm: Default::default(),
|
||||||
|
viewporter: Default::default(),
|
||||||
xdg: Default::default(),
|
xdg: Default::default(),
|
||||||
|
activation: Default::default(),
|
||||||
|
foreign_toplevel_list: Default::default(),
|
||||||
|
data_device_manager: Default::default(),
|
||||||
|
cursor_shape_manager: Default::default(),
|
||||||
|
syncobj_manager: Default::default(),
|
||||||
|
content_type_manager: Default::default(),
|
||||||
|
data_control_manager: Default::default(),
|
||||||
|
dmabuf: Default::default(),
|
||||||
|
drag_manager: Default::default(),
|
||||||
seats: Default::default(),
|
seats: Default::default(),
|
||||||
});
|
});
|
||||||
self.send(wl_display::GetRegistry {
|
self.send(wl_display::GetRegistry {
|
||||||
|
|
@ -159,7 +170,12 @@ impl TestTransport {
|
||||||
_ => bail!("Object with id {} has already been deleted", msg.id()),
|
_ => bail!("Object with id {} has already been deleted", msg.id()),
|
||||||
};
|
};
|
||||||
if obj.interface().name() != msg.interface().name() {
|
if obj.interface().name() != msg.interface().name() {
|
||||||
bail!("Object with id {} has an incompatible interface", msg.id());
|
bail!(
|
||||||
|
"Object with id {} has an incompatible interface: {} != {}",
|
||||||
|
msg.id(),
|
||||||
|
obj.interface().name(),
|
||||||
|
msg.interface().name()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
let mut fds = vec![];
|
let mut fds = vec![];
|
||||||
let mut swapchain = self.swapchain.borrow_mut();
|
let mut swapchain = self.swapchain.borrow_mut();
|
||||||
|
|
@ -186,7 +202,7 @@ struct Outgoing {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Outgoing {
|
impl Outgoing {
|
||||||
async fn run(mut self: Self) {
|
async fn run(mut self) {
|
||||||
loop {
|
loop {
|
||||||
self.tc.flush_request.triggered().await;
|
self.tc.flush_request.triggered().await;
|
||||||
if let Err(e) = self.flush().await {
|
if let Err(e) = self.flush().await {
|
||||||
|
|
@ -224,7 +240,7 @@ struct Incoming {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Incoming {
|
impl Incoming {
|
||||||
async fn run(mut self: Self) {
|
async fn run(mut self) {
|
||||||
loop {
|
loop {
|
||||||
if let Err(e) = self.handle_msg().await {
|
if let Err(e) = self.handle_msg().await {
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
|
pub mod test_container_node_ext;
|
||||||
pub mod test_expected_event;
|
pub mod test_expected_event;
|
||||||
pub mod test_object_ext;
|
pub mod test_object_ext;
|
||||||
|
pub mod test_ouput_node_ext;
|
||||||
|
pub mod test_rect_ext;
|
||||||
|
pub mod test_toplevel_node_ext;
|
||||||
pub mod test_window;
|
pub mod test_window;
|
||||||
|
pub mod test_workspace_node_ext;
|
||||||
|
|
|
||||||
20
src/it/test_utils/test_container_node_ext.rs
Normal file
20
src/it/test_utils/test_container_node_ext.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::test_error::TestResult,
|
||||||
|
tree::{ContainerNode, ToplevelNode},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait TestContainerExt {
|
||||||
|
fn first_toplevel(&self) -> TestResult<Rc<dyn ToplevelNode>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestContainerExt for ContainerNode {
|
||||||
|
fn first_toplevel(&self) -> TestResult<Rc<dyn ToplevelNode>> {
|
||||||
|
match self.children.first() {
|
||||||
|
None => bail!("container does not have children"),
|
||||||
|
Some(c) => Ok(c.node.clone()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/it/test_utils/test_ouput_node_ext.rs
Normal file
31
src/it/test_utils/test_ouput_node_ext.rs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_utils::{
|
||||||
|
test_container_node_ext::TestContainerExt,
|
||||||
|
test_workspace_node_ext::TestWorkspaceNodeExt,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tree::{OutputNode, ToplevelNode, WorkspaceNode},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait TestOutputNodeExt {
|
||||||
|
fn workspace(&self) -> TestResult<Rc<WorkspaceNode>>;
|
||||||
|
fn first_toplevel(&self) -> TestResult<Rc<dyn ToplevelNode>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestOutputNodeExt for OutputNode {
|
||||||
|
fn workspace(&self) -> TestResult<Rc<WorkspaceNode>> {
|
||||||
|
match self.workspace.get() {
|
||||||
|
None => bail!("Output node does not have a container"),
|
||||||
|
Some(w) => Ok(w),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn first_toplevel(&self) -> TestResult<Rc<dyn ToplevelNode>> {
|
||||||
|
self.workspace()?.container()?.first_toplevel()
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/it/test_utils/test_rect_ext.rs
Normal file
11
src/it/test_utils/test_rect_ext.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use crate::rect::Rect;
|
||||||
|
|
||||||
|
pub trait TestRectExt {
|
||||||
|
fn center(&self) -> (i32, i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestRectExt for Rect {
|
||||||
|
fn center(&self) -> (i32, i32) {
|
||||||
|
((self.x1() + self.x2()) / 2, (self.y1() + self.y2()) / 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/it/test_utils/test_toplevel_node_ext.rs
Normal file
11
src/it/test_utils/test_toplevel_node_ext.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use crate::{it::test_utils::test_rect_ext::TestRectExt, tree::ToplevelNode};
|
||||||
|
|
||||||
|
pub trait TestToplevelNodeExt {
|
||||||
|
fn center(&self) -> (i32, i32);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestToplevelNodeExt for dyn ToplevelNode {
|
||||||
|
fn center(&self) -> (i32, i32) {
|
||||||
|
self.node_absolute_position().center()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,42 +1,36 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::ARGB8888,
|
|
||||||
it::{
|
it::{
|
||||||
test_error::{TestError, TestResult},
|
test_error::{TestError, TestResult},
|
||||||
test_ifs::{
|
test_ifs::{
|
||||||
test_shm_buffer::TestShmBuffer, test_shm_pool::TestShmPool,
|
test_single_pixel_buffer_manager::TestSinglePixelBufferManager,
|
||||||
test_surface::TestSurface, test_xdg_surface::TestXdgSurface,
|
test_surface::TestSurface, test_viewport::TestViewport,
|
||||||
test_xdg_toplevel::TestXdgToplevel,
|
test_xdg_surface::TestXdgSurface, test_xdg_toplevel::TestXdgToplevel,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
utils::clonecell::CloneCell,
|
|
||||||
},
|
},
|
||||||
std::{cell::Cell, rc::Rc},
|
std::{cell::Cell, rc::Rc},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct TestWindow {
|
pub struct TestWindow {
|
||||||
pub surface: Rc<TestSurface>,
|
pub surface: Rc<TestSurface>,
|
||||||
|
pub spbm: Rc<TestSinglePixelBufferManager>,
|
||||||
|
pub viewport: Rc<TestViewport>,
|
||||||
pub xdg: Rc<TestXdgSurface>,
|
pub xdg: Rc<TestXdgSurface>,
|
||||||
pub tl: Rc<TestXdgToplevel>,
|
pub tl: Rc<TestXdgToplevel>,
|
||||||
pub shm: Rc<TestShmPool>,
|
|
||||||
pub buffer: CloneCell<Rc<TestShmBuffer>>,
|
|
||||||
pub color: Cell<Color>,
|
pub color: Cell<Color>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestWindow {
|
impl TestWindow {
|
||||||
pub async fn map(&self) -> Result<(), TestError> {
|
pub async fn map(&self) -> Result<(), TestError> {
|
||||||
let width = self.tl.width.get();
|
let buffer = self.spbm.create_buffer(self.color.get())?;
|
||||||
let height = self.tl.height.get();
|
|
||||||
let stride = width * 4;
|
|
||||||
let size = (stride * height) as usize;
|
|
||||||
self.shm.resize(size)?;
|
|
||||||
let buffer = self.shm.create_buffer(0, width, height, stride, ARGB8888)?;
|
|
||||||
buffer.fill(self.color.get());
|
|
||||||
self.surface.attach(buffer.id)?;
|
self.surface.attach(buffer.id)?;
|
||||||
|
self.viewport.set_source(0, 0, 1, 1)?;
|
||||||
|
self.viewport
|
||||||
|
.set_destination(self.tl.core.width.get(), self.tl.core.height.get())?;
|
||||||
self.xdg.ack_configure(self.xdg.last_serial.get())?;
|
self.xdg.ack_configure(self.xdg.last_serial.get())?;
|
||||||
self.surface.commit()?;
|
self.surface.commit()?;
|
||||||
self.buffer.set(buffer);
|
|
||||||
self.surface.tran.sync().await;
|
self.surface.tran.sync().await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
src/it/test_utils/test_workspace_node_ext.rs
Normal file
20
src/it/test_utils/test_workspace_node_ext.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::test_error::TestResult,
|
||||||
|
tree::{ContainerNode, WorkspaceNode},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait TestWorkspaceNodeExt {
|
||||||
|
fn container(&self) -> TestResult<Rc<ContainerNode>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestWorkspaceNodeExt for WorkspaceNode {
|
||||||
|
fn container(&self) -> TestResult<Rc<ContainerNode>> {
|
||||||
|
match self.container.get() {
|
||||||
|
None => bail!("workspace does not have a container"),
|
||||||
|
Some(c) => Ok(c),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
client::{ClientId, RequestParser},
|
client::{ClientId, RequestParser},
|
||||||
|
fixed::Fixed,
|
||||||
ifs::wl_seat::WlSeatGlobal,
|
ifs::wl_seat::WlSeatGlobal,
|
||||||
it::{
|
it::{
|
||||||
test_backend::{TestBackend, TestBackendKb, TestBackendMouse, TestConnector},
|
test_backend::{TestBackend, TestBackendKb, TestBackendMouse, TestConnector},
|
||||||
|
|
@ -73,6 +74,7 @@ impl TestRun {
|
||||||
tran.init();
|
tran.init();
|
||||||
let registry = tran.get_registry();
|
let registry = tran.get_registry();
|
||||||
let jc = registry.get_jay_compositor().await?;
|
let jc = registry.get_jay_compositor().await?;
|
||||||
|
jc.enable_symmetric_delete()?;
|
||||||
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 {
|
||||||
|
|
@ -83,7 +85,12 @@ impl TestRun {
|
||||||
comp: registry.get_compositor().await?,
|
comp: registry.get_compositor().await?,
|
||||||
sub: registry.get_subcompositor().await?,
|
sub: registry.get_subcompositor().await?,
|
||||||
shm: registry.get_shm().await?,
|
shm: registry.get_shm().await?,
|
||||||
|
spbm: registry.get_spbm().await?,
|
||||||
|
viewporter: registry.get_viewporter().await?,
|
||||||
xdg: registry.get_xdg().await?,
|
xdg: registry.get_xdg().await?,
|
||||||
|
activation: registry.get_activation().await?,
|
||||||
|
data_device_manager: registry.get_data_device_manager().await?,
|
||||||
|
cursor_shape_manager: registry.get_cursor_shape_manager().await?,
|
||||||
registry,
|
registry,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
@ -110,7 +117,9 @@ impl TestRun {
|
||||||
.set_input_device_seat(self.backend.default_kb.common.id, seat.id())?;
|
.set_input_device_seat(self.backend.default_kb.common.id, seat.id())?;
|
||||||
self.cfg
|
self.cfg
|
||||||
.set_input_device_seat(self.backend.default_mouse.common.id, seat.id())?;
|
.set_input_device_seat(self.backend.default_mouse.common.id, seat.id())?;
|
||||||
|
self.backend.default_mouse.click(1);
|
||||||
self.state.eng.yield_now().await;
|
self.state.eng.yield_now().await;
|
||||||
|
self.cfg.show_workspace(seat.id(), "")?;
|
||||||
Ok(DefaultSetup {
|
Ok(DefaultSetup {
|
||||||
connector: self.backend.default_connector.clone(),
|
connector: self.backend.default_connector.clone(),
|
||||||
output,
|
output,
|
||||||
|
|
@ -144,3 +153,12 @@ pub struct DefaultSetup {
|
||||||
pub mouse: Rc<TestBackendMouse>,
|
pub mouse: Rc<TestBackendMouse>,
|
||||||
pub seat: Rc<WlSeatGlobal>,
|
pub seat: Rc<WlSeatGlobal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DefaultSetup {
|
||||||
|
pub fn move_to(&self, x: i32, y: i32) {
|
||||||
|
let (ox, oy) = self.seat.position();
|
||||||
|
let (nx, ny) = (Fixed::from_int(x), Fixed::from_int(y));
|
||||||
|
let (dx, dy) = (nx - ox, ny - oy);
|
||||||
|
self.mouse.rel(dx.to_f64(), dy.to_f64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,11 @@ macro_rules! testcase {
|
||||||
Box::new(test(testrun))
|
Box::new(test(testrun))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn single() {
|
||||||
|
crate::it::run_tests_(vec![&Test])
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -44,6 +49,26 @@ mod t0015_scroll_partial;
|
||||||
mod t0016_scroll_ws;
|
mod t0016_scroll_ws;
|
||||||
mod t0017_remove_unused_ws;
|
mod t0017_remove_unused_ws;
|
||||||
mod t0018_click_to_active_ws;
|
mod t0018_click_to_active_ws;
|
||||||
|
mod t0019_natural_scrolling;
|
||||||
|
mod t0020_surface_offset;
|
||||||
|
mod t0021_preferred_buffer_scale;
|
||||||
|
mod t0022_toplevel_suspended;
|
||||||
|
mod t0023_xdg_activation;
|
||||||
|
mod t0024_foreign_toplevel_list;
|
||||||
|
mod t0025_dnd_focus_change;
|
||||||
|
mod t0026_output_transform;
|
||||||
|
mod t0027_input_region;
|
||||||
|
mod t0028_top_level_restacking;
|
||||||
|
mod t0029_double_click_float;
|
||||||
|
mod t0030_cursor_shape;
|
||||||
|
mod t0031_syncobj;
|
||||||
|
mod t0032_content_type;
|
||||||
|
mod t0032_data_control;
|
||||||
|
mod t0033_float_size_memoization;
|
||||||
|
mod t0034_workspace_restoration;
|
||||||
|
mod t0035_scanout_feedback;
|
||||||
|
mod t0036_idle;
|
||||||
|
mod t0037_toplevel_drag;
|
||||||
|
|
||||||
pub trait TestCase: Sync {
|
pub trait TestCase: Sync {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
@ -61,6 +86,7 @@ pub fn tests() -> Vec<&'static dyn TestCase> {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tests! {
|
tests! {
|
||||||
t0001_shm_formats,
|
t0001_shm_formats,
|
||||||
t0002_window,
|
t0002_window,
|
||||||
|
|
@ -80,5 +106,24 @@ pub fn tests() -> Vec<&'static dyn TestCase> {
|
||||||
t0016_scroll_ws,
|
t0016_scroll_ws,
|
||||||
t0017_remove_unused_ws,
|
t0017_remove_unused_ws,
|
||||||
t0018_click_to_active_ws,
|
t0018_click_to_active_ws,
|
||||||
|
t0019_natural_scrolling,
|
||||||
|
t0020_surface_offset,
|
||||||
|
t0021_preferred_buffer_scale,
|
||||||
|
t0022_toplevel_suspended,
|
||||||
|
t0023_xdg_activation,
|
||||||
|
t0024_foreign_toplevel_list,
|
||||||
|
t0025_dnd_focus_change,
|
||||||
|
t0026_output_transform,
|
||||||
|
t0027_input_region,
|
||||||
|
t0028_top_level_restacking,
|
||||||
|
t0029_double_click_float,
|
||||||
|
t0030_cursor_shape,
|
||||||
|
t0031_syncobj,
|
||||||
|
t0032_data_control,
|
||||||
|
t0033_float_size_memoization,
|
||||||
|
t0034_workspace_restoration,
|
||||||
|
t0035_scanout_feedback,
|
||||||
|
t0036_idle,
|
||||||
|
t0037_toplevel_drag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,9 @@ async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||||
let window = client.create_window().await?;
|
let window = client.create_window().await?;
|
||||||
window.map().await?;
|
window.map().await?;
|
||||||
|
|
||||||
tassert_eq!(window.tl.width.get(), 800);
|
tassert_eq!(window.tl.core.width.get(), 800);
|
||||||
tassert_eq!(
|
tassert_eq!(
|
||||||
window.tl.height.get(),
|
window.tl.core.height.get(),
|
||||||
600 - 2 * (run.state.theme.sizes.title_height.get() + 1)
|
600 - 2 * (run.state.theme.sizes.title_height.get() + 1)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -29,8 +29,8 @@ async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||||
Rect::new_sized(
|
Rect::new_sized(
|
||||||
0,
|
0,
|
||||||
2 * (run.state.theme.sizes.title_height.get() + 1),
|
2 * (run.state.theme.sizes.title_height.get() + 1),
|
||||||
window.tl.width.get(),
|
window.tl.core.width.get(),
|
||||||
window.tl.height.get(),
|
window.tl.core.height.get(),
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
format::ARGB8888,
|
|
||||||
it::{test_error::TestError, testrun::TestRun},
|
it::{test_error::TestError, testrun::TestRun},
|
||||||
theme::Color,
|
theme::Color,
|
||||||
},
|
},
|
||||||
|
|
@ -26,34 +25,35 @@ async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||||
parent.set_color(0, 0, 0, 255);
|
parent.set_color(0, 0, 0, 255);
|
||||||
|
|
||||||
let child = client.comp.create_surface().await?;
|
let child = client.comp.create_surface().await?;
|
||||||
|
let child_viewport = client.viewporter.get_viewport(&child)?;
|
||||||
let sub = client
|
let sub = client
|
||||||
.sub
|
.sub
|
||||||
.get_subsurface(child.id, parent.surface.id)
|
.get_subsurface(child.id, parent.surface.id)
|
||||||
.await?;
|
.await?;
|
||||||
sub.set_position(100, 100)?;
|
sub.set_position(100, 100)?;
|
||||||
|
|
||||||
let pool = client.shm.create_pool(100 * 100 * 4)?;
|
let buffer = client
|
||||||
let buffer = pool.create_buffer(0, 100, 100, 100 * 4, ARGB8888)?;
|
.spbm
|
||||||
buffer.fill(Color::from_rgba_straight(255, 255, 255, 255));
|
.create_buffer(Color::from_rgba_straight(255, 255, 255, 255))?;
|
||||||
|
|
||||||
child.attach(buffer.id)?;
|
child.attach(buffer.id)?;
|
||||||
|
child_viewport.set_source(0, 0, 1, 1)?;
|
||||||
|
child_viewport.set_destination(100, 100)?;
|
||||||
child.commit()?;
|
child.commit()?;
|
||||||
|
|
||||||
parent.map().await?;
|
parent.map().await?;
|
||||||
|
|
||||||
seat.set_app_cursor(None);
|
client.compare_screenshot("1", false).await?;
|
||||||
|
|
||||||
client.compare_screenshot("1").await?;
|
|
||||||
|
|
||||||
sub.place_below(parent.surface.id)?;
|
sub.place_below(parent.surface.id)?;
|
||||||
child.commit()?;
|
child.commit()?;
|
||||||
parent.map().await?;
|
parent.map().await?;
|
||||||
client.compare_screenshot("2").await?;
|
client.compare_screenshot("2", false).await?;
|
||||||
|
|
||||||
sub.place_above(parent.surface.id)?;
|
sub.place_above(parent.surface.id)?;
|
||||||
child.commit()?;
|
child.commit()?;
|
||||||
parent.map().await?;
|
parent.map().await?;
|
||||||
client.compare_screenshot("1").await?;
|
client.compare_screenshot("1", false).await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ use {
|
||||||
test_error::{TestErrorExt, TestResult},
|
test_error::{TestErrorExt, TestResult},
|
||||||
testrun::TestRun,
|
testrun::TestRun,
|
||||||
},
|
},
|
||||||
|
theme::Color,
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
@ -25,10 +26,13 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
window.map().await?;
|
window.map().await?;
|
||||||
|
|
||||||
let ns = client.comp.create_surface().await?;
|
let ns = client.comp.create_surface().await?;
|
||||||
|
let nsv = client.viewporter.get_viewport(&ns)?;
|
||||||
let nss = client.sub.get_subsurface(ns.id, window.surface.id).await?;
|
let nss = client.sub.get_subsurface(ns.id, window.surface.id).await?;
|
||||||
nss.set_position(100, 100)?;
|
nss.set_position(100, 100)?;
|
||||||
let buffer = client.shm.create_buffer(100, 100)?;
|
let buffer = client.spbm.create_buffer(Color::SOLID_BLACK)?;
|
||||||
ns.attach(buffer.id)?;
|
ns.attach(buffer.id)?;
|
||||||
|
nsv.set_source(0, 0, 1, 1)?;
|
||||||
|
nsv.set_destination(100, 100)?;
|
||||||
ns.commit()?;
|
ns.commit()?;
|
||||||
|
|
||||||
run.cfg.set_fullscreen(ds.seat.id(), true)?;
|
run.cfg.set_fullscreen(ds.seat.id(), true)?;
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
// | w_tiled | [ w_mono1 | w_mono2 ] | with w_mono2 visible and active
|
// | w_tiled | [ w_mono1 | w_mono2 ] | with w_mono2 visible and active
|
||||||
|
|
||||||
client.sync().await;
|
client.sync().await;
|
||||||
tassert_eq!(w_tiled.tl.width.get(), w_mono2.tl.width.get());
|
tassert_eq!(w_tiled.tl.core.width.get(), w_mono2.tl.core.width.get());
|
||||||
|
|
||||||
let enters = dss.kb.enter.expect()?;
|
let enters = dss.kb.enter.expect()?;
|
||||||
|
|
||||||
|
|
|
||||||
46
src/it/tests/t0019_natural_scrolling.rs
Normal file
46
src/it/tests/t0019_natural_scrolling.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::wl_seat::wl_pointer::{IDENTICAL, INVERTED},
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_utils::{
|
||||||
|
test_container_node_ext::TestContainerExt, test_ouput_node_ext::TestOutputNodeExt,
|
||||||
|
test_toplevel_node_ext::TestToplevelNodeExt,
|
||||||
|
test_workspace_node_ext::TestWorkspaceNodeExt,
|
||||||
|
},
|
||||||
|
testrun::TestRun,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.map2().await?;
|
||||||
|
|
||||||
|
let (x, y) = ds
|
||||||
|
.output
|
||||||
|
.workspace()?
|
||||||
|
.container()?
|
||||||
|
.first_toplevel()?
|
||||||
|
.center();
|
||||||
|
ds.move_to(x, y);
|
||||||
|
|
||||||
|
let seat = client.get_default_seat().await?;
|
||||||
|
let ard = seat.pointer.axis_relative_direction.expect()?;
|
||||||
|
|
||||||
|
ds.mouse.scroll_px2(1, false);
|
||||||
|
client.sync().await;
|
||||||
|
tassert_eq!(ard.next()?.direction, IDENTICAL);
|
||||||
|
|
||||||
|
ds.mouse.scroll_px2(1, true);
|
||||||
|
client.sync().await;
|
||||||
|
tassert_eq!(ard.next()?.direction, INVERTED);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
56
src/it/tests/t0020_surface_offset.rs
Normal file
56
src/it/tests/t0020_surface_offset.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{
|
||||||
|
test_error::TestError,
|
||||||
|
test_utils::{
|
||||||
|
test_container_node_ext::TestContainerExt, test_ouput_node_ext::TestOutputNodeExt,
|
||||||
|
test_toplevel_node_ext::TestToplevelNodeExt,
|
||||||
|
test_workspace_node_ext::TestWorkspaceNodeExt,
|
||||||
|
},
|
||||||
|
testrun::TestRun,
|
||||||
|
},
|
||||||
|
theme::Color,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
let seat = client.get_default_seat().await?;
|
||||||
|
let enter = seat.pointer.enter.expect()?;
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.map2().await?;
|
||||||
|
|
||||||
|
let buffer = client.spbm.create_buffer(Color::from_rgb(255, 0, 0))?;
|
||||||
|
let surface = client.comp.create_surface().await?;
|
||||||
|
let vp = client.viewporter.get_viewport(&surface)?;
|
||||||
|
vp.set_destination(100, 100)?;
|
||||||
|
surface.attach(buffer.id)?;
|
||||||
|
surface.commit()?;
|
||||||
|
|
||||||
|
let (x, y) = ds
|
||||||
|
.output
|
||||||
|
.workspace()?
|
||||||
|
.container()?
|
||||||
|
.first_toplevel()?
|
||||||
|
.center();
|
||||||
|
ds.move_to(x, y);
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
let enter = enter.next()?;
|
||||||
|
seat.pointer
|
||||||
|
.set_cursor(enter.serial, Some(&surface), 0, 0)?;
|
||||||
|
|
||||||
|
client.compare_screenshot("1", true).await?;
|
||||||
|
|
||||||
|
surface.offset(-100, -100)?;
|
||||||
|
surface.commit()?;
|
||||||
|
|
||||||
|
client.compare_screenshot("2", true).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
BIN
src/it/tests/t0020_surface_offset/screenshot_1.qoi
Normal file
BIN
src/it/tests/t0020_surface_offset/screenshot_1.qoi
Normal file
Binary file not shown.
BIN
src/it/tests/t0020_surface_offset/screenshot_2.qoi
Normal file
BIN
src/it/tests/t0020_surface_offset/screenshot_2.qoi
Normal file
Binary file not shown.
29
src/it/tests/t0021_preferred_buffer_scale.rs
Normal file
29
src/it/tests/t0021_preferred_buffer_scale.rs
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
use {
|
||||||
|
crate::it::{test_error::TestResult, testrun::TestRun},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.map2().await?;
|
||||||
|
|
||||||
|
let scale = win1.surface.preferred_buffer_scale.expect()?;
|
||||||
|
|
||||||
|
run.cfg.set_scale(&ds.output, 2.0)?;
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
tassert_eq!(scale.next()?, 2);
|
||||||
|
|
||||||
|
run.cfg.set_scale(&ds.output, 3.0)?;
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
tassert_eq!(scale.next()?, 3);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
48
src/it/tests/t0022_toplevel_suspended.rs
Normal file
48
src/it/tests/t0022_toplevel_suspended.rs
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::wl_surface::xdg_surface::xdg_toplevel::STATE_SUSPENDED,
|
||||||
|
it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_utils::{
|
||||||
|
test_ouput_node_ext::TestOutputNodeExt, test_toplevel_node_ext::TestToplevelNodeExt,
|
||||||
|
},
|
||||||
|
testrun::TestRun,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
isnt::std_1::collections::IsntHashSet2Ext,
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.set_color(255, 0, 0, 255);
|
||||||
|
win1.map2().await?;
|
||||||
|
|
||||||
|
let win2 = client.create_window().await?;
|
||||||
|
win2.set_color(0, 255, 0, 255);
|
||||||
|
win2.map2().await?;
|
||||||
|
|
||||||
|
let (x, y) = ds.output.first_toplevel()?.center();
|
||||||
|
ds.move_to(x, y);
|
||||||
|
|
||||||
|
tassert!(win2.tl.core.states.borrow().not_contains(&STATE_SUSPENDED));
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
run.cfg.set_mono(ds.seat.id(), true)?;
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
tassert!(win2.tl.core.states.borrow().contains(&STATE_SUSPENDED));
|
||||||
|
|
||||||
|
run.cfg.set_mono(ds.seat.id(), false)?;
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
tassert!(win2.tl.core.states.borrow().not_contains(&STATE_SUSPENDED));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
40
src/it/tests/t0023_xdg_activation.rs
Normal file
40
src/it/tests/t0023_xdg_activation.rs
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
use {
|
||||||
|
crate::it::{
|
||||||
|
test_error::TestResult,
|
||||||
|
test_utils::{
|
||||||
|
test_ouput_node_ext::TestOutputNodeExt, test_toplevel_node_ext::TestToplevelNodeExt,
|
||||||
|
},
|
||||||
|
testrun::TestRun,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.set_color(255, 0, 0, 255);
|
||||||
|
win1.map2().await?;
|
||||||
|
|
||||||
|
let win2 = client.create_window().await?;
|
||||||
|
win2.set_color(0, 255, 0, 255);
|
||||||
|
win2.map2().await?;
|
||||||
|
|
||||||
|
let (x, y) = ds.output.first_toplevel()?.center();
|
||||||
|
ds.move_to(x, y);
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
run.cfg.set_mono(ds.seat.id(), true)?;
|
||||||
|
|
||||||
|
let token = client.activation.get_token().await?;
|
||||||
|
client.activation.activate(&win2.surface, &token)?;
|
||||||
|
client.sync().await;
|
||||||
|
|
||||||
|
client.compare_screenshot("1", false).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
BIN
src/it/tests/t0023_xdg_activation/screenshot_1.qoi
Normal file
BIN
src/it/tests/t0023_xdg_activation/screenshot_1.qoi
Normal file
Binary file not shown.
62
src/it/tests/t0024_foreign_toplevel_list.rs
Normal file
62
src/it/tests/t0024_foreign_toplevel_list.rs
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
|
wire::WlBufferId,
|
||||||
|
},
|
||||||
|
ahash::AHashSet,
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let _ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client1 = run.create_client().await?;
|
||||||
|
let client2 = run.create_client().await?;
|
||||||
|
|
||||||
|
let list = client2.registry.get_foreign_toplevel_list().await?;
|
||||||
|
|
||||||
|
let win1 = client1.create_window().await?;
|
||||||
|
win1.tl.core.set_title("a")?;
|
||||||
|
win1.map().await?;
|
||||||
|
let win2 = client1.create_window().await?;
|
||||||
|
win2.tl.core.set_title("b")?;
|
||||||
|
win2.map().await?;
|
||||||
|
|
||||||
|
client2.sync().await;
|
||||||
|
let tls = list.toplevels.take();
|
||||||
|
tassert_eq!(tls.len(), 2);
|
||||||
|
|
||||||
|
tassert_eq!(tls[0].title.take().as_deref(), Some("a"));
|
||||||
|
tassert_eq!(tls[1].title.take().as_deref(), Some("b"));
|
||||||
|
|
||||||
|
let mut ids = AHashSet::new();
|
||||||
|
ids.insert(tls[0].identifier.take().unwrap());
|
||||||
|
ids.insert(tls[1].identifier.take().unwrap());
|
||||||
|
|
||||||
|
win2.tl.core.set_title("c")?;
|
||||||
|
client1.sync().await;
|
||||||
|
|
||||||
|
client2.sync().await;
|
||||||
|
tassert_eq!(tls[1].title.take().as_deref(), Some("c"));
|
||||||
|
|
||||||
|
win2.surface.attach(WlBufferId::NONE)?;
|
||||||
|
win2.surface.commit()?;
|
||||||
|
client1.sync().await;
|
||||||
|
|
||||||
|
client2.sync().await;
|
||||||
|
tassert!(tls[1].closed.get());
|
||||||
|
|
||||||
|
win2.map().await?;
|
||||||
|
|
||||||
|
client1.sync().await;
|
||||||
|
let tls = list.toplevels.take();
|
||||||
|
tassert_eq!(tls.len(), 1);
|
||||||
|
tassert_eq!(tls[0].title.take().as_deref(), Some("c"));
|
||||||
|
|
||||||
|
ids.insert(tls[0].identifier.take().unwrap());
|
||||||
|
tassert_eq!(ids.len(), 3);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
51
src/it/tests/t0025_dnd_focus_change.rs
Normal file
51
src/it/tests/t0025_dnd_focus_change.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::wl_seat::BTN_LEFT,
|
||||||
|
it::{test_error::TestResult, test_utils::test_rect_ext::TestRectExt, testrun::TestRun},
|
||||||
|
tree::Node,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.map2().await?;
|
||||||
|
let win2 = client.create_window().await?;
|
||||||
|
win2.map2().await?;
|
||||||
|
|
||||||
|
let seat = client.get_default_seat().await?;
|
||||||
|
let button = seat.pointer.button.expect()?;
|
||||||
|
|
||||||
|
let (x, y) = win1.tl.server.node_absolute_position().center();
|
||||||
|
ds.move_to(x, y);
|
||||||
|
let click = ds.mouse.click(BTN_LEFT);
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
let dev = client.data_device_manager.get_data_device(&seat.seat)?;
|
||||||
|
let src = client.data_device_manager.create_data_source()?;
|
||||||
|
src.set_actions(1)?;
|
||||||
|
dev.start_drag(&src, &win1.surface, None, button.next()?.serial)?;
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
let enter = seat.pointer.enter.expect()?;
|
||||||
|
|
||||||
|
let (x, y) = win2.tl.server.node_absolute_position().center();
|
||||||
|
ds.move_to(x, y);
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
tassert!(enter.next().is_err());
|
||||||
|
|
||||||
|
drop(click);
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
client.sync().await;
|
||||||
|
tassert_eq!(enter.next()?.surface, win2.surface.id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
27
src/it/tests/t0026_output_transform.rs
Normal file
27
src/it/tests/t0026_output_transform.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
use {
|
||||||
|
crate::it::{test_error::TestResult, testrun::TestRun},
|
||||||
|
jay_config::video::Transform,
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
run.cfg
|
||||||
|
.set_output_transform(&ds.output, Transform::FlipRotate90)?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
let win = client.create_window().await?;
|
||||||
|
|
||||||
|
let transform = win.surface.preferred_buffer_transform.expect()?;
|
||||||
|
|
||||||
|
win.map2().await?;
|
||||||
|
|
||||||
|
tassert_eq!(transform.next()?, 5);
|
||||||
|
|
||||||
|
client.compare_screenshot("1", false).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
BIN
src/it/tests/t0026_output_transform/screenshot_1.qoi
Normal file
BIN
src/it/tests/t0026_output_transform/screenshot_1.qoi
Normal file
Binary file not shown.
43
src/it/tests/t0027_input_region.rs
Normal file
43
src/it/tests/t0027_input_region.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{test_error::TestResult, test_utils::test_rect_ext::TestRectExt, testrun::TestRun},
|
||||||
|
tree::Node,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.set_color(255, 0, 0, 255);
|
||||||
|
win1.map2().await?;
|
||||||
|
let win2 = client.create_window().await?;
|
||||||
|
win2.set_color(0, 255, 0, 255);
|
||||||
|
win2.map2().await?;
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
let (x, y) = win2.tl.server.node_absolute_position().center();
|
||||||
|
ds.move_to(x, y);
|
||||||
|
client.sync().await;
|
||||||
|
run.cfg.set_floating(ds.seat.id(), true)?;
|
||||||
|
client.sync().await;
|
||||||
|
let (x, y) = win2.tl.server.node_absolute_position().center();
|
||||||
|
ds.move_to(x, y);
|
||||||
|
win2.map2().await?;
|
||||||
|
|
||||||
|
let seat = client.get_default_seat().await?;
|
||||||
|
let enter = seat.pointer.enter.expect()?;
|
||||||
|
|
||||||
|
let region = client.comp.create_region().await?;
|
||||||
|
win2.surface.set_input_region(®ion)?;
|
||||||
|
win2.surface.commit()?;
|
||||||
|
client.sync().await;
|
||||||
|
|
||||||
|
tassert_eq!(enter.next()?.surface, win1.surface.id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
43
src/it/tests/t0028_top_level_restacking.rs
Normal file
43
src/it/tests/t0028_top_level_restacking.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::wl_seat::BTN_LEFT,
|
||||||
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.set_color(255, 0, 0, 255);
|
||||||
|
win1.map2().await?;
|
||||||
|
run.cfg.set_floating(ds.seat.id(), true)?;
|
||||||
|
|
||||||
|
let win2 = client.create_window().await?;
|
||||||
|
win2.set_color(0, 255, 0, 255);
|
||||||
|
win2.map2().await?;
|
||||||
|
run.cfg.set_floating(ds.seat.id(), true)?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let parent = win1.tl.float_parent()?;
|
||||||
|
let rect = parent.position.get();
|
||||||
|
parent.position.set(rect.at_point(100, 100));
|
||||||
|
parent.schedule_layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
client.compare_screenshot("1", false).await?;
|
||||||
|
|
||||||
|
ds.move_to(110, 110);
|
||||||
|
ds.mouse.click(BTN_LEFT);
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
client.compare_screenshot("2", false).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
BIN
src/it/tests/t0028_top_level_restacking/screenshot_1.qoi
Normal file
BIN
src/it/tests/t0028_top_level_restacking/screenshot_1.qoi
Normal file
Binary file not shown.
BIN
src/it/tests/t0028_top_level_restacking/screenshot_2.qoi
Normal file
BIN
src/it/tests/t0028_top_level_restacking/screenshot_2.qoi
Normal file
Binary file not shown.
33
src/it/tests/t0029_double_click_float.rs
Normal file
33
src/it/tests/t0029_double_click_float.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::wl_seat::BTN_LEFT,
|
||||||
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
|
tree::Node,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.set_color(255, 0, 0, 255);
|
||||||
|
win1.map2().await?;
|
||||||
|
run.cfg.set_floating(ds.seat.id(), true)?;
|
||||||
|
|
||||||
|
for i in ["1", "2"] {
|
||||||
|
let (x, y) = win1.tl.server.node_absolute_position().position();
|
||||||
|
ds.move_to(x + 10, y - 3);
|
||||||
|
ds.mouse.click(BTN_LEFT);
|
||||||
|
ds.mouse.click(BTN_LEFT);
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
client.compare_screenshot(i, false).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
BIN
src/it/tests/t0029_double_click_float/screenshot_1.qoi
Normal file
BIN
src/it/tests/t0029_double_click_float/screenshot_1.qoi
Normal file
Binary file not shown.
BIN
src/it/tests/t0029_double_click_float/screenshot_2.qoi
Normal file
BIN
src/it/tests/t0029_double_click_float/screenshot_2.qoi
Normal file
Binary file not shown.
32
src/it/tests/t0030_cursor_shape.rs
Normal file
32
src/it/tests/t0030_cursor_shape.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
cursor::KnownCursor,
|
||||||
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
|
||||||
|
let seat = client.get_default_seat().await?;
|
||||||
|
let dev = client.cursor_shape_manager.get_pointer(&seat.pointer)?;
|
||||||
|
let enter = seat.pointer.enter.expect()?;
|
||||||
|
|
||||||
|
let win1 = client.create_window().await?;
|
||||||
|
win1.map2().await?;
|
||||||
|
|
||||||
|
dev.set_shape(enter.last()?.serial, 2)?;
|
||||||
|
client.sync().await;
|
||||||
|
|
||||||
|
tassert_eq!(
|
||||||
|
ds.seat.get_desired_known_cursor(),
|
||||||
|
Some(KnownCursor::ContextMenu)
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
65
src/it/tests/t0031_syncobj.rs
Normal file
65
src/it/tests/t0031_syncobj.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
|
theme::Color,
|
||||||
|
utils::errorfmt::ErrorFmt,
|
||||||
|
video::drm::{sync_obj::SyncObjPoint, wait_for_sync_obj::SyncObjWaiter, DrmError},
|
||||||
|
},
|
||||||
|
std::{cell::Cell, rc::Rc},
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let _ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
struct Waiter(Cell<bool>);
|
||||||
|
impl SyncObjWaiter for Waiter {
|
||||||
|
fn done(self: Rc<Self>, result: Result<(), DrmError>) {
|
||||||
|
result.unwrap();
|
||||||
|
self.0.set(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let waiter = Rc::new(Waiter(Cell::new(false)));
|
||||||
|
|
||||||
|
let eng = run.state.render_ctx.get().unwrap();
|
||||||
|
let syncobj = match eng.sync_obj_ctx().create_sync_obj() {
|
||||||
|
Ok(s) => Rc::new(s),
|
||||||
|
Err(e) => {
|
||||||
|
log::warn!("Cannot test explicit sync on this system: {}", ErrorFmt(e));
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let _wait_handle =
|
||||||
|
run.state
|
||||||
|
.wait_for_sync_obj
|
||||||
|
.wait(&syncobj, SyncObjPoint(2), true, waiter.clone())?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
|
||||||
|
let buf1 = client.spbm.create_buffer(Color::SOLID_BLACK)?;
|
||||||
|
let buf2 = client.spbm.create_buffer(Color::SOLID_BLACK)?;
|
||||||
|
|
||||||
|
let syncobj_manager = client.registry.get_syncobj_manager().await?;
|
||||||
|
let timeline = syncobj_manager.import_timeline(&syncobj)?;
|
||||||
|
|
||||||
|
let win = client.create_window().await?;
|
||||||
|
let sync = syncobj_manager.get_surface(&win.surface)?;
|
||||||
|
win.surface.attach(buf1.id)?;
|
||||||
|
sync.set_acquire_point(&timeline, 1)?;
|
||||||
|
sync.set_release_point(&timeline, 2)?;
|
||||||
|
win.surface.commit()?;
|
||||||
|
sync.destroy()?;
|
||||||
|
win.surface.attach(buf2.id)?;
|
||||||
|
win.surface.commit()?;
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
tassert_eq!(waiter.0.get(), false);
|
||||||
|
|
||||||
|
eng.sync_obj_ctx().signal(&syncobj, SyncObjPoint(1))?;
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
tassert_eq!(waiter.0.get(), true);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
25
src/it/tests/t0032_content_type.rs
Normal file
25
src/it/tests/t0032_content_type.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::wp_content_type_v1::ContentType,
|
||||||
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let _ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
let surface = client.comp.create_surface().await?;
|
||||||
|
let ctm = client.registry.get_content_type_manager().await?;
|
||||||
|
let ct = ctm.get_surface_content_type(&surface)?;
|
||||||
|
ct.set_content_type(2)?;
|
||||||
|
surface.commit()?;
|
||||||
|
client.sync().await;
|
||||||
|
|
||||||
|
tassert_eq!(surface.server.content_type.get(), Some(ContentType::Video));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
87
src/it/tests/t0032_data_control.rs
Normal file
87
src/it/tests/t0032_data_control.rs
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
use {
|
||||||
|
crate::it::{
|
||||||
|
test_error::{TestErrorExt, TestResult},
|
||||||
|
testrun::TestRun,
|
||||||
|
},
|
||||||
|
std::{
|
||||||
|
io::{Read, Write},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let _ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client1 = run.create_client().await?;
|
||||||
|
let seat1 = client1.get_default_seat().await?;
|
||||||
|
let dev1 = client1.data_device_manager.get_data_device(&seat1.seat)?;
|
||||||
|
let entered = seat1.kb.enter.expect()?;
|
||||||
|
let win1 = client1.create_window().await?;
|
||||||
|
win1.map2().await?;
|
||||||
|
let serial = entered.next()?.serial;
|
||||||
|
let source1 = client1.data_device_manager.create_data_source()?;
|
||||||
|
source1.offer("image")?;
|
||||||
|
let sends1 = source1.sends.expect()?;
|
||||||
|
|
||||||
|
let client2 = run.create_client().await?;
|
||||||
|
let seat2 = client2.get_default_seat().await?;
|
||||||
|
let data_control2 = client2.registry.get_data_control_manager().await?;
|
||||||
|
let dev2 = data_control2.get_data_device(&seat2.seat)?;
|
||||||
|
let source2 = data_control2.create_data_source()?;
|
||||||
|
source2.offer("text")?;
|
||||||
|
let sends2 = source2.sends.expect()?;
|
||||||
|
|
||||||
|
let client3 = run.create_client().await?;
|
||||||
|
let seat3 = client3.get_default_seat().await?;
|
||||||
|
let data_control3 = client3.registry.get_data_control_manager().await?;
|
||||||
|
let dev3 = data_control3.get_data_device(&seat3.seat)?;
|
||||||
|
let selection = dev3.selection.expect()?;
|
||||||
|
|
||||||
|
dev2.set_selection(&source2)?;
|
||||||
|
client2.sync().await;
|
||||||
|
client3.sync().await;
|
||||||
|
|
||||||
|
let Some(sel) = selection.last().with_context(|| "selection 1")? else {
|
||||||
|
bail!("no selection (1)");
|
||||||
|
};
|
||||||
|
tassert!(sel.offers.borrow().contains("text"));
|
||||||
|
{
|
||||||
|
let rfd = sel.receive("text")?;
|
||||||
|
client3.sync().await;
|
||||||
|
client2.sync().await;
|
||||||
|
let (mime, sfd) = sends2.next().with_context(|| "sends2")?;
|
||||||
|
tassert_eq!(mime, "text");
|
||||||
|
sfd.borrow().write_all(b"abcd")?;
|
||||||
|
drop(sfd);
|
||||||
|
let mut buf = vec![];
|
||||||
|
rfd.borrow().read_to_end(&mut buf)?;
|
||||||
|
tassert_eq!(buf, b"abcd");
|
||||||
|
}
|
||||||
|
|
||||||
|
tassert_eq!(source2.cancelled.get(), false);
|
||||||
|
dev1.set_selection(&source1, serial)?;
|
||||||
|
client1.sync().await;
|
||||||
|
client2.sync().await;
|
||||||
|
tassert_eq!(source2.cancelled.get(), true);
|
||||||
|
|
||||||
|
let Some(sel) = selection.last().with_context(|| "selection 2")? else {
|
||||||
|
bail!("no selection (2)");
|
||||||
|
};
|
||||||
|
tassert!(sel.offers.borrow().contains("image"));
|
||||||
|
{
|
||||||
|
let rfd = sel.receive("image")?;
|
||||||
|
client3.sync().await;
|
||||||
|
client1.sync().await;
|
||||||
|
let (mime, sfd) = sends1.next().with_context(|| "sends1")?;
|
||||||
|
tassert_eq!(mime, "image");
|
||||||
|
sfd.borrow().write_all(b"xyz")?;
|
||||||
|
drop(sfd);
|
||||||
|
let mut buf = vec![];
|
||||||
|
rfd.borrow().read_to_end(&mut buf)?;
|
||||||
|
tassert_eq!(buf, b"xyz");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
47
src/it/tests/t0033_float_size_memoization.rs
Normal file
47
src/it/tests/t0033_float_size_memoization.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
it::{test_error::TestResult, testrun::TestRun},
|
||||||
|
rect::Rect,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client1 = run.create_client().await?;
|
||||||
|
let win1 = client1.create_window().await?;
|
||||||
|
win1.map2().await?;
|
||||||
|
|
||||||
|
run.cfg.set_floating(ds.seat.id(), true)?;
|
||||||
|
|
||||||
|
client1.sync().await;
|
||||||
|
let (w1, h1) = (win1.tl.core.width.get(), win1.tl.core.height.get());
|
||||||
|
|
||||||
|
let float = win1.tl.float_parent()?;
|
||||||
|
let pos = float.position.get();
|
||||||
|
float
|
||||||
|
.position
|
||||||
|
.set(Rect::new_sized(pos.x1(), pos.x2(), pos.width() / 2, pos.height() / 2).unwrap());
|
||||||
|
float.schedule_layout();
|
||||||
|
|
||||||
|
client1.sync().await;
|
||||||
|
let (w2, h2) = (win1.tl.core.width.get(), win1.tl.core.height.get());
|
||||||
|
tassert!((w1, h1) != (w2, h2));
|
||||||
|
|
||||||
|
run.cfg.set_floating(ds.seat.id(), false)?;
|
||||||
|
|
||||||
|
client1.sync().await;
|
||||||
|
let (w3, h3) = (win1.tl.core.width.get(), win1.tl.core.height.get());
|
||||||
|
tassert!((w3, h3) != (w2, h2));
|
||||||
|
|
||||||
|
run.cfg.set_floating(ds.seat.id(), true)?;
|
||||||
|
|
||||||
|
client1.sync().await;
|
||||||
|
let (w4, h4) = (win1.tl.core.width.get(), win1.tl.core.height.get());
|
||||||
|
tassert!((w4, h4) == (w2, h2));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
95
src/it/tests/t0034_workspace_restoration.rs
Normal file
95
src/it/tests/t0034_workspace_restoration.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
backend::{BackendEvent, ConnectorEvent, ConnectorKernelId, Mode, MonitorInfo},
|
||||||
|
it::{test_backend::TestConnector, test_error::TestResult, testrun::TestRun},
|
||||||
|
video::drm::ConnectorType,
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client1 = run.create_client().await?;
|
||||||
|
let win1 = client1.create_window().await?;
|
||||||
|
win1.map2().await?;
|
||||||
|
let surface = &win1.surface.server;
|
||||||
|
|
||||||
|
let Some(dummy_output) = run.state.dummy_output.get() else {
|
||||||
|
bail!("no dummy output");
|
||||||
|
};
|
||||||
|
|
||||||
|
let new_connector = Rc::new(TestConnector {
|
||||||
|
id: run.state.connector_ids.next(),
|
||||||
|
kernel_id: ConnectorKernelId {
|
||||||
|
ty: ConnectorType::VGA,
|
||||||
|
idx: 2,
|
||||||
|
},
|
||||||
|
events: Default::default(),
|
||||||
|
feedback: Default::default(),
|
||||||
|
});
|
||||||
|
let new_monitor_info = MonitorInfo {
|
||||||
|
modes: vec![],
|
||||||
|
manufacturer: "jay".to_string(),
|
||||||
|
product: "jay second connector".to_string(),
|
||||||
|
serial_number: "".to_string(),
|
||||||
|
initial_mode: Mode {
|
||||||
|
width: 400,
|
||||||
|
height: 400,
|
||||||
|
refresh_rate_millihz: 60000,
|
||||||
|
},
|
||||||
|
width_mm: 0,
|
||||||
|
height_mm: 0,
|
||||||
|
};
|
||||||
|
run.backend
|
||||||
|
.state
|
||||||
|
.backend_events
|
||||||
|
.push(BackendEvent::NewConnector(new_connector.clone()));
|
||||||
|
|
||||||
|
new_connector
|
||||||
|
.events
|
||||||
|
.send_event(ConnectorEvent::Connected(new_monitor_info.clone()));
|
||||||
|
run.state.eng.yield_now().await;
|
||||||
|
tassert_eq!(
|
||||||
|
surface.get_output().global.connector.connector.id(),
|
||||||
|
ds.connector.id
|
||||||
|
);
|
||||||
|
|
||||||
|
ds.connector.events.send_event(ConnectorEvent::Disconnected);
|
||||||
|
run.state.eng.yield_now().await;
|
||||||
|
tassert_eq!(
|
||||||
|
surface.get_output().global.connector.connector.id(),
|
||||||
|
new_connector.id
|
||||||
|
);
|
||||||
|
|
||||||
|
new_connector
|
||||||
|
.events
|
||||||
|
.send_event(ConnectorEvent::Disconnected);
|
||||||
|
run.state.eng.yield_now().await;
|
||||||
|
tassert_eq!(
|
||||||
|
surface.get_output().global.connector.connector.id(),
|
||||||
|
dummy_output.global.connector.connector.id()
|
||||||
|
);
|
||||||
|
|
||||||
|
new_connector
|
||||||
|
.events
|
||||||
|
.send_event(ConnectorEvent::Connected(new_monitor_info.clone()));
|
||||||
|
run.state.eng.yield_now().await;
|
||||||
|
tassert_eq!(
|
||||||
|
surface.get_output().global.connector.connector.id(),
|
||||||
|
new_connector.id
|
||||||
|
);
|
||||||
|
|
||||||
|
ds.connector.events.send_event(ConnectorEvent::Connected(
|
||||||
|
run.backend.default_monitor_info.clone(),
|
||||||
|
));
|
||||||
|
run.state.eng.yield_now().await;
|
||||||
|
tassert_eq!(
|
||||||
|
surface.get_output().global.connector.connector.id(),
|
||||||
|
ds.connector.id
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
65
src/it/tests/t0035_scanout_feedback.rs
Normal file
65
src/it/tests/t0035_scanout_feedback.rs
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::zwp_linux_dmabuf_feedback_v1::SCANOUT,
|
||||||
|
it::{
|
||||||
|
test_error::{TestErrorExt, TestResult},
|
||||||
|
testrun::TestRun,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let scanout_feedback = {
|
||||||
|
let Some(base_fb) = run.state.drm_feedback.get() else {
|
||||||
|
bail!("no base fb");
|
||||||
|
};
|
||||||
|
let Some(index) = base_fb.shared.indices.keys().copied().next() else {
|
||||||
|
bail!("no formats");
|
||||||
|
};
|
||||||
|
let fb = base_fb
|
||||||
|
.for_scanout(&run.state.drm_feedback_ids, 1234, &[index])
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
Rc::new(fb)
|
||||||
|
};
|
||||||
|
|
||||||
|
ds.connector.feedback.set(Some(scanout_feedback.clone()));
|
||||||
|
|
||||||
|
let client1 = run.create_client().await?;
|
||||||
|
let win1 = client1.create_window().await?;
|
||||||
|
let dmabuf = client1.registry.get_dmabuf().await?;
|
||||||
|
let feedback = dmabuf.get_surface_feedback(&win1.surface)?;
|
||||||
|
let feedback = feedback.feedback.expect()?;
|
||||||
|
win1.map2().await?;
|
||||||
|
|
||||||
|
client1.sync().await;
|
||||||
|
let fb = feedback.last().with_context(|| "feedback 1")?;
|
||||||
|
tassert_eq!(fb.tranches.len(), 1);
|
||||||
|
tassert_eq!(fb.tranches[0].flags, 0);
|
||||||
|
|
||||||
|
run.cfg.set_fullscreen(ds.seat.id(), true)?;
|
||||||
|
|
||||||
|
client1.sync().await;
|
||||||
|
let fb = feedback.last().with_context(|| "feedback 2")?;
|
||||||
|
tassert_eq!(fb.tranches.len(), 2);
|
||||||
|
tassert_eq!(
|
||||||
|
fb.tranches[0].target_device,
|
||||||
|
scanout_feedback.tranches[0].device
|
||||||
|
);
|
||||||
|
tassert_eq!(fb.tranches[0].flags, SCANOUT);
|
||||||
|
tassert_eq!(fb.tranches[1].flags, 0);
|
||||||
|
|
||||||
|
run.cfg.set_fullscreen(ds.seat.id(), false)?;
|
||||||
|
|
||||||
|
client1.sync().await;
|
||||||
|
let fb = feedback.last().with_context(|| "feedback 2")?;
|
||||||
|
tassert_eq!(fb.tranches.len(), 1);
|
||||||
|
tassert_eq!(fb.tranches[0].flags, 0);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
30
src/it/tests/t0036_idle.rs
Normal file
30
src/it/tests/t0036_idle.rs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
use {
|
||||||
|
crate::it::{
|
||||||
|
test_error::{TestErrorExt, TestResult},
|
||||||
|
testrun::TestRun,
|
||||||
|
},
|
||||||
|
std::{rc::Rc, time::Duration},
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
run.cfg.set_idle(Duration::from_micros(100))?;
|
||||||
|
|
||||||
|
let idle = run.backend.idle.expect()?;
|
||||||
|
tassert!(idle.next().is_err());
|
||||||
|
|
||||||
|
run.state.wheel.timeout(3).await?;
|
||||||
|
|
||||||
|
tassert_eq!(idle.next().with_context(|| "idle")?, true);
|
||||||
|
tassert!(idle.next().is_err());
|
||||||
|
|
||||||
|
ds.mouse.rel(1.0, 1.0);
|
||||||
|
run.state.eng.yield_now().await;
|
||||||
|
|
||||||
|
tassert_eq!(idle.next().with_context(|| "wake")?, false);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
44
src/it/tests/t0037_toplevel_drag.rs
Normal file
44
src/it/tests/t0037_toplevel_drag.rs
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
use {
|
||||||
|
crate::{
|
||||||
|
ifs::wl_seat::BTN_LEFT,
|
||||||
|
it::{
|
||||||
|
test_error::{TestErrorExt, TestResult},
|
||||||
|
testrun::TestRun,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
std::rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
|
testcase!();
|
||||||
|
|
||||||
|
async fn test(run: Rc<TestRun>) -> TestResult {
|
||||||
|
let ds = run.create_default_setup().await?;
|
||||||
|
|
||||||
|
let client = run.create_client().await?;
|
||||||
|
let drag_manager = client.registry.get_drag_manager().await?;
|
||||||
|
let seat = client.get_default_seat().await?;
|
||||||
|
let source = client.data_device_manager.create_data_source()?;
|
||||||
|
let dev = client.data_device_manager.get_data_device(&seat.seat)?;
|
||||||
|
let drag = drag_manager.get_xdg_toplevel_drag(&source)?;
|
||||||
|
let win = client.create_window().await?;
|
||||||
|
win.set_color(255, 255, 0, 255);
|
||||||
|
win.map2().await?;
|
||||||
|
|
||||||
|
let button = seat.pointer.button.expect()?;
|
||||||
|
let click = ds.mouse.click(BTN_LEFT);
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
let serial = button.next().with_context(|| "button")?.serial;
|
||||||
|
seat.pointer.set_cursor(serial, None, 0, 0)?;
|
||||||
|
drag.attach(&win.tl, 100, 100)?;
|
||||||
|
source.set_actions(1)?;
|
||||||
|
dev.start_drag(&source, &win.surface, None, serial)?;
|
||||||
|
|
||||||
|
client.sync().await;
|
||||||
|
client.compare_screenshot("1", true).await?;
|
||||||
|
drop(click);
|
||||||
|
client.sync().await;
|
||||||
|
client.compare_screenshot("2", true).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
BIN
src/it/tests/t0037_toplevel_drag/screenshot_1.qoi
Normal file
BIN
src/it/tests/t0037_toplevel_drag/screenshot_1.qoi
Normal file
Binary file not shown.
BIN
src/it/tests/t0037_toplevel_drag/screenshot_2.qoi
Normal file
BIN
src/it/tests/t0037_toplevel_drag/screenshot_2.qoi
Normal file
Binary file not shown.
37
src/leaks.rs
37
src/leaks.rs
|
|
@ -65,15 +65,13 @@ mod leaks {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
unsafe {
|
if INITIALIZED.get() {
|
||||||
if INITIALIZED {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
MAP.set(Box::into_raw(Box::new(AHashMap::new())));
|
|
||||||
ALLOCATIONS.set(Box::into_raw(Box::new(AHashMap::new())));
|
|
||||||
IN_ALLOCATOR.set(0);
|
|
||||||
INITIALIZED.set(true);
|
|
||||||
}
|
}
|
||||||
|
MAP.set(Box::into_raw(Box::new(AHashMap::new())));
|
||||||
|
ALLOCATIONS.set(Box::into_raw(Box::new(AHashMap::new())));
|
||||||
|
IN_ALLOCATOR.set(0);
|
||||||
|
INITIALIZED.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log_containers(
|
fn log_containers(
|
||||||
|
|
@ -153,7 +151,7 @@ mod leaks {
|
||||||
unsafe {
|
unsafe {
|
||||||
IN_ALLOCATOR.set(IN_ALLOCATOR.get() + 1);
|
IN_ALLOCATOR.set(IN_ALLOCATOR.get() + 1);
|
||||||
let mut map: AHashMap<ClientId, Vec<(u64, Tracked)>> = AHashMap::new();
|
let mut map: AHashMap<ClientId, Vec<(u64, Tracked)>> = AHashMap::new();
|
||||||
for (id, obj) in MAP.deref_mut().drain() {
|
for (id, obj) in MAP.get().deref_mut().drain() {
|
||||||
map.entry(obj.client).or_default().push((id, obj));
|
map.entry(obj.client).or_default().push((id, obj));
|
||||||
}
|
}
|
||||||
if map.is_empty() {
|
if map.is_empty() {
|
||||||
|
|
@ -166,7 +164,8 @@ mod leaks {
|
||||||
objs.sort_by_key(|o| o.0);
|
objs.sort_by_key(|o| o.0);
|
||||||
log::info!("Client {} leaked {} objects", objs[0].1.client, objs.len());
|
log::info!("Client {} leaked {} objects", objs[0].1.client, objs.len());
|
||||||
for (_, obj) in objs {
|
for (_, obj) in objs {
|
||||||
let time = chrono::NaiveDateTime::from_timestamp(obj.time.0, obj.time.1);
|
let time =
|
||||||
|
chrono::NaiveDateTime::from_timestamp_opt(obj.time.0, obj.time.1).unwrap();
|
||||||
log::info!(" [{}] {}", time.format("%H:%M:%S%.3f"), obj.ty,);
|
log::info!(" [{}] {}", time.format("%H:%M:%S%.3f"), obj.ty,);
|
||||||
match find_allocation_containing(obj.addr) {
|
match find_allocation_containing(obj.addr) {
|
||||||
Some(mut alloc) => {
|
Some(mut alloc) => {
|
||||||
|
|
@ -209,7 +208,7 @@ mod leaks {
|
||||||
impl<T> Default for Tracker<T> {
|
impl<T> Default for Tracker<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: unsafe {
|
id: {
|
||||||
let id = ID.get();
|
let id = ID.get();
|
||||||
ID.set(id + 1);
|
ID.set(id + 1);
|
||||||
id
|
id
|
||||||
|
|
@ -228,7 +227,7 @@ mod leaks {
|
||||||
};
|
};
|
||||||
uapi::clock_gettime(c::CLOCK_REALTIME, &mut time).unwrap();
|
uapi::clock_gettime(c::CLOCK_REALTIME, &mut time).unwrap();
|
||||||
IN_ALLOCATOR.set(IN_ALLOCATOR.get() + 1);
|
IN_ALLOCATOR.set(IN_ALLOCATOR.get() + 1);
|
||||||
MAP.deref_mut().insert(
|
MAP.get().deref_mut().insert(
|
||||||
self.id,
|
self.id,
|
||||||
Tracked {
|
Tracked {
|
||||||
addr: self as *const _ as usize,
|
addr: self as *const _ as usize,
|
||||||
|
|
@ -245,7 +244,7 @@ mod leaks {
|
||||||
impl<T> Drop for Tracker<T> {
|
impl<T> Drop for Tracker<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
MAP.deref_mut().remove(&self.id);
|
MAP.get().deref_mut().remove(&self.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +272,7 @@ mod leaks {
|
||||||
let res = c::calloc(layout.size(), 1) as *mut u8;
|
let res = c::calloc(layout.size(), 1) as *mut u8;
|
||||||
if IN_ALLOCATOR.get() == 0 {
|
if IN_ALLOCATOR.get() == 0 {
|
||||||
IN_ALLOCATOR.set(1);
|
IN_ALLOCATOR.set(1);
|
||||||
ALLOCATIONS.deref_mut().insert(
|
ALLOCATIONS.get().deref_mut().insert(
|
||||||
res,
|
res,
|
||||||
Allocation {
|
Allocation {
|
||||||
addr: res,
|
addr: res,
|
||||||
|
|
@ -282,14 +281,14 @@ mod leaks {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// log::info!("allocated [0x{:x}, 0x{:x})", res as usize, res as usize + layout.size());
|
// log::info!("allocated [0x{:x}, 0x{:x})", res as usize, res as usize + layout.size());
|
||||||
IN_ALLOCATOR = 0;
|
IN_ALLOCATOR.set(0);
|
||||||
}
|
}
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||||
if INITIALIZED {
|
if INITIALIZED.get() {
|
||||||
ALLOCATIONS.deref_mut().remove(&ptr);
|
ALLOCATIONS.get().deref_mut().remove(&ptr);
|
||||||
}
|
}
|
||||||
// c::memset(ptr as _, 0, layout.size());
|
// c::memset(ptr as _, 0, layout.size());
|
||||||
c::free(ptr as _);
|
c::free(ptr as _);
|
||||||
|
|
@ -300,7 +299,7 @@ mod leaks {
|
||||||
unsafe {
|
unsafe {
|
||||||
IN_ALLOCATOR.set(IN_ALLOCATOR.get() + 1);
|
IN_ALLOCATOR.set(IN_ALLOCATOR.get() + 1);
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
for allocation in ALLOCATIONS.deref().values() {
|
for allocation in ALLOCATIONS.get().deref().values() {
|
||||||
let num = allocation.len / mem::size_of::<usize>();
|
let num = allocation.len / mem::size_of::<usize>();
|
||||||
let elements = std::slice::from_raw_parts(allocation.addr as *const *mut u8, num);
|
let elements = std::slice::from_raw_parts(allocation.addr as *const *mut u8, num);
|
||||||
for (offset, pos) in elements.iter().enumerate() {
|
for (offset, pos) in elements.iter().enumerate() {
|
||||||
|
|
@ -319,7 +318,7 @@ mod leaks {
|
||||||
unsafe {
|
unsafe {
|
||||||
IN_ALLOCATOR.set(IN_ALLOCATOR.get() + 1);
|
IN_ALLOCATOR.set(IN_ALLOCATOR.get() + 1);
|
||||||
let mut res = None;
|
let mut res = None;
|
||||||
for allocation in ALLOCATIONS.deref().values() {
|
for allocation in ALLOCATIONS.get().deref().values() {
|
||||||
let aaddr = allocation.addr as usize;
|
let aaddr = allocation.addr as usize;
|
||||||
if aaddr <= addr && addr < aaddr + allocation.len {
|
if aaddr <= addr && addr < aaddr + allocation.len {
|
||||||
res = Some(allocation.clone());
|
res = Some(allocation.clone());
|
||||||
|
|
|
||||||
|
|
@ -405,6 +405,7 @@ impl Renderer<'_> {
|
||||||
Some(bounds) => rect.intersect(*bounds),
|
Some(bounds) => rect.intersect(*bounds),
|
||||||
};
|
};
|
||||||
if !rect.is_empty() {
|
if !rect.is_empty() {
|
||||||
|
self.base.ops.push(GfxApiOpt::Sync);
|
||||||
self.base.fill_boxes(&[rect], color);
|
self.base.fill_boxes(&[rect], color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue