diff --git a/src/main.rs b/src/main.rs index ce192d4..1cb7e9e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,9 +81,9 @@ enum Msg { #[derive(Debug)] struct Workspace { name: String, - img_for_output: HashMap, + img_for_output: HashMap, handle: zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1, - output_names: Vec, + outputs: HashSet, is_active: bool, } @@ -91,13 +91,11 @@ struct Workspace { struct Toplevel { handle: zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, info: ToplevelInfo, - output_names: HashSet, img: Option, } #[derive(Clone)] struct Output { - // Output, on the `iced_sctk` Wayland connection handle: wl_output::WlOutput, name: String, width: i32, @@ -105,16 +103,17 @@ struct Output { } struct LayerSurface { - // Output, on the `iced_sctk` Wayland connection output: wl_output::WlOutput, - output_name: String, // for transitions, would need windows in more than one workspace? But don't capture all of // them all the time every frame. } #[derive(Clone, Debug)] enum DragSurface { - Workspace { name: String, output_name: String }, + Workspace { + name: String, + output: wl_output::WlOutput, + }, } #[derive(Default)] @@ -163,7 +162,6 @@ impl App { fn create_surface( &mut self, output: wl_output::WlOutput, - output_name: String, width: i32, height: i32, ) -> Command { @@ -172,7 +170,6 @@ impl App { id, LayerSurface { output: output.clone(), - output_name, }, ); get_layer_surface(SctkLayerSurfaceSettings { @@ -216,9 +213,7 @@ impl App { let cmd = Command::batch( outputs .into_iter() - .map(|output| { - self.create_surface(output.handle, output.name, output.width, output.height) - }) + .map(|output| self.create_surface(output.handle, output.width, output.height)) .collect::>(), ); self.update_capture_filter(); @@ -246,7 +241,7 @@ impl App { if self.visible { // XXX handle on wrong connection capture_filter.workspaces_on_outputs = - self.outputs.iter().map(|x| x.name.clone()).collect(); + self.outputs.iter().map(|x| x.handle.clone()).collect(); capture_filter.toplevels_on_workspaces = self .workspaces .iter() @@ -299,12 +294,7 @@ impl Application for App { height, }); if self.visible { - return self.create_surface( - output.clone(), - name, - width, - height, - ); + return self.create_surface(output.clone(), width, height); } } } @@ -350,7 +340,7 @@ impl Application for App { wayland::Event::Workspaces(workspaces) => { let old_workspaces = mem::take(&mut self.workspaces); self.workspaces = Vec::new(); - for (output_names, workspace) in workspaces { + for (outputs, workspace) in workspaces { let is_active = workspace.state.contains(&WEnum::Value( zcosmic_workspace_handle_v1::State::Active, )); @@ -365,27 +355,25 @@ impl Application for App { self.workspaces.push(Workspace { name: workspace.name, handle: workspace.handle, - output_names, + outputs, img_for_output, is_active, }); } self.update_capture_filter(); } - wayland::Event::NewToplevel(handle, output_names, info) => { + wayland::Event::NewToplevel(handle, info) => { println!("New toplevel: {info:?}"); self.toplevels.push(Toplevel { handle, - output_names, info, img: None, }); } - wayland::Event::UpdateToplevel(handle, output_names, info) => { + wayland::Event::UpdateToplevel(handle, info) => { if let Some(toplevel) = self.toplevels.iter_mut().find(|x| x.handle == handle) { - toplevel.output_names = output_names; toplevel.info = info; } } @@ -443,15 +431,12 @@ impl Application for App { } Msg::StartDrag(size, drag_surface) => { match &drag_surface { - DragSurface::Workspace { - output_name, - name: _, - } => { + DragSurface::Workspace { output, name: _ } => { let id = self.next_surface_id(); if let Some((parent_id, _)) = self .layer_surfaces .iter() - .find(|(_, x)| &x.output_name == output_name) + .find(|(_, x)| &x.output == output) { self.drag_surface = Some((id, drag_surface, size)); return start_drag( @@ -516,9 +501,9 @@ impl Application for App { if let Some((drag_id, drag_surface, size)) = &self.drag_surface { if drag_id == &id { match drag_surface { - DragSurface::Workspace { output_name, name } => { + DragSurface::Workspace { output, name } => { if let Some(workspace) = self.workspaces.iter().find(|x| &x.name == name) { - let item = workspace_item(workspace, &output_name); + let item = workspace_item(workspace, &output); return widget::container(item) .height(iced::Length::Fixed(size.height)) .width(iced::Length::Fixed(size.width)) @@ -542,11 +527,11 @@ fn layer_surface<'a>(app: &'a App, surface: &'a LayerSurface) -> cosmic::Element workspaces_sidebar( app.workspaces .iter() - .filter(|i| i.output_names.contains(&surface.output_name)), - &surface.output_name + .filter(|i| i.outputs.contains(&surface.output)), + &surface.output ), toplevel_previews(app.toplevels.iter().filter(|i| { - if !i.output_names.contains(&surface.output_name) { + if !i.info.output.contains(&surface.output) { return false; } @@ -569,7 +554,10 @@ fn close_button(on_press: Msg) -> cosmic::Element<'static, Msg> { .into() } -fn workspace_item<'a>(workspace: &'a Workspace, output_name: &'a str) -> cosmic::Element<'a, Msg> { +fn workspace_item<'a>( + workspace: &'a Workspace, + output: &wl_output::WlOutput, +) -> cosmic::Element<'a, Msg> { // TODO style let theme = if workspace.is_active { cosmic::theme::Button::Suggested @@ -582,7 +570,7 @@ fn workspace_item<'a>(workspace: &'a Workspace, output_name: &'a str) -> cosmic: widget::Image::new( workspace .img_for_output - .get(output_name) + .get(output) .cloned() .unwrap_or_else(|| widget::image::Handle::from_pixels( 1, @@ -601,15 +589,15 @@ fn workspace_item<'a>(workspace: &'a Workspace, output_name: &'a str) -> cosmic: fn workspace_sidebar_entry<'a>( workspace: &'a Workspace, - output_name: &'a str, + output: &'a wl_output::WlOutput, ) -> cosmic::Element<'a, Msg> { - widget::dnd_source(workspace_item(workspace, output_name)) + widget::dnd_source(workspace_item(workspace, output)) .on_drag(|size| { Msg::StartDrag( size, DragSurface::Workspace { name: workspace.name.to_string(), - output_name: output_name.to_string(), + output: output.clone(), }, ) }) @@ -620,12 +608,12 @@ fn workspace_sidebar_entry<'a>( fn workspaces_sidebar<'a>( workspaces: impl Iterator, - output_name: &'a str, + output: &'a wl_output::WlOutput, ) -> cosmic::Element<'a, Msg> { widget::container( widget::dnd_listener(widget::column( workspaces - .map(|w| workspace_sidebar_entry(w, output_name)) + .map(|w| workspace_sidebar_entry(w, output)) .collect(), )) .on_enter(Msg::DndWorkspaceEnter) diff --git a/src/wayland/capture.rs b/src/wayland/capture.rs index e1238e7..5b02071 100644 --- a/src/wayland/capture.rs +++ b/src/wayland/capture.rs @@ -41,7 +41,7 @@ impl std::hash::Hash for CaptureSource { #[derive(Clone, Debug, Default)] pub struct CaptureFilter { // TODO: Use `WlOutput` when one Wayland connection is used - pub workspaces_on_outputs: Vec, + pub workspaces_on_outputs: Vec, pub toplevels_on_workspaces: Vec, } diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 5f7af31..398f9ea 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -15,7 +15,6 @@ use cctk::{ screencopy::ScreencopyState, sctk::{ self, - output::{OutputHandler, OutputState}, reexports::calloop_wayland_source::WaylandSource, registry::{ProvidesRegistryState, RegistryState}, seat::{SeatHandler, SeatState}, @@ -24,10 +23,9 @@ use cctk::{ toplevel_info::{ToplevelInfo, ToplevelInfoState}, toplevel_management::ToplevelManagerState, wayland_client::{ - backend::ObjectId, globals::registry_queue_init, protocol::{wl_output, wl_seat}, - Connection, Proxy, QueueHandle, + Connection, QueueHandle, }, workspace::WorkspaceState, }; @@ -61,21 +59,18 @@ pub enum Event { CmdSender(calloop::channel::Sender), ToplevelManager(zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1), WorkspaceManager(zcosmic_workspace_manager_v1::ZcosmicWorkspaceManagerV1), - // XXX Output name rather than `WlOutput` - Workspaces(Vec<(Vec, cctk::workspace::Workspace)>), + Workspaces(Vec<(HashSet, cctk::workspace::Workspace)>), WorkspaceCapture( zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1, - String, + wl_output::WlOutput, image::Handle, ), NewToplevel( zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, - HashSet, ToplevelInfo, ), UpdateToplevel( zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, - HashSet, ToplevelInfo, ), CloseToplevel(zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1), @@ -97,7 +92,6 @@ pub enum Cmd { pub struct AppData { qh: QueueHandle, - output_state: OutputState, registry_state: RegistryState, toplevel_info_state: ToplevelInfoState, workspace_state: WorkspaceState, @@ -106,7 +100,6 @@ pub struct AppData { shm_state: Shm, toplevel_manager_state: ToplevelManagerState, sender: mpsc::Sender, - output_names: HashMap>, seats: Vec, capture_filter: CaptureFilter, captures: RefCell>>, @@ -138,11 +131,7 @@ impl AppData { }) } CaptureSource::Workspace(_, output) => { - if let Some(name) = &self.output_state.info(&output).and_then(|x| x.name) { - self.capture_filter.workspaces_on_outputs.contains(name) - } else { - false - } + self.capture_filter.workspaces_on_outputs.contains(output) } } } @@ -185,7 +174,7 @@ impl ProvidesRegistryState for AppData { &mut self.registry_state } - sctk::registry_handlers!(OutputState, SeatState); + sctk::registry_handlers!(SeatState); } impl SeatHandler for AppData { @@ -229,40 +218,6 @@ impl ShmHandler for AppData { } } -// TODO: don't need this if we use same connection with same IDs? Or? -impl OutputHandler for AppData { - fn output_state(&mut self) -> &mut OutputState { - &mut self.output_state - } - - fn new_output( - &mut self, - _conn: &Connection, - _qh: &QueueHandle, - output: wl_output::WlOutput, - ) { - let name = self.output_state.info(&output).unwrap().name; - self.output_names.insert(output.id(), name); - } - - fn update_output( - &mut self, - _conn: &Connection, - _qh: &QueueHandle, - _output: wl_output::WlOutput, - ) { - } - - fn output_destroyed( - &mut self, - _conn: &Connection, - _qh: &QueueHandle, - output: wl_output::WlOutput, - ) { - self.output_names.remove(&output.id()); - } -} - fn start(conn: Connection) -> mpsc::Receiver { let (sender, receiver) = mpsc::channel(20); @@ -272,7 +227,6 @@ fn start(conn: Connection) -> mpsc::Receiver { let registry_state = RegistryState::new(&globals); let mut app_data = AppData { qh: qh.clone(), - output_state: OutputState::new(&globals, &qh), workspace_state: WorkspaceState::new(®istry_state, &qh), // Create before toplevel info state toplevel_info_state: ToplevelInfoState::new(®istry_state, &qh), toplevel_manager_state: ToplevelManagerState::new(®istry_state, &qh), @@ -281,7 +235,6 @@ fn start(conn: Connection) -> mpsc::Receiver { seat_state: SeatState::new(&globals, &qh), shm_state: Shm::bind(&globals, &qh).unwrap(), sender, - output_names: HashMap::new(), seats: Vec::new(), capture_filter: CaptureFilter::default(), captures: RefCell::new(HashMap::new()), @@ -323,7 +276,7 @@ fn start(conn: Connection) -> mpsc::Receiver { receiver } -sctk::delegate_output!(AppData); +// Don't bind outputs; use `WlOutput` instances from iced-sctk sctk::delegate_registry!(AppData); sctk::delegate_seat!(AppData); sctk::delegate_shm!(AppData); diff --git a/src/wayland/screencopy.rs b/src/wayland/screencopy.rs index 805e583..90b8ee2 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, Proxy, QueueHandle, WEnum}, + wayland_client::{protocol::wl_shm, Connection, QueueHandle, WEnum}, }; use super::{AppData, Buffer, Capture, CaptureSource, Event}; @@ -76,13 +76,11 @@ impl ScreencopyHandler for AppData { 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::WorkspaceCapture( + workspace.clone(), + output.clone(), + image, + )); } }; session.destroy(); diff --git a/src/wayland/toplevel.rs b/src/wayland/toplevel.rs index 9fb69b0..e7dc293 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, Proxy, QueueHandle, WEnum}, + wayland_client::{Connection, QueueHandle, WEnum}, }; use super::{AppData, CaptureSource, Event}; @@ -23,16 +23,7 @@ impl ToplevelInfoHandler for AppData { toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, ) { let info = self.toplevel_info_state.info(toplevel).unwrap(); - let output_names = info - .output - .iter() - .filter_map(|o| self.output_names.get(&o.id()).cloned()?) - .collect(); - self.send_event(Event::NewToplevel( - toplevel.clone(), - output_names, - info.clone(), - )); + self.send_event(Event::NewToplevel(toplevel.clone(), info.clone())); self.add_capture_source(CaptureSource::Toplevel(toplevel.clone())); } @@ -44,16 +35,7 @@ impl ToplevelInfoHandler for AppData { toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, ) { let info = self.toplevel_info_state.info(toplevel).unwrap(); - let output_names = info - .output - .iter() - .filter_map(|o| self.output_names.get(&o.id()).cloned()?) - .collect(); - self.send_event(Event::UpdateToplevel( - toplevel.clone(), - output_names, - info.clone(), - )); + self.send_event(Event::UpdateToplevel(toplevel.clone(), info.clone())); } fn toplevel_closed( diff --git a/src/wayland/workspace.rs b/src/wayland/workspace.rs index f013ada..cf06f91 100644 --- a/src/wayland/workspace.rs +++ b/src/wayland/workspace.rs @@ -1,7 +1,4 @@ -use cctk::{ - wayland_client::Proxy, - workspace::{WorkspaceHandler, WorkspaceState}, -}; +use cctk::workspace::{WorkspaceHandler, WorkspaceState}; use super::{AppData, CaptureSource, Event}; @@ -18,20 +15,13 @@ impl WorkspaceHandler for AppData { for group in self.workspace_state.workspace_groups() { for workspace in &group.workspaces { - 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())); + workspaces.push((group.outputs.iter().cloned().collect(), workspace.clone())); - for output in &group.outputs { - self.add_capture_source(CaptureSource::Workspace( - workspace.handle.clone(), - output.clone(), - )); - } + for output in &group.outputs { + self.add_capture_source(CaptureSource::Workspace( + workspace.handle.clone(), + output.clone(), + )); } } }