From 4482c3168bf466c3ceb8d283837afcee61bc24ef Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sun, 13 Jul 2025 13:51:08 +0200 Subject: [PATCH] head-management: add tearing-state-v1 extension --- src/compositor.rs | 3 + src/ifs/head_management.rs | 26 ++++++++ .../head_management/head_management_macros.rs | 1 + src/ifs/head_management/jay_head_ext.rs | 1 + .../jay_head_ext_tearing_state_v1.rs | 64 +++++++++++++++++++ src/state.rs | 3 + src/tasks/connector.rs | 3 + src/tree/output.rs | 17 +++-- wire/jay_head_ext_tearing_state_v1.txt | 19 ++++++ .../jay_head_manager_ext_tearing_state_v1.txt | 7 ++ 10 files changed, 140 insertions(+), 4 deletions(-) create mode 100644 src/ifs/head_management/jay_head_ext/jay_head_ext_tearing_state_v1.rs create mode 100644 wire/jay_head_ext_tearing_state_v1.txt create mode 100644 wire/jay_head_manager_ext_tearing_state_v1.txt diff --git a/src/compositor.rs b/src/compositor.rs index d5f72de0..7ae496f6 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -654,6 +654,8 @@ fn create_dummy_output(state: &Rc) { inherent_non_desktop: false, override_non_desktop: None, vrr: false, + tearing_enabled: backend_state.tearing, + tearing_active: false, }; let connector_data = Rc::new(ConnectorData { id, @@ -727,6 +729,7 @@ fn create_dummy_output(state: &Rc) { tray_items: Default::default(), ext_workspace_groups: Default::default(), pinned: Default::default(), + tearing: Default::default(), }); let dummy_workspace = Rc::new(WorkspaceNode { id: state.node_ids.next(), diff --git a/src/ifs/head_management.rs b/src/ifs/head_management.rs index d964a6cd..77e1e528 100644 --- a/src/ifs/head_management.rs +++ b/src/ifs/head_management.rs @@ -80,6 +80,8 @@ pub struct HeadState { pub inherent_non_desktop: bool, pub override_non_desktop: Option, pub vrr: bool, + pub tearing_enabled: bool, + pub tearing_active: bool, } impl HeadState { @@ -380,4 +382,28 @@ impl HeadManagers { } } } + + pub fn handle_tearing_enabled_change(&self, enabled: bool) { + let state = &mut *self.state.borrow_mut(); + state.tearing_enabled = enabled; + for head in self.managers.lock().values() { + skip_in_transaction!(head); + if let Some(ext) = &head.ext.tearing_state_v1 { + ext.send_enabled(state); + head.session.schedule_done(); + } + } + } + + pub fn handle_tearing_active_change(&self, active: bool) { + let state = &mut *self.state.borrow_mut(); + state.tearing_active = active; + for head in self.managers.lock().values() { + skip_in_transaction!(head); + if let Some(ext) = &head.ext.tearing_state_v1 { + ext.send_active(state); + head.session.schedule_done(); + } + } + } } diff --git a/src/ifs/head_management/head_management_macros.rs b/src/ifs/head_management/head_management_macros.rs index 20160c2c..b52b0d5c 100644 --- a/src/ifs/head_management/head_management_macros.rs +++ b/src/ifs/head_management/head_management_macros.rs @@ -400,4 +400,5 @@ declare_extensions! { physical_display_info_v1: PhysicalDisplayInfoV1, non_desktop_info_v1: NonDesktopInfoV1, vrr_state_v1: VrrStateV1, + tearing_state_v1: TearingStateV1, } diff --git a/src/ifs/head_management/jay_head_ext.rs b/src/ifs/head_management/jay_head_ext.rs index 96d21fc7..c279a0f0 100644 --- a/src/ifs/head_management/jay_head_ext.rs +++ b/src/ifs/head_management/jay_head_ext.rs @@ -9,4 +9,5 @@ pub(super) mod jay_head_ext_mode_info_v1; pub(super) mod jay_head_ext_mode_setter_v1; pub(super) mod jay_head_ext_non_desktop_info_v1; pub(super) mod jay_head_ext_physical_display_info_v1; +pub(super) mod jay_head_ext_tearing_state_v1; pub(super) mod jay_head_ext_vrr_state_v1; diff --git a/src/ifs/head_management/jay_head_ext/jay_head_ext_tearing_state_v1.rs b/src/ifs/head_management/jay_head_ext/jay_head_ext_tearing_state_v1.rs new file mode 100644 index 00000000..e6491d48 --- /dev/null +++ b/src/ifs/head_management/jay_head_ext/jay_head_ext_tearing_state_v1.rs @@ -0,0 +1,64 @@ +use { + crate::{ + ifs::head_management::HeadState, + wire::{ + jay_head_ext_tearing_state_v1::{ + Active, Disabled, Enabled, Inactive, JayHeadExtTearingStateV1RequestHandler, + }, + jay_head_manager_ext_tearing_state_v1::JayHeadManagerExtTearingStateV1RequestHandler, + }, + }, + std::rc::Rc, +}; + +impl_tearing_state_v1! { + version = 1, + after_announce = after_announce, + after_transaction = after_transaction, +} + +impl HeadName { + fn after_announce(&self, shared: &HeadState) { + self.send_enabled(shared); + self.send_active(shared); + } + + fn after_transaction(&self, shared: &HeadState, tran: &HeadState) { + if shared.tearing_enabled != tran.tearing_enabled { + self.send_enabled(shared); + } + if shared.tearing_active != tran.tearing_active { + self.send_active(shared); + } + } + + pub(in super::super) fn send_enabled(&self, state: &HeadState) { + if state.tearing_enabled { + self.client.event(Enabled { self_id: self.id }); + } else { + self.client.event(Disabled { self_id: self.id }); + } + } + + pub(in super::super) fn send_active(&self, state: &HeadState) { + if state.tearing_active { + self.client.event(Active { self_id: self.id }); + } else { + self.client.event(Inactive { self_id: self.id }); + } + } +} + +impl JayHeadManagerExtTearingStateV1RequestHandler for MgrName { + type Error = ErrorName; + + mgr_common_req!(); +} + +impl JayHeadExtTearingStateV1RequestHandler for HeadName { + type Error = ErrorName; + + head_common_req!(); +} + +error!(); diff --git a/src/state.rs b/src/state.rs index b30b0da1..2a651d0b 100644 --- a/src/state.rs +++ b/src/state.rs @@ -456,6 +456,9 @@ impl ConnectorData { if old.vrr != s.vrr { self.head_managers.handle_vrr_change(s.vrr); } + if old.tearing != s.tearing { + self.head_managers.handle_tearing_enabled_change(s.tearing); + } if let Some(output) = state.outputs.get(&self.connector.id()) && let Some(node) = &output.node { diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index 73f356eb..9394d7ac 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -60,6 +60,8 @@ pub fn handle(state: &Rc, connector: &Rc) { inherent_non_desktop: false, override_non_desktop: backend_state.non_desktop_override, vrr: backend_state.vrr, + tearing_enabled: backend_state.tearing, + tearing_active: false, }; let data = Rc::new(ConnectorData { id, @@ -240,6 +242,7 @@ impl ConnectorHandler { tray_items: Default::default(), ext_workspace_groups: Default::default(), pinned: Default::default(), + tearing: Default::default(), }); on.update_visible(); on.update_rects(); diff --git a/src/tree/output.rs b/src/tree/output.rs index e20e6256..1295ddd8 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -32,6 +32,7 @@ use { ext_workspace_manager_v1::WorkspaceManagerId, }, wp_content_type_v1::ContentType, + wp_presentation_feedback::KIND_VSYNC, zwlr_layer_shell_v1::{BACKGROUND, BOTTOM, OVERLAY, TOP}, zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1, }, @@ -47,10 +48,10 @@ use { WorkspaceNodeId, walker::NodeVisitor, }, utils::{ - asyncevent::AsyncEvent, clonecell::CloneCell, copyhashmap::CopyHashMap, - errorfmt::ErrorFmt, event_listener::EventSource, hash_map_ext::HashMapExt, - linkedlist::LinkedList, on_drop_event::OnDropEvent, scroller::Scroller, - transform_ext::TransformExt, + asyncevent::AsyncEvent, bitflags::BitflagsExt, clonecell::CloneCell, + copyhashmap::CopyHashMap, errorfmt::ErrorFmt, event_listener::EventSource, + hash_map_ext::HashMapExt, linkedlist::LinkedList, on_drop_event::OnDropEvent, + scroller::Scroller, transform_ext::TransformExt, }, wire::{ ExtImageCopyCaptureSessionV1Id, JayOutputId, JayScreencastId, ZwlrScreencopyFrameV1Id, @@ -107,6 +108,7 @@ pub struct OutputNode { pub tray_items: LinkedList>, pub ext_workspace_groups: CopyHashMap>, pub pinned: LinkedList>, + pub tearing: Cell, } #[derive(Copy, Clone, Debug, PartialEq)] @@ -218,6 +220,13 @@ impl OutputNode { if locked && let Some(lock) = self.state.lock.lock.get() { lock.check_locked() } + let tearing = flags.not_contains(KIND_VSYNC); + if self.tearing.replace(tearing) != tearing { + self.global + .connector + .head_managers + .handle_tearing_active_change(tearing); + } } pub fn update_exclusive_zones(self: &Rc) { diff --git a/wire/jay_head_ext_tearing_state_v1.txt b/wire/jay_head_ext_tearing_state_v1.txt new file mode 100644 index 00000000..89182010 --- /dev/null +++ b/wire/jay_head_ext_tearing_state_v1.txt @@ -0,0 +1,19 @@ +request destroy (destructor) { + +} + +event enabled { + +} + +event disabled { + +} + +event active { + +} + +event inactive { + +} diff --git a/wire/jay_head_manager_ext_tearing_state_v1.txt b/wire/jay_head_manager_ext_tearing_state_v1.txt new file mode 100644 index 00000000..253b0a4b --- /dev/null +++ b/wire/jay_head_manager_ext_tearing_state_v1.txt @@ -0,0 +1,7 @@ +request destroy (destructor) { + +} + +event head { + head: id(jay_head_ext_tearing_state_v1) (new), +}