From 6193569596a85c16266bde0bc83b2e05ed8252a8 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sun, 16 Oct 2022 20:53:59 +0200 Subject: [PATCH] xwayland: add x-surface indirection --- src/ifs/wl_surface.rs | 29 ++++++- src/ifs/wl_surface/x_surface.rs | 53 ++++++++++++ src/ifs/wl_surface/{ => x_surface}/xwindow.rs | 81 +++++++------------ src/tree/walker.rs | 2 +- src/xwayland.rs | 2 +- src/xwayland/xwm.rs | 22 ++--- 6 files changed, 123 insertions(+), 66 deletions(-) create mode 100644 src/ifs/wl_surface/x_surface.rs rename src/ifs/wl_surface/{ => x_surface}/xwindow.rs (87%) diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 8c55c595..0c8ebb26 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -3,8 +3,8 @@ pub mod ext_session_lock_surface_v1; pub mod wl_subsurface; pub mod wp_fractional_scale_v1; pub mod wp_viewport; +pub mod x_surface; pub mod xdg_surface; -pub mod xwindow; pub mod zwlr_layer_surface_v1; pub mod zwp_idle_inhibitor_v1; @@ -27,7 +27,8 @@ use { wl_surface::{ cursor::CursorSurface, wl_subsurface::WlSubsurface, wp_fractional_scale_v1::WpFractionalScaleV1, wp_viewport::WpViewport, - xdg_surface::XdgSurfaceError, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error, + x_surface::XSurface, xdg_surface::XdgSurfaceError, + zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error, }, wp_presentation_feedback::WpPresentationFeedback, }, @@ -291,6 +292,10 @@ trait SurfaceExt { true } + fn is_none(&self) -> bool { + !self.is_some() + } + fn on_surface_destroy(&self) -> Result<(), WlSurfaceError> { if self.is_some() { Err(WlSurfaceError::ReloObjectStillExists) @@ -318,6 +323,10 @@ trait SurfaceExt { fn focus_node(&self) -> Option> { None } + + fn into_xsurface(self: Rc) -> Option> { + None + } } pub struct NoneSurfaceExt; @@ -394,6 +403,22 @@ impl WlSurface { } } + fn get_xsurface(self: &Rc) -> Result, WlSurfaceError> { + self.set_role(SurfaceRole::XSurface)?; + let mut ext = self.ext.get(); + if ext.is_none() { + let xsurface = Rc::new(XSurface { + surface: self.clone(), + xwindow: Default::default(), + tracker: Default::default(), + }); + track!(self.client, xsurface); + self.ext.set(xsurface.clone()); + ext = xsurface; + } + Ok(ext.into_xsurface().unwrap()) + } + pub fn set_output(&self, output: &Rc) { let old = self.output.set(output.clone()); if old.id == output.id { diff --git a/src/ifs/wl_surface/x_surface.rs b/src/ifs/wl_surface/x_surface.rs new file mode 100644 index 00000000..76e6d342 --- /dev/null +++ b/src/ifs/wl_surface/x_surface.rs @@ -0,0 +1,53 @@ +use { + crate::{ + ifs::wl_surface::{x_surface::xwindow::Xwindow, SurfaceExt, WlSurface, WlSurfaceError}, + leaks::Tracker, + tree::ToplevelNode, + utils::clonecell::CloneCell, + xwayland::XWaylandEvent, + }, + std::rc::Rc, +}; + +pub mod xwindow; + +pub struct XSurface { + pub surface: Rc, + pub xwindow: CloneCell>>, + pub tracker: Tracker, +} + +impl SurfaceExt for XSurface { + fn post_commit(self: Rc) { + if let Some(xwindow) = self.xwindow.get() { + xwindow.map_status_changed(); + } + } + + fn on_surface_destroy(&self) -> Result<(), WlSurfaceError> { + self.surface.unset_ext(); + if let Some(xwindow) = self.xwindow.take() { + xwindow.tl_destroy(); + xwindow.data.window.set(None); + xwindow.data.surface_id.set(None); + xwindow + .data + .state + .xwayland + .queue + .push(XWaylandEvent::SurfaceDestroyed(self.surface.id)); + } + Ok(()) + } + + fn extents_changed(&self) { + if let Some(xwindow) = self.xwindow.get() { + xwindow.toplevel_data.pos.set(self.surface.extents.get()); + xwindow.tl_extents_changed(); + } + } + + fn into_xsurface(self: Rc) -> Option> { + Some(self) + } +} diff --git a/src/ifs/wl_surface/xwindow.rs b/src/ifs/wl_surface/x_surface/xwindow.rs similarity index 87% rename from src/ifs/wl_surface/xwindow.rs rename to src/ifs/wl_surface/x_surface/xwindow.rs index 97440e5f..48064690 100644 --- a/src/ifs/wl_surface/xwindow.rs +++ b/src/ifs/wl_surface/x_surface/xwindow.rs @@ -5,7 +5,7 @@ use { fixed::Fixed, ifs::{ wl_seat::{NodeSeatState, SeatId, WlSeatGlobal}, - wl_surface::{SurfaceExt, SurfaceRole, WlSurface, WlSurfaceError}, + wl_surface::{x_surface::XSurface, WlSurface, WlSurfaceError}, }, rect::Rect, render::Renderer, @@ -132,7 +132,7 @@ pub struct Xwindow { pub id: XwindowId, pub seat_state: NodeSeatState, pub data: Rc, - pub surface: Rc, + pub x: Rc, pub display_link: RefCell>>>, pub toplevel_data: ToplevelData, } @@ -196,21 +196,31 @@ pub enum Change { } impl Xwindow { - pub fn new(data: &Rc, surface: &Rc) -> Self { + pub fn install( + data: &Rc, + surface: &Rc, + ) -> Result, XWindowError> { + let xsurface = surface.get_xsurface()?; + if xsurface.xwindow.get().is_some() { + return Err(XWindowError::AlreadyAttached); + } let tld = ToplevelData::new( &data.state, data.info.title.borrow_mut().clone().unwrap_or_default(), Some(surface.client.clone()), ); tld.pos.set(surface.extents.get()); - Self { + let slf = Rc::new(Self { id: data.state.node_ids.next(), seat_state: Default::default(), data: data.clone(), - surface: surface.clone(), display_link: Default::default(), toplevel_data: tld, - } + x: xsurface, + }); + slf.x.xwindow.set(Some(slf.clone())); + slf.x.surface.set_toplevel(Some(slf.clone())); + Ok(slf) } pub fn destroy(&self) { @@ -220,17 +230,8 @@ impl Xwindow { pub fn break_loops(&self) { self.tl_destroy(); - self.surface.set_toplevel(None); - } - - pub fn install(self: &Rc) -> Result<(), XWindowError> { - self.surface.set_role(SurfaceRole::XSurface)?; - if self.surface.ext.get().is_some() { - return Err(XWindowError::AlreadyAttached); - } - self.surface.ext.set(self.clone()); - self.surface.set_toplevel(Some(self.clone())); - Ok(()) + self.x.surface.set_toplevel(None); + self.x.xwindow.set(None); } pub fn is_mapped(&self) -> bool { @@ -238,7 +239,7 @@ impl Xwindow { } pub fn may_be_mapped(&self) -> bool { - self.surface.buffer.get().is_some() && self.data.info.mapped.get() + self.x.surface.buffer.get().is_some() && self.data.info.mapped.get() } fn map_change(&self) -> Change { @@ -289,30 +290,6 @@ impl Xwindow { } } -impl SurfaceExt for Xwindow { - fn post_commit(self: Rc) { - self.map_status_changed(); - } - - fn on_surface_destroy(&self) -> Result<(), WlSurfaceError> { - self.tl_destroy(); - self.surface.unset_ext(); - self.data.window.set(None); - self.data.surface_id.set(None); - self.data - .state - .xwayland - .queue - .push(XWaylandEvent::SurfaceDestroyed(self.surface.id)); - Ok(()) - } - - fn extents_changed(&self) { - self.toplevel_data.pos.set(self.surface.extents.get()); - self.tl_extents_changed(); - } -} - impl Node for Xwindow { fn node_id(&self) -> NodeId { self.id.into() @@ -327,11 +304,11 @@ impl Node for Xwindow { } fn node_visit_children(&self, visitor: &mut dyn NodeVisitor) { - visitor.visit_surface(&self.surface); + visitor.visit_surface(&self.x.surface); } fn node_visible(&self) -> bool { - self.surface.visible.get() + self.x.surface.visible.get() } fn node_absolute_position(&self) -> Rect { @@ -343,10 +320,10 @@ impl Node for Xwindow { } fn node_find_tree_at(&self, x: i32, y: i32, tree: &mut Vec) -> FindTreeResult { - let rect = self.surface.buffer_abs_pos.get(); + let rect = self.x.surface.buffer_abs_pos.get(); if x < rect.width() && y < rect.height() { tree.push(FoundNode { - node: self.surface.clone(), + node: self.x.surface.clone(), x, y, }); @@ -356,7 +333,7 @@ impl Node for Xwindow { } fn node_render(&self, renderer: &mut Renderer, x: i32, y: i32) { - renderer.render_surface(&self.surface, x, y) + renderer.render_surface(&self.x.surface, x, y) } fn node_client(&self) -> Option> { @@ -398,11 +375,11 @@ impl ToplevelNode for Xwindow { } fn tl_focus_child(&self, _seat: SeatId) -> Option> { - Some(self.surface.clone()) + Some(self.x.surface.clone()) } fn tl_set_workspace_ext(self: Rc, ws: &Rc) { - self.surface.set_output(&ws.output.get()); + self.x.surface.set_output(&ws.output.get()); } fn tl_change_extents(self: Rc, rect: &Rect) { @@ -421,7 +398,7 @@ impl ToplevelNode for Xwindow { .push(XWaylandEvent::Configure(self.clone())); } if old.position() != rect.position() { - self.surface.set_absolute_position(rect.x1(), rect.y1()); + self.x.surface.set_absolute_position(rect.x1(), rect.y1()); } } } @@ -435,14 +412,14 @@ impl ToplevelNode for Xwindow { } fn tl_set_visible(&self, visible: bool) { - self.surface.set_visible(visible); + self.x.surface.set_visible(visible); self.seat_state.set_visible(self, visible); } fn tl_destroy(&self) { self.toplevel_data.destroy_node(self); self.display_link.borrow_mut().take(); - self.surface.destroy_node(); + self.x.surface.destroy_node(); } } diff --git a/src/tree/walker.rs b/src/tree/walker.rs index a14aedce..808cdd7d 100644 --- a/src/tree/walker.rs +++ b/src/tree/walker.rs @@ -2,8 +2,8 @@ use { crate::{ ifs::wl_surface::{ ext_session_lock_surface_v1::ExtSessionLockSurfaceV1, + x_surface::xwindow::Xwindow, xdg_surface::{xdg_popup::XdgPopup, xdg_toplevel::XdgToplevel}, - xwindow::Xwindow, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, WlSurface, }, diff --git a/src/xwayland.rs b/src/xwayland.rs index 54a19bbf..ad6f35c5 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -14,7 +14,7 @@ use { }, wl_seat::SeatId, wl_surface::{ - xwindow::{Xwindow, XwindowData}, + x_surface::xwindow::{Xwindow, XwindowData}, WlSurface, }, }, diff --git a/src/xwayland/xwm.rs b/src/xwayland/xwm.rs index 6bf63c11..80dab9c5 100644 --- a/src/xwayland/xwm.rs +++ b/src/xwayland/xwm.rs @@ -16,7 +16,7 @@ use { }, wl_seat::{SeatId, WlSeatGlobal}, wl_surface::{ - xwindow::{XInputModel, Xwindow, XwindowData}, + x_surface::xwindow::{XInputModel, Xwindow, XwindowData}, WlSurface, }, }, @@ -1374,14 +1374,16 @@ impl Wm { log::error!("The xwindow has already been constructed"); return; } - let window = Rc::new(Xwindow::new(data, &surface)); - if let Err(e) = window.install() { - log::error!( - "Could not attach the xwindow to the surface: {}", - ErrorFmt(e) - ); - return; - } + let window = match Xwindow::install(data, &surface) { + Ok(w) => w, + Err(e) => { + log::error!( + "Could not attach the xwindow to the surface: {}", + ErrorFmt(e) + ); + return; + } + }; data.window.set(Some(window.clone())); { self.load_window_wm_class(data).await; @@ -1766,7 +1768,7 @@ impl Wm { if prev_pid.is_some() && prev_pid == new_pid && revent.serial() >= self.last_input_serial - && w.surface.node_visible() + && w.x.surface.node_visible() { // log::info!("xwm ACCEPT"); focus_window = new_window;