Define Workspaces and Toplevels structs
This way methods can be called while other parts of `App` are mutably borrowed.
This commit is contained in:
parent
20b694386d
commit
6d86762152
2 changed files with 52 additions and 59 deletions
100
src/main.rs
100
src/main.rs
|
|
@ -181,8 +181,8 @@ struct App {
|
||||||
capture_filter: backend::CaptureFilter,
|
capture_filter: backend::CaptureFilter,
|
||||||
layer_surfaces: HashMap<SurfaceId, LayerSurface>,
|
layer_surfaces: HashMap<SurfaceId, LayerSurface>,
|
||||||
outputs: Vec<Output>,
|
outputs: Vec<Output>,
|
||||||
workspaces: Vec<Workspace>,
|
workspaces: Workspaces,
|
||||||
toplevels: Vec<Toplevel>,
|
toplevels: Toplevels,
|
||||||
toplevel_capabilities:
|
toplevel_capabilities:
|
||||||
Vec<zcosmic_toplevel_manager_v1::ZcosmicToplelevelManagementCapabilitiesV1>,
|
Vec<zcosmic_toplevel_manager_v1::ZcosmicToplelevelManagementCapabilitiesV1>,
|
||||||
conn: Option<Connection>,
|
conn: Option<Connection>,
|
||||||
|
|
@ -195,35 +195,36 @@ struct App {
|
||||||
scroll: Option<(f32, Instant)>,
|
scroll: Option<(f32, Instant)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
#[derive(Debug, Default)]
|
||||||
fn workspace_for_handle(&self, handle: &ExtWorkspaceHandleV1) -> Option<&Workspace> {
|
struct Workspaces(Vec<Workspace>);
|
||||||
self.workspaces.iter().find(|i| i.handle() == handle)
|
|
||||||
|
impl Workspaces {
|
||||||
|
fn for_handle(&self, handle: &ExtWorkspaceHandleV1) -> Option<&Workspace> {
|
||||||
|
self.0.iter().find(|i| i.handle() == handle)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspace_for_handle_mut(
|
fn for_handle_mut(&mut self, handle: &ExtWorkspaceHandleV1) -> Option<&mut Workspace> {
|
||||||
&mut self,
|
self.0.iter_mut().find(|i| i.handle() == handle)
|
||||||
handle: &ExtWorkspaceHandleV1,
|
|
||||||
) -> Option<&mut Workspace> {
|
|
||||||
self.workspaces.iter_mut().find(|i| i.handle() == handle)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO iterate in order based on `coordinates`
|
fn for_output<'a>(
|
||||||
fn workspaces_for_output<'a>(
|
|
||||||
&'a self,
|
&'a self,
|
||||||
output: &'a wl_output::WlOutput,
|
output: &'a wl_output::WlOutput,
|
||||||
) -> impl Iterator<Item = &'a Workspace> + 'a {
|
) -> impl Iterator<Item = &'a Workspace> + 'a {
|
||||||
self.workspaces
|
self.0.iter().filter(|w| w.outputs.contains(output))
|
||||||
.iter()
|
|
||||||
.filter(|w| w.outputs.contains(output))
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn toplevel_for_handle_mut(
|
#[derive(Debug, Default)]
|
||||||
&mut self,
|
struct Toplevels(Vec<Toplevel>);
|
||||||
handle: &ExtForeignToplevelHandleV1,
|
|
||||||
) -> Option<&mut Toplevel> {
|
impl Toplevels {
|
||||||
self.toplevels.iter_mut().find(|i| &i.handle == handle)
|
fn for_handle_mut(&mut self, handle: &ExtForeignToplevelHandleV1) -> Option<&mut Toplevel> {
|
||||||
|
self.0.iter_mut().find(|i| &i.handle == handle)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl App {
|
||||||
fn create_surface(&mut self, output: wl_output::WlOutput) -> Task<cosmic::Action<Msg>> {
|
fn create_surface(&mut self, output: wl_output::WlOutput) -> Task<cosmic::Action<Msg>> {
|
||||||
let id = SurfaceId::unique();
|
let id = SurfaceId::unique();
|
||||||
self.layer_surfaces.insert(
|
self.layer_surfaces.insert(
|
||||||
|
|
@ -309,6 +310,7 @@ impl App {
|
||||||
self.outputs.iter().map(|x| x.handle.clone()).collect();
|
self.outputs.iter().map(|x| x.handle.clone()).collect();
|
||||||
capture_filter.toplevels_on_workspaces = self
|
capture_filter.toplevels_on_workspaces = self
|
||||||
.workspaces
|
.workspaces
|
||||||
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|x| x.is_active())
|
.filter(|x| x.is_active())
|
||||||
.map(|x| x.handle().clone())
|
.map(|x| x.handle().clone())
|
||||||
|
|
@ -317,12 +319,12 @@ impl App {
|
||||||
|
|
||||||
// Drop `CaptureImage` for workspaces and toplevels not matching new
|
// Drop `CaptureImage` for workspaces and toplevels not matching new
|
||||||
// filter.
|
// filter.
|
||||||
for workspace in &mut self.workspaces {
|
for workspace in &mut self.workspaces.0 {
|
||||||
if !capture_filter.workspace_outputs_matches(&workspace.outputs) {
|
if !capture_filter.workspace_outputs_matches(&workspace.outputs) {
|
||||||
workspace.img = None;
|
workspace.img = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for toplevel in &mut self.toplevels {
|
for toplevel in &mut self.toplevels.0 {
|
||||||
if !capture_filter.toplevel_matches(&toplevel.info) {
|
if !capture_filter.toplevel_matches(&toplevel.info) {
|
||||||
toplevel.img = None;
|
toplevel.img = None;
|
||||||
}
|
}
|
||||||
|
|
@ -421,18 +423,15 @@ 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);
|
||||||
self.workspaces = Vec::new();
|
|
||||||
for (outputs, workspace) in workspaces {
|
for (outputs, workspace) in workspaces {
|
||||||
// XXX efficiency
|
// XXX efficiency
|
||||||
let old_workspace = old_workspaces
|
let old_workspace = old_workspaces.for_handle(&workspace.handle);
|
||||||
.iter()
|
|
||||||
.find(|i| *i.handle() == workspace.handle);
|
|
||||||
let img = old_workspace.map(|i| i.img.clone()).unwrap_or_default();
|
let img = old_workspace.map(|i| i.img.clone()).unwrap_or_default();
|
||||||
let has_cursor = old_workspace.is_some_and(|w| w.has_cursor);
|
let has_cursor = old_workspace.is_some_and(|w| w.has_cursor);
|
||||||
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.push(Workspace {
|
self.workspaces.0.push(Workspace {
|
||||||
info: workspace,
|
info: workspace,
|
||||||
outputs,
|
outputs,
|
||||||
img,
|
img,
|
||||||
|
|
@ -450,7 +449,7 @@ impl Application for App {
|
||||||
move |path| Msg::UpdateToplevelIcon(app_id.clone(), path),
|
move |path| Msg::UpdateToplevelIcon(app_id.clone(), path),
|
||||||
)
|
)
|
||||||
.map(cosmic::Action::App);
|
.map(cosmic::Action::App);
|
||||||
self.toplevels.push(Toplevel {
|
self.toplevels.0.push(Toplevel {
|
||||||
icon: None,
|
icon: None,
|
||||||
handle,
|
handle,
|
||||||
info,
|
info,
|
||||||
|
|
@ -464,9 +463,7 @@ impl Application for App {
|
||||||
return icon_task;
|
return icon_task;
|
||||||
}
|
}
|
||||||
backend::Event::UpdateToplevel(handle, info) => {
|
backend::Event::UpdateToplevel(handle, info) => {
|
||||||
if let Some(toplevel) =
|
if let Some(toplevel) = self.toplevels.for_handle_mut(&handle) {
|
||||||
self.toplevels.iter_mut().find(|x| x.handle == handle)
|
|
||||||
{
|
|
||||||
let mut task = Task::none();
|
let mut task = Task::none();
|
||||||
if toplevel.info.app_id != info.app_id {
|
if toplevel.info.app_id != info.app_id {
|
||||||
let app_id = info.app_id.clone();
|
let app_id = info.app_id.clone();
|
||||||
|
|
@ -481,24 +478,26 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
backend::Event::CloseToplevel(handle) => {
|
backend::Event::CloseToplevel(handle) => {
|
||||||
if let Some(idx) = self.toplevels.iter().position(|x| x.handle == handle) {
|
if let Some(idx) = self.toplevels.0.iter().position(|x| x.handle == handle)
|
||||||
self.toplevels.remove(idx);
|
{
|
||||||
|
self.toplevels.0.remove(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
backend::Event::WorkspaceCapture(handle, image) => {
|
backend::Event::WorkspaceCapture(handle, image) => {
|
||||||
//println!("Workspace capture");
|
//println!("Workspace capture");
|
||||||
let capture_filter = self.capture_filter.clone(); // XXX
|
if let Some(workspace) = self.workspaces.for_handle_mut(&handle) {
|
||||||
if let Some(workspace) = self.workspace_for_handle_mut(&handle) {
|
if self
|
||||||
if capture_filter.workspace_outputs_matches(&workspace.outputs) {
|
.capture_filter
|
||||||
|
.workspace_outputs_matches(&workspace.outputs)
|
||||||
|
{
|
||||||
workspace.img = Some(image);
|
workspace.img = Some(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
backend::Event::ToplevelCapture(handle, image) => {
|
backend::Event::ToplevelCapture(handle, image) => {
|
||||||
let capture_filter = self.capture_filter.clone(); // XXX
|
if let Some(toplevel) = self.toplevels.for_handle_mut(&handle) {
|
||||||
if let Some(toplevel) = self.toplevel_for_handle_mut(&handle) {
|
|
||||||
// println!("Got toplevel image!");
|
// println!("Got toplevel image!");
|
||||||
if capture_filter.toplevel_matches(&toplevel.info) {
|
if self.capture_filter.toplevel_matches(&toplevel.info) {
|
||||||
toplevel.img = Some(image);
|
toplevel.img = Some(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -512,7 +511,7 @@ impl Application for App {
|
||||||
return self.hide();
|
return self.hide();
|
||||||
}
|
}
|
||||||
Msg::ActivateWorkspace(workspace_handle) => {
|
Msg::ActivateWorkspace(workspace_handle) => {
|
||||||
if let Some(workspace) = self.workspace_for_handle(&workspace_handle) {
|
if let Some(workspace) = self.workspaces.for_handle(&workspace_handle) {
|
||||||
if workspace.is_active() {
|
if workspace.is_active() {
|
||||||
return self.hide();
|
return self.hide();
|
||||||
}
|
}
|
||||||
|
|
@ -596,7 +595,7 @@ impl Application for App {
|
||||||
self.conf.bg = c;
|
self.conf.bg = c;
|
||||||
}
|
}
|
||||||
Msg::UpdateToplevelIcon(app_id, path) => {
|
Msg::UpdateToplevelIcon(app_id, path) => {
|
||||||
for toplevel in self.toplevels.iter_mut() {
|
for toplevel in self.toplevels.0.iter_mut() {
|
||||||
if toplevel.info.app_id == app_id {
|
if toplevel.info.app_id == app_id {
|
||||||
toplevel.icon = path.clone();
|
toplevel.icon = path.clone();
|
||||||
}
|
}
|
||||||
|
|
@ -651,7 +650,7 @@ impl Application for App {
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO assumes only one active workspace per output
|
// TODO assumes only one active workspace per output
|
||||||
let workspaces = self.workspaces_for_output(&output).collect::<Vec<_>>();
|
let workspaces = self.workspaces.for_output(&output).collect::<Vec<_>>();
|
||||||
if let Some(workspace_idx) = workspaces.iter().position(|i| i.is_active()) {
|
if let Some(workspace_idx) = workspaces.iter().position(|i| i.is_active()) {
|
||||||
let workspace = match direction {
|
let workspace = match direction {
|
||||||
// Next workspace on output
|
// Next workspace on output
|
||||||
|
|
@ -674,9 +673,8 @@ impl Application for App {
|
||||||
DropTarget::WorkspaceSidebarEntry(other_handle, _output)
|
DropTarget::WorkspaceSidebarEntry(other_handle, _output)
|
||||||
| DropTarget::WorkspaceSidebarDragPlaceholder(other_handle, _output),
|
| DropTarget::WorkspaceSidebarDragPlaceholder(other_handle, _output),
|
||||||
) => {
|
) => {
|
||||||
let workspace = self.workspaces.iter().find(|i| i.handle() == handle);
|
let workspace = self.workspaces.for_handle(handle);
|
||||||
let other_workspace =
|
let other_workspace = self.workspaces.for_handle(&other_handle);
|
||||||
self.workspaces.iter().find(|i| *i.handle() == other_handle);
|
|
||||||
if let (Some(workspace), Some(other_workspace)) =
|
if let (Some(workspace), Some(other_workspace)) =
|
||||||
(workspace, other_workspace)
|
(workspace, other_workspace)
|
||||||
{
|
{
|
||||||
|
|
@ -699,11 +697,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::TogglePinned(workspace_handle) => {
|
Msg::TogglePinned(workspace_handle) => {
|
||||||
if let Some(workspace) = self
|
if let Some(workspace) = self.workspaces.for_handle(&workspace_handle) {
|
||||||
.workspaces
|
|
||||||
.iter()
|
|
||||||
.find(|w| *w.handle() == workspace_handle)
|
|
||||||
{
|
|
||||||
self.send_wayland_cmd(backend::Cmd::SetWorkspacePinned(
|
self.send_wayland_cmd(backend::Cmd::SetWorkspacePinned(
|
||||||
workspace_handle,
|
workspace_handle,
|
||||||
!workspace.is_pinned(),
|
!workspace.is_pinned(),
|
||||||
|
|
@ -711,11 +705,7 @@ impl Application for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::EnteredWorkspaceSidebarEntry(workspace_handle, entered) => {
|
Msg::EnteredWorkspaceSidebarEntry(workspace_handle, entered) => {
|
||||||
if let Some(workspace) = self
|
if let Some(workspace) = self.workspaces.for_handle_mut(&workspace_handle) {
|
||||||
.workspaces
|
|
||||||
.iter_mut()
|
|
||||||
.find(|w| *w.handle() == workspace_handle)
|
|
||||||
{
|
|
||||||
workspace.has_cursor = entered;
|
workspace.has_cursor = entered;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,12 +94,13 @@ pub(crate) fn layer_surface<'a>(
|
||||||
#[allow(clippy::mutable_key_type)]
|
#[allow(clippy::mutable_key_type)]
|
||||||
let workspaces_with_toplevels = app
|
let workspaces_with_toplevels = app
|
||||||
.toplevels
|
.toplevels
|
||||||
|
.0
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|t| &t.info.workspace)
|
.flat_map(|t| &t.info.workspace)
|
||||||
.collect::<HashSet<_>>();
|
.collect::<HashSet<_>>();
|
||||||
let layout = app.conf.workspace_config.workspace_layout;
|
let layout = app.conf.workspace_config.workspace_layout;
|
||||||
let sidebar = workspaces_sidebar(
|
let sidebar = workspaces_sidebar(
|
||||||
app.workspaces_for_output(&surface.output),
|
app.workspaces.for_output(&surface.output),
|
||||||
&workspaces_with_toplevels,
|
&workspaces_with_toplevels,
|
||||||
&surface.output,
|
&surface.output,
|
||||||
layout,
|
layout,
|
||||||
|
|
@ -107,13 +108,14 @@ pub(crate) fn layer_surface<'a>(
|
||||||
drag_workspace,
|
drag_workspace,
|
||||||
);
|
);
|
||||||
let toplevels = toplevel_previews(
|
let toplevels = toplevel_previews(
|
||||||
app.toplevels.iter().filter(|i| {
|
app.toplevels.0.iter().filter(|i| {
|
||||||
if !i.info.output.contains(&surface.output) {
|
if !i.info.output.contains(&surface.output) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
i.info.workspace.iter().any(|workspace| {
|
i.info.workspace.iter().any(|workspace| {
|
||||||
app.workspace_for_handle(workspace)
|
app.workspaces
|
||||||
|
.for_handle(workspace)
|
||||||
.is_some_and(|x| x.is_active())
|
.is_some_and(|x| x.is_active())
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
|
@ -122,7 +124,8 @@ pub(crate) fn layer_surface<'a>(
|
||||||
);
|
);
|
||||||
// TODO multiple active workspaces? Not currently supported by cosmic.
|
// TODO multiple active workspaces? Not currently supported by cosmic.
|
||||||
let first_active_workspace = app
|
let first_active_workspace = app
|
||||||
.workspaces_for_output(&surface.output)
|
.workspaces
|
||||||
|
.for_output(&surface.output)
|
||||||
.find(|w| w.is_active());
|
.find(|w| w.is_active());
|
||||||
let toplevels = if let Some(workspace) = first_active_workspace {
|
let toplevels = if let Some(workspace) = first_active_workspace {
|
||||||
dnd_destination_for_target(
|
dnd_destination_for_target(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue