diff --git a/README.md b/README.md index 2ba3452..00b5436 100644 --- a/README.md +++ b/README.md @@ -53,11 +53,11 @@ See [flipclock-android](https://github.com/AlynxZhou/flipclock-android/). # Configuration -On Linux, program will first use `$XDG_CONFIG_HOME/flipclock.conf`, if `XDG_CONFIG_HOME` is not set, it will use `$HOME/.config/flipclock.conf`. +On Linux, program will first use `$XDG_CONFIG_HOME/flipclock.conf`, if `XDG_CONFIG_HOME` is not set or file does not exist, it will use `$HOME/.config/flipclock.conf`. If per-user configuration file does not exist, it will use `/etc/flipclock.conf` or `flipclock.conf` under `sysconfdir` you choosed while building. On Windows, program will use `flipclock.conf` under the same directory as program. -`flipclock.conf` will be automatically created if program does not find it, so please run program once before editing configuration file. +`flipclock.conf` should be installed with the binary by Meson. # Contribution diff --git a/dists/flipclock.conf b/dists/flipclock.conf new file mode 100644 index 0000000..ff1a466 --- /dev/null +++ b/dists/flipclock.conf @@ -0,0 +1,19 @@ +# Uncomment `ampm = true` to use 12-hour format. +#ampm = true +# Uncomment `full = false` to disable fullscreen. +# You should not change this for a screensaver. +#full = false +# Uncomment `font = ` and add path to use custom font. +#font = +# Uncomment `font_scale = 0.8` to modify digit scale. +# This scales the digits again based on card scale. +#font_scale = 0.8 +# Uncomment `rect_scale = 0.8` to modify card scale. +# This also scales the digits. +#rect_scale = 0.8 +# Uncomment `font_color = ` to modify the color of the digit. +#font_color = #000000ff +# Uncomment `rect_color = ` to modify the color of the card. +#rect_color = #fe9a00ff +# Uncomment `black_color = ` to modify the color of the background. +#back_color = #000000ff diff --git a/meson.build b/meson.build index d882c5b..86eed7c 100644 --- a/meson.build +++ b/meson.build @@ -25,6 +25,13 @@ conf_data = configuration_data() conf_data.set('project_version', meson.project_version()) conf_data.set('package_bindir', get_option('prefix') / get_option('bindir')) conf_data.set('package_datadir', get_option('prefix') / get_option('datadir')) +# `sysconfdir` is `/etc` if `prefix` is `/usr`, +# but it will be relative path if using other prefix. +# See . +# Meson's string path building operator will not join two absolute path, +# it will keep the right one, so it's OK to handle `sysconfdir` with it. +# See . +conf_data.set('package_sysconfdir', get_option('prefix') / get_option('sysconfdir')) configure_file( input: 'srcs/config.h.in', @@ -72,8 +79,8 @@ if host_machine.system() == 'linux' ) install_data( - 'LICENSE', - install_dir: get_option('datadir') / 'licenses' / meson.project_name() + 'dists' / 'flipclock.conf', + install_dir: get_option('sysconfdir') ) install_data( 'dists' / 'flipclock.ttf', @@ -87,6 +94,10 @@ if host_machine.system() == 'linux' 'dists' / 'one.alynx.FlipClock.svg', install_dir: get_option('datadir') / 'icons' / 'hicolor' / 'scalable' / 'apps' ) + install_data( + 'LICENSE', + install_dir: get_option('datadir') / 'licenses' / meson.project_name() + ) elif host_machine.system() == 'windows' if get_option('debug') == true executable( @@ -115,13 +126,17 @@ elif host_machine.system() == 'windows' endif install_data( - 'LICENSE', + 'dists' / 'flipclock.conf', install_dir: meson.project_name() ) install_data( 'dists' / 'flipclock.ttf', install_dir: meson.project_name() ) + install_data( + 'LICENSE', + install_dir: meson.project_name() + ) install_data( 'dists' / 'COPYING', install_dir: meson.project_name() diff --git a/srcs/config.h.in b/srcs/config.h.in index dfde1bb..2aff4f7 100644 --- a/srcs/config.h.in +++ b/srcs/config.h.in @@ -3,5 +3,6 @@ #define PROJECT_VERSION "@project_version@" #define PACKAGE_BINDIR "@package_bindir@" #define PACKAGE_DATADIR "@package_datadir@" +#define PACKAGE_SYSCONFDIR "@package_sysconfdir@" #endif diff --git a/srcs/flipclock.c b/srcs/flipclock.c index f8ca2fa..c5243ba 100644 --- a/srcs/flipclock.c +++ b/srcs/flipclock.c @@ -199,87 +199,70 @@ static int _flipclock_parse_color(const char *rgba, SDL_Color *color) } #if defined(_WIN32) -static void _flipclock_get_conf_path_win32(char *conf_path, - const char *program_dir) +static FILE *_flipclock_open_conf_win32(char *conf_path, + const char *program_dir) { snprintf(conf_path, MAX_BUFFER_LENGTH, "%s\\flipclock.conf", program_dir); conf_path[MAX_BUFFER_LENGTH - 1] = '\0'; if (strlen(conf_path) == MAX_BUFFER_LENGTH - 1) LOG_ERROR("conf_path too long, may fail to load.\n"); + return fopen(conf_path, "r"); } #elif defined(__linux__) -static void _flipclock_get_conf_path_linux(char *conf_path) +static FILE *_flipclock_open_conf_linux(char *conf_path) { + FILE *conf = NULL; // Be a good program. const char *conf_dir = getenv("XDG_CONFIG_HOME"); - if (conf_dir == NULL || strlen(conf_dir) == 0) { - // Linux users should not be homeless. - const char *home = getenv("HOME"); - snprintf(conf_path, MAX_BUFFER_LENGTH, - "%s/.config/flipclock.conf", home); - } else { + if (conf_dir != NULL && strlen(conf_dir) != 0) { snprintf(conf_path, MAX_BUFFER_LENGTH, "%s/flipclock.conf", conf_dir); + conf_path[MAX_BUFFER_LENGTH - 1] = '\0'; + if (strlen(conf_path) == MAX_BUFFER_LENGTH - 1) + LOG_ERROR("conf_path too long, may fail to load.\n"); + conf = fopen(conf_path, "r"); + if (conf != NULL) + return conf; + } + + // Linux users should not be homeless. But we may in sandbox. + const char *home = getenv("HOME"); + if (home != NULL && strlen(home) != 0) { + snprintf(conf_path, MAX_BUFFER_LENGTH, + "%s/.config/flipclock.conf", home); + conf_path[MAX_BUFFER_LENGTH - 1] = '\0'; + if (strlen(conf_path) == MAX_BUFFER_LENGTH - 1) + LOG_ERROR("conf_path too long, may fail to load.\n"); + conf = fopen(conf_path, "r"); + if (conf != NULL) + return conf; } + + strncpy(conf_path, PACKAGE_SYSCONFDIR "/flipclock.conf", + MAX_BUFFER_LENGTH); conf_path[MAX_BUFFER_LENGTH - 1] = '\0'; if (strlen(conf_path) == MAX_BUFFER_LENGTH - 1) LOG_ERROR("conf_path too long, may fail to load.\n"); + return fopen(conf_path, "r"); } #endif void flipclock_load_conf(struct flipclock *app) { + FILE *conf = NULL; #if defined(_WIN32) - _flipclock_get_conf_path_win32(app->properties.conf_path, - app->properties.program_dir); + conf = _flipclock_open_conf_win32(app->properties.conf_path, + app->properties.program_dir); #elif defined(__linux__) - _flipclock_get_conf_path_linux(app->properties.conf_path); + conf = _flipclock_open_conf_linux(app->properties.conf_path); #endif -#ifndef __ANDROID__ - LOG_DEBUG("Using conf_path `%s`.\n", app->properties.conf_path); -#endif - FILE *conf = fopen(app->properties.conf_path, "r"); - /** - * See https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-constants?view=msvc-160. - * errno seems work on MSVC. - */ - if (conf == NULL && errno == ENOENT) { - LOG_DEBUG("File not found, create with default content.\n"); - conf = fopen(app->properties.conf_path, "w"); - if (conf == NULL) { - // Just skip conf, it's able to run. - LOG_ERROR("Failed to write default content!\n"); - return; - } - fputs("# Uncomment `ampm = true` to use 12-hour format.\n" - "#ampm = true\n" - "# Uncomment `full = false` to disable fullscreen.\n" - "# You should not change this for a screensaver.\n" - "#full = false\n" - "# Uncomment `font = ` and " - "add path to use custom font.\n" - "#font = \n" - "# Uncomment `font_scale = 0.8` to modify digit scale.\n" - "# This scales the digits again based on card scale.\n" - "#font_scale = 0.8\n" - "# Uncomment `rect_scale = 0.8` to modify card scale.\n" - "# This also scales the digits.\n" - "#rect_scale = 0.8\n" - "# Uncomment `font_color = ` to modify " - "the color of the digit.\n" - "#font_color = #000000ff\n" - "# Uncomment `rect_color = ` to modify " - "the color of the card.\n" - "#rect_color = #fe9a00ff\n" - "# Uncomment `black_color = ` to modify " - "the color of the background.\n" - "#back_color = #000000ff\n", - conf); - fclose(conf); + // Should never happen, but it's fine. + if (conf == NULL) return; - } - /** +#ifndef __ANDROID__ + LOG_DEBUG("Parsing `%s`.\n", app->properties.conf_path); +#endif /** * Most file systems have max file name length limit. * So I don't need to alloc memory dynamically. */ @@ -305,7 +288,7 @@ void flipclock_load_conf(struct flipclock *app) app->properties.full = false; } else if (!strcmp(key, "font")) { strncpy(app->properties.font_path, value, - MAX_BUFFER_LENGTH - 1); + MAX_BUFFER_LENGTH); app->properties.font_path[MAX_BUFFER_LENGTH - 1] = '\0'; if (strlen(app->properties.font_path) == MAX_BUFFER_LENGTH - 1) @@ -586,7 +569,7 @@ void flipclock_refresh(struct flipclock *app, int clock_index) (app->clocks[clock_index].height * 0.4 > app->clocks[clock_index].width * 0.8 ? app->clocks[clock_index].width * 0.8 : - app->clocks[clock_index].height * 0.4) * + app->clocks[clock_index].height * 0.4) * app->properties.rect_scale; int space = app->clocks[clock_index].height * 0.06; app->clocks[clock_index].radius = @@ -620,7 +603,7 @@ void flipclock_refresh(struct flipclock *app, int clock_index) (app->clocks[clock_index].width * 0.4 > app->clocks[clock_index].height * 0.8 ? app->clocks[clock_index].height * 0.8 : - app->clocks[clock_index].width * 0.4) * + app->clocks[clock_index].width * 0.4) * app->properties.rect_scale; int space = app->clocks[clock_index].width * 0.06; app->clocks[clock_index].radius = @@ -1031,7 +1014,7 @@ static void _flipclock_flip_card(struct flipclock *app, int clock_index, bool upper_half = progress <= HALF_PROGRESS; double scale = upper_half ? 1.0 - (1.0 * progress) / HALF_PROGRESS : - ((1.0 * progress) - HALF_PROGRESS) / HALF_PROGRESS; + ((1.0 * progress) - HALF_PROGRESS) / HALF_PROGRESS; half_source_rect.x = card.rect.x; half_source_rect.y = card.rect.y + (upper_half ? 0 : card.rect.h / 2); half_source_rect.w = card.rect.w; @@ -1044,7 +1027,7 @@ static void _flipclock_flip_card(struct flipclock *app, int clock_index, half_target_rect.h = card.rect.h / 2 * scale; SDL_RenderCopy(app->clocks[clock_index].renderer, upper_half ? app->clocks[clock_index].textures.previous : - app->clocks[clock_index].textures.current, + app->clocks[clock_index].textures.current, &half_source_rect, &half_target_rect); }