diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 2dc95bd7..68d0310e 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -3,6 +3,4 @@ mod drm; pub use drm::*; #[cfg(feature = "experimental")] -mod workspace; -#[cfg(feature = "experimental")] -pub use workspace::*; \ No newline at end of file +pub mod workspace; diff --git a/src/wayland/workspace.rs b/src/wayland/workspace.rs index 85f17ce2..69a88fe1 100644 --- a/src/wayland/workspace.rs +++ b/src/wayland/workspace.rs @@ -5,7 +5,9 @@ // and avoid exposing internal details. // // You can use all the types from my_protocol as if they went from `wayland_client::protocol`. -pub use generated::server::{zext_workspace_manager_v1, zext_workspace_group_handle_v1, zext_workspace_handle_v1}; +pub use generated::server::{ + zext_workspace_group_handle_v1, zext_workspace_handle_v1, zext_workspace_manager_v1, +}; mod generated { // The generated code tends to trigger a lot of warnings @@ -28,20 +30,21 @@ mod generated { } } -use std::{ - cell::RefCell, - collections::HashSet, - fmt, - sync::{Arc, Mutex, Weak}, +pub use self::generated::server::zext_workspace_handle_v1::State; +use self::generated::server::{ + zext_workspace_group_handle_v1::ZextWorkspaceGroupHandleV1, + zext_workspace_handle_v1::ZextWorkspaceHandleV1, + zext_workspace_manager_v1::ZextWorkspaceManagerV1, }; use smithay::{ reexports::wayland_server::{Client, DispatchData, Display, Filter, Global, Main}, wayland::output::Output, }; -use self::generated::server::{ - zext_workspace_manager_v1::ZextWorkspaceManagerV1, - zext_workspace_group_handle_v1::ZextWorkspaceGroupHandleV1, - zext_workspace_handle_v1::{ZextWorkspaceHandleV1, State}, +use std::{ + cell::RefCell, + collections::HashSet, + fmt, + sync::{Arc, Mutex, Weak}, }; #[derive(Debug, Clone)] @@ -52,7 +55,10 @@ pub struct WorkspaceManager { struct WorkspaceManagerInner { instances: Vec>, groups: Vec>>, - commit: Box)>, DispatchData) + 'static>, + commit: Box< + dyn FnMut(&WorkspaceGroup, Vec<(&Workspace, Vec)>, DispatchData) + + 'static, + >, } impl fmt::Debug for WorkspaceManagerInner { @@ -64,7 +70,7 @@ impl fmt::Debug for WorkspaceManagerInner { } } -pub fn init_ext_workspace( +pub fn init_ext_workspace( display: &mut Display, commit: C, client_filter: F, @@ -80,27 +86,41 @@ where })); let inner_clone = inner.clone(); - let filter = Filter::new(move |(main, _version): (Main, u32), _, _| { - let inner = inner_clone.clone(); - main.quick_assign(move |main, request, mut ddata| { - match request { + let filter = Filter::new( + move |(main, _version): (Main, u32), _, _| { + let inner = inner_clone.clone(); + main.quick_assign(move |main, request, mut ddata| match request { zext_workspace_manager_v1::Request::Commit => { if let Some(client) = main.as_ref().client() { let mut inner_guard = inner.lock().unwrap(); let inner = &mut *inner_guard; for group in inner.groups.iter() { let group_inner = group.lock().unwrap(); - let mut changes = group_inner.workspaces + let mut changes = group_inner + .workspaces .iter() .flat_map(|x| x.upgrade()) .flat_map(|w| { let workspace_inner = w.lock().unwrap(); - let operations = workspace_inner.instances + let operations = workspace_inner + .instances .iter() - .find(|w_instance| w_instance.as_ref().client().map(|c| c == client).unwrap_or(false)) - .and_then(|w_instance| w_instance.as_ref().user_data().get::()) + .find(|w_instance| { + w_instance + .as_ref() + .client() + .map(|c| c == client) + .unwrap_or(false) + }) + .and_then(|w_instance| { + w_instance + .as_ref() + .user_data() + .get::() + }) .and_then(|user_data| { - let operations = std::mem::take( &mut *user_data.borrow_mut()); + let operations = + std::mem::take(&mut *user_data.borrow_mut()); if !operations.is_empty() { Some(operations) } else { @@ -109,67 +129,84 @@ where }); if let Some(ops) = operations { std::mem::drop(workspace_inner); - Some((Workspace{ inner: w }, ops)) + Some((Workspace { inner: w }, ops)) } else { None } }) .collect::)>>(); - + std::mem::drop(group_inner); let group = WorkspaceGroup { inner: group.clone(), }; - let borrowed_changes = changes.iter_mut().map(|(w, p)| (&*w, std::mem::take(p))).collect(); + let borrowed_changes = changes + .iter_mut() + .map(|(w, p)| (&*w, std::mem::take(p))) + .collect(); (inner.commit)(&group, borrowed_changes, ddata.reborrow()); } } - }, + } zext_workspace_manager_v1::Request::Stop => { let mut inner = inner.lock().unwrap(); inner.instances.retain(|m| **m != *main); - }, - } - }); + } + }); - let inner_guard = inner_clone.lock().unwrap(); - if let Some(client) = main.as_ref().client() { - for group in inner_guard.groups.iter() { - if let Some(new_instance) = WorkspaceGroup::create_instance(&client, group.clone()) { - main.workspace_group(&*new_instance); + let mut inner_guard = inner_clone.lock().unwrap(); + if let Some(client) = main.as_ref().client() { + for group in inner_guard.groups.iter() { + if let Some(new_instance) = + WorkspaceGroup::create_instance(&client, group.clone()) + { + main.workspace_group(&*new_instance); - let mut group_inner_guard = group.lock().unwrap(); - group_inner_guard.instances.push(new_instance); - for workspace in group_inner_guard.workspaces.iter() { - if let Some(workspace) = workspace.upgrade() { - let workspace_clone = workspace.clone(); - if let Some(new_instance) = Workspace::create_instance(&client, workspace_clone) { - let mut inner = workspace.lock().unwrap(); - inner.instances.push(new_instance); - inner.send(&client); - } + let mut group_inner_guard = group.lock().unwrap(); + for output in group_inner_guard.outputs.iter() { + output.with_client_outputs(client.clone(), |output| { + new_instance.output_enter(output) + }); } + for workspace in group_inner_guard.workspaces.iter() { + if let Some(workspace) = workspace.upgrade() { + let workspace_clone = workspace.clone(); + if let Some(new_ws_instance) = + Workspace::create_instance(&client, workspace_clone) + { + new_instance.workspace(&*new_ws_instance); + let mut inner = workspace.lock().unwrap(); + inner.instances.push(new_ws_instance); + inner.send(&client); + } + } + } + group_inner_guard.instances.push(new_instance); } } + main.done(); } - } - }); + + inner_guard.instances.push(main); + }, + ); let global = display.create_global_with_filter(1, filter, client_filter); - ( - WorkspaceManager { - inner, - }, global - ) + (WorkspaceManager { inner }, global) } impl WorkspaceManager { - pub fn new_group(&self, create_new_workspace: F, outputs: impl Iterator) -> WorkspaceGroup + pub fn new_group( + &self, + create_new_workspace: F, + outputs: impl Iterator, + ) -> WorkspaceGroup where F: Fn(&WorkspaceGroup, String, DispatchData) + 'static, { let mut inner = self.inner.lock().unwrap(); - let create_new_workspace = Arc::new(Box::new(create_new_workspace) as Box); + let create_new_workspace = Arc::new(Box::new(create_new_workspace) + as Box); let group_inner = Arc::new(Mutex::new(WorkspaceGroupInner { instances: Vec::new(), outputs: outputs.collect(), @@ -181,21 +218,25 @@ impl WorkspaceManager { if let Some(client) = instance.as_ref().client() { if let Some(group) = WorkspaceGroup::create_instance(&client, group_inner.clone()) { instance.workspace_group(&*group); - group_inner.lock().unwrap().instances.push(group); + let mut group_inner_guard = group_inner.lock().unwrap(); + for output in group_inner_guard.outputs.iter() { + output.with_client_outputs(client.clone(), |output| { + group.output_enter(output) + }); + } + group_inner_guard.instances.push(group); } } instance.done(); } inner.groups.push(group_inner.clone()); - WorkspaceGroup { - inner: group_inner, - } + WorkspaceGroup { inner: group_inner } } pub fn update_outputs(&self, mut update: F) where - F: FnMut(&WorkspaceGroup, &mut HashSet) + F: FnMut(&WorkspaceGroup, &mut HashSet), { let inner = self.inner.lock().unwrap(); for group in inner.groups.iter() { @@ -210,14 +251,18 @@ impl WorkspaceManager { for output in previous_outputs.difference(&group_inner.outputs) { for instance in group_inner.instances.iter() { if let Some(client) = instance.as_ref().client() { - output.with_client_outputs(client.clone(), |output| instance.output_leave(output)); + output.with_client_outputs(client.clone(), |output| { + instance.output_leave(output) + }); } } } for output in group_inner.outputs.difference(&previous_outputs) { for instance in group_inner.instances.iter() { if let Some(client) = instance.as_ref().client() { - output.with_client_outputs(client.clone(), |output| instance.output_enter(output)); + output.with_client_outputs(client.clone(), |output| { + instance.output_enter(output) + }); } } } @@ -230,7 +275,11 @@ impl WorkspaceManager { pub fn remove_group(&self, group: &WorkspaceGroup) { let mut inner = self.inner.lock().unwrap(); // grr I want drain_filter - if let Some(pos) = inner.groups.iter().position(|x| Arc::ptr_eq(x, &group.inner)) { + if let Some(pos) = inner + .groups + .iter() + .position(|x| Arc::ptr_eq(x, &group.inner)) + { let group = inner.groups.remove(pos); let inner = group.lock().unwrap(); for instance in inner.instances.iter() { @@ -238,6 +287,12 @@ impl WorkspaceManager { } } } + + pub fn done(&self) { + for instance in self.inner.lock().unwrap().instances.iter() { + instance.done(); + } + } } #[derive(Debug)] @@ -245,6 +300,12 @@ pub struct WorkspaceGroup { inner: Arc>, } +impl PartialEq for WorkspaceGroup { + fn eq(&self, other: &WorkspaceGroup) -> bool { + Arc::ptr_eq(&self.inner, &other.inner) + } +} + struct WorkspaceGroupInner { instances: Vec>, outputs: HashSet, @@ -263,8 +324,7 @@ impl fmt::Debug for WorkspaceGroupInner { } impl WorkspaceGroup { - pub fn create_workspace(&self, name: String) -> Workspace - { + pub fn create_workspace(&self, name: String) -> Workspace { let mut inner = self.inner.lock().unwrap(); let workspace_inner = Arc::new(Mutex::new(WorkspaceInner { instances: Vec::new(), @@ -278,11 +338,13 @@ impl WorkspaceGroup { for instance in inner.instances.iter() { if let Some(client) = instance.as_ref().client() { let workspace_inner_clone = workspace_inner.clone(); - if let Some(workspace) = Workspace::create_instance(&client, workspace_inner_clone) { + if let Some(workspace) = Workspace::create_instance(&client, workspace_inner_clone) + { + instance.workspace(&*workspace); let mut workspace_inner_guard = workspace_inner.lock().unwrap(); workspace_inner_guard.instances.push(workspace); workspace_inner_guard.send(&client); - } + } } } @@ -291,26 +353,40 @@ impl WorkspaceGroup { } } - fn create_instance(client: &Client, group_inner: Arc>) -> Option> { + pub fn belongs(&self, workspace: &Workspace) -> bool { + self.inner + .lock() + .unwrap() + .workspaces + .iter() + .flat_map(|x| x.upgrade()) + .any(|w| Arc::ptr_eq(&w, &workspace.inner)) + } + + fn create_instance( + client: &Client, + group_inner: Arc>, + ) -> Option> { if let Some(group) = client.create_resource::(1) { - let group_inner_guard = group_inner.lock().unwrap(); - for output in group_inner_guard.outputs.iter() { - output.with_client_outputs(client.clone(), |output| group.output_enter(output)); - } - let group_inner_clone = group_inner.clone(); - group.quick_assign(move |group, request, ddata| { - match request { - zext_workspace_group_handle_v1::Request::CreateWorkspace { workspace } => { - let callback = group_inner_clone.lock().unwrap().create_new_workspace.clone(); - let group = WorkspaceGroup { - inner: group_inner_clone.clone(), - }; - callback(&group, workspace, ddata); - }, - zext_workspace_group_handle_v1::Request::Destroy => { - group_inner_clone.lock().unwrap().instances.retain(|g| *g != group); - } + group.quick_assign(move |group, request, ddata| match request { + zext_workspace_group_handle_v1::Request::CreateWorkspace { workspace } => { + let callback = group_inner_clone + .lock() + .unwrap() + .create_new_workspace + .clone(); + let group = WorkspaceGroup { + inner: group_inner_clone.clone(), + }; + callback(&group, workspace, ddata); + } + zext_workspace_group_handle_v1::Request::Destroy => { + group_inner_clone + .lock() + .unwrap() + .instances + .retain(|g| *g != group); } }); Some(group) @@ -325,17 +401,22 @@ pub struct Workspace { inner: Arc>, } +impl PartialEq for Workspace { + fn eq(&self, other: &Workspace) -> bool { + Arc::ptr_eq(&self.inner, &other.inner) + } +} + #[derive(Debug)] struct WorkspaceInner { instances: Vec>, name: String, states: Vec, - coordinates: Vec, + coordinates: Vec, } type WorkspaceUserdata = RefCell>; - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum PendingOperation { Activate, @@ -347,7 +428,7 @@ impl Workspace { pub fn name(&self) -> String { self.inner.lock().unwrap().name.clone() } - + pub fn set_name(&self, name: String) { let mut inner = self.inner.lock().unwrap(); for instance in inner.instances.iter() { @@ -364,35 +445,67 @@ impl Workspace { let mut inner = self.inner.lock().unwrap(); inner.states.push(state); for instance in inner.instances.iter() { - instance.state(inner.states.iter().map(|s| s.to_raw() as u8).collect()); - }; + let states = { + let mut states = inner.states.clone(); + let ptr = states.as_mut_ptr(); + let len = states.len(); + let cap = states.capacity(); + ::std::mem::forget(states); + unsafe { Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4) } + }; + instance.state(states); + } } pub fn remove_state(&self, state: State) { let mut inner = self.inner.lock().unwrap(); inner.states.retain(|s| *s != state); for instance in inner.instances.iter() { - instance.state(inner.states.iter().map(|s| s.to_raw() as u8).collect()); - }; - } - - pub fn set_states(&self, states: impl Iterator) { - let mut inner = self.inner.lock().unwrap(); - inner.states = states.collect(); - for instance in inner.instances.iter() { - instance.state(inner.states.iter().map(|s| s.to_raw() as u8).collect()); + let states = { + let mut states = inner.states.clone(); + let ptr = states.as_mut_ptr(); + let len = states.len(); + let cap = states.capacity(); + ::std::mem::forget(states); + unsafe { Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4) } + }; + instance.state(states); } } - pub fn coordinates(&self) -> Vec { + pub fn set_states(&self, states: impl Iterator) { + let mut inner = self.inner.lock().unwrap(); + inner.states = states.collect(); + for instance in inner.instances.iter() { + let states = { + let mut states = inner.states.clone(); + let ptr = states.as_mut_ptr(); + let len = states.len(); + let cap = states.capacity(); + ::std::mem::forget(states); + unsafe { Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4) } + }; + instance.state(states); + } + } + + pub fn coordinates(&self) -> Vec { self.inner.lock().unwrap().coordinates.clone() } - pub fn set_coordinates(&self, coordinates: impl Iterator) { + pub fn set_coordinates(&self, coordinates: impl Iterator) { let mut inner = self.inner.lock().unwrap(); inner.coordinates = coordinates.collect(); for instances in inner.instances.iter() { - instances.coordinates(inner.coordinates.clone()); + let coords = { + let mut coords = inner.coordinates.clone(); + let ptr = coords.as_mut_ptr(); + let len = coords.len(); + let cap = coords.capacity(); + ::std::mem::forget(coords); + unsafe { Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4) } + }; + instances.coordinates(coords); } } @@ -402,31 +515,48 @@ impl Workspace { } } - fn create_instance(client: &Client, workspace_inner_clone: Arc>) -> Option> { + fn create_instance( + client: &Client, + workspace_inner_clone: Arc>, + ) -> Option> { if let Some(workspace) = client.create_resource::(1) { - workspace.quick_assign(move |workspace, request, _| { - match request { - zext_workspace_handle_v1::Request::Activate => { - let user_data = workspace.as_ref().user_data(); - user_data.set(|| -> WorkspaceUserdata { RefCell::new(Vec::new()) }); - user_data.get::().unwrap().borrow_mut().push(PendingOperation::Activate); - }, - zext_workspace_handle_v1::Request::Deactivate => { - let user_data = workspace.as_ref().user_data(); - user_data.set(|| -> WorkspaceUserdata { RefCell::new(Vec::new()) }); - user_data.get::().unwrap().borrow_mut().push(PendingOperation::Deactivate); - }, - zext_workspace_handle_v1::Request::Remove => { - let user_data = workspace.as_ref().user_data(); - user_data.set(|| -> WorkspaceUserdata { RefCell::new(Vec::new()) }); - user_data.get::().unwrap().borrow_mut().push(PendingOperation::Remove); - }, - zext_workspace_handle_v1::Request::Destroy => { - workspace_inner_clone.lock().unwrap().instances.retain(|w| **w != *workspace); - }, + workspace.quick_assign(move |workspace, request, _| match request { + zext_workspace_handle_v1::Request::Activate => { + let user_data = workspace.as_ref().user_data(); + user_data.set(|| -> WorkspaceUserdata { RefCell::new(Vec::new()) }); + user_data + .get::() + .unwrap() + .borrow_mut() + .push(PendingOperation::Activate); + } + zext_workspace_handle_v1::Request::Deactivate => { + let user_data = workspace.as_ref().user_data(); + user_data.set(|| -> WorkspaceUserdata { RefCell::new(Vec::new()) }); + user_data + .get::() + .unwrap() + .borrow_mut() + .push(PendingOperation::Deactivate); + } + zext_workspace_handle_v1::Request::Remove => { + let user_data = workspace.as_ref().user_data(); + user_data.set(|| -> WorkspaceUserdata { RefCell::new(Vec::new()) }); + user_data + .get::() + .unwrap() + .borrow_mut() + .push(PendingOperation::Remove); + } + zext_workspace_handle_v1::Request::Destroy => { + workspace_inner_clone + .lock() + .unwrap() + .instances + .retain(|w| **w != *workspace); } }); - Some(workspace) + Some(workspace) } else { None } @@ -435,10 +565,30 @@ impl Workspace { impl WorkspaceInner { fn send(&self, client: &Client) { - if let Some(instance) = self.instances.iter().find(|w| w.as_ref().client().map(|c| &c == client).unwrap_or(false)) { + if let Some(instance) = self + .instances + .iter() + .find(|w| w.as_ref().client().map(|c| &c == client).unwrap_or(false)) + { instance.name(self.name.clone()); - instance.state(self.states.iter().map(|x| x.to_raw() as u8).collect()); - instance.coordinates(self.coordinates.clone()); + let states = { + let mut states = self.states.clone(); + let ptr = states.as_mut_ptr(); + let len = states.len(); + let cap = states.capacity(); + ::std::mem::forget(states); + unsafe { Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4) } + }; + instance.state(states); + let coords = { + let mut coords = self.coordinates.clone(); + let ptr = coords.as_mut_ptr(); + let len = coords.len(); + let cap = coords.capacity(); + ::std::mem::forget(coords); + unsafe { Vec::from_raw_parts(ptr as *mut u8, len * 4, cap * 4) } + }; + instance.coordinates(coords); } } }