Skip to content

Commit 2e2d938

Browse files
committed
icon-lookup: allow for a list of icon themes
With the current implementation it's possible to have multiple icon themes in a somewhat performant manner.
1 parent 2ba4cfe commit 2e2d938

10 files changed

+153
-68
lines changed

docs/dunst.5.pod

+15-10
Original file line numberDiff line numberDiff line change
@@ -388,18 +388,22 @@ If B<icon_position> is set to off, this setting is ignored.
388388
Can be set to a colon-separated list of paths to search for icons to use with
389389
notifications.
390390

391-
Dunst doesn't currently do any type of icon lookup outside of these
392-
directories.
391+
Dunst doens't search outside of these direcories. For a recursive icon lookup
392+
system, see B<enable_recursive_icon_lookup>. This new system will eventually
393+
replace this and will need new settings.
393394

394-
=item B<icon_theme> (default: "hicolor") I<Experimental>
395+
=item B<icon_theme> (default: "Adwaita", example: "Adwaita, breeze") I<Experimental>
395396

396-
The name of the the theme to use for looking up icons. This has to be the name
397-
of the directory in which the theme is located, not the human-friendly name of
398-
the theme. So for example, the theme B<Breeze Dark> is located in
399-
F</usr/share/icons/breeze-dark>. In this case you have to set the theme to
400-
B<breeze-dark>.
397+
Comma-separated of names of the the themes to use for looking up icons. This has
398+
to be the name of the directory in which the theme is located, not the
399+
human-friendly name of the theme. So for example, the theme B<Breeze Dark> is
400+
located in F</usr/share/icons/breeze-dark>. In this case you have to set the
401+
theme to B<breeze-dark>.
401402

402-
Dunst will look for the theme in B<XDG_DATA_HOME/icons> and
403+
The first theme in the list is the most important. Only if the icon cannot be
404+
found in that theme, the next theme will be tried.
405+
406+
Dunst will look for the themes in B<XDG_DATA_HOME/icons> and
403407
B<$XDG_DATA_DIRS/icons> as specified in the icon theme specification:
404408
https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html.
405409

@@ -410,7 +414,8 @@ B<enable_recursive_icon_lookup> for how to enable it.
410414

411415
=item B<enable_recursive_icon_lookup> (default: false) I<Experimental>
412416

413-
This setting enables the new icon lookup method.
417+
This setting enables the new icon lookup method. This new system will eventually
418+
be the old icon lookup.
414419

415420
Currently icons are looked up in the B<icon_path> and scaled according to
416421
B<min_icon_size> and B<max_icon_size>. Since the B<icon_path> wasn't recursive,

src/draw.c

+26-5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,28 @@ PangoFontDescription *pango_fdesc;
4949

5050
#define UINT_MAX_N(bits) ((1 << bits) - 1)
5151

52+
void load_icon_themes()
53+
{
54+
bool loaded_theme = false;
55+
56+
for (int i = 0; settings.icon_theme[i] != NULL; i++) {
57+
char *theme = settings.icon_theme[i];
58+
int theme_index = load_icon_theme(theme);
59+
if (theme_index >= 0) {
60+
LOG_W("Adding default theme %s", theme);
61+
add_default_theme(theme_index);
62+
loaded_theme = true;
63+
} else {
64+
LOG_W("NOT Adding default theme '%s'", theme);
65+
}
66+
}
67+
if (!loaded_theme) {
68+
int theme_index = load_icon_theme("hicolor");
69+
add_default_theme(theme_index);
70+
}
71+
72+
}
73+
5274
void draw_setup(void)
5375
{
5476
const struct output *out = output_create(settings.force_xwayland);
@@ -58,11 +80,8 @@ void draw_setup(void)
5880

5981
pango_fdesc = pango_font_description_from_string(settings.font);
6082

61-
int theme_index = load_icon_theme(settings.icon_theme);
62-
if (theme_index == -1)
63-
theme_index = load_icon_theme("hicolor");
64-
65-
set_default_theme(theme_index);
83+
if (settings.enable_recursive_icon_lookup)
84+
load_icon_themes();
6685
}
6786

6887
static struct color hex_to_color(uint32_t hexValue, int dpc)
@@ -787,6 +806,8 @@ void draw_deinit(void)
787806
{
788807
output->win_destroy(win);
789808
output->deinit();
809+
if (settings.enable_recursive_icon_lookup)
810+
free_all_themes();
790811
}
791812

792813
double draw_get_scale(void)

src/icon-lookup.c

+24-30
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313

1414
struct icon_theme *icon_themes = NULL;
1515
int icon_themes_count = 0;
16-
int default_theme_index = -1;
16+
int *default_themes_index = NULL;
17+
int default_themes_count = 0;
1718

1819
static bool is_readable_file(const char *filename)
1920
{
@@ -29,13 +30,6 @@ int get_icon_theme(char *name) {
2930
return -1;
3031
}
3132

32-
void print_all_dir_counts(char *theme_name, char *msg) {
33-
printf("%s: %s\n", theme_name, msg);
34-
for (int i = 0; i < icon_themes_count; i++) {
35-
printf("Dir count %s: %i\n", icon_themes[i].name, icon_themes[i].dirs_count);
36-
}
37-
}
38-
3933
/**
4034
* Load a theme from a directory. Don't call this function if the theme is
4135
* already loaded. It also loads the inherited themes. If there are no
@@ -50,7 +44,7 @@ void print_all_dir_counts(char *theme_name, char *msg) {
5044
* @retval -1 means no index was found
5145
*/
5246
int load_icon_theme_from_dir(const char *icon_dir, const char *subdir_theme) {
53-
printf("Loading theme %s/%s\n", icon_dir, subdir_theme);
47+
LOG_D("Loading theme %s/%s\n", icon_dir, subdir_theme);
5448
char *theme_index_dir = g_build_filename(icon_dir, subdir_theme, "index.theme", NULL);
5549
FILE *theme_index = fopen(theme_index_dir, "r");
5650
g_free(theme_index_dir);
@@ -76,7 +70,6 @@ int load_icon_theme_from_dir(const char *icon_dir, const char *subdir_theme) {
7670

7771
// load theme directories
7872
icon_themes[index].dirs_count = ini->section_count - 1;
79-
print_all_dir_counts(icon_themes[index].name, "First");
8073
icon_themes[index].dirs = calloc(icon_themes[index].dirs_count, sizeof(struct icon_theme_dir));
8174

8275
for (int i = 0; i < icon_themes[index].dirs_count; i++) {
@@ -129,15 +122,14 @@ int load_icon_theme_from_dir(const char *icon_dir, const char *subdir_theme) {
129122
}
130123
}
131124
}
132-
print_all_dir_counts(icon_themes[index].name, "Second");
133125

134126

135127
// load inherited themes
136128
if (!STR_EQ(icon_themes[index].name, "Hicolor"))
137129
{
138130
char **inherits = string_to_array(get_value(ini, "Icon Theme", "Inherits"), ",");
139131
icon_themes[index].inherits_count = string_array_length(inherits);
140-
printf("Theme has %i inherited themes\n", icon_themes[index].inherits_count);
132+
LOG_D("Theme has %i inherited themes\n", icon_themes[index].inherits_count);
141133
if (icon_themes[index].inherits_count <= 0) {
142134
// set fallback theme to hicolor if there are no inherits
143135
g_strfreev(inherits);
@@ -150,15 +142,13 @@ int load_icon_theme_from_dir(const char *icon_dir, const char *subdir_theme) {
150142
icon_themes[index].inherits_index = calloc(icon_themes[index].inherits_count, sizeof(int));
151143

152144
for (int i = 0; inherits[i] != NULL; i++) {
153-
printf("inherits: %s\n", inherits[i]);
145+
LOG_D("inherits: %s\n", inherits[i]);
154146
icon_themes[index].inherits_index[i] = get_icon_theme(inherits[i]);
155147
if (icon_themes[index].inherits_index[i] == -1) {
156-
printf("Loading inherited theme\n");
157-
print_all_dir_counts(icon_themes[index].name, "Third");
148+
LOG_D("Loading inherited theme\n");
158149
// FIXME don't use a pointer to the theme,
159150
// since it may be invalidated after realloc. Use an index instead
160151
icon_themes[index].inherits_index[i] = load_icon_theme(inherits[i]);
161-
print_all_dir_counts("unknown", "Fourth");
162152
}
163153
}
164154
g_strfreev(inherits);
@@ -168,10 +158,6 @@ int load_icon_theme_from_dir(const char *icon_dir, const char *subdir_theme) {
168158

169159
finish_ini(ini);
170160
free(ini);
171-
172-
print_all_dir_counts("unknown", "End");
173-
printf("Othere dirs count %i\n", icon_themes[0].dirs_count);
174-
printf("index %i\n", index);
175161
return index;
176162
}
177163

@@ -215,7 +201,7 @@ void get_theme_path() {
215201
add_paths_from_env(theme_path, "XDG_DATA_DIRS", "icons", "/usr/local/share/:/usr/share/");
216202
g_ptr_array_add(theme_path, g_strdup("/usr/share/pixmaps"));
217203
for (int i = 0; i < theme_path->len; i++) {
218-
printf("Theme locations: %s\n", (char*)theme_path->pdata[i]);
204+
LOG_D("Theme locations: %s\n", (char*)theme_path->pdata[i]);
219205
}
220206
}
221207

@@ -244,7 +230,6 @@ void finish_icon_theme_dir(struct icon_theme_dir *dir) {
244230
void finish_icon_theme(struct icon_theme *theme) {
245231
if (!theme)
246232
return;
247-
printf("Finishing %i dirs\n", theme->dirs_count);
248233
for (int i = 0; i < theme->dirs_count; i++) {
249234
finish_icon_theme_dir(&theme->dirs[i]);
250235
}
@@ -256,9 +241,8 @@ void finish_icon_theme(struct icon_theme *theme) {
256241
}
257242

258243
void free_all_themes() {
259-
printf("Finishing %i themes\n", icon_themes_count);
244+
LOG_D("Finishing %i themes\n", icon_themes_count);
260245
for (int i = 0; i < icon_themes_count; i++) {
261-
printf("Theme dirs %i\n", icon_themes[i].dirs_count);
262246
finish_icon_theme(&icon_themes[i]);
263247
}
264248
free(icon_themes);
@@ -269,7 +253,7 @@ void free_all_themes() {
269253
}
270254

271255
// see icon-lookup.h
272-
void set_default_theme(int theme_index) {
256+
void add_default_theme(int theme_index) {
273257
if (theme_index < 0) {
274258
LOG_W("Invalid theme index: %i", theme_index);
275259
return;
@@ -279,13 +263,16 @@ void set_default_theme(int theme_index) {
279263
theme_index);
280264
return;
281265
}
282-
default_theme_index = theme_index;
266+
default_themes_count++;
267+
default_themes_index = realloc(default_themes_index,
268+
default_themes_count * sizeof(int));
269+
default_themes_index[default_themes_count - 1] = theme_index;
283270
}
284271

285272
// see icon-lookup.h
286273
char *find_icon_in_theme(const char *name, int theme_index, int size) {
287274
struct icon_theme *theme = &icon_themes[theme_index];
288-
printf("Finding icon %s in theme %s\n", name, theme->name);
275+
LOG_D("Finding icon %s in theme %s\n", name, theme->name);
289276
for (int i = 0; i < theme->dirs_count; i++) {
290277
bool match_size = false;
291278
struct icon_theme_dir dir = theme->dirs[i];
@@ -362,9 +349,16 @@ char *find_icon_path(const char *name, int size) {
362349
return NULL;
363350
}
364351

365-
if (default_theme_index == -1) {
366-
printf("No icon theme has been set.\n");
352+
if (!default_themes_index) {
353+
LOG_W("No icon theme has been set.\n");
367354
return NULL;
368355
}
369-
return find_icon_in_theme_with_inherit(name, default_theme_index, size);
356+
for (int i = 0; i < default_themes_count; i++) {
357+
char *icon = find_icon_in_theme_with_inherit(name,
358+
default_themes_index[i], size);
359+
if (icon)
360+
return icon;
361+
362+
}
363+
return NULL;
370364
}

src/icon-lookup.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ int load_icon_theme(char *name);
3838

3939

4040
/**
41-
* Set the default icon theme used for looking up icons. Inherited themes will
42-
* be used as a fallback.
41+
* Add theme to the list of default themes. The theme that's added first will
42+
* be used first for lookup. After that the inherited themes will be used and
43+
* only after that the next default theme will be used.
4344
*
4445
* @param theme_index The index of the theme as returned by #load_icon_theme
4546
*/
46-
void set_default_theme(int theme_index);
47+
void add_default_theme(int theme_index);
4748

4849
/**
4950
* Find icon of specified size in selected theme. This function will not return
@@ -72,5 +73,10 @@ void set_default_theme(int theme_index);
7273
*/
7374
char *find_icon_path(const char *name, int size);
7475

76+
/**
77+
* Free all icon themes.
78+
*/
79+
void free_all_themes();
80+
7581
#endif
7682
/* vim: set ft=c tabstop=8 shiftwidth=8 expandtab textwidth=0: */

src/option_parser.c

+6
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,12 @@ int string_parse_list(const void *data, const char *s, void *ret) {
153153
offset->y = int_arr[1];
154154
g_free(int_arr);
155155
break;
156+
case STRING_LIST: ;
157+
g_strfreev(*(char ***) ret);
158+
*(char ***) ret = string_to_array(s, ",");
159+
success = true;
160+
break;
161+
156162
default:
157163
LOG_W("Don't know this list type: %i", type);
158164
break;

src/settings.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ struct settings {
131131
enum vertical_alignment vertical_alignment;
132132
int min_icon_size;
133133
int max_icon_size;
134-
char *icon_theme; // experimental
134+
char **icon_theme; // experimental
135135
bool enable_recursive_icon_lookup; // experimental
136136
char *icon_path;
137137
enum follow_mode f_mode;

src/settings_data.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,8 @@ const enum zwlr_layer_shell_v1_layer {
139139
enum list_type {
140140
INVALID_LIST = 0,
141141
MOUSE_LIST = 1,
142-
ORIGIN_LIST = 2,
143-
OFFSET_LIST = 3,
142+
OFFSET_LIST = 2,
143+
STRING_LIST = 3,
144144
};
145145

146146
#define ENUM_END {NULL, 0}
@@ -1054,11 +1054,11 @@ static const struct setting allowed_settings[] = {
10541054
.name = "icon_theme",
10551055
.section = "global",
10561056
.description = "Name of the icon theme",
1057-
.type = TYPE_STRING,
1057+
.type = TYPE_LIST,
10581058
.default_value = "Adwaita",
10591059
.value = &settings.icon_theme,
10601060
.parser = NULL,
1061-
.parser_data = NULL,
1061+
.parser_data = GINT_TO_POINTER(STRING_LIST),
10621062
},
10631063
{
10641064
.name = "icon_path",

0 commit comments

Comments
 (0)