diff --git a/src/globals.rs b/src/globals.rs index 53c1cdbc..4ba88519 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -22,6 +22,7 @@ use { wl_surface::xwayland_shell_v1::XwaylandShellV1Global, wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global, wp_presentation::WpPresentationGlobal, + wp_tearing_control_manager_v1::WpTearingControlManagerV1Global, wp_viewporter::WpViewporterGlobal, xdg_wm_base::XdgWmBaseGlobal, zwlr_layer_shell_v1::ZwlrLayerShellV1Global, @@ -154,6 +155,7 @@ impl Globals { add_singleton!(WpFractionalScaleManagerV1Global); add_singleton!(ZwpPointerConstraintsV1Global); add_singleton!(XwaylandShellV1Global); + add_singleton!(WpTearingControlManagerV1Global); } pub fn add_backend_singletons(&self, backend: &Rc) { diff --git a/src/ifs.rs b/src/ifs.rs index 037856d6..c3d5ab02 100644 --- a/src/ifs.rs +++ b/src/ifs.rs @@ -30,6 +30,7 @@ pub mod wl_surface; pub mod wp_fractional_scale_manager_v1; pub mod wp_presentation; pub mod wp_presentation_feedback; +pub mod wp_tearing_control_manager_v1; pub mod wp_viewporter; pub mod xdg_positioner; pub mod xdg_wm_base; diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 600f9d06..ce7b85e1 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -2,6 +2,7 @@ pub mod cursor; pub mod ext_session_lock_surface_v1; pub mod wl_subsurface; pub mod wp_fractional_scale_v1; +pub mod wp_tearing_control_v1; pub mod wp_viewport; pub mod x_surface; pub mod xdg_surface; @@ -27,7 +28,8 @@ use { }, wl_surface::{ cursor::CursorSurface, wl_subsurface::WlSubsurface, - wp_fractional_scale_v1::WpFractionalScaleV1, wp_viewport::WpViewport, + wp_fractional_scale_v1::WpFractionalScaleV1, + wp_tearing_control_v1::WpTearingControlV1, wp_viewport::WpViewport, x_surface::XSurface, xdg_surface::XdgSurfaceError, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1Error, }, @@ -261,6 +263,8 @@ pub struct WlSurface { fractional_scale: CloneCell>>, pub constraints: SmallMap, 1>, xwayland_serial: Cell>, + tearing_control: CloneCell>>, + tearing: Cell, } impl Debug for WlSurface { @@ -353,6 +357,7 @@ struct PendingState { scale: Cell>, transform: Cell>, xwayland_serial: Cell>, + tearing: Cell>, } #[derive(Default)] @@ -405,6 +410,8 @@ impl WlSurface { fractional_scale: Default::default(), constraints: Default::default(), xwayland_serial: Default::default(), + tearing_control: Default::default(), + tearing: Cell::new(false), } } @@ -871,6 +878,9 @@ impl WlSurface { self.opaque_region.set(region); } } + if let Some(tearing) = self.pending.tearing.take() { + self.tearing.set(tearing); + } if let Some(xwayland_serial) = self.pending.xwayland_serial.take() { self.xwayland_serial.set(Some(xwayland_serial)); self.client @@ -1080,6 +1090,7 @@ impl Object for WlSurface { self.presentation_feedback.borrow_mut().clear(); self.viewporter.take(); self.fractional_scale.take(); + self.tearing_control.take(); self.constraints.clear(); } } diff --git a/src/ifs/wl_surface/wp_tearing_control_v1.rs b/src/ifs/wl_surface/wp_tearing_control_v1.rs new file mode 100644 index 00000000..181c4d3b --- /dev/null +++ b/src/ifs/wl_surface/wp_tearing_control_v1.rs @@ -0,0 +1,82 @@ +use { + crate::{ + client::ClientError, + ifs::wl_surface::WlSurface, + leaks::Tracker, + object::Object, + utils::buffd::{MsgParser, MsgParserError}, + wire::{wp_tearing_control_v1::*, WlSurfaceId, WpTearingControlV1Id}, + }, + std::{fmt::Debug, rc::Rc}, + thiserror::Error, +}; + +const VSYNC: u32 = 0; +const ASYNC: u32 = 1; + +pub struct WpTearingControlV1 { + pub id: WpTearingControlV1Id, + pub surface: Rc, + pub tracker: Tracker, +} + +impl WpTearingControlV1 { + pub fn install(self: &Rc) -> Result<(), WpTearingControlV1Error> { + if self.surface.tearing_control.get().is_some() { + return Err(WpTearingControlV1Error::AlreadyAttached(self.surface.id)); + } + self.surface.tearing_control.set(Some(self.clone())); + Ok(()) + } + + fn set_presentation_hint( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), WpTearingControlV1Error> { + let req: SetPresentationHint = self.surface.client.parse(self, parser)?; + let tearing = match req.hint { + VSYNC => false, + ASYNC => true, + _ => return Err(WpTearingControlV1Error::UnknownPresentationHint(req.hint)), + }; + self.surface.pending.tearing.set(Some(tearing)); + Ok(()) + } + + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), WpTearingControlV1Error> { + let _req: Destroy = self.surface.client.parse(self, parser)?; + self.surface.pending.tearing.set(Some(false)); + self.surface.tearing_control.take(); + self.surface.client.remove_obj(self)?; + Ok(()) + } +} + +object_base! { + WpTearingControlV1; + + SET_PRESENTATION_HINT => set_presentation_hint, + DESTROY => destroy, +} + +impl Object for WpTearingControlV1 { + fn num_requests(&self) -> u32 { + DESTROY + 1 + } +} + +simple_add_obj!(WpTearingControlV1); + +#[derive(Debug, Error)] +pub enum WpTearingControlV1Error { + #[error("Surface {0} already has a wp_tearing_control")] + AlreadyAttached(WlSurfaceId), + #[error("Unknown presentation hint {0}")] + UnknownPresentationHint(u32), + #[error(transparent)] + ClientError(Box), + #[error("Parsing failed")] + MsgParserError(#[source] Box), +} +efrom!(WpTearingControlV1Error, ClientError); +efrom!(WpTearingControlV1Error, MsgParserError); diff --git a/src/ifs/wp_tearing_control_manager_v1.rs b/src/ifs/wp_tearing_control_manager_v1.rs new file mode 100644 index 00000000..a84e57a9 --- /dev/null +++ b/src/ifs/wp_tearing_control_manager_v1.rs @@ -0,0 +1,118 @@ +use { + crate::{ + client::{Client, ClientError}, + globals::{Global, GlobalName}, + ifs::wl_surface::wp_tearing_control_v1::{WpTearingControlV1, WpTearingControlV1Error}, + leaks::Tracker, + object::Object, + utils::buffd::{MsgParser, MsgParserError}, + wire::{ + wp_tearing_control_manager_v1::{GET_TEARING_CONTROL, *}, + WpTearingControlManagerV1Id, + }, + }, + std::rc::Rc, + thiserror::Error, +}; + +pub struct WpTearingControlManagerV1Global { + name: GlobalName, +} + +impl WpTearingControlManagerV1Global { + pub fn new(name: GlobalName) -> Self { + Self { name } + } + + fn bind_( + self: Rc, + id: WpTearingControlManagerV1Id, + client: &Rc, + _version: u32, + ) -> Result<(), WpTearingControlManagerV1Error> { + let obj = Rc::new(WpTearingControlManagerV1 { + id, + client: client.clone(), + tracker: Default::default(), + }); + track!(client, obj); + client.add_client_obj(&obj)?; + Ok(()) + } +} + +global_base!( + WpTearingControlManagerV1Global, + WpTearingControlManagerV1, + WpTearingControlManagerV1Error +); + +impl Global for WpTearingControlManagerV1Global { + fn singleton(&self) -> bool { + true + } + + fn version(&self) -> u32 { + 1 + } +} + +simple_add_global!(WpTearingControlManagerV1Global); + +pub struct WpTearingControlManagerV1 { + pub id: WpTearingControlManagerV1Id, + pub client: Rc, + pub tracker: Tracker, +} + +impl WpTearingControlManagerV1 { + pub fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), WpTearingControlManagerV1Error> { + let _req: Destroy = self.client.parse(self, parser)?; + self.client.remove_obj(self)?; + Ok(()) + } + + pub fn get_tearing_control( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), WpTearingControlManagerV1Error> { + let req: GetTearingControl = self.client.parse(self, parser)?; + let surface = self.client.lookup(req.surface)?; + let control = Rc::new(WpTearingControlV1 { + id: req.id, + surface, + tracker: Default::default(), + }); + track!(self.client, control); + self.client.add_client_obj(&control)?; + control.install()?; + Ok(()) + } +} + +object_base! { + WpTearingControlManagerV1; + + DESTROY => destroy, + GET_TEARING_CONTROL => get_tearing_control, +} + +impl Object for WpTearingControlManagerV1 { + fn num_requests(&self) -> u32 { + GET_TEARING_CONTROL + 1 + } +} + +simple_add_obj!(WpTearingControlManagerV1); + +#[derive(Debug, Error)] +pub enum WpTearingControlManagerV1Error { + #[error("Parsing failed")] + MsgParserError(#[source] Box), + #[error(transparent)] + ClientError(Box), + #[error(transparent)] + WpTearingControlV1Error(#[from] WpTearingControlV1Error), +} +efrom!(WpTearingControlManagerV1Error, ClientError); +efrom!(WpTearingControlManagerV1Error, MsgParserError); diff --git a/wire/wp_tearing_control_manager_v1.txt b/wire/wp_tearing_control_manager_v1.txt new file mode 100644 index 00000000..639d606f --- /dev/null +++ b/wire/wp_tearing_control_manager_v1.txt @@ -0,0 +1,11 @@ +# requests + +msg destroy = 0 { + +} + +msg get_tearing_control = 1 { + id: id(wp_tearing_control_v1), + surface: id(wl_surface), +} + diff --git a/wire/wp_tearing_control_v1.txt b/wire/wp_tearing_control_v1.txt new file mode 100644 index 00000000..6dcebc20 --- /dev/null +++ b/wire/wp_tearing_control_v1.txt @@ -0,0 +1,9 @@ +# requests + +msg set_presentation_hint = 0 { + hint: u32, +} + +msg destroy = 1 { + +}