wayland: implement xwayland_shell_v1
This commit is contained in:
parent
1f64fefc86
commit
335677bbcd
11 changed files with 332 additions and 7 deletions
|
|
@ -2,14 +2,14 @@ use {
|
||||||
crate::{
|
crate::{
|
||||||
async_engine::SpawnedFuture,
|
async_engine::SpawnedFuture,
|
||||||
client::{error::LookupError, objects::Objects},
|
client::{error::LookupError, objects::Objects},
|
||||||
ifs::{wl_display::WlDisplay, wl_registry::WlRegistry},
|
ifs::{wl_display::WlDisplay, wl_registry::WlRegistry, wl_surface::WlSurface},
|
||||||
leaks::Tracker,
|
leaks::Tracker,
|
||||||
object::{Interface, Object, ObjectId, WL_DISPLAY_ID},
|
object::{Interface, Object, ObjectId, WL_DISPLAY_ID},
|
||||||
state::State,
|
state::State,
|
||||||
utils::{
|
utils::{
|
||||||
asyncevent::AsyncEvent,
|
asyncevent::AsyncEvent,
|
||||||
buffd::{MsgFormatter, MsgParser, MsgParserError, OutBufferSwapchain},
|
buffd::{MsgFormatter, MsgParser, MsgParserError, OutBufferSwapchain},
|
||||||
copyhashmap::Locked,
|
copyhashmap::{CopyHashMap, Locked},
|
||||||
errorfmt::ErrorFmt,
|
errorfmt::ErrorFmt,
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
trim::AsciiTrim,
|
trim::AsciiTrim,
|
||||||
|
|
@ -145,6 +145,8 @@ impl Clients {
|
||||||
pid_info: get_pid_info(uid, pid),
|
pid_info: get_pid_info(uid, pid),
|
||||||
serials: Default::default(),
|
serials: Default::default(),
|
||||||
symmetric_delete: Cell::new(false),
|
symmetric_delete: Cell::new(false),
|
||||||
|
last_xwayland_serial: Cell::new(0),
|
||||||
|
surfaces_by_xwayland_serial: Default::default(),
|
||||||
});
|
});
|
||||||
track!(data, data);
|
track!(data, data);
|
||||||
let display = Rc::new(WlDisplay::new(&data));
|
let display = Rc::new(WlDisplay::new(&data));
|
||||||
|
|
@ -214,6 +216,7 @@ impl Drop for ClientHolder {
|
||||||
self.data.objects.destroy();
|
self.data.objects.destroy();
|
||||||
self.data.flush_request.clear();
|
self.data.flush_request.clear();
|
||||||
self.data.shutdown.clear();
|
self.data.shutdown.clear();
|
||||||
|
self.data.surfaces_by_xwayland_serial.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,6 +254,8 @@ pub struct Client {
|
||||||
pub pid_info: PidInfo,
|
pub pid_info: PidInfo,
|
||||||
pub serials: RefCell<VecDeque<SerialRange>>,
|
pub serials: RefCell<VecDeque<SerialRange>>,
|
||||||
pub symmetric_delete: Cell<bool>,
|
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;
|
pub const NUM_CACHED_SERIAL_RANGES: usize = 64;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ use {
|
||||||
},
|
},
|
||||||
wl_shm::WlShmGlobal,
|
wl_shm::WlShmGlobal,
|
||||||
wl_subcompositor::WlSubcompositorGlobal,
|
wl_subcompositor::WlSubcompositorGlobal,
|
||||||
|
wl_surface::xwayland_shell_v1::XwaylandShellV1Global,
|
||||||
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
|
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
|
||||||
wp_presentation::WpPresentationGlobal,
|
wp_presentation::WpPresentationGlobal,
|
||||||
wp_viewporter::WpViewporterGlobal,
|
wp_viewporter::WpViewporterGlobal,
|
||||||
|
|
@ -152,6 +153,7 @@ impl Globals {
|
||||||
add_singleton!(WpViewporterGlobal);
|
add_singleton!(WpViewporterGlobal);
|
||||||
add_singleton!(WpFractionalScaleManagerV1Global);
|
add_singleton!(WpFractionalScaleManagerV1Global);
|
||||||
add_singleton!(ZwpPointerConstraintsV1Global);
|
add_singleton!(ZwpPointerConstraintsV1Global);
|
||||||
|
add_singleton!(XwaylandShellV1Global);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ pub mod wp_fractional_scale_v1;
|
||||||
pub mod wp_viewport;
|
pub mod wp_viewport;
|
||||||
pub mod x_surface;
|
pub mod x_surface;
|
||||||
pub mod xdg_surface;
|
pub mod xdg_surface;
|
||||||
|
pub mod xwayland_shell_v1;
|
||||||
pub mod zwlr_layer_surface_v1;
|
pub mod zwlr_layer_surface_v1;
|
||||||
pub mod zwp_idle_inhibitor_v1;
|
pub mod zwp_idle_inhibitor_v1;
|
||||||
|
|
||||||
|
|
@ -50,6 +51,7 @@ use {
|
||||||
},
|
},
|
||||||
wire::{wl_surface::*, WlOutputId, WlSurfaceId, ZwpIdleInhibitorV1Id},
|
wire::{wl_surface::*, WlOutputId, WlSurfaceId, ZwpIdleInhibitorV1Id},
|
||||||
xkbcommon::ModifierState,
|
xkbcommon::ModifierState,
|
||||||
|
xwayland::XWaylandEvent,
|
||||||
},
|
},
|
||||||
ahash::AHashMap,
|
ahash::AHashMap,
|
||||||
std::{
|
std::{
|
||||||
|
|
@ -258,6 +260,7 @@ pub struct WlSurface {
|
||||||
output: CloneCell<Rc<OutputNode>>,
|
output: CloneCell<Rc<OutputNode>>,
|
||||||
fractional_scale: CloneCell<Option<Rc<WpFractionalScaleV1>>>,
|
fractional_scale: CloneCell<Option<Rc<WpFractionalScaleV1>>>,
|
||||||
pub constraints: SmallMap<SeatId, Rc<SeatConstraint>, 1>,
|
pub constraints: SmallMap<SeatId, Rc<SeatConstraint>, 1>,
|
||||||
|
xwayland_serial: Cell<Option<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for WlSurface {
|
impl Debug for WlSurface {
|
||||||
|
|
@ -349,6 +352,7 @@ struct PendingState {
|
||||||
dst_size: Cell<Option<Option<(i32, i32)>>>,
|
dst_size: Cell<Option<Option<(i32, i32)>>>,
|
||||||
scale: Cell<Option<i32>>,
|
scale: Cell<Option<i32>>,
|
||||||
transform: Cell<Option<Transform>>,
|
transform: Cell<Option<Transform>>,
|
||||||
|
xwayland_serial: Cell<Option<u64>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -400,6 +404,7 @@ impl WlSurface {
|
||||||
output: CloneCell::new(client.state.dummy_output.get().unwrap()),
|
output: CloneCell::new(client.state.dummy_output.get().unwrap()),
|
||||||
fractional_scale: Default::default(),
|
fractional_scale: Default::default(),
|
||||||
constraints: Default::default(),
|
constraints: Default::default(),
|
||||||
|
xwayland_serial: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -410,6 +415,7 @@ impl WlSurface {
|
||||||
let xsurface = Rc::new(XSurface {
|
let xsurface = Rc::new(XSurface {
|
||||||
surface: self.clone(),
|
surface: self.clone(),
|
||||||
xwindow: Default::default(),
|
xwindow: Default::default(),
|
||||||
|
xwayland_surface: Default::default(),
|
||||||
tracker: Default::default(),
|
tracker: Default::default(),
|
||||||
});
|
});
|
||||||
track!(self.client, xsurface);
|
track!(self.client, xsurface);
|
||||||
|
|
@ -449,6 +455,10 @@ impl WlSurface {
|
||||||
self.toplevel.get()
|
self.toplevel.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn xwayland_serial(&self) -> Option<u64> {
|
||||||
|
self.xwayland_serial.get()
|
||||||
|
}
|
||||||
|
|
||||||
fn set_absolute_position(&self, x1: i32, y1: i32) {
|
fn set_absolute_position(&self, x1: i32, y1: i32) {
|
||||||
self.buffer_abs_pos
|
self.buffer_abs_pos
|
||||||
.set(self.buffer_abs_pos.get().at_point(x1, y1));
|
.set(self.buffer_abs_pos.get().at_point(x1, y1));
|
||||||
|
|
@ -621,6 +631,11 @@ impl WlSurface {
|
||||||
buffer.send_release();
|
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.frame_requests.borrow_mut().clear();
|
||||||
self.toplevel.set(None);
|
self.toplevel.set(None);
|
||||||
self.client.remove_obj(self)?;
|
self.client.remove_obj(self)?;
|
||||||
|
|
@ -856,6 +871,17 @@ impl WlSurface {
|
||||||
self.opaque_region.set(region);
|
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() {
|
if self.need_extents_update.get() {
|
||||||
self.calculate_extents();
|
self.calculate_extents();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
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,
|
leaks::Tracker,
|
||||||
tree::ToplevelNode,
|
tree::ToplevelNode,
|
||||||
utils::clonecell::CloneCell,
|
utils::clonecell::CloneCell,
|
||||||
|
|
@ -9,11 +12,13 @@ use {
|
||||||
std::rc::Rc,
|
std::rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub mod xwayland_surface_v1;
|
||||||
pub mod xwindow;
|
pub mod xwindow;
|
||||||
|
|
||||||
pub struct XSurface {
|
pub struct XSurface {
|
||||||
pub surface: Rc<WlSurface>,
|
pub surface: Rc<WlSurface>,
|
||||||
pub xwindow: CloneCell<Option<Rc<Xwindow>>>,
|
pub xwindow: CloneCell<Option<Rc<Xwindow>>>,
|
||||||
|
pub xwayland_surface: CloneCell<Option<Rc<XwaylandSurfaceV1>>>,
|
||||||
pub tracker: Tracker<Self>,
|
pub tracker: Tracker<Self>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -25,6 +30,9 @@ impl SurfaceExt for XSurface {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_surface_destroy(&self) -> Result<(), WlSurfaceError> {
|
fn on_surface_destroy(&self) -> Result<(), WlSurfaceError> {
|
||||||
|
if self.xwayland_surface.get().is_some() {
|
||||||
|
return Err(WlSurfaceError::ReloObjectStillExists);
|
||||||
|
}
|
||||||
self.surface.unset_ext();
|
self.surface.unset_ext();
|
||||||
if let Some(xwindow) = self.xwindow.take() {
|
if let Some(xwindow) = self.xwindow.take() {
|
||||||
xwindow.tl_destroy();
|
xwindow.tl_destroy();
|
||||||
|
|
@ -35,7 +43,10 @@ impl SurfaceExt for XSurface {
|
||||||
.state
|
.state
|
||||||
.xwayland
|
.xwayland
|
||||||
.queue
|
.queue
|
||||||
.push(XWaylandEvent::SurfaceDestroyed(self.surface.id));
|
.push(XWaylandEvent::SurfaceDestroyed(
|
||||||
|
self.surface.id,
|
||||||
|
self.surface.xwayland_serial.get(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
77
src/ifs/wl_surface/x_surface/xwayland_surface_v1.rs
Normal file
77
src/ifs/wl_surface/x_surface/xwayland_surface_v1.rs
Normal 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);
|
||||||
|
|
@ -117,6 +117,7 @@ pub struct XwindowData {
|
||||||
pub window_id: u32,
|
pub window_id: u32,
|
||||||
pub client: Rc<Client>,
|
pub client: Rc<Client>,
|
||||||
pub surface_id: Cell<Option<WlSurfaceId>>,
|
pub surface_id: Cell<Option<WlSurfaceId>>,
|
||||||
|
pub surface_serial: Cell<Option<u64>>,
|
||||||
pub window: CloneCell<Option<Rc<Xwindow>>>,
|
pub window: CloneCell<Option<Rc<Xwindow>>>,
|
||||||
pub info: XwindowInfo,
|
pub info: XwindowInfo,
|
||||||
pub children: CopyHashMap<u32, Rc<XwindowData>>,
|
pub children: CopyHashMap<u32, Rc<XwindowData>>,
|
||||||
|
|
@ -152,6 +153,7 @@ impl XwindowData {
|
||||||
window_id: event.window,
|
window_id: event.window,
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
surface_id: Cell::new(None),
|
surface_id: Cell::new(None),
|
||||||
|
surface_serial: Cell::new(None),
|
||||||
window: Default::default(),
|
window: Default::default(),
|
||||||
info: XwindowInfo {
|
info: XwindowInfo {
|
||||||
override_redirect: Cell::new(event.override_redirect != 0),
|
override_redirect: Cell::new(event.override_redirect != 0),
|
||||||
|
|
|
||||||
120
src/ifs/wl_surface/xwayland_shell_v1.rs
Normal file
120
src/ifs/wl_surface/xwayland_shell_v1.rs
Normal 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);
|
||||||
|
|
@ -271,7 +271,8 @@ async fn log_xwayland(state: Rc<State>, stderr: OwnedFd) {
|
||||||
|
|
||||||
pub enum XWaylandEvent {
|
pub enum XWaylandEvent {
|
||||||
SurfaceCreated(WlSurfaceId),
|
SurfaceCreated(WlSurfaceId),
|
||||||
SurfaceDestroyed(WlSurfaceId),
|
SurfaceSerialAssigned(WlSurfaceId),
|
||||||
|
SurfaceDestroyed(WlSurfaceId, Option<u64>),
|
||||||
Configure(Rc<Xwindow>),
|
Configure(Rc<Xwindow>),
|
||||||
Activate(Rc<XwindowData>),
|
Activate(Rc<XwindowData>),
|
||||||
ActivateRoot,
|
ActivateRoot,
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,7 @@ atoms! {
|
||||||
WINDOW,
|
WINDOW,
|
||||||
_WL_SELECTION,
|
_WL_SELECTION,
|
||||||
WL_SURFACE_ID,
|
WL_SURFACE_ID,
|
||||||
|
WL_SURFACE_SERIAL,
|
||||||
WM_CHANGE_STATE,
|
WM_CHANGE_STATE,
|
||||||
WM_DELETE_WINDOW,
|
WM_DELETE_WINDOW,
|
||||||
WM_HINTS,
|
WM_HINTS,
|
||||||
|
|
@ -236,6 +237,8 @@ pub struct Wm {
|
||||||
client: Rc<Client>,
|
client: Rc<Client>,
|
||||||
windows: AHashMap<u32, Rc<XwindowData>>,
|
windows: AHashMap<u32, Rc<XwindowData>>,
|
||||||
windows_by_surface_id: AHashMap<WlSurfaceId, 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>>,
|
focus_window: Option<Rc<XwindowData>>,
|
||||||
last_input_serial: u64,
|
last_input_serial: u64,
|
||||||
atom_cache: AHashMap<String, u32>,
|
atom_cache: AHashMap<String, u32>,
|
||||||
|
|
@ -514,6 +517,8 @@ impl Wm {
|
||||||
client,
|
client,
|
||||||
windows: Default::default(),
|
windows: Default::default(),
|
||||||
windows_by_surface_id: Default::default(),
|
windows_by_surface_id: Default::default(),
|
||||||
|
windows_by_surface_serial: Default::default(),
|
||||||
|
last_surface_serial: 0,
|
||||||
focus_window: Default::default(),
|
focus_window: Default::default(),
|
||||||
last_input_serial: 0,
|
last_input_serial: 0,
|
||||||
atom_cache: Default::default(),
|
atom_cache: Default::default(),
|
||||||
|
|
@ -592,8 +597,13 @@ impl Wm {
|
||||||
XWaylandEvent::SurfaceCreated(event) => {
|
XWaylandEvent::SurfaceCreated(event) => {
|
||||||
self.handle_xwayland_surface_created(event).await
|
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::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) => {
|
XWaylandEvent::Activate(window) => {
|
||||||
self.activate_window(Some(&window), Initiator::Wayland)
|
self.activate_window(Some(&window), Initiator::Wayland)
|
||||||
.await
|
.await
|
||||||
|
|
@ -1433,8 +1443,27 @@ impl Wm {
|
||||||
self.create_window(&data, surface).await;
|
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);
|
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) {
|
async fn handle_event(&mut self, event: &Event) {
|
||||||
|
|
@ -1895,6 +1924,9 @@ impl Wm {
|
||||||
if let Some(sid) = data.surface_id.take() {
|
if let Some(sid) = data.surface_id.take() {
|
||||||
self.windows_by_surface_id.remove(&sid);
|
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() {
|
if let Some(window) = data.window.take() {
|
||||||
window.destroy();
|
window.destroy();
|
||||||
}
|
}
|
||||||
|
|
@ -1961,6 +1993,8 @@ impl Wm {
|
||||||
self.handle_wm_change_state(&event).await?;
|
self.handle_wm_change_state(&event).await?;
|
||||||
} else if event.ty == self.atoms._NET_WM_MOVERESIZE {
|
} else if event.ty == self.atoms._NET_WM_MOVERESIZE {
|
||||||
self.handle_net_wm_moveresize(&event).await?;
|
self.handle_net_wm_moveresize(&event).await?;
|
||||||
|
} else if event.ty == self.atoms.WL_SURFACE_SERIAL {
|
||||||
|
self.handle_wl_surface_serial(&event).await?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -2334,6 +2368,37 @@ impl Wm {
|
||||||
Ok(())
|
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(
|
async fn handle_wl_surface_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
event: &ClientMessage<'_>,
|
event: &ClientMessage<'_>,
|
||||||
|
|
|
||||||
8
wire/xwayland_shell_v1.txt
Normal file
8
wire/xwayland_shell_v1.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# requests
|
||||||
|
|
||||||
|
msg destroy = 0 { }
|
||||||
|
|
||||||
|
msg get_xwayland_surface = 1 {
|
||||||
|
id: id(xwayland_surface_v1),
|
||||||
|
surface: id(wl_surface),
|
||||||
|
}
|
||||||
8
wire/xwayland_surface_v1.txt
Normal file
8
wire/xwayland_surface_v1.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# requests
|
||||||
|
|
||||||
|
msg set_serial = 0 {
|
||||||
|
serial_lo: u32,
|
||||||
|
serial_hi: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
msg destroy = 1 { }
|
||||||
Loading…
Add table
Add a link
Reference in a new issue