Refine shell status controls and glass rendering; defer cursor redraw safely
This commit is contained in:
1 parent
e85fc1e032
commit
b3fa82b53b
53 files changed
+3329
-259
No files matched your search
+81
-1
@@ -77,7 +77,19 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
|
||||
info!(socket = ?state.socket_name, backend = ?launch.backend, "Ferese is accepting Wayland clients");
|
||||
let mut child = spawn_client(&mut state, launch.client, launch.client_capabilities);
|
||||
let result = event_loop.run(None, &mut state, |_| {});
|
||||
let result = event_loop.run(None, &mut state, |state| {
|
||||
// All input/Wayland callbacks have returned, releasing seat locks.
|
||||
// Coalesce cursor changes and redraw here, never inside cursor_image.
|
||||
if std::mem::take(&mut state.cursor_redraw_pending) {
|
||||
backends::direct::render_all(state);
|
||||
}
|
||||
// Registry/sync/configure replies must not depend on a submitted
|
||||
// frame: at startup clients need these before they can draw anything.
|
||||
// This also keeps idle DRM sessions responsive when there is no damage.
|
||||
if let Err(error) = state.display_handle.flush_clients() {
|
||||
tracing::warn!(%error, "failed to flush Wayland clients");
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(child) = &mut child {
|
||||
terminate_child(child);
|
||||
@@ -151,3 +163,71 @@ fn terminate_child(child: &mut Child) {
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod startup_tests {
|
||||
use super::*;
|
||||
use std::{
|
||||
io::{Read, Write},
|
||||
os::unix::net::UnixStream,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn deferred_cursor_redraw_runs_after_input_lock_is_released() {
|
||||
use std::sync::Mutex;
|
||||
|
||||
let mut event_loop = EventLoop::<bool>::try_new().unwrap();
|
||||
let pointer_lock = Arc::new(Mutex::new(()));
|
||||
let callback_lock = pointer_lock.clone();
|
||||
event_loop.handle().insert_idle(move |pending| {
|
||||
// Mirrors Smithay's cursor_image callback during pointer motion.
|
||||
let _guard = callback_lock.lock().unwrap();
|
||||
*pending = true;
|
||||
*pending = true; // Multiple cursor changes must coalesce.
|
||||
assert!(callback_lock.try_lock().is_err());
|
||||
});
|
||||
|
||||
let signal = event_loop.get_signal();
|
||||
let mut pending = false;
|
||||
let mut redraws = 0;
|
||||
event_loop
|
||||
.run(Some(Duration::ZERO), &mut pending, |pending| {
|
||||
if std::mem::take(pending) {
|
||||
// Rendering reads the pointer location at this point.
|
||||
let _guard = pointer_lock.try_lock().expect("input lock still held");
|
||||
redraws += 1;
|
||||
}
|
||||
assert!(!std::mem::take(pending));
|
||||
signal.stop();
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(redraws, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wayland_roundtrip_completes_without_a_rendered_frame() {
|
||||
let mut display = Display::<()>::new().unwrap();
|
||||
let (server, mut client) = UnixStream::pair().unwrap();
|
||||
display
|
||||
.handle()
|
||||
.insert_client(server, Arc::new(state::ClientState::default()))
|
||||
.unwrap();
|
||||
// wl_display.sync(new_id=2), using native-endian Wayland wire format.
|
||||
for word in [1u32, 12u32 << 16, 2u32] {
|
||||
client.write_all(&word.to_ne_bytes()).unwrap();
|
||||
}
|
||||
display.dispatch_clients(&mut ()).unwrap();
|
||||
display.handle().flush_clients().unwrap();
|
||||
client
|
||||
.set_read_timeout(Some(Duration::from_secs(1)))
|
||||
.unwrap();
|
||||
let mut reply = [0u8; 12];
|
||||
client.read_exact(&mut reply).unwrap();
|
||||
assert_eq!(u32::from_ne_bytes(reply[0..4].try_into().unwrap()), 2);
|
||||
assert_eq!(
|
||||
u32::from_ne_bytes(reply[4..8].try_into().unwrap()) & 0xffff,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user