server: give uninitialized and initialized xstate with unique types

This commit is contained in:
En-En 2025-08-03 01:40:26 +00:00 committed by Supreeeme
parent 56d5cce2d0
commit 4280639df8
4 changed files with 180 additions and 137 deletions

View file

@ -1,7 +1,7 @@
mod server;
pub mod xstate;
use crate::server::{PendingSurfaceState, ServerState};
use crate::server::{EarlyConnection, PendingSurfaceState, ServerState};
use crate::xstate::{RealConnection, XState};
use log::{error, info};
use rustix::event::{poll, PollFd, PollFlags};
@ -16,7 +16,6 @@ use xcb::x;
pub trait XConnection: Sized + 'static {
type X11Selection: X11Selection;
fn root_window(&self) -> x::Window;
fn set_window_dims(&mut self, window: x::Window, dims: PendingSurfaceState);
fn set_fullscreen(&mut self, window: x::Window, fullscreen: bool);
fn focus_window(&mut self, window: x::Window, output_name: Option<String>);
@ -30,6 +29,7 @@ pub trait X11Selection {
fn write_to(&self, mime: &str, pipe: WritePipe);
}
type EarlyServerState = ServerState<EarlyConnection<<RealConnection as XConnection>::X11Selection>>;
type RealServerState = ServerState<RealConnection>;
pub trait RunData {
@ -58,8 +58,6 @@ pub fn main(mut data: impl RunData) -> Option<()> {
let dh = display.handle();
data.created_server();
let mut server_state = RealServerState::new(dh, data.server());
let (xsock_wl, xsock_xwl) = UnixStream::pair().unwrap();
// Prevent creation of new Xwayland command from closing fd
rustix::io::fcntl_setfd(&xsock_xwl, rustix::io::FdFlags::empty()).unwrap();
@ -136,11 +134,10 @@ pub fn main(mut data: impl RunData) -> Option<()> {
}
};
let mut server_state = EarlyServerState::new(dh, data.server());
server_state.connect(connection);
server_state.run();
let mut xstate: Option<XState> = None;
// Remove the lifetimes on our fds to avoid borrowing issues, since we know they will exist for
// the rest of our program anyway
let server_fd = unsafe { BorrowedFd::borrow_raw(server_state.clientside_fd().as_raw_fd()) };
@ -154,18 +151,74 @@ pub fn main(mut data: impl RunData) -> Option<()> {
PollFd::from_borrowed_fd(server_fd, PollFlags::IN),
PollFd::new(&xsock_wl, PollFlags::IN),
PollFd::from_borrowed_fd(display_fd, PollFlags::IN),
PollFd::new(&ready_rx, PollFlags::IN),
PollFd::new(&quit_rx, PollFlags::IN),
PollFd::new(&ready_rx, PollFlags::IN),
];
let mut ready = false;
loop {
match poll(&mut fds, -1) {
Ok(_) => {
if !fds[3].revents().is_empty() {
ready = true;
let status = xwayland_exit_code(&mut quit_rx);
if *status != ExitStatus::default() {
error!("Xwayland exited early with {status}");
}
return None;
}
if !fds[4].revents().is_empty() {
break;
}
}
Err(other) => panic!("Poll failed: {other:?}"),
}
display.dispatch_clients(server_state.inner_mut()).unwrap();
server_state.run();
display.flush_clients().unwrap();
}
let mut xstate: Option<XState> = None;
let xstate = xstate.insert(XState::new(xsock_wl.as_fd()));
let mut reader = BufReader::new(&ready_rx);
{
let mut display = String::new();
reader.read_line(&mut display).unwrap();
display.pop();
display.insert(0, ':');
info!("Connected to Xwayland on {display}");
data.xwayland_ready(display, xwl_pid);
}
let mut server_state = xstate.server_state_setup(server_state);
#[cfg(feature = "systemd")]
{
match sd_notify::notify(true, &[sd_notify::NotifyState::Ready]) {
Ok(()) => info!("Successfully notified systemd of ready state."),
Err(e) => log::warn!("Systemd notify failed: {e:?}"),
}
}
#[cfg(not(feature = "systemd"))]
info!("Systemd support disabled.");
loop {
xstate.handle_events(&mut server_state);
display.dispatch_clients(server_state.inner_mut()).unwrap();
server_state.run();
display.flush_clients().unwrap();
if let Some(sel) = server_state.new_selection() {
xstate.set_clipboard(sel);
}
if let Some(scale) = server_state.new_global_scale() {
xstate.update_global_scale(scale);
}
match poll(&mut fds, -1) {
Ok(_) => {
if !fds[3].revents().is_empty() {
let status = xwayland_exit_code(&mut quit_rx);
if *status != ExitStatus::default() {
error!("Xwayland exited early with {status}");
@ -175,46 +228,5 @@ pub fn main(mut data: impl RunData) -> Option<()> {
}
Err(other) => panic!("Poll failed: {other:?}"),
}
if xstate.is_none() && ready {
let xstate = xstate.insert(XState::new(xsock_wl.as_fd()));
let mut reader = BufReader::new(&ready_rx);
let mut display = String::new();
reader.read_line(&mut display).unwrap();
display.pop();
display.insert(0, ':');
info!("Connected to Xwayland on {display}");
data.xwayland_ready(display, xwl_pid);
xstate.server_state_setup(&mut server_state);
#[cfg(feature = "systemd")]
{
match sd_notify::notify(true, &[sd_notify::NotifyState::Ready]) {
Ok(()) => info!("Successfully notified systemd of ready state."),
Err(e) => log::warn!("Systemd notify failed: {e:?}"),
}
}
#[cfg(not(feature = "systemd"))]
info!("Systemd support disabled.");
}
if let Some(xstate) = &mut xstate {
xstate.handle_events(&mut server_state);
}
display.dispatch_clients(server_state.inner_mut()).unwrap();
server_state.run();
display.flush_clients().unwrap();
if let Some(xstate) = &mut xstate {
if let Some(sel) = server_state.new_selection() {
xstate.set_clipboard(sel);
}
if let Some(scale) = server_state.new_global_scale() {
xstate.update_global_scale(scale);
}
}
}
}