1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
use std::os::fd::AsFd as _;
use std::os::unix::net::UnixStream;
use std::sync::atomic::Ordering;
use std::time::Duration;
use calloop::generic::Generic;
use calloop::{EventLoop, Interest, LoopHandle, Mode, PostAction};
use niri_config::Config;
use smithay::output::Output;
use super::client::{Client, ClientId};
use super::server::Server;
use crate::niri::{NewClient, Niri};
pub struct Fixture {
pub event_loop: EventLoop<'static, State>,
pub handle: LoopHandle<'static, State>,
pub state: State,
}
pub struct State {
pub server: Server,
pub clients: Vec<Client>,
}
impl Fixture {
pub fn new() -> Self {
Self::with_config(Config::default())
}
pub fn with_config(config: Config) -> Self {
let event_loop = EventLoop::try_new().unwrap();
let handle = event_loop.handle();
let server = Server::new(config);
let fd = server.event_loop.as_fd().try_clone_to_owned().unwrap();
let source = Generic::new(fd, Interest::READ, Mode::Level);
handle
.insert_source(source, |_, _, state: &mut State| {
state.server.dispatch();
Ok(PostAction::Continue)
})
.unwrap();
let state = State {
server,
clients: Vec::new(),
};
Self {
event_loop,
handle,
state,
}
}
pub fn dispatch(&mut self) {
self.event_loop
.dispatch(Duration::ZERO, &mut self.state)
.unwrap();
}
pub fn niri_state(&mut self) -> &mut crate::niri::State {
&mut self.state.server.state
}
pub fn niri(&mut self) -> &mut Niri {
&mut self.niri_state().niri
}
pub fn niri_output(&self, n: u8) -> Output {
let niri = &self.state.server.state.niri;
let idx = usize::from(n - 1);
let output = niri.global_space.outputs().nth(idx).unwrap();
output.clone()
}
pub fn niri_focus_output(&mut self, n: u8) {
let niri = &mut self.state.server.state.niri;
let idx = usize::from(n - 1);
let output = niri.global_space.outputs().nth(idx).unwrap();
niri.layout.focus_output(output);
}
pub fn niri_complete_animations(&mut self) {
let niri = self.niri();
niri.clock.set_complete_instantly(true);
niri.advance_animations();
niri.clock.set_complete_instantly(false);
}
pub fn add_output(&mut self, n: u8, size: (u16, u16)) {
let state = self.niri_state();
let niri = &mut state.niri;
state.backend.headless().add_output(niri, n, size);
}
pub fn add_client(&mut self) -> ClientId {
let (sock1, sock2) = UnixStream::pair().unwrap();
self.niri().insert_client(NewClient {
client: sock1,
restricted: false,
credentials_unknown: false,
});
let client = Client::new(sock2);
let id = client.id;
let fd = client.event_loop.as_fd().try_clone_to_owned().unwrap();
let source = Generic::new(fd, Interest::READ, Mode::Level);
self.handle
.insert_source(source, move |_, _, state: &mut State| {
state.client(id).dispatch();
Ok(PostAction::Continue)
})
.unwrap();
self.state.clients.push(client);
self.roundtrip(id);
id
}
pub fn client(&mut self, id: ClientId) -> &mut Client {
self.state.client(id)
}
pub fn roundtrip(&mut self, id: ClientId) {
let client = self.state.client(id);
let data = client.send_sync();
while !data.done.load(Ordering::Relaxed) {
self.dispatch();
}
}
/// Roundtrip twice in a row.
///
/// For some reason, when running tests on many threads at once, a single roundtrip is
/// sometimes not sufficient to get the configure events to the client.
///
/// I suspect that this is because these configure events are sent from the niri loop callback,
/// so they arrive after the sync done event and don't get processed in that client dispatch
/// cycle. I'm not sure why this would be dependent on multithreading. But if this is indeed
/// the issue, then a double roundtrip fixes it.
pub fn double_roundtrip(&mut self, id: ClientId) {
self.roundtrip(id);
self.roundtrip(id);
}
}
impl State {
pub fn client(&mut self, id: ClientId) -> &mut Client {
self.clients.iter_mut().find(|c| c.id == id).unwrap()
}
}
|