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:
parent
3cf9be89fd
commit
b054c17d14
13 changed files with 132 additions and 64 deletions
48
src/image/gtk.rs
Normal file
48
src/image/gtk.rs
Normal 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
5
src/image/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
mod gtk;
|
||||
mod provider;
|
||||
|
||||
pub use self::gtk::*;
|
||||
pub use provider::ImageProvider;
|
|
@ -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)
|
||||
}
|
|
@ -120,6 +120,8 @@ impl Module<Button> for ClockModule {
|
|||
});
|
||||
}
|
||||
|
||||
container.show_all();
|
||||
|
||||
Some(container)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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:?}");
|
||||
|
|
|
@ -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(>k_image));
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue