1
0
Fork 0
forked from wry/wry

Add support for experimental xx_foreign_toplevel_geometry_tracker_v1 as

well as tracking_manager_v1.
This commit is contained in:
entailz 2026-04-30 03:00:44 -07:00
parent 4e9b6def83
commit 59c2b53350
10 changed files with 284 additions and 8 deletions

View file

@ -233,5 +233,7 @@ bitflags! {
pub const CC_GAMMA_CONTROL_MANAGER = 1 << 14,
/// Grants access to the `zwlr_virtual_pointer_manager_v1` global.
pub const CC_VIRTUAL_POINTER = 1 << 15,
/// Grants access to the `ext_foreign_toplevel_geometry_tracking_manager_v1` global.
pub const CC_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING = 1 << 16,
}
}

View file

@ -64,10 +64,11 @@ bitflags! {
CAP_DRM_LEASE = 1 << 9,
CAP_INPUT_METHOD = 1 << 10,
CAP_WORKSPACE = 1 << 11,
CAP_FOREIGN_TOPLEVEL_MANAGER = 1 << 12,
CAP_HEAD_MANAGER = 1 << 13,
CAP_GAMMA_CONTROL_MANAGER = 1 << 14,
CAP_VIRTUAL_POINTER_MANAGER = 1 << 15,
CAP_FOREIGN_TOPLEVEL_MANAGER = 1 << 12,
CAP_HEAD_MANAGER = 1 << 13,
CAP_GAMMA_CONTROL_MANAGER = 1 << 14,
CAP_VIRTUAL_POINTER_MANAGER = 1 << 15,
CAP_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING = 1 << 16,
}
impl StaticText for ClientCapsEnum {
@ -89,6 +90,9 @@ impl StaticText for ClientCapsEnum {
ClientCapsEnum::CAP_HEAD_MANAGER => "head-manager",
ClientCapsEnum::CAP_GAMMA_CONTROL_MANAGER => "gamma-control-manager",
ClientCapsEnum::CAP_VIRTUAL_POINTER_MANAGER => "virtual-pointer",
ClientCapsEnum::CAP_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING => {
"foreign-toplevel-geometry-tracking"
}
}
}
}

View file

@ -65,6 +65,7 @@ use {
xdg_toplevel_tag_manager_v1::XdgToplevelTagManagerV1Global,
xdg_wm_base::XdgWmBaseGlobal,
xdg_wm_dialog_v1::XdgWmDialogV1Global,
xx_foreign_toplevel_geometry_tracking_manager_v1::XxForeignToplevelGeometryTrackingManagerV1Global,
zwlr_foreign_toplevel_manager_v1::ZwlrForeignToplevelManagerV1Global,
zwlr_gamma_control_manager_v1::ZwlrGammaControlManagerV1Global,
zwlr_layer_shell_v1::ZwlrLayerShellV1Global,
@ -252,6 +253,7 @@ singletons! {
WpLinuxDrmSyncobjManagerV1,
WpPresentation,
ZwlrVirtualPointerManagerV1,
XxForeignToplevelGeometryTrackingManagerV1,
}
pub struct Globals {

View file

@ -88,6 +88,8 @@ pub mod xdg_toplevel_drag_v1;
pub mod xdg_toplevel_tag_manager_v1;
pub mod xdg_wm_base;
pub mod xdg_wm_dialog_v1;
pub mod xx_foreign_toplevel_geometry_tracker_v1;
pub mod xx_foreign_toplevel_geometry_tracking_manager_v1;
pub mod zwlr_foreign_toplevel_handle_v1;
pub mod zwlr_foreign_toplevel_manager_v1;
pub mod zwlr_gamma_control_manager_v1;

View file

@ -0,0 +1,99 @@
use {
crate::{
client::{Client, ClientError},
leaks::Tracker,
object::{Object, Version},
rect::Rect,
state::State,
tree::ToplevelOpt,
wire::{
XxForeignToplevelGeometryTrackerV1Id,
xx_foreign_toplevel_geometry_tracker_v1::*,
},
},
std::rc::Rc,
thiserror::Error,
};
pub struct XxForeignToplevelGeometryTrackerV1 {
pub id: XxForeignToplevelGeometryTrackerV1Id,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub toplevel: ToplevelOpt,
pub version: Version,
}
impl XxForeignToplevelGeometryTrackerV1 {
fn detach(&self) {
if let Some(tl) = self.toplevel.get() {
tl.tl_data()
.geometry_trackers
.remove(&(self.client.id, self.id));
}
}
pub fn send_finished(&self) {
self.client.event(Finished { self_id: self.id });
}
pub fn send_geometry_update(&self, rect: &Rect, state: &State) {
if rect.is_empty() {
self.client.event(Done { self_id: self.id });
return;
}
for output in state.globals.outputs.lock().values() {
let output_pos = output.pos.get();
if !rect.intersects(&output_pos) {
continue;
}
let scale = output.persistent.scale.get().to_f64();
let rel_x = rect.x1() - output_pos.x1();
let rel_y = rect.y1() - output_pos.y1();
let hw_x = (rel_x as f64 * scale).round() as i32;
let hw_y = (rel_y as f64 * scale).round() as i32;
let hw_w = (rect.width() as f64 * scale).round() as u32;
let hw_h = (rect.height() as f64 * scale).round() as u32;
self.client.event(Geometry {
self_id: self.id,
output: output.name.raw(),
x: hw_x,
y: hw_y,
width: hw_w,
height: hw_h,
});
}
self.client.event(Done { self_id: self.id });
}
}
impl XxForeignToplevelGeometryTrackerV1RequestHandler
for XxForeignToplevelGeometryTrackerV1
{
type Error = XxForeignToplevelGeometryTrackerV1Error;
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.detach();
self.client.remove_obj(self)?;
Ok(())
}
}
object_base! {
self = XxForeignToplevelGeometryTrackerV1;
version = self.version;
}
impl Object for XxForeignToplevelGeometryTrackerV1 {
fn break_loops(&self) {
self.detach();
}
}
simple_add_obj!(XxForeignToplevelGeometryTrackerV1);
#[derive(Debug, Error)]
pub enum XxForeignToplevelGeometryTrackerV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(XxForeignToplevelGeometryTrackerV1Error, ClientError);

View file

@ -0,0 +1,125 @@
use {
crate::{
client::{CAP_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING, Client, ClientCaps, ClientError},
globals::{Global, GlobalName},
ifs::{
xx_foreign_toplevel_geometry_tracker_v1::XxForeignToplevelGeometryTrackerV1,
ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
},
leaks::Tracker,
object::{Object, Version},
wire::{
XxForeignToplevelGeometryTrackingManagerV1Id,
xx_foreign_toplevel_geometry_tracking_manager_v1::*,
},
},
std::rc::Rc,
thiserror::Error,
};
pub struct XxForeignToplevelGeometryTrackingManagerV1Global {
pub name: GlobalName,
}
impl XxForeignToplevelGeometryTrackingManagerV1Global {
pub fn new(name: GlobalName) -> Self {
Self { name }
}
fn bind_(
self: Rc<Self>,
id: XxForeignToplevelGeometryTrackingManagerV1Id,
client: &Rc<Client>,
version: Version,
) -> Result<(), XxForeignToplevelGeometryTrackingManagerV1Error> {
let obj = Rc::new(XxForeignToplevelGeometryTrackingManagerV1 {
id,
client: client.clone(),
tracker: Default::default(),
version,
});
track!(client, obj);
client.add_client_obj(&obj)?;
Ok(())
}
}
pub struct XxForeignToplevelGeometryTrackingManagerV1 {
pub id: XxForeignToplevelGeometryTrackingManagerV1Id,
pub client: Rc<Client>,
pub tracker: Tracker<Self>,
pub version: Version,
}
impl XxForeignToplevelGeometryTrackingManagerV1RequestHandler
for XxForeignToplevelGeometryTrackingManagerV1
{
type Error = XxForeignToplevelGeometryTrackingManagerV1Error;
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> Result<(), Self::Error> {
self.client.remove_obj(self)?;
Ok(())
}
fn get_geometry_tracker(
&self,
req: GetGeometryTracker,
_slf: &Rc<Self>,
) -> Result<(), Self::Error> {
let handle: Rc<ExtForeignToplevelHandleV1> = self.client.lookup(req.toplevel)?;
let toplevel = handle.toplevel.clone();
let tracker_obj = Rc::new(XxForeignToplevelGeometryTrackerV1 {
id: req.tracker,
client: self.client.clone(),
tracker: Default::default(),
toplevel: toplevel.clone(),
version: self.version,
});
track!(self.client, tracker_obj);
self.client.add_client_obj(&tracker_obj)?;
if let Some(tl) = toplevel.get() {
let data = tl.tl_data();
data.geometry_trackers
.set((self.client.id, req.tracker), tracker_obj.clone());
let rect = tl.node_absolute_position();
tracker_obj.send_geometry_update(&rect, &data.state);
} else {
tracker_obj.send_finished();
}
Ok(())
}
}
global_base!(
XxForeignToplevelGeometryTrackingManagerV1Global,
XxForeignToplevelGeometryTrackingManagerV1,
XxForeignToplevelGeometryTrackingManagerV1Error
);
impl Global for XxForeignToplevelGeometryTrackingManagerV1Global {
fn version(&self) -> u32 {
1
}
fn required_caps(&self) -> ClientCaps {
CAP_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING
}
}
simple_add_global!(XxForeignToplevelGeometryTrackingManagerV1Global);
object_base! {
self = XxForeignToplevelGeometryTrackingManagerV1;
version = self.version;
}
impl Object for XxForeignToplevelGeometryTrackingManagerV1 {}
simple_add_obj!(XxForeignToplevelGeometryTrackingManagerV1);
#[derive(Debug, Error)]
pub enum XxForeignToplevelGeometryTrackingManagerV1Error {
#[error(transparent)]
ClientError(Box<ClientError>),
}
efrom!(XxForeignToplevelGeometryTrackingManagerV1Error, ClientError);

View file

@ -21,6 +21,7 @@ use {
xdg_surface::xdg_toplevel::XdgToplevelToplevelData,
},
wp_content_type_v1::ContentType,
xx_foreign_toplevel_geometry_tracker_v1::XxForeignToplevelGeometryTrackerV1,
zwlr_foreign_toplevel_handle_v1::ZwlrForeignToplevelHandleV1,
zwlr_foreign_toplevel_manager_v1::ZwlrForeignToplevelManagerV1,
},
@ -37,7 +38,7 @@ use {
},
wire::{
ExtForeignToplevelHandleV1Id, ExtImageCopyCaptureSessionV1Id, JayScreencastId,
JayToplevelId, ZwlrForeignToplevelHandleV1Id,
JayToplevelId, XxForeignToplevelGeometryTrackerV1Id, ZwlrForeignToplevelHandleV1Id,
},
},
jay_config::{window, window::WindowType},
@ -195,7 +196,13 @@ impl<T: ToplevelNodeBase> ToplevelNode for T {
data.float_width.set(rect.width());
data.float_height.set(rect.height());
}
self.tl_change_extents_impl(rect)
let _ = data;
let slf = self.clone();
self.tl_change_extents_impl(rect);
let data = slf.tl_data();
for tracker in data.geometry_trackers.lock().values() {
tracker.send_geometry_update(rect, &data.state);
}
}
fn tl_set_visible(&self, visible: bool) {
@ -401,6 +408,10 @@ pub struct ToplevelData {
pub identifier: Cell<ToplevelIdentifier>,
pub handles:
CopyHashMap<(ClientId, ExtForeignToplevelHandleV1Id), Rc<ExtForeignToplevelHandleV1>>,
pub geometry_trackers: CopyHashMap<
(ClientId, XxForeignToplevelGeometryTrackerV1Id),
Rc<XxForeignToplevelGeometryTrackerV1>,
>,
pub manager_handles:
CopyHashMap<(ClientId, ZwlrForeignToplevelHandleV1Id), Rc<ZwlrForeignToplevelHandleV1>>,
pub render_highlight: NumCell<u32>,
@ -459,6 +470,7 @@ impl ToplevelData {
app_id: Default::default(),
identifier: Cell::new(id),
handles: Default::default(),
geometry_trackers: Default::default(),
manager_handles: Default::default(),
render_highlight: Default::default(),
jay_toplevels: Default::default(),
@ -563,6 +575,12 @@ impl ToplevelData {
handle.send_closed();
}
}
{
let mut trackers = self.geometry_trackers.lock();
for tracker in trackers.drain_values() {
tracker.send_finished();
}
}
self.detach_node(node);
self.property_changed(TL_CHANGED_DESTROYED);
}
@ -951,7 +969,6 @@ impl ToplevelData {
};
parent.node_is_workspace()
}
}
impl Drop for ToplevelData {

View file

@ -7,7 +7,8 @@ use {
},
},
jay_config::client::{
CC_DATA_CONTROL, CC_DRM_LEASE, CC_FOREIGN_TOPLEVEL_LIST, CC_FOREIGN_TOPLEVEL_MANAGER,
CC_DATA_CONTROL, CC_DRM_LEASE, CC_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING,
CC_FOREIGN_TOPLEVEL_LIST, CC_FOREIGN_TOPLEVEL_MANAGER,
CC_GAMMA_CONTROL_MANAGER, CC_HEAD_MANAGER, CC_IDLE_NOTIFIER, CC_INPUT_METHOD,
CC_LAYER_SHELL, CC_SCREENCOPY, CC_SEAT_MANAGER, CC_SESSION_LOCK, CC_VIRTUAL_KEYBOARD,
CC_VIRTUAL_POINTER, CC_WORKSPACE_MANAGER, ClientCapabilities,
@ -49,6 +50,7 @@ impl Parser for CapabilitiesParser {
"head-manager" => CC_HEAD_MANAGER,
"gamma-control-manager" => CC_GAMMA_CONTROL_MANAGER,
"virtual-pointer" => CC_VIRTUAL_POINTER,
"foreign-toplevel-geometry-tracking" => CC_FOREIGN_TOPLEVEL_GEOMETRY_TRACKING,
_ => {
return Err(
CapabilitiesParserError::UnknownCapability(string.to_owned()).spanned(span),

View file

@ -0,0 +1,16 @@
request destroy (destructor) {
}
event finished {
}
event done {
}
event geometry {
output: u32,
x: i32,
y: i32,
width: u32,
height: u32,
}

View file

@ -0,0 +1,7 @@
request destroy (destructor) {
}
request get_geometry_tracker {
tracker: id(xx_foreign_toplevel_geometry_tracker_v1) (new),
toplevel: id(ext_foreign_toplevel_handle_v1),
}