mirror of
https://github.com/scorpion-26/gBar.git
synced 2024-11-22 03:02:49 +00:00
SNI: Allow svgs as icons
To facilitate that, Texture now accepts GdkPixbuf instead of raw uint8_t[], because we can't convert svgs into uint8_t[] easily without the use of GdkPixbuf.
This commit is contained in:
parent
dc7c7b7902
commit
2420574c70
4 changed files with 91 additions and 45 deletions
|
@ -133,7 +133,7 @@ namespace Utils
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string FindFileWithName(const std::string& directory, const std::string& name, const std::string& extension)
|
inline std::string FindFileWithName(const std::string& directory, const std::string& name)
|
||||||
{
|
{
|
||||||
if (!std::filesystem::exists(directory))
|
if (!std::filesystem::exists(directory))
|
||||||
{
|
{
|
||||||
|
@ -143,7 +143,7 @@ namespace Utils
|
||||||
{
|
{
|
||||||
if (path.is_directory())
|
if (path.is_directory())
|
||||||
continue;
|
continue;
|
||||||
if (path.path().filename().string().find(name) != std::string::npos && path.path().extension().string() == extension)
|
if (path.path().filename().string().find(name) != std::string::npos)
|
||||||
{
|
{
|
||||||
return path.path().string();
|
return path.path().string();
|
||||||
}
|
}
|
||||||
|
|
120
src/SNI.cpp
120
src/SNI.cpp
|
@ -32,7 +32,7 @@ namespace SNI
|
||||||
std::string object;
|
std::string object;
|
||||||
size_t w = 0;
|
size_t w = 0;
|
||||||
size_t h = 0;
|
size_t h = 0;
|
||||||
uint8_t* iconData = nullptr;
|
GdkPixbuf* pixbuf = nullptr;
|
||||||
|
|
||||||
std::string tooltip = "";
|
std::string tooltip = "";
|
||||||
|
|
||||||
|
@ -54,6 +54,77 @@ namespace SNI
|
||||||
Widget* parentBox;
|
Widget* parentBox;
|
||||||
Widget* iconBox;
|
Widget* iconBox;
|
||||||
|
|
||||||
|
// Swap channels for the render format and create a pixbuf out of it
|
||||||
|
static GdkPixbuf* ToPixbuf(uint8_t* sniData, int32_t width, int32_t height)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < width * height; i++)
|
||||||
|
{
|
||||||
|
struct Px
|
||||||
|
{
|
||||||
|
// This should be bgra...
|
||||||
|
// Since source is ARGB32 in network order(=big-endian)
|
||||||
|
// and x86 Linux is little-endian, we *should* swap b and r...
|
||||||
|
uint8_t a, r, g, b;
|
||||||
|
};
|
||||||
|
Px& pixel = ((Px*)sniData)[i];
|
||||||
|
// Swap to create rgba
|
||||||
|
pixel = {pixel.r, pixel.g, pixel.b, pixel.a};
|
||||||
|
}
|
||||||
|
return gdk_pixbuf_new_from_data(
|
||||||
|
sniData, GDK_COLORSPACE_RGB, true, 8, width, height, width * 4,
|
||||||
|
+[](uint8_t* data, void*)
|
||||||
|
{
|
||||||
|
delete[] data;
|
||||||
|
},
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocates a pixbuf that contains a bitmap of the icon
|
||||||
|
static void ToPixbuf(const std::string& location, GdkPixbuf*& outPixbuf, size_t& outWidth, size_t& outHeight)
|
||||||
|
{
|
||||||
|
std::string ext = location.substr(location.find_last_of('.') + 1);
|
||||||
|
if (ext == "png" || ext == "jpg")
|
||||||
|
{
|
||||||
|
// png, load via svg
|
||||||
|
int width, height, channels;
|
||||||
|
stbi_uc* pixels = stbi_load(location.c_str(), &width, &height, &channels, STBI_rgb_alpha);
|
||||||
|
if (!pixels)
|
||||||
|
{
|
||||||
|
LOG("SNI: Cannot open " << location);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
outWidth = width;
|
||||||
|
outHeight = height;
|
||||||
|
uint8_t* iconData = new uint8_t[width * height * 4];
|
||||||
|
// Already rgba32
|
||||||
|
memcpy(iconData, pixels, width * height * 4);
|
||||||
|
stbi_image_free(pixels);
|
||||||
|
|
||||||
|
outPixbuf = gdk_pixbuf_new_from_data(
|
||||||
|
iconData, GDK_COLORSPACE_RGB, true, 8, width, height, width * 4,
|
||||||
|
+[](uint8_t* data, void*)
|
||||||
|
{
|
||||||
|
delete[] data;
|
||||||
|
},
|
||||||
|
nullptr);
|
||||||
|
}
|
||||||
|
else if (ext == "svg")
|
||||||
|
{
|
||||||
|
// Just a random size, this should be plenty enough wiggle room
|
||||||
|
outWidth = 64;
|
||||||
|
outHeight = 64;
|
||||||
|
|
||||||
|
// Use glib functions
|
||||||
|
GError* err = nullptr;
|
||||||
|
outPixbuf = gdk_pixbuf_new_from_file_at_scale(location.c_str(), outWidth, outHeight, true, &err);
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
LOG("SNI: Error loading svg " << location << ": " << err->message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static Item CreateItem(std::string&& name, std::string&& object)
|
static Item CreateItem(std::string&& name, std::string&& object)
|
||||||
{
|
{
|
||||||
Item item{};
|
Item item{};
|
||||||
|
@ -102,28 +173,16 @@ namespace SNI
|
||||||
LOG("SNI: Height: " << height);
|
LOG("SNI: Height: " << height);
|
||||||
item.w = width;
|
item.w = width;
|
||||||
item.h = height;
|
item.h = height;
|
||||||
item.iconData = new uint8_t[width * height * 4];
|
uint8_t* iconData = new uint8_t[width * height * 4];
|
||||||
|
|
||||||
uint8_t px = 0;
|
uint8_t px = 0;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (g_variant_iter_next(data, "y", &px))
|
while (g_variant_iter_next(data, "y", &px))
|
||||||
{
|
{
|
||||||
item.iconData[i] = px;
|
iconData[i] = px;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < width * height; i++)
|
item.pixbuf = ToPixbuf(iconData, width, height);
|
||||||
{
|
|
||||||
struct Px
|
|
||||||
{
|
|
||||||
// This should be bgra...
|
|
||||||
// Since source is ARGB32 in network order(=big-endian)
|
|
||||||
// and x86 Linux is little-endian, we *should* swap b and r...
|
|
||||||
uint8_t a, r, g, b;
|
|
||||||
};
|
|
||||||
Px& pixel = ((Px*)item.iconData)[i];
|
|
||||||
// Swap to create rgba
|
|
||||||
pixel = {pixel.r, pixel.g, pixel.b, pixel.a};
|
|
||||||
}
|
|
||||||
|
|
||||||
g_variant_iter_free(data);
|
g_variant_iter_free(data);
|
||||||
|
|
||||||
|
@ -148,7 +207,7 @@ namespace SNI
|
||||||
for (auto& dataDir : Utils::Split(dataDirs, ':'))
|
for (auto& dataDir : Utils::Split(dataDirs, ':'))
|
||||||
{
|
{
|
||||||
LOG("SNI: Searching icon " << iconName << " in " << dataDir << "/icons");
|
LOG("SNI: Searching icon " << iconName << " in " << dataDir << "/icons");
|
||||||
std::string path = Utils::FindFileWithName(dataDir + "/icons", iconName, ".png");
|
std::string path = Utils::FindFileWithName(dataDir + "/icons", iconName);
|
||||||
if (path != "")
|
if (path != "")
|
||||||
{
|
{
|
||||||
iconPath = path;
|
iconPath = path;
|
||||||
|
@ -161,7 +220,7 @@ namespace SNI
|
||||||
// Fallback to /usr/share/icons
|
// Fallback to /usr/share/icons
|
||||||
LOG("SNI: Searching icon " << iconName << " in "
|
LOG("SNI: Searching icon " << iconName << " in "
|
||||||
<< "/usr/share/icons");
|
<< "/usr/share/icons");
|
||||||
iconPath = Utils::FindFileWithName("/usr/share/icons", iconName, ".png");
|
iconPath = Utils::FindFileWithName("/usr/share/icons", iconName);
|
||||||
}
|
}
|
||||||
return iconPath;
|
return iconPath;
|
||||||
};
|
};
|
||||||
|
@ -187,7 +246,8 @@ namespace SNI
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iconPath = std::string(themePath) + "/" + iconName + ".png"; // TODO: Find out if this is always png
|
LOG("SNI: Searching icon " << iconName << " in " << themePath);
|
||||||
|
iconPath = Utils::FindFileWithName(themePath, iconName);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_variant_unref(themePathVariant);
|
g_variant_unref(themePathVariant);
|
||||||
|
@ -222,20 +282,8 @@ namespace SNI
|
||||||
LOG("SNI: Cannot find icon path for " << name);
|
LOG("SNI: Cannot find icon path for " << name);
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
LOG("SNI: Creating icon from \"" << iconPath << "\"");
|
||||||
int width, height, channels;
|
ToPixbuf(iconPath, item.pixbuf, item.w, item.h);
|
||||||
stbi_uc* pixels = stbi_load(iconPath.c_str(), &width, &height, &channels, STBI_rgb_alpha);
|
|
||||||
if (!pixels)
|
|
||||||
{
|
|
||||||
LOG("SNI: Cannot open " << iconPath);
|
|
||||||
return item;
|
|
||||||
}
|
|
||||||
item.w = width;
|
|
||||||
item.h = height;
|
|
||||||
item.iconData = new uint8_t[width * height * 4];
|
|
||||||
// Already rgba32
|
|
||||||
memcpy(item.iconData, pixels, width * height * 4);
|
|
||||||
stbi_image_free(pixels);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Query tooltip(Steam e.g. doesn't have one)
|
// Query tooltip(Steam e.g. doesn't have one)
|
||||||
|
@ -303,6 +351,7 @@ namespace SNI
|
||||||
LOG("SNI: " << name << " vanished!");
|
LOG("SNI: " << name << " vanished!");
|
||||||
g_bus_unwatch_name(it->watcherID);
|
g_bus_unwatch_name(it->watcherID);
|
||||||
g_dbus_connection_signal_unsubscribe(dbusConnection, it->propertyChangeWatcherID);
|
g_dbus_connection_signal_unsubscribe(dbusConnection, it->propertyChangeWatcherID);
|
||||||
|
g_free(it->pixbuf);
|
||||||
items.erase(it);
|
items.erase(it);
|
||||||
InvalidateWidget();
|
InvalidateWidget();
|
||||||
return;
|
return;
|
||||||
|
@ -360,6 +409,7 @@ namespace SNI
|
||||||
{
|
{
|
||||||
g_bus_unwatch_name(it->watcherID);
|
g_bus_unwatch_name(it->watcherID);
|
||||||
g_dbus_connection_signal_unsubscribe(dbusConnection, it->propertyChangeWatcherID);
|
g_dbus_connection_signal_unsubscribe(dbusConnection, it->propertyChangeWatcherID);
|
||||||
|
g_free(it->pixbuf);
|
||||||
items.erase(it);
|
items.erase(it);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -441,7 +491,7 @@ namespace SNI
|
||||||
bool rotatedIcons = (Config::Get().location == 'L' || Config::Get().location == 'R') && Config::Get().iconsAlwaysUp;
|
bool rotatedIcons = (Config::Get().location == 'L' || Config::Get().location == 'R') && Config::Get().iconsAlwaysUp;
|
||||||
for (auto& item : items)
|
for (auto& item : items)
|
||||||
{
|
{
|
||||||
if (item.iconData)
|
if (item.pixbuf)
|
||||||
{
|
{
|
||||||
auto eventBox = Widget::Create<EventBox>();
|
auto eventBox = Widget::Create<EventBox>();
|
||||||
item.gtkEvent = eventBox.get();
|
item.gtkEvent = eventBox.get();
|
||||||
|
@ -496,7 +546,7 @@ namespace SNI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Utils::SetTransform(*texture, {size, true, Alignment::Fill}, {size, true, Alignment::Fill, 0, rotatedIcons ? 6 : 0});
|
Utils::SetTransform(*texture, {size, true, Alignment::Fill}, {size, true, Alignment::Fill, 0, rotatedIcons ? 6 : 0});
|
||||||
texture->SetBuf(item.w, item.h, item.iconData);
|
texture->SetBuf(item.pixbuf, item.w, item.h);
|
||||||
texture->SetTooltip(item.tooltip);
|
texture->SetTooltip(item.tooltip);
|
||||||
texture->SetAngle(Utils::GetAngle() == 270 ? 90 : 0);
|
texture->SetAngle(Utils::GetAngle() == 270 ? 90 : 0);
|
||||||
|
|
||||||
|
|
|
@ -525,16 +525,13 @@ Texture::~Texture()
|
||||||
{
|
{
|
||||||
if (m_Pixbuf)
|
if (m_Pixbuf)
|
||||||
g_free(m_Pixbuf);
|
g_free(m_Pixbuf);
|
||||||
if (m_Bytes)
|
|
||||||
g_free(m_Bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::SetBuf(size_t width, size_t height, uint8_t* buf)
|
void Texture::SetBuf(GdkPixbuf* pixbuf, size_t width, size_t height)
|
||||||
{
|
{
|
||||||
m_Width = width;
|
m_Width = width;
|
||||||
m_Height = height;
|
m_Height = height;
|
||||||
m_Bytes = g_bytes_new(buf, m_Width * m_Height * 4);
|
m_Pixbuf = gdk_pixbuf_copy(pixbuf);
|
||||||
m_Pixbuf = gdk_pixbuf_new_from_bytes((GBytes*)m_Bytes, GDK_COLORSPACE_RGB, true, 8, m_Width, m_Height, m_Width * 4);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Texture::Draw(cairo_t* cr)
|
void Texture::Draw(cairo_t* cr)
|
||||||
|
|
|
@ -285,8 +285,8 @@ public:
|
||||||
Texture() = default;
|
Texture() = default;
|
||||||
virtual ~Texture();
|
virtual ~Texture();
|
||||||
|
|
||||||
// Non-Owning, ARGB32
|
// Non-Owning (Copies the pixbuf), ARGB32
|
||||||
void SetBuf(size_t width, size_t height, uint8_t* buf);
|
void SetBuf(GdkPixbuf* pixbuf, size_t width, size_t height);
|
||||||
|
|
||||||
void ForceHeight(size_t height) { m_ForcedHeight = height; };
|
void ForceHeight(size_t height) { m_ForcedHeight = height; };
|
||||||
void AddPaddingTop(int32_t topPadding) { m_Padding = topPadding; };
|
void AddPaddingTop(int32_t topPadding) { m_Padding = topPadding; };
|
||||||
|
@ -300,7 +300,6 @@ private:
|
||||||
size_t m_ForcedHeight = 0;
|
size_t m_ForcedHeight = 0;
|
||||||
double m_Angle;
|
double m_Angle;
|
||||||
int32_t m_Padding = 0;
|
int32_t m_Padding = 0;
|
||||||
GBytes* m_Bytes;
|
|
||||||
GdkPixbuf* m_Pixbuf;
|
GdkPixbuf* m_Pixbuf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue