diff options
| -rw-r--r-- | comet.conf | 7 | ||||
| -rw-r--r-- | src/blocks/scheme.h | 4 | ||||
| -rw-r--r-- | src/config.c | 117 | ||||
| -rw-r--r-- | src/config.h | 6 | ||||
| -rw-r--r-- | src/effect.c | 43 | ||||
| -rw-r--r-- | src/effect.h | 16 | ||||
| -rw-r--r-- | src/effects/pulse.c | 75 | ||||
| -rw-r--r-- | src/effects/scheme.c | 8 | ||||
| -rw-r--r-- | src/effects/scheme.h | 23 | ||||
| -rw-r--r-- | src/event.c | 6 |
10 files changed, 243 insertions, 62 deletions
@@ -11,6 +11,12 @@ [jib] sus = false +[effect.cool] + type = pulse + duration = 100 + amplitude = 20 + + [block.try2] type=group blocks = try @@ -30,6 +36,7 @@ color = #DC143C spacing = 20 blocks = cpu, ram, disk + effect = cool [block.cpu] type = text diff --git a/src/blocks/scheme.h b/src/blocks/scheme.h index 1795013..f3b0499 100644 --- a/src/blocks/scheme.h +++ b/src/blocks/scheme.h @@ -1,5 +1,5 @@ -#ifndef COMET_SCHEME_H -#define COMET_SCHEME_H +#ifndef COMET_BLOCKS_SCHEME_H +#define COMET_BLOCKS_SCHEME_H #include "../block.h" diff --git a/src/config.c b/src/config.c index 84804bc..1b88b06 100644 --- a/src/config.c +++ b/src/config.c @@ -10,6 +10,7 @@ #include "util.h" #include "block.h" #include "blocks/scheme.h" +#include "effects/scheme.h" #define ANY_INI_IMPLEMENT #include "any_ini.h" @@ -43,6 +44,11 @@ static const config_entry_t block_entries[] = { { 0 }, }; +static const config_entry_t effect_entries[] = { + { "duration", CONFIG_TIME, NULL, offsetof(effect_t, duration) }, + { 0 }, +}; + static const config_entry_t block_group_entries[] = { { "spacing", CONFIG_UINT, NULL, offsetof(block_t, group.spacing) }, { "blocks", CONFIG_LIST, NULL, offsetof(block_t, group.children) }, @@ -350,6 +356,17 @@ static config_status_t config_read_block(const block_scheme_t *scheme, block_t * : config_read_entry(scheme->entries, block->state, type, section, key, value); } +static config_status_t config_read_effect(const effect_scheme_t *scheme, effect_t *effect, const char **type, + const char *section, const char *key, const char *value) +{ + config_status_t status = config_read_entry(effect_entries, effect, type, section, key, value); + if (status != CONFIG_UNKNOWN) return status; + + return status != CONFIG_UNKNOWN || scheme == NULL || scheme->entries == NULL + ? status + : config_read_entry(scheme->entries, effect->state, type, section, key, value); +} + void config_init(config_t *config) { const config_t config_default = { @@ -383,9 +400,13 @@ void config_read(config_t *config, FILE *file) int errors = 0; bool bar_section = false; + const block_scheme_t *scheme = NULL; block_t *block = NULL; + const effect_scheme_t *escheme = NULL; + effect_t *effect = NULL; + if (section != NULL) { if (!strncmp(section, "block.", 6)) { config->blocks = realloc(config->blocks, ++config->n_blocks * sizeof(block_t)); @@ -451,6 +472,70 @@ void config_read(config_t *config, FILE *file) "i:line", ini.line); goto skip_pair; + } else if (!strncmp(section, "effect.", 7)) { + config->effects = realloc(config->effects, ++config->n_effects * sizeof(effect_t)); + assert(config->effects != NULL); + effect = &config->effects[config->n_effects - 1]; + + char *label = strcopy(section + 6); + if (label == NULL || *label == '\0') { + ++errors; + log_value_error("Effect section must have a valid label", + "s:section", section, + "i:line", ini.line); + } else { + for (size_t i = 0; i < config->n_effects - 1; i++) { + if (!strcmp(label, config->effects[i].label)) { + ++errors; + log_value_error("Effect section must have a unique label", + "s:section", section, + "i:line", ini.line); + } + } + } + + if ((key = any_ini_stream_next_key(&ini)) == NULL || strcmp(key, "type")) { + ++errors; + log_value_error("Effect section must start with a 'type' pair", + "s:section", section, + "s:wrong_key", key, + "i:line", ini.line); + goto skip_pair; + } + + value = any_ini_stream_next_value(&ini); + if (value == NULL) { + ++errors; + log_value_error("Effect type must be non-empty", + "s:section", section, + "i:line", ini.line); + goto skip_pair; + } + + for (int i = 0; effect_schemes[i] != NULL; i++) { + if (strcmp(effect_schemes[i]->name, value)) + continue; + + escheme = effect_schemes[i]; + effect_copy(effect, &escheme->effect); + free(effect->label); + effect->label = label; + + if (escheme->size != 0) { + effect->state = malloc(escheme->size); + memset(effect->state, 0, escheme->size); + } + + goto skip_pair; + } + + ++errors; + log_value_error("Effect type not supported", + "s:section", section, + "s:type", value, + "i:line", ini.line); + + goto skip_pair; } else if (!strcmp(section, "bar")) { bar_section = true; } else @@ -466,25 +551,31 @@ void config_read(config_t *config, FILE *file) "s:value", value, "i:line", ini.line); - if (!bar_section && block == NULL) + if (!bar_section && block == NULL && effect == NULL) goto skip_pair; const char *type; config_status_t status; - if (bar_section) { - status = config_read_entry(bar_entries, config, &type, section, key, value); + if (effect != NULL) { + status = config_read_effect(escheme, &config->effects[config->n_effects - 1], + &type, section, key, value); + } else { + if (bar_section) { + status = config_read_entry(bar_entries, config, &type, section, key, value); - // Try the block entries - if (status == CONFIG_UNKNOWN) - block = config->blocks; - } + // Try the block entries + if (status == CONFIG_UNKNOWN) + block = config->blocks; + } - if (block != NULL) { - status = config_read_block(scheme, &config->blocks[config->n_blocks - 1], - &type, section, key, value); + if (block != NULL) { + status = config_read_block(scheme, &config->blocks[config->n_blocks - 1], + &type, section, key, value); + } } + switch (status) { case CONFIG_SUCCESS: break; @@ -522,6 +613,12 @@ skip_pair: else errors += !scheme->validate(block, scheme); } + if (effect != NULL && escheme != NULL && escheme->validate != NULL) { + if (errors != 0) + log_trace("Skipped validation for effect '%s'", section); + else + errors += !escheme->validate(effect, escheme); + } free(section); n_errors += errors; diff --git a/src/config.h b/src/config.h index a7d196f..4580031 100644 --- a/src/config.h +++ b/src/config.h @@ -8,6 +8,8 @@ typedef struct block block_t; +typedef struct effect effect_t; + typedef enum { CONFIG_STRING, CONFIG_INT, @@ -30,6 +32,8 @@ typedef struct { typedef struct { size_t n_blocks; block_t *blocks; + size_t n_effects; + effect_t *effects; char *font; char *monitor; bool override_redirect; @@ -40,7 +44,7 @@ typedef struct { typedef struct { const char *label; - int value; + intptr_t value; } config_enum_t; void config_init(config_t *config); diff --git a/src/effect.c b/src/effect.c index 705c42d..e2fab98 100644 --- a/src/effect.c +++ b/src/effect.c @@ -4,47 +4,10 @@ #include "effect.h" #include "any_log.h" -double cubic_bezier(double x, double a, double b, double c, double d) +void effect_copy(effect_t *copy, const effect_t *effect) { - const double t = 1 - x; - return a * (t * t * t) + 3 * b * (t * t * x) + 3 * c * (t * x * x) + d * (x * x * x); -} - -static void effect_pulse_pre(effect_t *effect, layout_t *layout, cairo_t *cr) -{ - struct timespec now; - timespec_get(&now, TIME_UTC); - - // After half the duration we invert direction - struct timespec midpoint = timespec_div(effect->duration, 2); - struct timespec diff = timespec_diff(now, effect->start); - - double t = timespec_greater(midpoint, diff) - ? (double)timespec_to_ms(diff) / timespec_to_ms(midpoint) - : 1.0 - (double)timespec_to_ms(timespec_diff(diff, midpoint)) / timespec_to_ms(midpoint); - - // Make it customizable - double s = cubic_bezier(t, 0.19, 1.0, 0.22, 1.0); - - // Make it a parameter - const double amplitude = 0.12; - - // FIXME: The intent was to scale the animation for long blocks, but it needs more love - // - int x_max = amplitude * (layout->height + (layout->width / (double)layout->height) - 1); - int y_max = amplitude * layout->height; - - layout->x_padding = layout->block->x_padding + x_max * s; - layout->y_padding = layout->block->y_padding + y_max * s; -} - -effect_t *effect_pulse(struct timespec duration) -{ - effect_t *effect = calloc(1, sizeof(effect_t)); - effect->type = EFFECT_PULSE; - effect->duration = duration; - effect->pre = effect_pulse_pre; - return effect; + memcpy(copy, effect, sizeof(effect_t)); + copy->label = strcopy(effect->label); } void effect_free(effect_t *effect) diff --git a/src/effect.h b/src/effect.h index 1bf1a9e..2c6ec2c 100644 --- a/src/effect.h +++ b/src/effect.h @@ -5,25 +5,29 @@ #include "util.h" -typedef enum { - EFFECT_PULSE, -} effect_type_t; - typedef struct effect effect_t; typedef struct layout layout_t; typedef void (*effect_render_t)(effect_t *effect, layout_t *layout, cairo_t *cr); +// NOTE: The effect state must be freed by this function +// +typedef void (*effect_finalize_t)(effect_t *effect); + +typedef void (*effect_init_t)(effect_t *effect); + struct effect { - effect_type_t type; + char *label; struct timespec start; struct timespec duration; effect_render_t pre; effect_render_t post; + void *state; + effect_finalize_t finalize; }; -effect_t *effect_pulse(struct timespec duration); +void effect_copy(effect_t *copy, const effect_t *effect); void effect_free(effect_t *effect); diff --git a/src/effects/pulse.c b/src/effects/pulse.c new file mode 100644 index 0000000..9e012e1 --- /dev/null +++ b/src/effects/pulse.c @@ -0,0 +1,75 @@ +#include <string.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> + +#include "scheme.h" + +#include "../any_log.h" + +double cubic_bezier(double x, double a, double b, double c, double d) +{ + const double t = 1 - x; + return a * (t * t * t) + 3 * b * (t * t * x) + 3 * c * (t * x * x) + d * (x * x * x); +} + +static void effect_pulse_pre(effect_t *effect, layout_t *layout, cairo_t *cr) +{ + struct timespec now; + timespec_get(&now, TIME_UTC); + + // After half the duration we invert direction + struct timespec midpoint = timespec_div(effect->duration, 2); + struct timespec diff = timespec_diff(now, effect->start); + + double t = timespec_greater(midpoint, diff) + ? (double)timespec_to_ms(diff) / timespec_to_ms(midpoint) + : 1.0 - (double)timespec_to_ms(timespec_diff(diff, midpoint)) / timespec_to_ms(midpoint); + + // Make it customizable + double s = cubic_bezier(t, 0.19, 1.0, 0.22, 1.0); + + // Make it a parameter + const double amplitude = *(unsigned int *)effect->state / 100.0; + + // FIXME: The intent was to scale the animation for long blocks, but it needs more love + // + int x_max = amplitude * (layout->height + (layout->width / (double)layout->height) - 1); + int y_max = amplitude * layout->height; + + layout->x_padding = layout->block->x_padding + x_max * s; + layout->y_padding = layout->block->y_padding + y_max * s; +} + +static void effect_pulse_finalize(effect_t *effect) +{ + free(effect->state); +} + +static bool effect_pulse_validate(effect_t *effect, const effect_scheme_t *scheme) +{ + unsigned int amplitude = *(unsigned int *)effect->state; + if (amplitude > 100) { + log_error("Effect '%s' pulse amplitude must not exceed 100", effect->label); + return false; + } + + return true; +} + +static const config_entry_t effect_pulse_entries[] = { + { "amplitude", CONFIG_UINT, NULL, 0 }, + { 0 }, +}; + +const effect_scheme_t effect_pulse_scheme = { + .name = "pulse", + .effect = { + .finalize = effect_pulse_finalize, + .pre = effect_pulse_pre, + }, + .size = sizeof(unsigned int), + .entries = effect_pulse_entries, + .validate = effect_pulse_validate, +}; + diff --git a/src/effects/scheme.c b/src/effects/scheme.c new file mode 100644 index 0000000..0d70dec --- /dev/null +++ b/src/effects/scheme.c @@ -0,0 +1,8 @@ +#include "scheme.h" + +extern const effect_scheme_t effect_pulse_scheme; + +const effect_scheme_t *effect_schemes[] = { + &effect_pulse_scheme, + NULL +}; diff --git a/src/effects/scheme.h b/src/effects/scheme.h new file mode 100644 index 0000000..28ad69c --- /dev/null +++ b/src/effects/scheme.h @@ -0,0 +1,23 @@ +#ifndef COMET_EFFECTS_SCHEME_H +#define COMET_EFFECTS_SCHEME_H + +#include "../effect.h" +#include "../config.h" +#include "../layout.h" + +typedef struct effect_scheme effect_scheme_t; + +typedef bool (*effect_validate_t)(effect_t *effect, const effect_scheme_t *scheme); + +struct effect_scheme { + const char *name; + effect_t effect; + size_t size; + const config_entry_t *entries; + effect_validate_t validate; +}; + +extern const effect_scheme_t *effect_schemes[]; + +#endif + diff --git a/src/event.c b/src/event.c index 5d315a3..d07433a 100644 --- a/src/event.c +++ b/src/event.c @@ -32,9 +32,9 @@ static bool event_click(layout_t *layout, event_t event) return true; } - if (layout->block->effect == NULL) { - layout->block->effect = effect_pulse(timespec_from_ms(200)); - } + //if (layout->block->effect == NULL) { + // layout->block->effect = effect_pulse(timespec_from_ms(200)); + //} log_value_debug("Block was clicked", "s:type", even_type_to_string(event.type), |
