diff --git a/src/main.rs b/src/main.rs index 23fe640..b984a41 100644 --- a/src/main.rs +++ b/src/main.rs @@ -184,6 +184,7 @@ struct Conf { pub struct RectId { id: window::Id, toplevel_id: Option, + workspaces_id: Option>, widget_id: Option, } @@ -444,6 +445,55 @@ impl App { } regions } + + fn update_active_workspace( + &mut self, + workspace_handle: ExtWorkspaceHandleV1, + ) -> Option>> { + if let Some((cur_window, _)) = self.layer_surfaces.iter().find(|(_, layer_surface)| { + self.workspaces + .for_output(&layer_surface.output) + .any(|w| *w.handle() == workspace_handle) + }) { + self.rects.retain(|id, r| { + id.toplevel_id == None + || (id.id == *cur_window + && id + .workspaces_id + .as_ref() + .is_some_and(|l| l.iter().any(|o| *o == workspace_handle.id()))) + }); + let active = cosmic::theme::active(); + let rad = active + .cosmic() + .radius_s() + .map(|x| if x < 4.0 { x } else { x + 8.0 }); + let strips: Vec = self + .rects + .iter() + .map(|(id, rect)| { + let rad = CornerRadius { + top_left: rad[0] as u32, + top_right: rad[1] as u32, + bottom_left: rad[3] as u32, + bottom_right: rad[2] as u32, + }; + + cosmic::surface::corner_radius::rounded_rect_strips(*rect, rad) + }) + .flatten() + .collect(); + + return Some( + cosmic::iced::platform_specific::shell::commands::blur::blur( + *cur_window, + Some(strips), + ) + .discard(), + ); + } + None + } } impl Application for App { @@ -470,18 +520,20 @@ impl Application for App { match message { Msg::Rectangle(u) => match u { RectangleUpdate::Rectangle(r) => { - // TODO should we reuse previously tracked rectangles on surface creation self.rects.insert(r.0.clone(), r.1); let active = cosmic::theme::active(); let rad = active .cosmic() .radius_s() .map(|x| if x < 4.0 { x } else { x + 8.0 }); - let strips = self + let mut rects = Vec::new(); + let mut strips: Vec = self .rects .iter() - .filter(|(id, _)| r.0.id == id.id) - .map(|(id, r)| { + .filter_map(|(id, rect)| { + if r.0.id != id.id { + return None; + } let rad = if id.toplevel_id.is_none() { CornerRadius { top_left: rad[0] as u32, @@ -490,16 +542,21 @@ impl Application for App { bottom_right: rad[2] as u32, } } else { - CornerRadius::default() + rects.push(*rect); + return None; }; - cosmic::surface::corner_radius::rounded_rect_strips(*r, rad) + Some(cosmic::surface::corner_radius::rounded_rect_strips( + *rect, rad, + )) }) - .flatten(); + .flatten() + .collect(); + strips.append(&mut rects); return cosmic::iced::platform_specific::shell::commands::blur::blur( r.0.id, - Some(strips.collect()), + Some(strips), ) .discard(); } @@ -576,6 +633,12 @@ impl Application for App { backend::Event::Workspaces(mut workspaces) => { workspaces.sort_by(|(_, w1), (_, w2)| w1.coordinates.cmp(&w2.coordinates)); let old_workspaces = mem::take(&mut self.workspaces); + let old_active: HashSet<_> = old_workspaces + .0 + .iter() + .filter_map(|w| w.is_active().then(|| w.handle().clone())) + .collect(); + let mut new_active = Vec::new(); for (outputs, workspace) in workspaces { // XXX efficiency let old_workspace = old_workspaces.for_handle(&workspace.handle); @@ -584,15 +647,26 @@ impl Application for App { let dnd_source_id = old_workspace .map_or_else(iced::id::Id::unique, |w| w.dnd_source_id.clone()); - self.workspaces.0.push(Workspace { + let w = Workspace { info: workspace, outputs, img, has_cursor, dnd_source_id, - }); + }; + if w.is_active() { + new_active.push(w.handle().clone()); + } + self.workspaces.0.push(w); } self.update_capture_filter(); + return Task::batch(new_active.into_iter().map(|new| { + if old_active.contains(&new) { + Task::none() + } else { + self.update_active_workspace(new).unwrap_or(Task::none()) + } + })); } backend::Event::NewToplevel(handle, info) => { log::debug!("New toplevel: {info:?}"); @@ -668,7 +742,11 @@ impl Application for App { { return self.hide(); } - self.send_wayland_cmd(backend::Cmd::ActivateWorkspace(workspace_handle)); + + self.send_wayland_cmd(backend::Cmd::ActivateWorkspace(workspace_handle.clone())); + if let Some(value) = self.update_active_workspace(workspace_handle) { + return value; + } } Msg::ActivateToplevel(toplevel_handle) => { self.send_wayland_cmd(backend::Cmd::ActivateToplevel(toplevel_handle)); diff --git a/src/view/mod.rs b/src/view/mod.rs index 2b69264..cc2e1e2 100644 --- a/src/view/mod.rs +++ b/src/view/mod.rs @@ -497,6 +497,7 @@ fn workspaces_sidebar<'a>( id: window_id, toplevel_id: None, widget_id: None, + workspaces_id: None, }, widget::container(sidebar_entries_container) .width(width) @@ -527,7 +528,12 @@ fn workspaces_sidebar<'a>( .into() } -fn toplevel_preview(toplevel: &Toplevel, is_being_dragged: bool) -> cosmic::Element<'static, Msg> { +fn toplevel_preview( + toplevel: &Toplevel, + is_being_dragged: bool, + window_id: window::Id, + rectangle_track: &rectangle_tracker::RectangleTracker, +) -> cosmic::Element<'static, Msg> { let cosmic::cosmic_theme::Spacing { space_xxs, space_s, .. } = cosmic::theme::active().cosmic().spacing; @@ -575,15 +581,23 @@ fn toplevel_preview(toplevel: &Toplevel, is_being_dragged: bool) -> cosmic::Elem .align_y(Alignment::Center); let alpha = if is_being_dragged { 0.5 } else { 1.0 }; - let preview = widget::button::custom(capture_image(toplevel.img.as_ref(), alpha)) - .selected( - toplevel - .info - .state - .contains(&zcosmic_toplevel_handle_v1::State::Activated), - ) - .class(cosmic::theme::Button::Image) - .on_press(Msg::ActivateToplevel(toplevel.handle.clone())); + let preview = widget::button::custom(rectangle_track.container( + RectId { + id: window_id, + toplevel_id: Some(toplevel.handle.id()), + widget_id: None, + workspaces_id: Some(toplevel.info.workspace.iter().map(|h| h.id()).collect()), + }, + capture_image(toplevel.img.as_ref(), alpha), + )) + .selected( + toplevel + .info + .state + .contains(&zcosmic_toplevel_handle_v1::State::Activated), + ) + .class(cosmic::theme::Button::Image) + .on_press(Msg::ActivateToplevel(toplevel.handle.clone())); widget::mouse_area(crate::widgets::size_cross_nth( vec![title.into(), preview.into()], @@ -602,24 +616,18 @@ fn toplevel_previews_entry<'a>( ) -> cosmic::Element<'a, Msg> { // Dragged window still takes up space until moved, but isn't rendered while drag surface is // shown. - let preview = rectangle_track.container( - RectId { - id: window_id, - toplevel_id: Some(toplevel.handle.id()), - widget_id: None, - }, - crate::widgets::visibility_wrapper( - toplevel_preview(toplevel, is_being_dragged), - !is_being_dragged, - ), + let preview = crate::widgets::visibility_wrapper( + toplevel_preview(toplevel, is_being_dragged, window_id, rectangle_track), + !is_being_dragged, ); let toplevel2 = toplevel.clone(); + let track = rectangle_track.clone(); dnd_source_with_drag_surface( DragToplevel {}, DragSurface::Toplevel(toplevel.handle.clone()), None, preview.into(), - move || toplevel_preview(&toplevel2, true), + move || toplevel_preview(&toplevel2, true, window_id, &track), ) }