1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-07-01 10:41:03 +02:00

fix: poor error handling for missing images

Previously images that could not be located were handled by throwing a
full report error, which incorrectly stated it was an invalid image
*type*.

This changes the image handling to instead log a single-line warning
directly in the image provider code, reducing the error handling
required by each consumer.

Resolves #146.
This commit is contained in:
Jake Stanger 2023-05-20 14:36:04 +01:00
parent 960da55a05
commit 87ca399220
7 changed files with 52 additions and 62 deletions

View file

@ -2,7 +2,6 @@ use super::ImageProvider;
use crate::gtk_helpers::add_class; use crate::gtk_helpers::add_class;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{Button, IconTheme, Image, Label, Orientation}; use gtk::{Button, IconTheme, Image, Label, Orientation};
use tracing::error;
#[cfg(any(feature = "music", feature = "workspaces", feature = "clipboard"))] #[cfg(any(feature = "music", feature = "workspaces", feature = "clipboard"))]
pub fn new_icon_button(input: &str, icon_theme: &IconTheme, size: i32) -> Button { pub fn new_icon_button(input: &str, icon_theme: &IconTheme, size: i32) -> Button {
@ -13,14 +12,13 @@ pub fn new_icon_button(input: &str, icon_theme: &IconTheme, size: i32) -> Button
add_class(&image, "image"); add_class(&image, "image");
match ImageProvider::parse(input, icon_theme, size) match ImageProvider::parse(input, icon_theme, size)
.and_then(|provider| provider.load_into_image(image.clone())) .map(|provider| provider.load_into_image(image.clone()))
{ {
Ok(_) => { Some(_) => {
button.set_image(Some(&image)); button.set_image(Some(&image));
button.set_always_show_image(true); button.set_always_show_image(true);
} }
Err(err) => { None => {
error!("{err:?}");
button.set_label(input); button.set_label(input);
} }
} }
@ -41,11 +39,8 @@ pub fn new_icon_label(input: &str, icon_theme: &IconTheme, size: i32) -> gtk::Bo
container.add(&image); container.add(&image);
if let Err(err) = ImageProvider::parse(input, icon_theme, size) ImageProvider::parse(input, icon_theme, size)
.and_then(|provider| provider.load_into_image(image)) .map(|provider| provider.load_into_image(image));
{
error!("{err:?}");
}
} else { } else {
let label = Label::new(Some(input)); let label = Label::new(Some(input));
add_class(&label, "label"); add_class(&label, "label");

View file

@ -7,6 +7,7 @@ use gtk::gdk_pixbuf::Pixbuf;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::{IconLookupFlags, IconTheme}; use gtk::{IconLookupFlags, IconTheme};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use tracing::warn;
cfg_if!( cfg_if!(
if #[cfg(feature = "http")] { if #[cfg(feature = "http")] {
@ -40,9 +41,9 @@ impl<'a> ImageProvider<'a> {
/// ///
/// Note this checks that icons exist in theme, or files exist on disk /// Note this checks that icons exist in theme, or files exist on disk
/// but no other check is performed. /// but no other check is performed.
pub fn parse(input: &str, theme: &'a IconTheme, size: i32) -> Result<Self> { pub fn parse(input: &str, theme: &'a IconTheme, size: i32) -> Option<Self> {
let location = Self::get_location(input, theme, size)?; let location = Self::get_location(input, theme, size)?;
Ok(Self { location, size }) Some(Self { location, size })
} }
/// Returns true if the input starts with a prefix /// Returns true if the input starts with a prefix
@ -56,44 +57,56 @@ impl<'a> ImageProvider<'a> {
|| input.starts_with("https://") || input.starts_with("https://")
} }
fn get_location(input: &str, theme: &'a IconTheme, size: i32) -> Result<ImageLocation<'a>> { fn get_location(input: &str, theme: &'a IconTheme, size: i32) -> Option<ImageLocation<'a>> {
let (input_type, input_name) = input let (input_type, input_name) = input
.split_once(':') .split_once(':')
.map_or((None, input), |(t, n)| (Some(t), n)); .map_or((None, input), |(t, n)| (Some(t), n));
match input_type { match input_type {
Some(input_type) if input_type == "icon" => Ok(ImageLocation::Icon { Some(input_type) if input_type == "icon" => Some(ImageLocation::Icon {
name: input_name.to_string(), name: input_name.to_string(),
theme, theme,
}), }),
Some(input_type) if input_type == "file" => Ok(ImageLocation::Local(PathBuf::from( Some(input_type) if input_type == "file" => Some(ImageLocation::Local(PathBuf::from(
input_name[2..].to_string(), input_name[2..].to_string(),
))), ))),
#[cfg(feature = "http")] #[cfg(feature = "http")]
Some(input_type) if input_type == "http" || input_type == "https" => { Some(input_type) if input_type == "http" || input_type == "https" => {
Ok(ImageLocation::Remote(input.parse()?)) input.parse().ok().map(ImageLocation::Remote)
} }
None if input.starts_with("steam_app_") => Ok(ImageLocation::Steam( None if input.starts_with("steam_app_") => Some(ImageLocation::Steam(
input_name.chars().skip("steam_app_".len()).collect(), input_name.chars().skip("steam_app_".len()).collect(),
)), )),
None if theme None if theme
.lookup_icon(input, size, IconLookupFlags::empty()) .lookup_icon(input, size, IconLookupFlags::empty())
.is_some() => .is_some() =>
{ {
Ok(ImageLocation::Icon { Some(ImageLocation::Icon {
name: input_name.to_string(), name: input_name.to_string(),
theme, theme,
}) })
} }
Some(input_type) => Err(Report::msg(format!("Unsupported image type: {input_type}")) Some(input_type) => {
.note("You may need to recompile with support if available")), warn!(
None if PathBuf::from(input_name).is_file() => { "{:?}",
Ok(ImageLocation::Local(PathBuf::from(input_name))) Report::msg(format!("Unsupported image type: {input_type}"))
.note("You may need to recompile with support if available")
);
None
}
None if PathBuf::from(input_name).is_file() => {
Some(ImageLocation::Local(PathBuf::from(input_name)))
}
None => {
if let Some(location) = get_desktop_icon_name(input_name)
.map(|input| Self::get_location(&input, theme, size))
{
location
} else {
warn!("Failed to find image: {input}");
None
}
} }
None => get_desktop_icon_name(input_name).map_or_else(
|| Err(Report::msg(format!("Unknown image type: '{input}'"))),
|input| Self::get_location(&input, theme, size),
),
} }
} }

View file

@ -5,7 +5,6 @@ use crate::image::ImageProvider;
use gtk::prelude::*; use gtk::prelude::*;
use gtk::Image; use gtk::Image;
use serde::Deserialize; use serde::Deserialize;
use tracing::error;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct ImageWidget { pub struct ImageWidget {
@ -31,12 +30,8 @@ impl CustomWidget for ImageWidget {
let icon_theme = context.icon_theme.clone(); let icon_theme = context.icon_theme.clone();
DynamicString::new(&self.src, move |src| { DynamicString::new(&self.src, move |src| {
let res = ImageProvider::parse(&src, &icon_theme, self.size) ImageProvider::parse(&src, &icon_theme, self.size)
.and_then(|image| image.load_into_image(gtk_image.clone())); .map(|image| image.load_into_image(gtk_image.clone()));
if let Err(err) = res {
error!("{err:?}");
}
Continue(true) Continue(true)
}); });

View file

@ -11,7 +11,7 @@ use gtk::Label;
use serde::Deserialize; use serde::Deserialize;
use tokio::spawn; use tokio::spawn;
use tokio::sync::mpsc::{Receiver, Sender}; use tokio::sync::mpsc::{Receiver, Sender};
use tracing::{debug, error}; use tracing::debug;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct FocusedModule { pub struct FocusedModule {
@ -113,11 +113,8 @@ impl Module<gtk::Box> for FocusedModule {
let icon_theme = icon_theme.clone(); let icon_theme = icon_theme.clone();
context.widget_rx.attach(None, move |(name, id)| { context.widget_rx.attach(None, move |(name, id)| {
if self.show_icon { if self.show_icon {
if let Err(err) = ImageProvider::parse(&id, &icon_theme, self.icon_size) ImageProvider::parse(&id, &icon_theme, self.icon_size)
.and_then(|image| image.load_into_image(icon.clone())) .map(|image| image.load_into_image(icon.clone()));
{
error!("{err:?}");
}
} }
if self.show_title { if self.show_title {

View file

@ -192,16 +192,13 @@ impl ItemButton {
let gtk_image = gtk::Image::new(); let gtk_image = gtk::Image::new();
let image = let image =
ImageProvider::parse(&item.app_id.clone(), icon_theme, appearance.icon_size); ImageProvider::parse(&item.app_id.clone(), icon_theme, appearance.icon_size);
match image { if let Some(image) = image {
Ok(image) => { button.set_image(Some(&gtk_image));
button.set_image(Some(&gtk_image)); button.set_always_show_image(true);
button.set_always_show_image(true);
if let Err(err) = image.load_into_image(gtk_image) { if let Err(err) = image.load_into_image(gtk_image) {
error!("{err:?}"); error!("{err:?}");
}
} }
Err(err) => error!("{err:?}"),
}; };
} }

View file

@ -342,19 +342,15 @@ impl Module<Button> for MusicModule {
let new_cover = update.song.cover_path; let new_cover = update.song.cover_path;
if prev_cover != new_cover { if prev_cover != new_cover {
prev_cover = new_cover.clone(); prev_cover = new_cover.clone();
let res = match new_cover.map(|cover_path| { let res = if let Some(image) = new_cover.and_then(|cover_path| {
ImageProvider::parse(&cover_path, &icon_theme, image_size) ImageProvider::parse(&cover_path, &icon_theme, image_size)
}) { }) {
Some(Ok(image)) => image.load_into_image(album_image.clone()), image.load_into_image(album_image.clone())
Some(Err(err)) => { } else {
album_image.set_from_pixbuf(None); album_image.set_from_pixbuf(None);
Err(err) Ok(())
}
None => {
album_image.set_from_pixbuf(None);
Ok(())
}
}; };
if let Err(err) = res { if let Err(err) = res {
error!("{err:?}"); error!("{err:?}");
} }

View file

@ -180,11 +180,8 @@ impl Module<gtk::Box> for UpowerModule {
.attach(None, move |properties: UpowerProperties| { .attach(None, move |properties: UpowerProperties| {
let format = format.replace("{percentage}", &properties.percentage.to_string()); let format = format.replace("{percentage}", &properties.percentage.to_string());
let icon_name = String::from("icon:") + &properties.icon_name; let icon_name = String::from("icon:") + &properties.icon_name;
if let Err(err) = ImageProvider::parse(&icon_name, &icon_theme, 32) ImageProvider::parse(&icon_name, &icon_theme, 32)
.and_then(|provider| provider.load_into_image(icon.clone())) .map(|provider| provider.load_into_image(icon.clone()));
{
error!("{err:?}");
}
label.set_markup(format.as_ref()); label.set_markup(format.as_ref());
Continue(true) Continue(true)
}); });