chore: apply recommendations from clippy
This commit is contained in:
parent
cec55dafd7
commit
8e0f1c4a09
56 changed files with 720 additions and 824 deletions
|
|
@ -42,7 +42,7 @@ impl AppListConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn remove_pinned(&mut self, id: &str, config: &Config) {
|
pub fn remove_pinned(&mut self, id: &str, config: &Config) {
|
||||||
if let Some(pos) = self.favorites.iter().position(|e| e == &id) {
|
if let Some(pos) = self.favorites.iter().position(|e| e == id) {
|
||||||
self.favorites.remove(pos);
|
self.favorites.remove(pos);
|
||||||
let _ = self.write_entry(config);
|
let _ = self.write_entry(config);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -269,22 +269,22 @@ impl DockItem {
|
||||||
.first()
|
.first()
|
||||||
.map(|t| Message::Toggle(t.0.foreign_toplevel.clone()))
|
.map(|t| Message::Toggle(t.0.foreign_toplevel.clone()))
|
||||||
} else {
|
} else {
|
||||||
Some(Message::TopLevelListPopup((*id).into(), window_id))
|
Some(Message::TopLevelListPopup(*id, window_id))
|
||||||
})
|
})
|
||||||
.width(Length::Shrink)
|
.width(Length::Shrink)
|
||||||
.height(Length::Shrink),
|
.height(Length::Shrink),
|
||||||
)
|
)
|
||||||
.on_right_release(Message::Popup((*id).into(), window_id))
|
.on_right_release(Message::Popup(*id, window_id))
|
||||||
.on_middle_release({
|
.on_middle_release({
|
||||||
launch_on_preferred_gpu(desktop_info, gpus)
|
launch_on_preferred_gpu(desktop_info, gpus)
|
||||||
.unwrap_or_else(|| Message::Popup((*id).into(), window_id))
|
.unwrap_or(Message::Popup(*id, window_id))
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
} else {
|
} else {
|
||||||
icon_button.into()
|
icon_button.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
let path = desktop_info.path.to_path_buf();
|
let path = desktop_info.path.clone();
|
||||||
let icon_button = if dnd_source_enabled && interaction_enabled {
|
let icon_button = if dnd_source_enabled && interaction_enabled {
|
||||||
dnd_source(icon_button)
|
dnd_source(icon_button)
|
||||||
.window(window_id)
|
.window(window_id)
|
||||||
|
|
@ -420,7 +420,7 @@ fn index_in_list(
|
||||||
|
|
||||||
if let Some(existing_preview) = existing_preview {
|
if let Some(existing_preview) = existing_preview {
|
||||||
if index >= existing_preview {
|
if index >= existing_preview {
|
||||||
index.checked_sub(1).unwrap_or_default()
|
index.saturating_sub(1)
|
||||||
} else {
|
} else {
|
||||||
index
|
index
|
||||||
}
|
}
|
||||||
|
|
@ -589,9 +589,10 @@ fn find_desktop_entries<'a>(
|
||||||
) -> impl Iterator<Item = fde::DesktopEntry> + 'a {
|
) -> impl Iterator<Item = fde::DesktopEntry> + 'a {
|
||||||
app_ids.iter().map(|fav| {
|
app_ids.iter().map(|fav| {
|
||||||
let unicase_fav = fde::unicase::Ascii::new(fav.as_str());
|
let unicase_fav = fde::unicase::Ascii::new(fav.as_str());
|
||||||
fde::find_app_by_id(desktop_entries, unicase_fav)
|
fde::find_app_by_id(desktop_entries, unicase_fav).map_or_else(
|
||||||
.map(ToOwned::to_owned)
|
|| fde::DesktopEntry::from_appid(fav.clone()).clone(),
|
||||||
.unwrap_or_else(|| fde::DesktopEntry::from_appid(fav.clone()).to_owned())
|
ToOwned::to_owned,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -610,7 +611,7 @@ impl CosmicAppList {
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(pinned_ctr, (e, original_id))| DockItem {
|
.map(|(pinned_ctr, (e, original_id))| DockItem {
|
||||||
id: pinned_ctr as u32,
|
id: pinned_ctr as u32,
|
||||||
toplevels: Default::default(),
|
toplevels: Vec::new(),
|
||||||
desktop_info: e.clone(),
|
desktop_info: e.clone(),
|
||||||
original_app_id: original_id.clone(),
|
original_app_id: original_id.clone(),
|
||||||
})
|
})
|
||||||
|
|
@ -681,12 +682,9 @@ impl cosmic::Application for CosmicAppList {
|
||||||
.chain(self.pinned_list.iter())
|
.chain(self.pinned_list.iter())
|
||||||
.find(|t| t.id == id)
|
.find(|t| t.id == id)
|
||||||
{
|
{
|
||||||
let rectangle = match self.rectangles.get(&toplevel_group.id.into()) {
|
let Some(rectangle) = self.rectangles.get(&toplevel_group.id.into()) else {
|
||||||
Some(r) => r,
|
tracing::error!("No rectangle found for toplevel group");
|
||||||
None => {
|
return Task::none();
|
||||||
tracing::error!("No rectangle found for toplevel group");
|
|
||||||
return Task::none();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
|
|
@ -751,9 +749,8 @@ impl cosmic::Application for CosmicAppList {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rectangle = match self.rectangles.get(&toplevel_group.id.into()) {
|
let Some(rectangle) = self.rectangles.get(&toplevel_group.id.into()) else {
|
||||||
Some(r) => r,
|
return Task::none();
|
||||||
None => return Task::none(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_id = window::Id::unique();
|
let new_id = window::Id::unique();
|
||||||
|
|
@ -1040,7 +1037,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
self.active_list.remove(pos)
|
self.active_list.remove(pos)
|
||||||
};
|
};
|
||||||
dock_item.toplevels = t.toplevels;
|
dock_item.toplevels = t.toplevels;
|
||||||
};
|
}
|
||||||
dock_item.id = self.item_ctr;
|
dock_item.id = self.item_ctr;
|
||||||
|
|
||||||
if dock_item.desktop_info.exec().is_some() {
|
if dock_item.desktop_info.exec().is_some() {
|
||||||
|
|
@ -1095,7 +1092,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
pending::<()>().await;
|
pending::<()>().await;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|_| Message::IncrementSubscriptionCtr,
|
|()| Message::IncrementSubscriptionCtr,
|
||||||
)
|
)
|
||||||
.map(cosmic::action::app);
|
.map(cosmic::action::app);
|
||||||
}
|
}
|
||||||
|
|
@ -1242,7 +1239,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
app_id.as_deref(),
|
app_id.as_deref(),
|
||||||
terminal,
|
terminal,
|
||||||
)
|
)
|
||||||
.await
|
.await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1307,13 +1304,13 @@ impl cosmic::Application for CosmicAppList {
|
||||||
{
|
{
|
||||||
let mut d = self.active_list.remove(p);
|
let mut d = self.active_list.remove(p);
|
||||||
// but use the id from the config
|
// but use the id from the config
|
||||||
d.original_app_id = original_id.clone();
|
d.original_app_id.clone_from(original_id);
|
||||||
d
|
d
|
||||||
} else {
|
} else {
|
||||||
self.item_ctr += 1;
|
self.item_ctr += 1;
|
||||||
DockItem {
|
DockItem {
|
||||||
id: self.item_ctr,
|
id: self.item_ctr,
|
||||||
toplevels: Default::default(),
|
toplevels: Vec::new(),
|
||||||
desktop_info: de.clone(),
|
desktop_info: de.clone(),
|
||||||
original_app_id: original_id.clone(),
|
original_app_id: original_id.clone(),
|
||||||
}
|
}
|
||||||
|
|
@ -1369,9 +1366,10 @@ impl cosmic::Application for CosmicAppList {
|
||||||
+ 2 * self.core.applet.suggested_padding(false);
|
+ 2 * self.core.applet.suggested_padding(false);
|
||||||
let (_favorite_popup_cutoff, active_popup_cutoff) =
|
let (_favorite_popup_cutoff, active_popup_cutoff) =
|
||||||
self.panel_overflow_lengths();
|
self.panel_overflow_lengths();
|
||||||
let popup_applet_count = self.active_list.len().saturating_sub(
|
let popup_applet_count =
|
||||||
(active_popup_cutoff.unwrap_or_default()).saturating_sub(1) as usize,
|
self.active_list.len().saturating_sub(
|
||||||
) as f32;
|
(active_popup_cutoff.unwrap_or_default()).saturating_sub(1),
|
||||||
|
) as f32;
|
||||||
let popup_applet_size = applet_suggested_size as f32 * popup_applet_count
|
let popup_applet_size = applet_suggested_size as f32 * popup_applet_count
|
||||||
+ 4.0 * (popup_applet_count - 1.);
|
+ 4.0 * (popup_applet_count - 1.);
|
||||||
let (max_width, max_height) = match self.core.applet.anchor {
|
let (max_width, max_height) = match self.core.applet.anchor {
|
||||||
|
|
@ -1425,9 +1423,10 @@ impl cosmic::Application for CosmicAppList {
|
||||||
+ 2 * self.core.applet.suggested_padding(false);
|
+ 2 * self.core.applet.suggested_padding(false);
|
||||||
let (favorite_popup_cutoff, _active_popup_cutoff) =
|
let (favorite_popup_cutoff, _active_popup_cutoff) =
|
||||||
self.panel_overflow_lengths();
|
self.panel_overflow_lengths();
|
||||||
let popup_applet_count = self.pinned_list.len().saturating_sub(
|
let popup_applet_count =
|
||||||
favorite_popup_cutoff.unwrap_or_default().saturating_sub(1) as usize,
|
self.pinned_list.len().saturating_sub(
|
||||||
) as f32;
|
favorite_popup_cutoff.unwrap_or_default().saturating_sub(1),
|
||||||
|
) as f32;
|
||||||
let popup_applet_size = applet_suggested_size as f32 * popup_applet_count
|
let popup_applet_size = applet_suggested_size as f32 * popup_applet_count
|
||||||
+ 4.0 * (popup_applet_count - 1.);
|
+ 4.0 * (popup_applet_count - 1.);
|
||||||
let (max_width, max_height) = match self.core.applet.anchor {
|
let (max_width, max_height) = match self.core.applet.anchor {
|
||||||
|
|
@ -1462,7 +1461,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
let focused_item = self.currently_active_toplevel();
|
let focused_item = self.currently_active_toplevel();
|
||||||
let theme = self.core.system_theme();
|
let theme = self.core.system_theme();
|
||||||
let dot_radius = theme.cosmic().radius_xs();
|
let dot_radius = theme.cosmic().radius_xs();
|
||||||
|
|
@ -1589,45 +1588,44 @@ impl cosmic::Application for CosmicAppList {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut active: Vec<_> = self.active_list[..active_popup_cutoff
|
let mut active: Vec<_> =
|
||||||
.map(|n| {
|
self.active_list[..active_popup_cutoff.map_or(self.active_list.len(), |n| {
|
||||||
if n < self.active_list.len() {
|
if n < self.active_list.len() {
|
||||||
n.saturating_sub(1)
|
n.saturating_sub(1)
|
||||||
} else {
|
} else {
|
||||||
n
|
n
|
||||||
}
|
}
|
||||||
})
|
})]
|
||||||
.unwrap_or(self.active_list.len())]
|
.iter()
|
||||||
.iter()
|
.map(|dock_item| {
|
||||||
.map(|dock_item| {
|
self.core
|
||||||
self.core
|
.applet
|
||||||
.applet
|
.applet_tooltip(
|
||||||
.applet_tooltip(
|
dock_item.as_icon(
|
||||||
dock_item.as_icon(
|
&self.core.applet,
|
||||||
&self.core.applet,
|
self.rectangle_tracker.as_ref(),
|
||||||
self.rectangle_tracker.as_ref(),
|
self.popup.is_none(),
|
||||||
self.popup.is_none(),
|
self.config.enable_drag_source,
|
||||||
self.config.enable_drag_source,
|
self.gpus.as_deref(),
|
||||||
self.gpus.as_deref(),
|
dock_item
|
||||||
|
.toplevels
|
||||||
|
.iter()
|
||||||
|
.any(|y| focused_item.contains(&y.0.foreign_toplevel)),
|
||||||
|
dot_radius,
|
||||||
|
self.core.main_window_id().unwrap(),
|
||||||
|
),
|
||||||
dock_item
|
dock_item
|
||||||
.toplevels
|
.desktop_info
|
||||||
.iter()
|
.full_name(&self.locales)
|
||||||
.any(|y| focused_item.contains(&y.0.foreign_toplevel)),
|
.unwrap_or_default()
|
||||||
dot_radius,
|
.to_string(),
|
||||||
self.core.main_window_id().unwrap(),
|
self.popup.is_some(),
|
||||||
),
|
Message::Surface,
|
||||||
dock_item
|
None,
|
||||||
.desktop_info
|
)
|
||||||
.full_name(&self.locales)
|
.into()
|
||||||
.unwrap_or_default()
|
})
|
||||||
.to_string(),
|
.collect();
|
||||||
self.popup.is_some(),
|
|
||||||
Message::Surface,
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
if active_popup_cutoff.is_some_and(|n| n < self.active_list.len()) {
|
if active_popup_cutoff.is_some_and(|n| n < self.active_list.len()) {
|
||||||
// button to show more active
|
// button to show more active
|
||||||
|
|
@ -1658,15 +1656,13 @@ impl cosmic::Application for CosmicAppList {
|
||||||
+ self.core.applet.suggested_padding(false) * 2;
|
+ self.core.applet.suggested_padding(false) * 2;
|
||||||
window_size
|
window_size
|
||||||
.map(|w| w.width)
|
.map(|w| w.width)
|
||||||
.map(|b| (b / suggested_width as f32) as u32)
|
.map_or(u32::MAX, |b| (b / suggested_width as f32) as u32) as usize
|
||||||
.unwrap_or(u32::MAX) as usize
|
|
||||||
} else {
|
} else {
|
||||||
let suggested_height = self.core.applet.suggested_size(false).1
|
let suggested_height = self.core.applet.suggested_size(false).1
|
||||||
+ self.core.applet.suggested_padding(false) * 2;
|
+ self.core.applet.suggested_padding(false) * 2;
|
||||||
window_size
|
window_size
|
||||||
.map(|w| w.height)
|
.map(|w| w.height)
|
||||||
.map(|b| (b / suggested_height as f32) as u32)
|
.map_or(u32::MAX, |b| (b / suggested_height as f32) as u32) as usize
|
||||||
.unwrap_or(u32::MAX) as usize
|
|
||||||
}
|
}
|
||||||
.max(4);
|
.max(4);
|
||||||
if max_num < favorites.len() + active.len() {
|
if max_num < favorites.len() + active.len() {
|
||||||
|
|
@ -1682,7 +1678,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
row(favorites).spacing(app_icon.icon_spacing),
|
row(favorites).spacing(app_icon.icon_spacing),
|
||||||
|_, _| Message::DndDropFinished,
|
|_, _| Message::DndDropFinished,
|
||||||
)
|
)
|
||||||
.drag_id(DND_FAVORITES.clone()),
|
.drag_id(DND_FAVORITES),
|
||||||
row(active).spacing(app_icon.icon_spacing).into(),
|
row(active).spacing(app_icon.icon_spacing).into(),
|
||||||
container(vertical_rule(1))
|
container(vertical_rule(1))
|
||||||
.height(Length::Fill)
|
.height(Length::Fill)
|
||||||
|
|
@ -1697,7 +1693,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
column(favorites).spacing(app_icon.icon_spacing),
|
column(favorites).spacing(app_icon.icon_spacing),
|
||||||
|_data: Option<DndPathBuf>, _| Message::DndDropFinished,
|
|_data: Option<DndPathBuf>, _| Message::DndDropFinished,
|
||||||
)
|
)
|
||||||
.drag_id(DND_FAVORITES.clone()),
|
.drag_id(DND_FAVORITES),
|
||||||
column(active).spacing(app_icon.icon_spacing).into(),
|
column(active).spacing(app_icon.icon_spacing).into(),
|
||||||
container(divider::horizontal::default())
|
container(divider::horizontal::default())
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
|
|
@ -1766,7 +1762,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, id: window::Id) -> Element<Message> {
|
fn view_window(&self, id: window::Id) -> Element<'_, Message> {
|
||||||
let theme = self.core.system_theme();
|
let theme = self.core.system_theme();
|
||||||
|
|
||||||
if let Some((_, item, _, _)) = self.dnd_source.as_ref().filter(|s| s.0 == id) {
|
if let Some((_, item, _, _)) = self.dnd_source.as_ref().filter(|s| s.0 == id) {
|
||||||
|
|
@ -1907,7 +1903,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
if toplevels.len() > 0 {
|
if !toplevels.is_empty() {
|
||||||
content = content.push(divider::horizontal::light());
|
content = content.push(divider::horizontal::light());
|
||||||
content = match toplevels.len() {
|
content = match toplevels.len() {
|
||||||
1 => content.push(
|
1 => content.push(
|
||||||
|
|
@ -2011,45 +2007,44 @@ impl cosmic::Application for CosmicAppList {
|
||||||
let focused_item = self.currently_active_toplevel();
|
let focused_item = self.currently_active_toplevel();
|
||||||
let dot_radius = theme.cosmic().radius_xs();
|
let dot_radius = theme.cosmic().radius_xs();
|
||||||
// show the overflow popup for active list
|
// show the overflow popup for active list
|
||||||
let active: Vec<_> = self.active_list[active_popup_cutoff
|
let active: Vec<_> =
|
||||||
.map(|n| {
|
self.active_list[..active_popup_cutoff.map_or(self.active_list.len(), |n| {
|
||||||
if n < self.active_list.len() {
|
if n < self.active_list.len() {
|
||||||
n.saturating_sub(1)
|
n.saturating_sub(1)
|
||||||
} else {
|
} else {
|
||||||
n - 1
|
n - 1
|
||||||
}
|
}
|
||||||
})
|
})]
|
||||||
.unwrap_or(self.active_list.len() - 1)..]
|
.iter()
|
||||||
.iter()
|
.map(|dock_item| {
|
||||||
.map(|dock_item| {
|
self.core
|
||||||
self.core
|
.applet
|
||||||
.applet
|
.applet_tooltip(
|
||||||
.applet_tooltip(
|
dock_item.as_icon(
|
||||||
dock_item.as_icon(
|
&self.core.applet,
|
||||||
&self.core.applet,
|
self.rectangle_tracker.as_ref(),
|
||||||
self.rectangle_tracker.as_ref(),
|
self.popup.is_none(),
|
||||||
self.popup.is_none(),
|
self.config.enable_drag_source,
|
||||||
self.config.enable_drag_source,
|
self.gpus.as_deref(),
|
||||||
self.gpus.as_deref(),
|
dock_item
|
||||||
|
.toplevels
|
||||||
|
.iter()
|
||||||
|
.any(|y| focused_item.contains(&y.0.foreign_toplevel)),
|
||||||
|
dot_radius,
|
||||||
|
self.core.main_window_id().unwrap(),
|
||||||
|
),
|
||||||
dock_item
|
dock_item
|
||||||
.toplevels
|
.desktop_info
|
||||||
.iter()
|
.full_name(&self.locales)
|
||||||
.any(|y| focused_item.contains(&y.0.foreign_toplevel)),
|
.unwrap_or_default()
|
||||||
dot_radius,
|
.to_string(),
|
||||||
id,
|
self.popup.is_some(),
|
||||||
),
|
Message::Surface,
|
||||||
dock_item
|
None,
|
||||||
.desktop_info
|
)
|
||||||
.full_name(&self.locales)
|
.into()
|
||||||
.unwrap_or_default()
|
})
|
||||||
.to_string(),
|
.collect();
|
||||||
self.popup.is_some(),
|
|
||||||
Message::Surface,
|
|
||||||
Some(id),
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let content = match &self.core.applet.anchor {
|
let content = match &self.core.applet.anchor {
|
||||||
PanelAnchor::Left | PanelAnchor::Right => container(
|
PanelAnchor::Left | PanelAnchor::Right => container(
|
||||||
Column::with_children(active)
|
Column::with_children(active)
|
||||||
|
|
@ -2117,7 +2112,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
favorites.extend(favorites_extra[..favorite_to_remove].into_iter().cloned());
|
favorites.extend(favorites_extra[..favorite_to_remove].iter().copied());
|
||||||
let favorites: Vec<_> = favorites
|
let favorites: Vec<_> = favorites
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
|
|
@ -2297,7 +2292,7 @@ impl CosmicAppList {
|
||||||
favorite_index = (btn_count as usize).min(self.pinned_list.len());
|
favorite_index = (btn_count as usize).min(self.pinned_list.len());
|
||||||
}
|
}
|
||||||
// tracing::error!("{} {} {:?}", btn_count, favorite_index, active_index);
|
// tracing::error!("{} {} {:?}", btn_count, favorite_index, active_index);
|
||||||
return (Some(favorite_index), active_index);
|
(Some(favorite_index), active_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn currently_active_toplevel(&self) -> Vec<ExtForeignToplevelHandleV1> {
|
fn currently_active_toplevel(&self) -> Vec<ExtForeignToplevelHandleV1> {
|
||||||
|
|
@ -2331,61 +2326,57 @@ impl CosmicAppList {
|
||||||
info: &ToplevelInfo,
|
info: &ToplevelInfo,
|
||||||
unicase_appid: Ascii<&str>,
|
unicase_appid: Ascii<&str>,
|
||||||
) -> DesktopEntry {
|
) -> DesktopEntry {
|
||||||
match fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
if let Some(appid) = fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
||||||
Some(appid) => appid.clone(),
|
appid.clone()
|
||||||
None => {
|
} else {
|
||||||
// Update desktop entries in case it was not found.
|
// Update desktop entries in case it was not found.
|
||||||
|
|
||||||
self.update_desktop_entries();
|
self.update_desktop_entries();
|
||||||
match fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
if let Some(appid) = fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
||||||
Some(appid) => appid.clone(),
|
appid.clone()
|
||||||
None => {
|
} else {
|
||||||
tracing::error!(id = info.app_id, "could not find desktop entry for app");
|
tracing::error!(id = info.app_id, "could not find desktop entry for app");
|
||||||
|
|
||||||
let mut fallback_entry = fde::DesktopEntry::from_appid(info.app_id.clone());
|
let mut fallback_entry = fde::DesktopEntry::from_appid(info.app_id.clone());
|
||||||
|
|
||||||
// proton opens games as steam_app_X, where X is either
|
// proton opens games as steam_app_X, where X is either
|
||||||
// the steam appid or "default". games with a steam appid
|
// the steam appid or "default". games with a steam appid
|
||||||
// can have a desktop entry generated elsewhere; this
|
// can have a desktop entry generated elsewhere; this
|
||||||
// specifically handles non-steam games opened
|
// specifically handles non-steam games opened
|
||||||
// under proton
|
// under proton
|
||||||
// in addition, try to match WINE entries who have its
|
// in addition, try to match WINE entries who have its
|
||||||
// appid = the full name of the executable (incl. .exe)
|
// appid = the full name of the executable (incl. .exe)
|
||||||
let is_proton_game = info.app_id == "steam_app_default";
|
let is_proton_game = info.app_id == "steam_app_default";
|
||||||
if is_proton_game || info.app_id.ends_with(".exe") {
|
if is_proton_game || info.app_id.ends_with(".exe") {
|
||||||
for entry in &self.desktop_entries {
|
for entry in &self.desktop_entries {
|
||||||
let localised_name = entry
|
let localised_name = entry
|
||||||
.name(&self.locales)
|
.name(&self.locales)
|
||||||
.map(|x| x.to_string())
|
.map(|x| x.to_string())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
if localised_name == info.title {
|
if localised_name == info.title {
|
||||||
// if this is a proton game, we only want
|
// if this is a proton game, we only want
|
||||||
// to look for game entries
|
// to look for game entries
|
||||||
if is_proton_game
|
if is_proton_game
|
||||||
&& !entry.categories().unwrap_or_default().contains(&"Game")
|
&& !entry.categories().unwrap_or_default().contains(&"Game")
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
fallback_entry = entry.clone();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fallback_entry
|
fallback_entry = entry.clone();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fallback_entry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn launch_on_preferred_gpu(desktop_info: &DesktopEntry, gpus: Option<&[Gpu]>) -> Option<Message> {
|
fn launch_on_preferred_gpu(desktop_info: &DesktopEntry, gpus: Option<&[Gpu]>) -> Option<Message> {
|
||||||
let Some(exec) = desktop_info.exec() else {
|
let exec = desktop_info.exec()?;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let gpu_idx = gpus.map(|gpus| {
|
let gpu_idx = gpus.map(|gpus| {
|
||||||
if desktop_info.prefers_non_default_gpu() {
|
if desktop_info.prefers_non_default_gpu() {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ impl ActivationHandler for AppData {
|
||||||
fn new_token(&mut self, token: String, data: &ExecRequestData) {
|
fn new_token(&mut self, token: String, data: &ExecRequestData) {
|
||||||
let _ = self.tx.unbounded_send(WaylandUpdate::ActivationToken {
|
let _ = self.tx.unbounded_send(WaylandUpdate::ActivationToken {
|
||||||
token: Some(token),
|
token: Some(token),
|
||||||
app_id: data.app_id().map(|x| x.to_owned()),
|
app_id: data.app_id().map(String::from),
|
||||||
exec: data.exec.clone(),
|
exec: data.exec.clone(),
|
||||||
gpu_idx: data.gpu_idx,
|
gpu_idx: data.gpu_idx,
|
||||||
terminal: data.terminal,
|
terminal: data.terminal,
|
||||||
|
|
@ -313,7 +313,10 @@ impl Session {
|
||||||
self.condvar.notify_all();
|
self.condvar.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_while<F: FnMut(&SessionInner) -> bool>(&self, mut f: F) -> MutexGuard<SessionInner> {
|
fn wait_while<F: FnMut(&SessionInner) -> bool>(
|
||||||
|
&self,
|
||||||
|
mut f: F,
|
||||||
|
) -> MutexGuard<'_, SessionInner> {
|
||||||
self.condvar
|
self.condvar
|
||||||
.wait_while(self.inner.lock().unwrap(), |data| f(data))
|
.wait_while(self.inner.lock().unwrap(), |data| f(data))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -337,7 +340,7 @@ impl Dispatch<wl_shm_pool::WlShmPool, ()> for AppData {
|
||||||
_app_data: &mut Self,
|
_app_data: &mut Self,
|
||||||
_buffer: &wl_shm_pool::WlShmPool,
|
_buffer: &wl_shm_pool::WlShmPool,
|
||||||
_event: wl_shm_pool::Event,
|
_event: wl_shm_pool::Event,
|
||||||
_: &(),
|
(): &(),
|
||||||
_: &Connection,
|
_: &Connection,
|
||||||
_qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -349,7 +352,7 @@ impl Dispatch<wl_buffer::WlBuffer, ()> for AppData {
|
||||||
_app_data: &mut Self,
|
_app_data: &mut Self,
|
||||||
_buffer: &wl_buffer::WlBuffer,
|
_buffer: &wl_buffer::WlBuffer,
|
||||||
_event: wl_buffer::Event,
|
_event: wl_buffer::Event,
|
||||||
_: &(),
|
(): &(),
|
||||||
_: &Connection,
|
_: &Connection,
|
||||||
_qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -387,7 +390,7 @@ impl CaptureData {
|
||||||
&self.qh,
|
&self.qh,
|
||||||
SessionData {
|
SessionData {
|
||||||
session: session.clone(),
|
session: session.clone(),
|
||||||
session_data: Default::default(),
|
session_data: ScreencopySessionData::default(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -405,22 +408,19 @@ impl CaptureData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX
|
// XXX
|
||||||
if !formats
|
if !formats.shm_formats.contains(&wl_shm::Format::Abgr8888) {
|
||||||
.shm_formats
|
|
||||||
.contains(&wl_shm::Format::Abgr8888.into())
|
|
||||||
{
|
|
||||||
tracing::error!("No suitable buffer format found");
|
tracing::error!("No suitable buffer format found");
|
||||||
tracing::warn!("Available formats: {:#?}", formats);
|
tracing::warn!("Available formats: {:#?}", formats);
|
||||||
return None;
|
return None;
|
||||||
};
|
}
|
||||||
|
|
||||||
let buf_len = width * height * 4;
|
let buf_len = width * height * 4;
|
||||||
if let Some(len) = len {
|
if let Some(len) = len {
|
||||||
if len != buf_len {
|
if len != buf_len {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
} else if let Err(_err) = rustix::fs::ftruncate(&fd, buf_len as _) {
|
} else if let Err(_err) = rustix::fs::ftruncate(&fd, buf_len.into()) {
|
||||||
};
|
}
|
||||||
let pool = self
|
let pool = self
|
||||||
.wl_shm
|
.wl_shm
|
||||||
.create_pool(fd.as_fd(), buf_len as i32, &self.qh, ());
|
.create_pool(fd.as_fd(), buf_len as i32, &self.qh, ());
|
||||||
|
|
@ -439,7 +439,7 @@ impl CaptureData {
|
||||||
&[],
|
&[],
|
||||||
&self.qh,
|
&self.qh,
|
||||||
FrameData {
|
FrameData {
|
||||||
frame_data: Default::default(),
|
frame_data: ScreencopyFrameData::default(),
|
||||||
session: capture_session.clone(),
|
session: capture_session.clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -484,7 +484,7 @@ impl AppData {
|
||||||
handle: &ExtForeignToplevelHandleV1,
|
handle: &ExtForeignToplevelHandleV1,
|
||||||
) -> Option<ZcosmicToplevelHandleV1> {
|
) -> Option<ZcosmicToplevelHandleV1> {
|
||||||
self.toplevel_info_state
|
self.toplevel_info_state
|
||||||
.info(&handle)?
|
.info(handle)?
|
||||||
.cosmic_toplevel
|
.cosmic_toplevel
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
@ -498,8 +498,7 @@ impl AppData {
|
||||||
capturer: self.screencopy_state.capturer().clone(),
|
capturer: self.screencopy_state.capturer().clone(),
|
||||||
};
|
};
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
use std::ffi::CStr;
|
let name = c"app-list-screencopy";
|
||||||
let name = unsafe { CStr::from_bytes_with_nul_unchecked(b"app-list-screencopy\0") };
|
|
||||||
let Ok(fd) = rustix::fs::memfd_create(name, rustix::fs::MemfdFlags::CLOEXEC) else {
|
let Ok(fd) = rustix::fs::memfd_create(name, rustix::fs::MemfdFlags::CLOEXEC) else {
|
||||||
tracing::error!("Failed to get fd for capture");
|
tracing::error!("Failed to get fd for capture");
|
||||||
return;
|
return;
|
||||||
|
|
@ -535,7 +534,7 @@ impl AppData {
|
||||||
tx.unbounded_send(WaylandUpdate::Image(handle, WaylandImage::new(img)))
|
tx.unbounded_send(WaylandUpdate::Image(handle, WaylandImage::new(img)))
|
||||||
{
|
{
|
||||||
tracing::error!("Failed to send image event to subscription {err:?}");
|
tracing::error!("Failed to send image event to subscription {err:?}");
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("Failed to capture image");
|
tracing::error!("Failed to capture image");
|
||||||
}
|
}
|
||||||
|
|
@ -624,7 +623,7 @@ pub(crate) fn wayland_handler(
|
||||||
.expect("Failed to insert wayland source.");
|
.expect("Failed to insert wayland source.");
|
||||||
|
|
||||||
if handle
|
if handle
|
||||||
.insert_source(rx, |event, _, state| match event {
|
.insert_source(rx, |event, (), state| match event {
|
||||||
calloop::channel::Event::Msg(req) => match req {
|
calloop::channel::Event::Msg(req) => match req {
|
||||||
WaylandRequest::Screencopy(handle) => {
|
WaylandRequest::Screencopy(handle) => {
|
||||||
state.send_image(handle.clone());
|
state.send_image(handle.clone());
|
||||||
|
|
|
||||||
|
|
@ -91,16 +91,13 @@ async fn start_listening(
|
||||||
}
|
}
|
||||||
guard.as_mut().unwrap()
|
guard.as_mut().unwrap()
|
||||||
};
|
};
|
||||||
match rx.next().await {
|
if let Some(u) = rx.next().await {
|
||||||
Some(u) => {
|
_ = output.send(u).await;
|
||||||
_ = output.send(u).await;
|
State::Waiting
|
||||||
State::Waiting
|
} else {
|
||||||
}
|
_ = output.send(WaylandUpdate::Finished).await;
|
||||||
None => {
|
tracing::error!("Wayland handler thread died");
|
||||||
_ = output.send(WaylandUpdate::Finished).await;
|
State::Finished
|
||||||
tracing::error!("Wayland handler thread died");
|
|
||||||
State::Finished
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::Finished => iced::futures::future::pending().await,
|
State::Finished => iced::futures::future::pending().await,
|
||||||
|
|
|
||||||
|
|
@ -235,7 +235,7 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("Wayland tx is None");
|
tracing::error!("Wayland tx is None");
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
Message::Token(u) => match u {
|
Message::Token(u) => match u {
|
||||||
TokenUpdate::Init(tx) => {
|
TokenUpdate::Init(tx) => {
|
||||||
|
|
@ -303,7 +303,7 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
self.core
|
self.core
|
||||||
.applet
|
.applet
|
||||||
.icon_button("preferences-desktop-accessibility-symbolic")
|
.icon_button("preferences-desktop-accessibility-symbolic")
|
||||||
|
|
@ -311,7 +311,7 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: window::Id) -> Element<Message> {
|
fn view_window(&self, _id: window::Id) -> Element<'_, Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,6 @@ pub struct WaylandWatcher {
|
||||||
impl WaylandWatcher {
|
impl WaylandWatcher {
|
||||||
pub fn new() -> anyhow::Result<Self> {
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
let (tx, rx) = thread::spawn_wayland_connection(1)?;
|
let (tx, rx) = thread::spawn_wayland_connection(1)?;
|
||||||
Ok(Self { tx, rx })
|
Ok(Self { rx, tx })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -166,14 +166,13 @@ pub enum Message {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Audio {
|
impl Audio {
|
||||||
fn playback_buttons(&self) -> Option<Element<Message>> {
|
fn playback_buttons(&self) -> Option<Element<'_, Message>> {
|
||||||
if self.player_status.is_some() && self.config.show_media_controls_in_top_panel {
|
if self.player_status.is_some() && self.config.show_media_controls_in_top_panel {
|
||||||
let mut elements = Vec::with_capacity(3);
|
let mut elements = Vec::with_capacity(3);
|
||||||
if self
|
if self
|
||||||
.player_status
|
.player_status
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| s.can_go_previous)
|
.is_some_and(|s| s.can_go_previous)
|
||||||
.unwrap_or_default()
|
|
||||||
{
|
{
|
||||||
elements.push(
|
elements.push(
|
||||||
self.core
|
self.core
|
||||||
|
|
@ -181,7 +180,7 @@ impl Audio {
|
||||||
.icon_button(GO_BACK)
|
.icon_button(GO_BACK)
|
||||||
.on_press(Message::MprisRequest(MprisRequest::Previous))
|
.on_press(Message::MprisRequest(MprisRequest::Previous))
|
||||||
.into(),
|
.into(),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
if let Some(play) = self.is_play() {
|
if let Some(play) = self.is_play() {
|
||||||
elements.push(
|
elements.push(
|
||||||
|
|
@ -196,12 +195,7 @@ impl Audio {
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if self
|
if self.player_status.as_ref().is_some_and(|s| s.can_go_next) {
|
||||||
.player_status
|
|
||||||
.as_ref()
|
|
||||||
.map(|s| s.can_go_next)
|
|
||||||
.unwrap_or_default()
|
|
||||||
{
|
|
||||||
elements.push(
|
elements.push(
|
||||||
self.core
|
self.core
|
||||||
.applet
|
.applet
|
||||||
|
|
@ -224,7 +218,7 @@ impl Audio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn go_previous(&self, icon_size: u16) -> Option<Element<Message>> {
|
fn go_previous(&self, icon_size: u16) -> Option<Element<'_, Message>> {
|
||||||
self.player_status.as_ref().and_then(|s| {
|
self.player_status.as_ref().and_then(|s| {
|
||||||
if s.can_go_previous {
|
if s.can_go_previous {
|
||||||
Some(
|
Some(
|
||||||
|
|
@ -240,7 +234,7 @@ impl Audio {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn go_next(&self, icon_size: u16) -> Option<Element<Message>> {
|
fn go_next(&self, icon_size: u16) -> Option<Element<'_, Message>> {
|
||||||
self.player_status.as_ref().and_then(|s| {
|
self.player_status.as_ref().and_then(|s| {
|
||||||
if s.can_go_next {
|
if s.can_go_next {
|
||||||
Some(
|
Some(
|
||||||
|
|
@ -277,17 +271,11 @@ impl Audio {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_output_mute(&self) -> bool {
|
fn current_output_mute(&self) -> bool {
|
||||||
self.current_output
|
self.current_output.as_ref().is_some_and(|o| o.mute)
|
||||||
.as_ref()
|
|
||||||
.map(|o| o.mute)
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_input_mute(&self) -> bool {
|
fn current_input_mute(&self) -> bool {
|
||||||
self.current_input
|
self.current_input.as_ref().is_some_and(|o| o.mute)
|
||||||
.as_ref()
|
|
||||||
.map(|o| o.mute)
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -421,7 +409,7 @@ impl cosmic::Application for Audio {
|
||||||
connection.send(pulse::Message::SetSourceVolumeByName(
|
connection.send(pulse::Message::SetSourceVolumeByName(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
device.volume,
|
device.volume,
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -434,7 +422,7 @@ impl cosmic::Application for Audio {
|
||||||
if let Some(device) = &self.current_output {
|
if let Some(device) = &self.current_output {
|
||||||
if let Some(name) = &device.name {
|
if let Some(name) = &device.name {
|
||||||
connection
|
connection
|
||||||
.send(pulse::Message::SetSinkMuteByName(name.clone(), device.mute))
|
.send(pulse::Message::SetSinkMuteByName(name.clone(), device.mute));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -625,7 +613,7 @@ impl cosmic::Application for Audio {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("Wayland tx is None");
|
tracing::error!("Wayland tx is None");
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
Message::Token(u) => match u {
|
Message::Token(u) => match u {
|
||||||
TokenUpdate::Init(tx) => {
|
TokenUpdate::Init(tx) => {
|
||||||
|
|
@ -688,7 +676,7 @@ impl cosmic::Application for Audio {
|
||||||
cosmic::app::Action::Surface(a),
|
cosmic::app::Action::Surface(a),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
@ -711,7 +699,7 @@ impl cosmic::Application for Audio {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
let btn = self
|
let btn = self
|
||||||
.core
|
.core
|
||||||
.applet
|
.applet
|
||||||
|
|
@ -765,7 +753,7 @@ impl cosmic::Application for Audio {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: window::Id) -> Element<Message> {
|
fn view_window(&self, _id: window::Id) -> Element<'_, Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ struct State {
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
drag_initiated: Default::default(),
|
drag_initiated: Option::default(),
|
||||||
is_out_of_bounds: true,
|
is_out_of_bounds: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -129,8 +129,8 @@ impl<'a, Message, Theme, Renderer> MouseArea<'a, Message, Theme, Renderer> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
||||||
for MouseArea<'a, Message, Theme, Renderer>
|
for MouseArea<'_, Message, Theme, Renderer>
|
||||||
where
|
where
|
||||||
Renderer: renderer::Renderer,
|
Renderer: renderer::Renderer,
|
||||||
Message: Clone,
|
Message: Clone,
|
||||||
|
|
@ -267,7 +267,7 @@ where
|
||||||
renderer: &Renderer,
|
renderer: &Renderer,
|
||||||
dnd_rectangles: &mut cosmic::iced_core::clipboard::DndDestinationRectangles,
|
dnd_rectangles: &mut cosmic::iced_core::clipboard::DndDestinationRectangles,
|
||||||
) {
|
) {
|
||||||
if let Some(state) = state.children.iter().next() {
|
if let Some(state) = state.children.first() {
|
||||||
self.content
|
self.content
|
||||||
.as_widget()
|
.as_widget()
|
||||||
.drag_destinations(state, layout, renderer, dnd_rectangles);
|
.drag_destinations(state, layout, renderer, dnd_rectangles);
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ pub struct PlayerStatus {
|
||||||
impl PlayerStatus {
|
impl PlayerStatus {
|
||||||
async fn new(player: Player) -> Option<Self> {
|
async fn new(player: Player) -> Option<Self> {
|
||||||
let metadata = player.metadata().await.ok()?;
|
let metadata = player.metadata().await.ok()?;
|
||||||
let pathname = metadata.url().unwrap_or("".into());
|
let pathname = metadata.url().unwrap_or_default();
|
||||||
let pathbuf = PathBuf::from(pathname);
|
let pathbuf = PathBuf::from(pathname);
|
||||||
|
|
||||||
let title = metadata
|
let title = metadata
|
||||||
|
|
@ -108,7 +108,7 @@ impl MprisPlayer {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name(&self) -> &BusName {
|
fn name(&self) -> &BusName<'_> {
|
||||||
self.player.inner().destination()
|
self.player.inner().destination()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -171,7 +171,7 @@ impl State {
|
||||||
filter_firefox_players(&mut players);
|
filter_firefox_players(&mut players);
|
||||||
|
|
||||||
// pre-sort by path so that the same player is always selected
|
// pre-sort by path so that the same player is always selected
|
||||||
players.sort_by(|a, b| a.name().cmp(&b.name()));
|
players.sort_by(|a, b| a.name().cmp(b.name()));
|
||||||
|
|
||||||
let mut state = Self {
|
let mut state = Self {
|
||||||
conn,
|
conn,
|
||||||
|
|
@ -196,7 +196,7 @@ impl State {
|
||||||
};
|
};
|
||||||
self.players.push(player);
|
self.players.push(player);
|
||||||
filter_firefox_players(&mut self.players);
|
filter_firefox_players(&mut self.players);
|
||||||
self.players.sort_by(|a, b| a.name().cmp(&b.name()));
|
self.players.sort_by(|a, b| a.name().cmp(b.name()));
|
||||||
self.update_any_player_state_stream().await;
|
self.update_any_player_state_stream().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -254,7 +254,7 @@ async fn run(output: &mut futures::channel::mpsc::Sender<MprisUpdate>) {
|
||||||
_ = output.send(MprisUpdate::Player(player_status)).await;
|
_ = output.send(MprisUpdate::Player(player_status)).await;
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("Failed to get player status.");
|
tracing::error!("Failed to get player status.");
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
let _ = output.send(MprisUpdate::Setup).await;
|
let _ = output.send(MprisUpdate::Setup).await;
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +287,7 @@ async fn run(output: &mut futures::channel::mpsc::Sender<MprisUpdate>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn find_active<'a>(players: &'a Vec<MprisPlayer>) -> Option<&'a MprisPlayer> {
|
async fn find_active<'a>(players: &'a [MprisPlayer]) -> Option<&'a MprisPlayer> {
|
||||||
let mut best = (0, None::<&'a MprisPlayer>);
|
let mut best = (0, None::<&'a MprisPlayer>);
|
||||||
let eval = |p: Player| async move {
|
let eval = |p: Player| async move {
|
||||||
let v = {
|
let v = {
|
||||||
|
|
@ -303,7 +303,7 @@ async fn find_active<'a>(players: &'a Vec<MprisPlayer>) -> Option<&'a MprisPlaye
|
||||||
v + p.metadata().await.is_ok() as i32
|
v + p.metadata().await.is_ok() as i32
|
||||||
};
|
};
|
||||||
|
|
||||||
for p in players.iter() {
|
for p in players {
|
||||||
let v = eval(p.player.clone()).await;
|
let v = eval(p.player.clone()).await;
|
||||||
if v > best.0 {
|
if v > best.0 {
|
||||||
best = (v, Some(p));
|
best = (v, Some(p));
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ impl Connection {
|
||||||
panic!();
|
panic!();
|
||||||
}
|
}
|
||||||
mpsc::error::TrySendError::Full(_) => {
|
mpsc::error::TrySendError::Full(_) => {
|
||||||
tracing::warn!("Failed to send message to PulseAudio server: channel is full")
|
tracing::warn!("Failed to send message to PulseAudio server: channel is full");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -249,9 +249,8 @@ impl PulseHandle {
|
||||||
for msg in msgs.drain(..) {
|
for msg in msgs.drain(..) {
|
||||||
match msg {
|
match msg {
|
||||||
Message::GetDefaultSink => {
|
Message::GetDefaultSink => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
match server.get_default_sink() {
|
match server.get_default_sink() {
|
||||||
Ok(sink) => {
|
Ok(sink) => {
|
||||||
|
|
@ -266,9 +265,8 @@ impl PulseHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::GetDefaultSource => {
|
Message::GetDefaultSource => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
match server.get_default_source() {
|
match server.get_default_source() {
|
||||||
Ok(source) => {
|
Ok(source) => {
|
||||||
|
|
@ -286,9 +284,8 @@ impl PulseHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::GetSinks => {
|
Message::GetSinks => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
match server.get_sinks() {
|
match server.get_sinks() {
|
||||||
Ok(sinks) => {
|
Ok(sinks) => {
|
||||||
|
|
@ -302,9 +299,8 @@ impl PulseHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::GetSources => {
|
Message::GetSources => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
match server.get_sources() {
|
match server.get_sources() {
|
||||||
Ok(sinks) => {
|
Ok(sinks) => {
|
||||||
|
|
@ -318,23 +314,20 @@ impl PulseHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SetSinkVolumeByName(name, channel_volumes) => {
|
Message::SetSinkVolumeByName(name, channel_volumes) => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
server.set_sink_volume_by_name(&name, &channel_volumes)
|
server.set_sink_volume_by_name(&name, &channel_volumes);
|
||||||
}
|
}
|
||||||
Message::SetSourceVolumeByName(name, channel_volumes) => {
|
Message::SetSourceVolumeByName(name, channel_volumes) => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
server.set_source_volume_by_name(&name, &channel_volumes)
|
server.set_source_volume_by_name(&name, &channel_volumes);
|
||||||
}
|
}
|
||||||
Message::SetSinkMuteByName(name, mute) => {
|
Message::SetSinkMuteByName(name, mute) => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let op =
|
let op =
|
||||||
|
|
@ -342,9 +335,8 @@ impl PulseHandle {
|
||||||
server.wait_for_result(op).ok();
|
server.wait_for_result(op).ok();
|
||||||
}
|
}
|
||||||
Message::SetSourceMuteByName(name, mute) => {
|
Message::SetSourceMuteByName(name, mute) => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let op = server
|
let op = server
|
||||||
|
|
@ -367,7 +359,7 @@ impl PulseHandle {
|
||||||
Self::send_connected(&from_pulse_send).await;
|
Self::send_connected(&from_pulse_send).await;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match PulseServer::connect().and_then(|server| server.init()) {
|
match PulseServer::connect().and_then(PulseServer::init) {
|
||||||
Ok(new_server) => {
|
Ok(new_server) => {
|
||||||
tracing::info!("Connected to server");
|
tracing::info!("Connected to server");
|
||||||
Self::send_connected(&from_pulse_send).await;
|
Self::send_connected(&from_pulse_send).await;
|
||||||
|
|
@ -384,13 +376,11 @@ impl PulseHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SetDefaultSink(device) => {
|
Message::SetDefaultSink(device) => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
let default_sink = match server.get_default_sink() {
|
let Ok(default_sink) = server.get_default_sink() else {
|
||||||
Ok(sink) => sink,
|
continue;
|
||||||
Err(_) => continue,
|
|
||||||
};
|
};
|
||||||
let to_move = server.get_sink_inputs(default_sink.index);
|
let to_move = server.get_sink_inputs(default_sink.index);
|
||||||
if let Some(name) = device.name.as_ref() {
|
if let Some(name) = device.name.as_ref() {
|
||||||
|
|
@ -405,13 +395,11 @@ impl PulseHandle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::SetDefaultSource(device) => {
|
Message::SetDefaultSource(device) => {
|
||||||
let server = match server.as_mut() {
|
let Some(server) = server.as_mut() else {
|
||||||
Some(s) => s,
|
continue;
|
||||||
None => continue,
|
|
||||||
};
|
};
|
||||||
let default_source = match server.get_default_source() {
|
let Ok(default_source) = server.get_default_source() else {
|
||||||
Ok(source) => source,
|
continue;
|
||||||
Err(_) => continue,
|
|
||||||
};
|
};
|
||||||
let to_move = server.get_source_outputs(default_source.index);
|
let to_move = server.get_source_outputs(default_source.index);
|
||||||
if let Some(name) = device.name.as_ref() {
|
if let Some(name) = device.name.as_ref() {
|
||||||
|
|
@ -421,12 +409,12 @@ impl PulseHandle {
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
tracing::error!("ERROR! {:?}", err);
|
tracing::error!("ERROR! {:?}", err);
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
tracing::warn!("message doesn't match")
|
tracing::warn!("message doesn't match");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -440,12 +428,12 @@ impl PulseHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_disconnected(sender: &tokio::sync::mpsc::Sender<Message>) {
|
async fn send_disconnected(sender: &tokio::sync::mpsc::Sender<Message>) {
|
||||||
sender.send(Message::Disconnected).await.unwrap()
|
sender.send(Message::Disconnected).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
async fn send_connected(sender: &tokio::sync::mpsc::Sender<Message>) {
|
async fn send_connected(sender: &tokio::sync::mpsc::Sender<Message>) {
|
||||||
sender.send(Message::Connected).await.unwrap()
|
sender.send(Message::Connected).await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -532,7 +520,7 @@ impl PulseServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of output devices
|
// Get a list of output devices
|
||||||
pub fn get_sinks(&self) -> Result<Vec<DeviceInfo>, PulseServerError> {
|
pub fn get_sinks(&self) -> Result<Vec<DeviceInfo>, PulseServerError<'_>> {
|
||||||
let list: Rc<RefCell<Option<Vec<DeviceInfo>>>> = Rc::new(RefCell::new(Some(Vec::new())));
|
let list: Rc<RefCell<Option<Vec<DeviceInfo>>>> = Rc::new(RefCell::new(Some(Vec::new())));
|
||||||
let list_ref = list.clone();
|
let list_ref = list.clone();
|
||||||
|
|
||||||
|
|
@ -543,7 +531,7 @@ impl PulseServer {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.wait_for_result(operation).and_then(|_| {
|
self.wait_for_result(operation).and_then(|()| {
|
||||||
list.borrow_mut().take().ok_or(PulseServerError::Misc(
|
list.borrow_mut().take().ok_or(PulseServerError::Misc(
|
||||||
"get_sinks(): failed to wait for operation",
|
"get_sinks(): failed to wait for operation",
|
||||||
))
|
))
|
||||||
|
|
@ -551,7 +539,7 @@ impl PulseServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a list of input devices
|
// Get a list of input devices
|
||||||
pub fn get_sources(&self) -> Result<Vec<DeviceInfo>, PulseServerError> {
|
pub fn get_sources(&self) -> Result<Vec<DeviceInfo>, PulseServerError<'_>> {
|
||||||
let list: Rc<RefCell<Option<Vec<DeviceInfo>>>> = Rc::new(RefCell::new(Some(Vec::new())));
|
let list: Rc<RefCell<Option<Vec<DeviceInfo>>>> = Rc::new(RefCell::new(Some(Vec::new())));
|
||||||
let list_ref = list.clone();
|
let list_ref = list.clone();
|
||||||
|
|
||||||
|
|
@ -562,14 +550,14 @@ impl PulseServer {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
self.wait_for_result(operation).and_then(|_| {
|
self.wait_for_result(operation).and_then(|()| {
|
||||||
list.borrow_mut().take().ok_or(PulseServerError::Misc(
|
list.borrow_mut().take().ok_or(PulseServerError::Misc(
|
||||||
"get_sources(): Failed to wait for operation",
|
"get_sources(): Failed to wait for operation",
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_server_info(&mut self) -> Result<ServerInfo, PulseServerError> {
|
pub fn get_server_info(&mut self) -> Result<ServerInfo, PulseServerError<'_>> {
|
||||||
let info = Rc::new(RefCell::new(Some(None)));
|
let info = Rc::new(RefCell::new(Some(None)));
|
||||||
let info_ref = info.clone();
|
let info_ref = info.clone();
|
||||||
|
|
||||||
|
|
@ -643,7 +631,7 @@ impl PulseServer {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_default_sink(&mut self) -> Result<DeviceInfo, PulseServerError> {
|
fn get_default_sink(&mut self) -> Result<DeviceInfo, PulseServerError<'_>> {
|
||||||
let server_info = self.get_server_info();
|
let server_info = self.get_server_info();
|
||||||
match server_info {
|
match server_info {
|
||||||
Ok(info) => {
|
Ok(info) => {
|
||||||
|
|
@ -668,7 +656,7 @@ impl PulseServer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_default_source(&mut self) -> Result<DeviceInfo, PulseServerError> {
|
fn get_default_source(&mut self) -> Result<DeviceInfo, PulseServerError<'_>> {
|
||||||
let server_info = self.get_server_info();
|
let server_info = self.get_server_info();
|
||||||
match server_info {
|
match server_info {
|
||||||
Ok(info) => {
|
Ok(info) => {
|
||||||
|
|
@ -750,7 +738,7 @@ impl PulseServer {
|
||||||
fn wait_for_result<G: ?Sized>(
|
fn wait_for_result<G: ?Sized>(
|
||||||
&self,
|
&self,
|
||||||
operation: pulse::operation::Operation<G>,
|
operation: pulse::operation::Operation<G>,
|
||||||
) -> Result<(), PulseServerError> {
|
) -> Result<(), PulseServerError<'_>> {
|
||||||
// TODO: make this loop async. It is already in an async context, so
|
// TODO: make this loop async. It is already in an async context, so
|
||||||
// we could make this thread sleep while waiting for the pulse server's
|
// we could make this thread sleep while waiting for the pulse server's
|
||||||
// response.
|
// response.
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
}
|
}
|
||||||
return cosmic::iced::Task::perform(
|
return cosmic::iced::Task::perform(
|
||||||
tokio::time::sleep(Duration::from_millis(200)),
|
tokio::time::sleep(Duration::from_millis(200)),
|
||||||
|_| cosmic::Action::App(Message::SetKbdBrightnessDebounced),
|
|()| cosmic::Action::App(Message::SetKbdBrightnessDebounced),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Message::SetScreenBrightnessDebounced => {
|
Message::SetScreenBrightnessDebounced => {
|
||||||
|
|
@ -276,7 +276,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
}
|
}
|
||||||
return cosmic::iced::Task::perform(
|
return cosmic::iced::Task::perform(
|
||||||
tokio::time::sleep(Duration::from_millis(200)),
|
tokio::time::sleep(Duration::from_millis(200)),
|
||||||
|_| cosmic::Action::App(Message::SetScreenBrightnessDebounced),
|
|()| cosmic::Action::App(Message::SetScreenBrightnessDebounced),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Message::ReleaseKbdBrightness => {
|
Message::ReleaseKbdBrightness => {
|
||||||
|
|
@ -410,7 +410,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("Wayland tx is None");
|
tracing::error!("Wayland tx is None");
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
Message::Token(u) => match u {
|
Message::Token(u) => match u {
|
||||||
TokenUpdate::Init(tx) => {
|
TokenUpdate::Init(tx) => {
|
||||||
|
|
@ -433,17 +433,13 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
self.update_trigger = Some(tx);
|
self.update_trigger = Some(tx);
|
||||||
}
|
}
|
||||||
Message::GpuOn(path, name, app_list) => {
|
Message::GpuOn(path, name, app_list) => {
|
||||||
let toggled = self
|
let toggled = self.gpus.get(&path).is_some_and(|data| data.toggled);
|
||||||
.gpus
|
|
||||||
.get(&path)
|
|
||||||
.map(|data| data.toggled)
|
|
||||||
.unwrap_or_default();
|
|
||||||
self.gpus.insert(
|
self.gpus.insert(
|
||||||
path,
|
path,
|
||||||
GPUData {
|
GPUData {
|
||||||
name,
|
name,
|
||||||
app_list,
|
|
||||||
toggled,
|
toggled,
|
||||||
|
app_list,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -483,7 +479,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
let btn = self
|
let btn = self
|
||||||
.core
|
.core
|
||||||
.applet
|
.applet
|
||||||
|
|
@ -491,7 +487,9 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
.on_press_down(Message::TogglePopup)
|
.on_press_down(Message::TogglePopup)
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
let content = if !self.gpus.is_empty() {
|
let content = if self.gpus.is_empty() {
|
||||||
|
btn
|
||||||
|
} else {
|
||||||
let dot = container(vertical_space().height(Length::Fixed(0.0)))
|
let dot = container(vertical_space().height(Length::Fixed(0.0)))
|
||||||
.padding(2.0)
|
.padding(2.0)
|
||||||
.class(cosmic::style::Container::Custom(Box::new(|theme| {
|
.class(cosmic::style::Container::Custom(Box::new(|theme| {
|
||||||
|
|
@ -517,14 +515,12 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
btn
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.core.applet.autosize_window(content).into()
|
self.core.applet.autosize_window(content).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: window::Id) -> Element<Message> {
|
fn view_window(&self, _id: window::Id) -> Element<'_, Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
@ -740,7 +736,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
width: 0.0,
|
width: 0.0,
|
||||||
color: Color::TRANSPARENT,
|
color: Color::TRANSPARENT,
|
||||||
},
|
},
|
||||||
shadow: Default::default(),
|
shadow: Shadow::default(),
|
||||||
icon_color: Some(Color::TRANSPARENT),
|
icon_color: Some(Color::TRANSPARENT),
|
||||||
}
|
}
|
||||||
},))),
|
},))),
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ pub async fn get_power_profile(daemon: Backend<'_>) -> Result<Power> {
|
||||||
"Battery" => Ok(Power::Battery),
|
"Battery" => Ok(Power::Battery),
|
||||||
"Balanced" => Ok(Power::Balanced),
|
"Balanced" => Ok(Power::Balanced),
|
||||||
"Performance" => Ok(Power::Performance),
|
"Performance" => Ok(Power::Performance),
|
||||||
_ => panic!("Unknown power profile: {}", power),
|
_ => panic!("Unknown power profile: {power}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Backend::PowerProfilesDaemon(ppd) => {
|
Backend::PowerProfilesDaemon(ppd) => {
|
||||||
|
|
@ -226,7 +226,7 @@ pub async fn get_charging_limit() -> anyhow::Result<bool> {
|
||||||
Backend::PowerProfilesDaemon(_) => {
|
Backend::PowerProfilesDaemon(_) => {
|
||||||
tracing::info!("Power Profiles Daemon is not supported.");
|
tracing::info!("Power Profiles Daemon is not supported.");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
anyhow::bail!("Unsupported")
|
anyhow::bail!("Unsupported")
|
||||||
|
|
@ -245,7 +245,7 @@ pub async fn set_charging_limit() -> Result<()> {
|
||||||
"Setting charging limit via Power Profiles Daemon is not supported."
|
"Setting charging limit via Power Profiles Daemon is not supported."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ async fn is_desktop() -> bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn powered_on(path: impl AsRef<Path>) -> bool {
|
async fn powered_on(path: impl AsRef<Path>) -> bool {
|
||||||
let Some(component) = path.as_ref().components().last() else {
|
let Some(component) = path.as_ref().components().next_back() else {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
let name_str = component.as_os_str();
|
let name_str = component.as_os_str();
|
||||||
|
|
@ -87,7 +87,7 @@ async fn powered_on(path: impl AsRef<Path>) -> bool {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
let Ok(state) =
|
let Ok(state) =
|
||||||
tokio::fs::read_to_string(format!("/sys/class/drm/{}/device/power_state", name)).await
|
tokio::fs::read_to_string(format!("/sys/class/drm/{name}/device/power_state")).await
|
||||||
else {
|
else {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
@ -201,120 +201,117 @@ impl Gpu {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn app_list(&self, running_apps: &[RunningApp]) -> Option<Vec<Entry>> {
|
async fn app_list(&self, running_apps: &[RunningApp]) -> Option<Vec<Entry>> {
|
||||||
match self.driver.as_ref().and_then(|s| s.to_str()) {
|
if let Some("nvidia") = self.driver.as_ref().and_then(|s| s.to_str()) {
|
||||||
Some("nvidia") => {
|
// figure out bus path for calling nvidia-smi
|
||||||
// figure out bus path for calling nvidia-smi
|
let mut sys_path = PathBuf::from("/sys/class/drm");
|
||||||
let mut sys_path = PathBuf::from("/sys/class/drm");
|
sys_path.push(self.path.components().next_back()?.as_os_str());
|
||||||
sys_path.push(self.path.components().last()?.as_os_str());
|
let buslink = std::fs::read_link(sys_path)
|
||||||
let buslink = std::fs::read_link(sys_path)
|
.ok()?
|
||||||
.ok()?
|
.components()
|
||||||
.components()
|
.rev()
|
||||||
.rev()
|
.nth(2)?
|
||||||
.nth(2)?
|
.as_os_str()
|
||||||
.as_os_str()
|
.to_string_lossy()
|
||||||
.to_string_lossy()
|
.into_owned();
|
||||||
.into_owned();
|
|
||||||
|
|
||||||
let smi_output = match tokio::process::Command::new("nvidia-smi")
|
let smi_output = match tokio::process::Command::new("nvidia-smi")
|
||||||
.args(["pmon", "--id", &buslink, "--count", "1"])
|
.args(["pmon", "--id", &buslink, "--count", "1"])
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(output) if output.status.success() => {
|
Ok(output) if output.status.success() => {
|
||||||
String::from_utf8_lossy(&output.stdout).into_owned()
|
String::from_utf8_lossy(&output.stdout).into_owned()
|
||||||
}
|
}
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
debug!(
|
debug!(
|
||||||
"smi returned error code {}: {}",
|
"smi returned error code {}: {}",
|
||||||
output.status,
|
output.status,
|
||||||
String::from_utf8_lossy(&output.stdout)
|
String::from_utf8_lossy(&output.stdout)
|
||||||
);
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
debug!("smi returned error code: {}", err);
|
debug!("smi returned error code: {}", err);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(
|
Some(
|
||||||
smi_output
|
smi_output
|
||||||
.lines()
|
.lines()
|
||||||
.filter(|line| {
|
.filter(|line| {
|
||||||
// smi shows an empty line filled with - when no app is running
|
// smi shows an empty line filled with - when no app is running
|
||||||
let components = line.split_whitespace().collect::<Vec<_>>();
|
let components = line.split_whitespace().collect::<Vec<_>>();
|
||||||
components[1].trim().ne("-") && !line.starts_with('#')
|
components[1].trim().ne("-") && !line.starts_with('#')
|
||||||
})
|
})
|
||||||
.map(|line| {
|
.map(|line| {
|
||||||
let components = line.split_whitespace().collect::<Vec<_>>();
|
let components = line.split_whitespace().collect::<Vec<_>>();
|
||||||
let pid = components[1].trim();
|
let pid = components[1].trim();
|
||||||
let process_name = components.last().unwrap().trim();
|
let process_name = components.last().unwrap().trim();
|
||||||
|
|
||||||
if let Some(application) = running_apps
|
if let Some(application) = running_apps
|
||||||
.iter()
|
.iter()
|
||||||
.find(|running_app| running_app.executable_name == process_name)
|
.find(|running_app| running_app.executable_name == process_name)
|
||||||
{
|
{
|
||||||
Entry {
|
Entry {
|
||||||
name: application.name.clone(),
|
name: application.name.clone(),
|
||||||
icon: application.icon.clone(),
|
icon: application.icon.clone(),
|
||||||
secondary: String::new(),
|
secondary: String::new(),
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Entry {
|
|
||||||
name: process_name.to_string(),
|
|
||||||
icon: None,
|
|
||||||
secondary: pid.to_string(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
.collect(),
|
Entry {
|
||||||
)
|
name: process_name.to_string(),
|
||||||
}
|
icon: None,
|
||||||
_ => {
|
secondary: pid.to_string(),
|
||||||
let lsof_output = match tokio::process::Command::new("lsof")
|
|
||||||
.args([OsStr::new("-t"), self.path.as_os_str()])
|
|
||||||
.output()
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(output) => String::from_utf8_lossy(&output.stdout).into_owned(),
|
|
||||||
Err(err) => {
|
|
||||||
debug!("lsof returned error code: {}", err);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(
|
|
||||||
lsof_output
|
|
||||||
.lines()
|
|
||||||
.filter_map(|pid| {
|
|
||||||
let executable = std::fs::read_link(format!("/proc/{}/exe", pid))
|
|
||||||
.ok()?
|
|
||||||
.components()
|
|
||||||
.last()?
|
|
||||||
.as_os_str()
|
|
||||||
.to_string_lossy()
|
|
||||||
.into_owned();
|
|
||||||
|
|
||||||
if let Some(application) = running_apps
|
|
||||||
.iter()
|
|
||||||
.find(|running_app| running_app.executable_name == executable)
|
|
||||||
{
|
|
||||||
Some(Entry {
|
|
||||||
name: application.name.clone(),
|
|
||||||
icon: application.icon.clone(),
|
|
||||||
secondary: String::new(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Some(Entry {
|
|
||||||
name: executable,
|
|
||||||
icon: None,
|
|
||||||
secondary: pid.to_string(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
.collect(),
|
})
|
||||||
)
|
.collect(),
|
||||||
}
|
)
|
||||||
|
} else {
|
||||||
|
let lsof_output = match tokio::process::Command::new("lsof")
|
||||||
|
.args([OsStr::new("-t"), self.path.as_os_str()])
|
||||||
|
.output()
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(output) => String::from_utf8_lossy(&output.stdout).into_owned(),
|
||||||
|
Err(err) => {
|
||||||
|
debug!("lsof returned error code: {err}");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(
|
||||||
|
lsof_output
|
||||||
|
.lines()
|
||||||
|
.filter_map(|pid| {
|
||||||
|
let executable = std::fs::read_link(format!("/proc/{pid}/exe"))
|
||||||
|
.ok()?
|
||||||
|
.components()
|
||||||
|
.next_back()?
|
||||||
|
.as_os_str()
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned();
|
||||||
|
|
||||||
|
if let Some(application) = running_apps
|
||||||
|
.iter()
|
||||||
|
.find(|running_app| running_app.executable_name == executable)
|
||||||
|
{
|
||||||
|
Some(Entry {
|
||||||
|
name: application.name.clone(),
|
||||||
|
icon: application.icon.clone(),
|
||||||
|
secondary: String::new(),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Some(Entry {
|
||||||
|
name: executable,
|
||||||
|
icon: None,
|
||||||
|
secondary: pid.to_string(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -325,14 +322,14 @@ fn all_gpus<S: AsRef<str>>(seat: S) -> io::Result<Vec<Gpu>> {
|
||||||
enumerator.match_sysname("card[0-9]*")?;
|
enumerator.match_sysname("card[0-9]*")?;
|
||||||
let mut gpus = enumerator
|
let mut gpus = enumerator
|
||||||
.scan_devices()?
|
.scan_devices()?
|
||||||
.filter(|device| {
|
.filter_map(|device| {
|
||||||
device
|
if device
|
||||||
.property_value("ID_SEAT")
|
.property_value("ID_SEAT")
|
||||||
.map(|x| x.to_os_string())
|
.unwrap_or_else(|| OsStr::new("seat0"))
|
||||||
.unwrap_or_else(|| OsString::from("seat0"))
|
!= seat.as_ref()
|
||||||
== *seat.as_ref()
|
{
|
||||||
})
|
return None;
|
||||||
.flat_map(|device| {
|
}
|
||||||
let path = device.devnode().map(PathBuf::from)?;
|
let path = device.devnode().map(PathBuf::from)?;
|
||||||
let node = DrmNode::from_path(&path).ok()?;
|
let node = DrmNode::from_path(&path).ok()?;
|
||||||
if !node.has_render() {
|
if !node.has_render() {
|
||||||
|
|
@ -340,11 +337,8 @@ fn all_gpus<S: AsRef<str>>(seat: S) -> io::Result<Vec<Gpu>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let boot_vga = if let Ok(Some(pci)) = device.parent_with_subsystem(Path::new("pci")) {
|
let boot_vga = if let Ok(Some(pci)) = device.parent_with_subsystem(Path::new("pci")) {
|
||||||
if let Some(value) = pci.attribute_value("boot_vga") {
|
pci.attribute_value("boot_vga")
|
||||||
value == "1"
|
.is_some_and(|value| value == "1")
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
@ -352,10 +346,10 @@ fn all_gpus<S: AsRef<str>>(seat: S) -> io::Result<Vec<Gpu>> {
|
||||||
let name = if let Some(parent) = device.parent() {
|
let name = if let Some(parent) = device.parent() {
|
||||||
let vendor = parent
|
let vendor = parent
|
||||||
.property_value("SWITCHEROO_CONTROL_VENDOR_NAME")
|
.property_value("SWITCHEROO_CONTROL_VENDOR_NAME")
|
||||||
.or_else(|| parent.property_value("ID_VENDOR_FROM_DATABASE"));
|
.or(parent.property_value("ID_VENDOR_FROM_DATABASE"));
|
||||||
let name = parent
|
let name = parent
|
||||||
.property_value("SWITCHEROO_CONTROL_PRODUCT_NAME")
|
.property_value("SWITCHEROO_CONTROL_PRODUCT_NAME")
|
||||||
.or_else(|| parent.property_value("ID_MODEL_FROM_DATABASE"));
|
.or(parent.property_value("ID_MODEL_FROM_DATABASE"));
|
||||||
|
|
||||||
if vendor.is_none() && name.is_none() {
|
if vendor.is_none() && name.is_none() {
|
||||||
String::from("Unknown GPU")
|
String::from("Unknown GPU")
|
||||||
|
|
@ -374,7 +368,7 @@ fn all_gpus<S: AsRef<str>>(seat: S) -> io::Result<Vec<Gpu>> {
|
||||||
let driver = loop {
|
let driver = loop {
|
||||||
if let Some(dev) = device {
|
if let Some(dev) = device {
|
||||||
if dev.driver().is_some() {
|
if dev.driver().is_some() {
|
||||||
break dev.driver().map(std::ffi::OsStr::to_os_string);
|
break dev.driver().map(OsStr::to_os_string);
|
||||||
} else {
|
} else {
|
||||||
device = dev.parent();
|
device = dev.parent();
|
||||||
}
|
}
|
||||||
|
|
@ -412,8 +406,8 @@ fn all_gpus<S: AsRef<str>>(seat: S) -> io::Result<Vec<Gpu>> {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.or_else(|| gpus.iter().position(|gpu| gpu.boot_vga))
|
.or(gpus.iter().position(|gpu| gpu.boot_vga))
|
||||||
.or_else(|| (gpus.len() == 1).then_some(0))
|
.or((gpus.len() == 1).then_some(0))
|
||||||
{
|
{
|
||||||
gpus[primary_idx].primary = true;
|
gpus[primary_idx].primary = true;
|
||||||
}
|
}
|
||||||
|
|
@ -487,10 +481,10 @@ async fn start_listening(
|
||||||
let name = if let Some(parent) = device.parent() {
|
let name = if let Some(parent) = device.parent() {
|
||||||
let vendor = parent
|
let vendor = parent
|
||||||
.property_value("SWITCHEROO_CONTROL_VENDOR_NAME")
|
.property_value("SWITCHEROO_CONTROL_VENDOR_NAME")
|
||||||
.or_else(|| parent.property_value("ID_VENDOR_FROM_DATABASE"));
|
.or(parent.property_value("ID_VENDOR_FROM_DATABASE"));
|
||||||
let name = parent
|
let name = parent
|
||||||
.property_value("SWITCHEROO_CONTROL_PRODUCT_NAME")
|
.property_value("SWITCHEROO_CONTROL_PRODUCT_NAME")
|
||||||
.or_else(|| parent.property_value("ID_MODEL_FROM_DATABASE"));
|
.or(parent.property_value("ID_MODEL_FROM_DATABASE"));
|
||||||
|
|
||||||
if vendor.is_none() && name.is_none() {
|
if vendor.is_none() && name.is_none() {
|
||||||
String::from("Unknown GPU")
|
String::from("Unknown GPU")
|
||||||
|
|
@ -509,7 +503,7 @@ async fn start_listening(
|
||||||
let driver = loop {
|
let driver = loop {
|
||||||
if let Some(dev) = device {
|
if let Some(dev) = device {
|
||||||
if dev.driver().is_some() {
|
if dev.driver().is_some() {
|
||||||
break dev.driver().map(std::ffi::OsStr::to_os_string);
|
break dev.driver().map(OsStr::to_os_string);
|
||||||
} else {
|
} else {
|
||||||
device = dev.parent();
|
device = dev.parent();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
destroy_popup(p),
|
destroy_popup(p),
|
||||||
cosmic::task::future(
|
cosmic::task::future(
|
||||||
set_tick(Duration::from_secs(10))
|
set_tick(Duration::from_secs(10))
|
||||||
.map(|_| cosmic::Action::App(Message::Ignore)),
|
.map(|()| cosmic::Action::App(Message::Ignore)),
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -133,7 +133,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let tx = self.bluer_sender.as_ref().cloned();
|
let tx = self.bluer_sender.clone();
|
||||||
return Task::batch(vec![
|
return Task::batch(vec![
|
||||||
iced::Task::perform(
|
iced::Task::perform(
|
||||||
async {
|
async {
|
||||||
|
|
@ -141,11 +141,11 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
let _ = tx.send(BluerRequest::StateUpdate).await;
|
let _ = tx.send(BluerRequest::StateUpdate).await;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|_| cosmic::action::app(Message::Ignore),
|
|()| cosmic::action::app(Message::Ignore),
|
||||||
),
|
),
|
||||||
get_popup(popup_settings),
|
get_popup(popup_settings),
|
||||||
cosmic::task::future(set_tick(Duration::from_secs(3)))
|
cosmic::task::future(set_tick(Duration::from_secs(3)))
|
||||||
.map(|_: ()| cosmic::Action::App(Message::Ignore)),
|
.map(|()| cosmic::Action::App(Message::Ignore)),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +160,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
err_msg,
|
err_msg,
|
||||||
} => {
|
} => {
|
||||||
if let Some(err_msg) = err_msg {
|
if let Some(err_msg) = err_msg {
|
||||||
eprintln!("bluetooth request error: {}", err_msg);
|
eprintln!("bluetooth request error: {err_msg}");
|
||||||
}
|
}
|
||||||
if self.bluer_state.bluetooth_enabled != state.bluetooth_enabled {
|
if self.bluer_state.bluetooth_enabled != state.bluetooth_enabled {
|
||||||
self.timeline
|
self.timeline
|
||||||
|
|
@ -178,7 +178,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
BluerRequest::StateUpdate
|
BluerRequest::StateUpdate
|
||||||
if self.popup.is_some() && self.bluer_sender.is_some() =>
|
if self.popup.is_some() && self.bluer_sender.is_some() =>
|
||||||
{
|
{
|
||||||
let tx = self.bluer_sender.as_ref().cloned().unwrap();
|
let tx = self.bluer_sender.clone().unwrap();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
// sleep for a bit before requesting state update again
|
// sleep for a bit before requesting state update again
|
||||||
tokio::time::sleep(Duration::from_millis(3000)).await;
|
tokio::time::sleep(Duration::from_millis(3000)).await;
|
||||||
|
|
@ -186,7 +186,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
BluerEvent::Init { sender, state } => {
|
BluerEvent::Init { sender, state } => {
|
||||||
self.bluer_sender.replace(sender);
|
self.bluer_sender.replace(sender);
|
||||||
|
|
@ -270,7 +270,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
}
|
}
|
||||||
_ => {} // TODO
|
_ => {} // TODO
|
||||||
}
|
}
|
||||||
if let Some(tx) = self.bluer_sender.as_mut().cloned() {
|
if let Some(tx) = self.bluer_sender.clone() {
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let _ = tx.send(r).await;
|
let _ = tx.send(r).await;
|
||||||
});
|
});
|
||||||
|
|
@ -295,7 +295,8 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
self.popup = None;
|
self.popup = None;
|
||||||
}
|
}
|
||||||
return cosmic::task::future(
|
return cosmic::task::future(
|
||||||
set_tick(Duration::from_secs(10)).map(|_| cosmic::Action::App(Message::Ignore)),
|
set_tick(Duration::from_secs(10))
|
||||||
|
.map(|()| cosmic::Action::App(Message::Ignore)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Message::OpenSettings => {
|
Message::OpenSettings => {
|
||||||
|
|
@ -305,7 +306,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
app_id: Self::APP_ID.to_string(),
|
app_id: Self::APP_ID.to_string(),
|
||||||
exec,
|
exec,
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
Message::Token(u) => match u {
|
Message::Token(u) => match u {
|
||||||
TokenUpdate::Init(tx) => {
|
TokenUpdate::Init(tx) => {
|
||||||
|
|
@ -347,7 +348,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
self.core
|
self.core
|
||||||
.applet
|
.applet
|
||||||
.icon_button(&self.icon_name)
|
.icon_button(&self.icon_name)
|
||||||
|
|
@ -355,7 +356,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: window::Id) -> Element<Message> {
|
fn view_window(&self, _id: window::Id) -> Element<'_, Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
@ -363,10 +364,9 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
let mut known_bluetooth = vec![];
|
let mut known_bluetooth = vec![];
|
||||||
// PERF: This should be pre-filtered in an update.
|
// PERF: This should be pre-filtered in an update.
|
||||||
for dev in self.bluer_state.devices.iter().filter(|d| {
|
for dev in self.bluer_state.devices.iter().filter(|d| {
|
||||||
!self
|
self.request_confirmation
|
||||||
.request_confirmation
|
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(false, |(dev, _, _)| d.address == dev.address)
|
.is_none_or(|(dev, _, _)| d.address != dev.address)
|
||||||
}) {
|
}) {
|
||||||
let mut row = row![
|
let mut row = row![
|
||||||
icon::from_name(dev.icon).size(16).symbolic(true),
|
icon::from_name(dev.icon).size(16).symbolic(true),
|
||||||
|
|
@ -380,13 +380,13 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
|
|
||||||
if let Some(battery) = dev.battery_percent {
|
if let Some(battery) = dev.battery_percent {
|
||||||
let icon = match battery {
|
let icon = match battery {
|
||||||
b if b >= 20 && b < 40 => "battery-low",
|
b if (20..40).contains(&b) => "battery-low",
|
||||||
b if b < 20 => "battery-caution",
|
b if b < 20 => "battery-caution",
|
||||||
_ => "battery",
|
_ => "battery",
|
||||||
};
|
};
|
||||||
let status = row!(
|
let status = row!(
|
||||||
icon::from_name(icon).symbolic(true).size(14),
|
icon::from_name(icon).symbolic(true).size(14),
|
||||||
text::body(format!("{}%", battery))
|
text::body(format!("{battery}%"))
|
||||||
)
|
)
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(2)
|
.spacing(2)
|
||||||
|
|
@ -416,7 +416,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
BluerDeviceStatus::Disconnected | BluerDeviceStatus::Pairing => continue,
|
BluerDeviceStatus::Disconnected | BluerDeviceStatus::Pairing => continue,
|
||||||
};
|
}
|
||||||
|
|
||||||
known_bluetooth.push(
|
known_bluetooth.push(
|
||||||
menu_button(row)
|
menu_button(row)
|
||||||
|
|
@ -529,10 +529,10 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
matches!(
|
matches!(
|
||||||
d.status,
|
d.status,
|
||||||
BluerDeviceStatus::Disconnected | BluerDeviceStatus::Pairing
|
BluerDeviceStatus::Disconnected | BluerDeviceStatus::Pairing
|
||||||
) && !self
|
) && self
|
||||||
.request_confirmation
|
.request_confirmation
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(false, |(dev, _, _)| d.address == dev.address)
|
.is_none_or(|(dev, _, _)| d.address != dev.address)
|
||||||
&& (d.has_name() || d.is_known_device_type())
|
&& (d.has_name() || d.is_known_device_type())
|
||||||
}) {
|
}) {
|
||||||
let row = row![
|
let row = row![
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
}
|
}
|
||||||
|
|
||||||
retry_count = retry_count.saturating_add(1);
|
retry_count = retry_count.saturating_add(1);
|
||||||
_ = tokio::time::sleep(Duration::from_millis(
|
() = tokio::time::sleep(Duration::from_millis(
|
||||||
2_u64.saturating_pow(retry_count).min(68719476734),
|
2_u64.saturating_pow(retry_count).min(68719476734),
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
|
|
@ -156,7 +156,7 @@ pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
event_handler(event).await;
|
event_handler(event).await;
|
||||||
// Consume any additional available events.
|
// Consume any additional available events.
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
while let Some(event) = session_rx.try_recv().ok() {
|
while let Ok(event) = session_rx.try_recv() {
|
||||||
event_handler(event).await;
|
event_handler(event).await;
|
||||||
count += 1;
|
count += 1;
|
||||||
if count == 100 {
|
if count == 100 {
|
||||||
|
|
@ -165,7 +165,7 @@ pub fn bluetooth_subscription<I: 'static + Hash + Copy + Send + Sync + Debug>(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
|
|
||||||
session_state.rx = Some(session_rx);
|
session_state.rx = Some(session_rx);
|
||||||
interval.tick().await;
|
interval.tick().await;
|
||||||
|
|
@ -271,10 +271,9 @@ impl BluerDevice {
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub async fn from_device(device: &bluer::Device) -> Self {
|
pub async fn from_device(device: &bluer::Device) -> Self {
|
||||||
let (mut name, is_paired, is_trusted, is_connected, battery_percent, icon) = futures::join!(
|
let (mut name, is_paired, is_trusted, is_connected, battery_percent, icon) = futures::join!(
|
||||||
device.name().map(|res| res
|
device
|
||||||
.ok()
|
.name()
|
||||||
.flatten()
|
.map(|res| res.ok().flatten().unwrap_or(device.address().to_string())),
|
||||||
.unwrap_or_else(|| device.address().to_string())),
|
|
||||||
device.is_paired().map(Result::unwrap_or_default),
|
device.is_paired().map(Result::unwrap_or_default),
|
||||||
device.is_trusted().map(Result::unwrap_or_default),
|
device.is_trusted().map(Result::unwrap_or_default),
|
||||||
device.is_connected().map(Result::unwrap_or_default),
|
device.is_connected().map(Result::unwrap_or_default),
|
||||||
|
|
@ -286,7 +285,7 @@ impl BluerDevice {
|
||||||
|
|
||||||
if name.is_empty() {
|
if name.is_empty() {
|
||||||
name = device.address().to_string();
|
name = device.address().to_string();
|
||||||
};
|
}
|
||||||
|
|
||||||
let status = if is_connected {
|
let status = if is_connected {
|
||||||
BluerDeviceStatus::Connected
|
BluerDeviceStatus::Connected
|
||||||
|
|
@ -385,9 +384,8 @@ impl BluerSessionState {
|
||||||
let agent_clone = adapter_clone_1.clone();
|
let agent_clone = adapter_clone_1.clone();
|
||||||
let tx_clone = tx_clone_1.clone();
|
let tx_clone = tx_clone_1.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let device = match agent_clone.device(req.device) {
|
let Ok(device) = agent_clone.device(req.device) else {
|
||||||
Ok(d) => d,
|
return Err(bluer::agent::ReqError::Rejected);
|
||||||
Err(_) => return Err(bluer::agent::ReqError::Rejected),
|
|
||||||
};
|
};
|
||||||
let _ = tx_clone
|
let _ = tx_clone
|
||||||
.send(BluerSessionEvent::AgentEvent(
|
.send(BluerSessionEvent::AgentEvent(
|
||||||
|
|
@ -397,16 +395,15 @@ impl BluerSessionState {
|
||||||
))
|
))
|
||||||
.await;
|
.await;
|
||||||
let pin_code = fastrand::u32(0..999999);
|
let pin_code = fastrand::u32(0..999999);
|
||||||
Ok(format!("{:06}", pin_code))
|
Ok(format!("{pin_code:06}"))
|
||||||
})
|
})
|
||||||
})),
|
})),
|
||||||
display_pin_code: Some(Box::new(move |req| {
|
display_pin_code: Some(Box::new(move |req| {
|
||||||
let agent_clone = adapter_clone_2.clone();
|
let agent_clone = adapter_clone_2.clone();
|
||||||
let tx_clone = tx_clone_2.clone();
|
let tx_clone = tx_clone_2.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let device = match agent_clone.device(req.device) {
|
let Ok(device) = agent_clone.device(req.device) else {
|
||||||
Ok(d) => d,
|
return Err(bluer::agent::ReqError::Rejected);
|
||||||
Err(_) => return Err(bluer::agent::ReqError::Rejected),
|
|
||||||
};
|
};
|
||||||
let _ = tx_clone
|
let _ = tx_clone
|
||||||
.send(BluerSessionEvent::AgentEvent(
|
.send(BluerSessionEvent::AgentEvent(
|
||||||
|
|
@ -424,9 +421,8 @@ impl BluerSessionState {
|
||||||
let agent_clone = adapter_clone_3.clone();
|
let agent_clone = adapter_clone_3.clone();
|
||||||
let tx_clone = tx_clone_3.clone();
|
let tx_clone = tx_clone_3.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let device = match agent_clone.device(req.device) {
|
let Ok(device) = agent_clone.device(req.device) else {
|
||||||
Ok(d) => d,
|
return Err(bluer::agent::ReqError::Rejected);
|
||||||
Err(_) => return Err(bluer::agent::ReqError::Rejected),
|
|
||||||
};
|
};
|
||||||
let _ = tx_clone
|
let _ = tx_clone
|
||||||
.send(BluerSessionEvent::AgentEvent(
|
.send(BluerSessionEvent::AgentEvent(
|
||||||
|
|
@ -443,9 +439,8 @@ impl BluerSessionState {
|
||||||
let agent_clone = adapter_clone_4.clone();
|
let agent_clone = adapter_clone_4.clone();
|
||||||
let tx_clone = tx_clone_4.clone();
|
let tx_clone = tx_clone_4.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let device = match agent_clone.device(req.device) {
|
let Ok(device) = agent_clone.device(req.device) else {
|
||||||
Ok(d) => d,
|
return Err(bluer::agent::ReqError::Rejected);
|
||||||
Err(_) => return Err(bluer::agent::ReqError::Rejected),
|
|
||||||
};
|
};
|
||||||
let _ = tx_clone
|
let _ = tx_clone
|
||||||
.send(BluerSessionEvent::AgentEvent(
|
.send(BluerSessionEvent::AgentEvent(
|
||||||
|
|
@ -462,9 +457,8 @@ impl BluerSessionState {
|
||||||
let agent_clone = adapter_clone_5.clone();
|
let agent_clone = adapter_clone_5.clone();
|
||||||
let tx_clone = tx_clone_5.clone();
|
let tx_clone = tx_clone_5.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let device = match agent_clone.device(req.device) {
|
let Ok(device) = agent_clone.device(req.device) else {
|
||||||
Ok(d) => d,
|
return Err(bluer::agent::ReqError::Rejected);
|
||||||
Err(_) => return Err(bluer::agent::ReqError::Rejected),
|
|
||||||
};
|
};
|
||||||
let (tx, mut rx) = channel(1);
|
let (tx, mut rx) = channel(1);
|
||||||
let _ = tx_clone
|
let _ = tx_clone
|
||||||
|
|
@ -487,9 +481,8 @@ impl BluerSessionState {
|
||||||
let agent_clone = adapter_clone_6.clone();
|
let agent_clone = adapter_clone_6.clone();
|
||||||
let tx_clone = tx_clone_6.clone();
|
let tx_clone = tx_clone_6.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let device = match agent_clone.device(req.device) {
|
let Ok(device) = agent_clone.device(req.device) else {
|
||||||
Ok(d) => d,
|
return Err(bluer::agent::ReqError::Rejected);
|
||||||
Err(_) => return Err(bluer::agent::ReqError::Rejected),
|
|
||||||
};
|
};
|
||||||
let (tx, mut rx) = channel(1);
|
let (tx, mut rx) = channel(1);
|
||||||
let _ = tx_clone
|
let _ = tx_clone
|
||||||
|
|
@ -511,9 +504,8 @@ impl BluerSessionState {
|
||||||
let agent_clone = adapter_clone_7.clone();
|
let agent_clone = adapter_clone_7.clone();
|
||||||
let tx_clone = tx_clone_7.clone();
|
let tx_clone = tx_clone_7.clone();
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let device = match agent_clone.device(req.device) {
|
let Ok(device) = agent_clone.device(req.device) else {
|
||||||
Ok(d) => d,
|
return Err(bluer::agent::ReqError::Rejected);
|
||||||
Err(_) => return Err(bluer::agent::ReqError::Rejected),
|
|
||||||
};
|
};
|
||||||
let (tx, mut rx) = channel(1);
|
let (tx, mut rx) = channel(1);
|
||||||
// TODO better describe the service to the user
|
// TODO better describe the service to the user
|
||||||
|
|
@ -614,16 +606,14 @@ impl BluerSessionState {
|
||||||
let mut new_devices = Vec::new();
|
let mut new_devices = Vec::new();
|
||||||
let mut interval = tokio::time::interval(Duration::from_secs(10));
|
let mut interval = tokio::time::interval(Duration::from_secs(10));
|
||||||
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);
|
||||||
let mut change_stream =
|
let Ok(mut change_stream) =
|
||||||
match adapter_clone.discover_devices_with_changes().await {
|
adapter_clone.discover_devices_with_changes().await
|
||||||
Ok(stream) => stream,
|
else {
|
||||||
Err(_) => {
|
tick(&mut interval).await;
|
||||||
tick(&mut interval).await;
|
return;
|
||||||
return;
|
};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
while let Some(_) = change_stream.next().await {
|
while change_stream.next().await.is_some() {
|
||||||
new_devices = build_device_list(new_devices, &adapter_clone).await;
|
new_devices = build_device_list(new_devices, &adapter_clone).await;
|
||||||
for d in new_devices
|
for d in new_devices
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -679,7 +669,7 @@ impl BluerSessionState {
|
||||||
match &req_clone {
|
match &req_clone {
|
||||||
BluerRequest::SetBluetoothEnabled(enabled) => {
|
BluerRequest::SetBluetoothEnabled(enabled) => {
|
||||||
if let Err(e) = adapter_clone.set_powered(*enabled).await {
|
if let Err(e) = adapter_clone.set_powered(*enabled).await {
|
||||||
tracing::error!("Failed to power off bluetooth adapter. {e:?}")
|
tracing::error!("Failed to power off bluetooth adapter. {e:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// rfkill will be persisted after reboot
|
// rfkill will be persisted after reboot
|
||||||
|
|
@ -695,8 +685,8 @@ impl BluerSessionState {
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|o| {
|
.and_then(|o| {
|
||||||
let lines = String::from_utf8(o.stdout).ok()?;
|
let lines = String::from_utf8(o.stdout).ok()?;
|
||||||
lines.split("\n").into_iter().find_map(|row| {
|
lines.split('\n').into_iter().find_map(|row| {
|
||||||
let (id, cname) = row.trim().split_once(" ")?;
|
let (id, cname) = row.trim().split_once(' ')?;
|
||||||
(name == cname).then_some(id.to_string())
|
(name == cname).then_some(id.to_string())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -768,7 +758,7 @@ impl BluerSessionState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BluerRequest::StateUpdate => {}
|
BluerRequest::StateUpdate => {}
|
||||||
};
|
}
|
||||||
|
|
||||||
let _ = tx_clone
|
let _ = tx_clone
|
||||||
.send(BluerSessionEvent::RequestResponse {
|
.send(BluerSessionEvent::RequestResponse {
|
||||||
|
|
@ -820,7 +810,7 @@ async fn build_device_list(mut devices: Vec<BluerDevice>, adapter: &Adapter) ->
|
||||||
.collect::<FuturesUnordered<_>>();
|
.collect::<FuturesUnordered<_>>();
|
||||||
|
|
||||||
while let Some(device) = device_stream.next().await {
|
while let Some(device) = device_stream.next().await {
|
||||||
devices.push(device)
|
devices.push(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
devices.sort();
|
devices.sort();
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -199,7 +199,7 @@ impl cosmic::Application for Window {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Self::Message> {
|
fn view(&self) -> Element<'_, Self::Message> {
|
||||||
let input_source_text = self.core.applet.text(
|
let input_source_text = self.core.applet.text(
|
||||||
self.active_layouts
|
self.active_layouts
|
||||||
.first()
|
.first()
|
||||||
|
|
@ -233,7 +233,7 @@ impl cosmic::Application for Window {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: Id) -> Element<Self::Message> {
|
fn view_window(&self, _id: Id) -> Element<'_, Self::Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
@ -294,7 +294,7 @@ impl Window {
|
||||||
.chain(std::iter::repeat(""));
|
.chain(std::iter::repeat(""));
|
||||||
|
|
||||||
'outer: for (layout, variant) in layouts.zip(variants) {
|
'outer: for (layout, variant) in layouts.zip(variants) {
|
||||||
println!("{} : {}", layout, variant);
|
println!("{layout} : {variant}");
|
||||||
for xkb_layout in &self.layouts {
|
for xkb_layout in &self.layouts {
|
||||||
if layout != xkb_layout.name() {
|
if layout != xkb_layout.name() {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -88,25 +88,23 @@ impl Minimize {
|
||||||
fn find_new_desktop_entry(&mut self, appid: &str) -> fde::DesktopEntry {
|
fn find_new_desktop_entry(&mut self, appid: &str) -> fde::DesktopEntry {
|
||||||
let unicase_appid = fde::unicase::Ascii::new(appid);
|
let unicase_appid = fde::unicase::Ascii::new(appid);
|
||||||
|
|
||||||
let de = match fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
let de = if let Some(de) = fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
||||||
Some(de) => de,
|
de
|
||||||
None => {
|
} else {
|
||||||
// Update desktop entries in case it was not found.
|
// Update desktop entries in case it was not found.
|
||||||
self.update_desktop_entries();
|
self.update_desktop_entries();
|
||||||
match fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
if let Some(appid) = fde::find_app_by_id(&self.desktop_entries, unicase_appid) {
|
||||||
Some(appid) => appid,
|
appid
|
||||||
None => {
|
} else {
|
||||||
tracing::warn!(appid, "could not find desktop entry for app");
|
tracing::warn!(appid, "could not find desktop entry for app");
|
||||||
let mut entry = fde::DesktopEntry {
|
let mut entry = fde::DesktopEntry {
|
||||||
appid: appid.to_owned(),
|
appid: appid.to_owned(),
|
||||||
groups: Default::default(),
|
groups: Default::default(),
|
||||||
path: Default::default(),
|
path: Default::default(),
|
||||||
ubuntu_gettext_domain: None,
|
ubuntu_gettext_domain: None,
|
||||||
};
|
};
|
||||||
entry.add_desktop_entry("Name".to_string(), appid.to_owned());
|
entry.add_desktop_entry("Name".to_string(), appid.to_owned());
|
||||||
return entry;
|
return entry;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -186,7 +184,7 @@ impl cosmic::Application for Minimize {
|
||||||
.desktop_entry
|
.desktop_entry
|
||||||
.icon()
|
.icon()
|
||||||
.unwrap_or(&apps[pos].desktop_entry.appid),
|
.unwrap_or(&apps[pos].desktop_entry.appid),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
apps[pos].toplevel_info = toplevel_info;
|
apps[pos].toplevel_info = toplevel_info;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -278,7 +276,7 @@ impl cosmic::Application for Minimize {
|
||||||
cosmic::app::Action::Surface(a),
|
cosmic::app::Action::Surface(a),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,17 +284,14 @@ impl cosmic::Application for Minimize {
|
||||||
wayland_subscription::wayland_subscription().map(Message::Wayland)
|
wayland_subscription::wayland_subscription().map(Message::Wayland)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Self::Message> {
|
fn view(&self) -> Element<'_, Self::Message> {
|
||||||
let max_icon_count = self
|
let max_icon_count = self.max_icon_count().map_or(self.apps.len(), |n| {
|
||||||
.max_icon_count()
|
if n < self.apps.len() {
|
||||||
.map(|n| {
|
n - 1
|
||||||
if n < self.apps.len() {
|
} else {
|
||||||
n - 1
|
self.apps.len()
|
||||||
} else {
|
}
|
||||||
self.apps.len()
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or(self.apps.len());
|
|
||||||
let (width, _) = self.core.applet.suggested_size(false);
|
let (width, _) = self.core.applet.suggested_size(false);
|
||||||
let padding = self.core.applet.suggested_padding(false);
|
let padding = self.core.applet.suggested_padding(false);
|
||||||
let theme = self.core.system_theme().cosmic();
|
let theme = self.core.system_theme().cosmic();
|
||||||
|
|
@ -339,7 +334,7 @@ impl cosmic::Application for Minimize {
|
||||||
|
|
||||||
// TODO optional dividers on ends if detects app list neighbor
|
// TODO optional dividers on ends if detects app list neighbor
|
||||||
// not sure the best way to tell if there is an adjacent app-list
|
// not sure the best way to tell if there is an adjacent app-list
|
||||||
let icon_buttons = icon_buttons.chain(overflow_btn.into_iter());
|
let icon_buttons = icon_buttons.chain(overflow_btn);
|
||||||
let content: Element<_> = if matches!(
|
let content: Element<_> = if matches!(
|
||||||
self.core.applet.anchor,
|
self.core.applet.anchor,
|
||||||
PanelAnchor::Top | PanelAnchor::Bottom
|
PanelAnchor::Top | PanelAnchor::Bottom
|
||||||
|
|
@ -384,17 +379,14 @@ impl cosmic::Application for Minimize {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: window::Id) -> Element<Self::Message> {
|
fn view_window(&self, _id: window::Id) -> Element<'_, Self::Message> {
|
||||||
let max_icon_count = self
|
let max_icon_count = self.max_icon_count().map_or(self.apps.len(), |n| {
|
||||||
.max_icon_count()
|
if n < self.apps.len() {
|
||||||
.map(|n| {
|
n - 1
|
||||||
if n < self.apps.len() {
|
} else {
|
||||||
n - 1
|
self.apps.len()
|
||||||
} else {
|
}
|
||||||
self.apps.len()
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or(self.apps.len());
|
|
||||||
let (width, _) = self.core.applet.suggested_size(false);
|
let (width, _) = self.core.applet.suggested_size(false);
|
||||||
let padding = self.core.applet.suggested_padding(false);
|
let padding = self.core.applet.suggested_padding(false);
|
||||||
let theme = self.core.system_theme().cosmic();
|
let theme = self.core.system_theme().cosmic();
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for Minimize {}", error);
|
eprintln!("Error while loading language for Minimize {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,10 @@ impl Session {
|
||||||
self.condvar.notify_all();
|
self.condvar.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait_while<F: FnMut(&SessionInner) -> bool>(&self, mut f: F) -> MutexGuard<SessionInner> {
|
fn wait_while<F: FnMut(&SessionInner) -> bool>(
|
||||||
|
&self,
|
||||||
|
mut f: F,
|
||||||
|
) -> MutexGuard<'_, SessionInner> {
|
||||||
self.condvar
|
self.condvar
|
||||||
.wait_while(self.inner.lock().unwrap(), |data| f(data))
|
.wait_while(self.inner.lock().unwrap(), |data| f(data))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -150,7 +153,7 @@ impl CaptureData {
|
||||||
&self.qh,
|
&self.qh,
|
||||||
SessionData {
|
SessionData {
|
||||||
session: session.clone(),
|
session: session.clone(),
|
||||||
session_data: Default::default(),
|
session_data: ScreencopySessionData::default(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -168,22 +171,19 @@ impl CaptureData {
|
||||||
}
|
}
|
||||||
|
|
||||||
// XXX
|
// XXX
|
||||||
if !formats
|
if !formats.shm_formats.contains(&wl_shm::Format::Abgr8888) {
|
||||||
.shm_formats
|
|
||||||
.contains(&wl_shm::Format::Abgr8888.into())
|
|
||||||
{
|
|
||||||
tracing::error!("No suitable buffer format found");
|
tracing::error!("No suitable buffer format found");
|
||||||
tracing::warn!("Available formats: {:#?}", formats);
|
tracing::warn!("Available formats: {:#?}", formats);
|
||||||
return None;
|
return None;
|
||||||
};
|
}
|
||||||
|
|
||||||
let buf_len = width * height * 4;
|
let buf_len = width * height * 4;
|
||||||
if let Some(len) = len {
|
if let Some(len) = len {
|
||||||
if len != buf_len {
|
if len != buf_len {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
} else if let Err(_err) = rustix::fs::ftruncate(&fd, buf_len as _) {
|
} else if let Err(_err) = rustix::fs::ftruncate(&fd, buf_len.into()) {
|
||||||
};
|
}
|
||||||
let pool = self
|
let pool = self
|
||||||
.wl_shm
|
.wl_shm
|
||||||
.create_pool(fd.as_fd(), buf_len as i32, &self.qh, ());
|
.create_pool(fd.as_fd(), buf_len as i32, &self.qh, ());
|
||||||
|
|
@ -202,7 +202,7 @@ impl CaptureData {
|
||||||
&[],
|
&[],
|
||||||
&self.qh,
|
&self.qh,
|
||||||
FrameData {
|
FrameData {
|
||||||
frame_data: Default::default(),
|
frame_data: ScreencopyFrameData::default(),
|
||||||
session: capture_session.clone(),
|
session: capture_session.clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
@ -237,7 +237,7 @@ impl<T: AsFd> ShmImage<T> {
|
||||||
pub fn image(&self) -> anyhow::Result<image::RgbaImage> {
|
pub fn image(&self) -> anyhow::Result<image::RgbaImage> {
|
||||||
let mmap = unsafe { memmap2::Mmap::map(&self.fd.as_fd())? };
|
let mmap = unsafe { memmap2::Mmap::map(&self.fd.as_fd())? };
|
||||||
image::RgbaImage::from_raw(self.width, self.height, mmap.to_vec())
|
image::RgbaImage::from_raw(self.width, self.height, mmap.to_vec())
|
||||||
.ok_or_else(|| anyhow::anyhow!("ShmImage had incorrect size"))
|
.ok_or(anyhow::anyhow!("ShmImage had incorrect size"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,7 +297,7 @@ impl AppData {
|
||||||
handle: &ExtForeignToplevelHandleV1,
|
handle: &ExtForeignToplevelHandleV1,
|
||||||
) -> Option<ZcosmicToplevelHandleV1> {
|
) -> Option<ZcosmicToplevelHandleV1> {
|
||||||
self.toplevel_info_state
|
self.toplevel_info_state
|
||||||
.info(&handle)?
|
.info(handle)?
|
||||||
.cosmic_toplevel
|
.cosmic_toplevel
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
@ -311,9 +311,7 @@ impl AppData {
|
||||||
capturer: self.screencopy_state.capturer().clone(),
|
capturer: self.screencopy_state.capturer().clone(),
|
||||||
};
|
};
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
use std::ffi::CStr;
|
let name = c"minimize-applet-screencopy";
|
||||||
let name =
|
|
||||||
unsafe { CStr::from_bytes_with_nul_unchecked(b"minimize-applet-screencopy\0") };
|
|
||||||
let Ok(fd) = rustix::fs::memfd_create(name, rustix::fs::MemfdFlags::CLOEXEC) else {
|
let Ok(fd) = rustix::fs::memfd_create(name, rustix::fs::MemfdFlags::CLOEXEC) else {
|
||||||
tracing::error!("Failed to get fd for capture");
|
tracing::error!("Failed to get fd for capture");
|
||||||
return;
|
return;
|
||||||
|
|
@ -347,7 +345,7 @@ impl AppData {
|
||||||
tx.send(WaylandUpdate::Image(handle, WaylandImage::new(img))),
|
tx.send(WaylandUpdate::Image(handle, WaylandImage::new(img))),
|
||||||
) {
|
) {
|
||||||
tracing::error!("Failed to send image event to subscription {err:?}");
|
tracing::error!("Failed to send image event to subscription {err:?}");
|
||||||
};
|
}
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("Failed to capture image");
|
tracing::error!("Failed to capture image");
|
||||||
}
|
}
|
||||||
|
|
@ -448,7 +446,7 @@ pub(crate) fn wayland_handler(
|
||||||
.expect("Failed to insert wayland source.");
|
.expect("Failed to insert wayland source.");
|
||||||
|
|
||||||
if handle
|
if handle
|
||||||
.insert_source(rx, |event, _, state| match event {
|
.insert_source(rx, |event, (), state| match event {
|
||||||
calloop::channel::Event::Msg(req) => match req {
|
calloop::channel::Event::Msg(req) => match req {
|
||||||
WaylandRequest::Toplevel(req) => match req {
|
WaylandRequest::Toplevel(req) => match req {
|
||||||
ToplevelRequest::Activate(handle) => {
|
ToplevelRequest::Activate(handle) => {
|
||||||
|
|
@ -552,7 +550,7 @@ impl Dispatch<wl_shm_pool::WlShmPool, ()> for AppData {
|
||||||
_app_data: &mut Self,
|
_app_data: &mut Self,
|
||||||
_buffer: &wl_shm_pool::WlShmPool,
|
_buffer: &wl_shm_pool::WlShmPool,
|
||||||
_event: wl_shm_pool::Event,
|
_event: wl_shm_pool::Event,
|
||||||
_: &(),
|
(): &(),
|
||||||
_: &Connection,
|
_: &Connection,
|
||||||
_qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -564,7 +562,7 @@ impl Dispatch<wl_buffer::WlBuffer, ()> for AppData {
|
||||||
_app_data: &mut Self,
|
_app_data: &mut Self,
|
||||||
_buffer: &wl_buffer::WlBuffer,
|
_buffer: &wl_buffer::WlBuffer,
|
||||||
_event: wl_buffer::Event,
|
_event: wl_buffer::Event,
|
||||||
_: &(),
|
(): &(),
|
||||||
_: &Connection,
|
_: &Connection,
|
||||||
_qh: &QueueHandle<Self>,
|
_qh: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ pub struct WindowImage<'a, Msg> {
|
||||||
icon: Element<'a, Msg>,
|
icon: Element<'a, Msg>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Msg> WindowImage<'a, Msg>
|
impl<Msg> WindowImage<'_, Msg>
|
||||||
where
|
where
|
||||||
Msg: 'static + Clone,
|
Msg: 'static + Clone,
|
||||||
{
|
{
|
||||||
|
|
@ -81,13 +81,13 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'a, Msg> {
|
impl<Msg> Widget<Msg, cosmic::Theme, cosmic::Renderer> for WindowImage<'_, Msg> {
|
||||||
fn children(&self) -> Vec<cosmic::iced_core::widget::Tree> {
|
fn children(&self) -> Vec<cosmic::iced_core::widget::Tree> {
|
||||||
vec![Tree::new(&self.image_button), Tree::new(&self.icon)]
|
vec![Tree::new(&self.image_button), Tree::new(&self.icon)]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn diff(&mut self, tree: &mut cosmic::iced_core::widget::Tree) {
|
fn diff(&mut self, tree: &mut cosmic::iced_core::widget::Tree) {
|
||||||
tree.diff_children(&mut [&mut self.image_button, &mut self.icon])
|
tree.diff_children(&mut [&mut self.image_button, &mut self.icon]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overlay<'b>(
|
fn overlay<'b>(
|
||||||
|
|
|
||||||
|
|
@ -127,9 +127,8 @@ impl CosmicNetworkApplet {
|
||||||
self.update_togglers(&new_state);
|
self.update_togglers(&new_state);
|
||||||
// check for failed conns that can be reset
|
// check for failed conns that can be reset
|
||||||
for new_s in &mut new_state.active_conns {
|
for new_s in &mut new_state.active_conns {
|
||||||
let state = match new_s {
|
let ActiveConnectionInfo::WiFi { state, .. } = new_s else {
|
||||||
ActiveConnectionInfo::WiFi { state, .. } => state,
|
continue;
|
||||||
_ => continue,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if matches!(state, ActiveConnectionState::Activated) {
|
if matches!(state, ActiveConnectionState::Activated) {
|
||||||
|
|
@ -180,7 +179,7 @@ impl CosmicNetworkApplet {
|
||||||
_ => icon_name,
|
_ => icon_name,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.to_string()
|
.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_togglers(&mut self, state: &NetworkManagerState) {
|
fn update_togglers(&mut self, state: &NetworkManagerState) {
|
||||||
|
|
@ -194,7 +193,7 @@ impl CosmicNetworkApplet {
|
||||||
chain::Toggler::off(WIFI.clone(), 1.)
|
chain::Toggler::off(WIFI.clone(), 1.)
|
||||||
};
|
};
|
||||||
timeline.set_chain(chain);
|
timeline.set_chain(chain);
|
||||||
};
|
}
|
||||||
|
|
||||||
if state.airplane_mode != self.nm_state.airplane_mode {
|
if state.airplane_mode != self.nm_state.airplane_mode {
|
||||||
changed = true;
|
changed = true;
|
||||||
|
|
@ -204,7 +203,7 @@ impl CosmicNetworkApplet {
|
||||||
chain::Toggler::off(AIRPLANE_MODE.clone(), 1.)
|
chain::Toggler::off(AIRPLANE_MODE.clone(), 1.)
|
||||||
};
|
};
|
||||||
timeline.set_chain(chain);
|
timeline.set_chain(chain);
|
||||||
};
|
}
|
||||||
if changed {
|
if changed {
|
||||||
timeline.start();
|
timeline.start();
|
||||||
}
|
}
|
||||||
|
|
@ -344,21 +343,15 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
let conn_match = self
|
let conn_match = self
|
||||||
.new_connection
|
.new_connection
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|c| c.ssid() == ssid && c.hw_address() == *hw_address)
|
.is_some_and(|c| c.ssid() == ssid && c.hw_address() == *hw_address);
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
if conn_match && success {
|
if conn_match && success {
|
||||||
if let Some(s) = state
|
if let Some(ActiveConnectionInfo::WiFi { state, .. }) = state
|
||||||
.active_conns
|
.active_conns
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.find(|ap| &ap.name() == ssid && ap.hw_address() == *hw_address)
|
.find(|ap| &ap.name() == ssid && ap.hw_address() == *hw_address)
|
||||||
{
|
{
|
||||||
match s {
|
*state = ActiveConnectionState::Activated;
|
||||||
ActiveConnectionInfo::WiFi { state, .. } => {
|
|
||||||
*state = ActiveConnectionState::Activated;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
self.failed_known_ssids.remove(ssid);
|
self.failed_known_ssids.remove(ssid);
|
||||||
self.new_connection = None;
|
self.new_connection = None;
|
||||||
|
|
@ -401,7 +394,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
} else if self
|
} else if self
|
||||||
.new_connection
|
.new_connection
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|c| c.ssid()).is_some_and(|ssid| {
|
.map(NewConnectionState::ssid).is_some_and(|ssid| {
|
||||||
state.active_conns.iter().any(|c|
|
state.active_conns.iter().any(|c|
|
||||||
matches!(c, ActiveConnectionInfo::WiFi { name, state: ActiveConnectionState::Activated, .. } if ssid == name)
|
matches!(c, ActiveConnectionInfo::WiFi { name, state: ActiveConnectionState::Activated, .. } if ssid == name)
|
||||||
)
|
)
|
||||||
|
|
@ -423,9 +416,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Message::SelectWirelessAccessPoint(access_point) => {
|
Message::SelectWirelessAccessPoint(access_point) => {
|
||||||
let tx = if let Some(tx) = self.nm_sender.as_ref() {
|
let Some(tx) = self.nm_sender.as_ref() else {
|
||||||
tx
|
|
||||||
} else {
|
|
||||||
return Task::none();
|
return Task::none();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -467,9 +458,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
}
|
}
|
||||||
Message::SubmitPassword => {
|
Message::SubmitPassword => {
|
||||||
// save password
|
// save password
|
||||||
let tx = if let Some(tx) = self.nm_sender.as_ref() {
|
let Some(tx) = self.nm_sender.as_ref() else {
|
||||||
tx
|
|
||||||
} else {
|
|
||||||
return Task::none();
|
return Task::none();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -485,12 +474,12 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
let _ = tx.unbounded_send(NetworkManagerRequest::Authenticate {
|
let _ = tx.unbounded_send(NetworkManagerRequest::Authenticate {
|
||||||
ssid: access_point.ssid.clone(),
|
ssid: access_point.ssid.clone(),
|
||||||
identity: is_enterprise.then(|| identity.clone()),
|
identity: is_enterprise.then(|| identity.clone()),
|
||||||
password: password,
|
password,
|
||||||
hw_address: access_point.hw_address,
|
hw_address: access_point.hw_address,
|
||||||
});
|
});
|
||||||
self.new_connection
|
self.new_connection
|
||||||
.replace(NewConnectionState::Waiting(access_point));
|
.replace(NewConnectionState::Waiting(access_point));
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
Message::ActivateKnownWifi(ssid, hw_address) => {
|
Message::ActivateKnownWifi(ssid, hw_address) => {
|
||||||
let mut network_type = NetworkType::Open;
|
let mut network_type = NetworkType::Open;
|
||||||
|
|
@ -616,7 +605,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
self.core
|
self.core
|
||||||
.applet
|
.applet
|
||||||
.icon_button(&self.icon_name)
|
.icon_button(&self.icon_name)
|
||||||
|
|
@ -624,7 +613,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: window::Id) -> Element<Message> {
|
fn view_window(&self, _id: window::Id) -> Element<'_, Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
@ -744,7 +733,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
}
|
||||||
if self.failed_known_ssids.contains(name) {
|
if self.failed_known_ssids.contains(name) {
|
||||||
btn_content.push(
|
btn_content.push(
|
||||||
cosmic::widget::button::icon(
|
cosmic::widget::button::icon(
|
||||||
|
|
@ -753,7 +742,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
.icon_size(16)
|
.icon_size(16)
|
||||||
.on_press(Message::ResetFailedKnownSsid(name.clone(), *hw_address))
|
.on_press(Message::ResetFailedKnownSsid(name.clone(), *hw_address))
|
||||||
.into(),
|
.into(),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
known_wifi.push(Element::from(
|
known_wifi.push(Element::from(
|
||||||
|
|
@ -768,7 +757,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
.align_x(Alignment::Center),
|
.align_x(Alignment::Center),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut content = if let Some(hw_device_to_show) = self.hw_device_to_show {
|
let mut content = if let Some(hw_device_to_show) = self.hw_device_to_show {
|
||||||
|
|
@ -899,7 +888,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.spacing(8),
|
.spacing(8),
|
||||||
)
|
)
|
||||||
.on_press(Message::OpenHwDevice(Some(hw_device.clone()))),
|
.on_press(Message::OpenHwDevice(Some(hw_device))),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -955,7 +944,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
known.hw_address,
|
known.hw_address,
|
||||||
))
|
))
|
||||||
.into(),
|
.into(),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut btn = menu_button(
|
let mut btn = menu_button(
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ async fn start_listening(
|
||||||
let mut active_conns_changed = network_manager.receive_active_connections_changed().await;
|
let mut active_conns_changed = network_manager.receive_active_connections_changed().await;
|
||||||
active_conns_changed.next().await;
|
active_conns_changed.next().await;
|
||||||
|
|
||||||
while let (Some(_change), _) = tokio::join!(
|
while let (Some(_change), ()) = tokio::join!(
|
||||||
active_conns_changed.next(),
|
active_conns_changed.next(),
|
||||||
tokio::time::sleep(tokio::time::Duration::from_secs(1))
|
tokio::time::sleep(tokio::time::Duration::from_secs(1))
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ pub async fn handle_wireless_device(
|
||||||
if let Some(t) = scan_changed.next().await {
|
if let Some(t) = scan_changed.next().await {
|
||||||
if let Ok(-1) = t.get().await {
|
if let Ok(-1) = t.get().await {
|
||||||
eprintln!("scan errored");
|
eprintln!("scan errored");
|
||||||
return Ok(Default::default());
|
return Ok(Vec::new());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let access_points = device.get_access_points().await?;
|
let access_points = device.get_access_points().await?;
|
||||||
|
|
@ -33,8 +33,7 @@ pub async fn handle_wireless_device(
|
||||||
.await
|
.await
|
||||||
.and_then(|dev| dev.cached_state())
|
.and_then(|dev| dev.cached_state())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.map(|s| s.into())
|
.map_or(DeviceState::Unknown, |s| s.into());
|
||||||
.unwrap_or_else(|| DeviceState::Unknown);
|
|
||||||
// Sort by strength and remove duplicates
|
// Sort by strength and remove duplicates
|
||||||
let mut aps = HashMap::<String, AccessPoint>::new();
|
let mut aps = HashMap::<String, AccessPoint>::new();
|
||||||
for ap in access_points {
|
for ap in access_points {
|
||||||
|
|
@ -45,7 +44,7 @@ pub async fn handle_wireless_device(
|
||||||
if access_point.strength > strength {
|
if access_point.strength > strength {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
let proxy: &AccessPointProxy = ≈
|
let proxy: &AccessPointProxy = ≈
|
||||||
let Ok(flags) = ap.rsn_flags().await else {
|
let Ok(flags) = ap.rsn_flags().await else {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -100,6 +99,7 @@ pub struct AccessPoint {
|
||||||
// TODO do we want to support eap methods other than peap in the applet?
|
// TODO do we want to support eap methods other than peap in the applet?
|
||||||
// Then we'd need a dropdown for the eap method,
|
// Then we'd need a dropdown for the eap method,
|
||||||
// and tls requires a cert instead of a password
|
// and tls requires a cert instead of a password
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum NetworkType {
|
pub enum NetworkType {
|
||||||
Open,
|
Open,
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ pub async fn active_connections(
|
||||||
Some(SpecificDevice::Wired(wired_device)) => {
|
Some(SpecificDevice::Wired(wired_device)) => {
|
||||||
info.push(ActiveConnectionInfo::Wired {
|
info.push(ActiveConnectionInfo::Wired {
|
||||||
name: connection.id().await?,
|
name: connection.id().await?,
|
||||||
hw_address: HwAddress::from_string(&wired_device.hw_address().await?)
|
hw_address: HwAddress::from_str(&wired_device.hw_address().await?)
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
speed: wired_device.speed().await?,
|
speed: wired_device.speed().await?,
|
||||||
ip_addresses: addresses.clone(),
|
ip_addresses: addresses.clone(),
|
||||||
|
|
@ -53,10 +53,8 @@ pub async fn active_connections(
|
||||||
info.push(ActiveConnectionInfo::WiFi {
|
info.push(ActiveConnectionInfo::WiFi {
|
||||||
name: String::from_utf8_lossy(&access_point.ssid().await?).into_owned(),
|
name: String::from_utf8_lossy(&access_point.ssid().await?).into_owned(),
|
||||||
ip_addresses: addresses.clone(),
|
ip_addresses: addresses.clone(),
|
||||||
hw_address: HwAddress::from_string(
|
hw_address: HwAddress::from_str(&wireless_device.hw_address().await?)
|
||||||
&wireless_device.hw_address().await?,
|
.unwrap_or_default(),
|
||||||
)
|
|
||||||
.unwrap_or_default(),
|
|
||||||
state,
|
state,
|
||||||
strength: access_point.strength().await.unwrap_or_default(),
|
strength: access_point.strength().await.unwrap_or_default(),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ async fn start_listening(
|
||||||
let mut devices_changed = network_manager.receive_devices_changed().await;
|
let mut devices_changed = network_manager.receive_devices_changed().await;
|
||||||
|
|
||||||
let secs = if has_popup { 4 } else { 60 };
|
let secs = if has_popup { 4 } else { 60 };
|
||||||
while let (Some(_change), _) = tokio::join!(
|
while let (Some(_change), ()) = tokio::join!(
|
||||||
devices_changed.next(),
|
devices_changed.next(),
|
||||||
tokio::time::sleep(tokio::time::Duration::from_secs(secs))
|
tokio::time::sleep(tokio::time::Duration::from_secs(secs))
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::fmt::Write;
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug, PartialOrd, Ord)]
|
#[derive(Copy, Clone, PartialEq, Eq, Default, Debug, PartialOrd, Ord)]
|
||||||
pub struct HwAddress {
|
pub struct HwAddress {
|
||||||
address: u64,
|
address: u64,
|
||||||
|
|
@ -5,7 +7,7 @@ pub struct HwAddress {
|
||||||
|
|
||||||
impl HwAddress {
|
impl HwAddress {
|
||||||
pub fn from_str(arg: &str) -> Option<Self> {
|
pub fn from_str(arg: &str) -> Option<Self> {
|
||||||
let columnless_vec = arg.split(":").collect::<Vec<&str>>();
|
let columnless_vec = arg.split(':').collect::<Box<[_]>>();
|
||||||
if columnless_vec.len() * 3 - 1 != arg.len() {
|
if columnless_vec.len() * 3 - 1 != arg.len() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
@ -16,24 +18,19 @@ impl HwAddress {
|
||||||
}
|
}
|
||||||
u64::from_str_radix(columnless_vec.join("").as_str(), 16)
|
u64::from_str_radix(columnless_vec.join("").as_str(), 16)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|address| Some(HwAddress { address }))
|
.map(|address| HwAddress { address })
|
||||||
}
|
}
|
||||||
pub fn from_string(arg: &String) -> Option<Self> {
|
}
|
||||||
HwAddress::from_str(arg.as_str())
|
|
||||||
}
|
impl std::fmt::Display for HwAddress {
|
||||||
pub fn to_string(&self) -> String {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
// return if self.address > 100000000000000 {
|
for (index, c) in format!("{:x}", self.address).char_indices() {
|
||||||
// "Intel Corp".to_string()
|
if index != 0 && index % 2 == 0 {
|
||||||
// } else {
|
f.write_char(':')?;
|
||||||
// "TP-Link".to_string()
|
}
|
||||||
// };
|
f.write_char(c)?;
|
||||||
format!("{:#x}", self.address)
|
}
|
||||||
.trim_start_matches("0x")
|
|
||||||
.chars()
|
Ok(())
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.chunks(2)
|
|
||||||
.map(|chunk| chunk.iter().cloned().collect::<String>())
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(":")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,9 +74,8 @@ async fn start_listening(
|
||||||
) -> State {
|
) -> State {
|
||||||
match state {
|
match state {
|
||||||
State::Ready => {
|
State::Ready => {
|
||||||
let conn = match Connection::system().await {
|
let Ok(conn) = Connection::system().await else {
|
||||||
Ok(c) => c,
|
return State::Finished;
|
||||||
Err(_) => return State::Finished,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let (tx, rx) = unbounded();
|
let (tx, rx) = unbounded();
|
||||||
|
|
@ -96,9 +95,8 @@ async fn start_listening(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::Waiting(conn, mut rx) => {
|
State::Waiting(conn, mut rx) => {
|
||||||
let network_manager = match NetworkManager::new(&conn).await {
|
let Ok(network_manager) = NetworkManager::new(&conn).await else {
|
||||||
Ok(n) => n,
|
return State::Finished;
|
||||||
Err(_) => return State::Finished,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match rx.next().await {
|
match rx.next().await {
|
||||||
|
|
@ -114,7 +112,7 @@ async fn start_listening(
|
||||||
}
|
}
|
||||||
let mut is_there_device = false;
|
let mut is_there_device = false;
|
||||||
for device in c.devices().await.unwrap_or_default() {
|
for device in c.devices().await.unwrap_or_default() {
|
||||||
if HwAddress::from_string(device.hw_address().await.as_ref().unwrap())
|
if HwAddress::from_str(device.hw_address().await.as_ref().unwrap())
|
||||||
== Some(hw_address)
|
== Some(hw_address)
|
||||||
{
|
{
|
||||||
is_there_device = true;
|
is_there_device = true;
|
||||||
|
|
@ -288,7 +286,7 @@ async fn start_listening(
|
||||||
_ => {
|
_ => {
|
||||||
return State::Finished;
|
return State::Finished;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
State::Waiting(conn, rx)
|
State::Waiting(conn, rx)
|
||||||
}
|
}
|
||||||
|
|
@ -494,7 +492,7 @@ impl NetworkManagerState {
|
||||||
ap.network_type,
|
ap.network_type,
|
||||||
ap.working,
|
ap.working,
|
||||||
ap.state
|
ap.state
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
self_.active_conns = active_conns;
|
self_.active_conns = active_conns;
|
||||||
self_.known_access_points = known_access_points;
|
self_.known_access_points = known_access_points;
|
||||||
|
|
@ -510,7 +508,7 @@ impl NetworkManagerState {
|
||||||
self.wireless_access_points = Vec::new();
|
self.wireless_access_points = Vec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn connect_wifi<'a>(
|
async fn connect_wifi(
|
||||||
&self,
|
&self,
|
||||||
conn: &Connection,
|
conn: &Connection,
|
||||||
ssid: &str,
|
ssid: &str,
|
||||||
|
|
@ -587,7 +585,7 @@ impl NetworkManagerState {
|
||||||
.hw_address()
|
.hw_address()
|
||||||
.await
|
.await
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|device_address| HwAddress::from_string(&device_address))
|
.and_then(|device_address| HwAddress::from_str(&device_address))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
if device_hw_address != hw_address {
|
if device_hw_address != hw_address {
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -631,8 +629,8 @@ impl NetworkManagerState {
|
||||||
let (_, active_conn) = nm
|
let (_, active_conn) = nm
|
||||||
.add_and_activate_connection(conn_settings, device.inner().path(), &ap.path)
|
.add_and_activate_connection(conn_settings, device.inner().path(), &ap.path)
|
||||||
.await?;
|
.await?;
|
||||||
let dummy = ActiveConnectionProxy::new(&conn, active_conn).await?;
|
let dummy = ActiveConnectionProxy::new(conn, active_conn).await?;
|
||||||
let active = ActiveConnectionProxy::builder(&conn)
|
let active = ActiveConnectionProxy::builder(conn)
|
||||||
.destination(dummy.inner().destination().to_owned())
|
.destination(dummy.inner().destination().to_owned())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.interface(dummy.inner().interface().to_owned())
|
.interface(dummy.inner().interface().to_owned())
|
||||||
|
|
@ -645,7 +643,7 @@ impl NetworkManagerState {
|
||||||
ActiveConnection::from(active)
|
ActiveConnection::from(active)
|
||||||
};
|
};
|
||||||
let mut changes = active_conn.receive_state_changed().await;
|
let mut changes = active_conn.receive_state_changed().await;
|
||||||
_ = tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
() = tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
||||||
let mut count = 5;
|
let mut count = 5;
|
||||||
loop {
|
loop {
|
||||||
let state = active_conn.state().await;
|
let state = active_conn.state().await;
|
||||||
|
|
@ -654,15 +652,14 @@ impl NetworkManagerState {
|
||||||
} else if let Ok(enums::ActiveConnectionState::Deactivated) = state {
|
} else if let Ok(enums::ActiveConnectionState::Deactivated) = state {
|
||||||
anyhow::bail!("Failed to activate connection");
|
anyhow::bail!("Failed to activate connection");
|
||||||
}
|
}
|
||||||
match tokio::time::timeout(Duration::from_secs(20), changes.next()).await {
|
if let Ok(Some(s)) =
|
||||||
Ok(Some(s)) => {
|
tokio::time::timeout(Duration::from_secs(20), changes.next()).await
|
||||||
let state = s.get().await.unwrap_or_default().into();
|
{
|
||||||
if matches!(state, enums::ActiveConnectionState::Activated) {
|
let state = s.get().await.unwrap_or_default().into();
|
||||||
return Ok(());
|
if matches!(state, enums::ActiveConnectionState::Activated) {
|
||||||
}
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
count -= 1;
|
count -= 1;
|
||||||
if count <= 0 {
|
if count <= 0 {
|
||||||
|
|
|
||||||
|
|
@ -125,12 +125,12 @@ impl cosmic::Application for Notifications {
|
||||||
core,
|
core,
|
||||||
config_helper: helper,
|
config_helper: helper,
|
||||||
config,
|
config,
|
||||||
icon_name: Default::default(),
|
icon_name: String::default(),
|
||||||
popup: None,
|
popup: None,
|
||||||
timeline: Default::default(),
|
timeline: Timeline::default(),
|
||||||
dbus_sender: Default::default(),
|
dbus_sender: Option::default(),
|
||||||
cards: Vec::new(),
|
cards: Vec::new(),
|
||||||
token_tx: Default::default(),
|
token_tx: Option::default(),
|
||||||
proxy: block_on(crate::subscriptions::notifications::get_proxy())
|
proxy: block_on(crate::subscriptions::notifications::get_proxy())
|
||||||
.expect("Failed to get proxy"),
|
.expect("Failed to get proxy"),
|
||||||
notifications_tx: None,
|
notifications_tx: None,
|
||||||
|
|
@ -290,7 +290,7 @@ impl cosmic::Application for Notifications {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::ClearAll(None) => {
|
Message::ClearAll(None) => {
|
||||||
for n in self.cards.drain(..).map(|n| n.1).flatten() {
|
for n in self.cards.drain(..).flat_map(|n| n.1) {
|
||||||
if let Some(tx) = &self.dbus_sender {
|
if let Some(tx) = &self.dbus_sender {
|
||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
|
@ -365,7 +365,7 @@ impl cosmic::Application for Notifications {
|
||||||
{
|
{
|
||||||
Some(ActionId::Default.to_string())
|
Some(ActionId::Default.to_string())
|
||||||
} else {
|
} else {
|
||||||
notification.actions.get(0).map(|a| a.0.to_string())
|
notification.actions.first().map(|a| a.0.to_string())
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(action) = maybe_action else {
|
let Some(action) = maybe_action else {
|
||||||
|
|
@ -392,12 +392,12 @@ impl cosmic::Application for Notifications {
|
||||||
cosmic::app::Action::Surface(a),
|
cosmic::app::Action::Surface(a),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
self.update_icon();
|
self.update_icon();
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
self.core
|
self.core
|
||||||
.applet
|
.applet
|
||||||
.icon_button(&self.icon_name)
|
.icon_button(&self.icon_name)
|
||||||
|
|
@ -405,7 +405,7 @@ impl cosmic::Application for Notifications {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: window::Id) -> Element<Message> {
|
fn view_window(&self, _id: window::Id) -> Element<'_, Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
@ -423,7 +423,7 @@ impl cosmic::Application for Notifications {
|
||||||
]);
|
]);
|
||||||
|
|
||||||
let notifications = if self.cards.is_empty() {
|
let notifications = if self.cards.is_empty() {
|
||||||
let no_notifications = String::from(fl!("no-notifications"));
|
let no_notifications = fl!("no-notifications");
|
||||||
row![
|
row![
|
||||||
container(
|
container(
|
||||||
column![
|
column![
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<O
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
} else {
|
} else {
|
||||||
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
};
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -101,10 +101,10 @@ pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<O
|
||||||
}
|
}
|
||||||
v = next_input => {
|
v = next_input => {
|
||||||
if let Some(Input::Activated(id, action)) = v {
|
if let Some(Input::Activated(id, action)) = v {
|
||||||
if let Err(err) = proxy.invoke_action(id, action.clone()).await {
|
if proxy.invoke_action(id, action.clone()).await.is_err() {
|
||||||
tracing::error!("Failed to invoke action {id} {action}");
|
tracing::error!("Failed to invoke action {id} {action}");
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("Invoked {action} for {id}")
|
tracing::error!("Invoked {action} for {id}");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("Channel closed, ending notifications subscription");
|
tracing::error!("Channel closed, ending notifications subscription");
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ impl cosmic::Application for Power {
|
||||||
core,
|
core,
|
||||||
icon_name: "system-shutdown-symbolic".to_string(),
|
icon_name: "system-shutdown-symbolic".to_string(),
|
||||||
subsurface_id: window::Id::unique(),
|
subsurface_id: window::Id::unique(),
|
||||||
popup: Default::default(),
|
popup: Option::default(),
|
||||||
},
|
},
|
||||||
Task::none(),
|
Task::none(),
|
||||||
)
|
)
|
||||||
|
|
@ -158,12 +158,12 @@ impl cosmic::Application for Power {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
a => return a.perform(),
|
a => return a.perform(),
|
||||||
};
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::Zbus(result) => {
|
Message::Zbus(result) => {
|
||||||
if let Err(e) = result {
|
if let Err(e) = result {
|
||||||
eprintln!("cosmic-applet-power ERROR: '{}'", e);
|
eprintln!("cosmic-applet-power ERROR: '{e}'");
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +181,7 @@ impl cosmic::Application for Power {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
self.core
|
self.core
|
||||||
.applet
|
.applet
|
||||||
.icon_button(&self.icon_name)
|
.icon_button(&self.icon_name)
|
||||||
|
|
@ -189,7 +189,7 @@ impl cosmic::Application for Power {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, id: window::Id) -> Element<Message> {
|
fn view_window(&self, id: window::Id) -> Element<'_, Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxs,
|
space_xxs,
|
||||||
space_s,
|
space_s,
|
||||||
|
|
@ -264,7 +264,7 @@ impl cosmic::Application for Power {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn power_buttons(name: &str, on_press: Message) -> button::Button<Message> {
|
fn power_buttons(name: &str, on_press: Message) -> button::Button<'_, Message> {
|
||||||
button::custom(
|
button::custom(
|
||||||
widget::container(text_icon(name, 40))
|
widget::container(text_icon(name, 40))
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
|
|
@ -340,16 +340,13 @@ async fn lock() -> zbus::Result<()> {
|
||||||
async fn log_out() -> zbus::Result<()> {
|
async fn log_out() -> zbus::Result<()> {
|
||||||
let session_type = std::env::var("XDG_CURRENT_DESKTOP").ok();
|
let session_type = std::env::var("XDG_CURRENT_DESKTOP").ok();
|
||||||
let connection = Connection::session().await?;
|
let connection = Connection::session().await?;
|
||||||
match session_type.as_ref().map(|s| s.trim()) {
|
if let Some("pop:GNOME") = session_type.as_ref().map(|s| s.trim()) {
|
||||||
Some("pop:GNOME") => {
|
let manager_proxy = SessionManagerProxy::new(&connection).await?;
|
||||||
let manager_proxy = SessionManagerProxy::new(&connection).await?;
|
manager_proxy.logout(0).await?;
|
||||||
manager_proxy.logout(0).await?;
|
} else {
|
||||||
}
|
|
||||||
// By default assume COSMIC
|
// By default assume COSMIC
|
||||||
_ => {
|
let cosmic_session = CosmicSessionProxy::new(&connection).await?;
|
||||||
let cosmic_session = CosmicSessionProxy::new(&connection).await?;
|
cosmic_session.exit().await?;
|
||||||
cosmic_session.exit().await?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,15 +65,13 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overflow_index(&self) -> Option<usize> {
|
fn overflow_index(&self) -> Option<usize> {
|
||||||
let Some(max_major_axis_len) = self.core.applet.suggested_bounds.as_ref().map(|c| {
|
let max_major_axis_len = self.core.applet.suggested_bounds.as_ref().map(|c| {
|
||||||
// if we have a configure for width and height, we're in a overflow popup
|
// if we have a configure for width and height, we're in a overflow popup
|
||||||
match self.core.applet.anchor {
|
match self.core.applet.anchor {
|
||||||
PanelAnchor::Top | PanelAnchor::Bottom => c.width as u32,
|
PanelAnchor::Top | PanelAnchor::Bottom => c.width as u32,
|
||||||
PanelAnchor::Left | PanelAnchor::Right => c.height as u32,
|
PanelAnchor::Left | PanelAnchor::Right => c.height as u32,
|
||||||
}
|
}
|
||||||
}) else {
|
})?;
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
let button_total_size =
|
let button_total_size =
|
||||||
self.core.applet.suggested_size(true).0 + self.core.applet.suggested_padding(true) * 2;
|
self.core.applet.suggested_size(true).0 + self.core.applet.suggested_padding(true) * 2;
|
||||||
|
|
@ -111,7 +109,7 @@ impl App {
|
||||||
});
|
});
|
||||||
let theme = self.core.system_theme();
|
let theme = self.core.system_theme();
|
||||||
let cosmic = theme.cosmic();
|
let cosmic = theme.cosmic();
|
||||||
let corners = cosmic.corner_radii.clone();
|
let corners = cosmic.corner_radii;
|
||||||
let pad = corners.radius_m[0];
|
let pad = corners.radius_m[0];
|
||||||
|
|
||||||
self.core
|
self.core
|
||||||
|
|
@ -211,12 +209,12 @@ impl cosmic::Application for App {
|
||||||
self.resize_window()
|
self.resize_window()
|
||||||
}
|
}
|
||||||
status_notifier_watcher::Event::Error(err) => {
|
status_notifier_watcher::Event::Error(err) => {
|
||||||
eprintln!("Status notifier error: {}", err);
|
eprintln!("Status notifier error: {err}");
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Msg::TogglePopup(id) => {
|
Msg::TogglePopup(id) => {
|
||||||
self.open_menu = if self.open_menu != Some(id) {
|
self.open_menu = if self.open_menu.is_none() {
|
||||||
Some(id)
|
Some(id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -232,15 +230,14 @@ impl cosmic::Application for App {
|
||||||
let i = self.menus.keys().position(|&i| i == id).unwrap();
|
let i = self.menus.keys().position(|&i| i == id).unwrap();
|
||||||
let (i, parent) = self
|
let (i, parent) = self
|
||||||
.overflow_index()
|
.overflow_index()
|
||||||
.clone()
|
|
||||||
.and_then(|overflow_i| {
|
.and_then(|overflow_i| {
|
||||||
if overflow_i <= i {
|
if overflow_i <= i {
|
||||||
Some(i - overflow_i).zip(self.overflow_popup.clone())
|
Some(i - overflow_i).zip(self.overflow_popup)
|
||||||
} else {
|
} else {
|
||||||
Some((i, self.core.main_window_id().unwrap()))
|
Some((i, self.core.main_window_id().unwrap()))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| (0, self.core.main_window_id().unwrap()));
|
.unwrap_or((0, self.core.main_window_id().unwrap()));
|
||||||
|
|
||||||
let mut popup_settings = self
|
let mut popup_settings = self
|
||||||
.core
|
.core
|
||||||
|
|
@ -315,15 +312,14 @@ impl cosmic::Application for App {
|
||||||
|
|
||||||
let (i, parent) = self
|
let (i, parent) = self
|
||||||
.overflow_index()
|
.overflow_index()
|
||||||
.clone()
|
|
||||||
.and_then(|overflow_i| {
|
.and_then(|overflow_i| {
|
||||||
if overflow_i <= i {
|
if overflow_i <= i {
|
||||||
Some(i - overflow_i).zip(self.overflow_popup.clone())
|
Some(i - overflow_i).zip(self.overflow_popup)
|
||||||
} else {
|
} else {
|
||||||
Some((i, self.core.main_window_id().unwrap()))
|
Some((i, self.core.main_window_id().unwrap()))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| (0, self.core.main_window_id().unwrap()));
|
.unwrap_or((0, self.core.main_window_id().unwrap()));
|
||||||
|
|
||||||
let mut popup_settings = self
|
let mut popup_settings = self
|
||||||
.core
|
.core
|
||||||
|
|
@ -384,8 +380,7 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.overflow_popup = Some(popup_id);
|
self.overflow_popup = Some(popup_id);
|
||||||
let mut cmds = Vec::new();
|
let cmds = vec![get_popup(popup_settings)];
|
||||||
cmds.push(get_popup(popup_settings));
|
|
||||||
return Task::batch(cmds);
|
return Task::batch(cmds);
|
||||||
} else {
|
} else {
|
||||||
return Task::none();
|
return Task::none();
|
||||||
|
|
@ -442,7 +437,7 @@ impl cosmic::Application for App {
|
||||||
|
|
||||||
subscriptions.push(status_notifier_watcher::subscription().map(Msg::StatusNotifier));
|
subscriptions.push(status_notifier_watcher::subscription().map(Msg::StatusNotifier));
|
||||||
|
|
||||||
for (id, menu) in self.menus.iter() {
|
for (id, menu) in &self.menus {
|
||||||
subscriptions.push(menu.subscription().with(*id).map(Msg::StatusMenu));
|
subscriptions.push(menu.subscription().with(*id).map(Msg::StatusMenu));
|
||||||
}
|
}
|
||||||
subscriptions.push(activation_token_subscription(0).map(Msg::Token));
|
subscriptions.push(activation_token_subscription(0).map(Msg::Token));
|
||||||
|
|
@ -513,7 +508,7 @@ impl cosmic::Application for App {
|
||||||
|
|
||||||
let theme = self.core.system_theme();
|
let theme = self.core.system_theme();
|
||||||
let cosmic = theme.cosmic();
|
let cosmic = theme.cosmic();
|
||||||
let corners = cosmic.corner_radii.clone();
|
let corners = cosmic.corner_radii;
|
||||||
let pad = corners.radius_m[0];
|
let pad = corners.radius_m[0];
|
||||||
match self.open_menu {
|
match self.open_menu {
|
||||||
Some(id) => match self.menus.get(&id) {
|
Some(id) => match self.menus.get(&id) {
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ impl State {
|
||||||
Ok(layout) => {
|
Ok(layout) => {
|
||||||
self.layout = Some(layout);
|
self.layout = Some(layout);
|
||||||
}
|
}
|
||||||
Err(err) => eprintln!("Error getting layout from icon: {}", err),
|
Err(err) => eprintln!("Error getting layout from icon: {err}"),
|
||||||
}
|
}
|
||||||
iced::Task::none()
|
iced::Task::none()
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +109,7 @@ impl State {
|
||||||
let _ = menu_proxy.event(id, "clicked", &0.into(), 0).await;
|
let _ = menu_proxy.event(id, "clicked", &0.into(), 0).await;
|
||||||
});
|
});
|
||||||
if is_submenu {
|
if is_submenu {
|
||||||
self.expanded = if self.expanded != Some(id) {
|
self.expanded = if self.expanded.is_none() {
|
||||||
Some(id)
|
Some(id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
@ -134,7 +134,7 @@ impl State {
|
||||||
self.icon_pixmap.as_ref()
|
self.icon_pixmap.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn popup_view(&self) -> cosmic::Element<Msg> {
|
pub fn popup_view(&self) -> cosmic::Element<'_, Msg> {
|
||||||
if let Some(layout) = self.layout.as_ref() {
|
if let Some(layout) = self.layout.as_ref() {
|
||||||
layout_view(layout, self.expanded)
|
layout_view(layout, self.expanded)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -165,7 +165,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_view(layout: &Layout, expanded: Option<i32>) -> cosmic::Element<Msg> {
|
fn layout_view(layout: &Layout, expanded: Option<i32>) -> cosmic::Element<'_, Msg> {
|
||||||
iced::widget::column(layout.children().iter().filter_map(|i| {
|
iced::widget::column(layout.children().iter().filter_map(|i| {
|
||||||
if !i.visible() {
|
if !i.visible() {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ impl StatusNotifierItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn icon_subscription(&self) -> iced::Subscription<IconUpdate> {
|
pub fn icon_subscription(&self) -> iced::Subscription<IconUpdate> {
|
||||||
fn icon_events<'a>(
|
fn icon_events(
|
||||||
item_proxy: StatusNotifierItemProxy<'static>,
|
item_proxy: StatusNotifierItemProxy<'static>,
|
||||||
) -> impl futures::Stream<Item = IconUpdate> + 'static {
|
) -> impl futures::Stream<Item = IconUpdate> + 'static {
|
||||||
async move {
|
async move {
|
||||||
|
|
@ -99,7 +99,7 @@ impl StatusNotifierItem {
|
||||||
format!("status-notifier-item-icon-{}", &self.name),
|
format!("status-notifier-item-icon-{}", &self.name),
|
||||||
async move {
|
async move {
|
||||||
let new_icon_stream = item_proxy.receive_new_icon().await.unwrap();
|
let new_icon_stream = item_proxy.receive_new_icon().await.unwrap();
|
||||||
futures::stream::once(async { () })
|
futures::stream::once(async {})
|
||||||
.chain(new_icon_stream.map(|_| ()))
|
.chain(new_icon_stream.map(|_| ()))
|
||||||
.flat_map(move |()| icon_events(item_proxy.clone()))
|
.flat_map(move |()| icon_events(item_proxy.clone()))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ pub async fn watch(connection: &zbus::Connection) -> zbus::Result<EventStream> {
|
||||||
|
|
||||||
let name = connection.unique_name().unwrap().as_str();
|
let name = connection.unique_name().unwrap().as_str();
|
||||||
if let Err(err) = watcher.register_status_notifier_host(name).await {
|
if let Err(err) = watcher.register_status_notifier_host(name).await {
|
||||||
eprintln!("Failed to register status notifier host: {}", err);
|
eprintln!("Failed to register status notifier host: {err}");
|
||||||
}
|
}
|
||||||
|
|
||||||
let connection_clone = connection.clone();
|
let connection_clone = connection.clone();
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,10 @@ pub fn subscription() -> iced::Subscription<Event> {
|
||||||
}
|
}
|
||||||
Err(err) => Some((Event::Error(err.to_string()), State::Failed)),
|
Err(err) => Some((Event::Error(err.to_string()), State::Failed)),
|
||||||
},
|
},
|
||||||
State::Connected(mut stream) => match stream.next().await {
|
State::Connected(mut stream) => stream
|
||||||
Some(event) => Some((event, State::Connected(stream))),
|
.next()
|
||||||
None => None,
|
.await
|
||||||
},
|
.map(|event| (event, State::Connected(stream))),
|
||||||
State::Failed => None,
|
State::Failed => None,
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ impl StatusNotifierWatcher {
|
||||||
) {
|
) {
|
||||||
let sender = hdr.sender().unwrap();
|
let sender = hdr.sender().unwrap();
|
||||||
let service = if service.starts_with('/') {
|
let service = if service.starts_with('/') {
|
||||||
format!("{}{}", sender, service)
|
format!("{sender}{service}")
|
||||||
} else {
|
} else {
|
||||||
service.to_string()
|
service.to_string()
|
||||||
};
|
};
|
||||||
|
|
@ -95,7 +95,7 @@ pub async fn create_service(connection: &zbus::Connection) -> zbus::Result<()> {
|
||||||
|
|
||||||
let flags = RequestNameFlags::AllowReplacement.into();
|
let flags = RequestNameFlags::AllowReplacement.into();
|
||||||
if dbus_proxy.request_name(NAME.as_ref(), flags).await? == RequestNameReply::InQueue {
|
if dbus_proxy.request_name(NAME.as_ref(), flags).await? == RequestNameReply::InQueue {
|
||||||
eprintln!("Bus name '{}' already owned", NAME);
|
eprintln!("Bus name '{NAME}' already owned");
|
||||||
}
|
}
|
||||||
|
|
||||||
let connection = connection.clone();
|
let connection = connection.clone();
|
||||||
|
|
@ -103,18 +103,15 @@ pub async fn create_service(connection: &zbus::Connection) -> zbus::Result<()> {
|
||||||
let mut have_bus_name = false;
|
let mut have_bus_name = false;
|
||||||
let unique_name = connection.unique_name().map(|x| x.as_ref());
|
let unique_name = connection.unique_name().map(|x| x.as_ref());
|
||||||
while let Some(evt) = name_owner_changed_stream.next().await {
|
while let Some(evt) = name_owner_changed_stream.next().await {
|
||||||
let args = match evt.args() {
|
let Ok(args) = evt.args() else {
|
||||||
Ok(args) => args,
|
continue;
|
||||||
Err(_) => {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
if args.name.as_ref() == NAME {
|
if args.name.as_ref() == NAME {
|
||||||
if args.new_owner.as_ref() == unique_name.as_ref() {
|
if args.new_owner.as_ref() == unique_name.as_ref() {
|
||||||
eprintln!("Acquired bus name: {}", NAME);
|
eprintln!("Acquired bus name: {NAME}");
|
||||||
have_bus_name = true;
|
have_bus_name = true;
|
||||||
} else if have_bus_name {
|
} else if have_bus_name {
|
||||||
eprintln!("Lost bus name: {}", NAME);
|
eprintln!("Lost bus name: {NAME}");
|
||||||
have_bus_name = false;
|
have_bus_name = false;
|
||||||
}
|
}
|
||||||
} else if let BusName::Unique(name) = &args.name {
|
} else if let BusName::Unique(name) = &args.name {
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ pub fn spawn_workspaces(tx: mpsc::Sender<TilingState>) -> SyncSender<AppRequest>
|
||||||
};
|
};
|
||||||
let loop_handle = event_loop.handle();
|
let loop_handle = event_loop.handle();
|
||||||
loop_handle
|
loop_handle
|
||||||
.insert_source(workspaces_rx, |e, _, state| match e {
|
.insert_source(workspaces_rx, |e, (), state| match e {
|
||||||
Event::Msg(AppRequest::TilingState(autotile)) => {
|
Event::Msg(AppRequest::TilingState(autotile)) => {
|
||||||
if let Some(w) = state.workspace_state.workspace_groups().find_map(|g| {
|
if let Some(w) = state.workspace_state.workspace_groups().find_map(|g| {
|
||||||
if let Some(o) = state.expected_output.as_ref() {
|
if let Some(o) = state.expected_output.as_ref() {
|
||||||
|
|
@ -183,9 +183,10 @@ impl State {
|
||||||
.filter_map(|handle| self.workspace_state.workspace_info(handle))
|
.filter_map(|handle| self.workspace_state.workspace_info(handle))
|
||||||
.find_map(|w| {
|
.find_map(|w| {
|
||||||
if w.state.contains(ext_workspace_handle_v1::State::Active) {
|
if w.state.contains(ext_workspace_handle_v1::State::Active) {
|
||||||
w.tiling.and_then(|e| match e {
|
w.tiling.and_then(|e| {
|
||||||
WEnum::Value(v) => Some(v),
|
if let WEnum::Value(v) = e {
|
||||||
_ => {
|
Some(v)
|
||||||
|
} else {
|
||||||
error!("No tiling state for the workspace");
|
error!("No tiling state for the workspace");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
@ -273,7 +274,7 @@ impl ToplevelInfoHandler for State {
|
||||||
) {
|
) {
|
||||||
let Some(w) = self
|
let Some(w) = self
|
||||||
.toplevel_info_state
|
.toplevel_info_state
|
||||||
.info(&toplevel)
|
.info(toplevel)
|
||||||
.map(|t| t.workspace.clone())
|
.map(|t| t.workspace.clone())
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -289,7 +290,7 @@ impl ToplevelInfoHandler for State {
|
||||||
) {
|
) {
|
||||||
let Some(w) = self
|
let Some(w) = self
|
||||||
.toplevel_info_state
|
.toplevel_info_state
|
||||||
.info(&toplevel)
|
.info(toplevel)
|
||||||
.map(|t| t.workspace.clone())
|
.map(|t| t.workspace.clone())
|
||||||
else {
|
else {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,6 @@ impl WorkspacesWatcher {
|
||||||
pub fn new() -> anyhow::Result<Self> {
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
let (tx, rx) = mpsc::channel(20);
|
let (tx, rx) = mpsc::channel(20);
|
||||||
let tx = wayland::spawn_workspaces(tx);
|
let tx = wayland::spawn_workspaces(tx);
|
||||||
Ok(Self { tx, rx })
|
Ok(Self { rx, tx })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ impl cosmic::Application for Window {
|
||||||
let window = Self {
|
let window = Self {
|
||||||
core,
|
core,
|
||||||
popup: None,
|
popup: None,
|
||||||
timeline: Default::default(),
|
timeline: Timeline::default(),
|
||||||
autotiled: config.autotile,
|
autotiled: config.autotile,
|
||||||
config,
|
config,
|
||||||
config_helper,
|
config_helper,
|
||||||
|
|
@ -202,7 +202,7 @@ impl cosmic::Application for Window {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = tx.send(AppRequest::TilingState(state)) {
|
if let Err(err) = tx.send(AppRequest::TilingState(state)) {
|
||||||
error!("Failed to send the tiling state update. {err:?}")
|
error!("Failed to send the tiling state update. {err:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -223,16 +223,14 @@ impl cosmic::Application for Window {
|
||||||
.activate_position(if c.autotile { 0 } else { 1 });
|
.activate_position(if c.autotile { 0 } else { 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.active_hint != self.config.active_hint {
|
if c.active_hint != self.config.active_hint && self.popup.is_some() {
|
||||||
if self.popup.is_some() {
|
self.timeline
|
||||||
self.timeline
|
.set_chain(if c.active_hint {
|
||||||
.set_chain(if c.active_hint {
|
cosmic_time::chain::Toggler::on(self.active_hint.clone(), 1.0)
|
||||||
cosmic_time::chain::Toggler::on(self.active_hint.clone(), 1.0)
|
} else {
|
||||||
} else {
|
cosmic_time::chain::Toggler::off(self.active_hint.clone(), 1.0)
|
||||||
cosmic_time::chain::Toggler::off(self.active_hint.clone(), 1.0)
|
})
|
||||||
})
|
.start();
|
||||||
.start();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.config = *c;
|
self.config = *c;
|
||||||
|
|
@ -252,7 +250,7 @@ impl cosmic::Application for Window {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = tx.send(AppRequest::DefaultBehavior(state)) {
|
if let Err(err) = tx.send(AppRequest::DefaultBehavior(state)) {
|
||||||
error!("Failed to send the tiling state update. {err:?}")
|
error!("Failed to send the tiling state update. {err:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -276,7 +274,7 @@ impl cosmic::Application for Window {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Self::Message> {
|
fn view(&self) -> Element<'_, Self::Message> {
|
||||||
self.core
|
self.core
|
||||||
.applet
|
.applet
|
||||||
.icon_button(if self.autotiled { ON } else { OFF })
|
.icon_button(if self.autotiled { ON } else { OFF })
|
||||||
|
|
@ -284,7 +282,7 @@ impl cosmic::Application for Window {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: Id) -> Element<Self::Message> {
|
fn view_window(&self, _id: Id) -> Element<'_, Self::Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxxs,
|
space_xxxs,
|
||||||
space_xxs,
|
space_xxs,
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ impl Window {
|
||||||
calendar
|
calendar
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vertical_layout(&self) -> Element<Message> {
|
fn vertical_layout(&self) -> Element<'_, Message> {
|
||||||
let mut elements = Vec::new();
|
let mut elements = Vec::new();
|
||||||
let date = self.now.naive_local();
|
let date = self.now.naive_local();
|
||||||
let datetime = self.create_datetime(&date);
|
let datetime = self.create_datetime(&date);
|
||||||
|
|
@ -216,7 +216,7 @@ impl Window {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn horizontal_layout(&self) -> Element<Message> {
|
fn horizontal_layout(&self) -> Element<'_, Message> {
|
||||||
let datetime = self.create_datetime(&self.now);
|
let datetime = self.create_datetime(&self.now);
|
||||||
let mut prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
let mut prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
||||||
prefs.hour_cycle = Some(if self.config.military_time {
|
prefs.hour_cycle = Some(if self.config.military_time {
|
||||||
|
|
@ -500,10 +500,10 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Tick => {
|
Message::Tick => {
|
||||||
self.now = self
|
self.now = self.timezone.map_or_else(
|
||||||
.timezone
|
|| chrono::Local::now().into(),
|
||||||
.map(|tz| chrono::Local::now().with_timezone(&tz).fixed_offset())
|
|tz| chrono::Local::now().with_timezone(&tz).fixed_offset(),
|
||||||
.unwrap_or_else(|| chrono::Local::now().into());
|
);
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::Rectangle(u) => {
|
Message::Rectangle(u) => {
|
||||||
|
|
@ -523,8 +523,8 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::SelectDay(_day) => {
|
Message::SelectDay(day) => {
|
||||||
if let Some(date) = self.date_selected.with_day(_day) {
|
if let Some(date) = self.date_selected.with_day(day) {
|
||||||
self.date_selected = date;
|
self.date_selected = date;
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("invalid naivedate");
|
tracing::error!("invalid naivedate");
|
||||||
|
|
@ -562,7 +562,7 @@ impl cosmic::Application for Window {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("Wayland tx is None");
|
tracing::error!("Wayland tx is None");
|
||||||
};
|
}
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
Message::Token(u) => {
|
Message::Token(u) => {
|
||||||
|
|
@ -616,7 +616,7 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
let horizontal = matches!(
|
let horizontal = matches!(
|
||||||
self.core.applet.anchor,
|
self.core.applet.anchor,
|
||||||
PanelAnchor::Top | PanelAnchor::Bottom
|
PanelAnchor::Top | PanelAnchor::Bottom
|
||||||
|
|
@ -646,7 +646,7 @@ impl cosmic::Application for Window {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view_window(&self, _id: window::Id) -> Element<Message> {
|
fn view_window(&self, _id: window::Id) -> Element<'_, Message> {
|
||||||
let Spacing {
|
let Spacing {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,7 @@ impl cosmic::Application for IcedWorkspacesApplet {
|
||||||
},
|
},
|
||||||
core,
|
core,
|
||||||
workspaces: Vec::new(),
|
workspaces: Vec::new(),
|
||||||
workspace_tx: Default::default(),
|
workspace_tx: Option::default(),
|
||||||
scroll: 0.0,
|
scroll: 0.0,
|
||||||
next_scroll: None,
|
next_scroll: None,
|
||||||
last_scroll: Instant::now(),
|
last_scroll: Instant::now(),
|
||||||
|
|
@ -211,7 +211,7 @@ impl cosmic::Application for IcedWorkspacesApplet {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> Element<Message> {
|
fn view(&self) -> Element<'_, Message> {
|
||||||
if self.workspaces.is_empty() {
|
if self.workspaces.is_empty() {
|
||||||
return row![].padding(8).into();
|
return row![].padding(8).into();
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +224,7 @@ impl cosmic::Application for IcedWorkspacesApplet {
|
||||||
let suggested_window_size = self.core.applet.suggested_window_size();
|
let suggested_window_size = self.core.applet.suggested_window_size();
|
||||||
let popup_index = self.popup_index().unwrap_or(self.workspaces.len());
|
let popup_index = self.popup_index().unwrap_or(self.workspaces.len());
|
||||||
|
|
||||||
let buttons = self.workspaces[..popup_index].iter().filter_map(|w| {
|
let buttons = self.workspaces[..popup_index].iter().map(|w| {
|
||||||
let content = self.core.applet.text(&w.name).font(cosmic::font::bold());
|
let content = self.core.applet.text(&w.name).font(cosmic::font::bold());
|
||||||
|
|
||||||
let (width, height) = if self.core.applet.is_horizontal() {
|
let (width, height) = if self.core.applet.is_horizontal() {
|
||||||
|
|
@ -258,79 +258,73 @@ impl cosmic::Application for IcedWorkspacesApplet {
|
||||||
)
|
)
|
||||||
.padding(0);
|
.padding(0);
|
||||||
|
|
||||||
Some(
|
btn.class(
|
||||||
btn.class(
|
if w.state.contains(ext_workspace_handle_v1::State::Active) {
|
||||||
if w.state.contains(ext_workspace_handle_v1::State::Active) {
|
cosmic::theme::iced::Button::Primary
|
||||||
cosmic::theme::iced::Button::Primary
|
} else if w.state.contains(ext_workspace_handle_v1::State::Urgent) {
|
||||||
} else if w.state.contains(ext_workspace_handle_v1::State::Urgent) {
|
let appearance = |theme: &Theme| {
|
||||||
let appearance = |theme: &Theme| {
|
let cosmic = theme.cosmic();
|
||||||
let cosmic = theme.cosmic();
|
button::Style {
|
||||||
button::Style {
|
background: Some(Background::Color(cosmic.palette.neutral_3.into())),
|
||||||
|
border: Border {
|
||||||
|
radius: cosmic.radius_xl().into(),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
border_radius: theme.cosmic().radius_xl().into(),
|
||||||
|
text_color: theme.cosmic().destructive_button.base.into(),
|
||||||
|
..button::Style::default()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cosmic::theme::iced::Button::Custom(Box::new(
|
||||||
|
move |theme, status| match status {
|
||||||
|
button::Status::Active => appearance(theme),
|
||||||
|
button::Status::Hovered => button::Style {
|
||||||
background: Some(Background::Color(
|
background: Some(Background::Color(
|
||||||
cosmic.palette.neutral_3.into(),
|
theme.current_container().component.hover.into(),
|
||||||
)),
|
)),
|
||||||
border: Border {
|
border: Border {
|
||||||
radius: cosmic.radius_xl().into(),
|
radius: theme.cosmic().radius_xl().into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
border_radius: theme.cosmic().radius_xl().into(),
|
..appearance(theme)
|
||||||
text_color: theme.cosmic().destructive_button.base.into(),
|
},
|
||||||
..button::Style::default()
|
button::Status::Pressed => appearance(theme),
|
||||||
}
|
button::Status::Disabled => appearance(theme),
|
||||||
};
|
},
|
||||||
cosmic::theme::iced::Button::Custom(Box::new(move |theme, status| {
|
))
|
||||||
match status {
|
} else {
|
||||||
button::Status::Active => appearance(theme),
|
let appearance = |theme: &Theme| {
|
||||||
button::Status::Hovered => button::Style {
|
let cosmic = theme.cosmic();
|
||||||
background: Some(Background::Color(
|
button::Style {
|
||||||
theme.current_container().component.hover.into(),
|
background: None,
|
||||||
)),
|
border: Border {
|
||||||
border: Border {
|
radius: cosmic.radius_xl().into(),
|
||||||
radius: theme.cosmic().radius_xl().into(),
|
..Default::default()
|
||||||
..Default::default()
|
},
|
||||||
},
|
border_radius: cosmic.radius_xl().into(),
|
||||||
..appearance(theme)
|
text_color: theme.current_container().component.on.into(),
|
||||||
},
|
..button::Style::default()
|
||||||
button::Status::Pressed => appearance(theme),
|
}
|
||||||
button::Status::Disabled => appearance(theme),
|
};
|
||||||
}
|
cosmic::theme::iced::Button::Custom(Box::new(
|
||||||
}))
|
move |theme, status| match status {
|
||||||
} else {
|
button::Status::Active => appearance(theme),
|
||||||
let appearance = |theme: &Theme| {
|
button::Status::Hovered => button::Style {
|
||||||
let cosmic = theme.cosmic();
|
background: Some(Background::Color(
|
||||||
button::Style {
|
theme.current_container().component.hover.into(),
|
||||||
background: None,
|
)),
|
||||||
border: Border {
|
border: Border {
|
||||||
radius: cosmic.radius_xl().into(),
|
radius: theme.cosmic().radius_xl().into(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
border_radius: cosmic.radius_xl().into(),
|
..appearance(theme)
|
||||||
text_color: theme.current_container().component.on.into(),
|
},
|
||||||
..button::Style::default()
|
button::Status::Pressed | button::Status::Disabled => appearance(theme),
|
||||||
}
|
},
|
||||||
};
|
))
|
||||||
cosmic::theme::iced::Button::Custom(Box::new(move |theme, status| {
|
},
|
||||||
match status {
|
|
||||||
button::Status::Active => appearance(theme),
|
|
||||||
button::Status::Hovered => button::Style {
|
|
||||||
background: Some(Background::Color(
|
|
||||||
theme.current_container().component.hover.into(),
|
|
||||||
)),
|
|
||||||
border: Border {
|
|
||||||
radius: theme.cosmic().radius_xl().into(),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
..appearance(theme)
|
|
||||||
},
|
|
||||||
button::Status::Pressed | button::Status::Disabled => {
|
|
||||||
appearance(theme)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
)
|
)
|
||||||
|
.into()
|
||||||
});
|
});
|
||||||
// TODO if there is a popup_index, create a button with a popup for the remaining workspaces
|
// TODO if there is a popup_index, create a button with a popup for the remaining workspaces
|
||||||
// Should it appear on hover or on click?
|
// Should it appear on hover or on click?
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,6 @@ pub fn localize() {
|
||||||
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
let requested_languages = i18n_embed::DesktopLanguageRequester::requested_languages();
|
||||||
|
|
||||||
if let Err(error) = localizer.select(&requested_languages) {
|
if let Err(error) = localizer.select(&requested_languages) {
|
||||||
eprintln!("Error while loading language for App List {}", error);
|
eprintln!("Error while loading language for App List {error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ pub fn spawn_workspaces(tx: mpsc::Sender<Vec<Workspace>>) -> SyncSender<Workspac
|
||||||
};
|
};
|
||||||
let loop_handle = event_loop.handle();
|
let loop_handle = event_loop.handle();
|
||||||
loop_handle
|
loop_handle
|
||||||
.insert_source(workspaces_rx, |e, _, state| match e {
|
.insert_source(workspaces_rx, |e, (), state| match e {
|
||||||
Event::Msg(WorkspaceEvent::Activate(handle)) => {
|
Event::Msg(WorkspaceEvent::Activate(handle)) => {
|
||||||
handle.activate();
|
handle.activate();
|
||||||
state
|
state
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,6 @@ impl WorkspacesWatcher {
|
||||||
pub fn new() -> anyhow::Result<Self> {
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
let (tx, rx) = mpsc::channel(20);
|
let (tx, rx) = mpsc::channel(20);
|
||||||
let tx = wayland::spawn_workspaces(tx);
|
let tx = wayland::spawn_workspaces(tx);
|
||||||
Ok(Self { tx, rx })
|
Ok(Self { rx, tx })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ fn main() -> cosmic::iced::Result {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
let start = applet.rfind('/').map(|v| v + 1).unwrap_or(0);
|
let start = applet.rfind('/').map_or(0, |v| v + 1);
|
||||||
let cmd = &applet.as_str()[start..];
|
let cmd = &applet.as_str()[start..];
|
||||||
|
|
||||||
tracing::info!("Starting `{cmd}` with version {VERSION}");
|
tracing::info!("Starting `{cmd}` with version {VERSION}");
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ impl cosmic::Application for Button {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self) -> cosmic::Element<Msg> {
|
fn view(&self) -> cosmic::Element<'_, Msg> {
|
||||||
// currently, panel being anchored to the left or right is a hard
|
// currently, panel being anchored to the left or right is a hard
|
||||||
// override for icon, later if text is updated to wrap, we may
|
// override for icon, later if text is updated to wrap, we may
|
||||||
// use Override::Text to override this behavior
|
// use Override::Text to override this behavior
|
||||||
|
|
@ -181,15 +181,15 @@ pub fn run() -> iced::Result {
|
||||||
if let Ok(bytes) = fs::read_to_string(&path) {
|
if let Ok(bytes) = fs::read_to_string(&path) {
|
||||||
if let Ok(entry) = DesktopEntry::from_str(&path, &bytes, Some(&locales)) {
|
if let Ok(entry) = DesktopEntry::from_str(&path, &bytes, Some(&locales)) {
|
||||||
desktop = Some(Desktop {
|
desktop = Some(Desktop {
|
||||||
name: entry
|
name: entry.name(&locales).map_or_else(
|
||||||
.name(&locales)
|
|| panic!("Desktop file '{filename}' doesn't have `Name`"),
|
||||||
.map(|x| x.to_string())
|
|x| x.to_string(),
|
||||||
.unwrap_or_else(|| panic!("Desktop file '{filename}' doesn't have `Name`")),
|
),
|
||||||
icon: entry.icon().map(|x| x.to_string()),
|
icon: entry.icon().map(|x| x.to_string()),
|
||||||
exec: entry
|
exec: entry.exec().map_or_else(
|
||||||
.exec()
|
|| panic!("Desktop file '{filename}' doesn't have `Exec`"),
|
||||||
.map(|x| x.to_string())
|
|x| x.to_string(),
|
||||||
.unwrap_or_else(|| panic!("Desktop file '{filename}' doesn't have `Exec`")),
|
),
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue