diff --git a/jay-config/src/_private/client.rs b/jay-config/src/_private/client.rs index f30b628f..c78399a7 100644 --- a/jay-config/src/_private/client.rs +++ b/jay-config/src/_private/client.rs @@ -417,6 +417,12 @@ impl Client { workspace } + pub fn get_seat_keyboard_workspace(&self, seat: Seat) -> Workspace { + let res = self.send_with_response(&ClientMessage::GetSeatKeyboardWorkspace { seat }); + get_response!(res, Workspace(0), GetSeatKeyboardWorkspace { workspace }); + workspace + } + pub fn set_default_workspace_capture(&self, capture: bool) { self.send(&ClientMessage::SetDefaultWorkspaceCapture { capture }); } @@ -1076,6 +1082,19 @@ impl Client { self.send(&ClientMessage::SetEiSocketEnabled { enabled }) } + pub fn get_connector_active_workspace(&self, connector: Connector) -> Workspace { + let res = + self.send_with_response(&ClientMessage::GetConnectorActiveWorkspace { connector }); + get_response!(res, Workspace(0), GetConnectorActiveWorkspace { workspace }); + workspace + } + + pub fn get_connector_workspaces(&self, connector: Connector) -> Vec { + let res = self.send_with_response(&ClientMessage::GetConnectorWorkspaces { connector }); + get_response!(res, vec![], GetConnectorWorkspaces { workspaces }); + workspaces + } + pub fn latch(&self, seat: Seat, f: F) { if !self.feat_mod_mask.get() { log::error!("compositor does not support latching"); diff --git a/jay-config/src/_private/ipc.rs b/jay-config/src/_private/ipc.rs index 531faae7..dd8f82ea 100644 --- a/jay-config/src/_private/ipc.rs +++ b/jay-config/src/_private/ipc.rs @@ -556,6 +556,15 @@ pub enum ClientMessage<'a> { SetShowFloatPinIcon { show: bool, }, + GetSeatKeyboardWorkspace { + seat: Seat, + }, + GetConnectorActiveWorkspace { + connector: Connector, + }, + GetConnectorWorkspaces { + connector: Connector, + }, } #[derive(Serialize, Deserialize, Debug)] @@ -710,6 +719,15 @@ pub enum Response { GetFloatPinned { pinned: bool, }, + GetSeatKeyboardWorkspace { + workspace: Workspace, + }, + GetConnectorActiveWorkspace { + workspace: Workspace, + }, + GetConnectorWorkspaces { + workspaces: Vec, + }, } #[derive(Serialize, Deserialize, Debug)] diff --git a/jay-config/src/input.rs b/jay-config/src/input.rs index dfd3b433..555eb7cf 100644 --- a/jay-config/src/input.rs +++ b/jay-config/src/input.rs @@ -359,6 +359,14 @@ impl Seat { get!(Workspace(0)).get_seat_workspace(self) } + /// Returns the workspace that is currently active on the output that contains the seat's + /// keyboard focus. + /// + /// If no such workspace exists, `exists` returns `false` for the returned workspace. + pub fn get_keyboard_workspace(self) -> Workspace { + get!(Workspace(0)).get_seat_keyboard_workspace(self) + } + /// Shows the workspace and sets the keyboard focus of the seat to that workspace. /// /// If the workspace doesn't currently exist, it is created on the output that contains the diff --git a/jay-config/src/video.rs b/jay-config/src/video.rs index 070f1b80..d029ca82 100644 --- a/jay-config/src/video.rs +++ b/jay-config/src/video.rs @@ -3,7 +3,7 @@ use { crate::{ _private::WireMode, - PciId, + PciId, Workspace, video::connector_type::{ CON_9PIN_DIN, CON_COMPONENT, CON_COMPOSITE, CON_DISPLAY_PORT, CON_DPI, CON_DSI, CON_DVIA, CON_DVID, CON_DVII, CON_EDP, CON_EMBEDDED_WINDOW, CON_HDMIA, CON_HDMIB, @@ -301,6 +301,21 @@ impl Connector { pub fn set_brightness(self, brightness: Option) { get!().connector_set_brightness(self, brightness); } + + /// Get the currently visible/active workspace. + /// + /// If this connector is not connected, or is there no active workspace, returns a + /// workspace whose `exists()` returns false. + pub fn active_workspace(self) -> Workspace { + get!(Workspace(0)).get_connector_active_workspace(self) + } + + /// Get all workspaces on this connector. + /// + /// If this connector is not connected, returns an empty list. + pub fn workspaces(self) -> Vec { + get!().get_connector_workspaces(self) + } } /// Returns all available DRM devices. diff --git a/src/config/handler.rs b/src/config/handler.rs index 8f39efdc..3caff976 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -137,6 +137,20 @@ impl ConfigProxyHandler { self.next_id.fetch_add(1) } + fn get_workspace_by_name(&self, name: &String) -> Workspace { + let id = match self.workspaces_by_name.get(name) { + None => { + let id = self.workspace_ids.fetch_add(1); + let name = Rc::new(name.clone()); + self.workspaces_by_name.set(name.clone(), id); + self.workspaces_by_id.set(id, name); + id + } + Some(id) => id, + }; + Workspace(id) + } + fn handle_log_request( &self, level: LogLevel, @@ -410,17 +424,7 @@ impl ConfigProxyHandler { fn handle_get_workspaces(&self) { let mut workspaces = vec![]; for ws in self.state.workspaces.lock().values() { - let id = match self.workspaces_by_name.get(&ws.name) { - None => { - let id = self.workspace_ids.fetch_add(1); - let name = Rc::new(ws.name.clone()); - self.workspaces_by_name.set(name.clone(), id); - self.workspaces_by_id.set(id, name); - id - } - Some(id) => id, - }; - workspaces.push(Workspace(id)); + workspaces.push(self.get_workspace_by_name(&ws.name)); } self.respond(Response::GetWorkspaces { workspaces }); } @@ -708,18 +712,8 @@ impl ConfigProxyHandler { } fn handle_get_workspace(&self, name: &str) { - let name = Rc::new(name.to_owned()); - let ws = match self.workspaces_by_name.get(&name) { - Some(w) => w, - _ => { - let ws = self.workspace_ids.fetch_add(1); - self.workspaces_by_name.set(name.clone(), ws); - self.workspaces_by_id.set(ws, name); - ws - } - }; self.respond(Response::GetWorkspace { - workspace: Workspace(ws), + workspace: self.get_workspace_by_name(&name.to_owned()), }); } @@ -818,17 +812,27 @@ impl ConfigProxyHandler { fn handle_get_seat_workspace(&self, seat: Seat) -> Result<(), CphError> { let seat = self.get_seat(seat)?; let output = seat.get_output(); - let mut workspace = 0; + let mut workspace = Workspace(0); if !output.is_dummy { if let Some(ws) = output.workspace.get() { - if let Some(ws) = self.workspaces_by_name.get(&ws.name) { - workspace = ws; + workspace = self.get_workspace_by_name(&ws.name); + } + } + self.respond(Response::GetSeatWorkspace { workspace }); + Ok(()) + } + + fn handle_get_seat_keyboard_workspace(&self, seat: Seat) -> Result<(), CphError> { + let seat = self.get_seat(seat)?; + let mut workspace = Workspace(0); + if let Some(output) = seat.get_keyboard_output() { + if !output.is_dummy { + if let Some(ws) = output.workspace.get() { + workspace = self.get_workspace_by_name(&ws.name); } } } - self.respond(Response::GetSeatWorkspace { - workspace: Workspace(workspace), - }); + self.respond(Response::GetSeatKeyboardWorkspace { workspace }); Ok(()) } @@ -1292,6 +1296,27 @@ impl ConfigProxyHandler { Ok(()) } + fn handle_get_connector_active_workspace(&self, connector: Connector) -> Result<(), CphError> { + let output = self.get_output_node(connector)?; + let workspace = output + .workspace + .get() + .map_or(Workspace(0), |ws| self.get_workspace_by_name(&ws.name)); + self.respond(Response::GetConnectorActiveWorkspace { workspace }); + Ok(()) + } + + fn handle_get_connector_workspaces(&self, connector: Connector) -> Result<(), CphError> { + let output = self.get_output_node(connector)?; + let workspaces = output + .workspaces + .iter() + .map(|ws| self.get_workspace_by_name(&ws.name)) + .collect::>(); + self.respond(Response::GetConnectorWorkspaces { workspaces }); + Ok(()) + } + fn handle_has_capability(&self, device: InputDevice, cap: Capability) -> Result<(), CphError> { let dev = self.get_device_handler_data(device)?; let mut is_unknown = false; @@ -1904,6 +1929,9 @@ impl ConfigProxyHandler { ClientMessage::GetSeatWorkspace { seat } => self .handle_get_seat_workspace(seat) .wrn("get_seat_workspace")?, + ClientMessage::GetSeatKeyboardWorkspace { seat } => self + .handle_get_seat_keyboard_workspace(seat) + .wrn("get_seat_keyboard_workspace")?, ClientMessage::SetDefaultWorkspaceCapture { capture } => { self.handle_set_default_workspace_capture(capture) } @@ -2092,6 +2120,12 @@ impl ConfigProxyHandler { ClientMessage::SetShowFloatPinIcon { show } => { self.handle_set_show_float_pin_icon(show) } + ClientMessage::GetConnectorActiveWorkspace { connector } => self + .handle_get_connector_active_workspace(connector) + .wrn("get_connector_active_workspace")?, + ClientMessage::GetConnectorWorkspaces { connector } => self + .handle_get_connector_workspaces(connector) + .wrn("get_connector_workspaces")?, } Ok(()) } diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 6366f110..b37978ba 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -401,6 +401,10 @@ impl WlSeatGlobal { self.cursor_user_group.latest_output() } + pub fn get_keyboard_output(&self) -> Option> { + self.keyboard_node.get().node_output() + } + pub fn set_workspace(&self, ws: &Rc) { let tl = match self.keyboard_node.get().node_toplevel() { Some(tl) => tl, diff --git a/src/tree.rs b/src/tree.rs index d35fb11d..41dd7890 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -122,7 +122,6 @@ pub trait Node: 'static { fn node_visit_children(&self, visitor: &mut dyn NodeVisitor); fn node_visible(&self) -> bool; fn node_absolute_position(&self) -> Rect; - #[expect(dead_code)] fn node_output(&self) -> Option>; fn node_child_title_changed(self: Rc, child: &dyn Node, title: &str) {