From 27e19828fd2f95d0072aa1b6b76c317535262993 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 3 Jan 2023 12:58:08 -0800 Subject: [PATCH] Use `cosmic-client-toolkit` helpers in workspace applet --- Cargo.lock | 2 +- cosmic-applet-workspaces/Cargo.toml | 2 +- cosmic-applet-workspaces/src/wayland.rs | 424 +++++++----------------- 3 files changed, 129 insertions(+), 299 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65f0eccf..f3fefc2d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -624,6 +624,7 @@ version = "0.1.0" dependencies = [ "anyhow", "calloop", + "cosmic-client-toolkit", "cosmic-protocols", "futures", "i18n-embed", @@ -634,7 +635,6 @@ dependencies = [ "once_cell", "pretty_env_logger", "rust-embed", - "smithay-client-toolkit", "wayland-backend", "wayland-client", "xdg", diff --git a/cosmic-applet-workspaces/Cargo.toml b/cosmic-applet-workspaces/Cargo.toml index db68a3f8..2a508865 100644 --- a/cosmic-applet-workspaces/Cargo.toml +++ b/cosmic-applet-workspaces/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] libcosmic = { git = "https://github.com/pop-os/libcosmic/", branch = "master", default-features = false, features = ["wayland", "applet"] } -sctk = { package = "smithay-client-toolkit", git = "https://github.com/Smithay/client-toolkit", rev = "3776d4a" } +cosmic-client-toolkit = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false } cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols", default-features = false, features = ["client"] } wayland-backend = {version = "0.1.0-beta.14", features = ["client_system"]} wayland-client = {version = "0.30.0-beta.14"} diff --git a/cosmic-applet-workspaces/src/wayland.rs b/cosmic-applet-workspaces/src/wayland.rs index fbd06032..f884e8e2 100644 --- a/cosmic-applet-workspaces/src/wayland.rs +++ b/cosmic-applet-workspaces/src/wayland.rs @@ -1,23 +1,24 @@ use calloop::channel::*; use cosmic::applet::cosmic_panel_config::CosmicPanelOuput; -use cosmic_protocols::workspace::v1::client::{ - zcosmic_workspace_group_handle_v1::{self, ZcosmicWorkspaceGroupHandleV1}, - zcosmic_workspace_handle_v1::{self, ZcosmicWorkspaceHandleV1}, - zcosmic_workspace_manager_v1::{self, ZcosmicWorkspaceManagerV1}, +use cosmic_client_toolkit::{ + sctk::{ + self, + event_loop::WaylandSource, + output::{OutputHandler, OutputState}, + registry::{ProvidesRegistryState, RegistryState}, + }, + workspace::{WorkspaceHandler, WorkspaceState}, }; +use cosmic_protocols::workspace::v1::client::zcosmic_workspace_handle_v1; use futures::{channel::mpsc, executor::block_on, SinkExt}; -use sctk::event_loop::WaylandSource; use std::{env, os::unix::net::UnixStream, path::PathBuf, str::FromStr, time::Duration}; use wayland_backend::client::ObjectId; use wayland_client::{ - event_created_child, - protocol::{ - wl_output::{self, WlOutput}, - wl_registry::{self, WlRegistry}, - }, + globals::registry_queue_init, + protocol::wl_output::{self, WlOutput}, ConnectError, Proxy, }; -use wayland_client::{Connection, Dispatch, QueueHandle}; +use wayland_client::{Connection, QueueHandle, WEnum}; #[derive(Debug, Clone)] pub enum WorkspaceEvent { @@ -42,7 +43,7 @@ pub fn spawn_workspaces(tx: mpsc::Sender) -> SyncSender name, @@ -51,7 +52,7 @@ pub fn spawn_workspaces(tx: mpsc::Sender) -> SyncSender::try_new().unwrap(); let loop_handle = event_loop.handle(); - let event_queue = conn.new_event_queue::(); + let (globals, event_queue) = registry_queue_init(&conn).unwrap(); let qhandle = event_queue.handle(); WaylandSource::new(event_queue) @@ -59,43 +60,56 @@ pub fn spawn_workspaces(tx: mpsc::Sender) -> SyncSender { - if let Some(w) = state.workspace_groups.iter().find_map(|g| { - g.workspaces.iter().find(|w| w.workspace_handle.id() == id) - }) { - w.workspace_handle.activate(); - state.workspace_manager.as_ref().unwrap().commit(); + if let Some(w) = state + .workspace_state + .workspace_groups() + .iter() + .find_map(|g| g.workspaces.iter().find(|w| w.handle.id() == id)) + { + w.handle.activate(); + state + .workspace_state + .workspace_manager() + .get() + .unwrap() + .commit(); } } Event::Msg(WorkspaceEvent::Scroll(v)) => { - if let Some((w_g, w_i)) = state.workspace_groups.iter().find_map(|g| { - if g.output != state.expected_output { - return None; - } - g.workspaces - .iter() - .position(|w| { - w.states - .contains(&zcosmic_workspace_handle_v1::State::Active) - }) - .map(|w_i| (g, w_i)) - }) { + if let Some((w_g, w_i)) = state + .workspace_state + .workspace_groups() + .iter() + .find_map(|g| { + if g.output != state.expected_output { + return None; + } + g.workspaces + .iter() + .position(|w| { + w.state.contains(&WEnum::Value( + zcosmic_workspace_handle_v1::State::Active, + )) + }) + .map(|w_i| (g, w_i)) + }) + { let max_w = w_g.workspaces.len().wrapping_sub(1); let d_i = if v > 0.0 { if w_i == max_w { @@ -111,15 +125,22 @@ pub fn spawn_workspaces(tx: mpsc::Sender) -> SyncSender { - if let Some(workspace_manager) = &mut state.workspace_manager { - for g in &mut state.workspace_groups { - g.workspace_group_handle.destroy(); + if let Ok(workspace_manager) = + state.workspace_state.workspace_manager().get() + { + for g in state.workspace_state.workspace_groups() { + g.handle.destroy(); } workspace_manager.stop(); } @@ -140,44 +161,52 @@ pub fn spawn_workspaces(tx: mpsc::Sender) -> SyncSender>, - wm_name: Option<(u32, WlRegistry)>, running: bool, tx: mpsc::Sender, configured_output: String, expected_output: Option, - workspace_manager: Option, - workspace_groups: Vec, + output_state: OutputState, + registry_state: RegistryState, + workspace_state: WorkspaceState, + have_workspaces: bool, } impl State { - // XXX pub fn workspace_list( &self, ) -> Vec<(String, Option, ObjectId)> { - self.workspace_groups + self.workspace_state + .workspace_groups() .iter() .filter_map(|g| { - // TODO remove none check when workspace groups receive output event - if g.output.is_none() || g.output == self.expected_output { + if g.output == self.expected_output { Some(g.workspaces.iter().map(|w| { ( w.name.clone(), - match &w.states { - x if x.contains(&zcosmic_workspace_handle_v1::State::Active) => { + match &w.state { + x if x.contains(&WEnum::Value( + zcosmic_workspace_handle_v1::State::Active, + )) => + { Some(zcosmic_workspace_handle_v1::State::Active) } - x if x.contains(&zcosmic_workspace_handle_v1::State::Urgent) => { + x if x.contains(&WEnum::Value( + zcosmic_workspace_handle_v1::State::Urgent, + )) => + { Some(zcosmic_workspace_handle_v1::State::Urgent) } - x if x.contains(&zcosmic_workspace_handle_v1::State::Hidden) => { + x if x.contains(&WEnum::Value( + zcosmic_workspace_handle_v1::State::Hidden, + )) => + { Some(zcosmic_workspace_handle_v1::State::Hidden) } _ => None, }, - w.workspace_handle.id(), + w.handle.id(), ) })) } else { @@ -189,260 +218,61 @@ impl State { } } -#[derive(Debug, Clone)] -struct WorkspaceGroup { - workspace_group_handle: ZcosmicWorkspaceGroupHandleV1, - output: Option, - workspaces: Vec, +impl ProvidesRegistryState for State { + fn registry(&mut self) -> &mut RegistryState { + &mut self.registry_state + } + sctk::registry_handlers![OutputState,]; } -#[derive(Debug, Clone)] -pub struct Workspace { - workspace_handle: ZcosmicWorkspaceHandleV1, - name: String, - coordinates: Vec, - states: Vec, -} +impl OutputHandler for State { + fn output_state(&mut self) -> &mut OutputState { + &mut self.output_state + } -impl Dispatch for State { - fn event( - state: &mut Self, - registry: &wl_registry::WlRegistry, - event: wl_registry::Event, - _: &(), - _: &Connection, - qh: &QueueHandle, + fn new_output( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + output: wl_output::WlOutput, ) { - if let wl_registry::Event::Global { - name, - interface, - version: _version, - } = event - { - match &interface[..] { - "zcosmic_workspace_manager_v1" => { - if let Some(outputs_to_handle) = state.outputs_to_handle.as_ref() { - if outputs_to_handle.is_empty() { - let workspace_manager = - registry.bind::(name, 1, qh, ()); - state.workspace_manager = Some(workspace_manager); - return; - } - } - // will be handled when outputs are done... - state.wm_name.replace((name, registry.clone())); - } - "wl_output" => { - let _output = registry.bind::(name, 4, qh, ()); - match state.outputs_to_handle.as_mut() { - Some(outputs_to_handle) => outputs_to_handle.push(_output), - None => { - state.outputs_to_handle.replace(vec![_output]); - } - }; - } - _ => {} + let info = self.output_state.info(&output).unwrap(); + if info.name.as_deref() == Some(&self.configured_output) { + self.expected_output = Some(output); + if self.have_workspaces { + let _ = block_on(self.tx.send(self.workspace_list())); } } } -} -impl Dispatch for State { - fn event( - state: &mut Self, - _: &ZcosmicWorkspaceManagerV1, - event: zcosmic_workspace_manager_v1::Event, - _: &(), - _: &Connection, - _: &QueueHandle, + fn update_output( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + _output: wl_output::WlOutput, ) { - match event { - zcosmic_workspace_manager_v1::Event::WorkspaceGroup { workspace_group } => { - state.workspace_groups.push(WorkspaceGroup { - workspace_group_handle: workspace_group, - output: None, - workspaces: Vec::new(), - }); - } - zcosmic_workspace_manager_v1::Event::Done => { - for group in &mut state.workspace_groups { - group.workspaces.sort_by(|w1, w2| { - w1.coordinates - .iter() - .zip(w2.coordinates.iter()) - .rev() - .skip_while(|(coord1, coord2)| coord1 == coord2) - .next() - .map(|(coord1, coord2)| coord1.cmp(coord2)) - .unwrap_or(std::cmp::Ordering::Equal) - }); - } - let _ = block_on(state.tx.send(state.workspace_list())); - } - zcosmic_workspace_manager_v1::Event::Finished => { - state.workspace_manager.take(); - } - _ => {} - } } - event_created_child!(State, ZcosmicWorkspaceManagerV1, [ - 0 => (ZcosmicWorkspaceGroupHandleV1, ()) - ]); -} - -impl Dispatch for State { - fn event( - state: &mut Self, - group: &ZcosmicWorkspaceGroupHandleV1, - event: zcosmic_workspace_group_handle_v1::Event, - _: &(), - _: &Connection, - _: &QueueHandle, + fn output_destroyed( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + _output: wl_output::WlOutput, ) { - match event { - zcosmic_workspace_group_handle_v1::Event::OutputEnter { output } => { - if let Some(group) = state - .workspace_groups - .iter_mut() - .find(|g| &g.workspace_group_handle == group) - { - group.output = Some(output); - } - } - zcosmic_workspace_group_handle_v1::Event::OutputLeave { output } => { - if let Some(group) = state.workspace_groups.iter_mut().find(|g| { - &g.workspace_group_handle == group && g.output.as_ref() == Some(&output) - }) { - group.output = None; - } - } - zcosmic_workspace_group_handle_v1::Event::Workspace { workspace } => { - if let Some(group) = state - .workspace_groups - .iter_mut() - .find(|g| &g.workspace_group_handle == group) - { - group.workspaces.push(Workspace { - workspace_handle: workspace, - name: String::new(), - coordinates: Vec::new(), - states: Vec::new(), - }) - } - } - zcosmic_workspace_group_handle_v1::Event::Remove => { - if let Some(group) = state - .workspace_groups - .iter() - .position(|g| &g.workspace_group_handle == group) - { - state.workspace_groups.remove(group); - } - } - _ => {} - } - } - - event_created_child!(State, ZcosmicWorkspaceGroupHandleV1, [ - 3 => (ZcosmicWorkspaceHandleV1, ()) - ]); -} - -impl Dispatch for State { - fn event( - state: &mut Self, - workspace: &ZcosmicWorkspaceHandleV1, - event: zcosmic_workspace_handle_v1::Event, - _: &(), - _: &Connection, - _: &QueueHandle, - ) { - match event { - zcosmic_workspace_handle_v1::Event::Name { name } => { - if let Some(w) = state.workspace_groups.iter_mut().find_map(|g| { - g.workspaces - .iter_mut() - .find(|w| &w.workspace_handle == workspace) - }) { - w.name = name; - } - } - zcosmic_workspace_handle_v1::Event::Coordinates { coordinates } => { - if let Some(w) = state.workspace_groups.iter_mut().find_map(|g| { - g.workspaces - .iter_mut() - .find(|w| &w.workspace_handle == workspace) - }) { - // wayland is host byte order - w.coordinates = coordinates - .chunks(4) - .map(|chunk| u32::from_ne_bytes(chunk.try_into().unwrap())) - .collect(); - } - } - zcosmic_workspace_handle_v1::Event::State { - state: workspace_state, - } => { - if let Some(w) = state.workspace_groups.iter_mut().find_map(|g| { - g.workspaces - .iter_mut() - .find(|w| &w.workspace_handle == workspace) - }) { - // wayland is host byte order - w.states = workspace_state - .chunks(4) - .map(|chunk| { - zcosmic_workspace_handle_v1::State::try_from(u32::from_ne_bytes( - chunk.try_into().unwrap(), - )) - .unwrap() - }) - .collect(); - } - } - zcosmic_workspace_handle_v1::Event::Remove => { - if let Some((g, w_i)) = state.workspace_groups.iter_mut().find_map(|g| { - g.workspaces - .iter_mut() - .position(|w| &w.workspace_handle == workspace) - .map(|p| (g, p)) - }) { - g.workspaces.remove(w_i); - } - } - _ => {} - } } } -impl Dispatch for State { - fn event( - state: &mut Self, - o: &WlOutput, - e: wl_output::Event, - _: &(), - _: &Connection, - qh: &QueueHandle, - ) { - match e { - wl_output::Event::Name { name } if name == state.configured_output => { - state.expected_output.replace(o.clone()); - // Necessary bc often the output is handled after the workspaces - let _ = block_on(state.tx.send(state.workspace_list())); - } - wl_output::Event::Done => { - let outputs_to_handle = state.outputs_to_handle.as_mut().unwrap(); - outputs_to_handle.retain(|o_to_handle| o != o_to_handle); - if outputs_to_handle.is_empty() { - if let Some((wm_name, registry)) = state.wm_name.as_ref() { - let workspace_manager = - registry.bind::(*wm_name, 1, qh, ()); - state.workspace_manager = Some(workspace_manager); - } - } - } - _ => {} // ignored - } +impl WorkspaceHandler for State { + fn workspace_state(&mut self) -> &mut WorkspaceState { + &mut self.workspace_state + } + + fn done(&mut self) { + self.have_workspaces = true; + let _ = block_on(self.tx.send(self.workspace_list())); } } + +cosmic_client_toolkit::delegate_workspace!(State); +sctk::delegate_output!(State); +sctk::delegate_registry!(State);