config: handle transform opts; make implementation futureproof

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Ic67d4485d08114f605a6dc2535224b276a6a6964
This commit is contained in:
raf 2025-11-02 00:04:11 +03:00
commit 5fd2e5660f
Signed by: NotAShelf
GPG key ID: 29D95B64378DB4BF

View file

@ -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", "====================");