Skip to content

Commit 4e5e829

Browse files
committed
perf: refactor to reduce memory allocations and cpu work
1 parent 0c3e3c8 commit 4e5e829

File tree

23 files changed

+222
-229
lines changed

23 files changed

+222
-229
lines changed

cosmic-app-list/src/app.rs

Lines changed: 58 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ use cosmic_app_list_config::{APP_ID, AppListConfig};
5353
use cosmic_protocols::toplevel_info::v1::client::zcosmic_toplevel_handle_v1::State;
5454
use futures::future::pending;
5555
use iced::{Alignment, Background, Length};
56-
use itertools::Itertools;
5756
use std::{borrow::Cow, collections::HashMap, path::PathBuf, rc::Rc, str::FromStr, time::Duration};
5857
use switcheroo_control::Gpu;
5958
use tokio::time::sleep;
@@ -177,31 +176,24 @@ impl DockItem {
177176
.width(app_icon.icon_size.into())
178177
.height(app_icon.icon_size.into());
179178

180-
let dots = if toplevels.is_empty() {
181-
(0..1)
182-
.map(|_| {
183-
container(vertical_space().height(Length::Fixed(0.0)))
184-
.padding(app_icon.dot_radius)
185-
.into()
186-
})
187-
.collect_vec()
188-
} else {
189-
(0..1)
190-
.map(|_| {
191-
container(if toplevels.len() == 1 {
192-
vertical_space().height(Length::Fixed(0.0))
193-
} else {
194-
match applet.anchor {
195-
PanelAnchor::Left | PanelAnchor::Right => {
196-
vertical_space().height(app_icon.bar_size)
197-
}
198-
PanelAnchor::Top | PanelAnchor::Bottom => {
199-
horizontal_space().width(app_icon.bar_size)
200-
}
201-
}
202-
})
203-
.padding(app_icon.dot_radius)
204-
.class(theme::style::Container::Custom(Box::new(move |theme| {
179+
let dot_constructor = || {
180+
let space = if toplevels.len() <= 1 {
181+
vertical_space().height(Length::Fixed(0.0))
182+
} else {
183+
match applet.anchor {
184+
PanelAnchor::Left | PanelAnchor::Right => {
185+
vertical_space().height(app_icon.bar_size)
186+
}
187+
PanelAnchor::Top | PanelAnchor::Bottom => {
188+
horizontal_space().width(app_icon.bar_size)
189+
}
190+
}
191+
};
192+
let mut container = container(space).padding(app_icon.dot_radius);
193+
194+
if !toplevels.is_empty() {
195+
container =
196+
container.class(theme::style::Container::Custom(Box::new(move |theme| {
205197
container::Style {
206198
text_color: Some(Color::TRANSPARENT),
207199
background: if is_focused {
@@ -218,34 +210,35 @@ impl DockItem {
218210
icon_color: Some(Color::TRANSPARENT),
219211
}
220212
})))
221-
.into()
222-
})
223-
.collect_vec()
213+
}
214+
container.into()
224215
};
225216

217+
let dots = std::iter::repeat_with(dot_constructor).take(2);
218+
226219
let icon_wrapper: Element<_> = match applet.anchor {
227-
PanelAnchor::Left => row(vec![
220+
PanelAnchor::Left => row([
228221
column(dots).into(),
229222
horizontal_space().width(Length::Fixed(1.0)).into(),
230223
cosmic_icon.clone().into(),
231224
])
232225
.align_y(Alignment::Center)
233226
.into(),
234-
PanelAnchor::Right => row(vec![
227+
PanelAnchor::Right => row([
235228
cosmic_icon.clone().into(),
236229
horizontal_space().width(Length::Fixed(1.0)).into(),
237230
column(dots).into(),
238231
])
239232
.align_y(Alignment::Center)
240233
.into(),
241-
PanelAnchor::Top => column(vec![
234+
PanelAnchor::Top => column([
242235
row(dots).into(),
243236
vertical_space().height(Length::Fixed(1.0)).into(),
244237
cosmic_icon.clone().into(),
245238
])
246239
.align_x(Alignment::Center)
247240
.into(),
248-
PanelAnchor::Bottom => column(vec![
241+
PanelAnchor::Bottom => column([
249242
cosmic_icon.clone().into(),
250243
vertical_space().height(Length::Fixed(1.0)).into(),
251244
row(dots).into(),
@@ -470,7 +463,7 @@ where
470463
img.img.clone(),
471464
)))
472465
} else {
473-
Image::new(Handle::from_rgba(1, 1, vec![0, 0, 0, 255])).into()
466+
Image::new(Handle::from_rgba(1, 1, [0u8, 0u8, 0u8, 255u8].as_slice())).into()
474467
})
475468
.class(Container::Custom(Box::new(move |theme| {
476469
container::Style {
@@ -590,7 +583,7 @@ fn find_desktop_entries<'a>(
590583
app_ids.iter().map(|fav| {
591584
let unicase_fav = fde::unicase::Ascii::new(fav.as_str());
592585
fde::find_app_by_id(desktop_entries, unicase_fav).map_or_else(
593-
|| fde::DesktopEntry::from_appid(fav.clone()).clone(),
586+
|| fde::DesktopEntry::from_appid(fav.clone()),
594587
ToOwned::to_owned,
595588
)
596589
})
@@ -612,7 +605,7 @@ impl CosmicAppList {
612605
.map(|(pinned_ctr, (e, original_id))| DockItem {
613606
id: pinned_ctr as u32,
614607
toplevels: Vec::new(),
615-
desktop_info: e.clone(),
608+
desktop_info: e,
616609
original_app_id: original_id.clone(),
617610
})
618611
.collect();
@@ -673,7 +666,7 @@ impl cosmic::Application for CosmicAppList {
673666
} else {
674667
self.overflow_active_popup = None;
675668
self.overflow_favorites_popup = None;
676-
return Task::batch(vec![destroy_popup(popup_id), destroy_popup(parent)]);
669+
return Task::batch([destroy_popup(popup_id), destroy_popup(parent)]);
677670
}
678671
}
679672
if let Some(toplevel_group) = self
@@ -733,7 +726,7 @@ impl cosmic::Application for CosmicAppList {
733726
} else {
734727
self.overflow_active_popup = None;
735728
self.overflow_favorites_popup = None;
736-
return Task::batch(vec![destroy_popup(popup_id), destroy_popup(parent)]);
729+
return Task::batch([destroy_popup(popup_id), destroy_popup(parent)]);
737730
}
738731
}
739732
if let Some(toplevel_group) = self
@@ -1490,7 +1483,10 @@ impl cosmic::Application for CosmicAppList {
14901483
} else {
14911484
0
14921485
};
1493-
let favorites: Vec<_> = (&mut self.pinned_list.iter().rev())
1486+
let favorites: Vec<_> = self
1487+
.pinned_list
1488+
.iter()
1489+
.rev()
14941490
.filter(|f| {
14951491
if favorite_to_remove > 0 && f.toplevels.is_empty() {
14961492
favorite_to_remove -= 1;
@@ -1524,7 +1520,7 @@ impl cosmic::Application for CosmicAppList {
15241520
.desktop_info
15251521
.full_name(&self.locales)
15261522
.unwrap_or_default()
1527-
.to_string(),
1523+
.into_owned(),
15281524
self.popup.is_some(),
15291525
Message::Surface,
15301526
None,
@@ -1618,7 +1614,7 @@ impl cosmic::Application for CosmicAppList {
16181614
.desktop_info
16191615
.full_name(&self.locales)
16201616
.unwrap_or_default()
1621-
.to_string(),
1617+
.into_owned(),
16221618
self.popup.is_some(),
16231619
Message::Surface,
16241620
None,
@@ -1812,11 +1808,7 @@ impl cosmic::Application for CosmicAppList {
18121808
Message::Exec(exec.to_string(), None, desktop_info.terminal()),
18131809
));
18141810
} else if let Some(gpus) = self.gpus.as_ref() {
1815-
let default_idx = if desktop_info.prefers_non_default_gpu() {
1816-
gpus.iter().position(|gpu| !gpu.default).unwrap_or(0)
1817-
} else {
1818-
gpus.iter().position(|gpu| gpu.default).unwrap_or(0)
1819-
};
1811+
let default_idx = preferred_gpu_idx(desktop_info, gpus.iter());
18201812
for (i, gpu) in gpus.iter().enumerate() {
18211813
content = content.push(
18221814
menu_button(text::body(format!(
@@ -2037,7 +2029,7 @@ impl cosmic::Application for CosmicAppList {
20372029
.desktop_info
20382030
.full_name(&self.locales)
20392031
.unwrap_or_default()
2040-
.to_string(),
2032+
.into_owned(),
20412033
self.popup.is_some(),
20422034
Message::Surface,
20432035
None,
@@ -2101,7 +2093,10 @@ impl cosmic::Application for CosmicAppList {
21012093
0
21022094
};
21032095
let mut favorites_extra = Vec::with_capacity(favorite_to_remove);
2104-
let mut favorites: Vec<_> = (&mut self.pinned_list.iter().rev())
2096+
let mut favorites: Vec<_> = self
2097+
.pinned_list
2098+
.iter()
2099+
.rev()
21052100
.filter(|f| {
21062101
if favorite_to_remove > 0 && f.toplevels.is_empty() {
21072102
favorite_to_remove -= 1;
@@ -2190,7 +2185,7 @@ impl cosmic::Application for CosmicAppList {
21902185
}
21912186

21922187
fn subscription(&self) -> Subscription<Message> {
2193-
Subscription::batch(vec![
2188+
Subscription::batch([
21942189
wayland_subscription().map(Message::Wayland),
21952190
listen_with(|e, _, id| match e {
21962191
cosmic::iced_runtime::core::Event::PlatformSpecific(
@@ -2299,9 +2294,9 @@ impl CosmicAppList {
22992294
if self.active_workspaces.is_empty() {
23002295
return Vec::new();
23012296
}
2302-
let current_output = self.core.applet.output_name.clone();
2297+
let current_output = self.core.applet.output_name.as_ref();
23032298
let mut focused_toplevels: Vec<ExtForeignToplevelHandleV1> = Vec::new();
2304-
let active_workspaces = self.active_workspaces.clone();
2299+
let active_workspaces = &self.active_workspaces;
23052300
for toplevel_list in self.active_list.iter().chain(self.pinned_list.iter()) {
23062301
for (t_info, _) in &toplevel_list.toplevels {
23072302
if t_info.state.contains(&State::Activated)
@@ -2349,10 +2344,8 @@ impl CosmicAppList {
23492344
let is_proton_game = info.app_id == "steam_app_default";
23502345
if is_proton_game || info.app_id.ends_with(".exe") {
23512346
for entry in &self.desktop_entries {
2352-
let localised_name = entry
2353-
.name(&self.locales)
2354-
.map(|x| x.to_string())
2355-
.unwrap_or_default();
2347+
let localised_name =
2348+
entry.name(&self.locales).unwrap_or_default().into_owned();
23562349

23572350
if localised_name == info.title {
23582351
// if this is a proton game, we only want
@@ -2378,13 +2371,7 @@ impl CosmicAppList {
23782371
fn launch_on_preferred_gpu(desktop_info: &DesktopEntry, gpus: Option<&[Gpu]>) -> Option<Message> {
23792372
let exec = desktop_info.exec()?;
23802373

2381-
let gpu_idx = gpus.map(|gpus| {
2382-
if desktop_info.prefers_non_default_gpu() {
2383-
gpus.iter().position(|gpu| !gpu.default).unwrap_or(0)
2384-
} else {
2385-
gpus.iter().position(|gpu| gpu.default).unwrap_or(0)
2386-
}
2387-
});
2374+
let gpu_idx = gpus.map(|gpus| preferred_gpu_idx(desktop_info, gpus.iter()));
23882375

23892376
Some(Message::Exec(
23902377
exec.to_string(),
@@ -2393,6 +2380,14 @@ fn launch_on_preferred_gpu(desktop_info: &DesktopEntry, gpus: Option<&[Gpu]>) ->
23932380
))
23942381
}
23952382

2383+
fn preferred_gpu_idx<'a, I>(desktop_info: &DesktopEntry, mut gpus: I) -> usize
2384+
where
2385+
I: Iterator<Item = &'a Gpu>,
2386+
{
2387+
gpus.position(|gpu| gpu.default ^ desktop_info.prefers_non_default_gpu())
2388+
.unwrap_or(0)
2389+
}
2390+
23962391
#[derive(Debug, Default, Clone)]
23972392
pub struct DndPathBuf(PathBuf);
23982393

@@ -2428,8 +2423,6 @@ impl AsMimeTypes for DndPathBuf {
24282423
}
24292424

24302425
fn as_bytes(&self, _mime_type: &str) -> Option<std::borrow::Cow<'static, [u8]>> {
2431-
Some(Cow::Owned(
2432-
self.0.clone().to_str()?.to_string().into_bytes(),
2433-
))
2426+
Some(Cow::Owned(self.0.to_str()?.as_bytes().to_vec()))
24342427
}
24352428
}

cosmic-app-list/src/wayland_handler.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,7 @@ impl OutputHandler for AppData {
8787
if let Some(info) = self.output_state.info(&output) {
8888
let _ = self
8989
.tx
90-
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Add(
91-
output.clone(),
92-
info.clone(),
93-
)));
90+
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Add(output, info)));
9491
}
9592
}
9693

@@ -103,10 +100,7 @@ impl OutputHandler for AppData {
103100
if let Some(info) = self.output_state.info(&output) {
104101
let _ = self
105102
.tx
106-
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Update(
107-
output.clone(),
108-
info.clone(),
109-
)));
103+
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Update(output, info)));
110104
}
111105
}
112106

@@ -118,7 +112,7 @@ impl OutputHandler for AppData {
118112
) {
119113
let _ = self
120114
.tx
121-
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Remove(output.clone())));
115+
.unbounded_send(WaylandUpdate::Output(OutputUpdate::Remove(output)));
122116
}
123117
}
124118

@@ -136,12 +130,12 @@ impl WorkspaceHandler for AppData {
136130
.iter()
137131
.filter_map(|handle| self.workspace_state.workspace_info(handle))
138132
.find(|w| w.state.contains(WorkspaceUpdateState::Active))
133+
.map(|workspace| workspace.handle.clone())
139134
})
140-
.map(|workspace| workspace.handle.clone())
141135
.collect::<Vec<_>>();
142136
let _ = self
143137
.tx
144-
.unbounded_send(WaylandUpdate::Workspace(active_workspaces.clone()));
138+
.unbounded_send(WaylandUpdate::Workspace(active_workspaces));
145139
}
146140
}
147141

@@ -699,7 +693,6 @@ pub(crate) fn wayland_handler(
699693
exit: false,
700694
tx,
701695
conn,
702-
queue_handle: qh.clone(),
703696
output_state: OutputState::new(&globals, &qh),
704697
workspace_state: WorkspaceState::new(&registry_state, &qh),
705698
toplevel_info_state: ToplevelInfoState::new(&registry_state, &qh),
@@ -709,6 +702,7 @@ pub(crate) fn wayland_handler(
709702
seat_state: SeatState::new(&globals, &qh),
710703
shm_state: Shm::bind(&globals, &qh).unwrap(),
711704
activation_state: ActivationState::bind::<AppData>(&globals, &qh).ok(),
705+
queue_handle: qh,
712706
};
713707

714708
loop {

cosmic-app-list/src/wayland_subscription.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,13 @@ pub struct WaylandImage {
5757

5858
impl WaylandImage {
5959
pub fn new(img: image::RgbaImage) -> Self {
60+
let width = img.width();
61+
let height = img.height();
62+
6063
Self {
61-
// TODO avoid copy?
62-
img: Bytes::copy_from_slice(img.as_bytes()),
63-
width: img.width(),
64-
height: img.height(),
64+
img: Bytes::from_owner(img.into_vec()),
65+
width,
66+
height,
6567
}
6668
}
6769
}

cosmic-applet-a11y/src/app.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ impl cosmic::Application for CosmicA11yApplet {
401401
}
402402

403403
fn subscription(&self) -> Subscription<Message> {
404-
Subscription::batch(vec![
404+
Subscription::batch([
405405
accessibility::subscription().map(Message::DBusUpdate),
406406
backend::wayland::a11y_subscription().map(Message::WaylandUpdate),
407407
self.timeline

0 commit comments

Comments
 (0)