From 5fd2e5660f7f3898feaeeed5b1ca40f6e9931d9f Mon Sep 17 00:00:00 2001 From: NotAShelf Date: Sun, 2 Nov 2025 00:04:11 +0300 Subject: [PATCH] config: handle transform opts; make implementation futureproof Signed-off-by: NotAShelf Change-Id: Ic67d4485d08114f605a6dc2535224b276a6a6964 --- src/config.c | 195 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 186 insertions(+), 9 deletions(-) diff --git a/src/config.c b/src/config.c index 8a9551a..6dde3b1 100644 --- a/src/config.c +++ b/src/config.c @@ -52,11 +52,81 @@ static bool parse_bool(const char *value) { return false; } -// Parse integer value from string +// Parse scaling mode from string +static chroma_scale_mode_t parse_scale_mode(const char *value) { + if (!value) + return CHROMA_SCALE_FILL; // default + + if (strcasecmp(value, "fill") == 0) { + return CHROMA_SCALE_FILL; + } else if (strcasecmp(value, "fit") == 0) { + return CHROMA_SCALE_FIT; + } else if (strcasecmp(value, "stretch") == 0) { + return CHROMA_SCALE_STRETCH; + } else if (strcasecmp(value, "center") == 0) { + return CHROMA_SCALE_CENTER; + } + + chroma_log("WARN", "Unknown scaling mode: %s (using fill)", value); + return CHROMA_SCALE_FILL; +} + +// Parse filter quality from string +static chroma_filter_quality_t parse_filter_quality(const char *value) { + if (!value) + return CHROMA_FILTER_LINEAR; // default + + if (strcasecmp(value, "nearest") == 0) { + return CHROMA_FILTER_NEAREST; + } else if (strcasecmp(value, "linear") == 0) { + return CHROMA_FILTER_LINEAR; + } else if (strcasecmp(value, "bilinear") == 0) { + return CHROMA_FILTER_BILINEAR; + } else if (strcasecmp(value, "trilinear") == 0) { + return CHROMA_FILTER_TRILINEAR; + } + + chroma_log("WARN", "Unknown filter quality: %s (using linear)", value); + return CHROMA_FILTER_LINEAR; +} + +// Get string representation of scaling mode +static const char *scale_mode_to_string(chroma_scale_mode_t mode) { + switch (mode) { + case CHROMA_SCALE_FILL: + return "fill"; + case CHROMA_SCALE_FIT: + return "fit"; + case CHROMA_SCALE_STRETCH: + return "stretch"; + case CHROMA_SCALE_CENTER: + return "center"; + default: + return "unknown"; + } +} + +// Get string representation of filter quality +static const char *filter_quality_to_string(chroma_filter_quality_t quality) { + switch (quality) { + case CHROMA_FILTER_NEAREST: + return "nearest"; + case CHROMA_FILTER_LINEAR: + return "linear"; + case CHROMA_FILTER_BILINEAR: + return "bilinear"; + case CHROMA_FILTER_TRILINEAR: + return "trilinear"; + default: + return "unknown"; + } +} // Output-to-image mapping static int add_output_mapping(chroma_config_t *config, const char *output_name, - const char *image_path) { + const char *image_path, + chroma_scale_mode_t scale_mode, + chroma_filter_quality_t filter_quality) { if (!config || !output_name || !image_path) { return CHROMA_ERROR_INIT; } @@ -87,10 +157,14 @@ static int add_output_mapping(chroma_config_t *config, const char *output_name, strcpy(mapping->output_name, output_name); strcpy(mapping->image_path, image_path); + mapping->scale_mode = scale_mode; + mapping->filter_quality = filter_quality; config->mapping_count++; - chroma_log("DEBUG", "Added mapping: %s -> %s", output_name, image_path); + chroma_log("DEBUG", "Added mapping: %s -> %s (scale: %s, filter: %s)", + output_name, image_path, scale_mode_to_string(scale_mode), + filter_quality_to_string(filter_quality)); chroma_log("TRACE", "Output mapping %d: '%s' -> '%s' (path length: %zu)", config->mapping_count, output_name, image_path, path_len); return CHROMA_OK; @@ -106,6 +180,10 @@ static void init_default_config(chroma_config_t *config) { config->daemon_mode = false; config->mapping_count = 0; + // Set default scaling and filtering + config->default_scale_mode = CHROMA_SCALE_FILL; + config->default_filter_quality = CHROMA_FILTER_LINEAR; + // Set default image path (can be overridden) const char *home = getenv("HOME"); if (home) { @@ -181,6 +259,23 @@ static int parse_config_line(chroma_config_t *config, char *line, chroma_log("TRACE", "Daemon mode configuration: key='%s', value='%s', parsed=%s", key, value, config->daemon_mode ? "true" : "false"); + } else if (strcasecmp(key, "scale_mode") == 0 || + strcasecmp(key, "default_scale_mode") == 0) { + config->default_scale_mode = parse_scale_mode(value); + chroma_log("DEBUG", "Set default scale mode: %s", + scale_mode_to_string(config->default_scale_mode)); + chroma_log("TRACE", + "Scale mode configuration: key='%s', value='%s', parsed=%s", key, + value, scale_mode_to_string(config->default_scale_mode)); + } else if (strcasecmp(key, "filter_quality") == 0 || + strcasecmp(key, "default_filter_quality") == 0) { + config->default_filter_quality = parse_filter_quality(value); + chroma_log("DEBUG", "Set default filter quality: %s", + filter_quality_to_string(config->default_filter_quality)); + chroma_log("TRACE", + "Filter quality configuration: key='%s', value='%s', parsed=%s", + key, value, + filter_quality_to_string(config->default_filter_quality)); } else if (strncasecmp(key, "output.", 7) == 0) { // Output-specific mapping: e.g., output.DP-1=/path/to/image.jpg const char *output_name = key + 7; @@ -190,6 +285,46 @@ static int parse_config_line(chroma_config_t *config, char *line, return CHROMA_OK; } + // Check for extended output configuration with properties + // Format: output.DP-1.scale = fill + // Format: output.DP-1.filter = linear + char *dot = strchr(output_name, '.'); + if (dot) { + // This is an output property (scale or filter) + *dot = '\0'; + const char *property = dot + 1; + + // Find existing mapping for this output + chroma_config_mapping_t *mapping = NULL; + for (int i = 0; i < config->mapping_count; i++) { + if (strcmp(config->mappings[i].output_name, output_name) == 0) { + mapping = &config->mappings[i]; + break; + } + } + + if (!mapping) { + chroma_log("WARN", "Output %s not found for property %s (line %d)", + output_name, property, line_number); + return CHROMA_OK; + } + + if (strcasecmp(property, "scale") == 0) { + mapping->scale_mode = parse_scale_mode(value); + chroma_log("DEBUG", "Set scale mode for output %s: %s", output_name, + scale_mode_to_string(mapping->scale_mode)); + } else if (strcasecmp(property, "filter") == 0) { + mapping->filter_quality = parse_filter_quality(value); + chroma_log("DEBUG", "Set filter quality for output %s: %s", output_name, + filter_quality_to_string(mapping->filter_quality)); + } else { + chroma_log("WARN", "Unknown output property: %s (line %d)", property, + line_number); + } + + return CHROMA_OK; + } + // Expand path before validation and storage char *expanded_path = chroma_expand_path(value); const char *path_to_validate = expanded_path ? expanded_path : value; @@ -204,8 +339,9 @@ static int parse_config_line(chroma_config_t *config, char *line, return CHROMA_OK; } - if (add_output_mapping(config, output_name, path_to_validate) != - CHROMA_OK) { + if (add_output_mapping(config, output_name, path_to_validate, + config->default_scale_mode, + config->default_filter_quality) != CHROMA_OK) { chroma_log("ERROR", "Failed to add output mapping: %s -> %s", output_name, path_to_validate); if (expanded_path) { @@ -348,6 +484,37 @@ const char *chroma_config_get_image_for_output(chroma_config_t *config, return NULL; } +// Get configuration mapping for output, including scale mode and filter +// quality +int chroma_config_get_mapping_for_output( + chroma_config_t *config, const char *output_name, + chroma_scale_mode_t *scale_mode, chroma_filter_quality_t *filter_quality) { + if (!config || !output_name || !scale_mode || !filter_quality) { + return CHROMA_ERROR_INIT; + } + + // Look for specific output mapping + for (int i = 0; i < config->mapping_count; i++) { + if (strcmp(config->mappings[i].output_name, output_name) == 0) { + *scale_mode = config->mappings[i].scale_mode; + *filter_quality = config->mappings[i].filter_quality; + chroma_log("DEBUG", + "Found specific mapping for output %s: scale=%s, filter=%s", + output_name, scale_mode_to_string(*scale_mode), + filter_quality_to_string(*filter_quality)); + return CHROMA_OK; + } + } + + // Return defaults if no specific mapping found + *scale_mode = config->default_scale_mode; + *filter_quality = config->default_filter_quality; + chroma_log("DEBUG", "Using defaults for output %s: scale=%s, filter=%s", + output_name, scale_mode_to_string(*scale_mode), + filter_quality_to_string(*filter_quality)); + return CHROMA_OK; +} + // Create a sample configuration file int chroma_config_create_sample(const char *config_file) { if (!config_file) { @@ -391,14 +558,24 @@ void chroma_config_print(const chroma_config_t *config) { chroma_log("INFO", "=== Configuration ==="); chroma_log("INFO", "Default image: %s", config->default_image); chroma_log("INFO", "Daemon mode: %s", config->daemon_mode ? "true" : "false"); + chroma_log("INFO", "Default scale mode: %s", + scale_mode_to_string(config->default_scale_mode)); + chroma_log("INFO", "Default filter quality: %s", + filter_quality_to_string(config->default_filter_quality)); chroma_log("INFO", "Output mappings: %d", config->mapping_count); for (int i = 0; i < config->mapping_count; i++) { - chroma_log("INFO", " %s -> %s", config->mappings[i].output_name, - config->mappings[i].image_path); + chroma_log("INFO", " %s -> %s (scale: %s, filter: %s)", + config->mappings[i].output_name, config->mappings[i].image_path, + scale_mode_to_string(config->mappings[i].scale_mode), + filter_quality_to_string(config->mappings[i].filter_quality)); chroma_log( - "TRACE", " Mapping %d: output='%s', image='%s', path_exists=%s", i, - config->mappings[i].output_name, config->mappings[i].image_path, + "TRACE", + " Mapping %d: output='%s', image='%s', scale='%s', filter='%s', " + "path_exists=%s", + i, config->mappings[i].output_name, config->mappings[i].image_path, + scale_mode_to_string(config->mappings[i].scale_mode), + filter_quality_to_string(config->mappings[i].filter_quality), chroma_path_exists(config->mappings[i].image_path) ? "yes" : "no"); } chroma_log("INFO", "====================");