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

feat(workspaces): support for using images in name_map

This commit is contained in:
Jake Stanger 2023-01-29 22:48:42 +00:00
parent 3cf9be89fd
commit b054c17d14
No known key found for this signature in database
GPG key ID: C51FC8F9CB0BEA61
13 changed files with 132 additions and 64 deletions

48
src/image/gtk.rs Normal file
View file

@ -0,0 +1,48 @@
use super::ImageProvider;
use gtk::prelude::*;
use gtk::{Button, IconTheme, Image, Label, Orientation};
use tracing::error;
pub fn new_icon_button(input: &str, icon_theme: &IconTheme, size: i32) -> Button {
let button = Button::new();
if ImageProvider::is_definitely_image_input(input) {
let image = Image::new();
match ImageProvider::parse(input, icon_theme, size)
.and_then(|provider| provider.load_into_image(image.clone()))
{
Ok(_) => {
button.set_image(Some(&image));
button.set_always_show_image(true);
}
Err(err) => {
error!("{err:?}");
button.set_label(input);
}
}
} else {
button.set_label(input);
}
button
}
pub fn new_icon_label(input: &str, icon_theme: &IconTheme, size: i32) -> gtk::Box {
let container = gtk::Box::new(Orientation::Horizontal, 0);
if ImageProvider::is_definitely_image_input(input) {
let image = Image::new();
container.add(&image);
if let Err(err) = ImageProvider::parse(input, icon_theme, size)
.and_then(|provider| provider.load_into_image(image))
{
error!("{err:?}");
}
} else {
let label = Label::new(Some(input));
container.add(&label);
}
container
}

5
src/image/mod.rs Normal file
View file

@ -0,0 +1,5 @@
mod gtk;
mod provider;
pub use self::gtk::*;
pub use provider::ImageProvider;

View file

@ -30,7 +30,7 @@ impl<'a> ImageProvider<'a> {
///
/// Note this checks that icons exist in theme, or files exist on disk
/// but no other check is performed.
pub fn parse(input: String, theme: &'a IconTheme, size: i32) -> Result<Self> {
pub fn parse(input: &str, theme: &'a IconTheme, size: i32) -> Result<Self> {
let location = Self::get_location(input, theme, size)?;
Ok(Self { location, size })
}
@ -45,11 +45,10 @@ impl<'a> ImageProvider<'a> {
|| input.starts_with("https://")
}
fn get_location(input: String, theme: &'a IconTheme, size: i32) -> Result<ImageLocation> {
fn get_location(input: &str, theme: &'a IconTheme, size: i32) -> Result<ImageLocation<'a>> {
let (input_type, input_name) = input
.split_once(':')
.map(|(t, n)| (Some(t), n))
.unwrap_or((None, &input));
.map_or((None, input), |(t, n)| (Some(t), n));
match input_type {
Some(input_type) if input_type == "icon" => Ok(ImageLocation::Icon {
@ -66,7 +65,7 @@ impl<'a> ImageProvider<'a> {
input_name.chars().skip("steam_app_".len()).collect(),
)),
None if theme
.lookup_icon(&input, size, IconLookupFlags::empty())
.lookup_icon(input, size, IconLookupFlags::empty())
.is_some() =>
{
Ok(ImageLocation::Icon {
@ -78,10 +77,10 @@ impl<'a> ImageProvider<'a> {
None if PathBuf::from(input_name).exists() => {
Ok(ImageLocation::Local(PathBuf::from(input_name)))
}
None => match get_desktop_icon_name(input_name) {
Some(input) => Self::get_location(input, theme, size),
None => Err(Report::msg("Unknown image type")),
},
None => get_desktop_icon_name(input_name).map_or_else(
|| Err(Report::msg("Unknown image type")),
|input| Self::get_location(&input, theme, size),
),
}
}
@ -120,8 +119,6 @@ impl<'a> ImageProvider<'a> {
Continue(false)
});
}
Ok(())
} else {
let pixbuf = match &self.location {
ImageLocation::Icon { name, theme } => self.get_from_icon(name, theme),
@ -131,8 +128,9 @@ impl<'a> ImageProvider<'a> {
}?;
image.set_pixbuf(Some(&pixbuf));
Ok(())
}
};
Ok(())
}
/// Attempts to get a `Pixbuf` from the GTK icon theme.
@ -142,10 +140,10 @@ impl<'a> ImageProvider<'a> {
None => Ok(None),
}?;
match pixbuf {
Some(pixbuf) => Ok(pixbuf),
None => Err(Report::msg("Icon theme does not contain icon '{name}'")),
}
pixbuf.map_or_else(
|| Err(Report::msg("Icon theme does not contain icon '{name}'")),
Ok,
)
}
/// Attempts to get a `Pixbuf` from a local file.
@ -158,12 +156,14 @@ impl<'a> ImageProvider<'a> {
/// using the Steam game ID to look it up.
fn get_from_steam_id(&self, steam_id: &str) -> Result<Pixbuf> {
// TODO: Can we load this from icon theme with app id `steam_icon_{}`?
let path = match dirs::data_dir() {
Some(dir) => Ok(dir.join(format!(
"icons/hicolor/32x32/apps/steam_icon_{steam_id}.png"
))),
None => Err(Report::msg("Missing XDG data dir")),
}?;
let path = dirs::data_dir().map_or_else(
|| Err(Report::msg("Missing XDG data dir")),
|dir| {
Ok(dir.join(format!(
"icons/hicolor/32x32/apps/steam_icon_{steam_id}.png"
)))
},
)?;
self.get_from_file(&path)
}

View file

@ -120,6 +120,8 @@ impl Module<Button> for ClockModule {
});
}
container.show_all();
Some(container)
}
}

View file

@ -103,9 +103,9 @@ impl Widget {
}
if let Some(widgets) = self.widgets {
widgets.into_iter().for_each(|widget| {
widget.add_to(&container, tx.clone(), bar_orientation, icon_theme)
});
for widget in widgets {
widget.add_to(&container, tx.clone(), bar_orientation, icon_theme);
}
}
container
@ -185,7 +185,7 @@ impl Widget {
if let Some(src) = self.src {
let size = self.size.unwrap_or(32);
if let Err(err) = ImageProvider::parse(src, icon_theme, size)
if let Err(err) = ImageProvider::parse(&src, icon_theme, size)
.and_then(|image| image.load_into_image(gtk_image.clone()))
{
error!("{err:?}");
@ -292,16 +292,18 @@ impl Module<gtk::Box> for CustomModule {
}
if let Some(popup) = self.popup {
popup.into_iter().for_each(|widget| {
for widget in popup {
widget.add_to(
&container,
tx.clone(),
Orientation::Horizontal,
info.icon_theme,
)
});
);
}
}
container.show_all();
Some(container)
}
}

View file

@ -111,7 +111,7 @@ impl Module<gtk::Box> for FocusedModule {
let icon_theme = icon_theme.clone();
context.widget_rx.attach(None, move |(name, id)| {
if self.show_icon {
if let Err(err) = ImageProvider::parse(id, &icon_theme, self.icon_size)
if let Err(err) = ImageProvider::parse(&id, &icon_theme, self.icon_size)
.and_then(|image| image.load_into_image(icon.clone()))
{
error!("{err:?}");

View file

@ -156,7 +156,7 @@ impl ItemButton {
if show_icons {
let gtk_image = gtk::Image::new();
let image = ImageProvider::parse(item.app_id.clone(), icon_theme, 32);
let image = ImageProvider::parse(&item.app_id.clone(), icon_theme, 32);
match image {
Ok(image) => {
button.set_image(Some(&gtk_image));

View file

@ -1,10 +1,11 @@
use crate::clients::compositor::{Compositor, WorkspaceUpdate};
use crate::config::CommonConfig;
use crate::image::new_icon_button;
use crate::modules::{Module, ModuleInfo, ModuleUpdateEvent, ModuleWidget, WidgetContext};
use crate::{send_async, try_send};
use color_eyre::{Report, Result};
use gtk::prelude::*;
use gtk::Button;
use gtk::{Button, IconTheme};
use serde::Deserialize;
use std::cmp::Ordering;
use std::collections::HashMap;
@ -49,12 +50,13 @@ fn create_button(
name: &str,
focused: bool,
name_map: &HashMap<String, String>,
icon_theme: &IconTheme,
tx: &Sender<String>,
) -> Button {
let button = Button::builder()
.label(name_map.get(name).map_or(name, String::as_str))
.name(name)
.build();
let label = name_map.get(name).map_or(name, String::as_str);
let button = new_icon_button(label, icon_theme, 32);
button.set_widget_name(name);
let style_context = button.style_context();
style_context.add_class("item");
@ -154,6 +156,7 @@ impl Module<gtk::Box> for WorkspacesModule {
{
let container = container.clone();
let output_name = info.output_name.to_string();
let icon_theme = info.icon_theme.clone();
// keep track of whether init event has fired previously
// since it fires for every workspace subscriber
@ -170,6 +173,7 @@ impl Module<gtk::Box> for WorkspacesModule {
&workspace.name,
workspace.focused,
&name_map,
&icon_theme,
&context.controller_tx,
);
container.add(&item);
@ -204,6 +208,7 @@ impl Module<gtk::Box> for WorkspacesModule {
&name,
workspace.focused,
&name_map,
&icon_theme,
&context.controller_tx,
);
@ -227,6 +232,7 @@ impl Module<gtk::Box> for WorkspacesModule {
&name,
workspace.focused,
&name_map,
&icon_theme,
&context.controller_tx,
);

View file

@ -133,7 +133,7 @@ impl Popup {
/// Shows the popup
pub fn show(&self, geometry: ButtonGeometry) {
self.window.show_all();
self.window.show();
self.set_pos(geometry);
}