diff --git a/src/compositor.rs b/src/compositor.rs index ad857998..3c307503 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -76,7 +76,10 @@ use { }, ahash::AHashSet, forker::ForkerProxy, - jay_config::{_private::DEFAULT_SEAT_NAME, video::GfxApi}, + jay_config::{ + _private::DEFAULT_SEAT_NAME, + video::{GfxApi, Transform}, + }, std::{cell::Cell, env, future::Future, ops::Deref, rc::Rc, sync::Arc, time::Duration}, thiserror::Error, uapi::c, @@ -637,7 +640,13 @@ fn create_dummy_output(state: &Rc) { let head_name = state.head_names.next(); let head_state = HeadState { name: RcEq(name.clone()), + position: (0, 0), + size: (0, 0), + transform: Transform::None, + scale: Default::default(), wl_output: None, + connector_enabled: true, + in_compositor_space: false, monitor_info: None, }; let connector_data = Rc::new(ConnectorData { diff --git a/src/ifs/head_management.rs b/src/ifs/head_management.rs index b5a539ae..0bc38665 100644 --- a/src/ifs/head_management.rs +++ b/src/ifs/head_management.rs @@ -7,10 +7,13 @@ use { head_management_macros::HeadExts, jay_head_manager_session_v1::JayHeadManagerSessionV1, jay_head_v1::JayHeadV1, }, + scale::Scale, state::OutputData, + tree::OutputNode, utils::{copyhashmap::CopyHashMap, hash_map_ext::HashMapExt, rc_eq::RcEq}, wire::JayHeadManagerSessionV1Id, }, + jay_config::video::Transform, std::{ cell::{Cell, RefCell}, rc::Rc, @@ -64,9 +67,33 @@ struct HeadCommon { pub struct HeadState { pub name: RcEq, pub wl_output: Option, + pub connector_enabled: bool, + pub in_compositor_space: bool, + pub position: (i32, i32), + pub size: (i32, i32), + pub transform: Transform, + pub scale: Scale, pub monitor_info: Option>, } +impl HeadState { + fn update_in_compositor_space(&mut self, wl_output: Option) { + self.in_compositor_space = false; + self.wl_output = None; + if !self.connector_enabled { + return; + } + let Some(mi) = &self.monitor_info else { + return; + }; + if mi.non_desktop { + return; + } + self.in_compositor_space = true; + self.wl_output = wl_output; + } +} + enum HeadOp {} #[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] @@ -164,11 +191,18 @@ impl HeadManagers { pub fn handle_output_connected(&self, output: &OutputData) { let state = &mut *self.state.borrow_mut(); state.monitor_info = Some(RcEq(output.monitor_info.clone())); + state.update_in_compositor_space(output.node.as_ref().map(|n| n.global.name)); if let Some(n) = &output.node { - state.wl_output = Some(n.global.name); + state.position = n.global.pos.get().position(); + state.size = n.global.pos.get().size(); + state.transform = n.global.persistent.transform.get(); } for head in self.managers.lock().values() { skip_in_transaction!(head); + if let Some(ext) = &head.ext.compositor_space_info_v1 { + ext.send_inside_outside(state); + head.session.schedule_done(); + } if let Some(ext) = &head.ext.core_info_v1 { ext.send_wl_output(state); head.session.schedule_done(); @@ -178,14 +212,71 @@ impl HeadManagers { pub fn handle_output_disconnected(&self) { let state = &mut *self.state.borrow_mut(); - state.wl_output = None; state.monitor_info = None; + state.update_in_compositor_space(None); for head in self.managers.lock().values() { skip_in_transaction!(head); + if let Some(ext) = &head.ext.compositor_space_info_v1 { + ext.send_inside_outside(state); + head.session.schedule_done(); + } if let Some(ext) = &head.ext.core_info_v1 { ext.send_wl_output(state); head.session.schedule_done(); } } } + + pub fn handle_position_size_change(&self, node: &OutputNode) { + let state = &mut *self.state.borrow_mut(); + let pos = node.global.pos.get(); + state.position = pos.position(); + state.size = pos.size(); + for head in self.managers.lock().values() { + skip_in_transaction!(head); + if let Some(ext) = &head.ext.compositor_space_info_v1 { + ext.send_position(state); + ext.send_size(state); + head.session.schedule_done(); + } + } + } + + pub fn handle_transform_change(&self, transform: Transform) { + let state = &mut *self.state.borrow_mut(); + state.transform = transform; + for head in self.managers.lock().values() { + skip_in_transaction!(head); + if let Some(ext) = &head.ext.compositor_space_info_v1 { + ext.send_transform(state); + head.session.schedule_done(); + } + } + } + + pub fn handle_scale_change(&self, scale: Scale) { + let state = &mut *self.state.borrow_mut(); + state.scale = scale; + for head in self.managers.lock().values() { + skip_in_transaction!(head); + if let Some(ext) = &head.ext.compositor_space_info_v1 { + ext.send_scale(state); + head.session.schedule_done(); + } + } + } + + pub fn handle_enabled_change(&self, enabled: bool) { + let state = &mut *self.state.borrow_mut(); + state.connector_enabled = enabled; + state.update_in_compositor_space(state.wl_output); + for head in self.managers.lock().values() { + skip_in_transaction!(head); + if let Some(ext) = &head.ext.compositor_space_info_v1 { + ext.send_enabled(state); + ext.send_inside_outside(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 a99a79d4..db97aef4 100644 --- a/src/ifs/head_management/head_management_macros.rs +++ b/src/ifs/head_management/head_management_macros.rs @@ -389,4 +389,5 @@ macro_rules! declare_extensions { declare_extensions! { core_info_v1: CoreInfoV1, + compositor_space_info_v1: CompositorSpaceInfoV1, } diff --git a/src/ifs/head_management/jay_head_ext.rs b/src/ifs/head_management/jay_head_ext.rs index d6d1abf0..44bcd59f 100644 --- a/src/ifs/head_management/jay_head_ext.rs +++ b/src/ifs/head_management/jay_head_ext.rs @@ -1 +1,2 @@ +pub(super) mod jay_head_ext_compositor_space_info_v1; pub(super) mod jay_head_ext_core_info_v1; diff --git a/src/ifs/head_management/jay_head_ext/jay_head_ext_compositor_space_info_v1.rs b/src/ifs/head_management/jay_head_ext/jay_head_ext_compositor_space_info_v1.rs new file mode 100644 index 00000000..acffb919 --- /dev/null +++ b/src/ifs/head_management/jay_head_ext/jay_head_ext_compositor_space_info_v1.rs @@ -0,0 +1,113 @@ +use { + crate::{ + ifs::head_management::HeadState, + utils::transform_ext::TransformExt, + wire::{ + jay_head_ext_compositor_space_info_v1::{ + Disabled, Enabled, Inside, JayHeadExtCompositorSpaceInfoV1RequestHandler, Outside, + Position, Scaling, Size, Transform, + }, + jay_head_manager_ext_compositor_space_info_v1::JayHeadManagerExtCompositorSpaceInfoV1RequestHandler, + }, + }, + std::rc::Rc, +}; + +impl_compositor_space_info_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_inside_outside(shared); + } + + fn after_transaction(&self, shared: &HeadState, tran: &HeadState) { + if shared.connector_enabled != tran.connector_enabled { + self.send_enabled(shared); + } + if shared.in_compositor_space != tran.in_compositor_space { + self.send_inside_outside(shared); + } else if shared.in_compositor_space { + if shared.position != tran.position { + self.send_position(shared); + } + if shared.size != tran.size { + self.send_size(shared); + } + if shared.transform != tran.transform { + self.send_transform(shared); + } + if shared.scale != tran.scale { + self.send_scale(shared); + } + } + } + + pub(in super::super) fn send_inside_outside(&self, state: &HeadState) { + if state.in_compositor_space { + self.client.event(Inside { self_id: self.id }); + self.send_position(state); + self.send_size(state); + self.send_transform(state); + self.send_scale(state); + } else { + self.client.event(Outside { self_id: self.id }); + } + } + + pub(in super::super) fn send_enabled(&self, state: &HeadState) { + if state.connector_enabled { + self.client.event(Enabled { self_id: self.id }); + } else { + self.client.event(Disabled { self_id: self.id }); + } + } + + pub(in super::super) fn send_position(&self, state: &HeadState) { + self.client.event(Position { + self_id: self.id, + x: state.position.0, + y: state.position.1, + }); + } + + pub(in super::super) fn send_size(&self, state: &HeadState) { + self.client.event(Size { + self_id: self.id, + width: state.size.0, + height: state.size.1, + }); + } + + pub(in super::super) fn send_transform(&self, state: &HeadState) { + self.client.event(Transform { + self_id: self.id, + transform: state.transform.to_wl() as _, + }); + } + + pub(in super::super) fn send_scale(&self, state: &HeadState) { + self.client.event(Scaling { + self_id: self.id, + scaling: state.scale.to_wl(), + }); + } +} + +impl JayHeadManagerExtCompositorSpaceInfoV1RequestHandler for MgrName { + type Error = ErrorName; + + mgr_common_req!(); +} + +impl JayHeadExtCompositorSpaceInfoV1RequestHandler for HeadName { + type Error = ErrorName; + + head_common_req!(); +} + +error!(); diff --git a/src/ifs/head_management/jay_head_manager_session_v1.rs b/src/ifs/head_management/jay_head_manager_session_v1.rs index 022dbe55..a6ef1f89 100644 --- a/src/ifs/head_management/jay_head_manager_session_v1.rs +++ b/src/ifs/head_management/jay_head_manager_session_v1.rs @@ -374,7 +374,13 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 { } bitflags! { ToSend: u32; - CORE_INFO = 1 << 0, + CORE_INFO = 1 << 0, + COMPOSITOR_SPACE_INFO_FULL = 1 << 1, + COMPOSITOR_SPACE_INFO_POS = 1 << 2, + COMPOSITOR_SPACE_INFO_SIZE = 1 << 3, + COMPOSITOR_SPACE_INFO_TRANSFORM = 1 << 4, + COMPOSITOR_SPACE_INFO_SCALE = 1 << 5, + COMPOSITOR_SPACE_INFO_ENABLED = 1 << 13, } for head in self.heads.lock().values() { let pending = mem::take(&mut *head.common.pending.borrow_mut()); @@ -392,6 +398,27 @@ impl JayHeadManagerSessionV1RequestHandler for JayHeadManagerSessionV1 { { i.send_wl_output(state); } + if let Some(i) = &head.ext.compositor_space_info_v1 { + if to_send.contains(COMPOSITOR_SPACE_INFO_ENABLED) { + i.send_enabled(state); + } + if to_send.contains(COMPOSITOR_SPACE_INFO_FULL) { + i.send_inside_outside(state); + } else { + if to_send.contains(COMPOSITOR_SPACE_INFO_POS) { + i.send_position(state); + } + if to_send.contains(COMPOSITOR_SPACE_INFO_SIZE) { + i.send_size(state); + } + if to_send.contains(COMPOSITOR_SPACE_INFO_TRANSFORM) { + i.send_transform(state); + } + if to_send.contains(COMPOSITOR_SPACE_INFO_SCALE) { + i.send_scale(state); + } + } + } } slf.schedule_transaction_result(req.result, None)?; Ok(()) diff --git a/src/state.rs b/src/state.rs index 51f4951d..f708ef92 100644 --- a/src/state.rs +++ b/src/state.rs @@ -443,6 +443,9 @@ impl ConnectorData { return; } self.state.set(s); + if old.enabled != s.enabled { + self.head_managers.handle_enabled_change(s.enabled); + } 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 555d2900..203f3049 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -18,6 +18,7 @@ use { asyncevent::AsyncEvent, clonecell::CloneCell, hash_map_ext::HashMapExt, rc_eq::RcEq, }, }, + jay_config::video::Transform, std::{cell::Cell, collections::VecDeque, rc::Rc}, }; @@ -45,7 +46,13 @@ pub fn handle(state: &Rc, connector: &Rc) { let name = Rc::new(connector.kernel_id().to_string()); let head_state = HeadState { name: RcEq(name.clone()), + position: (0, 0), + size: (0, 0), + transform: Transform::None, + scale: Default::default(), wl_output: None, + connector_enabled: backend_state.enabled, + in_compositor_space: false, monitor_info: None, }; let data = Rc::new(ConnectorData { diff --git a/src/tree/output.rs b/src/tree/output.rs index 60c091ba..cb06b12e 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -470,6 +470,10 @@ impl OutputNode { } } self.schedule_update_render_data(); + self.global + .connector + .head_managers + .handle_scale_change(scale); } pub fn schedule_update_render_data(self: &Rc) { @@ -800,6 +804,10 @@ impl OutputNode { if transform != old_transform { self.state.refresh_hardware_cursors(); self.node_visit_children(&mut SurfaceSendPreferredTransformVisitor); + self.global + .connector + .head_managers + .handle_transform_change(transform); } } @@ -847,6 +855,10 @@ impl OutputNode { seat.cursor_group().output_pos_changed(self) } self.state.tree_changed(); + self.global + .connector + .head_managers + .handle_position_size_change(self); } pub fn update_state(self: &Rc, old: BackendConnectorState, state: BackendConnectorState) { diff --git a/wire/jay_head_ext_compositor_space_info_v1.txt b/wire/jay_head_ext_compositor_space_info_v1.txt new file mode 100644 index 00000000..562895b4 --- /dev/null +++ b/wire/jay_head_ext_compositor_space_info_v1.txt @@ -0,0 +1,37 @@ +request destroy (destructor) { + +} + +event enabled { + +} + +event disabled { + +} + +event inside { + +} + +event outside { + +} + +event position { + x: i32, + y: i32, +} + +event size { + width: i32, + height: i32, +} + +event transform { + transform: u32, +} + +event scaling { + scaling: u32, +} diff --git a/wire/jay_head_manager_ext_compositor_space_info_v1.txt b/wire/jay_head_manager_ext_compositor_space_info_v1.txt new file mode 100644 index 00000000..a86df828 --- /dev/null +++ b/wire/jay_head_manager_ext_compositor_space_info_v1.txt @@ -0,0 +1,7 @@ +request destroy (destructor) { + +} + +event head { + head: id(jay_head_ext_compositor_space_info_v1) (new), +}