fix(sni): render attention and overlay tray icon assets
Load attention and overlay pixmaps from item properties, watch the corresponding update signals, and prefer attention artwork while an item is in NeedsAttention state. When an item only exports an attention movie asset, fall back to loading that asset as a static pixbuf so the tray still shows the alert state. Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
This commit is contained in:
@@ -48,7 +48,9 @@ class Item : public sigc::trackable {
|
|||||||
Glib::RefPtr<Gdk::Pixbuf> icon_pixmap;
|
Glib::RefPtr<Gdk::Pixbuf> icon_pixmap;
|
||||||
Glib::RefPtr<Gtk::IconTheme> icon_theme;
|
Glib::RefPtr<Gtk::IconTheme> icon_theme;
|
||||||
std::string overlay_icon_name;
|
std::string overlay_icon_name;
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> overlay_icon_pixmap;
|
||||||
std::string attention_icon_name;
|
std::string attention_icon_name;
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> attention_icon_pixmap;
|
||||||
std::string attention_movie_name;
|
std::string attention_movie_name;
|
||||||
std::string icon_theme_path;
|
std::string icon_theme_path;
|
||||||
std::string menu;
|
std::string menu;
|
||||||
@@ -76,8 +78,13 @@ class Item : public sigc::trackable {
|
|||||||
const Glib::VariantContainerBase& arguments);
|
const Glib::VariantContainerBase& arguments);
|
||||||
|
|
||||||
void updateImage();
|
void updateImage();
|
||||||
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant);
|
static Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant* variant);
|
||||||
Glib::RefPtr<Gdk::Pixbuf> getIconPixbuf();
|
Glib::RefPtr<Gdk::Pixbuf> getIconPixbuf();
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> getAttentionIconPixbuf();
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> getOverlayIconPixbuf();
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> loadIconFromNameOrFile(const std::string& name, bool log_failure);
|
||||||
|
static Glib::RefPtr<Gdk::Pixbuf> overlayPixbufs(const Glib::RefPtr<Gdk::Pixbuf>&,
|
||||||
|
const Glib::RefPtr<Gdk::Pixbuf>&);
|
||||||
Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size);
|
Glib::RefPtr<Gdk::Pixbuf> getIconByName(const std::string& name, int size);
|
||||||
double getScaledIconSize();
|
double getScaledIconSize();
|
||||||
static void onMenuDestroyed(Item* self, GObject* old_menu_pointer);
|
static void onMenuDestroyed(Item* self, GObject* old_menu_pointer);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <gtkmm/tooltip.h>
|
#include <gtkmm/tooltip.h>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <map>
|
#include <map>
|
||||||
@@ -195,11 +196,11 @@ void Item::setProperty(const Glib::ustring& name, Glib::VariantBase& value) {
|
|||||||
} else if (name == "OverlayIconName") {
|
} else if (name == "OverlayIconName") {
|
||||||
overlay_icon_name = get_variant<std::string>(value);
|
overlay_icon_name = get_variant<std::string>(value);
|
||||||
} else if (name == "OverlayIconPixmap") {
|
} else if (name == "OverlayIconPixmap") {
|
||||||
// TODO: overlay_icon_pixmap
|
overlay_icon_pixmap = extractPixBuf(value.gobj());
|
||||||
} else if (name == "AttentionIconName") {
|
} else if (name == "AttentionIconName") {
|
||||||
attention_icon_name = get_variant<std::string>(value);
|
attention_icon_name = get_variant<std::string>(value);
|
||||||
} else if (name == "AttentionIconPixmap") {
|
} else if (name == "AttentionIconPixmap") {
|
||||||
// TODO: attention_icon_pixmap
|
attention_icon_pixmap = extractPixBuf(value.gobj());
|
||||||
} else if (name == "AttentionMovieName") {
|
} else if (name == "AttentionMovieName") {
|
||||||
attention_movie_name = get_variant<std::string>(value);
|
attention_movie_name = get_variant<std::string>(value);
|
||||||
} else if (name == "ToolTip") {
|
} else if (name == "ToolTip") {
|
||||||
@@ -315,8 +316,8 @@ void Item::processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& _result) {
|
|||||||
static const std::map<std::string_view, std::set<std::string_view>> signal2props = {
|
static const std::map<std::string_view, std::set<std::string_view>> signal2props = {
|
||||||
{"NewTitle", {"Title"}},
|
{"NewTitle", {"Title"}},
|
||||||
{"NewIcon", {"IconName", "IconPixmap"}},
|
{"NewIcon", {"IconName", "IconPixmap"}},
|
||||||
// {"NewAttentionIcon", {"AttentionIconName", "AttentionIconPixmap", "AttentionMovieName"}},
|
{"NewAttentionIcon", {"AttentionIconName", "AttentionIconPixmap", "AttentionMovieName"}},
|
||||||
// {"NewOverlayIcon", {"OverlayIconName", "OverlayIconPixmap"}},
|
{"NewOverlayIcon", {"OverlayIconName", "OverlayIconPixmap"}},
|
||||||
{"NewIconThemePath", {"IconThemePath"}},
|
{"NewIconThemePath", {"IconThemePath"}},
|
||||||
{"NewToolTip", {"ToolTip"}},
|
{"NewToolTip", {"ToolTip"}},
|
||||||
{"NewStatus", {"Status"}},
|
{"NewStatus", {"Status"}},
|
||||||
@@ -406,36 +407,24 @@ void Item::updateImage() {
|
|||||||
pixbuf = pixbuf->scale_simple(width, scaled_icon_size, Gdk::InterpType::INTERP_BILINEAR);
|
pixbuf = pixbuf->scale_simple(width, scaled_icon_size, Gdk::InterpType::INTERP_BILINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pixbuf = overlayPixbufs(pixbuf, getOverlayIconPixbuf());
|
||||||
|
|
||||||
auto surface =
|
auto surface =
|
||||||
Gdk::Cairo::create_surface_from_pixbuf(pixbuf, image.get_scale_factor(), image.get_window());
|
Gdk::Cairo::create_surface_from_pixbuf(pixbuf, image.get_scale_factor(), image.get_window());
|
||||||
image.set(surface);
|
image.set(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> Item::getIconPixbuf() {
|
Glib::RefPtr<Gdk::Pixbuf> Item::getIconPixbuf() {
|
||||||
if (!icon_name.empty()) {
|
if (status_ == "needsattention") {
|
||||||
try {
|
if (auto attention_pixbuf = getAttentionIconPixbuf()) {
|
||||||
std::ifstream temp(icon_name);
|
return attention_pixbuf;
|
||||||
if (temp.is_open()) {
|
|
||||||
return Gdk::Pixbuf::create_from_file(icon_name);
|
|
||||||
}
|
|
||||||
} catch (Glib::Error& e) {
|
|
||||||
// Ignore because we want to also try different methods of getting an icon.
|
|
||||||
//
|
|
||||||
// But a warning is logged, as the file apparently exists, but there was
|
|
||||||
// a failure in creating a pixbuf out of it.
|
|
||||||
|
|
||||||
spdlog::warn("Item '{}': {}", id, static_cast<std::string>(e.what()));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Will throw if it can not find an icon.
|
|
||||||
return getIconByName(icon_name, getScaledIconSize());
|
|
||||||
} catch (Glib::Error& e) {
|
|
||||||
spdlog::trace("Item '{}': {}", id, static_cast<std::string>(e.what()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the pixmap only if an icon for the given name could not be found.
|
if (auto pixbuf = loadIconFromNameOrFile(icon_name, true)) {
|
||||||
|
return pixbuf;
|
||||||
|
}
|
||||||
|
|
||||||
if (icon_pixmap) {
|
if (icon_pixmap) {
|
||||||
return icon_pixmap;
|
return icon_pixmap;
|
||||||
}
|
}
|
||||||
@@ -450,6 +439,77 @@ Glib::RefPtr<Gdk::Pixbuf> Item::getIconPixbuf() {
|
|||||||
return getIconByName("image-missing", getScaledIconSize());
|
return getIconByName("image-missing", getScaledIconSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> Item::getAttentionIconPixbuf() {
|
||||||
|
if (auto pixbuf = loadIconFromNameOrFile(attention_icon_name, false)) {
|
||||||
|
return pixbuf;
|
||||||
|
}
|
||||||
|
if (auto pixbuf = loadIconFromNameOrFile(attention_movie_name, false)) {
|
||||||
|
return pixbuf;
|
||||||
|
}
|
||||||
|
return attention_icon_pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> Item::getOverlayIconPixbuf() {
|
||||||
|
if (auto pixbuf = loadIconFromNameOrFile(overlay_icon_name, false)) {
|
||||||
|
return pixbuf;
|
||||||
|
}
|
||||||
|
return overlay_icon_pixmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> Item::loadIconFromNameOrFile(const std::string& name, bool log_failure) {
|
||||||
|
if (name.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
std::ifstream temp(name);
|
||||||
|
if (temp.is_open()) {
|
||||||
|
return Gdk::Pixbuf::create_from_file(name);
|
||||||
|
}
|
||||||
|
} catch (const Glib::Error& e) {
|
||||||
|
if (log_failure) {
|
||||||
|
spdlog::warn("Item '{}': {}", id, static_cast<std::string>(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return getIconByName(name, getScaledIconSize());
|
||||||
|
} catch (const Glib::Error& e) {
|
||||||
|
if (log_failure) {
|
||||||
|
spdlog::trace("Item '{}': {}", id, static_cast<std::string>(e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
Glib::RefPtr<Gdk::Pixbuf> Item::overlayPixbufs(const Glib::RefPtr<Gdk::Pixbuf>& base,
|
||||||
|
const Glib::RefPtr<Gdk::Pixbuf>& overlay) {
|
||||||
|
if (!base || !overlay) {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto composed = base->copy();
|
||||||
|
if (!composed) {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
int overlay_target_size =
|
||||||
|
std::max(1, std::min(composed->get_width(), composed->get_height()) / 2);
|
||||||
|
auto scaled_overlay = overlay->scale_simple(overlay_target_size, overlay_target_size,
|
||||||
|
Gdk::InterpType::INTERP_BILINEAR);
|
||||||
|
if (!scaled_overlay) {
|
||||||
|
return composed;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dest_x = std::max(0, composed->get_width() - scaled_overlay->get_width());
|
||||||
|
int dest_y = std::max(0, composed->get_height() - scaled_overlay->get_height());
|
||||||
|
scaled_overlay->composite(composed, dest_x, dest_y, scaled_overlay->get_width(),
|
||||||
|
scaled_overlay->get_height(), dest_x, dest_y, 1.0, 1.0,
|
||||||
|
Gdk::InterpType::INTERP_BILINEAR, 255);
|
||||||
|
return composed;
|
||||||
|
}
|
||||||
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> Item::getIconByName(const std::string& name, int request_size) {
|
Glib::RefPtr<Gdk::Pixbuf> Item::getIconByName(const std::string& name, int request_size) {
|
||||||
if (!icon_theme_path.empty()) {
|
if (!icon_theme_path.empty()) {
|
||||||
auto icon_info = icon_theme->lookup_icon(name.c_str(), request_size,
|
auto icon_info = icon_theme->lookup_icon(name.c_str(), request_size,
|
||||||
|
|||||||
Reference in New Issue
Block a user