fix: cleanup rectangles on workspace swap
This commit is contained in:
parent
127b966e3e
commit
fa4d8d68a4
2 changed files with 118 additions and 32 deletions
100
src/main.rs
100
src/main.rs
|
|
@ -184,6 +184,7 @@ struct Conf {
|
||||||
pub struct RectId {
|
pub struct RectId {
|
||||||
id: window::Id,
|
id: window::Id,
|
||||||
toplevel_id: Option<ObjectId>,
|
toplevel_id: Option<ObjectId>,
|
||||||
|
workspaces_id: Option<Vec<ObjectId>>,
|
||||||
widget_id: Option<widget::Id>,
|
widget_id: Option<widget::Id>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -444,6 +445,55 @@ impl App {
|
||||||
}
|
}
|
||||||
regions
|
regions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_active_workspace(
|
||||||
|
&mut self,
|
||||||
|
workspace_handle: ExtWorkspaceHandleV1,
|
||||||
|
) -> Option<Task<cosmic::Action<Msg>>> {
|
||||||
|
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<Rectangle> = 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 {
|
impl Application for App {
|
||||||
|
|
@ -470,18 +520,20 @@ impl Application for App {
|
||||||
match message {
|
match message {
|
||||||
Msg::Rectangle(u) => match u {
|
Msg::Rectangle(u) => match u {
|
||||||
RectangleUpdate::Rectangle(r) => {
|
RectangleUpdate::Rectangle(r) => {
|
||||||
// TODO should we reuse previously tracked rectangles on surface creation
|
|
||||||
self.rects.insert(r.0.clone(), r.1);
|
self.rects.insert(r.0.clone(), r.1);
|
||||||
let active = cosmic::theme::active();
|
let active = cosmic::theme::active();
|
||||||
let rad = active
|
let rad = active
|
||||||
.cosmic()
|
.cosmic()
|
||||||
.radius_s()
|
.radius_s()
|
||||||
.map(|x| if x < 4.0 { x } else { x + 8.0 });
|
.map(|x| if x < 4.0 { x } else { x + 8.0 });
|
||||||
let strips = self
|
let mut rects = Vec::new();
|
||||||
|
let mut strips: Vec<Rectangle> = self
|
||||||
.rects
|
.rects
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(id, _)| r.0.id == id.id)
|
.filter_map(|(id, rect)| {
|
||||||
.map(|(id, r)| {
|
if r.0.id != id.id {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
let rad = if id.toplevel_id.is_none() {
|
let rad = if id.toplevel_id.is_none() {
|
||||||
CornerRadius {
|
CornerRadius {
|
||||||
top_left: rad[0] as u32,
|
top_left: rad[0] as u32,
|
||||||
|
|
@ -490,16 +542,21 @@ impl Application for App {
|
||||||
bottom_right: rad[2] as u32,
|
bottom_right: rad[2] as u32,
|
||||||
}
|
}
|
||||||
} else {
|
} 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(
|
return cosmic::iced::platform_specific::shell::commands::blur::blur(
|
||||||
r.0.id,
|
r.0.id,
|
||||||
Some(strips.collect()),
|
Some(strips),
|
||||||
)
|
)
|
||||||
.discard();
|
.discard();
|
||||||
}
|
}
|
||||||
|
|
@ -576,6 +633,12 @@ impl Application for App {
|
||||||
backend::Event::Workspaces(mut workspaces) => {
|
backend::Event::Workspaces(mut workspaces) => {
|
||||||
workspaces.sort_by(|(_, w1), (_, w2)| w1.coordinates.cmp(&w2.coordinates));
|
workspaces.sort_by(|(_, w1), (_, w2)| w1.coordinates.cmp(&w2.coordinates));
|
||||||
let old_workspaces = mem::take(&mut self.workspaces);
|
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 {
|
for (outputs, workspace) in workspaces {
|
||||||
// XXX efficiency
|
// XXX efficiency
|
||||||
let old_workspace = old_workspaces.for_handle(&workspace.handle);
|
let old_workspace = old_workspaces.for_handle(&workspace.handle);
|
||||||
|
|
@ -584,15 +647,26 @@ impl Application for App {
|
||||||
let dnd_source_id = old_workspace
|
let dnd_source_id = old_workspace
|
||||||
.map_or_else(iced::id::Id::unique, |w| w.dnd_source_id.clone());
|
.map_or_else(iced::id::Id::unique, |w| w.dnd_source_id.clone());
|
||||||
|
|
||||||
self.workspaces.0.push(Workspace {
|
let w = Workspace {
|
||||||
info: workspace,
|
info: workspace,
|
||||||
outputs,
|
outputs,
|
||||||
img,
|
img,
|
||||||
has_cursor,
|
has_cursor,
|
||||||
dnd_source_id,
|
dnd_source_id,
|
||||||
});
|
};
|
||||||
|
if w.is_active() {
|
||||||
|
new_active.push(w.handle().clone());
|
||||||
|
}
|
||||||
|
self.workspaces.0.push(w);
|
||||||
}
|
}
|
||||||
self.update_capture_filter();
|
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) => {
|
backend::Event::NewToplevel(handle, info) => {
|
||||||
log::debug!("New toplevel: {info:?}");
|
log::debug!("New toplevel: {info:?}");
|
||||||
|
|
@ -668,7 +742,11 @@ impl Application for App {
|
||||||
{
|
{
|
||||||
return self.hide();
|
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) => {
|
Msg::ActivateToplevel(toplevel_handle) => {
|
||||||
self.send_wayland_cmd(backend::Cmd::ActivateToplevel(toplevel_handle));
|
self.send_wayland_cmd(backend::Cmd::ActivateToplevel(toplevel_handle));
|
||||||
|
|
|
||||||
|
|
@ -497,6 +497,7 @@ fn workspaces_sidebar<'a>(
|
||||||
id: window_id,
|
id: window_id,
|
||||||
toplevel_id: None,
|
toplevel_id: None,
|
||||||
widget_id: None,
|
widget_id: None,
|
||||||
|
workspaces_id: None,
|
||||||
},
|
},
|
||||||
widget::container(sidebar_entries_container)
|
widget::container(sidebar_entries_container)
|
||||||
.width(width)
|
.width(width)
|
||||||
|
|
@ -527,7 +528,12 @@ fn workspaces_sidebar<'a>(
|
||||||
.into()
|
.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<RectId>,
|
||||||
|
) -> cosmic::Element<'static, Msg> {
|
||||||
let cosmic::cosmic_theme::Spacing {
|
let cosmic::cosmic_theme::Spacing {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = cosmic::theme::active().cosmic().spacing;
|
} = cosmic::theme::active().cosmic().spacing;
|
||||||
|
|
@ -575,15 +581,23 @@ fn toplevel_preview(toplevel: &Toplevel, is_being_dragged: bool) -> cosmic::Elem
|
||||||
.align_y(Alignment::Center);
|
.align_y(Alignment::Center);
|
||||||
|
|
||||||
let alpha = if is_being_dragged { 0.5 } else { 1.0 };
|
let alpha = if is_being_dragged { 0.5 } else { 1.0 };
|
||||||
let preview = widget::button::custom(capture_image(toplevel.img.as_ref(), alpha))
|
let preview = widget::button::custom(rectangle_track.container(
|
||||||
.selected(
|
RectId {
|
||||||
toplevel
|
id: window_id,
|
||||||
.info
|
toplevel_id: Some(toplevel.handle.id()),
|
||||||
.state
|
widget_id: None,
|
||||||
.contains(&zcosmic_toplevel_handle_v1::State::Activated),
|
workspaces_id: Some(toplevel.info.workspace.iter().map(|h| h.id()).collect()),
|
||||||
)
|
},
|
||||||
.class(cosmic::theme::Button::Image)
|
capture_image(toplevel.img.as_ref(), alpha),
|
||||||
.on_press(Msg::ActivateToplevel(toplevel.handle.clone()));
|
))
|
||||||
|
.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(
|
widget::mouse_area(crate::widgets::size_cross_nth(
|
||||||
vec![title.into(), preview.into()],
|
vec![title.into(), preview.into()],
|
||||||
|
|
@ -602,24 +616,18 @@ fn toplevel_previews_entry<'a>(
|
||||||
) -> cosmic::Element<'a, Msg> {
|
) -> cosmic::Element<'a, Msg> {
|
||||||
// Dragged window still takes up space until moved, but isn't rendered while drag surface is
|
// Dragged window still takes up space until moved, but isn't rendered while drag surface is
|
||||||
// shown.
|
// shown.
|
||||||
let preview = rectangle_track.container(
|
let preview = crate::widgets::visibility_wrapper(
|
||||||
RectId {
|
toplevel_preview(toplevel, is_being_dragged, window_id, rectangle_track),
|
||||||
id: window_id,
|
!is_being_dragged,
|
||||||
toplevel_id: Some(toplevel.handle.id()),
|
|
||||||
widget_id: None,
|
|
||||||
},
|
|
||||||
crate::widgets::visibility_wrapper(
|
|
||||||
toplevel_preview(toplevel, is_being_dragged),
|
|
||||||
!is_being_dragged,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
let toplevel2 = toplevel.clone();
|
let toplevel2 = toplevel.clone();
|
||||||
|
let track = rectangle_track.clone();
|
||||||
dnd_source_with_drag_surface(
|
dnd_source_with_drag_surface(
|
||||||
DragToplevel {},
|
DragToplevel {},
|
||||||
DragSurface::Toplevel(toplevel.handle.clone()),
|
DragSurface::Toplevel(toplevel.handle.clone()),
|
||||||
None,
|
None,
|
||||||
preview.into(),
|
preview.into(),
|
||||||
move || toplevel_preview(&toplevel2, true),
|
move || toplevel_preview(&toplevel2, true, window_id, &track),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue