perf: refactor to reduce memory allocations and cpu work
This commit is contained in:
parent
0c3e3c8629
commit
dd0158d8f0
24 changed files with 234 additions and 242 deletions
|
|
@ -53,7 +53,6 @@ use cosmic_app_list_config::{APP_ID, AppListConfig};
|
||||||
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
|
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
|
||||||
use futures::future::pending;
|
use futures::future::pending;
|
||||||
use iced::{Alignment, Background, Length};
|
use iced::{Alignment, Background, Length};
|
||||||
use itertools::Itertools;
|
|
||||||
use std::{borrow::Cow, collections::HashMap, path::PathBuf, rc::Rc, str::FromStr, time::Duration};
|
use std::{borrow::Cow, collections::HashMap, path::PathBuf, rc::Rc, str::FromStr, time::Duration};
|
||||||
use switcheroo_control::Gpu;
|
use switcheroo_control::Gpu;
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
@ -177,31 +176,24 @@ impl DockItem {
|
||||||
.width(app_icon.icon_size.into())
|
.width(app_icon.icon_size.into())
|
||||||
.height(app_icon.icon_size.into());
|
.height(app_icon.icon_size.into());
|
||||||
|
|
||||||
let dots = if toplevels.is_empty() {
|
let dot_constructor = || {
|
||||||
(0..1)
|
let space = if toplevels.len() <= 1 {
|
||||||
.map(|_| {
|
vertical_space().height(Length::Fixed(0.0))
|
||||||
container(vertical_space().height(Length::Fixed(0.0)))
|
} else {
|
||||||
.padding(app_icon.dot_radius)
|
match applet.anchor {
|
||||||
.into()
|
PanelAnchor::Left | PanelAnchor::Right => {
|
||||||
})
|
vertical_space().height(app_icon.bar_size)
|
||||||
.collect_vec()
|
}
|
||||||
} else {
|
PanelAnchor::Top | PanelAnchor::Bottom => {
|
||||||
(0..1)
|
horizontal_space().width(app_icon.bar_size)
|
||||||
.map(|_| {
|
}
|
||||||
container(if toplevels.len() == 1 {
|
}
|
||||||
vertical_space().height(Length::Fixed(0.0))
|
};
|
||||||
} else {
|
let mut container = container(space).padding(app_icon.dot_radius);
|
||||||
match applet.anchor {
|
|
||||||
PanelAnchor::Left | PanelAnchor::Right => {
|
if !toplevels.is_empty() {
|
||||||
vertical_space().height(app_icon.bar_size)
|
container =
|
||||||
}
|
container.class(theme::style::Container::Custom(Box::new(move |theme| {
|
||||||
PanelAnchor::Top | PanelAnchor::Bottom => {
|
|
||||||
horizontal_space().width(app_icon.bar_size)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.padding(app_icon.dot_radius)
|
|
||||||
.class(theme::style::Container::Custom(Box::new(move |theme| {
|
|
||||||
container::Style {
|
container::Style {
|
||||||
text_color: Some(Color::TRANSPARENT),
|
text_color: Some(Color::TRANSPARENT),
|
||||||
background: if is_focused {
|
background: if is_focused {
|
||||||
|
|
@ -218,34 +210,35 @@ impl DockItem {
|
||||||
icon_color: Some(Color::TRANSPARENT),
|
icon_color: Some(Color::TRANSPARENT),
|
||||||
}
|
}
|
||||||
})))
|
})))
|
||||||
.into()
|
}
|
||||||
})
|
container.into()
|
||||||
.collect_vec()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let dots = std::iter::repeat_with(dot_constructor).take(2);
|
||||||
|
|
||||||
let icon_wrapper: Element<_> = match applet.anchor {
|
let icon_wrapper: Element<_> = match applet.anchor {
|
||||||
PanelAnchor::Left => row(vec![
|
PanelAnchor::Left => row([
|
||||||
column(dots).into(),
|
column(dots).into(),
|
||||||
horizontal_space().width(Length::Fixed(1.0)).into(),
|
horizontal_space().width(Length::Fixed(1.0)).into(),
|
||||||
cosmic_icon.clone().into(),
|
cosmic_icon.clone().into(),
|
||||||
])
|
])
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.into(),
|
.into(),
|
||||||
PanelAnchor::Right => row(vec![
|
PanelAnchor::Right => row([
|
||||||
cosmic_icon.clone().into(),
|
cosmic_icon.clone().into(),
|
||||||
horizontal_space().width(Length::Fixed(1.0)).into(),
|
horizontal_space().width(Length::Fixed(1.0)).into(),
|
||||||
column(dots).into(),
|
column(dots).into(),
|
||||||
])
|
])
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.into(),
|
.into(),
|
||||||
PanelAnchor::Top => column(vec![
|
PanelAnchor::Top => column([
|
||||||
row(dots).into(),
|
row(dots).into(),
|
||||||
vertical_space().height(Length::Fixed(1.0)).into(),
|
vertical_space().height(Length::Fixed(1.0)).into(),
|
||||||
cosmic_icon.clone().into(),
|
cosmic_icon.clone().into(),
|
||||||
])
|
])
|
||||||
.align_x(Alignment::Center)
|
.align_x(Alignment::Center)
|
||||||
.into(),
|
.into(),
|
||||||
PanelAnchor::Bottom => column(vec![
|
PanelAnchor::Bottom => column([
|
||||||
cosmic_icon.clone().into(),
|
cosmic_icon.clone().into(),
|
||||||
vertical_space().height(Length::Fixed(1.0)).into(),
|
vertical_space().height(Length::Fixed(1.0)).into(),
|
||||||
row(dots).into(),
|
row(dots).into(),
|
||||||
|
|
@ -470,7 +463,7 @@ where
|
||||||
img.img.clone(),
|
img.img.clone(),
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
Image::new(Handle::from_rgba(1, 1, vec![0, 0, 0, 255])).into()
|
Image::new(Handle::from_rgba(1, 1, [0u8, 0u8, 0u8, 255u8].as_slice())).into()
|
||||||
})
|
})
|
||||||
.class(Container::Custom(Box::new(move |theme| {
|
.class(Container::Custom(Box::new(move |theme| {
|
||||||
container::Style {
|
container::Style {
|
||||||
|
|
@ -590,7 +583,7 @@ fn find_desktop_entries<'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).map_or_else(
|
fde::find_app_by_id(desktop_entries, unicase_fav).map_or_else(
|
||||||
|| fde::DesktopEntry::from_appid(fav.clone()).clone(),
|
|| fde::DesktopEntry::from_appid(fav.clone()),
|
||||||
ToOwned::to_owned,
|
ToOwned::to_owned,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
@ -612,7 +605,7 @@ impl CosmicAppList {
|
||||||
.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: Vec::new(),
|
toplevels: Vec::new(),
|
||||||
desktop_info: e.clone(),
|
desktop_info: e,
|
||||||
original_app_id: original_id.clone(),
|
original_app_id: original_id.clone(),
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
@ -673,7 +666,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
} else {
|
} else {
|
||||||
self.overflow_active_popup = None;
|
self.overflow_active_popup = None;
|
||||||
self.overflow_favorites_popup = None;
|
self.overflow_favorites_popup = None;
|
||||||
return Task::batch(vec![destroy_popup(popup_id), destroy_popup(parent)]);
|
return Task::batch([destroy_popup(popup_id), destroy_popup(parent)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(toplevel_group) = self
|
if let Some(toplevel_group) = self
|
||||||
|
|
@ -733,7 +726,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
} else {
|
} else {
|
||||||
self.overflow_active_popup = None;
|
self.overflow_active_popup = None;
|
||||||
self.overflow_favorites_popup = None;
|
self.overflow_favorites_popup = None;
|
||||||
return Task::batch(vec![destroy_popup(popup_id), destroy_popup(parent)]);
|
return Task::batch([destroy_popup(popup_id), destroy_popup(parent)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(toplevel_group) = self
|
if let Some(toplevel_group) = self
|
||||||
|
|
@ -1490,7 +1483,10 @@ impl cosmic::Application for CosmicAppList {
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
let favorites: Vec<_> = (&mut self.pinned_list.iter().rev())
|
let favorites: Vec<_> = self
|
||||||
|
.pinned_list
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
.filter(|f| {
|
.filter(|f| {
|
||||||
if favorite_to_remove > 0 && f.toplevels.is_empty() {
|
if favorite_to_remove > 0 && f.toplevels.is_empty() {
|
||||||
favorite_to_remove -= 1;
|
favorite_to_remove -= 1;
|
||||||
|
|
@ -1524,7 +1520,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
.desktop_info
|
.desktop_info
|
||||||
.full_name(&self.locales)
|
.full_name(&self.locales)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string(),
|
.into_owned(),
|
||||||
self.popup.is_some(),
|
self.popup.is_some(),
|
||||||
Message::Surface,
|
Message::Surface,
|
||||||
None,
|
None,
|
||||||
|
|
@ -1618,7 +1614,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
.desktop_info
|
.desktop_info
|
||||||
.full_name(&self.locales)
|
.full_name(&self.locales)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string(),
|
.into_owned(),
|
||||||
self.popup.is_some(),
|
self.popup.is_some(),
|
||||||
Message::Surface,
|
Message::Surface,
|
||||||
None,
|
None,
|
||||||
|
|
@ -1812,11 +1808,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
Message::Exec(exec.to_string(), None, desktop_info.terminal()),
|
Message::Exec(exec.to_string(), None, desktop_info.terminal()),
|
||||||
));
|
));
|
||||||
} else if let Some(gpus) = self.gpus.as_ref() {
|
} else if let Some(gpus) = self.gpus.as_ref() {
|
||||||
let default_idx = if desktop_info.prefers_non_default_gpu() {
|
let default_idx = preferred_gpu_idx(desktop_info, gpus.iter());
|
||||||
gpus.iter().position(|gpu| !gpu.default).unwrap_or(0)
|
|
||||||
} else {
|
|
||||||
gpus.iter().position(|gpu| gpu.default).unwrap_or(0)
|
|
||||||
};
|
|
||||||
for (i, gpu) in gpus.iter().enumerate() {
|
for (i, gpu) in gpus.iter().enumerate() {
|
||||||
content = content.push(
|
content = content.push(
|
||||||
menu_button(text::body(format!(
|
menu_button(text::body(format!(
|
||||||
|
|
@ -2037,7 +2029,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
.desktop_info
|
.desktop_info
|
||||||
.full_name(&self.locales)
|
.full_name(&self.locales)
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
.to_string(),
|
.into_owned(),
|
||||||
self.popup.is_some(),
|
self.popup.is_some(),
|
||||||
Message::Surface,
|
Message::Surface,
|
||||||
None,
|
None,
|
||||||
|
|
@ -2101,7 +2093,10 @@ impl cosmic::Application for CosmicAppList {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
let mut favorites_extra = Vec::with_capacity(favorite_to_remove);
|
let mut favorites_extra = Vec::with_capacity(favorite_to_remove);
|
||||||
let mut favorites: Vec<_> = (&mut self.pinned_list.iter().rev())
|
let mut favorites: Vec<_> = self
|
||||||
|
.pinned_list
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
.filter(|f| {
|
.filter(|f| {
|
||||||
if favorite_to_remove > 0 && f.toplevels.is_empty() {
|
if favorite_to_remove > 0 && f.toplevels.is_empty() {
|
||||||
favorite_to_remove -= 1;
|
favorite_to_remove -= 1;
|
||||||
|
|
@ -2190,7 +2185,7 @@ impl cosmic::Application for CosmicAppList {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
Subscription::batch(vec![
|
Subscription::batch([
|
||||||
wayland_subscription().map(Message::Wayland),
|
wayland_subscription().map(Message::Wayland),
|
||||||
listen_with(|e, _, id| match e {
|
listen_with(|e, _, id| match e {
|
||||||
cosmic::iced_runtime::core::Event::PlatformSpecific(
|
cosmic::iced_runtime::core::Event::PlatformSpecific(
|
||||||
|
|
@ -2299,9 +2294,9 @@ impl CosmicAppList {
|
||||||
if self.active_workspaces.is_empty() {
|
if self.active_workspaces.is_empty() {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
let current_output = self.core.applet.output_name.clone();
|
let current_output = self.core.applet.output_name.as_ref();
|
||||||
let mut focused_toplevels: Vec<ExtForeignToplevelHandleV1> = Vec::new();
|
let mut focused_toplevels: Vec<ExtForeignToplevelHandleV1> = Vec::new();
|
||||||
let active_workspaces = self.active_workspaces.clone();
|
let active_workspaces = &self.active_workspaces;
|
||||||
for toplevel_list in self.active_list.iter().chain(self.pinned_list.iter()) {
|
for toplevel_list in self.active_list.iter().chain(self.pinned_list.iter()) {
|
||||||
for (t_info, _) in &toplevel_list.toplevels {
|
for (t_info, _) in &toplevel_list.toplevels {
|
||||||
if t_info.state.contains(&State::Activated)
|
if t_info.state.contains(&State::Activated)
|
||||||
|
|
@ -2349,10 +2344,7 @@ impl CosmicAppList {
|
||||||
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).unwrap_or_default();
|
||||||
.name(&self.locales)
|
|
||||||
.map(|x| x.to_string())
|
|
||||||
.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
|
||||||
|
|
@ -2378,13 +2370,7 @@ impl CosmicAppList {
|
||||||
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 exec = desktop_info.exec()?;
|
let exec = desktop_info.exec()?;
|
||||||
|
|
||||||
let gpu_idx = gpus.map(|gpus| {
|
let gpu_idx = gpus.map(|gpus| preferred_gpu_idx(desktop_info, gpus.iter()));
|
||||||
if desktop_info.prefers_non_default_gpu() {
|
|
||||||
gpus.iter().position(|gpu| !gpu.default).unwrap_or(0)
|
|
||||||
} else {
|
|
||||||
gpus.iter().position(|gpu| gpu.default).unwrap_or(0)
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Some(Message::Exec(
|
Some(Message::Exec(
|
||||||
exec.to_string(),
|
exec.to_string(),
|
||||||
|
|
@ -2393,6 +2379,14 @@ fn launch_on_preferred_gpu(desktop_info: &DesktopEntry, gpus: Option<&[Gpu]>) ->
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn preferred_gpu_idx<'a, I>(desktop_info: &DesktopEntry, mut gpus: I) -> usize
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a Gpu>,
|
||||||
|
{
|
||||||
|
gpus.position(|gpu| gpu.default ^ desktop_info.prefers_non_default_gpu())
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct DndPathBuf(PathBuf);
|
pub struct DndPathBuf(PathBuf);
|
||||||
|
|
||||||
|
|
@ -2428,8 +2422,6 @@ impl AsMimeTypes for DndPathBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_bytes(&self, _mime_type: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
|
fn as_bytes(&self, _mime_type: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
|
||||||
Some(Cow::Owned(
|
Some(Cow::Owned(self.0.to_str()?.as_bytes().to_vec()))
|
||||||
self.0.clone().to_str()?.to_string().into_bytes(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,10 +87,7 @@ impl OutputHandler for AppData {
|
||||||
if let Some(info) = self.output_state.info(&output) {
|
if let Some(info) = self.output_state.info(&output) {
|
||||||
let _ = self
|
let _ = self
|
||||||
.tx
|
.tx
|
||||||
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Add(
|
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Add(output, info)));
|
||||||
output.clone(),
|
|
||||||
info.clone(),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,10 +100,7 @@ impl OutputHandler for AppData {
|
||||||
if let Some(info) = self.output_state.info(&output) {
|
if let Some(info) = self.output_state.info(&output) {
|
||||||
let _ = self
|
let _ = self
|
||||||
.tx
|
.tx
|
||||||
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Update(
|
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Update(output, info)));
|
||||||
output.clone(),
|
|
||||||
info.clone(),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +112,7 @@ impl OutputHandler for AppData {
|
||||||
) {
|
) {
|
||||||
let _ = self
|
let _ = self
|
||||||
.tx
|
.tx
|
||||||
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Remove(output.clone())));
|
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Remove(output)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,12 +130,12 @@ impl WorkspaceHandler for AppData {
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|handle| self.workspace_state.workspace_info(handle))
|
.filter_map(|handle| self.workspace_state.workspace_info(handle))
|
||||||
.find(|w| w.state.contains(WorkspaceUpdateState::Active))
|
.find(|w| w.state.contains(WorkspaceUpdateState::Active))
|
||||||
|
.map(|workspace| workspace.handle.clone())
|
||||||
})
|
})
|
||||||
.map(|workspace| workspace.handle.clone())
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let _ = self
|
let _ = self
|
||||||
.tx
|
.tx
|
||||||
.unbounded_send(WaylandUpdate::Workspace(active_workspaces.clone()));
|
.unbounded_send(WaylandUpdate::Workspace(active_workspaces));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -699,7 +693,6 @@ pub(crate) fn wayland_handler(
|
||||||
exit: false,
|
exit: false,
|
||||||
tx,
|
tx,
|
||||||
conn,
|
conn,
|
||||||
queue_handle: qh.clone(),
|
|
||||||
output_state: OutputState::new(&globals, &qh),
|
output_state: OutputState::new(&globals, &qh),
|
||||||
workspace_state: WorkspaceState::new(®istry_state, &qh),
|
workspace_state: WorkspaceState::new(®istry_state, &qh),
|
||||||
toplevel_info_state: ToplevelInfoState::new(®istry_state, &qh),
|
toplevel_info_state: ToplevelInfoState::new(®istry_state, &qh),
|
||||||
|
|
@ -709,6 +702,7 @@ pub(crate) fn wayland_handler(
|
||||||
seat_state: SeatState::new(&globals, &qh),
|
seat_state: SeatState::new(&globals, &qh),
|
||||||
shm_state: Shm::bind(&globals, &qh).unwrap(),
|
shm_state: Shm::bind(&globals, &qh).unwrap(),
|
||||||
activation_state: ActivationState::bind::<AppData>(&globals, &qh).ok(),
|
activation_state: ActivationState::bind::<AppData>(&globals, &qh).ok(),
|
||||||
|
queue_handle: qh,
|
||||||
};
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
|
||||||
|
|
@ -57,11 +57,13 @@ pub struct WaylandImage {
|
||||||
|
|
||||||
impl WaylandImage {
|
impl WaylandImage {
|
||||||
pub fn new(img: image::RgbaImage) -> Self {
|
pub fn new(img: image::RgbaImage) -> Self {
|
||||||
|
let width = img.width();
|
||||||
|
let height = img.height();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
// TODO avoid copy?
|
img: Bytes::from_owner(img.into_vec()),
|
||||||
img: Bytes::copy_from_slice(img.as_bytes()),
|
width,
|
||||||
width: img.width(),
|
height,
|
||||||
height: img.height(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -401,7 +401,7 @@ impl cosmic::Application for CosmicA11yApplet {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
Subscription::batch(vec![
|
Subscription::batch([
|
||||||
accessibility::subscription().map(Message::DBusUpdate),
|
accessibility::subscription().map(Message::DBusUpdate),
|
||||||
backend::wayland::a11y_subscription().map(Message::WaylandUpdate),
|
backend::wayland::a11y_subscription().map(Message::WaylandUpdate),
|
||||||
self.timeline
|
self.timeline
|
||||||
|
|
|
||||||
|
|
@ -131,8 +131,9 @@ impl Audio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq, Default)]
|
||||||
enum IsOpen {
|
enum IsOpen {
|
||||||
|
#[default]
|
||||||
None,
|
None,
|
||||||
Output,
|
Output,
|
||||||
Input,
|
Input,
|
||||||
|
|
@ -289,12 +290,6 @@ impl cosmic::Application for Audio {
|
||||||
(
|
(
|
||||||
Self {
|
Self {
|
||||||
core,
|
core,
|
||||||
is_open: IsOpen::None,
|
|
||||||
current_output: None,
|
|
||||||
current_input: None,
|
|
||||||
outputs: vec![],
|
|
||||||
inputs: vec![],
|
|
||||||
token_tx: None,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Task::none(),
|
Task::none(),
|
||||||
|
|
@ -495,17 +490,11 @@ impl cosmic::Application for Audio {
|
||||||
match msg {
|
match msg {
|
||||||
// This is where we match messages from the subscription to app state
|
// This is where we match messages from the subscription to app state
|
||||||
pulse::Message::SetSinks(sinks) => self.outputs = sinks,
|
pulse::Message::SetSinks(sinks) => self.outputs = sinks,
|
||||||
pulse::Message::SetSources(sources) => {
|
pulse::Message::SetSources(mut sources) => {
|
||||||
self.inputs = sources
|
sources.retain(|source| {
|
||||||
.into_iter()
|
!source.name.as_ref().is_some_and(|n| n.contains("monitor"))
|
||||||
.filter(|source| {
|
});
|
||||||
!source
|
self.inputs = sources;
|
||||||
.name
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&String::from("Generic"))
|
|
||||||
.contains("monitor")
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
pulse::Message::SetDefaultSink(sink) => {
|
pulse::Message::SetDefaultSink(sink) => {
|
||||||
self.update_output(Some(sink));
|
self.update_output(Some(sink));
|
||||||
|
|
@ -682,7 +671,7 @@ impl cosmic::Application for Audio {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
Subscription::batch(vec![
|
Subscription::batch([
|
||||||
pulse::connect().map(Message::Pulse),
|
pulse::connect().map(Message::Pulse),
|
||||||
self.timeline
|
self.timeline
|
||||||
.as_subscription()
|
.as_subscription()
|
||||||
|
|
@ -738,11 +727,11 @@ impl cosmic::Application for Audio {
|
||||||
.autosize_window(if let Some(Some(playback_buttons)) = playback_buttons {
|
.autosize_window(if let Some(Some(playback_buttons)) = playback_buttons {
|
||||||
match self.core.applet.anchor {
|
match self.core.applet.anchor {
|
||||||
PanelAnchor::Left | PanelAnchor::Right => Element::from(
|
PanelAnchor::Left | PanelAnchor::Right => Element::from(
|
||||||
Column::with_children(vec![playback_buttons, btn.into()])
|
Column::with_children([playback_buttons, btn.into()])
|
||||||
.align_x(Alignment::Center),
|
.align_x(Alignment::Center),
|
||||||
),
|
),
|
||||||
PanelAnchor::Top | PanelAnchor::Bottom => {
|
PanelAnchor::Top | PanelAnchor::Bottom => {
|
||||||
Row::with_children(vec![playback_buttons, btn.into()])
|
Row::with_children([playback_buttons, btn.into()])
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
@ -833,14 +822,7 @@ impl cosmic::Application for Audio {
|
||||||
Some(output) => pretty_name(output.description.clone()),
|
Some(output) => pretty_name(output.description.clone()),
|
||||||
None => String::from("No device selected"),
|
None => String::from("No device selected"),
|
||||||
},
|
},
|
||||||
self.outputs
|
self.outputs.as_slice(),
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.map(|output| (
|
|
||||||
output.name.clone().unwrap_or_default(),
|
|
||||||
pretty_name(output.description)
|
|
||||||
))
|
|
||||||
.collect(),
|
|
||||||
Message::OutputToggle,
|
Message::OutputToggle,
|
||||||
Message::OutputChanged,
|
Message::OutputChanged,
|
||||||
),
|
),
|
||||||
|
|
@ -851,14 +833,7 @@ impl cosmic::Application for Audio {
|
||||||
Some(input) => pretty_name(input.description.clone()),
|
Some(input) => pretty_name(input.description.clone()),
|
||||||
None => fl!("no-device"),
|
None => fl!("no-device"),
|
||||||
},
|
},
|
||||||
self.inputs
|
self.inputs.as_slice(),
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.map(|input| (
|
|
||||||
input.name.clone().unwrap_or_default(),
|
|
||||||
pretty_name(input.description)
|
|
||||||
))
|
|
||||||
.collect(),
|
|
||||||
Message::InputToggle,
|
Message::InputToggle,
|
||||||
Message::InputChanged,
|
Message::InputChanged,
|
||||||
)
|
)
|
||||||
|
|
@ -986,17 +961,23 @@ fn revealer(
|
||||||
open: bool,
|
open: bool,
|
||||||
title: String,
|
title: String,
|
||||||
selected: String,
|
selected: String,
|
||||||
options: Vec<(String, String)>,
|
device_info: &[DeviceInfo],
|
||||||
toggle: Message,
|
toggle: Message,
|
||||||
mut change: impl FnMut(String) -> Message + 'static,
|
mut change: impl FnMut(String) -> Message + 'static,
|
||||||
) -> widget::Column<'static, Message, crate::Theme, Renderer> {
|
) -> widget::Column<'static, Message, crate::Theme, Renderer> {
|
||||||
if open {
|
if open {
|
||||||
options.iter().fold(
|
let options = device_info.iter().map(|device| {
|
||||||
|
(
|
||||||
|
device.name.clone().unwrap_or_default(),
|
||||||
|
pretty_name(device.description.clone()),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
options.fold(
|
||||||
column![revealer_head(open, title, selected, toggle)].width(Length::Fill),
|
column![revealer_head(open, title, selected, toggle)].width(Length::Fill),
|
||||||
|col, (id, name)| {
|
|col, (id, name)| {
|
||||||
col.push(
|
col.push(
|
||||||
menu_button(text::body(name.clone()))
|
menu_button(text::body(name))
|
||||||
.on_press(change(id.clone()))
|
.on_press(change(id))
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.padding([8, 48]),
|
.padding([8, 48]),
|
||||||
)
|
)
|
||||||
|
|
@ -1057,12 +1038,6 @@ impl PulseState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for IsOpen {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn volume_to_percent(volume: Volume) -> f64 {
|
fn volume_to_percent(volume: Volume) -> f64 {
|
||||||
volume.0 as f64 * 100. / FULL_VOLUME
|
volume.0 as f64 * 100. / FULL_VOLUME
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ impl State {
|
||||||
players,
|
players,
|
||||||
active_player: None,
|
active_player: None,
|
||||||
active_player_metadata_stream: None,
|
active_player_metadata_stream: None,
|
||||||
any_player_state_stream: futures::stream::select_all(Vec::new()),
|
any_player_state_stream: futures::stream::select_all([]),
|
||||||
};
|
};
|
||||||
state.update_active_player().await;
|
state.update_active_player().await;
|
||||||
state.update_any_player_state_stream().await;
|
state.update_any_player_state_stream().await;
|
||||||
|
|
@ -243,7 +243,7 @@ async fn run(output: &mut futures::channel::mpsc::Sender<MprisUpdate>) {
|
||||||
let mut state = match State::new().await {
|
let mut state = match State::new().await {
|
||||||
Ok(state) => state,
|
Ok(state) => state,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
tracing::error!("Faile do monitor for mpris clients: {}", err);
|
tracing::error!("Failed to monitor for mpris clients: {}", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -777,8 +777,8 @@ pub struct DeviceInfo {
|
||||||
impl<'a> From<&SinkInfo<'a>> for DeviceInfo {
|
impl<'a> From<&SinkInfo<'a>> for DeviceInfo {
|
||||||
fn from(info: &SinkInfo<'a>) -> Self {
|
fn from(info: &SinkInfo<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: info.name.clone().map(|x| x.into_owned()),
|
name: info.name.as_deref().map(str::to_string),
|
||||||
description: info.description.clone().map(|x| x.into_owned()),
|
description: info.description.as_deref().map(str::to_string),
|
||||||
volume: info.volume,
|
volume: info.volume,
|
||||||
mute: info.mute,
|
mute: info.mute,
|
||||||
index: info.index,
|
index: info.index,
|
||||||
|
|
@ -789,8 +789,8 @@ impl<'a> From<&SinkInfo<'a>> for DeviceInfo {
|
||||||
impl<'a> From<&SourceInfo<'a>> for DeviceInfo {
|
impl<'a> From<&SourceInfo<'a>> for DeviceInfo {
|
||||||
fn from(info: &SourceInfo<'a>) -> Self {
|
fn from(info: &SourceInfo<'a>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: info.name.clone().map(|x| x.into_owned()),
|
name: info.name.as_deref().map(str::to_string),
|
||||||
description: info.description.clone().map(|x| x.into_owned()),
|
description: info.description.as_deref().map(str::to_string),
|
||||||
volume: info.volume,
|
volume: info.volume,
|
||||||
mute: info.mute,
|
mute: info.mute,
|
||||||
index: info.index,
|
index: info.index,
|
||||||
|
|
@ -824,14 +824,15 @@ pub struct ServerInfo {
|
||||||
|
|
||||||
impl<'a> From<&'a pulse::context::introspect::ServerInfo<'a>> for ServerInfo {
|
impl<'a> From<&'a pulse::context::introspect::ServerInfo<'a>> for ServerInfo {
|
||||||
fn from(info: &'a pulse::context::introspect::ServerInfo<'a>) -> Self {
|
fn from(info: &'a pulse::context::introspect::ServerInfo<'a>) -> Self {
|
||||||
|
use std::borrow::Cow;
|
||||||
Self {
|
Self {
|
||||||
user_name: info.user_name.as_ref().map(|cow| cow.to_string()),
|
user_name: info.user_name.as_ref().map(Cow::to_string),
|
||||||
host_name: info.host_name.as_ref().map(|cow| cow.to_string()),
|
host_name: info.host_name.as_ref().map(Cow::to_string),
|
||||||
server_version: info.server_version.as_ref().map(|cow| cow.to_string()),
|
server_version: info.server_version.as_ref().map(Cow::to_string),
|
||||||
server_name: info.server_name.as_ref().map(|cow| cow.to_string()),
|
server_name: info.server_name.as_ref().map(Cow::to_string),
|
||||||
//sample_spec: info.sample_spec,
|
//sample_spec: info.sample_spec,
|
||||||
default_sink_name: info.default_sink_name.as_ref().map(|cow| cow.to_string()),
|
default_sink_name: info.default_sink_name.as_ref().map(Cow::to_string),
|
||||||
default_source_name: info.default_source_name.as_ref().map(|cow| cow.to_string()),
|
default_source_name: info.default_source_name.as_ref().map(Cow::to_string),
|
||||||
cookie: info.cookie,
|
cookie: info.cookie,
|
||||||
//channel_map: info.channel_map,
|
//channel_map: info.channel_map,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -154,8 +154,7 @@ impl CosmicBatteryApplet {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
"off"
|
"off"
|
||||||
}
|
};
|
||||||
.to_string();
|
|
||||||
|
|
||||||
self.display_icon_name =
|
self.display_icon_name =
|
||||||
format!("cosmic-applet-battery-display-brightness-{screen_brightness}-symbolic",);
|
format!("cosmic-applet-battery-display-brightness-{screen_brightness}-symbolic",);
|
||||||
|
|
@ -219,7 +218,7 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Task::batch(vec![zbus_session_cmd, init_charging_limit_cmd]),
|
Task::batch([zbus_session_cmd, init_charging_limit_cmd]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -508,10 +507,10 @@ impl cosmic::Application for CosmicBatteryApplet {
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
match self.core.applet.anchor {
|
match self.core.applet.anchor {
|
||||||
PanelAnchor::Left | PanelAnchor::Right => Column::with_children(vec![btn, dot])
|
PanelAnchor::Left | PanelAnchor::Right => Column::with_children([btn, dot])
|
||||||
.align_x(Alignment::Center)
|
.align_x(Alignment::Center)
|
||||||
.into(),
|
.into(),
|
||||||
PanelAnchor::Top | PanelAnchor::Bottom => Row::with_children(vec![btn, dot])
|
PanelAnchor::Top | PanelAnchor::Bottom => Row::with_children([btn, dot])
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -205,17 +205,17 @@ impl Gpu {
|
||||||
// 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().next_back()?.as_os_str());
|
||||||
let buslink = std::fs::read_link(sys_path)
|
let buslink = std::fs::read_link(sys_path).ok()?;
|
||||||
.ok()?
|
let buslink = buslink.components().nth_back(2)?.as_os_str();
|
||||||
.components()
|
|
||||||
.rev()
|
|
||||||
.nth(2)?
|
|
||||||
.as_os_str()
|
|
||||||
.to_string_lossy()
|
|
||||||
.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".as_ref(),
|
||||||
|
"--id".as_ref(),
|
||||||
|
buslink,
|
||||||
|
"--count".as_ref(),
|
||||||
|
"1".as_ref(),
|
||||||
|
])
|
||||||
.output()
|
.output()
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
match message {
|
match message {
|
||||||
Message::TogglePopup => {
|
Message::TogglePopup => {
|
||||||
if let Some(p) = self.popup.take() {
|
if let Some(p) = self.popup.take() {
|
||||||
return Task::batch(vec![
|
return Task::batch([
|
||||||
destroy_popup(p),
|
destroy_popup(p),
|
||||||
cosmic::task::future(
|
cosmic::task::future(
|
||||||
set_tick(Duration::from_secs(10))
|
set_tick(Duration::from_secs(10))
|
||||||
|
|
@ -134,7 +134,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
);
|
);
|
||||||
|
|
||||||
let tx = self.bluer_sender.clone();
|
let tx = self.bluer_sender.clone();
|
||||||
return Task::batch(vec![
|
return Task::batch([
|
||||||
iced::Task::perform(
|
iced::Task::perform(
|
||||||
async {
|
async {
|
||||||
if let Some(tx) = tx {
|
if let Some(tx) = tx {
|
||||||
|
|
@ -361,7 +361,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
space_xxs, space_s, ..
|
space_xxs, space_s, ..
|
||||||
} = theme::active().cosmic().spacing;
|
} = theme::active().cosmic().spacing;
|
||||||
|
|
||||||
let mut known_bluetooth = vec![];
|
let mut known_bluetooth = Vec::new();
|
||||||
// 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.request_confirmation
|
self.request_confirmation
|
||||||
|
|
@ -370,7 +370,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
}) {
|
}) {
|
||||||
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),
|
||||||
text::body(dev.name.clone())
|
text::body(dev.name.as_str())
|
||||||
.align_x(Alignment::Start)
|
.align_x(Alignment::Start)
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
|
|
@ -493,7 +493,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
padded_control(
|
padded_control(
|
||||||
text::body(fl!(
|
text::body(fl!(
|
||||||
"confirm-pin",
|
"confirm-pin",
|
||||||
HashMap::from_iter(vec![("deviceName", device.name.clone())])
|
HashMap::from([("deviceName", device.name.clone())])
|
||||||
))
|
))
|
||||||
.align_x(Alignment::Start)
|
.align_x(Alignment::Start)
|
||||||
.align_y(Alignment::Center)
|
.align_y(Alignment::Center)
|
||||||
|
|
@ -571,7 +571,7 @@ impl cosmic::Application for CosmicBluetoothApplet {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
Subscription::batch(vec![
|
Subscription::batch([
|
||||||
activation_token_subscription(0).map(Message::Token),
|
activation_token_subscription(0).map(Message::Token),
|
||||||
bluetooth_subscription(0).map(Message::BluetoothEvent),
|
bluetooth_subscription(0).map(Message::BluetoothEvent),
|
||||||
self.timeline
|
self.timeline
|
||||||
|
|
|
||||||
|
|
@ -249,12 +249,7 @@ impl Ord for BluerDevice {
|
||||||
impl PartialOrd for BluerDevice {
|
impl PartialOrd for BluerDevice {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
match self.status.cmp(&other.status) {
|
Some(self.cmp(other))
|
||||||
std::cmp::Ordering::Equal => {
|
|
||||||
Some(self.name.to_lowercase().cmp(&other.name.to_lowercase()))
|
|
||||||
}
|
|
||||||
o => Some(o),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -242,8 +242,8 @@ impl cosmic::Application for Window {
|
||||||
widget::column::with_capacity(4 + self.active_layouts.len()).padding([8, 0]);
|
widget::column::with_capacity(4 + self.active_layouts.len()).padding([8, 0]);
|
||||||
for (id, layout) in self.active_layouts.iter().enumerate() {
|
for (id, layout) in self.active_layouts.iter().enumerate() {
|
||||||
let group = widget::column::with_capacity(2)
|
let group = widget::column::with_capacity(2)
|
||||||
.push(widget::text::body(layout.description.clone()))
|
.push(widget::text::body(layout.description.as_str()))
|
||||||
.push(widget::text::caption(layout.layout.clone()));
|
.push(widget::text::caption(layout.layout.as_str()));
|
||||||
content_list = content_list
|
content_list = content_list
|
||||||
.push(applet::menu_button(group).on_press(Message::SetActiveLayout(id)));
|
.push(applet::menu_button(group).on_press(Message::SetActiveLayout(id)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ impl cosmic::Application for Minimize {
|
||||||
// Temporarily take ownership to appease the borrow checker.
|
// Temporarily take ownership to appease the borrow checker.
|
||||||
let mut apps = std::mem::take(&mut self.apps);
|
let mut apps = std::mem::take(&mut self.apps);
|
||||||
|
|
||||||
if let Some(pos) = apps.iter_mut().position(|a| {
|
if let Some(pos) = apps.iter().position(|a| {
|
||||||
a.toplevel_info.foreign_toplevel == toplevel_info.foreign_toplevel
|
a.toplevel_info.foreign_toplevel == toplevel_info.foreign_toplevel
|
||||||
}) {
|
}) {
|
||||||
if apps[pos].toplevel_info.app_id != toplevel_info.app_id {
|
if apps[pos].toplevel_info.app_id != toplevel_info.app_id {
|
||||||
|
|
@ -194,7 +194,7 @@ impl cosmic::Application for Minimize {
|
||||||
name: desktop_entry
|
name: desktop_entry
|
||||||
.full_name(&self.locales)
|
.full_name(&self.locales)
|
||||||
.unwrap_or(Cow::Borrowed(&desktop_entry.appid))
|
.unwrap_or(Cow::Borrowed(&desktop_entry.appid))
|
||||||
.to_string(),
|
.into_owned(),
|
||||||
icon_source: fde::IconSource::from_unknown(
|
icon_source: fde::IconSource::from_unknown(
|
||||||
desktop_entry.icon().unwrap_or(&desktop_entry.appid),
|
desktop_entry.icon().unwrap_or(&desktop_entry.appid),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -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(anyhow::anyhow!("ShmImage had incorrect size"))
|
.ok_or_else(|| anyhow::anyhow!("ShmImage had incorrect size"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -475,12 +475,12 @@ pub(crate) fn wayland_handler(
|
||||||
exit: false,
|
exit: false,
|
||||||
tx,
|
tx,
|
||||||
conn,
|
conn,
|
||||||
queue_handle: qh.clone(),
|
|
||||||
shm_state,
|
shm_state,
|
||||||
screencopy_state,
|
screencopy_state,
|
||||||
seat_state: SeatState::new(&globals, &qh),
|
seat_state: SeatState::new(&globals, &qh),
|
||||||
toplevel_info_state: ToplevelInfoState::new(®istry_state, &qh),
|
toplevel_info_state: ToplevelInfoState::new(®istry_state, &qh),
|
||||||
toplevel_manager_state: ToplevelManagerState::new(®istry_state, &qh),
|
toplevel_manager_state: ToplevelManagerState::new(®istry_state, &qh),
|
||||||
|
queue_handle: qh,
|
||||||
registry_state,
|
registry_state,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -370,7 +370,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
} = &req
|
} = &req
|
||||||
{
|
{
|
||||||
if let Some(NewConnectionState::Waiting(access_point)) =
|
if let Some(NewConnectionState::Waiting(access_point)) =
|
||||||
self.new_connection.clone()
|
self.new_connection.as_ref()
|
||||||
{
|
{
|
||||||
if !success
|
if !success
|
||||||
&& ssid == &access_point.ssid
|
&& ssid == &access_point.ssid
|
||||||
|
|
@ -384,7 +384,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
}
|
}
|
||||||
} else if let Some(NewConnectionState::EnterPassword {
|
} else if let Some(NewConnectionState::EnterPassword {
|
||||||
access_point, ..
|
access_point, ..
|
||||||
}) = self.new_connection.clone()
|
}) = self.new_connection.as_ref()
|
||||||
{
|
{
|
||||||
if success && ssid == &access_point.ssid && *hw_address == access_point.hw_address {
|
if success && ssid == &access_point.ssid && *hw_address == access_point.hw_address {
|
||||||
self.new_connection = None;
|
self.new_connection = None;
|
||||||
|
|
@ -863,7 +863,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
let mut btn_content = vec![
|
let mut btn_content = vec![
|
||||||
column![
|
column![
|
||||||
text::body(display_name),
|
text::body(display_name),
|
||||||
Column::with_children(vec![text("Adapter").size(10).into()])
|
Column::with_children([text("Adapter").size(10).into()])
|
||||||
]
|
]
|
||||||
.width(Length::Fill)
|
.width(Length::Fill)
|
||||||
.into(),
|
.into(),
|
||||||
|
|
@ -1149,7 +1149,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
|
|
||||||
if let Some(conn) = self.conn.as_ref() {
|
if let Some(conn) = self.conn.as_ref() {
|
||||||
let has_popup = self.popup.is_some();
|
let has_popup = self.popup.is_some();
|
||||||
Subscription::batch(vec![
|
Subscription::batch([
|
||||||
timeline,
|
timeline,
|
||||||
network_sub,
|
network_sub,
|
||||||
token_sub,
|
token_sub,
|
||||||
|
|
@ -1161,7 +1161,7 @@ impl cosmic::Application for CosmicNetworkApplet {
|
||||||
.map(Message::NetworkManagerEvent),
|
.map(Message::NetworkManagerEvent),
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
Subscription::batch(vec![timeline, network_sub, token_sub])
|
Subscription::batch([timeline, network_sub, token_sub])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ use cosmic_dbus_networkmanager::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use itertools::Itertools;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use zbus::zvariant::ObjectPath;
|
use zbus::zvariant::ObjectPath;
|
||||||
|
|
||||||
|
|
@ -37,7 +36,7 @@ pub async fn handle_wireless_device(
|
||||||
// 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 {
|
||||||
let ssid = String::from_utf8_lossy(&ap.ssid().await?.clone()).into_owned();
|
let ssid = String::from_utf8_lossy(ap.ssid().await?.as_slice()).into_owned();
|
||||||
let wps_push = ap.flags().await?.contains(ApFlags::WPS_PBC);
|
let wps_push = ap.flags().await?.contains(ApFlags::WPS_PBC);
|
||||||
let strength = ap.strength().await?;
|
let strength = ap.strength().await?;
|
||||||
if let Some(access_point) = aps.get(&ssid) {
|
if let Some(access_point) = aps.get(&ssid) {
|
||||||
|
|
@ -77,10 +76,8 @@ pub async fn handle_wireless_device(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let aps = aps
|
let mut aps = aps.into_values().collect::<Vec<_>>();
|
||||||
.into_values()
|
aps.sort_by_key(|ap| ap.strength);
|
||||||
.sorted_by(|a, b| b.strength.cmp(&a.strength))
|
|
||||||
.collect();
|
|
||||||
Ok(aps)
|
Ok(aps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,15 +71,7 @@ pub async fn active_connections(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info.sort_by(|a, b| {
|
info.sort();
|
||||||
let helper = |conn: &ActiveConnectionInfo| match conn {
|
|
||||||
ActiveConnectionInfo::Vpn { name, .. } => format!("0{name}"),
|
|
||||||
ActiveConnectionInfo::Wired { name, .. } => format!("1{name}"),
|
|
||||||
ActiveConnectionInfo::WiFi { name, .. } => format!("2{name}"),
|
|
||||||
};
|
|
||||||
helper(a).cmp(&helper(b))
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(info)
|
Ok(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -107,16 +99,74 @@ pub enum ActiveConnectionInfo {
|
||||||
impl ActiveConnectionInfo {
|
impl ActiveConnectionInfo {
|
||||||
pub fn name(&self) -> String {
|
pub fn name(&self) -> String {
|
||||||
match &self {
|
match &self {
|
||||||
Self::Wired { name, .. } => name.clone(),
|
Self::Wired { name, .. } | Self::WiFi { name, .. } | Self::Vpn { name, .. } => {
|
||||||
Self::WiFi { name, .. } => name.clone(),
|
name.clone()
|
||||||
Self::Vpn { name, .. } => name.clone(),
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn hw_address(&self) -> HwAddress {
|
pub fn hw_address(&self) -> HwAddress {
|
||||||
match &self {
|
match &self {
|
||||||
Self::Wired { hw_address, .. } => *hw_address,
|
Self::Wired { hw_address, .. } | Self::WiFi { hw_address, .. } => *hw_address,
|
||||||
Self::WiFi { hw_address, .. } => *hw_address,
|
|
||||||
Self::Vpn { .. } => HwAddress::default(),
|
Self::Vpn { .. } => HwAddress::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::cmp::Ord for ActiveConnectionInfo {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
match (self, other) {
|
||||||
|
(Self::Vpn { .. }, Self::Wired { .. } | Self::WiFi { .. })
|
||||||
|
| (Self::Wired { .. }, Self::WiFi { .. }) => std::cmp::Ordering::Greater,
|
||||||
|
|
||||||
|
(Self::WiFi { .. }, Self::Wired { .. } | Self::Vpn { .. })
|
||||||
|
| (Self::Wired { .. }, Self::Vpn { .. }) => std::cmp::Ordering::Less,
|
||||||
|
|
||||||
|
(Self::Vpn { name: n1, .. }, Self::Vpn { name: n2, .. })
|
||||||
|
| (Self::Wired { name: n1, .. }, Self::Wired { name: n2, .. })
|
||||||
|
| (Self::WiFi { name: n1, .. }, Self::WiFi { name: n2, .. }) => n1.cmp(n2),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::Eq for ActiveConnectionInfo {}
|
||||||
|
|
||||||
|
impl std::cmp::PartialOrd for ActiveConnectionInfo {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::cmp::PartialEq for ActiveConnectionInfo {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
match (self, other) {
|
||||||
|
(
|
||||||
|
Self::Wired {
|
||||||
|
name: n1,
|
||||||
|
hw_address: a1,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
Self::Wired {
|
||||||
|
name: n2,
|
||||||
|
hw_address: a2,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
)
|
||||||
|
| (
|
||||||
|
Self::WiFi {
|
||||||
|
name: n1,
|
||||||
|
hw_address: a1,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
Self::WiFi {
|
||||||
|
name: n2,
|
||||||
|
hw_address: a2,
|
||||||
|
..
|
||||||
|
},
|
||||||
|
) => n1 == n2 && a1 == a2,
|
||||||
|
|
||||||
|
(Self::Vpn { name: n1, .. }, Self::Vpn { name: n2, .. }) => n1 == n2,
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -263,10 +263,9 @@ async fn start_listening(
|
||||||
let settings = c.get_settings().await.ok().unwrap_or_default();
|
let settings = c.get_settings().await.ok().unwrap_or_default();
|
||||||
let s = Settings::new(settings);
|
let s = Settings::new(settings);
|
||||||
if s.wifi
|
if s.wifi
|
||||||
.clone()
|
.as_ref()
|
||||||
.and_then(|w| w.ssid)
|
.and_then(|w| w.ssid.as_deref())
|
||||||
.and_then(|ssid| String::from_utf8(ssid).ok())
|
.is_some_and(|s| std::str::from_utf8(s).is_ok_and(|s| s == ssid))
|
||||||
.is_some_and(|s| s == ssid)
|
|
||||||
{
|
{
|
||||||
// todo most likely we can here forget ssid from wrong hw_address
|
// todo most likely we can here forget ssid from wrong hw_address
|
||||||
_ = c.delete().await;
|
_ = c.delete().await;
|
||||||
|
|
@ -429,14 +428,7 @@ impl NetworkManagerState {
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
active_conns.sort_by(|a, b| {
|
active_conns.sort();
|
||||||
let helper = |conn: &ActiveConnectionInfo| match conn {
|
|
||||||
ActiveConnectionInfo::Vpn { name, .. } => format!("0{name}"),
|
|
||||||
ActiveConnectionInfo::Wired { name, .. } => format!("1{name}"),
|
|
||||||
ActiveConnectionInfo::WiFi { name, .. } => format!("2{name}"),
|
|
||||||
};
|
|
||||||
helper(a).cmp(&helper(b))
|
|
||||||
});
|
|
||||||
let devices = network_manager.devices().await.ok().unwrap_or_default();
|
let devices = network_manager.devices().await.ok().unwrap_or_default();
|
||||||
let wireless_access_point_futures: Vec<_> = devices
|
let wireless_access_point_futures: Vec<_> = devices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -483,7 +475,7 @@ impl NetworkManagerState {
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
wireless_access_points.sort_by(|a, b| b.strength.cmp(&a.strength));
|
wireless_access_points.sort_by_key(|ap| ap.strength);
|
||||||
self_.wireless_access_points = wireless_access_points;
|
self_.wireless_access_points = wireless_access_points;
|
||||||
for ap in &self_.wireless_access_points {
|
for ap in &self_.wireless_access_points {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
|
|
@ -519,11 +511,11 @@ impl NetworkManagerState {
|
||||||
let nm = NetworkManager::new(conn).await?;
|
let nm = NetworkManager::new(conn).await?;
|
||||||
|
|
||||||
for c in nm.active_connections().await.unwrap_or_default() {
|
for c in nm.active_connections().await.unwrap_or_default() {
|
||||||
if self
|
if self.wireless_access_points.iter().any(|w| {
|
||||||
.wireless_access_points
|
c.cached_id()
|
||||||
.iter()
|
.is_ok_and(|opt| opt.is_some_and(|id| id == w.ssid))
|
||||||
.any(|w| Ok(Some(w.ssid.clone())) == c.cached_id() && w.hw_address == hw_address)
|
&& w.hw_address == hw_address
|
||||||
{
|
}) {
|
||||||
_ = nm.deactivate_connection(&c).await;
|
_ = nm.deactivate_connection(&c).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -556,7 +548,7 @@ impl NetworkManagerState {
|
||||||
HashMap::from([
|
HashMap::from([
|
||||||
("identity", Value::Str(identity.into())),
|
("identity", Value::Str(identity.into())),
|
||||||
// most common default
|
// most common default
|
||||||
("eap", Value::Array(vec!["peap"].into())),
|
("eap", Value::Array(["peap"].as_slice().into())),
|
||||||
// most common default
|
// most common default
|
||||||
("phase2-auth", Value::Str("mschapv2".into())),
|
("phase2-auth", Value::Str("mschapv2".into())),
|
||||||
("password", Value::Str(password.unwrap_or("").into())),
|
("password", Value::Str(password.unwrap_or("").into())),
|
||||||
|
|
@ -605,16 +597,13 @@ impl NetworkManagerState {
|
||||||
|
|
||||||
let s = Settings::new(settings);
|
let s = Settings::new(settings);
|
||||||
// todo try to add hw_address comparing here if it changes anything
|
// todo try to add hw_address comparing here if it changes anything
|
||||||
if let Some(cur_ssid) = s
|
if s.wifi
|
||||||
.wifi
|
.as_ref()
|
||||||
.clone()
|
.and_then(|w| w.ssid.as_deref())
|
||||||
.and_then(|w| w.ssid)
|
.is_some_and(|s| std::str::from_utf8(s).is_ok_and(|cur_ssid| cur_ssid == ssid))
|
||||||
.and_then(|ssid| String::from_utf8(ssid).ok())
|
|
||||||
{
|
{
|
||||||
if cur_ssid == ssid {
|
known_conn = Some(c);
|
||||||
known_conn = Some(c);
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ struct Notifications {
|
||||||
|
|
||||||
impl Notifications {
|
impl Notifications {
|
||||||
fn update_cards(&mut self, id: id::Cards) {
|
fn update_cards(&mut self, id: id::Cards) {
|
||||||
if let Some((id, _, card_value, ..)) = self.cards.iter_mut().find(|c| c.0 == id) {
|
if let Some((id, _, card_value, ..)) = self.cards.iter().find(|c| c.0 == id) {
|
||||||
let chain = if *card_value {
|
let chain = if *card_value {
|
||||||
chain::Cards::on(id.clone(), 1.)
|
chain::Cards::on(id.clone(), 1.)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -152,7 +152,7 @@ impl cosmic::Application for Notifications {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
Subscription::batch(vec![
|
Subscription::batch([
|
||||||
self.core
|
self.core
|
||||||
.watch_config(cosmic_notifications_config::ID)
|
.watch_config(cosmic_notifications_config::ID)
|
||||||
.map(|res| {
|
.map(|res| {
|
||||||
|
|
@ -217,7 +217,7 @@ impl cosmic::Application for Notifications {
|
||||||
c.1.push(n);
|
c.1.push(n);
|
||||||
c.3 = fl!(
|
c.3 = fl!(
|
||||||
"show-more",
|
"show-more",
|
||||||
HashMap::from_iter(vec![("more", c.1.len().saturating_sub(1))])
|
HashMap::from([("more", c.1.len().saturating_sub(1))])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -225,7 +225,7 @@ impl cosmic::Application for Notifications {
|
||||||
id::Cards::new(n.app_name.clone()),
|
id::Cards::new(n.app_name.clone()),
|
||||||
vec![n],
|
vec![n],
|
||||||
false,
|
false,
|
||||||
fl!("show-more", HashMap::from_iter(vec![("more", "1")])),
|
fl!("show-more", HashMap::from([("more", "1")])),
|
||||||
fl!("show-less"),
|
fl!("show-less"),
|
||||||
fl!("clear-group"),
|
fl!("clear-group"),
|
||||||
));
|
));
|
||||||
|
|
@ -263,7 +263,7 @@ impl cosmic::Application for Notifications {
|
||||||
c.1.retain(|n| n.id != id);
|
c.1.retain(|n| n.id != id);
|
||||||
c.3 = fl!(
|
c.3 = fl!(
|
||||||
"show-more",
|
"show-more",
|
||||||
HashMap::from_iter(vec![("more", c.1.len().saturating_sub(1))])
|
HashMap::from([("more", c.1.len().saturating_sub(1))])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
self.cards.retain(|c| !c.1.is_empty());
|
self.cards.retain(|c| !c.1.is_empty());
|
||||||
|
|
@ -581,9 +581,9 @@ fn duration_ago_msg(notification: &Notification) -> String {
|
||||||
let min = d.as_secs() / 60;
|
let min = d.as_secs() / 60;
|
||||||
let hrs = min / 60;
|
let hrs = min / 60;
|
||||||
if hrs > 0 {
|
if hrs > 0 {
|
||||||
fl!("hours-ago", HashMap::from_iter(vec![("duration", hrs)]))
|
fl!("hours-ago", HashMap::from([("duration", hrs)]))
|
||||||
} else {
|
} else {
|
||||||
fl!("minutes-ago", HashMap::from_iter(vec![("duration", min)]))
|
fl!("minutes-ago", HashMap::from([("duration", min)]))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String::new()
|
String::new()
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ pub fn notifications(proxy: NotificationsAppletProxy<'static>) -> Subscription<O
|
||||||
cosmic::iced::futures::select! {
|
cosmic::iced::futures::select! {
|
||||||
v = next_signal => {
|
v = next_signal => {
|
||||||
if let Some(msg) = v {
|
if let Some(msg) = v {
|
||||||
let Some(args) = msg.args().into_iter().next() else {
|
let Ok(args) = msg.args() else {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
let notification = Notification::new(
|
let notification = Notification::new(
|
||||||
|
|
|
||||||
|
|
@ -380,8 +380,7 @@ impl cosmic::Application for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.overflow_popup = Some(popup_id);
|
self.overflow_popup = Some(popup_id);
|
||||||
let cmds = vec![get_popup(popup_settings)];
|
return get_popup(popup_settings);
|
||||||
return Task::batch(cmds);
|
|
||||||
} else {
|
} else {
|
||||||
return Task::none();
|
return Task::none();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,7 @@ impl cosmic::Application for Window {
|
||||||
.timeline
|
.timeline
|
||||||
.as_subscription()
|
.as_subscription()
|
||||||
.map(|(_, now)| Message::Frame(now));
|
.map(|(_, now)| Message::Frame(now));
|
||||||
Subscription::batch(vec![
|
Subscription::batch([
|
||||||
timeline,
|
timeline,
|
||||||
self.core
|
self.core
|
||||||
.watch_config::<CosmicCompConfig>("com.system76.CosmicComp")
|
.watch_config::<CosmicCompConfig>("com.system76.CosmicComp")
|
||||||
|
|
|
||||||
|
|
@ -125,12 +125,11 @@ impl Window {
|
||||||
first_day_of_week,
|
first_day_of_week,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut day_iter = first_day.iter_days();
|
let day_iter = first_day.iter_days();
|
||||||
let prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
let prefs = DateTimeFormatterPreferences::from(self.locale.clone());
|
||||||
let weekday = DateTimeFormatter::try_new(prefs, fieldsets::E::short()).unwrap();
|
let weekday = DateTimeFormatter::try_new(prefs, fieldsets::E::short()).unwrap();
|
||||||
|
|
||||||
for _ in 0..7 {
|
for date in day_iter.take(7) {
|
||||||
let date = day_iter.next().unwrap();
|
|
||||||
let datetime = self.create_datetime(&date);
|
let datetime = self.create_datetime(&date);
|
||||||
calendar = calendar.push(
|
calendar = calendar.push(
|
||||||
text::caption(weekday.format(&datetime).to_string())
|
text::caption(weekday.format(&datetime).to_string())
|
||||||
|
|
@ -447,7 +446,7 @@ impl cosmic::Application for Window {
|
||||||
}
|
}
|
||||||
|
|
||||||
let show_seconds_rx = self.show_seconds_tx.subscribe();
|
let show_seconds_rx = self.show_seconds_tx.subscribe();
|
||||||
Subscription::batch(vec![
|
Subscription::batch([
|
||||||
rectangle_tracker_subscription(0).map(|e| Message::Rectangle(e.1)),
|
rectangle_tracker_subscription(0).map(|e| Message::Rectangle(e.1)),
|
||||||
time_subscription(show_seconds_rx),
|
time_subscription(show_seconds_rx),
|
||||||
activation_token_subscription(0).map(Message::Token),
|
activation_token_subscription(0).map(Message::Token),
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,7 @@ impl cosmic::Application for IcedWorkspacesApplet {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subscription(&self) -> Subscription<Message> {
|
fn subscription(&self) -> Subscription<Message> {
|
||||||
Subscription::batch(vec![
|
Subscription::batch([
|
||||||
workspaces().map(Message::WorkspaceUpdate),
|
workspaces().map(Message::WorkspaceUpdate),
|
||||||
event::listen_with(|e, _, _| match e {
|
event::listen_with(|e, _, _| match e {
|
||||||
Mouse(mouse::Event::WheelScrolled { delta }) => Some(Message::WheelScrolled(delta)),
|
Mouse(mouse::Event::WheelScrolled { delta }) => Some(Message::WheelScrolled(delta)),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue