diff --git a/.gitignore b/.gitignore index c94817c..487fbaf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ docs/Gemfile.lock docs/_site docs/.jekyll-cache +build/ diff --git a/src/image.c b/src/image.c index df4a7c8..360865c 100644 --- a/src/image.c +++ b/src/image.c @@ -11,6 +11,7 @@ #include "util.h" #include "debug.h" #include +#include #define NANOSVG_IMPLEMENTATION #include #define NANOSVGRAST_IMPLEMENTATION @@ -106,6 +107,61 @@ int load_next_slideshow_background_async(void *data) return 0; } +#ifdef __unix__ +SDL_Surface *load_surface_from_xdg(const char *path){ + // TODO: allow the user to specify a specific theme in the config.ini + // then prefer that to `hicolor`. + // Spec for this is here: https://specifications.freedesktop.org/icon-theme/latest/#icon_lookup + SDL_Surface *surface = NULL; + const char* xdg_dirs = getenv("XDG_DATA_DIRS"); + const char* sizes[] = { + "scalable", + "512x512", + "256x256", + "128x128", + "64x64", + "32x32" + }; + const char* exts[] = {"", ".svg", ".png"}; + + for(int i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++){ + char icon_path[128] = {}; + snprintf(icon_path, 127, "/icons/hicolor/%s/apps/", sizes[i]); + + if(xdg_dirs != NULL){ + ssize_t last_delim = -1; + ssize_t dirs_len = strlen(xdg_dirs); + while(surface == NULL && last_delim < dirs_len){ + char xdg_path[4096] = {0}; + ssize_t start_ind = last_delim; + if(start_ind < 0) + start_ind = 0; + + ssize_t end = strcspn(&xdg_dirs[start_ind], ":"); + memcpy(&xdg_path, &xdg_dirs[start_ind], end); + memcpy(&xdg_path[end], icon_path, strlen(icon_path)); + memcpy(&xdg_path[end + strlen(icon_path)], path, strlen(path)); + for(int j = 0; j < sizeof(exts) / sizeof(exts[0]); j++){ + memcpy(&xdg_path[end + strlen(icon_path) + strlen(path)], exts[j], strlen(exts[j])); + surface = IMG_Load(xdg_path); + if (surface != NULL) + return surface; + } + + + + last_delim += end + 1; + } + } + } + + log_error( + "Could not load %s from XDG_DATA_DIRS", + path + ); +} +#endif + // A function to load a texture from a file SDL_Texture *load_texture_from_file(const char *path) { @@ -119,8 +175,13 @@ SDL_Texture *load_texture_from_file(const char *path) path, IMG_GetError() ); +#ifdef __unix__ + // we failed to find the image normally, lets try xdg on unix + surface = load_surface_from_xdg(path); +#endif } - else + + if(surface != NULL) texture = load_texture(surface); } return texture; diff --git a/src/image.h b/src/image.h index b32d612..065719a 100644 --- a/src/image.h +++ b/src/image.h @@ -28,6 +28,9 @@ void render_scroll_indicators(Scroll *scroll, int height, Geometry *geo); SDL_Surface *load_next_slideshow_background(Slideshow *slideshow, bool transition); int load_next_slideshow_background_async(void *data); SDL_Texture *load_texture(SDL_Surface *surface); +#ifdef __unix__ +SDL_Surface *load_surface_from_xdg(const char *path); +#endif SDL_Texture *load_texture_from_file(const char *path); SDL_Texture *rasterize_svg(char *buffer, int w, int h, SDL_Rect *rect); SDL_Texture *rasterize_svg_from_file(const char *path, int w, int h, SDL_Rect *rect); diff --git a/src/launcher.c b/src/launcher.c index 3b8e0bc..8bd38d8 100755 --- a/src/launcher.c +++ b/src/launcher.c @@ -723,6 +723,7 @@ static void move_right() calculate_button_geometry(current_menu->root_entry, (int) buttons); if (config.highlight) highlight->rect.x = current_entry->icon_rect.x - config.highlight_hpadding; + highlight->rect.x = current_entry->icon_rect.x - config.highlight_hpadding; current_menu->page++; current_menu->highlight_position = 0; } diff --git a/src/util.c b/src/util.c index 1df240b..a97f2cf 100755 --- a/src/util.c +++ b/src/util.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -124,6 +125,65 @@ void parse_config_file(const char *config_file_path) log_fatal("Could not parse config file"); } +#ifdef __unix__ +int desktop_config_handler(void *user, const char *section, const char *name, const char *value){ + Entry* entry = (Entry*)(user); + if(MATCH(section, "Desktop Entry")){ + if(MATCH(name, "Icon")) + entry->icon_path = strdup(value); + + if(MATCH(name, "Exec")){ + ssize_t end = strcspn(value, "%@"); + char* cmd = malloc(end + 1); + cmd[end] = '\0'; + memcpy(cmd, value, end); + entry->cmd = cmd; + log_error("Parsed command '%s' from desktop file.", cmd); + } + + if(MATCH(name, "Name")) + entry->title = strdup(value); + return 0; + } + return 1; +} + + +Entry parse_possible_desktop_file(const char* name){ + const char* xdg_dirs = getenv("XDG_DATA_DIRS"); + const char* app_path = "/applications/"; + + Entry result = {}; + if(xdg_dirs != NULL){ + ssize_t last_delim = -1; + ssize_t dirs_len = strlen(xdg_dirs); + while(last_delim < dirs_len){ + char xdg_path[4096] = {0}; + ssize_t start_ind = last_delim; + if(start_ind < 0) + start_ind = 0; + + ssize_t end = strcspn(&xdg_dirs[start_ind], ":"); + memcpy(&xdg_path, &xdg_dirs[start_ind], end); + memcpy(&xdg_path[end], app_path, strlen(app_path)); + memcpy(&xdg_path[end + strlen(app_path)], name, strlen(name)); + + FILE *file = fopen(xdg_path, "r"); + if(file != NULL){ + int error = ini_parse_file(file, desktop_config_handler, &result); + fclose(file); + if(error == 0) + return result; + } + last_delim += end + 1; + } + } + return result; + +} +#endif + + // A function to handle config file parsing int config_handler(void *user, const char *section, const char *name, const char *value) { @@ -445,8 +505,19 @@ int config_handler(void *user, const char *section, const char *name, const char // Store data in entry struct int i; for (i = 0;i < 3 && token != NULL; i++) { - if (i == 0) + if (i == 0){ entry->title = strdup(token); +#ifdef __unix__ + Entry ent = parse_possible_desktop_file(entry->title); + if(ent.cmd != NULL || ent.icon_path != NULL || ent.title != NULL){ + entry->cmd = ent.cmd; + entry->icon_path = ent.icon_path; + entry->title = ent.title; + i = 3; + break; + } +#endif + } else if (i == 1) { entry->icon_path = strdup(token); clean_path(entry->icon_path); @@ -1101,4 +1172,4 @@ void sprintf_alloc(char **buffer, const char *format, ...) } va_end(args1); va_end(args2); -} \ No newline at end of file +} diff --git a/src/util.h b/src/util.h index 90dc0cf..b6bc676 100755 --- a/src/util.h +++ b/src/util.h @@ -23,6 +23,11 @@ struct gamepad_info { }; int config_handler(void *user, const char *section, const char *name, const char *value); +#ifdef __unix__ +int desktop_config_handler(void *user, const char *section, const char *name, const char *value); +Entry parse_possible_desktop_file(const char* name); +#endif + int convert_percent(const char *string, int max_value); const char *get_mode_setting(int type, int value); int utf8_length(const char *string); @@ -46,4 +51,4 @@ void read_file(const char *path, char **buffer); void sprintf_alloc(char **buffer, const char *format, ...); Uint16 get_unicode_code_point(const char *p, int *bytes); Menu *get_menu(const char *menu_name); -Entry *advance_entries(Entry *entry, int spaces, Direction direction); \ No newline at end of file +Entry *advance_entries(Entry *entry, int spaces, Direction direction);