/* * Find the configuration and theme directories * * Copyright Johan Malm 2020 */ #include #include #include #include #include #include "common/dir.h" struct dir { const char *prefix; const char *path; }; /* clang-format off */ static struct dir config_dirs[] = { { "XDG_CONFIG_HOME", "labwc" }, { "HOME", ".config/labwc" }, { "XDG_CONFIG_DIRS", "labwc" }, { NULL, "/etc/xdg/labwc" }, { "XDG_CONFIG_HOME", "openbox" }, { "HOME", ".config/openbox" }, { "XDG_CONFIG_DIRS", "openbox" }, { NULL, "/etc/xdg/openbox" }, { NULL, NULL } }; static struct dir theme_dirs[] = { { "XDG_DATA_HOME", "themes" }, { "HOME", ".local/share/themes" }, { "HOME", ".themes" }, { "XDG_DATA_DIRS", "themes" }, { NULL, "/usr/share/themes" }, { NULL, "/usr/local/share/themes" }, { NULL, "opt/share/themes" }, { NULL, NULL } }; /* clang-format on */ static bool isdir(const char *path) { struct stat st; return (!stat(path, &st) && S_ISDIR(st.st_mode)); } struct ctx { void (*build_path_fn)(struct ctx *ctx, char *prefix, const char *path); char *buf; size_t len; struct dir *dirs; const char *theme_name; }; static void build_config_path(struct ctx *ctx, char *prefix, const char *path) { if (!prefix) snprintf(ctx->buf, ctx->len, "%s", path); else snprintf(ctx->buf, ctx->len, "%s/%s", prefix, path); } static void build_theme_path(struct ctx *ctx, char *prefix, const char *path) { if (!prefix) snprintf(ctx->buf, ctx->len, "%s/%s/openbox-3", path, ctx->theme_name); else snprintf(ctx->buf, ctx->len, "%s/%s/%s/openbox-3", prefix, path, ctx->theme_name); } char *find_dir(struct ctx *ctx) { char *debug = getenv("LABWC_DEBUG_DIR_CONFIG_AND_THEME"); for (int i = 0; ctx->dirs[i].path; i++) { struct dir d = ctx->dirs[i]; if (!d.prefix) { /* handle /etc/xdg... */ ctx->build_path_fn(ctx, NULL, d.path); if (debug) fprintf(stderr, "DEBUG: %s\n", ctx->buf); if (isdir(ctx->buf)) return ctx->buf; } else { /* handle $HOME/.config/... and $XDG_* */ char *prefix = getenv(d.prefix); if (!prefix) continue; gchar **prefixes = g_strsplit(prefix, ":", -1); for (gchar **p = prefixes; *p; p++) { ctx->build_path_fn(ctx, *p, d.path); if (debug) fprintf(stderr, "DEBUG: %s\n", ctx->buf); if (isdir(ctx->buf)) return ctx->buf; } } } /* no directory was found */ ctx->buf[0] = '.'; ctx->buf[1] = '\0'; return ctx->buf; } char *config_dir(void) { static char buf[4096] = { 0 }; if (buf[0] != '\0') return buf; struct ctx ctx = { .build_path_fn = build_config_path, .buf = buf, .len = sizeof(buf), .dirs = config_dirs }; return find_dir(&ctx); } char *theme_dir(const char *theme_name) { static char buf[4096] = { 0 }; if (buf[0] != '\0') return buf; struct ctx ctx = { .build_path_fn = build_theme_path, .buf = buf, .len = sizeof(buf), .dirs = theme_dirs, .theme_name = theme_name }; return find_dir(&ctx); }