1
0
Fork 0
forked from wry/wry

wayland: implement xwayland_shell_v1

This commit is contained in:
Julian Orth 2022-10-16 21:14:12 +02:00
parent 1f64fefc86
commit 335677bbcd
11 changed files with 332 additions and 7 deletions

View file

@ -2,14 +2,14 @@ use {
crate::{
async_engine::SpawnedFuture,
client::{error::LookupError, objects::Objects},
ifs::{wl_display::WlDisplay, wl_registry::WlRegistry},
ifs::{wl_display::WlDisplay, wl_registry::WlRegistry, wl_surface::WlSurface},
leaks::Tracker,
object::{Interface, Object, ObjectId, WL_DISPLAY_ID},
state::State,
utils::{
asyncevent::AsyncEvent,
buffd::{MsgFormatter, MsgParser, MsgParserError, OutBufferSwapchain},
copyhashmap::Locked,
copyhashmap::{CopyHashMap, Locked},
errorfmt::ErrorFmt,
numcell::NumCell,
trim::AsciiTrim,
@ -145,6 +145,8 @@ impl Clients {
pid_info: get_pid_info(uid, pid),
serials: Default::default(),
symmetric_delete: Cell::new(false),
last_xwayland_serial: Cell::new(0),
surfaces_by_xwayland_serial: Default::default(),
});
track!(data, data);
let display = Rc::new(WlDisplay::new(&data));
@ -214,6 +216,7 @@ impl Drop for ClientHolder {
self.data.objects.destroy();
self.data.flush_request.clear();
self.data.shutdown.clear();
self.data.surfaces_by_xwayland_serial.clear();
}
}
@ -251,6 +254,8 @@ pub struct Client {
pub pid_info: PidInfo,
pub serials: RefCell<VecDeque<SerialRange>>,
pub symmetric_delete: Cell<bool>,
pub last_xwayland_serial: Cell<u64>,
pub surfaces_by_xwayland_serial: CopyHashMap<u64, Rc<WlSurface>>,
}
pub const NUM_CACHED_SERIAL_RANGES: usize = 64;

View file

@ -19,6 +19,7 @@ use {
},
wl_shm::WlShmGlobal,
wl_subcompositor::WlSubcompositorGlobal,
wl_surface::xwayland_shell_v1::XwaylandShellV1Global,
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
wp_presentation::WpPresentationGlobal,
wp_viewporter::WpViewporterGlobal,
@ -152,6 +153,7 @@ impl Globals {
add_singleton!(WpViewporterGlobal);
add_singleton!(WpFractionalScaleManagerV1Global);
add_singleton!(ZwpPointerConstraintsV1Global);
add_singleton!(XwaylandShellV1Global);
}
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {

View file

@ -5,6 +5,7 @@ pub mod wp_fractional_scale_v1;
pub mod wp_viewport;
pub mod x_surface;
pub mod xdg_surface;
pub mod xwayland_shell_v1;
pub mod zwlr_layer_surface_v1;
pub mod zwp_idle_inhibitor_v1;
@ -50,6 +51,7 @@ use {
},
wire::{wl_surface::*, WlOutputId, WlSurfaceId, ZwpIdleInhibitorV1Id},
xkbcommon::ModifierState,
xwayland::XWaylandEvent,
},
ahash::AHashMap,
std::{
@ -258,6 +260,7 @@ pub struct WlSurface {
output: CloneCell<Rc<OutputNode>>,
fractional_scale: CloneCell<Option<Rc<WpFractionalScaleV1>>>,
pub constraints: SmallMap<SeatId, Rc<SeatConstraint>, 1>,
xwayland_serial: Cell<Option<u64>>,
}
impl Debug for WlSurface {
@ -349,6 +352,7 @@ struct PendingState {
dst_size: Cell<Option<Option<(i32, i32)>>>,
scale: Cell<Option<i32>>,
transform: Cell<Option<Transform>>,
xwayland_serial: Cell<Option<u64>>,
}
#[derive(Default)]
@ -400,6 +404,7 @@ impl WlSurface {
output: CloneCell::new(client.state.dummy_output.get().unwrap()),
fractional_scale: Default::default(),
constraints: Default::default(),
xwayland_serial: Default::default(),
}
}
@ -410,6 +415,7 @@ impl WlSurface {
let xsurface = Rc::new(XSurface {
surface: self.clone(),
xwindow: Default::default(),
xwayland_surface: Default::default(),
tracker: Default::default(),
});
track!(self.client, xsurface);
@ -449,6 +455,10 @@ impl WlSurface {
self.toplevel.get()
}
pub fn xwayland_serial(&self) -> Option<u64> {
self.xwayland_serial.get()
}
fn set_absolute_position(&self, x1: i32, y1: i32) {
self.buffer_abs_pos
.set(self.buffer_abs_pos.get().at_point(x1, y1));
@ -621,6 +631,11 @@ impl WlSurface {
buffer.send_release();
}
}
if let Some(xwayland_serial) = self.xwayland_serial.get() {
self.client
.surfaces_by_xwayland_serial
.remove(&xwayland_serial);
}
self.frame_requests.borrow_mut().clear();
self.toplevel.set(None);
self.client.remove_obj(self)?;
@ -856,6 +871,17 @@ impl WlSurface {
self.opaque_region.set(region);
}
}
if let Some(xwayland_serial) = self.pending.xwayland_serial.take() {
self.xwayland_serial.set(Some(xwayland_serial));
self.client
.surfaces_by_xwayland_serial
.set(xwayland_serial, self.clone());
self.client
.state
.xwayland
.queue
.push(XWaylandEvent::SurfaceSerialAssigned(self.id));
}
if self.need_extents_update.get() {
self.calculate_extents();
}

View file

@ -1,6 +1,9 @@
use {
crate::{
ifs::wl_surface::{x_surface::xwindow::Xwindow, SurfaceExt, WlSurface, WlSurfaceError},
ifs::wl_surface::{
x_surface::{xwayland_surface_v1::XwaylandSurfaceV1, xwindow::Xwindow},
SurfaceExt, WlSurface, WlSurfaceError,
},
leaks::Tracker,
tree::ToplevelNode,
utils::clonecell::CloneCell,
@ -9,11 +12,13 @@ use {
std::rc::Rc,
};
pub mod xwayland_surface_v1;
pub mod xwindow;
pub struct XSurface {
pub surface: Rc<WlSurface>,
pub xwindow: CloneCell<Option<Rc<Xwindow>>>,
pub xwayland_surface: CloneCell<Option<Rc<XwaylandSurfaceV1>>>,
pub tracker: Tracker<Self>,
}
@ -25,6 +30,9 @@ impl SurfaceExt for XSurface {
}
fn on_surface_destroy(&self) -> Result<(), WlSurfaceError> {
if self.xwayland_surface.get().is_some() {
return Err(WlSurfaceError::ReloObjectStillExists);
}
self.surface.unset_ext();
if let Some(xwindow) = self.xwindow.take() {
xwindow.tl_destroy();
@ -35,7 +43,10 @@ impl SurfaceExt for XSurface {
.state
.xwayland
.queue
.push(XWaylandEvent::SurfaceDestroyed(self.surface.id));
.push(XWaylandEvent::SurfaceDestroyed(
self.surface.id,
self.surface.xwayland_serial.get(),
));
}
Ok(())
}

View file

@ -0,0 +1,77 @@
use {
crate::{
client::{Client, ClientError},
ifs::wl_surface::{x_surface::XSurface, WlSurfaceError},
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{xwayland_surface_v1::*, XwaylandSurfaceV1Id},
},
std::rc::Rc,
thiserror::Error,
};
pub struct XwaylandSurfaceV1 {
pub id: XwaylandSurfaceV1Id,
pub client: Rc<Client>,
pub x: Rc<XSurface>,
pub tracker: Tracker<Self>,
}
impl XwaylandSurfaceV1 {
fn set_serial(&self, parser: MsgParser<'_, '_>) -> Result<(), XwaylandSurfaceV1Error> {
let req: SetSerial = self.client.parse(self, parser)?;
if self.x.surface.xwayland_serial.get().is_some() {
return Err(XwaylandSurfaceV1Error::SerialAlreadySet);
}
let serial = req.serial_lo as u64 | ((req.serial_hi as u64) << 32);
if self.client.last_xwayland_serial.get() >= serial {
return Err(XwaylandSurfaceV1Error::NonMonotonicSerial);
}
self.client.last_xwayland_serial.set(serial);
self.x.surface.pending.xwayland_serial.set(Some(serial));
Ok(())
}
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), XwaylandSurfaceV1Error> {
let _req: Destroy = self.client.parse(self, parser)?;
self.x.xwayland_surface.set(None);
self.client.remove_obj(self)?;
Ok(())
}
}
object_base! {
XwaylandSurfaceV1;
SET_SERIAL => set_serial,
DESTROY => destroy,
}
impl Object for XwaylandSurfaceV1 {
fn num_requests(&self) -> u32 {
DESTROY + 1
}
fn break_loops(&self) {
self.x.xwayland_surface.set(None);
}
}
simple_add_obj!(XwaylandSurfaceV1);
#[derive(Debug, Error)]
pub enum XwaylandSurfaceV1Error {
#[error("The serial for this surface is already set")]
SerialAlreadySet,
#[error("The serial is not larger than the previously used serial")]
NonMonotonicSerial,
#[error(transparent)]
WlSurfaceError(#[from] WlSurfaceError),
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(XwaylandSurfaceV1Error, MsgParserError);
efrom!(XwaylandSurfaceV1Error, ClientError);

View file

@ -117,6 +117,7 @@ pub struct XwindowData {
pub window_id: u32,
pub client: Rc<Client>,
pub surface_id: Cell<Option<WlSurfaceId>>,
pub surface_serial: Cell<Option<u64>>,
pub window: CloneCell<Option<Rc<Xwindow>>>,
pub info: XwindowInfo,
pub children: CopyHashMap<u32, Rc<XwindowData>>,
@ -152,6 +153,7 @@ impl XwindowData {
window_id: event.window,
client: client.clone(),
surface_id: Cell::new(None),
surface_serial: Cell::new(None),
window: Default::default(),
info: XwindowInfo {
override_redirect: Cell::new(event.override_redirect != 0),

View file

@ -0,0 +1,120 @@
use {
crate::{
client::{Client, ClientError},
globals::{Global, GlobalName},
ifs::wl_surface::{x_surface::xwayland_surface_v1::XwaylandSurfaceV1, WlSurfaceError},
leaks::Tracker,
object::Object,
utils::buffd::{MsgParser, MsgParserError},
wire::{xwayland_shell_v1::*, WlSurfaceId, XwaylandShellV1Id},
},
std::rc::Rc,
thiserror::Error,
};
pub struct XwaylandShellV1Global {
name: GlobalName,
}
pub struct XwaylandShellV1 {
id: XwaylandShellV1Id,
client: Rc<Client>,
pub version: u32,
pub tracker: Tracker<Self>,
}
impl XwaylandShellV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}
fn bind_(
self: Rc<Self>,
id: XwaylandShellV1Id,
client: &Rc<Client>,
version: u32,
) -> Result<(), XwaylandShellV1Error> {
let obj = Rc::new(XwaylandShellV1 {
id,
client: client.clone(),
version,
tracker: Default::default(),
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}
impl XwaylandShellV1 {
fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), XwaylandShellV1Error> {
let _req: Destroy = self.client.parse(self, parser)?;
self.client.remove_obj(self)?;
Ok(())
}
fn get_xwayland_surface(&self, parser: MsgParser<'_, '_>) -> Result<(), XwaylandShellV1Error> {
let req: GetXwaylandSurface = self.client.parse(self, parser)?;
let surface = self.client.lookup(req.surface)?;
let xsurface = surface.get_xsurface()?;
if xsurface.xwayland_surface.get().is_some() {
return Err(XwaylandShellV1Error::AlreadyAttached(surface.id));
}
let xws = Rc::new(XwaylandSurfaceV1 {
id: req.id,
client: self.client.clone(),
x: xsurface,
tracker: Default::default(),
});
track!(self.client, xws);
xws.x.xwayland_surface.set(Some(xws.clone()));
self.client.add_client_obj(&xws)?;
Ok(())
}
}
global_base!(XwaylandShellV1Global, XwaylandShellV1, XwaylandShellV1Error);
impl Global for XwaylandShellV1Global {
fn singleton(&self) -> bool {
true
}
fn version(&self) -> u32 {
1
}
fn xwayland_only(&self) -> bool {
true
}
}
simple_add_global!(XwaylandShellV1Global);
object_base! {
XwaylandShellV1;
DESTROY => destroy,
GET_XWAYLAND_SURFACE => get_xwayland_surface,
}
impl Object for XwaylandShellV1 {
fn num_requests(&self) -> u32 {
GET_XWAYLAND_SURFACE + 1
}
}
simple_add_obj!(XwaylandShellV1);
#[derive(Debug, Error)]
pub enum XwaylandShellV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
#[error("Parsing failed")]
MsgParserError(#[source] Box<MsgParserError>),
#[error("The `wl_surface` {0} already has an extension object")]
AlreadyAttached(WlSurfaceId),
#[error(transparent)]
WlSurfaceError(#[from] WlSurfaceError),
}
efrom!(XwaylandShellV1Error, ClientError);
efrom!(XwaylandShellV1Error, MsgParserError);

View file

@ -271,7 +271,8 @@ async fn log_xwayland(state: Rc<State>, stderr: OwnedFd) {
pub enum XWaylandEvent {
SurfaceCreated(WlSurfaceId),
SurfaceDestroyed(WlSurfaceId),
SurfaceSerialAssigned(WlSurfaceId),
SurfaceDestroyed(WlSurfaceId, Option<u64>),
Configure(Rc<Xwindow>),
Activate(Rc<XwindowData>),
ActivateRoot,

View file

@ -124,6 +124,7 @@ atoms! {
WINDOW,
_WL_SELECTION,
WL_SURFACE_ID,
WL_SURFACE_SERIAL,
WM_CHANGE_STATE,
WM_DELETE_WINDOW,
WM_HINTS,
@ -236,6 +237,8 @@ pub struct Wm {
client: Rc<Client>,
windows: AHashMap<u32, Rc<XwindowData>>,
windows_by_surface_id: AHashMap<WlSurfaceId, Rc<XwindowData>>,
windows_by_surface_serial: AHashMap<u64, Rc<XwindowData>>,
last_surface_serial: u64,
focus_window: Option<Rc<XwindowData>>,
last_input_serial: u64,
atom_cache: AHashMap<String, u32>,
@ -514,6 +517,8 @@ impl Wm {
client,
windows: Default::default(),
windows_by_surface_id: Default::default(),
windows_by_surface_serial: Default::default(),
last_surface_serial: 0,
focus_window: Default::default(),
last_input_serial: 0,
atom_cache: Default::default(),
@ -592,8 +597,13 @@ impl Wm {
XWaylandEvent::SurfaceCreated(event) => {
self.handle_xwayland_surface_created(event).await
}
XWaylandEvent::SurfaceSerialAssigned(event) => {
self.handle_xwayland_surface_serial_assigned(event).await
}
XWaylandEvent::Configure(event) => self.handle_xwayland_configure(event).await,
XWaylandEvent::SurfaceDestroyed(event) => self.handle_xwayland_surface_destroyed(event),
XWaylandEvent::SurfaceDestroyed(surface_id, serial) => {
self.handle_xwayland_surface_destroyed(surface_id, serial)
}
XWaylandEvent::Activate(window) => {
self.activate_window(Some(&window), Initiator::Wayland)
.await
@ -1433,8 +1443,27 @@ impl Wm {
self.create_window(&data, surface).await;
}
fn handle_xwayland_surface_destroyed(&mut self, surface: WlSurfaceId) {
async fn handle_xwayland_surface_serial_assigned(&mut self, surface: WlSurfaceId) {
let surface = match self.client.lookup(surface) {
Ok(s) => s,
_ => return,
};
let serial = match surface.xwayland_serial() {
Some(s) => s,
_ => return,
};
let data = match self.windows_by_surface_serial.get(&serial) {
Some(w) => w.clone(),
_ => return,
};
self.create_window(&data, surface).await;
}
fn handle_xwayland_surface_destroyed(&mut self, surface: WlSurfaceId, serial: Option<u64>) {
self.windows_by_surface_id.remove(&surface);
if let Some(serial) = serial {
self.windows_by_surface_serial.remove(&serial);
}
}
async fn handle_event(&mut self, event: &Event) {
@ -1895,6 +1924,9 @@ impl Wm {
if let Some(sid) = data.surface_id.take() {
self.windows_by_surface_id.remove(&sid);
}
if let Some(serial) = data.surface_serial.take() {
self.windows_by_surface_serial.remove(&serial);
}
if let Some(window) = data.window.take() {
window.destroy();
}
@ -1961,6 +1993,8 @@ impl Wm {
self.handle_wm_change_state(&event).await?;
} else if event.ty == self.atoms._NET_WM_MOVERESIZE {
self.handle_net_wm_moveresize(&event).await?;
} else if event.ty == self.atoms.WL_SURFACE_SERIAL {
self.handle_wl_surface_serial(&event).await?;
}
Ok(())
}
@ -2334,6 +2368,37 @@ impl Wm {
Ok(())
}
async fn handle_wl_surface_serial(
&mut self,
event: &ClientMessage<'_>,
) -> Result<(), XWaylandError> {
let serial = event.data[0] as u64 | ((event.data[1] as u64) << 32);
if serial <= self.last_surface_serial {
log::error!(
"Surface serial is not monotonic: {} <= {}",
serial,
self.last_surface_serial
);
return Ok(());
}
self.last_surface_serial = serial;
let data = match self.windows.get(&event.window) {
Some(d) => d.clone(),
_ => return Ok(()),
};
if let Some(old) = data.surface_serial.replace(Some(serial)) {
self.windows_by_surface_serial.remove(&old);
}
if let Some(old) = data.window.take() {
old.break_loops();
}
self.windows_by_surface_serial.insert(serial, data.clone());
if let Some(surface) = self.client.surfaces_by_xwayland_serial.get(&serial) {
self.create_window(&data, surface).await;
}
Ok(())
}
async fn handle_wl_surface_id(
&mut self,
event: &ClientMessage<'_>,