diff --git a/config.c b/config.c index 817f7e9..63fb1c5 100644 --- a/config.c +++ b/config.c @@ -15,6 +15,10 @@ static int32_t max(int32_t a, int32_t b) { return (a > b) ? a : b; } +static int32_t min(int32_t a, int32_t b) { + return (a < b) ? a : b; +} + void init_default_config(struct mako_config *config) { wl_list_init(&config->criteria); struct mako_criteria *new_criteria = create_criteria(config); @@ -99,6 +103,7 @@ void init_default_style(struct mako_style *style) { style->icons = false; #endif style->max_icon_size = 64; + style->min_icon_size = 8; style->icon_path = strdup(""); // hicolor and pixmaps are implicit. style->icon_border_radius = 0; @@ -263,6 +268,11 @@ bool apply_style(struct mako_style *target, const struct mako_style *style) { target->spec.max_icon_size = true; } + if (style->spec.min_icon_size) { + target->min_icon_size = style->min_icon_size; + target->spec.min_icon_size = true; + } + if (style->spec.icon_path) { free(target->icon_path); target->icon_path = new_icon_path; @@ -420,6 +430,7 @@ bool apply_superset_style( target->spec.border_radius = true; target->spec.icons = true; target->spec.max_icon_size = true; + target->spec.min_icon_size = true; target->spec.default_timeout = true; target->spec.markup = true; target->spec.actions = true; @@ -466,6 +477,7 @@ bool apply_superset_style( target->border_size = max(style->border_size, target->border_size); target->icons = style->icons || target->icons; target->max_icon_size = max(style->max_icon_size, target->max_icon_size); + target->min_icon_size = min(style->min_icon_size, target->min_icon_size); target->default_timeout = max(style->default_timeout, target->default_timeout); @@ -611,6 +623,9 @@ static bool apply_style_option(struct mako_style *style, const char *name, } else if (strcmp(name, "max-icon-size") == 0) { return spec->max_icon_size = parse_int_ge(value, &style->max_icon_size, 1); + } else if (strcmp(name, "min-icon-size") == 0) { + return spec->min_icon_size = + parse_int_ge(value, &style->min_icon_size, 1); } else if (strcmp(name, "icon-path") == 0) { free(style->icon_path); return spec->icon_path = !!(style->icon_path = strdup(value)); @@ -912,6 +927,7 @@ int parse_config_arguments(struct mako_config *config, int argc, char **argv) { {"icon-location", required_argument, 0, 0}, {"icon-path", required_argument, 0, 0}, {"max-icon-size", required_argument, 0, 0}, + {"min-icon-size", required_argument, 0, 0}, {"icon-border-radius", required_argument, 0, 0}, {"markup", required_argument, 0, 0}, {"actions", required_argument, 0, 0}, diff --git a/contrib/completions/bash/mako b/contrib/completions/bash/mako index bdb5bbb..0a9455c 100644 --- a/contrib/completions/bash/mako +++ b/contrib/completions/bash/mako @@ -23,6 +23,7 @@ _mako() '--icons' '--icon-path' '--max-icon-size' + '--min-icon-size' '--icon-border-radius' '--markup' '--actions' diff --git a/contrib/completions/fish/mako.fish b/contrib/completions/fish/mako.fish index c64d203..b0cb505 100644 --- a/contrib/completions/fish/mako.fish +++ b/contrib/completions/fish/mako.fish @@ -22,6 +22,7 @@ complete -c mako -l progress-color -d 'Progress color indicator' -x complete -c mako -l icons -d 'Show icons or not' -xa "1 0" complete -c mako -l icon-path -d 'Icon search path, colon delimited' -r complete -c mako -l max-icon-size -d 'Max icon size in px' -x +complete -c mako -l min-icon-size -d 'Min icon size in px' -x complete -c mako -l icon-border-radius -d 'Icon border radius value in px' -x complete -c mako -l markup -d 'Enable markup or not' -xa "1 0" complete -c mako -l actions -d 'Enable actions or not' -xa "1 0" diff --git a/doc/mako.5.scd b/doc/mako.5.scd index 18eb3fb..98b432e 100644 --- a/doc/mako.5.scd +++ b/doc/mako.5.scd @@ -204,6 +204,11 @@ Supported actions: Default: 64 +*min-icon-size*=_px_ + Set minimum icon size to _px_ pixels. + + Default: 8 + *icon-path*=_path_\[:_path_...\] Paths to search for icons when a notification specifies a name instead of a full path. Colon-delimited. This approximates the search algorithm diff --git a/icon.c b/icon.c index 3a0d49b..87ffbd6 100644 --- a/icon.c +++ b/icon.c @@ -54,6 +54,34 @@ static GdkPixbuf *load_image(const char *path) { return pixbuf; } +static GdkPixbuf *load_scaled_to_minimum(GdkPixbuf *image, char *path, int min_size) { + int image_width = gdk_pixbuf_get_width(image); + int image_height = gdk_pixbuf_get_height(image); + + double longest = image_width > image_height ? image_width : image_height; + + if (longest >= min_size) { + return image; + } + + const double scale = min_size / longest; + image_width *= scale; + image_height *= scale; + + GError *err = NULL; + GdkPixbuf *scaled_pixbuf = gdk_pixbuf_new_from_file_at_scale( + path, image_width, image_height, true, &err); + free(image); + + if (!scaled_pixbuf) { + fprintf(stderr, "Failed to load icon (%s)\n", err->message); + g_error_free(err); + return NULL; + } + + return scaled_pixbuf; +} + static GdkPixbuf *load_image_data(struct mako_image_data *image_data) { GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data(image_data->data, GDK_COLORSPACE_RGB, image_data->has_alpha, image_data->bits_per_sample, image_data->width, @@ -65,9 +93,15 @@ static GdkPixbuf *load_image_data(struct mako_image_data *image_data) { return pixbuf; } -static double fit_to_square(int width, int height, int square_size) { - double longest = width > height ? width : height; - return longest > square_size ? square_size/longest : 1.0; +static void fit_to_square(GdkPixbuf *image, struct mako_icon *icon, int max_size) { + int image_width = gdk_pixbuf_get_width(image); + int image_height = gdk_pixbuf_get_height(image); + + double longest = image_width > image_height ? image_width : image_height; + + icon->scale = longest > max_size ? max_size / longest : 1.0; + icon->width = image_width * icon->scale; + icon->height = image_height * icon->scale; } static char hex_val(char digit) { @@ -263,20 +297,16 @@ struct mako_icon *create_icon(struct mako_notification *notif) { } image = load_image(path); + image = load_scaled_to_minimum(image, path, notif->style.min_icon_size); + free(path); if (image == NULL) { return NULL; } } - int image_width = gdk_pixbuf_get_width(image); - int image_height = gdk_pixbuf_get_height(image); - struct mako_icon *icon = calloc(1, sizeof(struct mako_icon)); - icon->scale = fit_to_square( - image_width, image_height, notif->style.max_icon_size); - icon->width = image_width * icon->scale; - icon->height = image_height * icon->scale; + fit_to_square(image, icon, notif->style.max_icon_size); icon->image = create_cairo_surface_from_gdk_pixbuf(image); g_object_unref(image); diff --git a/include/config.h b/include/config.h index 4876989..d5d161e 100644 --- a/include/config.h +++ b/include/config.h @@ -41,7 +41,7 @@ enum mako_icon_location { struct mako_style_spec { bool width, height, outer_margin, margin, padding, border_size, border_radius, font, markup, format, text_alignment, actions, default_timeout, ignore_timeout, - icons, max_icon_size, icon_path, icon_border_radius, group_criteria_spec, invisible, history, + icons, max_icon_size, min_icon_size, icon_path, icon_border_radius, group_criteria_spec, invisible, history, icon_location, max_visible, layer, output, anchor; struct { bool background, text, border, progress; @@ -66,6 +66,7 @@ struct mako_style { bool icons; int32_t max_icon_size; + int32_t min_icon_size; char *icon_path; int32_t icon_border_radius; diff --git a/main.c b/main.c index c273a4b..dcf6591 100644 --- a/main.c +++ b/main.c @@ -39,6 +39,7 @@ static const char usage[] = " --icons <0|1> Show icons in notifications.\n" " --icon-path [:...] Icon search path, colon delimited.\n" " --max-icon-size Set max size of icons.\n" + " --min-icon-size Set min size of icons.\n" " --icon-border-radius Icon's corner radius.\n" " --markup <0|1> Enable/disable markup.\n" " --actions <0|1> Enable/disable application action\n"