milkyway/src/state/xwayland.rs
2026-07-04 22:57:08 -07:00

131 lines
3.7 KiB
Rust

use std::process::Stdio;
use smithay::{
delegate_dispatch2,
utils::{Logical, Rectangle},
wayland::xwayland_shell::{XWaylandShellHandler, XWaylandShellState},
xwayland::{
xwm::{Reorder, ResizeEdge, XwmId},
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
},
};
use wayland_server::Display;
use crate::state::{AppWrapper, State};
pub struct XWaylandState {
pub xwm: Option<X11Wm>,
pub xwayland_shell_state: XWaylandShellState,
}
impl XwmHandler for State {
fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm {
self.xwayland_state.xwm.as_mut().unwrap()
}
fn new_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
fn new_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
fn map_window_request(&mut self, _xwm: XwmId, window: X11Surface) {
// grant it — the window will be mapped once you set this
window.set_mapped(true).unwrap();
let mut space = self.space.lock();
space.map_element(AppWrapper::new_x11(window), (0, 0), true);
// insert it into your Space/window management here
}
fn mapped_override_redirect_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
fn unmapped_window(&mut self, _xwm: XwmId, _window: X11Surface) {
// let mut space = self.space.lock();
}
fn destroyed_window(&mut self, _xwm: XwmId, _window: X11Surface) {}
fn configure_request(
&mut self,
_xwm: XwmId,
window: X11Surface,
x: Option<i32>,
y: Option<i32>,
w: Option<u32>,
h: Option<u32>,
_reorder: Option<Reorder>,
) {
// Usually you just approve the requested geometry
let _ = window.configure(None);
}
fn configure_notify(
&mut self,
_xwm: XwmId,
_window: X11Surface,
_geo: Rectangle<i32, Logical>,
_above: Option<u32>,
) {
}
fn resize_request(
&mut self,
_xwm: XwmId,
_window: X11Surface,
_button: u32,
_edge: ResizeEdge,
) {
}
fn move_request(&mut self, _xwm: XwmId, _window: X11Surface, _button: u32) {}
}
impl XWaylandShellHandler for State {
fn xwayland_shell_state(
&mut self,
) -> &mut smithay::wayland::xwayland_shell::XWaylandShellState {
&mut self.xwayland_state.xwayland_shell_state
}
}
impl State {
pub fn setup_xwayland(
&mut self,
display: &Display<State>,
) -> Result<(), Box<dyn std::error::Error>> {
let dh = display.handle();
let (xwayland, client) = XWayland::spawn(
&dh,
None,
std::iter::empty::<(String, String)>(),
std::iter::empty::<String>(),
true,
Stdio::null(),
Stdio::null(),
|_| {},
)?;
let event_loop_handle = self.event_loop_handle.clone();
event_loop_handle.insert_source(xwayland, move |event, _, state| {
match event {
XWaylandEvent::Ready {
x11_socket,
display_number,
} => {
let event_loop = state.event_loop_handle.clone();
let wm = X11Wm::start_wm(event_loop, &dh, x11_socket, client.clone())
.expect("failed to start X11 wm");
state.xwayland_state.xwm = Some(wm);
println!("XWayland started on display :{display_number}");
unsafe { std::env::set_var("DISPLAY", format!(":{display_number}")) };
}
XWaylandEvent::Error => {
// warn!("XWayland crashed on startup");
}
}
})?;
Ok(())
}
}