Add a new surface role for Xwayland surfaces

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter 2021-01-04 09:46:59 +01:00 committed by Victor Berger
parent 734b541ecd
commit 3504182a5e
4 changed files with 103 additions and 6 deletions

View File

@ -38,12 +38,25 @@ use crate::{
window_map::{Kind as SurfaceKind, WindowMap},
};
#[cfg(feature = "xwayland")]
use crate::xwayland::X11SurfaceRole;
// The xwayland feature only adds a X11Surface role, but the macro does not support #[cfg]
#[cfg(not(feature = "xwayland"))]
define_roles!(Roles =>
[ XdgSurface, XdgSurfaceRole ]
[ ShellSurface, ShellSurfaceRole]
[ DnDIcon, DnDIconRole ]
[ CursorImage, CursorImageRole ]
);
#[cfg(feature = "xwayland")]
define_roles!(Roles =>
[ XdgSurface, XdgSurfaceRole ]
[ ShellSurface, ShellSurfaceRole]
[ X11Surface, X11SurfaceRole ]
[ DnDIcon, DnDIconRole ]
[ CursorImage, CursorImageRole ]
);
pub type MyWindowMap = WindowMap<Roles>;
@ -219,6 +232,10 @@ impl PointerGrab for ResizeSurfaceGrab {
(self.last_window_size.0 as u32, self.last_window_size.1 as u32),
self.edges.into(),
),
#[cfg(feature = "xwayland")]
SurfaceKind::X11(_) => {
// TODO: What to do here? Send the update via X11?
}
}
}

View File

@ -161,7 +161,12 @@ impl AnvilState {
#[cfg(feature = "xwayland")]
let _xwayland = {
let xwm = XWm::new(handle.clone(), log.clone());
let xwm = XWm::new(
handle.clone(),
shell_handles.token,
shell_handles.window_map.clone(),
log.clone(),
);
XWayland::init(xwm, handle.clone(), display.clone(), &mut (), log.clone()).unwrap()
};

View File

@ -13,10 +13,14 @@ use smithay::{
};
use crate::shell::SurfaceData;
#[cfg(feature = "xwayland")]
use crate::xwayland::X11Surface;
pub enum Kind<R> {
Xdg(ToplevelSurface<R>),
Wl(ShellSurface<R>),
#[cfg(feature = "xwayland")]
X11(X11Surface),
}
// We implement Clone manually because #[derive(..)] would require R: Clone.
@ -25,6 +29,8 @@ impl<R> Clone for Kind<R> {
match self {
Kind::Xdg(xdg) => Kind::Xdg(xdg.clone()),
Kind::Wl(wl) => Kind::Wl(wl.clone()),
#[cfg(feature = "xwayland")]
Kind::X11(x11) => Kind::X11(x11.clone()),
}
}
}
@ -37,12 +43,16 @@ where
match *self {
Kind::Xdg(ref t) => t.alive(),
Kind::Wl(ref t) => t.alive(),
#[cfg(feature = "xwayland")]
Kind::X11(ref t) => t.alive(),
}
}
pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
match *self {
Kind::Xdg(ref t) => t.get_surface(),
Kind::Wl(ref t) => t.get_surface(),
#[cfg(feature = "xwayland")]
Kind::X11(ref t) => t.get_surface(),
}
}
@ -51,6 +61,8 @@ where
match (self, other) {
(Kind::Xdg(a), Kind::Xdg(b)) => a.equals(b),
(Kind::Wl(a), Kind::Wl(b)) => a.equals(b),
#[cfg(feature = "xwayland")]
(Kind::X11(a), Kind::X11(b)) => a.equals(b),
_ => false,
}
}

View File

@ -5,6 +5,7 @@ use smithay::{
calloop::LoopHandle,
wayland_server::{protocol::wl_surface::WlSurface, Client},
},
wayland::compositor::CompositorToken,
xwayland::XWindowManager,
};
@ -22,7 +23,11 @@ use x11rb::{
rust_connection::{DefaultStream, RustConnection},
};
use crate::AnvilState;
use crate::{
shell::{MyWindowMap, Roles},
window_map::Kind,
AnvilState,
};
use x11rb_event_source::X11Source;
@ -32,18 +37,31 @@ mod x11rb_event_source;
/// After XWayland was started, the actual state is kept in `X11State`.
pub struct XWm {
handle: LoopHandle<AnvilState>,
token: CompositorToken<Roles>,
window_map: Rc<RefCell<MyWindowMap>>,
log: slog::Logger,
}
impl XWm {
pub fn new(handle: LoopHandle<AnvilState>, log: slog::Logger) -> Self {
Self { handle, log }
pub fn new(
handle: LoopHandle<AnvilState>,
token: CompositorToken<Roles>,
window_map: Rc<RefCell<MyWindowMap>>,
log: slog::Logger,
) -> Self {
Self {
handle,
token,
window_map,
log,
}
}
}
impl XWindowManager for XWm {
fn xwayland_ready(&mut self, connection: UnixStream, client: Client) {
let (wm, source) = X11State::start_wm(connection, self.log.clone()).unwrap();
let (wm, source) =
X11State::start_wm(connection, self.token, self.window_map.clone(), self.log.clone()).unwrap();
let wm = Rc::new(RefCell::new(wm));
client.data_map().insert_if_missing(|| Rc::clone(&wm));
self.handle
@ -73,10 +91,17 @@ struct X11State {
atoms: Atoms,
log: slog::Logger,
unpaired_surfaces: HashMap<u32, Window>,
token: CompositorToken<Roles>,
window_map: Rc<RefCell<MyWindowMap>>,
}
impl X11State {
fn start_wm(connection: UnixStream, log: slog::Logger) -> Result<(Self, X11Source), Box<dyn std::error::Error>> {
fn start_wm(
connection: UnixStream,
token: CompositorToken<Roles>,
window_map: Rc<RefCell<MyWindowMap>>,
log: slog::Logger,
) -> Result<(Self, X11Source), Box<dyn std::error::Error>> {
// Create an X11 connection. XWayland only uses screen 0.
let screen = 0;
let stream = DefaultStream::from_unix_stream(connection)?;
@ -119,6 +144,8 @@ impl X11State {
conn: Rc::clone(&conn),
atoms,
unpaired_surfaces: Default::default(),
token,
window_map,
log,
};
@ -187,6 +214,17 @@ impl X11State {
fn new_window(&mut self, window: Window, surface: WlSurface) {
debug!(self.log, "Matched X11 surface {:x?} to {:x?}", window, surface);
if self.token.give_role_with(&surface, X11SurfaceRole).is_err() {
// It makes no sense to post a protocol error here since that would only kill Xwayland
error!(self.log, "Surface {:x?} already has a role?!", surface);
return;
}
let x11surface = X11Surface { surface };
self.window_map
.borrow_mut()
.insert(Kind::X11(x11surface), (0, 0));
}
}
@ -204,3 +242,28 @@ pub fn commit_hook(surface: &WlSurface) {
}
}
}
pub struct X11SurfaceRole;
#[derive(Clone)]
pub struct X11Surface {
surface: WlSurface,
}
impl X11Surface {
pub fn alive(&self) -> bool {
self.surface.as_ref().is_alive()
}
pub fn equals(&self, other: &Self) -> bool {
self.alive() && other.alive() && self.surface.as_ref().equals(&other.surface.as_ref())
}
pub fn get_surface(&self) -> Option<&WlSurface> {
if self.alive() {
Some(&self.surface)
} else {
None
}
}
}