feat(xwayland): serialize start

This commit is contained in:
Nova
2023-05-24 05:35:09 -04:00
parent 1cb8e1b7a4
commit e3b1276d77
4 changed files with 138 additions and 12 deletions

View File

@@ -6,6 +6,7 @@ use smithay::{
delegate_compositor,
reexports::wayland_server::{protocol::wl_surface::WlSurface, Client},
wayland::compositor::{self, CompositorClientState, CompositorHandler, CompositorState},
xwayland::XWaylandClientData,
};
use std::sync::Arc;
use tracing::debug;
@@ -38,7 +39,13 @@ impl CompositorHandler for WaylandState {
}
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {
&client.get_data::<ClientState>().unwrap().compositor_state
if let Some(client_state) = client.get_data::<ClientState>() {
&client_state.compositor_state
} else if let Some(xwayland_client_data) = client.get_data::<XWaylandClientData>() {
&xwayland_client_data.compositor_state
} else {
unimplemented!()
}
}
}

View File

@@ -88,7 +88,7 @@ impl Wayland {
let (dmabuf_tx, dmabuf_rx) = mpsc::unbounded_channel();
let display = Arc::new(Mutex::new(display));
let xwayland_state = XWaylandState::create(&display_handle).unwrap();
let xwayland_state = XWaylandState::create(display.clone(), &display_handle).unwrap();
let wayland_state = WaylandState::new(display.clone(), display_handle, &renderer, dmabuf_tx);
let (global_destroy_queue_in, global_destroy_queue) = mpsc::channel(8);

View File

@@ -41,6 +41,7 @@ use smithay::{
},
},
wayland::compositor,
xwayland::X11Surface,
};
use stardust_xr::schemas::flex::{deserialize, serialize};
use std::sync::{Arc, Weak};
@@ -316,7 +317,10 @@ impl WaylandBackend {
}
}
#[derive(Debug)]
pub struct X11Backend;
pub struct X11Backend {
pub toplevel_parent: Option<X11Surface>,
pub toplevel: X11Surface,
}
#[derive(Debug)]
pub enum Backend {
@@ -719,7 +723,24 @@ impl ItemSpecialization for PanelItem {
))
.unwrap()
}
Backend::X11(_) => todo!(),
Backend::X11(x) => {
let toplevel_state = (
None::<String>,
x.toplevel.title(),
None::<String>,
(x.toplevel.geometry().size.w, x.toplevel.geometry().size.h),
x.toplevel.min_size().map(|s| (s.w, s.h)),
x.toplevel.max_size().map(|s| (s.w, s.w)),
);
let info = (
None::<String>,
toplevel_state,
Vec::<PopupData>::new(),
None::<SurfaceID>,
None::<SurfaceID>,
);
serialize((id, info)).unwrap()
}
}
}
}

View File

@@ -1,13 +1,20 @@
use super::seat::SeatData;
use super::{panel_item::RecommendedState, seat::SeatData, state::WaylandState};
use crate::wayland::{
panel_item::{Backend, PanelItem, X11Backend},
surface::CoreSurface,
};
use color_eyre::eyre::Result;
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use smithay::{
reexports::{
calloop::{self, EventLoop, LoopSignal},
wayland_server::DisplayHandle,
wayland_protocols::xdg::shell::server::xdg_toplevel,
wayland_server::{Display, DisplayHandle, Resource, WEnum},
x11rb::protocol::xproto::Window,
},
utils::{Logical, Rectangle},
wayland::compositor,
xwayland::{
xwm::{Reorder, ResizeEdge, XwmId},
X11Surface, X11Wm, XWayland, XWaylandEvent, XwmHandler,
@@ -26,7 +33,10 @@ pub struct XWaylandState {
event_loop_join: Option<JoinHandle<Result<(), calloop::Error>>>,
}
impl XWaylandState {
pub fn create(dh: &DisplayHandle) -> Result<Self> {
pub fn create(
wayland_display: Arc<Mutex<Display<WaylandState>>>,
dh: &DisplayHandle,
) -> Result<Self> {
let dh = dh.clone();
let (tx, rx) = oneshot::channel();
@@ -57,7 +67,7 @@ impl XWaylandState {
None,
empty::<(&OsStr, &OsStr)>(),
true,
move |_| (),
|_| (),
)?;
let _ = tx.send(XWaylandState {
display,
@@ -65,7 +75,13 @@ impl XWaylandState {
event_loop_signal: event_loop.get_signal(),
event_loop_join: None,
});
let mut handler = XWaylandHandler::default();
let wayland_display_handle = wayland_display.lock().handle();
let mut handler = XWaylandHandler {
wayland_display,
wayland_display_handle,
wm: None,
seat: None,
};
event_loop.run(Duration::from_secs(60 * 60), &mut handler, |_| ())
});
@@ -83,11 +99,19 @@ impl Drop for XWaylandState {
}
}
#[derive(Default)]
struct XWaylandHandler {
wayland_display: Arc<Mutex<Display<WaylandState>>>,
wayland_display_handle: DisplayHandle,
wm: Option<X11Wm>,
seat: Option<Arc<SeatData>>,
}
impl XWaylandHandler {
fn panel_item(&self, window: &X11Surface) -> Option<Arc<PanelItem>> {
compositor::with_states(&window.wl_surface()?, |s| {
s.data_map.get::<Arc<PanelItem>>().cloned()
})
}
}
impl XwmHandler for XWaylandHandler {
fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm {
@@ -104,6 +128,44 @@ impl XwmHandler for XWaylandHandler {
fn map_window_request(&mut self, _xwm: XwmId, window: X11Surface) {
debug!(?window, "X map window request");
window.set_mapped(true).unwrap();
}
fn map_window_notify(&mut self, _xwm: XwmId, window: X11Surface) {
debug!(?window, "X map window notify");
let dh = self.wayland_display_handle.clone();
let seat = self.seat.clone().unwrap();
CoreSurface::add_to(
&self.wayland_display,
self.wayland_display.lock().handle(),
&window.wl_surface().unwrap(),
move |c| {
let Some(wl_surface) = window.wl_surface() else {return};
match c {
0 => {
let seat = seat.clone();
window.user_data().insert_if_missing_threadsafe(|| {
let (_node, panel_item) = PanelItem::create(
wl_surface.clone(),
Backend::X11(X11Backend {
toplevel_parent: None,
toplevel: window.clone(),
}),
wl_surface
.client()
.and_then(|c| c.get_credentials(&dh).ok()),
seat,
);
panel_item
});
}
_ => {
let Some(panel_item) = window.user_data().get::<Arc<PanelItem>>() else {return};
panel_item.commit_toplevel();
}
}
},
);
}
fn mapped_override_redirect_window(&mut self, _xwm: XwmId, window: X11Surface) {
@@ -141,6 +203,11 @@ impl XwmHandler for XWaylandHandler {
debug!(?window, ?geometry, above, "Configure X window");
}
fn move_request(&mut self, _xwm: XwmId, window: X11Surface, button: u32) {
let Some(panel_item) = self.panel_item(&window) else {return};
debug!(?window, button, "X window requests move");
panel_item.recommend_toplevel_state(RecommendedState::Move);
}
fn resize_request(
&mut self,
_xwm: XwmId,
@@ -148,10 +215,41 @@ impl XwmHandler for XWaylandHandler {
button: u32,
resize_edge: ResizeEdge,
) {
let Some(panel_item) = self.panel_item(&window) else {return};
debug!(?window, button, ?resize_edge, "X window requests resize");
panel_item.recommend_toplevel_state(RecommendedState::Resize(
WEnum::Value(match resize_edge {
ResizeEdge::Top => xdg_toplevel::ResizeEdge::Top,
ResizeEdge::Bottom => xdg_toplevel::ResizeEdge::Bottom,
ResizeEdge::Left => xdg_toplevel::ResizeEdge::Left,
ResizeEdge::TopLeft => xdg_toplevel::ResizeEdge::TopLeft,
ResizeEdge::BottomLeft => xdg_toplevel::ResizeEdge::BottomLeft,
ResizeEdge::Right => xdg_toplevel::ResizeEdge::Right,
ResizeEdge::TopRight => xdg_toplevel::ResizeEdge::TopRight,
ResizeEdge::BottomRight => xdg_toplevel::ResizeEdge::BottomRight,
})
.into(),
));
}
fn move_request(&mut self, _xwm: XwmId, window: X11Surface, button: u32) {
debug!(?window, button, "X window requests move");
fn maximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
let Some(panel_item) = self.panel_item(&window) else {return};
panel_item.recommend_toplevel_state(RecommendedState::Maximize(true));
}
fn unmaximize_request(&mut self, _xwm: XwmId, window: X11Surface) {
let Some(panel_item) = self.panel_item(&window) else {return};
panel_item.recommend_toplevel_state(RecommendedState::Maximize(false));
}
fn fullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
let Some(panel_item) = self.panel_item(&window) else {return};
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
}
fn unfullscreen_request(&mut self, _xwm: XwmId, window: X11Surface) {
let Some(panel_item) = self.panel_item(&window) else {return};
panel_item.recommend_toplevel_state(RecommendedState::Fullscreen(true));
}
fn minimize_request(&mut self, _xwm: XwmId, window: X11Surface) {
let Some(panel_item) = self.panel_item(&window) else {return};
panel_item.recommend_toplevel_state(RecommendedState::Minimize);
}
}