Skip to content

Commit

Permalink
Merge pull request #1003 from fwsmit/recursive-icon-scale
Browse files Browse the repository at this point in the history
Always scale icons to `icon_size`
  • Loading branch information
fwsmit authored Jan 15, 2022
2 parents 867b04b + f2720cb commit 37c72d5
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 36 deletions.
25 changes: 15 additions & 10 deletions src/dbus.c
Original file line number Diff line number Diff line change
Expand Up @@ -584,16 +584,6 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
g_variant_unref(dict_value);
}

dict_value = g_variant_lookup_value(hints, "image-data", G_VARIANT_TYPE("(iiibiiay)"));
if (!dict_value)
dict_value = g_variant_lookup_value(hints, "image_data", G_VARIANT_TYPE("(iiibiiay)"));
if (!dict_value)
dict_value = g_variant_lookup_value(hints, "icon_data", G_VARIANT_TYPE("(iiibiiay)"));
if (dict_value) {
notification_icon_replace_data(n, dict_value);
g_variant_unref(dict_value);
}

if ((dict_value = g_variant_lookup_value(hints, "image-path", G_VARIANT_TYPE_STRING))) {
g_free(n->iconname);
n->iconname = g_variant_dup_string(dict_value, NULL);
Expand All @@ -605,6 +595,21 @@ static struct notification *dbus_message_to_notification(const gchar *sender, GV
// are defined and applies the formatting to the message.
notification_init(n);


// Set raw icon data only after initializing the notification, so the
// desired icon size is known. This way the buffer can be immediately
// rescaled. If at some point you might want to match by if a
// notificaton has an image, this has to be reworked.
dict_value = g_variant_lookup_value(hints, "image-data", G_VARIANT_TYPE("(iiibiiay)"));
if (!dict_value)
dict_value = g_variant_lookup_value(hints, "image_data", G_VARIANT_TYPE("(iiibiiay)"));
if (!dict_value)
dict_value = g_variant_lookup_value(hints, "icon_data", G_VARIANT_TYPE("(iiibiiay)"));
if (dict_value) {
notification_icon_replace_data(n, dict_value);
g_variant_unref(dict_value);
}

// Modify these values after the notification is initialized and all rules are applied.
if ((dict_value = g_variant_lookup_value(hints, "fgcolor", G_VARIANT_TYPE_STRING))) {
g_free(n->colors.fg);
Expand Down
84 changes: 62 additions & 22 deletions src/icon.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,40 +149,67 @@ static bool icon_size_clamp(int *w, int *h) {
return FALSE;
}

static bool icon_size_clamp2(int *w, int *h, int desired_size, double scale) {
int largest_size = MAX(*w, *h);
int new_size = desired_size * scale;
if (largest_size != new_size) {
double scale = (double) new_size / (double) largest_size;
*w = round(*w * scale);
*h = round(*h * scale);
return true;
}
return false;
}
/**
* Scales the given GdkPixbuf if necessary according to the settings.
* Scales the given GdkPixbuf to a given size.. If the image is not square, the
* largest size will be scaled up to the given size.
*
* The icon is scaled to a size of icon_size * dpi_scale.
*
* @param pixbuf (nullable) The pixbuf, which may be too big.
* Takes ownership of the reference.
* @param dpi_scale An integer for the dpi scaling. That doesn't mean the icon
* is always scaled by dpi_scale.
* @param icon_size An integer the unscaled icon size.
* @param dpi_scale A double for the dpi scaling.
* @return the scaled version of the pixbuf. If scaling wasn't
* necessary, it returns the same pixbuf. Transfers full
* ownership of the reference.
*/
static GdkPixbuf *icon_pixbuf_scale(GdkPixbuf *pixbuf, double dpi_scale)
static GdkPixbuf *icon_pixbuf_scale_to_size(GdkPixbuf *pixbuf, int icon_size, double dpi_scale)
{
ASSERT_OR_RET(pixbuf, NULL);

int w = gdk_pixbuf_get_width(pixbuf);
int h = gdk_pixbuf_get_height(pixbuf);


// TODO immediately rescale icon upon scale changes
if (icon_size_clamp(&w, &h)) {
bool needs_change = false;

if (settings.enable_recursive_icon_lookup)
{
needs_change = icon_size_clamp2(&w, &h, icon_size, dpi_scale);
if (needs_change) {
LOG_D("Scaling to a size of %ix%i", w, h);
LOG_D("While the icon size and scale are %ix%f", icon_size, dpi_scale);
}
} else {
// TODO immediately rescale icon upon scale changes
if(icon_size_clamp(&w, &h)) {
w = round(w * dpi_scale);
h = round(h * dpi_scale);
needs_change = true;
}
}
if (needs_change) {
GdkPixbuf *scaled = gdk_pixbuf_scale_simple(
pixbuf,
round(w * dpi_scale),
round(h * dpi_scale),
w,
h,
GDK_INTERP_BILINEAR);
g_object_unref(pixbuf);
pixbuf = scaled;
}

return pixbuf;
}

GdkPixbuf *get_pixbuf_from_file(const char *filename, double scale)
GdkPixbuf *get_pixbuf_from_file(const char *filename, int icon_size, double scale)
{
char *path = string_to_path(g_strdup(filename));
GError *error = NULL;
Expand All @@ -193,13 +220,24 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename, double scale)
g_free(path);
return NULL;
}
// TODO immediately rescale icon upon scale changes
icon_size_clamp(&w, &h);
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file_at_scale(path,
round(w * scale),
round(h * scale),
TRUE,
&error);
GdkPixbuf *pixbuf = NULL;
if (settings.enable_recursive_icon_lookup)
{
icon_size_clamp2(&w, &h, icon_size, scale);
pixbuf = gdk_pixbuf_new_from_file_at_scale(path,
w,
h,
TRUE,
&error);
} else {
// TODO immediately rescale icon upon scale changes
icon_size_clamp(&w, &h);
pixbuf = gdk_pixbuf_new_from_file_at_scale(path,
round(w * scale),
round(h * scale),
TRUE,
&error);
}

if (error) {
LOG_W("%s", error->message);
Expand All @@ -213,7 +251,9 @@ GdkPixbuf *get_pixbuf_from_file(const char *filename, double scale)
char *get_path_from_icon_name(const char *iconname, int size)
{
if (settings.enable_recursive_icon_lookup) {
return find_icon_path(iconname, size);
char *path = find_icon_path(iconname, size);
LOG_I("Found icon at %s", path);
return path;
}
if (STR_EMPTY(iconname))
return NULL;
Expand Down Expand Up @@ -268,7 +308,7 @@ char *get_path_from_icon_name(const char *iconname, int size)
return new_name;
}

GdkPixbuf *icon_get_for_data(GVariant *data, char **id, double dpi_scale)
GdkPixbuf *icon_get_for_data(GVariant *data, char **id, double dpi_scale, int icon_size)
{
ASSERT_OR_RET(data, NULL);
ASSERT_OR_RET(id, NULL);
Expand Down Expand Up @@ -378,7 +418,7 @@ GdkPixbuf *icon_get_for_data(GVariant *data, char **id, double dpi_scale)
g_free(data_chk);
g_variant_unref(data_variant);

pixbuf = icon_pixbuf_scale(pixbuf, dpi_scale);
pixbuf = icon_pixbuf_scale_to_size(pixbuf, icon_size, dpi_scale);

return pixbuf;
}
Expand Down
6 changes: 4 additions & 2 deletions src/icon.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ cairo_surface_t *gdk_pixbuf_to_cairo_surface(GdkPixbuf *pixbuf);
/** Retrieve an icon by its full filepath, scaled according to settings.
*
* @param filename A string representing a readable file path
* @param icon_size An iteger representing the desired unscaled icon size.
* @param scale An integer representing the output dpi scaling.
*
* @return an instance of `GdkPixbuf`
* @retval NULL: file does not exist, not readable, etc..
*/
GdkPixbuf *get_pixbuf_from_file(const char *filename, double scale);
GdkPixbuf *get_pixbuf_from_file(const char *filename, int icon_size, double scale);


/**
Expand Down Expand Up @@ -55,10 +56,11 @@ char *get_path_from_icon_name(const char *iconname, int size);
* @param id (necessary) A unique identifier of the returned pixbuf.
* Only filled, if the return value is non-NULL.
* @param scale An integer representing the output dpi scaling.
* @param icon_size An integer representing the desired unscaled icon size.
* @return an instance of `GdkPixbuf` derived from the GVariant
* @retval NULL: GVariant parameter nulled, invalid or in wrong format
*/
GdkPixbuf *icon_get_for_data(GVariant *data, char **id, double scale);
GdkPixbuf *icon_get_for_data(GVariant *data, char **id, double scale, int icon_size);

#endif
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */
6 changes: 4 additions & 2 deletions src/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,8 @@ void notification_icon_replace_path(struct notification *n, const char *new_icon
g_free(n->icon_path);
n->icon_path = get_path_from_icon_name(new_icon, n->icon_size);
if (n->icon_path) {
GdkPixbuf *pixbuf = get_pixbuf_from_file(n->icon_path, draw_get_scale());
GdkPixbuf *pixbuf = get_pixbuf_from_file(n->icon_path,
n->icon_size, draw_get_scale());
if (pixbuf) {
n->icon = gdk_pixbuf_to_cairo_surface(pixbuf);
g_object_unref(pixbuf);
Expand All @@ -358,7 +359,8 @@ void notification_icon_replace_data(struct notification *n, GVariant *new_icon)
n->icon = NULL;
g_clear_pointer(&n->icon_id, g_free);

GdkPixbuf *icon = icon_get_for_data(new_icon, &n->icon_id, draw_get_scale());
GdkPixbuf *icon = icon_get_for_data(new_icon, &n->icon_id,
draw_get_scale(), n->icon_size);
n->icon = gdk_pixbuf_to_cairo_surface(icon);
g_object_unref(icon);
}
Expand Down

0 comments on commit 37c72d5

Please sign in to comment.