perf: reduce memory allocations
This also changes `widget::column::with_children` and `widget::row::with_children` to take an `impl IntoIterator` instead of a `Vec`, like the `iced` variants of these functions do. This shouldn't be a breaking change since passing in a `Vec` will still compile and function exactly as before. (Using `iced::widget::Column::from_vec` or `iced::widget::Row::from_vec` isn't possible, since the elements of the `Vec` aren't checked, so the size of the resulting `Column` or `Row` won't adapt to the size of its children. Perhaps a new function could be added to mirror `iced`'s?)
This commit is contained in:
parent
840ef21e4d
commit
bd438a8581
20 changed files with 83 additions and 88 deletions
|
|
@ -170,11 +170,10 @@ impl Config {
|
|||
.map(|x| x.join("COSMIC").join(&path));
|
||||
|
||||
// Get libcosmic user configuration directory
|
||||
let cosmic_user_path = dirs::config_dir()
|
||||
.ok_or(Error::NoConfigDirectory)?
|
||||
.join("cosmic");
|
||||
let mut user_path = dirs::config_dir().ok_or(Error::NoConfigDirectory)?;
|
||||
user_path.push("cosmic");
|
||||
user_path.push(path);
|
||||
|
||||
let user_path = cosmic_user_path.join(path);
|
||||
// Create new configuration directory if not found.
|
||||
fs::create_dir_all(&user_path)?;
|
||||
|
||||
|
|
@ -190,9 +189,9 @@ impl Config {
|
|||
// Look for [name]/v[version]
|
||||
let path = sanitize_name(name)?.join(format!("v{version}"));
|
||||
|
||||
let cosmic_user_path = custom_path.join("cosmic");
|
||||
|
||||
let user_path = cosmic_user_path.join(path);
|
||||
let mut user_path = custom_path;
|
||||
user_path.push("cosmic");
|
||||
user_path.push(path);
|
||||
// Create new configuration directory if not found.
|
||||
fs::create_dir_all(&user_path)?;
|
||||
|
||||
|
|
@ -213,11 +212,9 @@ impl Config {
|
|||
let path = sanitize_name(name)?.join(format!("v{}", version));
|
||||
|
||||
// Get libcosmic user state directory
|
||||
let cosmic_user_path = dirs::state_dir()
|
||||
.ok_or(Error::NoConfigDirectory)?
|
||||
.join("cosmic");
|
||||
|
||||
let user_path = cosmic_user_path.join(path);
|
||||
let mut user_path = dirs::state_dir().ok_or(Error::NoConfigDirectory)?;
|
||||
user_path.push("cosmic");
|
||||
user_path.push(path);
|
||||
// Create new state directory if not found.
|
||||
fs::create_dir_all(&user_path)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ impl Theme {
|
|||
#[cold]
|
||||
pub fn write_gtk4(&self) -> Result<(), OutputError> {
|
||||
let css_str = self.as_gtk4();
|
||||
let Some(config_dir) = dirs::config_dir() else {
|
||||
let Some(mut config_dir) = dirs::config_dir() else {
|
||||
return Err(OutputError::MissingConfigDir);
|
||||
};
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ impl Theme {
|
|||
"light.css"
|
||||
};
|
||||
|
||||
let config_dir = config_dir.join("gtk-4.0").join("cosmic");
|
||||
config_dir.extend(["gtk-4.0", "cosmic"]);
|
||||
if !config_dir.exists() {
|
||||
std::fs::create_dir_all(&config_dir).map_err(OutputError::Io)?;
|
||||
}
|
||||
|
|
@ -181,23 +181,20 @@ impl Theme {
|
|||
return Err(OutputError::MissingConfigDir);
|
||||
};
|
||||
|
||||
let gtk4 = config_dir.join("gtk-4.0");
|
||||
let gtk3 = config_dir.join("gtk-3.0");
|
||||
let mut gtk4 = config_dir.join("gtk-4.0");
|
||||
let mut gtk3 = config_dir.join("gtk-3.0");
|
||||
|
||||
fs::create_dir_all(>k4).map_err(OutputError::Io)?;
|
||||
fs::create_dir_all(>k3).map_err(OutputError::Io)?;
|
||||
|
||||
let cosmic_css_dir = gtk4.join("cosmic");
|
||||
let cosmic_css =
|
||||
cosmic_css_dir
|
||||
.clone()
|
||||
.join(if is_dark { "dark.css" } else { "light.css" });
|
||||
let cosmic_css = cosmic_css_dir.join(if is_dark { "dark.css" } else { "light.css" });
|
||||
|
||||
let gtk4_dest = gtk4.join("gtk.css");
|
||||
let gtk3_dest = gtk3.join("gtk.css");
|
||||
gtk4.push("gtk.css");
|
||||
gtk3.push("gtk.css");
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
for gtk_dest in [>k4_dest, >k3_dest] {
|
||||
for gtk_dest in [>k4, >k3] {
|
||||
use std::os::unix::fs::symlink;
|
||||
Self::backup_non_cosmic_css(gtk_dest, &cosmic_css_dir).map_err(OutputError::Io)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -269,8 +269,9 @@ impl Theme {
|
|||
#[cold]
|
||||
pub fn apply_vs_code(self) -> Result<(), OutputError> {
|
||||
let vs_theme = VsTheme::from(self);
|
||||
let config_dir = dirs::config_dir().ok_or(OutputError::MissingConfigDir)?;
|
||||
let vs_code_dir = config_dir.join("Code").join("User");
|
||||
let mut config_dir = dirs::config_dir().ok_or(OutputError::MissingConfigDir)?;
|
||||
config_dir.extend(["Code", "User"]);
|
||||
let vs_code_dir = config_dir;
|
||||
if !vs_code_dir.exists() {
|
||||
std::fs::create_dir_all(&vs_code_dir).map_err(OutputError::Io)?;
|
||||
}
|
||||
|
|
@ -292,9 +293,9 @@ impl Theme {
|
|||
|
||||
#[cold]
|
||||
pub fn reset_vs_code() -> Result<(), OutputError> {
|
||||
let config_dir = dirs::config_dir().ok_or(OutputError::MissingConfigDir)?;
|
||||
let vs_code_dir = config_dir.join("Code").join("User");
|
||||
let settings_file = vs_code_dir.join("settings.json");
|
||||
let mut config_dir = dirs::config_dir().ok_or(OutputError::MissingConfigDir)?;
|
||||
config_dir.extend(["Code", "User", "settings.json"]);
|
||||
let settings_file = config_dir;
|
||||
// just remove the json entry for workbench.colorCustomizations
|
||||
let settings = std::fs::read_to_string(&settings_file).unwrap_or_default();
|
||||
let mut settings: serde_json::Value = serde_json::from_str(&settings).unwrap_or_default();
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ impl From<String> for PanelType {
|
|||
match value.as_str() {
|
||||
"Panel" => PanelType::Panel,
|
||||
"Dock" => PanelType::Dock,
|
||||
other => PanelType::Other(other.to_string()),
|
||||
_ => PanelType::Other(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -470,8 +470,8 @@ pub fn run<App: Application>(flags: App::Flags) -> iced::Result {
|
|||
crate::malloc::limit_mmap_threshold(threshold);
|
||||
}
|
||||
|
||||
if let Some(icon_theme) = settings.default_icon_theme.clone() {
|
||||
crate::icon_theme::set_default(icon_theme);
|
||||
if let Some(icon_theme) = settings.default_icon_theme.as_ref() {
|
||||
crate::icon_theme::set_default(icon_theme.clone());
|
||||
}
|
||||
|
||||
THEME
|
||||
|
|
|
|||
|
|
@ -162,8 +162,8 @@ pub(crate) fn wayland_handler(
|
|||
exit: false,
|
||||
tx,
|
||||
seat_state: SeatState::new(&globals, &qh),
|
||||
queue_handle: qh.clone(),
|
||||
activation_state: ActivationState::bind::<AppData>(&globals, &qh).ok(),
|
||||
queue_handle: qh,
|
||||
registry_state,
|
||||
};
|
||||
|
||||
|
|
|
|||
16
src/core.rs
16
src/core.rs
|
|
@ -361,8 +361,12 @@ impl Core {
|
|||
config_id: &'static str,
|
||||
) -> iced::Subscription<cosmic_config::Update<T>> {
|
||||
#[cfg(all(feature = "dbus-config", target_os = "linux"))]
|
||||
if let Some(settings_daemon) = self.settings_daemon.clone() {
|
||||
return cosmic_config::dbus::watcher_subscription(settings_daemon, config_id, false);
|
||||
if let Some(settings_daemon) = self.settings_daemon.as_ref() {
|
||||
return cosmic_config::dbus::watcher_subscription(
|
||||
settings_daemon.clone(),
|
||||
config_id,
|
||||
false,
|
||||
);
|
||||
}
|
||||
cosmic_config::config_subscription(
|
||||
std::any::TypeId::of::<T>(),
|
||||
|
|
@ -378,8 +382,12 @@ impl Core {
|
|||
state_id: &'static str,
|
||||
) -> iced::Subscription<cosmic_config::Update<T>> {
|
||||
#[cfg(all(feature = "dbus-config", target_os = "linux"))]
|
||||
if let Some(settings_daemon) = self.settings_daemon.clone() {
|
||||
return cosmic_config::dbus::watcher_subscription(settings_daemon, state_id, true);
|
||||
if let Some(settings_daemon) = self.settings_daemon.as_ref() {
|
||||
return cosmic_config::dbus::watcher_subscription(
|
||||
settings_daemon.clone(),
|
||||
state_id,
|
||||
true,
|
||||
);
|
||||
}
|
||||
cosmic_config::config_subscription(
|
||||
std::any::TypeId::of::<T>(),
|
||||
|
|
|
|||
|
|
@ -113,10 +113,7 @@ pub fn about<'a, Message: Clone + 'static>(
|
|||
|
||||
let section = |list: &'a Vec<(String, String)>, title: String| {
|
||||
(!list.is_empty()).then_some({
|
||||
let items: Vec<Element<Message>> = list
|
||||
.iter()
|
||||
.map(|(name, url)| section_button(name, url))
|
||||
.collect();
|
||||
let items = list.iter().map(|(name, url)| section_button(name, url));
|
||||
widget::settings::section().title(title).extend(items)
|
||||
})
|
||||
};
|
||||
|
|
|
|||
|
|
@ -179,8 +179,8 @@ where
|
|||
));
|
||||
}
|
||||
|
||||
let content_list = column::with_children(vec![
|
||||
row::with_children(vec![
|
||||
let content_list = column::with_children([
|
||||
row::with_children([
|
||||
date.into(),
|
||||
crate::widget::Space::with_width(Length::Fill).into(),
|
||||
month_controls.into(),
|
||||
|
|
|
|||
|
|
@ -455,10 +455,7 @@ where
|
|||
// TODO get global colors from some cache?
|
||||
// TODO how to handle overflow? should this use a grid widget for the list or a horizontal scroll and a limit for the max?
|
||||
crate::widget::scrollable(
|
||||
Row::with_children(
|
||||
self.recent_colors
|
||||
.iter()
|
||||
.map(|c| {
|
||||
Row::with_children(self.recent_colors.iter().map(|c| {
|
||||
let initial_srgb = palette::Srgb::from(*c);
|
||||
let hsv = palette::Hsv::from_color(initial_srgb);
|
||||
color_button(
|
||||
|
|
@ -467,9 +464,7 @@ where
|
|||
Length::FillPortion(12),
|
||||
)
|
||||
.into()
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}))
|
||||
.padding([0.0, 0.0, f32::from(spacing.space_m), 0.0])
|
||||
.spacing(spacing.space_xxs),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -158,8 +158,7 @@ impl<'a, Message: Clone + 'static> From<Dialog<'a, Message>> for Element<'a, Mes
|
|||
}
|
||||
|
||||
let mut container = widget::container(
|
||||
widget::column::with_children(vec![content_row.into(), button_row.into()])
|
||||
.spacing(space_l),
|
||||
widget::column::with_children([content_row.into(), button_row.into()]).spacing(space_l),
|
||||
)
|
||||
.class(style::Container::Dialog)
|
||||
.padding(space_m)
|
||||
|
|
|
|||
|
|
@ -477,8 +477,8 @@ where
|
|||
if cursor.is_over(layout.bounds()) {
|
||||
if let Some(index) = *hovered_guard {
|
||||
shell.publish((self.on_selected)(index));
|
||||
if let Some(close_on_selected) = self.close_on_selected.clone() {
|
||||
shell.publish(close_on_selected);
|
||||
if let Some(close_on_selected) = self.close_on_selected.as_ref() {
|
||||
shell.publish(close_on_selected.clone());
|
||||
}
|
||||
return event::Status::Captured;
|
||||
}
|
||||
|
|
@ -521,8 +521,8 @@ where
|
|||
|
||||
if let Some(index) = *hovered_guard {
|
||||
shell.publish((self.on_selected)(index));
|
||||
if let Some(close_on_selected) = self.close_on_selected.clone() {
|
||||
shell.publish(close_on_selected);
|
||||
if let Some(close_on_selected) = self.close_on_selected.as_ref() {
|
||||
shell.publish(close_on_selected.clone());
|
||||
}
|
||||
return event::Status::Captured;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -521,8 +521,8 @@ pub fn draw<'a, S, Item: Clone + PartialEq + 'static>(
|
|||
style.background,
|
||||
);
|
||||
|
||||
if let Some(handle) = state.icon.clone() {
|
||||
let svg_handle = iced_core::Svg::new(handle).color(style.text_color);
|
||||
if let Some(handle) = state.icon.as_ref() {
|
||||
let svg_handle = iced_core::Svg::new(handle.clone()).color(style.text_color);
|
||||
svg::Renderer::draw_svg(
|
||||
renderer,
|
||||
svg_handle,
|
||||
|
|
|
|||
|
|
@ -1653,7 +1653,7 @@ fn get_children_layout<Message>(
|
|||
let child_sizes: Vec<Size> = match item_height {
|
||||
ItemHeight::Uniform(u) => {
|
||||
let count = menu_tree.children.len();
|
||||
(0..count).map(|_| Size::new(width, f32::from(u))).collect()
|
||||
vec![Size::new(width, f32::from(u)); count]
|
||||
}
|
||||
ItemHeight::Static(s) => menu_tree
|
||||
.children
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ where
|
|||
Message: std::clone::Clone + 'a,
|
||||
{
|
||||
widget::button::custom(
|
||||
widget::Row::with_children(children)
|
||||
widget::Row::from_vec(children)
|
||||
.align_y(Alignment::Center)
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill),
|
||||
|
|
@ -252,7 +252,7 @@ pub fn menu_items<
|
|||
let l: Cow<'static, str> = label.into();
|
||||
let key = find_key(&action, key_binds);
|
||||
let mut items = vec![
|
||||
widget::text(l.clone()).into(),
|
||||
widget::text(l).into(),
|
||||
widget::horizontal_space().into(),
|
||||
widget::text(key).class(key_class).into(),
|
||||
];
|
||||
|
|
@ -272,7 +272,7 @@ pub fn menu_items<
|
|||
let key = find_key(&action, key_binds);
|
||||
|
||||
let mut items = vec![
|
||||
widget::text(l.clone()).into(),
|
||||
widget::text(l).into(),
|
||||
widget::horizontal_space().into(),
|
||||
widget::text(key).class(key_class).into(),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -147,12 +147,14 @@ pub mod column {
|
|||
#[must_use]
|
||||
/// A pre-allocated [`column`].
|
||||
pub fn with_capacity<'a, Message>(capacity: usize) -> Column<'a, Message> {
|
||||
Column::with_children(Vec::with_capacity(capacity))
|
||||
Column::with_capacity(capacity)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// A [`column`] that will be assigned a [`Vec`] of children.
|
||||
pub fn with_children<Message>(children: Vec<crate::Element<Message>>) -> Column<Message> {
|
||||
/// A [`column`] that will be assigned an [`Iterator`] of children.
|
||||
pub fn with_children<'a, Message>(
|
||||
children: impl IntoIterator<Item = crate::Element<'a, Message>>,
|
||||
) -> Column<'a, Message> {
|
||||
Column::with_children(children)
|
||||
}
|
||||
}
|
||||
|
|
@ -298,12 +300,14 @@ pub mod row {
|
|||
#[must_use]
|
||||
/// A pre-allocated [`row`].
|
||||
pub fn with_capacity<'a, Message>(capacity: usize) -> Row<'a, Message> {
|
||||
Row::with_children(Vec::with_capacity(capacity))
|
||||
Row::with_capacity(capacity)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
/// A [`row`] that will be assigned a [`Vec`] of children.
|
||||
pub fn with_children<Message>(children: Vec<crate::Element<Message>>) -> Row<Message> {
|
||||
/// A [`row`] that will be assigned an [`Iterator`] of children.
|
||||
pub fn with_children<'a, Message>(
|
||||
children: impl IntoIterator<Item = crate::Element<'a, Message>>,
|
||||
) -> Row<'a, Message> {
|
||||
Row::with_children(children)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,14 +141,14 @@ where
|
|||
if matches!(event, Event::Mouse(_) | Event::Touch(_)) {
|
||||
return event::Status::Captured;
|
||||
}
|
||||
} else if let Some(on_close) = self.on_close.clone() {
|
||||
} else if let Some(on_close) = self.on_close.as_ref() {
|
||||
if matches!(
|
||||
event,
|
||||
Event::Mouse(mouse::Event::ButtonPressed(_))
|
||||
| Event::Touch(touch::Event::FingerPressed { .. })
|
||||
) && !cursor_position.is_over(layout.bounds())
|
||||
{
|
||||
shell.publish(on_close);
|
||||
shell.publish(on_close.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,7 +274,7 @@ where
|
|||
self.on_dnd_drop = Some(Box::new(move |entity, data, mime, action| {
|
||||
dnd_drop_handler(entity, D::try_from((data, mime)).ok(), action)
|
||||
}));
|
||||
self.mimes = D::allowed().iter().cloned().collect();
|
||||
self.mimes = D::allowed().into_owned();
|
||||
self
|
||||
}
|
||||
|
||||
|
|
@ -1867,7 +1867,7 @@ fn draw_icon<Message: 'static>(
|
|||
});
|
||||
|
||||
Widget::<Message, crate::Theme, Renderer>::draw(
|
||||
Element::<Message>::from(icon.clone()).as_widget(),
|
||||
Element::<Message>::from(icon).as_widget(),
|
||||
&Tree::empty(),
|
||||
renderer,
|
||||
theme,
|
||||
|
|
|
|||
|
|
@ -170,7 +170,6 @@ where
|
|||
)
|
||||
.apply(Element::from)
|
||||
})
|
||||
.collect::<Vec<Element<'a, Message>>>()
|
||||
.apply(widget::column::with_children)
|
||||
.spacing(val.item_spacing)
|
||||
.padding(val.element_padding)
|
||||
|
|
|
|||
|
|
@ -125,7 +125,6 @@ where
|
|||
.apply(|mouse_area| widget::context_menu(mouse_area, cat_context_tree))
|
||||
.apply(Element::from)
|
||||
})
|
||||
.collect::<Vec<Element<'a, Message>>>()
|
||||
.apply(widget::row::with_children)
|
||||
.apply(Element::from);
|
||||
// Build the items
|
||||
|
|
@ -166,7 +165,6 @@ where
|
|||
.align_y(Alignment::Center)
|
||||
.apply(Element::from)
|
||||
})
|
||||
.collect::<Vec<Element<'static, Message>>>()
|
||||
.apply(widget::row::with_children)
|
||||
.apply(container)
|
||||
.padding(val.item_padding)
|
||||
|
|
|
|||
|
|
@ -760,14 +760,14 @@ where
|
|||
if state.dirty {
|
||||
state.dirty = false;
|
||||
let value = if self.is_secure {
|
||||
self.value.secure()
|
||||
&self.value.secure()
|
||||
} else {
|
||||
self.value.clone()
|
||||
&self.value
|
||||
};
|
||||
replace_paragraph(
|
||||
state,
|
||||
Layout::new(&res),
|
||||
&value,
|
||||
value,
|
||||
font,
|
||||
iced::Pixels(size),
|
||||
line_height,
|
||||
|
|
@ -2022,7 +2022,7 @@ pub fn update<'a, Message: Clone + 'static>(
|
|||
if let DndOfferState::HandlingOffer(mime_types, _action) = state.dnd_offer.clone() {
|
||||
let Some(mime_type) = SUPPORTED_TEXT_MIME_TYPES
|
||||
.iter()
|
||||
.find(|m| mime_types.contains(&(**m).to_string()))
|
||||
.find(|&&m| mime_types.iter().any(|t| t == m))
|
||||
else {
|
||||
state.dnd_offer = DndOfferState::None;
|
||||
return event::Status::Captured;
|
||||
|
|
@ -2057,7 +2057,7 @@ pub fn update<'a, Message: Clone + 'static>(
|
|||
{
|
||||
cold();
|
||||
let state = state();
|
||||
if let DndOfferState::Dropped = state.dnd_offer.clone() {
|
||||
if matches!(&state.dnd_offer, DndOfferState::Dropped) {
|
||||
state.dnd_offer = DndOfferState::None;
|
||||
if !SUPPORTED_TEXT_MIME_TYPES.contains(&mime_type.as_str()) || data.is_empty() {
|
||||
return event::Status::Captured;
|
||||
|
|
@ -2536,7 +2536,7 @@ impl AsMimeTypes for TextInputString {
|
|||
|
||||
fn as_bytes(&self, mime_type: &str) -> Option<Cow<'static, [u8]>> {
|
||||
if SUPPORTED_TEXT_MIME_TYPES.contains(&mime_type) {
|
||||
Some(Cow::Owned(self.0.clone().as_bytes().to_vec()))
|
||||
Some(Cow::Owned(self.0.clone().into_bytes()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue