diff --git a/applets/cosmic-app-list/Cargo.lock b/applets/cosmic-app-list/Cargo.lock index c0a5c54b..2e284273 100644 --- a/applets/cosmic-app-list/Cargo.lock +++ b/applets/cosmic-app-list/Cargo.lock @@ -252,9 +252,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.77" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d" [[package]] name = "cfg-if" @@ -450,15 +450,15 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-theme.git#896b228e4462c2fdeea0e89d1a657458b4a0a144" +source = "git+https://github.com/pop-os/cosmic-theme.git#77aad06a6e3e2996ef24fc12e5f59d6da7226692" dependencies = [ "anyhow", "csscolorparser", + "directories", "lazy_static", "palette", "ron", "serde", - "xdg", ] [[package]] @@ -644,6 +644,15 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "directories" +version = "4.0.1" +source = "git+https://github.com/edfloreshz/directories-rs#b93c018bc319f066fbeadcd8e3b865f1fccaaa8c" +dependencies = [ + "anyhow", + "dirs-sys", +] + [[package]] name = "dirs" version = "3.0.2" @@ -1415,7 +1424,7 @@ dependencies = [ [[package]] name = "iced" version = "0.5.2" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "iced_core", "iced_futures", @@ -1431,7 +1440,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.6.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "bitflags", "palette", @@ -1441,7 +1450,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.5.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "futures", "log", @@ -1453,7 +1462,7 @@ dependencies = [ [[package]] name = "iced_glow" version = "0.4.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "bytemuck", "euclid", @@ -1468,7 +1477,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.4.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "bitflags", "bytemuck", @@ -1488,7 +1497,7 @@ dependencies = [ [[package]] name = "iced_lazy" version = "0.2.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "iced_native", "ouroboros", @@ -1497,7 +1506,7 @@ dependencies = [ [[package]] name = "iced_native" version = "0.6.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "iced_core", "iced_futures", @@ -1511,7 +1520,7 @@ dependencies = [ [[package]] name = "iced_sctk" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "enum-repr", "futures", @@ -1530,7 +1539,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.5.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "iced_core", "once_cell", @@ -1540,7 +1549,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.6.1" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "bitflags", "bytemuck", @@ -1719,7 +1728,7 @@ checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic/?branch=master#db8b53b83699bf4e10c205873ba281de8d6a5bc3" +source = "git+https://github.com/pop-os/libcosmic/?branch=master#5fe445118ed1fbf8a98270777379c16826e2e8ad" dependencies = [ "apply", "cosmic-panel-config", @@ -2983,9 +2992,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" dependencies = [ "serde", ] diff --git a/applets/cosmic-app-list/i18n/en/cosmic_app_list.ftl b/applets/cosmic-app-list/i18n/en/cosmic_app_list.ftl index 2d5ea1e4..d3bffb22 100644 --- a/applets/cosmic-app-list/i18n/en/cosmic_app_list.ftl +++ b/applets/cosmic-app-list/i18n/en/cosmic_app_list.ftl @@ -1 +1,6 @@ cosmic-app-list = Cosmic Dock App List +favorite = Favorite +unfavorite = Un-Favorite +quit = Quit +quit-all = Quit All +new-window = New Window \ No newline at end of file diff --git a/applets/cosmic-app-list/src/app.rs b/applets/cosmic-app-list/src/app.rs index deb29d99..ad967fc7 100644 --- a/applets/cosmic-app-list/src/app.rs +++ b/applets/cosmic-app-list/src/app.rs @@ -1,8 +1,10 @@ +use std::collections::HashMap; use std::ffi::OsStr; use std::path::PathBuf; use crate::config; use crate::config::AppListConfig; +use crate::fl; use crate::toplevel_subscription::toplevel_subscription; use crate::toplevel_subscription::ToplevelRequest; use crate::toplevel_subscription::ToplevelUpdate; @@ -14,12 +16,16 @@ use cosmic::iced; use cosmic::iced::wayland::popup::destroy_popup; use cosmic::iced::wayland::popup::get_popup; use cosmic::iced::wayland::SurfaceIdWrapper; +use cosmic::iced::widget::event_container; use cosmic::iced::widget::{column, row}; use cosmic::iced::{executor, window, Application, Command, Subscription}; use cosmic::iced_native::subscription::events_with; use cosmic::iced_style::application::{self, Appearance}; use cosmic::iced_style::Color; use cosmic::theme::Button; +use cosmic::widget::rectangle_tracker::rectangle_tracker_subscription; +use cosmic::widget::rectangle_tracker::RectangleTracker; +use cosmic::widget::rectangle_tracker::RectangleUpdate; use cosmic::widget::{horizontal_rule, vertical_rule}; use cosmic::{Element, Theme}; use cosmic_panel_config::PanelAnchor; @@ -42,21 +48,50 @@ pub fn run() -> cosmic::iced::Result { #[derive(Debug, Clone, Default)] struct Toplevel { + id: u32, toplevels: Vec<(ZcosmicToplevelHandleV1, ToplevelInfo)>, desktop_info: DesktopInfo, + popup: Option, } #[derive(Clone, Default)] struct CosmicAppList { theme: Theme, popup: Option, - id_ctr: u32, + surface_id_ctr: u32, subscription_ctr: u32, + toplevel_ctr: u32, toplevel_list: Vec, config: AppListConfig, toplevel_sender: Option>, applet_helper: CosmicAppletHelper, seat: Option, + rectangle_tracker: Option>, + rectangles: HashMap, +} + +impl CosmicAppList { + fn window_size(&self) -> (u32, u32) { + let pixel_size = self.applet_helper.suggested_icon_size(); + let padding = 8; + let dot_size = 4; + let spacing = 4; + let mut length = self + .toplevel_list + .iter() + .map(|t| { + (pixel_size + 2 * padding).max((dot_size + spacing) * t.toplevels.len() as u16) + as u32 + + spacing as u32 + }) + .sum(); + length += spacing as u32 * 2 + 2; + let thickness = (pixel_size + 2 * padding + dot_size + spacing) as u32; + match self.applet_helper.anchor { + PanelAnchor::Left | PanelAnchor::Right => (thickness, length), + PanelAnchor::Top | PanelAnchor::Bottom => (length, thickness), + } + } } // TODO DnD after sctk merges DnD @@ -65,14 +100,15 @@ enum Message { Toplevel(ToplevelUpdate), Favorite(String), UnFavorite(String), - TogglePopup(usize), + Popup(String), Activate(ZcosmicToplevelHandleV1), Exec(String), - Quit(ZcosmicToplevelHandleV1), + Quit(String), Errored(String), Ignore, NewSeat(WlSeat), RemovedSeat(WlSeat), + Rectangle((RectangleUpdate)), } #[derive(Debug, Clone, Default)] @@ -88,13 +124,21 @@ fn desktop_info_for_app_ids(mut app_ids: Vec) -> Vec { .filter_map(|path| { std::fs::read_to_string(&path).ok().and_then(|input| { DesktopEntry::decode(&path, &input).ok().and_then(|de| { - if let Some(i) = app_ids.iter().position(|s| s == de.appid || s.eq(&de.name(None).unwrap_or_default())) { + if let Some(i) = app_ids + .iter() + .position(|s| s == de.appid || s.eq(&de.name(None).unwrap_or_default())) + { let id = app_ids.remove(i); freedesktop_icons::lookup(de.icon().unwrap_or(de.appid)) .with_size(128) .with_cache() .find() - .map(|buf| DesktopInfo {id, icon: buf, exec: de.exec().unwrap_or_default().to_string(), name: de.name(None).unwrap_or_default().to_string()}) + .map(|buf| DesktopInfo { + id, + icon: buf, + exec: de.exec().unwrap_or_default().to_string(), + name: de.name(None).unwrap_or_default().to_string(), + }) } else { None } @@ -105,7 +149,10 @@ fn desktop_info_for_app_ids(mut app_ids: Vec) -> Vec { ret.append( &mut app_ids .into_iter() - .map(|id| DesktopInfo { id, ..Default::default() }) + .map(|id| DesktopInfo { + id, + ..Default::default() + }) .collect_vec(), ); ret @@ -119,16 +166,23 @@ impl Application for CosmicAppList { fn new(_flags: ()) -> (Self, Command) { let config = config::AppListConfig::load().unwrap_or_default(); + let mut toplevel_ctr = 0; ( CosmicAppList { toplevel_list: desktop_info_for_app_ids(config.favorites.clone()) .into_iter() - .map(|e| Toplevel { - toplevels: Default::default(), - desktop_info: e + .map(|e| { + toplevel_ctr += 1; + Toplevel { + id: toplevel_ctr, + toplevels: Default::default(), + desktop_info: e, + popup: None, + } }) .collect(), config, + toplevel_ctr, ..Default::default() }, Command::none(), @@ -144,21 +198,45 @@ impl Application for CosmicAppList { Message::Errored(_) => { // TODO log errors } - Message::TogglePopup(_) => { - if let Some(p) = self.popup.take() { - return destroy_popup(p); - } else { - self.id_ctr += 1; - let new_id = window::Id::new(self.id_ctr); - self.popup.replace(new_id); + Message::Popup(id) => { + if let Some(toplevel_group) = self + .toplevel_list + .iter_mut() + .find(|t| t.desktop_info.id == id) + { + if let Some(p) = self.popup.take() { + toplevel_group.popup.take(); + return destroy_popup(p); + } + let rectangle = match self.rectangles.get(&toplevel_group.id) { + Some(r) => r, + None => return Command::none(), + }; - let popup_settings = self.applet_helper.get_popup_settings( + self.surface_id_ctr += 1; + let new_id = window::Id::new(self.surface_id_ctr); + self.popup.replace(new_id); + toplevel_group.popup.replace(new_id); + + let mut popup_settings = self.applet_helper.get_popup_settings( window::Id::new(0), new_id, - (400, 240), + (200, 240 + toplevel_group.toplevels.len() as u32 * 20), None, None, ); + let iced::Rectangle { + x, + y, + width, + height, + } = *rectangle; + popup_settings.positioner.anchor_rect = iced::Rectangle:: { + x: x as i32, + y: y as i32, + width: width as i32, + height: height as i32, + }; return get_popup(popup_settings); } } @@ -167,58 +245,58 @@ impl Application for CosmicAppList { } Message::UnFavorite(id) => { let _ = self.config.remove_favorite(id); + self.toplevel_list.retain(|t| { + self.config.favorites.contains(&t.desktop_info.id) + || self.config.favorites.contains(&t.desktop_info.name) + }) } Message::Activate(handle) => { - if let (Some(tx), Some(seat)) = (self.toplevel_sender.as_ref(), self.seat.as_ref()) { + if let Some(p) = self.popup.take() { + if let Some(toplevel_group) = + self.toplevel_list.iter_mut().find(|t| t.popup == Some(p)) + { + toplevel_group.popup.take(); + } + return destroy_popup(p); + } + if let (Some(tx), Some(seat)) = (self.toplevel_sender.as_ref(), self.seat.as_ref()) + { let _ = tx.send(ToplevelRequest::Activate(handle, seat.clone())); } } - Message::Quit(handle) => { - if let Some(tx) = self.toplevel_sender.as_ref() { - let _ = tx.send(ToplevelRequest::Quit(handle)); + Message::Quit(id) => { + if let Some(toplevel_group) = + self.toplevel_list.iter().find(|t| t.desktop_info.id == id) + { + for (handle, _) in &toplevel_group.toplevels { + if let Some(tx) = self.toplevel_sender.as_ref() { + let _ = tx.send(ToplevelRequest::Quit(handle.clone())); + } + } } } Message::Toplevel(event) => { - // dbg!(&self.toplevel_list); match event { ToplevelUpdate::AddToplevel(handle, info) => { if info.app_id == "" { return Command::none(); } - if let Some(i) = self - .toplevel_list - .iter() - .position(|Toplevel { desktop_info, .. }| &desktop_info.id == &info.app_id) - { + if let Some(i) = self.toplevel_list.iter().position( + |Toplevel { desktop_info, .. }| &desktop_info.id == &info.app_id, + ) { self.toplevel_list[i].toplevels.push((handle, info)); } else { let desktop_info = desktop_info_for_app_ids(vec![info.app_id.clone()]).remove(0); - + self.toplevel_ctr += 1; self.toplevel_list.push(Toplevel { + id: self.toplevel_ctr, toplevels: vec![(handle, info)], - desktop_info + desktop_info, + popup: None, }); - // TODO better way of setting window size? - let pixel_size = self.applet_helper.suggested_icon_size(); - let padding = 8; - let dot_size = 4; - let spacing = 4; - let length = self - .toplevel_list - .iter() - .map(|t| { - (pixel_size + 2 * padding) - .max((dot_size + spacing) * t.toplevels.len() as u16) - as u32 - + spacing as u32 - }) - .sum(); - let thickness = (pixel_size + 2 * padding + dot_size + spacing) as u32; - let (w, h) = match self.applet_helper.anchor { - PanelAnchor::Left | PanelAnchor::Right => (thickness, length), - PanelAnchor::Top | PanelAnchor::Bottom => (length, thickness), - }; + + let (w, h) = self.window_size(); return resize_window(window::Id::new(0), w, h); } } @@ -234,11 +312,15 @@ impl Application for CosmicAppList { ToplevelUpdate::RemoveToplevel(handle) => { if let Some(i) = self.toplevel_list.iter_mut().position( |Toplevel { - toplevels, desktop_info, .. + toplevels, + desktop_info, + .. }| { if let Some(ret) = toplevels.iter().position(|t| &t.0 == &handle) { toplevels.remove(ret); - toplevels.is_empty() && self.config.favorites.contains(&desktop_info.id) + toplevels.is_empty() + && !self.config.favorites.contains(&desktop_info.id) + && !self.config.favorites.contains(&desktop_info.name) } else { false } @@ -246,26 +328,7 @@ impl Application for CosmicAppList { ) { self.toplevel_list.remove(i); } - // TODO better way of setting window size? - let pixel_size = self.applet_helper.suggested_icon_size(); - let padding = 8; - let dot_size = 4; - let spacing = 4; - let length = self - .toplevel_list - .iter() - .map(|t| { - (pixel_size + 2 * padding) - .max((dot_size + spacing) * t.toplevels.len() as u16) - as u32 - + spacing as u32 - }) - .sum(); - let thickness = (pixel_size + 2 * padding + dot_size + spacing) as u32; - let (w, h) = match self.applet_helper.anchor { - PanelAnchor::Left | PanelAnchor::Right => (thickness, length), - PanelAnchor::Top | PanelAnchor::Bottom => (length, thickness), - }; + let (w, h) = self.window_size(); return resize_window(window::Id::new(0), w, h); } ToplevelUpdate::UpdateToplevel(handle, info) => { @@ -281,37 +344,17 @@ impl Application for CosmicAppList { } } } - // TODO better way of setting window size? - let pixel_size = self.applet_helper.suggested_icon_size(); - let padding = 8; - let dot_size = 4; - let spacing = 4; - let length = self - .toplevel_list - .iter() - .map(|t| { - (pixel_size + 2 * padding) - .max((dot_size + spacing) * t.toplevels.len() as u16) - as u32 - + spacing as u32 - }) - .sum(); - let thickness = (pixel_size + 2 * padding + dot_size + spacing) as u32; - let (w, h) = match self.applet_helper.anchor { - PanelAnchor::Left | PanelAnchor::Right => (thickness, length), - PanelAnchor::Top | PanelAnchor::Bottom => (length, thickness), - }; + let (w, h) = self.window_size(); return resize_window(window::Id::new(0), w, h); } } } - Message::Ignore => {} Message::NewSeat(s) => { self.seat.replace(s); - }, + } Message::RemovedSeat(_) => { self.seat.take(); - }, + } Message::Exec(exec_str) => { let mut exec = shlex::Shlex::new(&exec_str); let mut cmd = match exec.next() { @@ -325,7 +368,16 @@ impl Application for CosmicAppList { } } let _ = cmd.spawn(); + } + Message::Rectangle(u) => match u { + RectangleUpdate::Rectangle(r) => { + self.rectangles.insert(r.0, r.1); + } + RectangleUpdate::Init(tracker) => { + self.rectangle_tracker.replace(tracker); + } }, + Message::Ignore => {} } Command::none() } @@ -334,16 +386,15 @@ impl Application for CosmicAppList { match id { SurfaceIdWrapper::LayerSurface(_) => unimplemented!(), SurfaceIdWrapper::Window(_) => { - let (favorites, running) = self.toplevel_list.iter().enumerate().fold( + let (favorites, running) = self.toplevel_list.iter().fold( (Vec::new(), Vec::new()), |(mut favorites, mut running), - ( - i, - Toplevel { - toplevels, - desktop_info - }, - )| { + Toplevel { + id, + toplevels, + desktop_info, + .. + }| { let icon = if desktop_info.icon.extension() == Some(&OsStr::new("svg")) { let handle = svg::Handle::from_path(&desktop_info.icon); svg::Svg::new(handle) @@ -396,12 +447,28 @@ impl Application for CosmicAppList { .into(), }; // TODO tooltip on hover - let icon_button = cosmic::widget::button(Button::Text) - .custom(vec![icon_wrapper]) - .on_press(toplevels.first().map(|t| Message::Activate(t.0.clone())).unwrap_or_else(|| Message::Exec(desktop_info.exec.clone()))) - .padding(8) - .into(); - if self.config.favorites.contains(&desktop_info.id) || self.config.favorites.contains(&desktop_info.name) { + let icon_button = event_container( + cosmic::widget::button(Button::Text) + .custom(vec![icon_wrapper]) + .on_press( + toplevels + .first() + .map(|t| Message::Activate(t.0.clone())) + .unwrap_or_else(|| { + Message::Exec(desktop_info.exec.clone()) + }), + ) + .padding(8), + ) + .on_right_release(Message::Popup(desktop_info.id.clone())); + let icon_button = if let Some(tracker) = self.rectangle_tracker.as_ref() { + tracker.container(*id, icon_button).into() + } else { + icon_button.into() + }; + if self.config.favorites.contains(&desktop_info.id) + || self.config.favorites.contains(&desktop_info.name) + { favorites.push(icon_button) } else { running.push(icon_button); @@ -409,6 +476,7 @@ impl Application for CosmicAppList { (favorites, running) }, ); + match &self.applet_helper.anchor { PanelAnchor::Left | PanelAnchor::Right => { column![column(favorites), horizontal_rule(1), column(running)] @@ -428,8 +496,69 @@ impl Application for CosmicAppList { } } } - SurfaceIdWrapper::Popup(_) => { - todo!(); + SurfaceIdWrapper::Popup(p) => { + if let Some(Toplevel { + toplevels, + desktop_info, + .. + }) = self.toplevel_list.iter().find(|t| t.popup == Some(p)) + { + let is_favorite = self.config.favorites.contains(&desktop_info.id) + || self.config.favorites.contains(&desktop_info.name); + + let mut content = column![ + iced::widget::text(&desktop_info.name), + cosmic::widget::button(Button::Text) + .custom(vec![iced::widget::text(fl!("new-window")).into()]) + .on_press(Message::Exec(desktop_info.exec.clone())), + ] + .padding(4) + .spacing(4) + .align_items(Alignment::Center); + if !toplevels.is_empty() { + let mut list_col = column![]; + for (handle, info) in toplevels { + let title = if info.title.len() > 20 { + format!("{:.20}...", &info.title) + } else { + info.title.clone() + }; + list_col = list_col.push( + cosmic::widget::button(Button::Text) + .custom(vec![iced::widget::text(title).into()]) + .on_press(Message::Activate(handle.clone())), + ); + } + content = content.push(horizontal_rule(1)); + content = content.push(list_col); + content = content.push(horizontal_rule(1)); + } + content = content.push(if is_favorite { + cosmic::widget::button(Button::Text) + .custom(vec![iced::widget::text(fl!("unfavorite")).into()]) + .on_press(Message::UnFavorite(desktop_info.id.clone())) + } else { + cosmic::widget::button(Button::Text) + .custom(vec![iced::widget::text(fl!("favorite")).into()]) + .on_press(Message::Favorite(desktop_info.id.clone())) + }); + + if toplevels.len() == 1 { + content = content.push( + cosmic::widget::button(Button::Text) + .custom(vec![iced::widget::text(fl!("quit")).into()]) + .on_press(Message::Quit(desktop_info.id.clone())), + ) + } else if toplevels.len() > 1 { + content = content.push( + cosmic::widget::button(Button::Text) + .custom(vec![iced::widget::text(&fl!("quit-all")).into()]) + .on_press(Message::Quit(desktop_info.id.clone())), + ) + } + return self.applet_helper.popup_container(content).into(); + } + return horizontal_space(Length::Units(0)).into(); } } } @@ -437,7 +566,7 @@ impl Application for CosmicAppList { fn subscription(&self) -> Subscription { Subscription::batch(vec![ toplevel_subscription(self.subscription_ctr).map(|(_, event)| Message::Toplevel(event)), - events_with(|e, status| match e { + events_with(|e, _| match e { cosmic::iced_native::Event::PlatformSpecific( cosmic::iced_native::event::PlatformSpecific::Wayland( cosmic::iced_native::event::wayland::Event::Seat(e, seat), @@ -445,13 +574,14 @@ impl Application for CosmicAppList { ) => match e { cosmic::iced_native::event::wayland::SeatEvent::Enter => { Some(Message::NewSeat(seat)) - }, + } cosmic::iced_native::event::wayland::SeatEvent::Leave => { Some(Message::RemovedSeat(seat)) - }, + } }, - _ => None + _ => None, }), + rectangle_tracker_subscription(0).map(|(_, update)| Message::Rectangle(update)), ]) } diff --git a/applets/cosmic-app-list/src/config.rs b/applets/cosmic-app-list/src/config.rs index adb84c51..1a35b98d 100644 --- a/applets/cosmic-app-list/src/config.rs +++ b/applets/cosmic-app-list/src/config.rs @@ -1,5 +1,5 @@ use anyhow::anyhow; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use std::fmt::Debug; use std::fs::File; use std::path::PathBuf; diff --git a/applets/cosmic-app-list/src/main.rs b/applets/cosmic-app-list/src/main.rs index 9431be12..4d0ff468 100644 --- a/applets/cosmic-app-list/src/main.rs +++ b/applets/cosmic-app-list/src/main.rs @@ -16,7 +16,6 @@ fn main() -> cosmic::iced::Result { pretty_env_logger::init(); info!("Iced Workspaces Applet ({})", APP_ID); info!("Version: {}", VERSION); - config::AppListConfig::default().save().unwrap(); // Prepare i18n localize(); diff --git a/applets/cosmic-app-list/src/toplevel_handler.rs b/applets/cosmic-app-list/src/toplevel_handler.rs index a6137785..a5b23762 100644 --- a/applets/cosmic-app-list/src/toplevel_handler.rs +++ b/applets/cosmic-app-list/src/toplevel_handler.rs @@ -1,18 +1,19 @@ +use crate::toplevel_subscription::{ToplevelRequest, ToplevelUpdate}; use cctk::{ - sctk::{self, event_loop::WaylandSource, seat::{SeatHandler, SeatState}, reexports::client::protocol::wl_seat::WlSeat}, + sctk::{ + self, + event_loop::WaylandSource, + reexports::client::protocol::wl_seat::WlSeat, + seat::{SeatHandler, SeatState}, + }, toplevel_info::{ToplevelInfoHandler, ToplevelInfoState}, toplevel_management::{ToplevelManagerHandler, ToplevelManagerState}, - wayland_client::{self, Proxy, backend::ObjectId}, -}; -use cosmic_protocols::{ - toplevel_info::v1::client::zcosmic_toplevel_handle_v1, - toplevel_management::v1::client::zcosmic_toplevel_manager_v1, + wayland_client, }; +use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1; use futures::channel::mpsc::UnboundedSender; use sctk::registry::{ProvidesRegistryState, RegistryState}; use wayland_client::{globals::registry_queue_init, Connection, QueueHandle}; -use itertools::Itertools; -use crate::toplevel_subscription::{ToplevelRequest, ToplevelUpdate}; struct AppData { exit: bool, @@ -36,25 +37,27 @@ impl SeatHandler for AppData { &mut self.seat_state } - fn new_seat(&mut self, conn: &Connection, qh: &QueueHandle, seat: WlSeat) {} + fn new_seat(&mut self, _: &Connection, _: &QueueHandle, _: WlSeat) {} fn new_capability( &mut self, - conn: &Connection, - qh: &QueueHandle, - seat: WlSeat, - capability: sctk::seat::Capability, - ) {} + _: &Connection, + _: &QueueHandle, + _: WlSeat, + _: sctk::seat::Capability, + ) { + } fn remove_capability( &mut self, - conn: &Connection, - qh: &QueueHandle, - seat: WlSeat, - capability: sctk::seat::Capability, - ) {} + _: &Connection, + _: &QueueHandle, + _: WlSeat, + _: sctk::seat::Capability, + ) { + } - fn remove_seat(&mut self, conn: &Connection, qh: &QueueHandle, seat: WlSeat) {} + fn remove_seat(&mut self, _: &Connection, _: &QueueHandle, _: WlSeat) {} } impl ToplevelManagerHandler for AppData { @@ -62,7 +65,7 @@ impl ToplevelManagerHandler for AppData { &mut self.toplevel_manager_state } - fn capabilities(&mut self, conn: &Connection, qh: &QueueHandle, capabilities: Vec) { + fn capabilities(&mut self, _: &Connection, _: &QueueHandle, _: Vec) { // TODO capabilities could affect the options in the applet } } @@ -133,11 +136,13 @@ pub(crate) fn toplevel_handler( .insert_source(rx, |event, _, state| match event { calloop::channel::Event::Msg(req) => match req { ToplevelRequest::Activate(handle, seat) => { - let manager = &state.toplevel_manager_state.manager; manager.activate(&handle, &seat); - } // TODO - ToplevelRequest::Quit(_) => {} // TODO + } + ToplevelRequest::Quit(handle) => { + let manager = &state.toplevel_manager_state.manager; + manager.close(&handle); + } ToplevelRequest::Exit => { state.exit = true; }