diff --git a/src/nkutils-xdg-theme.h b/src/nkutils-xdg-theme.h index 6ab5cfd..6802ded 100644 --- a/src/nkutils-xdg-theme.h +++ b/src/nkutils-xdg-theme.h @@ -31,7 +31,7 @@ typedef struct _NkXdgThemeContext NkXdgThemeContext; NkXdgThemeContext *nk_xdg_theme_context_new(void); void nk_xdg_theme_context_free(NkXdgThemeContext *context); -gchar *nk_xdg_theme_get_icon(NkXdgThemeContext *context, const gchar *theme, const gchar *context_name, const gchar *name, gint size, gint scale, gboolean svg); -gchar *nk_xdg_theme_get_sound(NkXdgThemeContext *context, const gchar *theme, const gchar *name, const gchar *profile, const gchar *locale); +gchar *nk_xdg_theme_get_icon(NkXdgThemeContext *context, const gchar * const *themes, const gchar *context_name, const gchar *name, gint size, gint scale, gboolean svg); +gchar *nk_xdg_theme_get_sound(NkXdgThemeContext *context, const gchar * const *themes, const gchar *name, const gchar *profile, const gchar *locale); #endif /* __NK_UTILS_XDG_THEME_H__ */ diff --git a/src/xdg-theme.c b/src/xdg-theme.c index 6a70532..9544e7f 100644 --- a/src/xdg-theme.c +++ b/src/xdg-theme.c @@ -575,7 +575,7 @@ _nk_xdg_theme_get_file(NkXdgThemeTheme *self, const gchar *name, gboolean (*find } static gboolean -_nk_xdg_theme_try_file(const gchar *dir, const gchar *name, const gchar *extensions[], gchar **ret) +_nk_xdg_theme_try_file(const gchar *dir, const gchar *name, const gchar **extensions, gchar **ret) { gsize i; for ( i = 0 ; extensions[i] != NULL ; ++i ) @@ -593,36 +593,50 @@ _nk_xdg_theme_try_file(const gchar *dir, const gchar *name, const gchar *extensi } static gboolean -_nk_xdg_theme_try_fallback(gchar **dirs, const gchar *extra_dir, const gchar *theme_name, const gchar *name, const gchar *extensions[], gchar **ret) +_nk_xdg_theme_try_fallback_internal(gchar **dir, const gchar *extra_dir, const gchar *name, const gchar **extensions, gchar **ret) { - gchar *themed_name = NULL; - gsize l; - if ( theme_name != NULL ) + if ( dir != NULL ) + for ( ; *dir != NULL ; ++dir ) { - l = strlen(theme_name) + strlen(G_DIR_SEPARATOR_S) + strlen(name) + 1; - themed_name = g_newa(gchar, l); - g_snprintf(themed_name, l, "%s%c%s", theme_name, G_DIR_SEPARATOR, name); - } - - gchar **dir; - if ( dirs != NULL ) - for ( dir = dirs ; *dir != NULL ; ++dir ) - { - if ( ( themed_name != NULL ) && _nk_xdg_theme_try_file(*dir, themed_name, extensions, ret) ) - return TRUE; if ( _nk_xdg_theme_try_file(*dir, name, extensions, ret) ) return TRUE; } if ( extra_dir == NULL ) return FALSE; - if ( ( themed_name != NULL ) && _nk_xdg_theme_try_file(extra_dir, themed_name, extensions, ret) ) - return TRUE; if ( _nk_xdg_theme_try_file(extra_dir, name, extensions, ret) ) return TRUE; return FALSE; } +static gboolean +_nk_xdg_theme_try_fallback(gchar **dirs, const gchar *extra_dir, const gchar * const *theme_names, const gchar *name, const gchar **extensions, gchar **ret) +{ + if ( theme_names != NULL ) + { + const gchar * const *theme_name; + gsize l = 0, tl; + for ( theme_name = theme_names ; *theme_name != NULL ; ++theme_name ) + { + tl = strlen(*theme_name); + if ( tl > l ) + l = tl; + } + l += strlen(G_DIR_SEPARATOR_S) + strlen(name) + 1; + + gchar *themed_name = NULL; + themed_name = g_newa(gchar, l); + for ( theme_name = theme_names ; *theme_name != NULL ; ++theme_name ) + { + g_snprintf(themed_name, l, "%s%c%s", *theme_name, G_DIR_SEPARATOR, name); + if ( _nk_xdg_theme_try_fallback_internal(dirs, extra_dir, themed_name, extensions, ret) ) + return TRUE; + } + } + + return _nk_xdg_theme_try_fallback_internal(dirs, extra_dir, name, extensions, ret); +} + static gint _nk_xdg_theme_icon_subdir_compute_distance(NkXdgThemeIconDir *self, gint size) { @@ -694,7 +708,7 @@ _nk_xdg_theme_icon_find_file(NkXdgThemeTheme *self, const gchar *name, gpointer } gchar * -nk_xdg_theme_get_icon(NkXdgThemeContext *self, const gchar *theme_name, const gchar *context_name, const gchar *name, gint size, gint scale, gboolean svg) +nk_xdg_theme_get_icon(NkXdgThemeContext *self, const gchar * const *theme_names, const gchar *context_name, const gchar *name, gint size, gint scale, gboolean svg) { g_return_val_if_fail(self != NULL, NULL); g_return_val_if_fail(name != NULL, NULL); @@ -715,9 +729,13 @@ nk_xdg_theme_get_icon(NkXdgThemeContext *self, const gchar *theme_name, const gc NkXdgThemeTheme *theme; gchar *file; - theme = _nk_xdg_theme_get_theme(self, TYPE_ICON, theme_name); - if ( ( theme != NULL ) && _nk_xdg_theme_get_file(theme, name, _nk_xdg_theme_icon_find_file, &data, &file) ) - return file; + const gchar * const *theme_name; + for ( theme_name = theme_names ; *theme_name != NULL ; ++theme_name ) + { + theme = _nk_xdg_theme_get_theme(self, TYPE_ICON, *theme_name); + if ( ( theme != NULL ) && _nk_xdg_theme_get_file(theme, name, _nk_xdg_theme_icon_find_file, &data, &file) ) + return file; + } theme = _nk_xdg_theme_get_theme(self, TYPE_ICON, "hicolor"); if ( ( theme != NULL ) && _nk_xdg_theme_get_file(theme, name, _nk_xdg_theme_icon_find_file, &data, &file) ) @@ -733,7 +751,7 @@ nk_xdg_theme_get_icon(NkXdgThemeContext *self, const gchar *theme_name, const gc l = strlen(name) - strlen("-symbolic") + 1; no_symbolic_name = g_newa(gchar, l); g_snprintf(no_symbolic_name, l, "%s", name); - return nk_xdg_theme_get_icon(self, theme_name, context_name, no_symbolic_name, size, scale, svg); + return nk_xdg_theme_get_icon(self, theme_names, context_name, no_symbolic_name, size, scale, svg); } return NULL; @@ -776,17 +794,11 @@ _nk_xdg_theme_sound_find_file(NkXdgThemeTheme *self, const gchar *name_, gpointe } gchar * -nk_xdg_theme_get_sound(NkXdgThemeContext *self, const gchar *theme_name, const gchar *name, const gchar *profile, const gchar *locale) +nk_xdg_theme_get_sound(NkXdgThemeContext *self, const gchar * const *theme_names, const gchar *name, const gchar *profile, const gchar *locale) { g_return_val_if_fail(self != NULL, NULL); g_return_val_if_fail(name != NULL, NULL); - NkXdgThemeTheme *theme; - gchar *file; - theme = _nk_xdg_theme_get_theme(self, TYPE_SOUND, theme_name); - if ( theme == NULL ) - theme = _nk_xdg_theme_get_theme(self, TYPE_SOUND, "freedesktop"); - NkXdgThemeSoundFindData data = { .profile = profile, }; @@ -856,13 +868,23 @@ nk_xdg_theme_get_sound(NkXdgThemeContext *self, const gchar *theme_name, const g } } + NkXdgThemeTheme *theme; + gchar *file; + const gchar * const *theme_name; + for ( theme_name = theme_names ; *theme_name != NULL ; ++theme_name ) + { + theme = _nk_xdg_theme_get_theme(self, TYPE_SOUND, *theme_name); + if ( ( theme != NULL ) && _nk_xdg_theme_get_file(theme, name, _nk_xdg_theme_sound_find_file, &data, &file) ) + return file; + } + theme = _nk_xdg_theme_get_theme(self, TYPE_SOUND, "freedesktop"); if ( ( theme != NULL ) && _nk_xdg_theme_get_file(theme, name, _nk_xdg_theme_sound_find_file, &data, &file) ) return file; gchar **subname; for ( subname = data.names ; *subname != NULL ; ++subname ) { - if ( _nk_xdg_theme_try_fallback(self->dirs[TYPE_SOUND], NULL, theme_name, *subname, _nk_xdg_theme_sound_extensions, &file) ) + if ( _nk_xdg_theme_try_fallback(self->dirs[TYPE_SOUND], NULL, theme_names, *subname, _nk_xdg_theme_sound_extensions, &file) ) return file; } diff --git a/tests/xdg-theme.c b/tests/xdg-theme.c index dd9ad21..b711678 100644 --- a/tests/xdg-theme.c +++ b/tests/xdg-theme.c @@ -34,6 +34,8 @@ #include +#define MAX_THEMES 5 + static NkXdgThemeContext *context; typedef enum { TYPE_NONE = 0, @@ -43,7 +45,7 @@ typedef enum { typedef struct { NkXdgThemeTestType type; - const gchar *theme; + const gchar *themes[MAX_THEMES]; const gchar *name; const gchar *context; gint size; @@ -62,7 +64,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/Adwaita/symbolic/found", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "zoom-in-symbolic", .size = 48, .scale = 1, @@ -75,7 +77,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/Adwaita/symbolic/not-scalable", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "zoom-in-symbolic", .size = 48, .scale = 1, @@ -88,7 +90,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/Adwaita/symbolic/found-no-symbolic", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "trophy-gold-symbolic", .size = 48, .scale = 1, @@ -97,11 +99,24 @@ static const struct { .theme_test = "/usr/share/icons/Adwaita/index.theme", } }, + { + .testpath = "/nkutils/xdg-theme/icon/Adwaita/theme-found/second-choice", + .data = { + .type = TYPE_ICON, + .themes = { [0] = "hopefully-no-theme-has-this-name", [1] = "Adwaita" }, + .name = "trophy-gold", + .size = 48, + .scale = 1, + .svg = TRUE, + .result = "/usr/share/icons/Adwaita/48x48/status/trophy-gold.png", + .theme_test = "/usr/share/icons/Adwaita/index.theme", + } + }, { .testpath = "/nkutils/xdg-theme/icon/Adwaita/theme-found/fallback", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "geany", .size = 16, .scale = 1, @@ -114,7 +129,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/Adwaita/context/exist-match/1", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "network-wireless-signal-ok-symbolic", .context = "Status", .size = 48, @@ -128,7 +143,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/Adwaita/context/exist-no-match", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "network-wireless-signal-ok-symbolic", .context = "Applications", .size = 48, @@ -142,7 +157,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/Adwaita/context/exist-match/2", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "emblem-favorite-symbolic", .context = "Emblems", .size = 48, @@ -156,7 +171,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/symbolic/found", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "zoom-in-symbolic", .size = 48, .scale = 1, @@ -169,7 +184,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/symbolic/not-scalable", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "zoom-in-symbolic", .size = 48, .scale = 1, @@ -182,7 +197,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/symbolic/found-no-symbolic", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "trophy-gold-symbolic", .size = 48, .scale = 1, @@ -195,7 +210,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/theme-found/fallback", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "geany", .size = 16, .scale = 1, @@ -208,7 +223,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/context/exist-match/1", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "network-wireless-signal-ok-symbolic", .context = "Status", .size = 48, @@ -222,7 +237,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/context/exist-no-match", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "network-wireless-signal-ok-symbolic", .context = "Applications", .size = 48, @@ -236,7 +251,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/context/exist-match/2", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "emblem-favorite-symbolic", .context = "Emblems", .size = 48, @@ -250,7 +265,6 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/no-theme/threshold/found/1", .data = { .type = TYPE_ICON, - .theme = NULL, .name = "geany", .size = 18, .scale = 1, @@ -263,7 +277,6 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/no-theme/threshold/found/2", .data = { .type = TYPE_ICON, - .theme = NULL, .name = "pidgin", .size = 18, .scale = 1, @@ -276,7 +289,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/no-theme/size/fallback/hicolor/1", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "pidgin", .size = 0, .scale = 1, @@ -289,7 +302,6 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/no-theme/size/fallback/pixmaps/1", .data = { .type = TYPE_ICON, - .theme = NULL, .name = "htop", .size = 19, .scale = 1, @@ -301,7 +313,6 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/no-theme/size/fallback/pixmaps/2", .data = { .type = TYPE_ICON, - .theme = NULL, .name = "debian-logo", .size = 0, .scale = 1, @@ -313,7 +324,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/Adwaita/size/biggest/fixed", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "edit-find-symbolic", .size = 0, .scale = 1, @@ -326,7 +337,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/Adwaita/size/biggest/svg", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "edit-find-symbolic", .size = 0, .scale = 1, @@ -339,7 +350,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/Adwaita/size/best-distance", .data = { .type = TYPE_ICON, - .theme = "Adwaita", + .themes = { [0] = "Adwaita" }, .name = "edit-find", .size = 19, .scale = 1, @@ -352,7 +363,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/size/biggest/fixed", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "edit-find-symbolic", .size = 0, .scale = 1, @@ -365,7 +376,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/size/biggest/svg", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "edit-find-symbolic", .size = 0, .scale = 1, @@ -378,7 +389,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/gnome/size/best-distance", .data = { .type = TYPE_ICON, - .theme = "gnome", + .themes = { [0] = "gnome" }, .name = "edit-find", .size = 19, .scale = 1, @@ -391,7 +402,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/wrong-theme/not-found", .data = { .type = TYPE_ICON, - .theme = "do-not-exists-hopefully", + .themes = { [0] = "do-not-exists-hopefully" }, .name = "nothing-on-earth-will-have-that-name", .size = 48, .scale = 1, @@ -403,7 +414,6 @@ static const struct { .testpath = "/nkutils/xdg-theme/icon/no-theme/not-found", .data = { .type = TYPE_ICON, - .theme = NULL, .name = "nothing-on-earth-will-have-that-name", .size = 48, .scale = 1, @@ -415,7 +425,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/sound/found/variant", .data = { .type = TYPE_SOUND, - .theme = "freedesktop", + .themes = { [0] = "freedesktop" }, .name = "network-connectivity-established", .profile = "stereo", .result = "/usr/share/sounds/freedesktop/stereo/network-connectivity-established.oga", @@ -426,7 +436,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/sound/fallback/variant", .data = { .type = TYPE_SOUND, - .theme = "freedesktop", + .themes = { [0] = "freedesktop" }, .name = "bell-too-specific", .profile = "stereo", .result = "/usr/share/sounds/freedesktop/stereo/bell.oga", @@ -437,7 +447,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/sound/fallback/freedesktop", .data = { .type = TYPE_SOUND, - .theme = "non-existing-i-hope", + .themes = { [0] = "non-existing-i-hope" }, .name = "dialog-information", .profile = "stereo", .result = "/usr/share/sounds/freedesktop/stereo/dialog-information.oga", @@ -448,7 +458,7 @@ static const struct { .testpath = "/nkutils/xdg-theme/sound/fallback/no-index", .data = { .type = TYPE_SOUND, - .theme = "purple", + .themes = { [0] = "purple" }, .name = "logout", .profile = "stereo", .result = "/usr/share/sounds/purple/logout.wav", @@ -472,10 +482,10 @@ _nk_uuid_tests_func(gconstpointer user_data) switch ( data->type ) { case TYPE_ICON: - file = nk_xdg_theme_get_icon(context, data->theme, data->context, data->name, data->size, data->scale, data->svg); + file = nk_xdg_theme_get_icon(context, data->themes, data->context, data->name, data->size, data->scale, data->svg); break; case TYPE_SOUND: - file = nk_xdg_theme_get_sound(context, data->theme, data->name, data->profile, NULL); + file = nk_xdg_theme_get_sound(context, data->themes, data->name, data->profile, NULL); break; default: g_assert_not_reached();