wip: update libcosmic (#93)
* wip: update libcosmic * fix: damge issue resolved by updating iced * fix: high cpu usage by time applet and app-list * refactor subscriptions to produce fewer events * refactor network applet to use less cpu * fix: text size * refactor: i18n for audio applet * refactor: power applet i18n setup * fix (battery): always send profile update * fix (battery): set toggler width to layout correctly * fix (app-list): backoff for restarts of toplevel subscription * fix (network): alignment * feat: ask for comfirmation before applying power applet actions * wip: integrate cosmic-config * update zbus * feat: update to use latest libcosmic * update iced * udpate deps * update deps * refactor: move applet helpers to this repo, outside of libcosmic. this should help alleviate some dependency hell * chore update deps * update deps * cleanup
This commit is contained in:
parent
8b46cc209f
commit
9ebd9b511a
48 changed files with 2841 additions and 1681 deletions
|
|
@ -1,10 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::config;
|
||||
use crate::config::AppListConfig;
|
||||
use crate::config::APP_ID;
|
||||
use crate::fl;
|
||||
use crate::toplevel_subscription::toplevel_subscription;
|
||||
use crate::toplevel_subscription::ToplevelRequest;
|
||||
|
|
@ -13,46 +9,56 @@ use calloop::channel::Sender;
|
|||
use cctk::toplevel_info::ToplevelInfo;
|
||||
use cctk::wayland_client::protocol::wl_data_device_manager::DndAction;
|
||||
use cctk::wayland_client::protocol::wl_seat::WlSeat;
|
||||
use cosmic::applet::cosmic_panel_config::PanelAnchor;
|
||||
use cosmic::applet::CosmicAppletHelper;
|
||||
use cosmic::cosmic_config;
|
||||
use cosmic::cosmic_config::Config;
|
||||
use cosmic::iced;
|
||||
use cosmic::iced::subscription::events_with;
|
||||
use cosmic::iced::wayland::actions::data_device::DataFromMimeType;
|
||||
use cosmic::iced::wayland::actions::data_device::DndIcon;
|
||||
use cosmic::iced::wayland::actions::window::SctkWindowSettings;
|
||||
use cosmic::iced::wayland::popup::destroy_popup;
|
||||
use cosmic::iced::wayland::popup::get_popup;
|
||||
use cosmic::iced::widget::{column, dnd_source, mouse_listener, row, text, Column, Row};
|
||||
use cosmic::iced::widget::dnd_listener;
|
||||
use cosmic::iced::widget::vertical_rule;
|
||||
use cosmic::iced::widget::vertical_space;
|
||||
use cosmic::iced::widget::{column, dnd_source, mouse_area, row, Column, Row};
|
||||
use cosmic::iced::Color;
|
||||
use cosmic::iced::Limits;
|
||||
use cosmic::iced::Settings;
|
||||
use cosmic::iced::{window, Application, Command, Subscription};
|
||||
use cosmic::iced_native as native;
|
||||
use cosmic::iced_native::alignment::Horizontal;
|
||||
use cosmic::iced_native::subscription::events_with;
|
||||
use cosmic::iced_native::widget::vertical_space;
|
||||
use cosmic::iced_runtime::core::alignment::Horizontal;
|
||||
use cosmic::iced_runtime::core::event;
|
||||
use cosmic::iced_sctk::commands::data_device::accept_mime_type;
|
||||
use cosmic::iced_sctk::commands::data_device::finish_dnd;
|
||||
use cosmic::iced_sctk::commands::data_device::request_dnd_data;
|
||||
use cosmic::iced_sctk::commands::data_device::set_actions;
|
||||
use cosmic::iced_sctk::commands::data_device::start_drag;
|
||||
use cosmic::iced_sctk::layout::Limits;
|
||||
use cosmic::iced_sctk::settings::InitialSurface;
|
||||
use cosmic::iced_sctk::widget::dnd_listener;
|
||||
use cosmic::iced_sctk::widget::vertical_rule;
|
||||
use cosmic::iced_style::application::{self, Appearance};
|
||||
use cosmic::iced_style::Color;
|
||||
use cosmic::theme::Button;
|
||||
use cosmic::widget::divider;
|
||||
use cosmic::widget::rectangle_tracker::rectangle_tracker_subscription;
|
||||
use cosmic::widget::rectangle_tracker::RectangleTracker;
|
||||
use cosmic::widget::rectangle_tracker::RectangleUpdate;
|
||||
use cosmic::{Element, Theme};
|
||||
use cosmic_applet::cosmic_panel_config::PanelAnchor;
|
||||
use cosmic_applet::CosmicAppletHelper;
|
||||
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1;
|
||||
use freedesktop_desktop_entry::DesktopEntry;
|
||||
use futures::future::pending;
|
||||
use iced::widget::container;
|
||||
use iced::Alignment;
|
||||
use iced::Background;
|
||||
use iced::Length;
|
||||
use itertools::Itertools;
|
||||
use native::event;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use tokio::time::sleep;
|
||||
use url::Url;
|
||||
|
||||
static MIME_TYPE: &str = "text/uri-list";
|
||||
|
|
@ -71,15 +77,12 @@ pub fn run() -> cosmic::iced::Result {
|
|||
|
||||
CosmicAppList::run(Settings {
|
||||
initial_surface: InitialSurface::XdgWindow(SctkWindowSettings {
|
||||
iced_settings: cosmic::iced_native::window::Settings {
|
||||
..Default::default()
|
||||
},
|
||||
autosize: true,
|
||||
size_limits: Limits::NONE
|
||||
.min_height(1)
|
||||
.min_width(1)
|
||||
.max_height(h)
|
||||
.max_width(w),
|
||||
.min_height(1.0)
|
||||
.min_width(1.0)
|
||||
.max_height(h as f32)
|
||||
.max_width(w as f32),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
|
|
@ -144,19 +147,19 @@ impl DockItem {
|
|||
let dots = (0..toplevels.len())
|
||||
.into_iter()
|
||||
.map(|_| {
|
||||
container(vertical_space(Length::Units(0)))
|
||||
container(vertical_space(Length::Fixed(0.0)))
|
||||
.padding(dot_radius)
|
||||
.style(<<CosmicAppList as cosmic::iced::Application>::Theme as container::StyleSheet>::Style::Custom(
|
||||
.style(<<CosmicAppList as cosmic::iced::Application>::Theme as container::StyleSheet>::Style::Custom(Box::new(
|
||||
|theme| container::Appearance {
|
||||
text_color: Some(Color::TRANSPARENT),
|
||||
background: Some(Background::Color(
|
||||
theme.cosmic().on_bg_color().into(),
|
||||
)),
|
||||
border_radius: 4.0,
|
||||
border_radius: 4.0.into(),
|
||||
border_width: 0.0,
|
||||
border_color: Color::TRANSPARENT,
|
||||
},
|
||||
))
|
||||
)))
|
||||
.into()
|
||||
})
|
||||
.collect_vec();
|
||||
|
|
@ -179,12 +182,12 @@ impl DockItem {
|
|||
.into(),
|
||||
};
|
||||
|
||||
let mut icon_button = cosmic::widget::button(Button::Text)
|
||||
let icon_button = cosmic::widget::button(Button::Text)
|
||||
.custom(vec![icon_wrapper])
|
||||
.padding(8);
|
||||
let icon_button = if interaction_enabled {
|
||||
dnd_source(
|
||||
mouse_listener(
|
||||
mouse_area(
|
||||
icon_button
|
||||
.on_press(
|
||||
toplevels
|
||||
|
|
@ -222,7 +225,7 @@ struct DndOffer {
|
|||
struct CosmicAppList {
|
||||
theme: Theme,
|
||||
popup: Option<(window::Id, DockItem)>,
|
||||
surface_id_ctr: u32,
|
||||
surface_id_ctr: u128,
|
||||
subscription_ctr: u32,
|
||||
item_ctr: u32,
|
||||
active_list: Vec<DockItem>,
|
||||
|
|
@ -262,6 +265,8 @@ enum Message {
|
|||
DndData(PathBuf),
|
||||
StartListeningForDnd,
|
||||
StopListeningForDnd,
|
||||
IncrementSubscriptionCtr,
|
||||
ConfigUpdated(AppListConfig),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
|
@ -363,22 +368,20 @@ impl Application for CosmicAppList {
|
|||
|
||||
fn new(_flags: ()) -> (Self, Command<Message>) {
|
||||
let config = config::AppListConfig::load().unwrap_or_default();
|
||||
let mut favorite_ctr = 0;
|
||||
let self_ = CosmicAppList {
|
||||
let mut self_ = CosmicAppList {
|
||||
favorite_list: desktop_info_for_app_ids(config.favorites.clone())
|
||||
.into_iter()
|
||||
.map(|e| {
|
||||
favorite_ctr += 1;
|
||||
DockItem {
|
||||
id: favorite_ctr,
|
||||
toplevels: Default::default(),
|
||||
desktop_info: e,
|
||||
}
|
||||
.enumerate()
|
||||
.map(|(favorite_ctr, e)| DockItem {
|
||||
id: favorite_ctr as u32,
|
||||
toplevels: Default::default(),
|
||||
desktop_info: e,
|
||||
})
|
||||
.collect(),
|
||||
config,
|
||||
..Default::default()
|
||||
};
|
||||
self_.item_ctr = self_.favorite_list.len() as u32;
|
||||
|
||||
(self_, Command::none())
|
||||
}
|
||||
|
|
@ -405,11 +408,11 @@ impl Application for CosmicAppList {
|
|||
};
|
||||
|
||||
self.surface_id_ctr += 1;
|
||||
let new_id = window::Id::new(self.surface_id_ctr);
|
||||
let new_id = window::Id(self.surface_id_ctr);
|
||||
self.popup = Some((new_id, toplevel_group.clone()));
|
||||
|
||||
let mut popup_settings = self.applet_helper.get_popup_settings(
|
||||
window::Id::new(0),
|
||||
window::Id(0),
|
||||
new_id,
|
||||
None,
|
||||
None,
|
||||
|
|
@ -440,13 +443,16 @@ impl Application for CosmicAppList {
|
|||
self.favorite_list.push(entry);
|
||||
}
|
||||
|
||||
let _ = self.config.add_favorite(id);
|
||||
self.config
|
||||
.add_favorite(id, &Config::new(APP_ID, 1).unwrap());
|
||||
if let Some((popup_id, _toplevel)) = self.popup.take() {
|
||||
return destroy_popup(popup_id);
|
||||
}
|
||||
}
|
||||
Message::UnFavorite(id) => {
|
||||
let _ = self.config.remove_favorite(id.clone());
|
||||
let _ = self
|
||||
.config
|
||||
.remove_favorite(id.clone(), &Config::new(APP_ID, 1).unwrap());
|
||||
if let Some(i) = self
|
||||
.favorite_list
|
||||
.iter()
|
||||
|
|
@ -506,7 +512,10 @@ impl Application for CosmicAppList {
|
|||
.position(|t| t.desktop_info.id == id)
|
||||
{
|
||||
let t = self.favorite_list.remove(pos);
|
||||
let _ = self.config.remove_favorite(t.desktop_info.id.clone());
|
||||
let _ = self.config.remove_favorite(
|
||||
t.desktop_info.id.clone(),
|
||||
&Config::new(APP_ID, 1).unwrap(),
|
||||
);
|
||||
Some((true, t))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -514,7 +523,7 @@ impl Application for CosmicAppList {
|
|||
})
|
||||
{
|
||||
self.surface_id_ctr += 1;
|
||||
let icon_id = window::Id::new(self.surface_id_ctr);
|
||||
let icon_id = window::Id(self.surface_id_ctr);
|
||||
self.dnd_source = Some((icon_id, toplevel_group.clone(), DndAction::empty()));
|
||||
return start_drag(
|
||||
vec![MIME_TYPE.to_string()],
|
||||
|
|
@ -523,7 +532,7 @@ impl Application for CosmicAppList {
|
|||
} else {
|
||||
DndAction::Copy
|
||||
},
|
||||
window::Id::new(0),
|
||||
window::Id(0),
|
||||
Some(DndIcon::Custom(icon_id)),
|
||||
Box::new(toplevel_group.clone()),
|
||||
);
|
||||
|
|
@ -629,7 +638,10 @@ impl Application for CosmicAppList {
|
|||
.and_then(|o| o.dock_item.map(|i| (i, o.preview_index)))
|
||||
{
|
||||
self.item_ctr += 1;
|
||||
let _ = self.config.add_favorite(dock_item.desktop_info.id.clone());
|
||||
let _ = self.config.add_favorite(
|
||||
dock_item.desktop_info.id.clone(),
|
||||
&Config::new(APP_ID, 1).unwrap(),
|
||||
);
|
||||
if let Some((pos, is_favorite)) = self
|
||||
.active_list
|
||||
.iter()
|
||||
|
|
@ -689,11 +701,26 @@ impl Application for CosmicAppList {
|
|||
self.toplevel_sender.replace(tx);
|
||||
}
|
||||
ToplevelUpdate::Finished => {
|
||||
self.subscription_ctr += 1;
|
||||
for t in &mut self.favorite_list {
|
||||
t.toplevels.clear();
|
||||
}
|
||||
self.active_list.clear();
|
||||
let subscription_ctr = self.subscription_ctr;
|
||||
let mut rng = thread_rng();
|
||||
let rand_d = rng.gen_range(0..100);
|
||||
return Command::perform(
|
||||
async move {
|
||||
if let Some(millis) = 2u64
|
||||
.checked_pow(subscription_ctr)
|
||||
.and_then(|d| d.checked_add(rand_d))
|
||||
{
|
||||
sleep(Duration::from_millis(millis)).await;
|
||||
} else {
|
||||
pending::<()>().await;
|
||||
}
|
||||
},
|
||||
|_| Message::IncrementSubscriptionCtr,
|
||||
);
|
||||
}
|
||||
ToplevelUpdate::RemoveToplevel(handle) => {
|
||||
for t in self
|
||||
|
|
@ -765,6 +792,49 @@ impl Application for CosmicAppList {
|
|||
Message::StopListeningForDnd => {
|
||||
self.is_listening_for_dnd = false;
|
||||
}
|
||||
Message::IncrementSubscriptionCtr => {
|
||||
self.subscription_ctr += 1;
|
||||
}
|
||||
Message::ConfigUpdated(config) => {
|
||||
self.config = config;
|
||||
|
||||
let mut new_list: Vec<_> = desktop_info_for_app_ids(self.config.favorites.clone())
|
||||
.into_iter()
|
||||
.map(|e| {
|
||||
self.item_ctr += 1;
|
||||
|
||||
DockItem {
|
||||
id: self.item_ctr,
|
||||
toplevels: Default::default(),
|
||||
desktop_info: e,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
for item in &mut new_list {
|
||||
if let Some(old_item) = self
|
||||
.favorite_list
|
||||
.iter()
|
||||
.position(|i| i.desktop_info.id == item.desktop_info.id)
|
||||
{
|
||||
let old_item = self.favorite_list.swap_remove(old_item);
|
||||
*item = old_item;
|
||||
} else if let Some(old_item) = self
|
||||
.active_list
|
||||
.iter()
|
||||
.position(|i| i.desktop_info.id == item.desktop_info.id)
|
||||
{
|
||||
let old_item = self.active_list.remove(old_item);
|
||||
*item = old_item;
|
||||
}
|
||||
}
|
||||
|
||||
for item in self.favorite_list.drain(..) {
|
||||
self.active_list.push(item);
|
||||
}
|
||||
|
||||
self.favorite_list = new_list;
|
||||
}
|
||||
}
|
||||
Command::none()
|
||||
}
|
||||
|
|
@ -970,7 +1040,7 @@ impl Application for CosmicAppList {
|
|||
),
|
||||
};
|
||||
if self.popup.is_some() {
|
||||
mouse_listener(content)
|
||||
mouse_area(content)
|
||||
.on_right_release(Message::ClosePopup)
|
||||
.on_press(Message::ClosePopup)
|
||||
.into()
|
||||
|
|
@ -981,48 +1051,58 @@ impl Application for CosmicAppList {
|
|||
|
||||
fn subscription(&self) -> Subscription<Message> {
|
||||
Subscription::batch(vec![
|
||||
toplevel_subscription(self.subscription_ctr).map(|(_, event)| Message::Toplevel(event)),
|
||||
toplevel_subscription(self.subscription_ctr).map(|e| Message::Toplevel(e.1)),
|
||||
events_with(|e, _| match e {
|
||||
native::Event::PlatformSpecific(event::PlatformSpecific::Wayland(
|
||||
event::wayland::Event::Seat(e, seat),
|
||||
)) => match e {
|
||||
cosmic::iced_runtime::core::Event::PlatformSpecific(
|
||||
event::PlatformSpecific::Wayland(event::wayland::Event::Seat(e, seat)),
|
||||
) => match e {
|
||||
event::wayland::SeatEvent::Enter => Some(Message::NewSeat(seat)),
|
||||
event::wayland::SeatEvent::Leave => Some(Message::RemovedSeat(seat)),
|
||||
},
|
||||
// XXX Must be done to catch a finished drag after the source is removed
|
||||
// (for now, the source is removed when the drag starts)
|
||||
native::Event::PlatformSpecific(event::PlatformSpecific::Wayland(
|
||||
event::wayland::Event::DataSource(
|
||||
cosmic::iced_runtime::core::Event::PlatformSpecific(
|
||||
event::PlatformSpecific::Wayland(event::wayland::Event::DataSource(
|
||||
event::wayland::DataSourceEvent::DndFinished
|
||||
| event::wayland::DataSourceEvent::Cancelled,
|
||||
),
|
||||
)) => Some(Message::DragFinished),
|
||||
native::Event::PlatformSpecific(event::PlatformSpecific::Wayland(
|
||||
event::wayland::Event::DndOffer(event::wayland::DndOfferEvent::Enter {
|
||||
mime_types,
|
||||
..
|
||||
}),
|
||||
)) => {
|
||||
)),
|
||||
) => Some(Message::DragFinished),
|
||||
cosmic::iced_runtime::core::Event::PlatformSpecific(
|
||||
event::PlatformSpecific::Wayland(event::wayland::Event::DndOffer(
|
||||
event::wayland::DndOfferEvent::Enter { mime_types, .. },
|
||||
)),
|
||||
) => {
|
||||
if mime_types.iter().any(|m| m == MIME_TYPE) {
|
||||
Some(Message::StartListeningForDnd)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
native::Event::PlatformSpecific(event::PlatformSpecific::Wayland(
|
||||
event::wayland::Event::DndOffer(
|
||||
cosmic::iced_runtime::core::Event::PlatformSpecific(
|
||||
event::PlatformSpecific::Wayland(event::wayland::Event::DndOffer(
|
||||
event::wayland::DndOfferEvent::Leave
|
||||
| event::wayland::DndOfferEvent::DropPerformed,
|
||||
),
|
||||
)) => Some(Message::StopListeningForDnd),
|
||||
)),
|
||||
) => Some(Message::StopListeningForDnd),
|
||||
_ => None,
|
||||
}),
|
||||
rectangle_tracker_subscription(0).map(|(_, update)| Message::Rectangle(update)),
|
||||
rectangle_tracker_subscription(0).map(|update| Message::Rectangle(update.1)),
|
||||
cosmic_config::config_subscription(0, Cow::from(APP_ID), 1).map(|(_, config)| {
|
||||
match config {
|
||||
Ok(config) => Message::ConfigUpdated(config),
|
||||
Err((errors, config)) => {
|
||||
for error in errors {
|
||||
log::error!("{:?}", error);
|
||||
}
|
||||
Message::ConfigUpdated(config)
|
||||
}
|
||||
}
|
||||
}),
|
||||
])
|
||||
}
|
||||
|
||||
fn theme(&self) -> Theme {
|
||||
self.theme
|
||||
self.theme.clone()
|
||||
}
|
||||
|
||||
fn close_requested(&self, _id: window::Id) -> Self::Message {
|
||||
|
|
@ -1030,9 +1110,9 @@ impl Application for CosmicAppList {
|
|||
}
|
||||
|
||||
fn style(&self) -> <Self::Theme as application::StyleSheet>::Style {
|
||||
<Self::Theme as application::StyleSheet>::Style::Custom(|theme| Appearance {
|
||||
<Self::Theme as application::StyleSheet>::Style::Custom(Box::new(|theme| Appearance {
|
||||
background_color: Color::from_rgba(0.0, 0.0, 0.0, 0.0),
|
||||
text_color: theme.cosmic().on_bg_color().into(),
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
use anyhow::anyhow;
|
||||
|
||||
use cosmic::cosmic_config::cosmic_config_derive::CosmicConfigEntry;
|
||||
use cosmic::cosmic_config::{self, Config, ConfigGet, ConfigSet, CosmicConfigEntry};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt::Debug;
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use xdg::BaseDirectories;
|
||||
|
||||
pub const APP_ID: &str = "com.system76.CosmicAppList";
|
||||
pub const VERSION: &str = "0.1.0";
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
|
||||
pub enum TopLevelFilter {
|
||||
#[default]
|
||||
ActiveWorkspace,
|
||||
ConfiguredOutput,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize)]
|
||||
#[derive(Debug, Clone, Default, Deserialize, Serialize, PartialEq, Eq, CosmicConfigEntry)]
|
||||
pub struct AppListConfig {
|
||||
pub filter_top_levels: Option<TopLevelFilter>,
|
||||
pub favorites: Vec<String>,
|
||||
|
|
@ -42,26 +44,17 @@ impl AppListConfig {
|
|||
.map_err(|err| anyhow!("Failed to parse config file: {}", err))
|
||||
}
|
||||
|
||||
pub fn add_favorite(&mut self, id: String) -> anyhow::Result<()> {
|
||||
pub fn add_favorite(&mut self, id: String, config: &Config) {
|
||||
if !self.favorites.contains(&id) {
|
||||
self.favorites.push(id);
|
||||
let _ = self.write_entry(&config);
|
||||
}
|
||||
self.save()
|
||||
}
|
||||
|
||||
pub fn remove_favorite(&mut self, id: String) -> anyhow::Result<()> {
|
||||
self.favorites.retain(|e| e != &id);
|
||||
self.save()
|
||||
}
|
||||
|
||||
// TODO async?
|
||||
pub fn save(&self) -> anyhow::Result<()> {
|
||||
let bd = BaseDirectories::new()?;
|
||||
let mut relative_path = PathBuf::from(APP_ID);
|
||||
relative_path.push("config.ron");
|
||||
let config_path = bd.place_config_file(relative_path)?;
|
||||
let f = File::create(config_path)?;
|
||||
ron::ser::to_writer_pretty(f, self, Default::default())?;
|
||||
Ok(())
|
||||
pub fn remove_favorite(&mut self, id: String, config: &Config) {
|
||||
if let Some(pos) = self.favorites.iter().position(|e| e == &id) {
|
||||
self.favorites.remove(pos);
|
||||
let _ = self.write_entry(&config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use futures::{
|
|||
channel::mpsc::{unbounded, UnboundedReceiver},
|
||||
StreamExt,
|
||||
};
|
||||
use std::{fmt::Debug, hash::Hash};
|
||||
use std::{fmt::Debug, hash::Hash, thread::JoinHandle};
|
||||
|
||||
use crate::toplevel_handler::toplevel_handler;
|
||||
|
||||
|
|
@ -26,31 +26,45 @@ pub enum State {
|
|||
Waiting(
|
||||
UnboundedReceiver<ToplevelUpdate>,
|
||||
calloop::channel::Sender<ToplevelRequest>,
|
||||
JoinHandle<()>,
|
||||
),
|
||||
Finished,
|
||||
}
|
||||
|
||||
async fn start_listening<I: Copy>(id: I, state: State) -> (Option<(I, ToplevelUpdate)>, State) {
|
||||
match state {
|
||||
State::Ready => {
|
||||
let (calloop_tx, calloop_rx) = calloop::channel::channel();
|
||||
let (toplevel_tx, toplevel_rx) = unbounded();
|
||||
std::thread::spawn(move || {
|
||||
toplevel_handler(toplevel_tx, calloop_rx);
|
||||
});
|
||||
(
|
||||
Some((id, ToplevelUpdate::Init(calloop_tx.clone()))),
|
||||
State::Waiting(toplevel_rx, calloop_tx),
|
||||
)
|
||||
}
|
||||
State::Waiting(mut rx, tx) => match rx.next().await {
|
||||
Some(u) => (Some((id, u)), State::Waiting(rx, tx)),
|
||||
None => {
|
||||
let _ = tx.send(ToplevelRequest::Exit);
|
||||
(Some((id, ToplevelUpdate::Finished)), State::Finished)
|
||||
async fn start_listening<I: Copy>(id: I, mut state: State) -> ((I, ToplevelUpdate), State) {
|
||||
loop {
|
||||
let (update, new_state) = match state {
|
||||
State::Ready => {
|
||||
let (calloop_tx, calloop_rx) = calloop::channel::channel();
|
||||
let (toplevel_tx, toplevel_rx) = unbounded();
|
||||
let handle = std::thread::spawn(move || {
|
||||
toplevel_handler(toplevel_tx, calloop_rx);
|
||||
});
|
||||
(
|
||||
Some((id, ToplevelUpdate::Init(calloop_tx.clone()))),
|
||||
State::Waiting(toplevel_rx, calloop_tx, handle),
|
||||
)
|
||||
}
|
||||
},
|
||||
State::Finished => iced::futures::future::pending().await,
|
||||
State::Waiting(mut rx, tx, handle) => {
|
||||
if handle.is_finished() {
|
||||
return ((id, ToplevelUpdate::Finished), State::Finished);
|
||||
}
|
||||
match rx.next().await {
|
||||
Some(u) => (Some((id, u)), State::Waiting(rx, tx, handle)),
|
||||
None => {
|
||||
let _ = tx.send(ToplevelRequest::Exit);
|
||||
(Some((id, ToplevelUpdate::Finished)), State::Finished)
|
||||
}
|
||||
}
|
||||
}
|
||||
State::Finished => iced::futures::future::pending().await,
|
||||
};
|
||||
|
||||
if let Some(update) = update {
|
||||
return (update, new_state);
|
||||
} else {
|
||||
state = new_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue