From 83baa6aadb216ff8e3fe2dfc8d336ffd42f4e6d3 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sat, 30 Jul 2022 11:22:40 +0200 Subject: [PATCH] wayland: add jay_workspace --- src/client/objects.rs | 10 ++-- src/compositor.rs | 1 + src/ifs.rs | 1 + src/ifs/jay_workspace.rs | 102 +++++++++++++++++++++++++++++++++++++++ src/state.rs | 31 +++--------- src/tasks/connector.rs | 4 ++ src/tree/output.rs | 12 ++++- src/tree/toplevel.rs | 1 + src/tree/workspace.rs | 18 +++++++ wire/jay_workspace.txt | 31 ++++++++++++ 10 files changed, 183 insertions(+), 28 deletions(-) create mode 100644 src/ifs/jay_workspace.rs create mode 100644 wire/jay_workspace.txt diff --git a/src/client/objects.rs b/src/client/objects.rs index 8477e992..98d3c4cb 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -7,6 +7,7 @@ use { zwp_primary_selection_source_v1::ZwpPrimarySelectionSourceV1, }, jay_output::JayOutput, + jay_workspace::JayWorkspace, wl_buffer::WlBuffer, wl_display::WlDisplay, wl_output::WlOutput, @@ -26,9 +27,9 @@ use { copyhashmap::{CopyHashMap, Locked}, }, wire::{ - JayOutputId, WlBufferId, WlDataSourceId, WlOutputId, WlPointerId, WlRegionId, - WlRegistryId, WlSeatId, WlSurfaceId, XdgPositionerId, XdgSurfaceId, XdgToplevelId, - XdgWmBaseId, ZwpPrimarySelectionSourceV1Id, + JayOutputId, JayWorkspaceId, WlBufferId, WlDataSourceId, WlOutputId, WlPointerId, + WlRegionId, WlRegistryId, WlSeatId, WlSurfaceId, XdgPositionerId, XdgSurfaceId, + XdgToplevelId, XdgWmBaseId, ZwpPrimarySelectionSourceV1Id, }, }, std::{cell::RefCell, mem, rc::Rc}, @@ -49,6 +50,7 @@ pub struct Objects { pub regions: CopyHashMap>, pub buffers: CopyHashMap>, pub jay_outputs: CopyHashMap>, + pub jay_workspaces: CopyHashMap>, pub pointers: CopyHashMap>, pub xdg_wm_bases: CopyHashMap>, pub seats: CopyHashMap>, @@ -74,6 +76,7 @@ impl Objects { regions: Default::default(), buffers: Default::default(), jay_outputs: Default::default(), + jay_workspaces: Default::default(), pointers: Default::default(), xdg_wm_bases: Default::default(), seats: Default::default(), @@ -103,6 +106,7 @@ impl Objects { self.regions.clear(); self.buffers.clear(); self.jay_outputs.clear(); + self.jay_workspaces.clear(); self.xdg_wm_bases.clear(); self.seats.clear(); self.pointers.clear(); diff --git a/src/compositor.rs b/src/compositor.rs index fff98dbb..7e9a1779 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -404,6 +404,7 @@ fn create_dummy_output(state: &Rc) { fullscreen: Default::default(), visible_on_desired_output: Default::default(), desired_output: CloneCell::new(dummy_output.global.output_id.clone()), + jay_workspaces: Default::default(), }); dummy_workspace.output_link.set(Some( dummy_output.workspaces.add_last(dummy_workspace.clone()), diff --git a/src/ifs.rs b/src/ifs.rs index cec5d32c..ad69d68b 100644 --- a/src/ifs.rs +++ b/src/ifs.rs @@ -9,6 +9,7 @@ pub mod jay_pointer; pub mod jay_render_ctx; pub mod jay_screenshot; pub mod jay_seat_events; +pub mod jay_workspace; pub mod org_kde_kwin_server_decoration; pub mod org_kde_kwin_server_decoration_manager; pub mod wl_buffer; diff --git a/src/ifs/jay_workspace.rs b/src/ifs/jay_workspace.rs new file mode 100644 index 00000000..2a91fd60 --- /dev/null +++ b/src/ifs/jay_workspace.rs @@ -0,0 +1,102 @@ +use { + crate::{ + client::{Client, ClientError}, + leaks::Tracker, + object::Object, + tree::{OutputNode, WorkspaceNode}, + utils::{ + buffd::{MsgParser, MsgParserError}, + clonecell::CloneCell, + }, + wire::{jay_workspace::*, JayWorkspaceId}, + }, + std::rc::Rc, + thiserror::Error, +}; + +pub struct JayWorkspace { + pub id: JayWorkspaceId, + pub client: Rc, + pub workspace: CloneCell>>, + pub tracker: Tracker, +} + +#[allow(dead_code)] +impl JayWorkspace { + pub fn send_linear_id(&self, ws: &WorkspaceNode) { + self.client.event(LinearId { + self_id: self.id, + linear_id: ws.id.raw(), + }); + } + + pub fn send_name(&self, ws: &WorkspaceNode) { + self.client.event(Name { + self_id: self.id, + name: &ws.name, + }); + } + + pub fn send_destroyed(&self) { + self.client.event(Destroyed { self_id: self.id }); + } + + pub fn send_done(&self) { + self.client.event(Done { self_id: self.id }); + } + + pub fn send_output(&self, output: &OutputNode) { + self.client.event(Output { + self_id: self.id, + global_name: output.global.name.raw(), + }); + } + + pub fn send_visible(&self, visible: bool) { + self.client.event(Visible { + self_id: self.id, + visible: visible as _, + }); + } + + fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), JayWorkspaceError> { + let _req: Destroy = self.client.parse(self, parser)?; + self.remove_from_node(); + self.client.remove_obj(self)?; + Ok(()) + } + + fn remove_from_node(&self) { + if let Some(ws) = self.workspace.take() { + ws.jay_workspaces.remove(&(self.client.id, self.id)); + } + } +} + +object_base! { + JayWorkspace; + + DESTROY => destroy, +} + +impl Object for JayWorkspace { + fn num_requests(&self) -> u32 { + DESTROY + 1 + } + + fn break_loops(&self) { + self.remove_from_node(); + } +} + +dedicated_add_obj!(JayWorkspace, JayWorkspaceId, jay_workspaces); + +#[derive(Debug, Error)] +pub enum JayWorkspaceError { + #[error("Parsing failed")] + MsgParserError(Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(JayWorkspaceError, MsgParserError); +efrom!(JayWorkspaceError, ClientError); diff --git a/src/state.rs b/src/state.rs index 167fc5a2..b6c2fd28 100644 --- a/src/state.rs +++ b/src/state.rs @@ -434,15 +434,15 @@ impl State { } pub fn show_workspace(&self, seat: &Rc, name: &str) { - let output = match self.workspaces.get(name) { + let (output, ws) = match self.workspaces.get(name) { Some(ws) => { let output = ws.output.get(); let did_change = output.show_workspace(&ws); - ws.node_do_focus(seat, Direction::Unspecified); + ws.clone().node_do_focus(seat, Direction::Unspecified); if !did_change { return; } - output + (output, ws) } _ => { let output = seat.get_output(); @@ -450,29 +450,12 @@ impl State { log::warn!("Not showing workspace because seat is on dummy output"); return; } - let workspace = Rc::new(WorkspaceNode { - id: self.node_ids.next(), - is_dummy: false, - output: CloneCell::new(output.clone()), - position: Cell::new(Default::default()), - container: Default::default(), - stacked: Default::default(), - seat_state: Default::default(), - name: name.to_string(), - output_link: Cell::new(None), - visible: Cell::new(false), - fullscreen: Default::default(), - visible_on_desired_output: Cell::new(false), - desired_output: CloneCell::new(output.global.output_id.clone()), - }); - workspace - .output_link - .set(Some(output.workspaces.add_last(workspace.clone()))); - output.show_workspace(&workspace); - self.workspaces.set(name.to_string(), workspace); - output + let ws = output.create_workspace(name); + output.show_workspace(&ws); + (output, ws) } }; + ws.flush_jay_workspaces(); output.update_render_data(); self.tree_changed(); // let seats = self.globals.seats.lock(); diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index c2a235a6..17344f86 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -166,6 +166,7 @@ impl ConnectorHandler { } else { ws.set_visible(false); } + ws.flush_jay_workspaces(); if let Some(visible) = source.node.workspace.get() { if visible.id == ws.id { source.node.workspace.take(); @@ -175,6 +176,7 @@ impl ConnectorHandler { if source.node.workspace.get().is_none() { if let Some(ws) = source.node.workspaces.first() { source.node.show_workspace(&ws); + ws.flush_jay_workspaces(); } } source.node.update_render_data(); @@ -182,6 +184,7 @@ impl ConnectorHandler { if on.workspace.get().is_none() { if let Some(ws) = on.workspaces.first() { on.show_workspace(&ws); + ws.flush_jay_workspaces(); } } } @@ -239,6 +242,7 @@ impl ConnectorHandler { } else if ws.visible.get() { ws.set_visible(false); } + ws.flush_jay_workspaces(); } target.update_render_data(); self.state.tree_changed(); diff --git a/src/tree/output.rs b/src/tree/output.rs index bb68f611..7fe90224 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -237,6 +237,7 @@ impl OutputNode { fullscreen: Default::default(), visible_on_desired_output: Cell::new(false), desired_output: CloneCell::new(self.global.output_id.clone()), + jay_workspaces: Default::default(), }); self.state.workspaces.set(name, workspace.clone()); workspace @@ -254,10 +255,16 @@ impl OutputNode { return false; } collect_kb_foci2(old.clone(), &mut seats); - old.set_visible(false); if old.is_empty() { + for jw in old.jay_workspaces.lock().values() { + jw.send_destroyed(); + jw.workspace.set(None); + } old.clear(); self.state.workspaces.remove(&old.name); + } else { + old.set_visible(false); + old.flush_jay_workspaces(); } } ws.set_visible(true); @@ -286,6 +293,7 @@ impl OutputNode { fullscreen: Default::default(), visible_on_desired_output: Cell::new(false), desired_output: CloneCell::new(self.global.output_id.clone()), + jay_workspaces: Default::default(), }); ws.output_link .set(Some(self.workspaces.add_last(ws.clone()))); @@ -581,6 +589,7 @@ impl Node for OutputNode { return; }; self.show_workspace(&ws); + ws.flush_jay_workspaces(); self.update_render_data(); self.state.tree_changed(); } @@ -615,6 +624,7 @@ impl Node for OutputNode { if !self.show_workspace(&ws) { return; } + ws.flush_jay_workspaces(); ws.deref() .clone() .node_do_focus(seat, Direction::Unspecified); diff --git a/src/tree/toplevel.rs b/src/tree/toplevel.rs index dea198cb..8d8cfbaf 100644 --- a/src/tree/toplevel.rs +++ b/src/tree/toplevel.rs @@ -316,6 +316,7 @@ impl ToplevelData { fd.workspace.fullscreen.take(); if node.node_visible() { fd.workspace.set_visible(true); + fd.workspace.flush_jay_workspaces(); } if fd.placeholder.is_destroyed() { state.map_tiled(node); diff --git a/src/tree/workspace.rs b/src/tree/workspace.rs index 1f7d2a57..904981dd 100644 --- a/src/tree/workspace.rs +++ b/src/tree/workspace.rs @@ -1,7 +1,9 @@ use { crate::{ + client::ClientId, cursor::KnownCursor, ifs::{ + jay_workspace::JayWorkspace, wl_output::OutputId, wl_seat::{NodeSeatState, WlSeatGlobal}, wl_surface::WlSurface, @@ -15,8 +17,10 @@ use { }, utils::{ clonecell::CloneCell, + copyhashmap::CopyHashMap, linkedlist::{LinkedList, LinkedNode}, }, + wire::JayWorkspaceId, }, std::{cell::Cell, fmt::Debug, ops::Deref, rc::Rc}, }; @@ -37,6 +41,7 @@ pub struct WorkspaceNode { pub fullscreen: CloneCell>>, pub visible_on_desired_output: Cell, pub desired_output: CloneCell>, + pub jay_workspaces: CopyHashMap<(ClientId, JayWorkspaceId), Rc>, } impl WorkspaceNode { @@ -44,10 +49,14 @@ impl WorkspaceNode { self.container.set(None); self.output_link.set(None); self.fullscreen.set(None); + self.jay_workspaces.clear(); } pub fn set_output(&self, output: &Rc) { self.output.set(output.clone()); + for jw in self.jay_workspaces.lock().values() { + jw.send_output(output); + } struct OutputSetter<'a>(&'a Rc); impl NodeVisitorBase for OutputSetter<'_> { fn visit_surface(&mut self, node: &Rc) { @@ -85,7 +94,16 @@ impl WorkspaceNode { } } + pub fn flush_jay_workspaces(&self) { + for jw in self.jay_workspaces.lock().values() { + jw.send_done(); + } + } + pub fn set_visible(&self, visible: bool) { + for jw in self.jay_workspaces.lock().values() { + jw.send_visible(visible); + } self.visible.set(visible); if let Some(fs) = self.fullscreen.get() { fs.tl_set_visible(visible); diff --git a/wire/jay_workspace.txt b/wire/jay_workspace.txt new file mode 100644 index 00000000..0575531b --- /dev/null +++ b/wire/jay_workspace.txt @@ -0,0 +1,31 @@ +# requests + +msg destroy = 0 { + +} + +# events + +msg linear_id = 0 { + linear_id: u32, +} + +msg name = 1 { + name: str, +} + +msg destroyed = 2 { + +} + +msg done = 3 { + +} + +msg output = 4 { + global_name: u32, +} + +msg visible = 5 { + visible: u32, +}