diff --git a/Cargo.lock b/Cargo.lock index c24216d..580959c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -365,7 +365,7 @@ dependencies = [ [[package]] name = "cosmic-client-toolkit" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=e491d91#e491d91d10cc0a6af725d733bada77ae413e459a" +source = "git+https://github.com/pop-os/cosmic-protocols#62986ea6ab3b6517f45395e7912f9bddc8dc94e4" dependencies = [ "cosmic-protocols", "smithay-client-toolkit", @@ -375,7 +375,7 @@ dependencies = [ [[package]] name = "cosmic-protocols" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-protocols?rev=e491d91#e491d91d10cc0a6af725d733bada77ae413e459a" +source = "git+https://github.com/pop-os/cosmic-protocols#62986ea6ab3b6517f45395e7912f9bddc8dc94e4" dependencies = [ "bitflags", "wayland-backend", diff --git a/Cargo.toml b/Cargo.toml index ca202da..e8e0a87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] calloop = "0.10.5" -cctk = { package = "cosmic-client-toolkit", git = "https://github.com/pop-os/cosmic-protocols", rev = "e491d91" } +cctk = { package = "cosmic-client-toolkit", git = "https://github.com/pop-os/cosmic-protocols" } futures-channel = "0.3.25" libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false, features = ["tokio", "wayland"] } tokio = "1.23.0" diff --git a/src/main.rs b/src/main.rs index 3d7b69c..e10f821 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,9 +53,9 @@ enum Msg { #[derive(Debug)] struct Workspace { name: String, - img: Option, + img_for_output: HashMap, handle: zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1, - output_name: String, + output_names: Vec, is_active: bool, } @@ -63,6 +63,7 @@ struct Workspace { struct Toplevel { handle: zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, info: ToplevelInfo, + output_name: Option, img: Option, } @@ -300,39 +301,42 @@ impl Application for App { wayland::Event::Workspaces(workspaces) => { let old_workspaces = mem::take(&mut self.workspaces); self.workspaces = Vec::new(); - for (output_name, workspace) in workspaces { + for (output_names, workspace) in workspaces { let is_active = workspace.state.contains(&WEnum::Value( zcosmic_workspace_handle_v1::State::Active, )); // XXX efficiency - let img = old_workspaces + let img_for_output = old_workspaces .iter() .find(|i| i.handle == workspace.handle) - .and_then(|i| i.img.clone()); + .map(|i| i.img_for_output.clone()) + .unwrap_or_default(); self.workspaces.push(Workspace { name: workspace.name, handle: workspace.handle, - output_name, - img, + output_names, + img_for_output, is_active, }); } self.update_capture_filter(); } - wayland::Event::NewToplevel(handle, info) => { + wayland::Event::NewToplevel(handle, output_name, info) => { println!("New toplevel: {info:?}"); self.toplevels.push(Toplevel { handle, + output_name, info, img: None, }); } - wayland::Event::UpdateToplevel(handle, info) => { + wayland::Event::UpdateToplevel(handle, output_name, info) => { if let Some(toplevel) = self.toplevels.iter_mut().find(|x| x.handle == handle) { + toplevel.output_name = output_name; toplevel.info = info; } } @@ -341,9 +345,9 @@ impl Application for App { self.toplevels.remove(idx); } } - wayland::Event::WorkspaceCapture(handle, image) => { + wayland::Event::WorkspaceCapture(handle, output_name, image) => { if let Some(workspace) = self.workspace_for_handle_mut(&handle) { - workspace.img = Some(image); + workspace.img_for_output.insert(output_name, image); } } wayland::Event::ToplevelCapture(handle, image) => { @@ -435,17 +439,21 @@ fn layer_surface<'a>(app: &'a App, surface: &'a LayerSurface) -> cosmic::Element workspaces_sidebar( app.workspaces .iter() - .filter(|i| i.output_name == surface.output_name), + .filter(|i| i.output_names.contains(&surface.output_name)), + &surface.output_name ), toplevel_previews(app.toplevels.iter().filter(|i| { + if i.output_name.as_ref() != Some(&surface.output_name) { + return false; + } + if let Some(workspace) = &i.info.workspace { - app.workspace_for_handle(workspace).map_or(false, |x| { - x.is_active && x.output_name == surface.output_name - }) + app.workspace_for_handle(workspace) + .map_or(false, |x| x.is_active) } else { false } - })), + })) ] .spacing(12) .height(iced::Length::Fill) @@ -460,7 +468,10 @@ fn close_button(on_press: Msg) -> cosmic::Element<'static, Msg> { .into() } -fn workspace_sidebar_entry(workspace: &Workspace) -> cosmic::Element { +fn workspace_sidebar_entry<'a>( + workspace: &'a Workspace, + output_name: &'a str, +) -> cosmic::Element<'a, Msg> { // TODO style let theme = if workspace.is_active { cosmic::theme::Button::Primary @@ -472,8 +483,9 @@ fn workspace_sidebar_entry(workspace: &Workspace) -> cosmic::Element { widget::button(widget::column![ widget::Image::new( workspace - .img - .clone() + .img_for_output + .get(output_name) + .cloned() .unwrap_or_else(|| widget::image::Handle::from_pixels( 1, 1, @@ -491,11 +503,16 @@ fn workspace_sidebar_entry(workspace: &Workspace) -> cosmic::Element { fn workspaces_sidebar<'a>( workspaces: impl Iterator, + output_name: &'a str, ) -> cosmic::Element<'a, Msg> { - widget::column(workspaces.map(workspace_sidebar_entry).collect()) - .width(iced::Length::Fill) - .height(iced::Length::Fill) - .into() + widget::column( + workspaces + .map(|w| workspace_sidebar_entry(w, output_name)) + .collect(), + ) + .width(iced::Length::Fill) + .height(iced::Length::Fill) + .into() // New workspace } diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 78521a7..f49e106 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -57,17 +57,20 @@ pub enum Event { ToplevelManager(zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1), WorkspaceManager(zcosmic_workspace_manager_v1::ZcosmicWorkspaceManagerV1), // XXX Output name rather than `WlOutput` - Workspaces(Vec<(String, cctk::workspace::Workspace)>), + Workspaces(Vec<(Vec, cctk::workspace::Workspace)>), WorkspaceCapture( zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1, + String, image::Handle, ), NewToplevel( zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, + Option, ToplevelInfo, ), UpdateToplevel( zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, + Option, ToplevelInfo, ), CloseToplevel(zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1), diff --git a/src/wayland/screencopy.rs b/src/wayland/screencopy.rs index d52ead1..805e583 100644 --- a/src/wayland/screencopy.rs +++ b/src/wayland/screencopy.rs @@ -1,7 +1,7 @@ use cctk::{ cosmic_protocols::screencopy::v1::client::zcosmic_screencopy_session_v1, screencopy::{BufferInfo, ScreencopyHandler, ScreencopyState}, - wayland_client::{protocol::wl_shm, Connection, QueueHandle, WEnum}, + wayland_client::{protocol::wl_shm, Connection, Proxy, QueueHandle, WEnum}, }; use super::{AppData, Buffer, Capture, CaptureSource, Event}; @@ -71,13 +71,20 @@ impl ScreencopyHandler for AppData { let mut buffer = capture.buffer.lock().unwrap(); let image = unsafe { buffer.as_mut().unwrap().to_image() }; - let event = match &capture.source { - CaptureSource::Toplevel(toplevel) => Event::ToplevelCapture(toplevel.clone(), image), - CaptureSource::Workspace(workspace, _) => { - Event::WorkspaceCapture(workspace.clone(), image) + match &capture.source { + CaptureSource::Toplevel(toplevel) => { + self.send_event(Event::ToplevelCapture(toplevel.clone(), image)) + } + CaptureSource::Workspace(workspace, output) => { + if let Some(Some(output_name)) = self.output_names.get(&output.id()) { + self.send_event(Event::WorkspaceCapture( + workspace.clone(), + output_name.clone(), + image, + )); + } } }; - self.send_event(event); session.destroy(); // Capture again on damage diff --git a/src/wayland/toplevel.rs b/src/wayland/toplevel.rs index e7dc293..e1e3949 100644 --- a/src/wayland/toplevel.rs +++ b/src/wayland/toplevel.rs @@ -5,7 +5,7 @@ use cctk::{ }, toplevel_info::{ToplevelInfoHandler, ToplevelInfoState}, toplevel_management::{ToplevelManagerHandler, ToplevelManagerState}, - wayland_client::{Connection, QueueHandle, WEnum}, + wayland_client::{Connection, Proxy, QueueHandle, WEnum}, }; use super::{AppData, CaptureSource, Event}; @@ -23,7 +23,15 @@ impl ToplevelInfoHandler for AppData { toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, ) { let info = self.toplevel_info_state.info(toplevel).unwrap(); - self.send_event(Event::NewToplevel(toplevel.clone(), info.clone())); + let output_name = info + .output + .as_ref() + .and_then(|o| self.output_names.get(&o.id()).cloned()?); + self.send_event(Event::NewToplevel( + toplevel.clone(), + output_name, + info.clone(), + )); self.add_capture_source(CaptureSource::Toplevel(toplevel.clone())); } @@ -35,7 +43,15 @@ impl ToplevelInfoHandler for AppData { toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, ) { let info = self.toplevel_info_state.info(toplevel).unwrap(); - self.send_event(Event::UpdateToplevel(toplevel.clone(), info.clone())); + let output_name = info + .output + .as_ref() + .and_then(|o| self.output_names.get(&o.id()).cloned()?); + self.send_event(Event::UpdateToplevel( + toplevel.clone(), + output_name, + info.clone(), + )); } fn toplevel_closed( diff --git a/src/wayland/workspace.rs b/src/wayland/workspace.rs index 36775bb..f013ada 100644 --- a/src/wayland/workspace.rs +++ b/src/wayland/workspace.rs @@ -18,11 +18,15 @@ impl WorkspaceHandler for AppData { for group in self.workspace_state.workspace_groups() { for workspace in &group.workspaces { - if let Some(output) = group.output.as_ref() { - if let Some(output_name) = self.output_names.get(&output.id()).unwrap().clone() - { - workspaces.push((output_name, workspace.clone())); + let output_names: Vec<_> = group + .outputs + .iter() + .filter_map(|output| self.output_names.get(&output.id()).cloned()?) + .collect(); + if !output_names.is_empty() { + workspaces.push((output_names, workspace.clone())); + for output in &group.outputs { self.add_capture_source(CaptureSource::Workspace( workspace.handle.clone(), output.clone(),