Skip to content

Commit

Permalink
Add a new surface role for Xwayland surfaces
Browse files Browse the repository at this point in the history
Signed-off-by: Uli Schlachter <psychon@znc.in>
  • Loading branch information
psychon committed Jan 4, 2021
1 parent 40406bb commit 36be6d3
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 7 deletions.
17 changes: 17 additions & 0 deletions anvil/src/shell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,22 @@ 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 ]
);
Expand Down Expand Up @@ -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?
}
}
}

Expand Down
17 changes: 15 additions & 2 deletions anvil/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,21 @@ impl AnvilState {

#[cfg(feature = "xwayland")]
let _xwayland = {
let xwm = XWm::new(handle.clone(), log.clone());
XWayland::init(xwm, handle.clone(), display.clone(), &mut (), log.clone(), _helper).unwrap()
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(),
_helper,
)
.unwrap()
};

AnvilState {
Expand Down
12 changes: 12 additions & 0 deletions anvil/src/window_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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()),
}
}
}
Expand All @@ -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(),
}
}

Expand All @@ -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,
}
}
Expand Down
73 changes: 68 additions & 5 deletions anvil/src/xwayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use smithay::{
calloop::LoopHandle,
wayland_server::{protocol::wl_surface::WlSurface, Client},
},
wayland::compositor::CompositorToken,
xwayland::XWindowManager,
};

Expand All @@ -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;

Expand All @@ -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
Expand Down Expand Up @@ -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)?;
Expand Down Expand Up @@ -119,6 +144,8 @@ impl X11State {
conn: Rc::clone(&conn),
atoms,
unpaired_surfaces: Default::default(),
token,
window_map,
log,
};

Expand Down Expand Up @@ -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));
}
}

Expand All @@ -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
}
}
}

0 comments on commit 36be6d3

Please sign in to comment.