it: test window gains kb focus when mapped
This commit is contained in:
parent
cbf539cbcc
commit
c827a93dbb
19 changed files with 672 additions and 39 deletions
|
|
@ -7,8 +7,10 @@ use {
|
|||
Mode, MonitorInfo, TransformMatrix,
|
||||
},
|
||||
compositor::TestFuture,
|
||||
fixed::Fixed,
|
||||
render::{RenderContext, RenderError},
|
||||
state::State,
|
||||
time::Time,
|
||||
utils::{
|
||||
clonecell::CloneCell, copyhashmap::CopyHashMap, oserror::OsError, syncqueue::SyncQueue,
|
||||
},
|
||||
|
|
@ -36,11 +38,13 @@ pub struct TestBackend {
|
|||
pub state: Rc<State>,
|
||||
pub test_future: TestFuture,
|
||||
pub default_connector: Rc<TestConnector>,
|
||||
pub default_mouse: Rc<TestBackendMouse>,
|
||||
pub default_kb: Rc<TestBackendKb>,
|
||||
}
|
||||
|
||||
impl TestBackend {
|
||||
pub fn new(state: &Rc<State>, future: TestFuture) -> Self {
|
||||
let connector = Rc::new(TestConnector {
|
||||
let default_connector = Rc::new(TestConnector {
|
||||
id: state.connector_ids.next(),
|
||||
kernel_id: ConnectorKernelId {
|
||||
ty: ConnectorType::VGA,
|
||||
|
|
@ -49,10 +53,44 @@ impl TestBackend {
|
|||
events: Default::default(),
|
||||
on_change: Default::default(),
|
||||
});
|
||||
let default_mouse = Rc::new(TestBackendMouse {
|
||||
common: TestInputDeviceCommon {
|
||||
id: state.input_device_ids.next(),
|
||||
removed: Cell::new(false),
|
||||
events: Default::default(),
|
||||
on_change: Default::default(),
|
||||
capabilities: {
|
||||
let chm = CopyHashMap::new();
|
||||
chm.set(InputDeviceCapability::Pointer, ());
|
||||
chm
|
||||
},
|
||||
name: Rc::new("default-mouse".to_string()),
|
||||
},
|
||||
transform_matrix: Cell::new([[1.0, 0.0], [0.0, 1.0]]),
|
||||
accel_speed: Cell::new(1.0),
|
||||
accel_profile: Cell::new(InputDeviceAccelProfile::Flat),
|
||||
left_handed: Cell::new(false),
|
||||
});
|
||||
let default_kb = Rc::new(TestBackendKb {
|
||||
common: TestInputDeviceCommon {
|
||||
id: state.input_device_ids.next(),
|
||||
removed: Cell::new(false),
|
||||
events: Default::default(),
|
||||
on_change: Default::default(),
|
||||
capabilities: {
|
||||
let chm = CopyHashMap::new();
|
||||
chm.set(InputDeviceCapability::Keyboard, ());
|
||||
chm
|
||||
},
|
||||
name: Rc::new("default-keyboard".to_string()),
|
||||
},
|
||||
});
|
||||
Self {
|
||||
state: state.clone(),
|
||||
test_future: future,
|
||||
default_connector: connector,
|
||||
default_connector,
|
||||
default_mouse,
|
||||
default_kb,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +114,12 @@ impl TestBackend {
|
|||
width_mm: 80,
|
||||
height_mm: 60,
|
||||
}));
|
||||
self.state
|
||||
.backend_events
|
||||
.push(BackendEvent::NewInputDevice(self.default_kb.clone()));
|
||||
self.state
|
||||
.backend_events
|
||||
.push(BackendEvent::NewInputDevice(self.default_mouse.clone()));
|
||||
}
|
||||
|
||||
fn create_render_context(&self) -> Result<(), TestBackendError> {
|
||||
|
|
@ -189,50 +233,47 @@ impl Connector for TestConnector {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct TestInputDevice {
|
||||
pub id: InputDeviceId,
|
||||
pub remove: Cell<bool>,
|
||||
pub events: SyncQueue<InputEvent>,
|
||||
pub on_change: CloneCell<Option<Rc<dyn Fn()>>>,
|
||||
pub capabilities: CopyHashMap<InputDeviceCapability, ()>,
|
||||
pub struct TestBackendMouse {
|
||||
pub common: TestInputDeviceCommon,
|
||||
pub transform_matrix: Cell<TransformMatrix>,
|
||||
pub name: Rc<String>,
|
||||
pub accel_speed: Cell<f64>,
|
||||
pub accel_profile: Cell<InputDeviceAccelProfile>,
|
||||
pub left_handed: Cell<bool>,
|
||||
}
|
||||
|
||||
impl InputDevice for TestInputDevice {
|
||||
fn id(&self) -> InputDeviceId {
|
||||
self.id
|
||||
impl TestBackendMouse {
|
||||
pub fn rel(&self, dx: f64, dy: f64) {
|
||||
self.common.event(InputEvent::Motion {
|
||||
time_usec: Time::now_unchecked().usec(),
|
||||
dx: Fixed::from_f64(dx * self.accel_speed.get()),
|
||||
dy: Fixed::from_f64(dy * self.accel_speed.get()),
|
||||
dx_unaccelerated: Fixed::from_f64(dx),
|
||||
dy_unaccelerated: Fixed::from_f64(dy),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn removed(&self) -> bool {
|
||||
self.remove.get()
|
||||
pub struct TestBackendKb {
|
||||
pub common: TestInputDeviceCommon,
|
||||
}
|
||||
|
||||
impl TestInputDevice for TestBackendKb {
|
||||
fn common(&self) -> &TestInputDeviceCommon {
|
||||
&self.common
|
||||
}
|
||||
}
|
||||
|
||||
fn event(&self) -> Option<InputEvent> {
|
||||
self.events.pop()
|
||||
}
|
||||
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||
self.on_change.set(Some(cb));
|
||||
}
|
||||
|
||||
fn grab(&self, _grab: bool) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn has_capability(&self, cap: InputDeviceCapability) -> bool {
|
||||
self.capabilities.contains(&cap)
|
||||
impl TestInputDevice for TestBackendMouse {
|
||||
fn common(&self) -> &TestInputDeviceCommon {
|
||||
&self.common
|
||||
}
|
||||
|
||||
fn set_left_handed(&self, left_handed: bool) {
|
||||
self.left_handed.set(left_handed);
|
||||
self.left_handed.set(left_handed)
|
||||
}
|
||||
|
||||
fn set_accel_profile(&self, profile: InputDeviceAccelProfile) {
|
||||
self.accel_profile.set(profile);
|
||||
self.accel_profile.set(profile)
|
||||
}
|
||||
|
||||
fn set_accel_speed(&self, speed: f64) {
|
||||
|
|
@ -242,8 +283,88 @@ impl InputDevice for TestInputDevice {
|
|||
fn set_transform_matrix(&self, matrix: TransformMatrix) {
|
||||
self.transform_matrix.set(matrix);
|
||||
}
|
||||
}
|
||||
|
||||
fn name(&self) -> Rc<String> {
|
||||
self.name.clone()
|
||||
pub struct TestInputDeviceCommon {
|
||||
pub id: InputDeviceId,
|
||||
pub removed: Cell<bool>,
|
||||
pub events: SyncQueue<InputEvent>,
|
||||
pub on_change: CloneCell<Option<Rc<dyn Fn()>>>,
|
||||
pub capabilities: CopyHashMap<InputDeviceCapability, ()>,
|
||||
pub name: Rc<String>,
|
||||
}
|
||||
|
||||
impl TestInputDeviceCommon {
|
||||
pub fn event(&self, e: InputEvent) {
|
||||
self.events.push(e);
|
||||
if let Some(oc) = self.on_change.get() {
|
||||
oc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait TestInputDevice: InputDevice {
|
||||
fn common(&self) -> &TestInputDeviceCommon;
|
||||
|
||||
fn set_left_handed(&self, left_handed: bool) {
|
||||
let _ = left_handed;
|
||||
}
|
||||
|
||||
fn set_accel_profile(&self, profile: InputDeviceAccelProfile) {
|
||||
let _ = profile;
|
||||
}
|
||||
|
||||
fn set_accel_speed(&self, speed: f64) {
|
||||
let _ = speed;
|
||||
}
|
||||
|
||||
fn set_transform_matrix(&self, matrix: TransformMatrix) {
|
||||
let _ = matrix;
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: TestInputDevice> InputDevice for T {
|
||||
fn id(&self) -> InputDeviceId {
|
||||
self.common().id
|
||||
}
|
||||
|
||||
fn removed(&self) -> bool {
|
||||
self.common().removed.get()
|
||||
}
|
||||
|
||||
fn event(&self) -> Option<InputEvent> {
|
||||
self.common().events.pop()
|
||||
}
|
||||
|
||||
fn on_change(&self, cb: Rc<dyn Fn()>) {
|
||||
self.common().on_change.set(Some(cb));
|
||||
}
|
||||
|
||||
fn grab(&self, _grab: bool) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn has_capability(&self, cap: InputDeviceCapability) -> bool {
|
||||
self.common().capabilities.contains(&cap)
|
||||
}
|
||||
|
||||
fn set_left_handed(&self, left_handed: bool) {
|
||||
<Self as TestInputDevice>::set_left_handed(self, left_handed)
|
||||
}
|
||||
|
||||
fn set_accel_profile(&self, profile: InputDeviceAccelProfile) {
|
||||
<Self as TestInputDevice>::set_accel_profile(self, profile)
|
||||
}
|
||||
|
||||
fn set_accel_speed(&self, speed: f64) {
|
||||
<Self as TestInputDevice>::set_accel_speed(self, speed)
|
||||
}
|
||||
|
||||
fn set_transform_matrix(&self, matrix: TransformMatrix) {
|
||||
<Self as TestInputDevice>::set_transform_matrix(self, matrix)
|
||||
}
|
||||
|
||||
fn name(&self) -> Rc<String> {
|
||||
self.common().name.clone()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ use {
|
|||
cli::screenshot::buf_to_qoi,
|
||||
client::Client,
|
||||
format::ARGB8888,
|
||||
globals::GlobalBase,
|
||||
it::{
|
||||
test_error::TestError,
|
||||
test_error::{TestError, TestResult},
|
||||
test_ifs::{
|
||||
test_compositor::TestCompositor, test_jay_compositor::TestJayCompositor,
|
||||
test_registry::TestRegistry, test_shm::TestShm,
|
||||
test_keyboard::TestKeyboard, test_pointer::TestPointer,
|
||||
test_registry::TestRegistry, test_seat::TestSeat, test_shm::TestShm,
|
||||
test_subcompositor::TestSubcompositor, test_xdg_base::TestXdgWmBase,
|
||||
},
|
||||
test_transport::TestTransport,
|
||||
|
|
@ -32,12 +34,50 @@ pub struct TestClient {
|
|||
pub xdg: Rc<TestXdgWmBase>,
|
||||
}
|
||||
|
||||
pub struct DefaultSeat {
|
||||
pub seat: Rc<TestSeat>,
|
||||
pub kb: Rc<TestKeyboard>,
|
||||
pub pointer: Rc<TestPointer>,
|
||||
}
|
||||
|
||||
impl TestClient {
|
||||
#[allow(dead_code)]
|
||||
pub fn error(&self, msg: &str) {
|
||||
self.tran.error(msg)
|
||||
}
|
||||
|
||||
pub async fn get_default_seat(&self) -> TestResult<DefaultSeat> {
|
||||
self.tran.sync().await;
|
||||
let seat = 'get_seat: {
|
||||
for seat in self.tran.run.state.globals.seats.lock().values() {
|
||||
if seat.seat_name() == "default" {
|
||||
break 'get_seat seat.clone();
|
||||
}
|
||||
}
|
||||
bail!("Default seat not found");
|
||||
};
|
||||
let id = self.tran.id();
|
||||
let tseat = Rc::new(TestSeat {
|
||||
id,
|
||||
tran: self.tran.clone(),
|
||||
server: Default::default(),
|
||||
destroyed: Default::default(),
|
||||
caps: Cell::new(0),
|
||||
name: Default::default(),
|
||||
});
|
||||
self.registry.bind(&tseat, seat.name().raw(), 7)?;
|
||||
self.tran.sync().await;
|
||||
let server = self.tran.get_server_obj(tseat.id)?;
|
||||
tseat.server.set(Some(server));
|
||||
let pointer = tseat.get_pointer().await?;
|
||||
let tkb = tseat.get_keyboard().await?;
|
||||
Ok(DefaultSeat {
|
||||
seat: tseat,
|
||||
kb: tkb,
|
||||
pointer,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn sync(&self) {
|
||||
self.tran.sync().await
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
use {
|
||||
crate::{ifs::wl_seat::SeatId, it::test_error::TestError, utils::stack::Stack},
|
||||
crate::{
|
||||
backend::InputDeviceId, ifs::wl_seat::SeatId, it::test_error::TestError,
|
||||
utils::stack::Stack,
|
||||
},
|
||||
isnt::std_1::primitive::IsntConstPtrExt,
|
||||
jay_config::{
|
||||
_private::{
|
||||
|
|
@ -7,7 +10,7 @@ use {
|
|||
ipc::{ClientMessage, Response, ServerMessage},
|
||||
ConfigEntry, VERSION,
|
||||
},
|
||||
input::Seat,
|
||||
input::{InputDevice, Seat},
|
||||
},
|
||||
std::{cell::Cell, ops::Deref, ptr, rc::Rc},
|
||||
};
|
||||
|
|
@ -161,6 +164,13 @@ impl TestConfig {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn set_input_device_seat(&self, id: InputDeviceId, seat: SeatId) -> Result<(), TestError> {
|
||||
self.send(ClientMessage::SetSeat {
|
||||
device: InputDevice(id.raw() as _),
|
||||
seat: Seat(seat.raw() as _),
|
||||
})
|
||||
}
|
||||
|
||||
fn clear(&self) {
|
||||
unsafe {
|
||||
if let Some(srv) = self.srv.take() {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ use {
|
|||
},
|
||||
};
|
||||
|
||||
pub type TestResult<T = ()> = Result<T, TestError>;
|
||||
|
||||
pub struct TestError {
|
||||
error: Box<dyn Error + 'static>,
|
||||
source: Option<Box<TestError>>,
|
||||
|
|
|
|||
|
|
@ -2,9 +2,12 @@ pub mod test_callback;
|
|||
pub mod test_compositor;
|
||||
pub mod test_display;
|
||||
pub mod test_jay_compositor;
|
||||
pub mod test_keyboard;
|
||||
pub mod test_pointer;
|
||||
pub mod test_region;
|
||||
pub mod test_registry;
|
||||
pub mod test_screenshot;
|
||||
pub mod test_seat;
|
||||
pub mod test_shm;
|
||||
pub mod test_shm_buffer;
|
||||
pub mod test_shm_pool;
|
||||
|
|
|
|||
89
src/it/test_ifs/test_keyboard.rs
Normal file
89
src/it/test_ifs/test_keyboard.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
use {
|
||||
crate::{
|
||||
ifs::wl_seat::wl_keyboard::WlKeyboard,
|
||||
it::{
|
||||
test_error::TestResult, test_object::TestObject, test_transport::TestTransport,
|
||||
test_utils::test_expected_event::TEEH, testrun::ParseFull,
|
||||
},
|
||||
utils::{buffd::MsgParser, clonecell::CloneCell, once::Once},
|
||||
wire::{wl_keyboard::*, WlKeyboardId, WlSurfaceId},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct TestEnterEvent {
|
||||
pub serial: u32,
|
||||
pub surface: WlSurfaceId,
|
||||
pub keys: Vec<u32>,
|
||||
}
|
||||
|
||||
pub struct TestKeyboard {
|
||||
pub id: WlKeyboardId,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub server: CloneCell<Option<Rc<WlKeyboard>>>,
|
||||
pub destroyed: Once,
|
||||
pub enter: TEEH<TestEnterEvent>,
|
||||
}
|
||||
|
||||
impl TestKeyboard {
|
||||
pub fn destroy(&self) -> TestResult {
|
||||
if self.destroyed.set() {
|
||||
self.tran.send(Release { self_id: self.id })?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_keymap(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = Keymap::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_enter(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let ev = Enter::parse_full(parser)?;
|
||||
self.enter.push(TestEnterEvent {
|
||||
serial: ev.serial,
|
||||
surface: ev.surface,
|
||||
keys: ev.keys.to_vec(),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_leave(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = Leave::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_key(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = Key::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_modifiers(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = Modifiers::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_repeat_info(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = RepeatInfo::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestKeyboard {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestKeyboard, WlKeyboard;
|
||||
|
||||
KEYMAP => handle_keymap,
|
||||
ENTER => handle_enter,
|
||||
LEAVE => handle_leave,
|
||||
KEY => handle_key,
|
||||
MODIFIERS => handle_modifiers,
|
||||
REPEAT_INFO => handle_repeat_info,
|
||||
}
|
||||
|
||||
impl TestObject for TestKeyboard {}
|
||||
95
src/it/test_ifs/test_pointer.rs
Normal file
95
src/it/test_ifs/test_pointer.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
use {
|
||||
crate::{
|
||||
ifs::wl_seat::wl_pointer::WlPointer,
|
||||
it::{
|
||||
test_error::TestResult, test_object::TestObject, test_transport::TestTransport,
|
||||
testrun::ParseFull,
|
||||
},
|
||||
utils::{buffd::MsgParser, clonecell::CloneCell},
|
||||
wire::{wl_pointer::*, WlPointerId},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestPointer {
|
||||
pub id: WlPointerId,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub server: CloneCell<Option<Rc<WlPointer>>>,
|
||||
pub destroyed: Cell<bool>,
|
||||
}
|
||||
|
||||
impl TestPointer {
|
||||
pub fn destroy(&self) -> TestResult {
|
||||
if !self.destroyed.replace(true) {
|
||||
self.tran.send(Release { self_id: self.id })?;
|
||||
}
|
||||
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_button(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = Button::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_axis(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = Axis::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_frame(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = Frame::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_axis_source(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = AxisSource::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_axis_stop(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = AxisStop::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_axis_discrete(&self, parser: MsgParser<'_, '_>) -> TestResult {
|
||||
let _ev = AxisDiscrete::parse_full(parser)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestPointer {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestPointer, WlPointer;
|
||||
|
||||
ENTER => handle_enter,
|
||||
LEAVE => handle_leave,
|
||||
MOTION => handle_motion,
|
||||
BUTTON => handle_button,
|
||||
AXIS => handle_axis,
|
||||
FRAME => handle_frame,
|
||||
AXIS_SOURCE => handle_axis_source,
|
||||
AXIS_STOP => handle_axis_stop,
|
||||
AXIS_DISCRETE => handle_axis_discrete,
|
||||
}
|
||||
|
||||
impl TestObject for TestPointer {}
|
||||
99
src/it/test_ifs/test_seat.rs
Normal file
99
src/it/test_ifs/test_seat.rs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
use {
|
||||
crate::{
|
||||
ifs::wl_seat::WlSeat,
|
||||
it::{
|
||||
test_error::{TestError, TestResult},
|
||||
test_ifs::{test_keyboard::TestKeyboard, test_pointer::TestPointer},
|
||||
test_object::TestObject,
|
||||
test_transport::TestTransport,
|
||||
testrun::ParseFull,
|
||||
},
|
||||
utils::{buffd::MsgParser, clonecell::CloneCell, once::Once},
|
||||
wire::{wl_seat::*, WlSeatId},
|
||||
},
|
||||
std::{cell::Cell, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestSeat {
|
||||
pub id: WlSeatId,
|
||||
pub tran: Rc<TestTransport>,
|
||||
pub server: CloneCell<Option<Rc<WlSeat>>>,
|
||||
pub destroyed: Once,
|
||||
pub caps: Cell<u32>,
|
||||
pub name: CloneCell<Option<Rc<String>>>,
|
||||
}
|
||||
|
||||
impl TestSeat {
|
||||
pub fn destroy(&self) -> Result<(), TestError> {
|
||||
if self.destroyed.set() {
|
||||
self.tran.send(Release { self_id: self.id })?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get_keyboard(&self) -> TestResult<Rc<TestKeyboard>> {
|
||||
let id = self.tran.id();
|
||||
self.tran.send(GetKeyboard {
|
||||
self_id: self.id,
|
||||
id,
|
||||
})?;
|
||||
let kb = Rc::new(TestKeyboard {
|
||||
id,
|
||||
tran: self.tran.clone(),
|
||||
server: Default::default(),
|
||||
destroyed: Default::default(),
|
||||
enter: Default::default(),
|
||||
});
|
||||
self.tran.add_obj(kb.clone())?;
|
||||
self.tran.sync().await;
|
||||
let server = self.tran.get_server_obj(id)?;
|
||||
kb.server.set(Some(server));
|
||||
Ok(kb)
|
||||
}
|
||||
|
||||
pub async fn get_pointer(&self) -> TestResult<Rc<TestPointer>> {
|
||||
let id = self.tran.id();
|
||||
self.tran.send(GetPointer {
|
||||
self_id: self.id,
|
||||
id,
|
||||
})?;
|
||||
let pointer = Rc::new(TestPointer {
|
||||
id,
|
||||
tran: self.tran.clone(),
|
||||
server: Default::default(),
|
||||
destroyed: Default::default(),
|
||||
});
|
||||
self.tran.add_obj(pointer.clone())?;
|
||||
self.tran.sync().await;
|
||||
let server = self.tran.get_server_obj(id)?;
|
||||
pointer.server.set(Some(server));
|
||||
Ok(pointer)
|
||||
}
|
||||
|
||||
fn handle_capabilities(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Capabilities::parse_full(parser)?;
|
||||
self.caps.set(ev.capabilities);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_name(&self, parser: MsgParser<'_, '_>) -> Result<(), TestError> {
|
||||
let ev = Name::parse_full(parser)?;
|
||||
self.name.set(Some(Rc::new(ev.name.to_string())));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for TestSeat {
|
||||
fn drop(&mut self) {
|
||||
let _ = self.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
test_object! {
|
||||
TestSeat, WlSeat;
|
||||
|
||||
CAPABILITIES => handle_capabilities,
|
||||
NAME => handle_name,
|
||||
}
|
||||
|
||||
impl TestObject for TestSeat {}
|
||||
|
|
@ -40,7 +40,7 @@ impl TestSubcompositor {
|
|||
id,
|
||||
tran: self.tran.clone(),
|
||||
destroyed: Cell::new(false),
|
||||
server: self.tran.get_object(id)?,
|
||||
server: self.tran.get_server_obj(id)?,
|
||||
});
|
||||
self.tran.add_obj(ss.clone())?;
|
||||
Ok(ss)
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ impl TestTransport {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_object<I: Into<ObjectId>, T: 'static>(&self, id: I) -> Result<Rc<T>, TestError> {
|
||||
pub fn get_server_obj<I: Into<ObjectId>, T: 'static>(&self, id: I) -> Result<Rc<T>, TestError> {
|
||||
let client = self.get_client()?;
|
||||
client.objects.get_obj(id.into())?.downcast()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
pub mod test_expected_event;
|
||||
pub mod test_object_ext;
|
||||
pub mod test_window;
|
||||
|
|
|
|||
71
src/it/test_utils/test_expected_event.rs
Normal file
71
src/it/test_utils/test_expected_event.rs
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
use {
|
||||
crate::{it::test_error::TestResult, utils::clonecell::CloneCell},
|
||||
std::{cell::RefCell, collections::VecDeque, rc::Rc},
|
||||
};
|
||||
|
||||
pub struct TestExpectedEvent<T> {
|
||||
data: Rc<TestExpectedEventData<T>>,
|
||||
holder: Rc<TestExpectedEventHolder<T>>,
|
||||
}
|
||||
|
||||
impl<T> TestExpectedEvent<T> {
|
||||
pub fn next(&self) -> TestResult<T> {
|
||||
match self.data.events.borrow_mut().pop_front() {
|
||||
Some(t) => Ok(t),
|
||||
_ => bail!("No event occurred"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last(&self) -> TestResult<T> {
|
||||
match self.data.events.borrow_mut().pop_back() {
|
||||
Some(t) => Ok(t),
|
||||
_ => bail!("No event occurred"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestExpectedEventHolder<T> {
|
||||
data: CloneCell<Option<Rc<TestExpectedEventData<T>>>>,
|
||||
}
|
||||
|
||||
pub type TEEH<T> = Rc<TestExpectedEventHolder<T>>;
|
||||
|
||||
impl<T> Default for TestExpectedEventHolder<T> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
data: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TestExpectedEventHolder<T> {
|
||||
pub fn expect(self: &Rc<Self>) -> TestResult<TestExpectedEvent<T>> {
|
||||
if self.data.get().is_some() {
|
||||
bail!("There is already an expected event data");
|
||||
}
|
||||
let data = Rc::new(TestExpectedEventData {
|
||||
events: Default::default(),
|
||||
});
|
||||
self.data.set(Some(data.clone()));
|
||||
Ok(TestExpectedEvent {
|
||||
data,
|
||||
holder: self.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn push(&self, t: T) {
|
||||
if let Some(data) = self.data.get() {
|
||||
data.events.borrow_mut().push_back(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TestExpectedEventData<T> {
|
||||
events: RefCell<VecDeque<T>>,
|
||||
}
|
||||
|
||||
impl<T> Drop for TestExpectedEvent<T> {
|
||||
fn drop(&mut self) {
|
||||
self.holder.data.set(None);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ use {
|
|||
client::{ClientId, RequestParser},
|
||||
ifs::wl_seat::WlSeatGlobal,
|
||||
it::{
|
||||
test_backend::TestBackend,
|
||||
test_backend::{TestBackend, TestBackendKb, TestBackendMouse, TestConnector},
|
||||
test_client::TestClient,
|
||||
test_config::TestConfig,
|
||||
test_error::{TestError, TestErrorExt},
|
||||
|
|
@ -12,6 +12,7 @@ use {
|
|||
},
|
||||
object::WL_DISPLAY_ID,
|
||||
state::State,
|
||||
tree::OutputNode,
|
||||
utils::{bitfield::Bitfield, buffd::MsgParser, oserror::OsErrorExt, stack::Stack},
|
||||
},
|
||||
std::{
|
||||
|
|
@ -102,6 +103,28 @@ impl TestRun {
|
|||
}
|
||||
bail!("Seat {} does not exist", id)
|
||||
}
|
||||
|
||||
pub async fn create_default_setup(&self) -> Result<DefaultSetup, TestError> {
|
||||
self.backend.install_default();
|
||||
let seat = self.get_seat("default")?;
|
||||
self.state.eng.yield_now().await;
|
||||
let output = match self.state.outputs.lock().values().next() {
|
||||
None => bail!("No output"),
|
||||
Some(d) => d.node.clone(),
|
||||
};
|
||||
self.cfg
|
||||
.set_input_device_seat(self.backend.default_kb.common.id, seat.id())?;
|
||||
self.cfg
|
||||
.set_input_device_seat(self.backend.default_mouse.common.id, seat.id())?;
|
||||
self.state.eng.yield_now().await;
|
||||
Ok(DefaultSetup {
|
||||
connector: self.backend.default_connector.clone(),
|
||||
output,
|
||||
kb: self.backend.default_kb.clone(),
|
||||
mouse: self.backend.default_mouse.clone(),
|
||||
seat,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParseFull<'a>: Sized {
|
||||
|
|
@ -115,3 +138,11 @@ impl<'a, T: RequestParser<'a>> ParseFull<'a> for T {
|
|||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DefaultSetup {
|
||||
pub connector: Rc<TestConnector>,
|
||||
pub output: Rc<OutputNode>,
|
||||
pub kb: Rc<TestBackendKb>,
|
||||
pub mouse: Rc<TestBackendMouse>,
|
||||
pub seat: Rc<WlSeatGlobal>,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ mod t0004_quit;
|
|||
mod t0005_create_seat;
|
||||
mod t0006_region;
|
||||
mod t0007_subsurface;
|
||||
mod t0008_map_focus;
|
||||
|
||||
pub trait TestCase: Sync {
|
||||
fn name(&self) -> &'static str;
|
||||
|
|
@ -58,5 +59,6 @@ pub fn tests() -> Vec<&'static dyn TestCase> {
|
|||
t0005_create_seat,
|
||||
t0006_region,
|
||||
t0007_subsurface,
|
||||
t0008_map_focus,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ use {
|
|||
|
||||
testcase!();
|
||||
|
||||
/// Test subsurface positioning
|
||||
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||
run.backend.install_default();
|
||||
|
||||
|
|
|
|||
27
src/it/tests/t0008_map_focus.rs
Normal file
27
src/it/tests/t0008_map_focus.rs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
use {
|
||||
crate::it::{
|
||||
test_error::{TestError, TestErrorExt},
|
||||
testrun::TestRun,
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
testcase!();
|
||||
|
||||
async fn test(run: Rc<TestRun>) -> Result<(), TestError> {
|
||||
let ds = run.create_default_setup().await?;
|
||||
ds.mouse.rel(1.0, 1.0);
|
||||
|
||||
let client = run.create_client().await?;
|
||||
let default_seat = client.get_default_seat().await?;
|
||||
|
||||
let enter = default_seat.kb.enter.expect()?;
|
||||
|
||||
let window = client.create_window().await?;
|
||||
window.map().await?;
|
||||
|
||||
let enter = enter.next().with_context(|| "Did not enter")?;
|
||||
tassert_eq!(enter.surface, window.surface.id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
14
src/time.rs
14
src/time.rs
|
|
@ -36,6 +36,13 @@ impl Time {
|
|||
Ok(Self(time))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn now_unchecked() -> Time {
|
||||
let mut time = uapi::pod_zeroed();
|
||||
let _ = uapi::clock_gettime(c::CLOCK_MONOTONIC, &mut time);
|
||||
Self(time)
|
||||
}
|
||||
|
||||
pub fn round_to_ms(self) -> Time {
|
||||
if self.0.tv_nsec > 999_000_000 {
|
||||
Time(c::timespec {
|
||||
|
|
@ -49,6 +56,13 @@ impl Time {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn usec(self) -> u64 {
|
||||
let sec = self.0.tv_sec as u64 * 1_000_000;
|
||||
let nsec = self.0.tv_nsec as u64 / 1_000;
|
||||
sec + nsec
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Time {}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ pub mod log_on_drop;
|
|||
pub mod nonblock;
|
||||
pub mod num_cpus;
|
||||
pub mod numcell;
|
||||
pub mod once;
|
||||
pub mod oserror;
|
||||
pub mod ptr_ext;
|
||||
pub mod queue;
|
||||
|
|
|
|||
26
src/utils/once.rs
Normal file
26
src/utils/once.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use std::{cell::Cell, future::Future};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Once {
|
||||
done: Cell<bool>,
|
||||
}
|
||||
|
||||
impl Once {
|
||||
pub fn set(&self) -> bool {
|
||||
!self.done.replace(true)
|
||||
}
|
||||
|
||||
pub fn exec<F: FnOnce()>(&self, f: F) {
|
||||
if !self.done.replace(true) {
|
||||
f();
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn exec_async<G: Future<Output = ()>, F: FnOnce() -> G>(&self, f: F) {
|
||||
if !self.done.replace(true) {
|
||||
f().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue