From 6ab3b52fbde3ab2ac11e66e4d664f67e108f6aee Mon Sep 17 00:00:00 2001 From: Federico Angelilli Date: Wed, 27 Nov 2024 23:19:38 +0100 Subject: Rework resolve functions --- comet.conf | 3 +- src/action.c | 8 +++- src/action.h | 4 ++ src/block.c | 22 +++++++++ src/block.h | 8 ++++ src/blocks/group.c | 57 ++++++++++++++++++++++ src/blocks/slider.c | 64 ++++++++++++++++++------- src/comet.c | 2 +- src/config.c | 133 ++++++++++++++-------------------------------------- src/config.h | 4 +- src/util.c | 2 +- src/util.h | 4 +- 12 files changed, 188 insertions(+), 123 deletions(-) diff --git a/comet.conf b/comet.conf index ec03a52..54f6000 100644 --- a/comet.conf +++ b/comet.conf @@ -115,7 +115,8 @@ ;action-left-click = just ;on-left-click = just ;when-left-click = just - left-click = just + ;left-click = just + left-click-bar = just [action.just] ;block.slide.color = #18baf2 diff --git a/src/action.c b/src/action.c index 1ea7d7f..3a358c3 100644 --- a/src/action.c +++ b/src/action.c @@ -124,10 +124,16 @@ error: int action_validate(action_t *action, config_t *config) { - // TODO + action->validated = true; return 0; } +bool action_resolve(action_t *action, config_t *config) +{ + action->resolved = true; + return true; +} + void action_free(action_t *action) { for (size_t i = 0; i < action->length; i++) { diff --git a/src/action.h b/src/action.h index 712bf81..795a79c 100644 --- a/src/action.h +++ b/src/action.h @@ -22,6 +22,8 @@ struct action { char *label; action_part_t *parts; size_t length; + bool validated; + bool resolved; }; typedef struct action action_t; @@ -30,6 +32,8 @@ bool action_perform(action_t *action, block_t *block, config_t *config); int action_validate(action_t *action, config_t *config); +bool action_resolve(action_t *action, config_t *config); + void action_free(action_t *action); #endif diff --git a/src/block.c b/src/block.c index 1786502..04ad902 100644 --- a/src/block.c +++ b/src/block.c @@ -3,6 +3,7 @@ #include "block.h" #include "util.h" +#include "action.h" #include "any_log.h" extern const block_scheme_t block_text_scheme; @@ -50,6 +51,27 @@ void block_update(block_t *block) } } +bool block_resolve(block_t *block, config_t *config) +{ + if (block->resolved) + return true; + + block->resolved = true; + + for (size_t i = 0; i < EVENT_MAX; i++) { + char *action = (char *)block->actions[i]; + if (action == NULL) continue; + + if (!config_resolve_action(config, action, &block->actions[i])) + return false; + + free(action); + } + + return block->scheme->resolve_fn == NULL + || block->scheme->resolve_fn(block, config); +} + bool block_change(block_t *block, config_t *config, const char *key, const char *value) { extern const config_entry_t block_entries[]; diff --git a/src/block.h b/src/block.h index be62d20..940231a 100644 --- a/src/block.h +++ b/src/block.h @@ -54,6 +54,7 @@ struct block { const block_scheme_t *scheme; bool validated; bool resolved; + bool grouped; bool hidden; struct timespec update_interval; struct timespec update_last; @@ -104,6 +105,10 @@ typedef void (*block_clean_t)(block_t *block); // typedef int (*block_validate_t)(block_t *block, config_t *config); +// Called to resolve references in the block +// +typedef bool (*block_resolve_t)(block_t *block, config_t *config); + // Called to validate changes to a block variable // typedef config_status_t (*block_change_t)(block_t *block, config_t *config, const char *key, const char *value); @@ -116,6 +121,7 @@ struct block_scheme { block_init_t init_fn; block_clean_t clean_fn; block_validate_t validate_fn; + block_resolve_t resolve_fn; block_change_t change_fn; }; @@ -123,6 +129,8 @@ extern const block_scheme_t *block_schemes[]; void block_update(block_t *block); +bool block_resolve(block_t *block, config_t *config); + bool block_change(block_t *block, config_t *config, const char *key, const char *value); void block_free(block_t *block); diff --git a/src/blocks/group.c b/src/blocks/group.c index eeac132..da9e6d6 100644 --- a/src/blocks/group.c +++ b/src/blocks/group.c @@ -1,3 +1,5 @@ +#include + #include "../block.h" #include "../any_log.h" @@ -12,6 +14,60 @@ static void block_group_clean(block_t *block) free(group->children); } +static bool block_group_resolve(block_t *block, config_t *config) +{ + block_group_t *group = (block_group_t *)block; + assert(block->type == BLOCK_GROUP); + + char **children = (char **)group->children; + group->children = NULL; + group->n_children = 0; + + if (children == NULL) + return true; + + while (children[group->n_children] != NULL) + group->n_children++; + + group->children = malloc(group->n_children * sizeof(block_t *)); + bool result = true; + + for (size_t i = 0; i < group->n_children; i++) { + for (size_t j = 0; j < config->n_blocks; j++) { + if (config->blocks[j] == block) + continue; + + if (!strcmp(children[i], config->blocks[j]->label)) { + if (config->blocks[j]->grouped) { + log_error("Block '%s' can only be in one group", children[i]); + result = false; + goto end; + } + + log_debug("Block '%s' is parent of '%s'", block->label, children[i]); + group->children[i] = config->blocks[j]; + group->children[i]->grouped = true; + + if (!block_resolve(group->children[i], config)) { + result = false; + goto end; + } + + goto next; + } + } + + log_error("Block '%s' not found (referenced by '%s')", children[i], block->label); + result = false; + goto end; +next: + } + +end: + strfreelist(children); + return result; +} + static config_status_t block_group_change(block_t *block, config_t *config, const char *key, const char *value) { if (!strcmp(key, "blocks")) { @@ -30,5 +86,6 @@ const block_scheme_t block_group_scheme = { .init_fn = block_group_init, .clean_fn = block_group_clean, .validate_fn = NULL, + .resolve_fn = block_group_resolve, .change_fn = block_group_change, }; diff --git a/src/blocks/slider.c b/src/blocks/slider.c index 34d6c35..1b5d4c3 100644 --- a/src/blocks/slider.c +++ b/src/blocks/slider.c @@ -34,6 +34,9 @@ typedef struct { gradient_t knob_color; gradient_t knob_line_color; double knob_rotation; + action_t *left_click; + action_t *middle_click; + action_t *right_click; } block_slider_t; static void block_slider_layout(block_t *block, layout_t *layout, layout_info_t info) @@ -242,6 +245,29 @@ static int block_slider_validate(block_t *block, config_t *config) return errors; } +static bool block_slider_resolve(block_t *block, config_t *config) +{ + block_slider_t *slider = (block_slider_t *)block; + + action_t **actions[] = { + &slider->left_click, + &slider->middle_click, + &slider->right_click, + }; + + for (size_t i = 0; i < 3; i++) { + char *label = (char *)*actions[i]; + if (label == NULL) continue; + + if (!config_resolve_action(config, label, actions[i])) + return false; + + free(label); + } + + return true; +} + static config_enum_t knob_shape_enum[] = { { "none", KNOB_NONE }, { "capsule", KNOB_CAPSULE }, @@ -252,23 +278,26 @@ static config_enum_t knob_shape_enum[] = { static const config_entry_t block_slider_entries[] = { // TODO: Ugly names - { "bar-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, bar_color) }, - { "bar-line-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, line_color) }, - { "bar-bg-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, bg_color) }, - { "bar-height", CONFIG_UINT, NULL, offsetof(block_slider_t, height) }, - { "bar-width", CONFIG_UINT, NULL, offsetof(block_slider_t, width) }, - { "bar-line-width", CONFIG_UINT, NULL, offsetof(block_slider_t, line_width) }, - { "bar-value", CONFIG_INT, NULL, offsetof(block_slider_t, value) }, - { "seekable", CONFIG_BOOL, NULL, offsetof(block_slider_t, seekable) }, - { "knob", CONFIG_ENUM, knob_shape_enum, offsetof(block_slider_t, knob) }, - { "knob-height", CONFIG_UINT, NULL, offsetof(block_slider_t, knob_height) }, - { "knob-width", CONFIG_UINT, NULL, offsetof(block_slider_t, knob_width) }, - { "knob-line-width", CONFIG_UINT, NULL, offsetof(block_slider_t, knob_line_width) }, - { "knob-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, knob_color) }, - { "knob-line-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, knob_line_color) }, - { "knob-x-offset", CONFIG_INT, NULL, offsetof(block_slider_t, knob_x_offset) }, - { "knob-y-offset", CONFIG_INT, NULL, offsetof(block_slider_t, knob_y_offset) }, - { "knob-rotation", CONFIG_DOUBLE, NULL, offsetof(block_slider_t, knob_rotation) }, + { "bar-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, bar_color) }, + { "bar-line-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, line_color) }, + { "bar-bg-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, bg_color) }, + { "bar-height", CONFIG_UINT, NULL, offsetof(block_slider_t, height) }, + { "bar-width", CONFIG_UINT, NULL, offsetof(block_slider_t, width) }, + { "bar-line-width", CONFIG_UINT, NULL, offsetof(block_slider_t, line_width) }, + { "bar-value", CONFIG_INT, NULL, offsetof(block_slider_t, value) }, + { "seekable", CONFIG_BOOL, NULL, offsetof(block_slider_t, seekable) }, + { "knob", CONFIG_ENUM, knob_shape_enum, offsetof(block_slider_t, knob) }, + { "knob-height", CONFIG_UINT, NULL, offsetof(block_slider_t, knob_height) }, + { "knob-width", CONFIG_UINT, NULL, offsetof(block_slider_t, knob_width) }, + { "knob-line-width", CONFIG_UINT, NULL, offsetof(block_slider_t, knob_line_width) }, + { "knob-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, knob_color) }, + { "knob-line-color", CONFIG_GRADIENT, NULL, offsetof(block_slider_t, knob_line_color) }, + { "knob-x-offset", CONFIG_INT, NULL, offsetof(block_slider_t, knob_x_offset) }, + { "knob-y-offset", CONFIG_INT, NULL, offsetof(block_slider_t, knob_y_offset) }, + { "knob-rotation", CONFIG_DOUBLE, NULL, offsetof(block_slider_t, knob_rotation) }, + { "left-click-bar", CONFIG_STRING, NULL, offsetof(block_slider_t, left_click) }, + { "middle-click-bar", CONFIG_STRING, NULL, offsetof(block_slider_t, middle_click) }, + { "right-click-bar", CONFIG_STRING, NULL, offsetof(block_slider_t, right_click) }, { 0 }, }; @@ -285,5 +314,6 @@ const block_scheme_t block_slider_scheme = { .init_fn = block_slider_init, .clean_fn = block_slider_clean, .validate_fn = block_slider_validate, + .resolve_fn = block_slider_resolve, .change_fn = block_slider_change, }; diff --git a/src/comet.c b/src/comet.c index 9ff848c..8cd9f24 100644 --- a/src/comet.c +++ b/src/comet.c @@ -112,7 +112,7 @@ int main(int argc, char **argv) }; block_t *block = NULL; - if (config_resolve(&config, &block) > 0) { + if (!config_resolve(&config, &block)) { log_error("Config could not be resolved"); return EXIT_FAILURE; } diff --git a/src/config.c b/src/config.c index c8b63b4..e7c47d7 100644 --- a/src/config.c +++ b/src/config.c @@ -205,8 +205,8 @@ static bool config_read_color(const char *value, color_t *result) static bool config_read_gradient(const char *value, gradient_t *result) { - // TODO: Ensure that this is correct gradient_free(result); + memset(result, 0, sizeof(gradient_t)); size_t count = 0; for (size_t i = 0; value[i] != '\0'; ++i) @@ -235,15 +235,15 @@ static bool config_read_gradient(const char *value, gradient_t *result) } free(copy); - result->colors = colors; - result->length = n; - if (n == 0) { free(colors); log_debug("Expected at least one color"); return false; } + result->colors = colors; + result->length = n; + if (n == 1) { result->pattern = cairo_pattern_create_rgba(colors->r, colors->g, colors->b, colors->a); return true; @@ -289,8 +289,8 @@ static bool config_read_time(const char *value, struct timespec *result) // TODO: Handle quotation marks static bool config_read_list(const char *value, char ***result) { - // TODO: Ensure that this is correct - strfree(*result); + strfreelist(*result); + *result = NULL; size_t count = 0; for (size_t i = 0; value[i] != '\0'; ++i) @@ -312,9 +312,9 @@ static bool config_read_list(const char *value, char ***result) *end = '\0'; if (!config_read_string(token, &list[n++])) { - free(copy); list[n] = NULL; - strfree(list); + strfreelist(list); + free(copy); return false; } } @@ -716,6 +716,12 @@ skip_pair: int config_validate(config_t *config) { int errors = 0; + block_group_t *bar = (block_group_t *)config->blocks[0]; + + if (bar->children == NULL) { + log_error("Section '%s' requires at least one child", "bar"); + errors++; + } // Validate the config itself if (config->scale < 1 && config->scale != 0) { @@ -737,7 +743,6 @@ int config_validate(config_t *config) } // Validate actions - // NOTE: Maybe move this after the config is resolved? // for (size_t i = 0; i < config->n_actions; i++) { action_t *action = &config->actions[i]; @@ -748,109 +753,41 @@ int config_validate(config_t *config) return errors; } -bool config_resolve_action(config_t *config, block_t *block) +bool config_resolve_action(config_t *config, const char *label, action_t **action) { - action_t *actions[EVENT_MAX] = { 0 }; - - for (size_t i = 0; i < EVENT_MAX; i++) { - char *label = (char *)block->actions[i]; - - if (label == NULL) - continue; - - for (size_t j = 0; j < config->n_actions; j++) { - if (!strcmp(label, config->actions[j].label)) { - log_debug("Block '%s' uses action '%s' for %s", block->label, label, event_type_to_string(i)); - - actions[i] = &config->actions[j]; - free(label); - goto next; - } + for (size_t j = 0; j < config->n_actions; j++) { + if (!strcmp(label, config->actions[j].label)) { + *action = &config->actions[j]; + return true; } - - log_error("Action '%s' not found (referenced by '%s')", label, block->label); - return false; -next: } - memcpy(block->actions, actions, sizeof(actions)); - return true; + log_error("Action '%s' not found", label); + return false; } -bool config_resolve_children(config_t *config, block_t *block) +bool config_resolve(config_t *config, block_t **block) { - block->resolved = true; - - if (!config_resolve_action(config, block)) - return false; - - if (block->type != BLOCK_GROUP) - return true; - - assert(block->type == BLOCK_GROUP); - block_group_t *group = (block_group_t *)block; - - char **children = (char **)group->children; - group->children = NULL; - group->n_children = 0; - - if (children == NULL) - return true; - - while (children[group->n_children] != NULL) - group->n_children++; - - group->children = malloc(group->n_children * sizeof(block_t *)); - - for (size_t i = 0; i < group->n_children; i++) { - for (size_t j = 0; j < config->n_blocks; j++) { - if (config->blocks[j] == block) - continue; - - if (!strcmp(children[i], config->blocks[j]->label)) { - if (config->blocks[j]->resolved) { - log_error("Block '%s' can only be referenced by one block", children[i]); - goto error; - } - - log_debug("Block '%s' is parent of '%s'", block->label, children[i]); - group->children[i] = config->blocks[j]; - - if (!config_resolve_children(config, config->blocks[j])) - goto error; - goto next; - } - } + block_group_t *bar = (block_group_t *)config->blocks[0]; + assert(bar->children != NULL); - log_error("Block '%s' not found (referenced by '%s')", children[i], block->label); - goto error; -next: + for (size_t i = 0; i < config->n_actions; i++) { + if (!action_resolve(&config->actions[i], config)) + return false; } - strfree(children); - return true; - -error: - strfree(children); - return false; -} - -int config_resolve(config_t *config, block_t **block) -{ - int errors = 0; - block_group_t *bar = (block_group_t *)config->blocks[0]; + log_debug("Resolved %zu actions", config->n_actions); - if (bar->children == NULL) { - errors++; - log_error("Section '%s' requires at least one child", "bar"); - } else { - // NOTE: The first item is the main block - bar->block.min_width = bar->block.max_width = config->width; - errors += !config_resolve_children(config, config->blocks[0]); + for (size_t i = 0; i < config->n_blocks; i++) { + if (!block_resolve(config->blocks[i], config)) + return false; } + log_debug("Resolved %zu blocks", config->n_blocks); + *block = config->blocks[0]; - return errors; + bar->block.min_width = bar->block.max_width = config->width; + return true; } void config_free(config_t *config) diff --git a/src/config.h b/src/config.h index 9a26615..6a13ab3 100644 --- a/src/config.h +++ b/src/config.h @@ -73,9 +73,9 @@ int config_read(config_t *config, FILE *file); int config_validate(config_t *config); -bool config_resolve_children(config_t *config, block_t *block); +bool config_resolve_action(config_t *config, const char *label, action_t **action); -int config_resolve(config_t *config, block_t **block); +bool config_resolve(config_t *config, block_t **block); void config_free(config_t *config); diff --git a/src/util.c b/src/util.c index 6001a31..0c58808 100644 --- a/src/util.c +++ b/src/util.c @@ -194,7 +194,7 @@ size_t strprefix(const char *string, const char *prefix) return i; } -void strfree(char **list) +void strfreelist(char **list) { if (list == NULL) return; diff --git a/src/util.h b/src/util.h index 2326c8d..390bc88 100644 --- a/src/util.h +++ b/src/util.h @@ -81,10 +81,10 @@ bool strfind(const char *string, const char *cases[]); size_t strprefix(const char *string, const char *prefix); -void strfree(char **list); - bool iszero(const void *ptr, size_t size); +void strfreelist(char **list); + double steps(double value, int n); void render_triangle(cairo_t *cr, int x, int y, int w, int h); -- cgit v1.2.3