it: test workspace restoration
This commit is contained in:
parent
9efe9415c2
commit
15a1b600f3
8 changed files with 165 additions and 53 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>,
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,8 @@ use {
|
||||||
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,6 +40,7 @@ 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>,
|
||||||
|
|
@ -55,7 +57,6 @@ impl TestBackend {
|
||||||
idx: 1,
|
idx: 1,
|
||||||
},
|
},
|
||||||
events: Default::default(),
|
events: Default::default(),
|
||||||
on_change: Default::default(),
|
|
||||||
});
|
});
|
||||||
let default_mouse = Rc::new(TestBackendMouse {
|
let default_mouse = Rc::new(TestBackendMouse {
|
||||||
common: TestInputDeviceCommon {
|
common: TestInputDeviceCommon {
|
||||||
|
|
@ -89,9 +90,24 @@ 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,
|
||||||
|
|
@ -113,22 +129,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()));
|
||||||
|
|
@ -215,8 +218,7 @@ 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()>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Connector for TestConnector {
|
impl Connector for TestConnector {
|
||||||
|
|
@ -229,11 +231,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) {
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ mod t0031_syncobj;
|
||||||
mod t0032_content_type;
|
mod t0032_content_type;
|
||||||
mod t0032_data_control;
|
mod t0032_data_control;
|
||||||
mod t0033_float_size_memoization;
|
mod t0033_float_size_memoization;
|
||||||
|
mod t0034_workspace_restoration;
|
||||||
|
|
||||||
pub trait TestCase: Sync {
|
pub trait TestCase: Sync {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
|
|
@ -117,5 +118,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> {
|
||||||
t0031_syncobj,
|
t0031_syncobj,
|
||||||
t0032_data_control,
|
t0032_data_control,
|
||||||
t0033_float_size_memoization,
|
t0033_float_size_memoization,
|
||||||
|
t0034_workspace_restoration,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
94
src/it/tests/t0034_workspace_restoration.rs
Normal file
94
src/it/tests/t0034_workspace_restoration.rs
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
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(),
|
||||||
|
});
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
|
@ -237,6 +237,7 @@ impl ConnectorHandler {
|
||||||
}
|
}
|
||||||
global.destroyed.set(true);
|
global.destroyed.set(true);
|
||||||
self.state.root.outputs.remove(&self.id);
|
self.state.root.outputs.remove(&self.id);
|
||||||
|
self.state.root.update_extents();
|
||||||
self.data.connected.set(false);
|
self.data.connected.set(false);
|
||||||
self.state.outputs.remove(&self.id);
|
self.state.outputs.remove(&self.id);
|
||||||
on.lock_surface.take();
|
on.lock_surface.take();
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ pub mod mmap;
|
||||||
pub mod nonblock;
|
pub mod nonblock;
|
||||||
pub mod num_cpus;
|
pub mod num_cpus;
|
||||||
pub mod numcell;
|
pub mod numcell;
|
||||||
|
pub mod on_change;
|
||||||
pub mod once;
|
pub mod once;
|
||||||
pub mod opaque;
|
pub mod opaque;
|
||||||
pub mod opaque_cell;
|
pub mod opaque_cell;
|
||||||
|
|
|
||||||
39
src/utils/on_change.rs
Normal file
39
src/utils/on_change.rs
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
use {
|
||||||
|
crate::utils::{clonecell::CloneCell, syncqueue::SyncQueue},
|
||||||
|
std::{
|
||||||
|
fmt::{Debug, Formatter},
|
||||||
|
rc::Rc,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue