diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/config.c | 119 | ||||
| -rw-r--r-- | src/config.h | 4 | ||||
| -rw-r--r-- | src/effect.c | 90 | ||||
| -rw-r--r-- | src/effect.h | 32 | ||||
| -rw-r--r-- | src/effects/pulse.c | 91 | ||||
| -rw-r--r-- | src/effects/scheme.c | 8 | ||||
| -rw-r--r-- | src/effects/scheme.h | 22 | ||||
| -rw-r--r-- | src/event.c | 4 | ||||
| -rw-r--r-- | src/layout.c | 10 | ||||
| -rw-r--r-- | src/util.c | 4 | ||||
| -rw-r--r-- | src/util.h | 4 |
11 files changed, 315 insertions, 73 deletions
diff --git a/src/config.c b/src/config.c index 84804bc..54d32eb 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" @@ -30,6 +31,11 @@ static const config_entry_t bar_entries[] = { { 0 }, }; +static const config_entry_t effect_entries[] = { + { "duration", CONFIG_TIME, NULL, offsetof(effect_info_t, duration) }, + { 0 }, +}; + static const config_entry_t block_entries[] = { { "hidden", CONFIG_BOOL, NULL, offsetof(block_t, hidden) }, { "color", CONFIG_COLOR, NULL, offsetof(block_t, color) }, @@ -336,11 +342,24 @@ static config_status_t config_read_entry(const config_entry_t *entries, void *re return CONFIG_UNKNOWN; } +static config_status_t config_read_effect(const effect_scheme_t *scheme, effect_info_t *info, const char **type, + const char *section, const char *key, const char *value) +{ + config_status_t status = config_read_entry(effect_entries, info, 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, info->state, type, section, key, value); +} + static config_status_t config_read_block(const block_scheme_t *scheme, block_t *block, const char **type, const char *section, const char *key, const char *value) { config_status_t status = config_read_entry(block_entries, block, type, section, key, value); - if (status != CONFIG_UNKNOWN) return status; + if (status != CONFIG_UNKNOWN) + return status; status = config_read_entry(block->type == BLOCK_GROUP ? block_group_entries : block_text_entries, block, type, section, key, value); @@ -383,9 +402,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_info_t *info = NULL; + if (section != NULL) { if (!strncmp(section, "block.", 6)) { config->blocks = realloc(config->blocks, ++config->n_blocks * sizeof(block_t)); @@ -451,6 +474,68 @@ void config_read(config_t *config, FILE *file) "i:line", ini.line); goto skip_pair; + } else if (!strncmp(section, "effect.", 7)) { + config->infos = realloc(config->infos, ++config->n_infos * sizeof(effect_info_t)); + assert(config->infos != NULL); + info = &config->infos[config->n_infos - 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_infos - 1; i++) { + if (!strcmp(label, config->infos[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]; + memcpy(info, &escheme->info, sizeof(effect_info_t)); + + free(info->label); + info->label = label; + + if (escheme->size != 0) + info->state = calloc(1, 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,23 +551,28 @@ 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 && info == 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 (info != NULL) { + status = config_read_effect(escheme, &config->infos[config->n_infos - 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) { @@ -523,6 +613,13 @@ skip_pair: errors += !scheme->validate(block, scheme); } + if (info != NULL && escheme != NULL && escheme->validate != NULL) { + if (errors != 0) + log_trace("Skipped validation for effect '%s'", section); + else + errors += !escheme->validate(info, escheme); + } + free(section); n_errors += errors; } while ((section = any_ini_stream_next_section(&ini)) != NULL); diff --git a/src/config.h b/src/config.h index a7d196f..848cb16 100644 --- a/src/config.h +++ b/src/config.h @@ -8,6 +8,8 @@ typedef struct block block_t; +typedef struct effect_info effect_info_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_infos; + effect_info_t *infos; char *font; char *monitor; bool override_redirect; diff --git a/src/effect.c b/src/effect.c index 705c42d..9266979 100644 --- a/src/effect.c +++ b/src/effect.c @@ -1,53 +1,61 @@ -#include <math.h> +#include <assert.h> #include "layout.h" #include "effect.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 = 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) +//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 = 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; +//} + +void effect_info_free(effect_info_t *info) { - effect_t *effect = calloc(1, sizeof(effect_t)); - effect->type = EFFECT_PULSE; - effect->duration = duration; - effect->pre = effect_pulse_pre; - return effect; + free(info->state); + free(info); } void effect_free(effect_t *effect) { - free(effect); + assert(effect->info->finalize != NULL); + effect->info->finalize(effect); } diff --git a/src/effect.h b/src/effect.h index 1bf1a9e..980d339 100644 --- a/src/effect.h +++ b/src/effect.h @@ -5,25 +5,41 @@ #include "util.h" -typedef enum { - EFFECT_PULSE, -} effect_type_t; - typedef struct effect effect_t; +typedef struct effect_info effect_info_t; + typedef struct layout layout_t; +// NOTE: Should only allocate the effect and set any extra values +// +typedef effect_t *(*effect_allocate_t)(const effect_info_t *info); + +// NOTE: Must free any state associated with the effect +// +typedef void (*effect_finalize_t)(effect_t *effect); + typedef void (*effect_render_t)(effect_t *effect, layout_t *layout, cairo_t *cr); -struct effect { - effect_type_t type; - struct timespec start; +// NOTE: effect_info's state will be free'd simply +// +struct effect_info { + char *label; struct timespec duration; + effect_allocate_t allocate; + effect_finalize_t finalize; effect_render_t pre; effect_render_t post; + void *state; +}; + +struct effect { + effect_info_t *info; + struct timespec start; + struct effect *next; }; -effect_t *effect_pulse(struct timespec duration); +void effect_info_free(effect_info_t *info); void effect_free(effect_t *effect); diff --git a/src/effects/pulse.c b/src/effects/pulse.c new file mode 100644 index 0000000..c2a324a --- /dev/null +++ b/src/effects/pulse.c @@ -0,0 +1,91 @@ +#include <string.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> + +#include "scheme.h" + +#include "../any_log.h" + +typedef struct { + effect_t effect; + double amplitude; +} effect_pulse_t; + +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->info->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); + + const double amplitude = ((effect_pulse_t *)effect)->amplitude; + + // 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 effect_t *effect_pulse_allocate(const effect_info_t *info) +{ + effect_pulse_t *effect = calloc(1, sizeof(effect_pulse_t)); + assert(effect != NULL); + effect->amplitude = *(unsigned int *)info->state / 100.0; + return (effect_t *)effect; +} + +static void effect_pulse_finalize(effect_t *effect) +{ + free(effect); +} + +static bool effect_pulse_validate(effect_info_t *info, const effect_scheme_t *scheme) +{ + unsigned int amplitude = *(unsigned int *)info->state; + if (amplitude > 100) { + log_error("Effect '%s' pulse amplitude must not exceed 100", info->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", + .info = { + .duration = { + .tv_sec = 0, + .tv_nsec = 200000000, + }, + .allocate = effect_pulse_allocate, + .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..6026b12 --- /dev/null +++ b/src/effects/scheme.h @@ -0,0 +1,22 @@ +#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_info_t *info, const effect_scheme_t *scheme); + +struct effect_scheme { + const char *name; + effect_info_t info; + 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..5792a34 100644 --- a/src/event.c +++ b/src/event.c @@ -32,10 +32,6 @@ 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)); - } - log_value_debug("Block was clicked", "s:type", even_type_to_string(event.type), "i:x", event.x, diff --git a/src/layout.c b/src/layout.c index 3ebbcce..ae476b4 100644 --- a/src/layout.c +++ b/src/layout.c @@ -81,13 +81,13 @@ void layout_render(layout_t *layout, cairo_t *cr) if (timespec_zero(effect->start)) effect->start = now; - else if (timespec_greater(now, timespec_add(effect->start, effect->duration))) + else if (timespec_greater(now, timespec_add(effect->start, effect->info->duration))) layout->block->effect = NULL; } // Pre-processing effects - if (effect != NULL && effect->pre != NULL) { - effect->pre(effect, layout, cr); + if (effect != NULL && effect->info->pre != NULL) { + effect->info->pre(effect, layout, cr); } double degree = M_PI / 180.0; @@ -136,8 +136,8 @@ void layout_render(layout_t *layout, cairo_t *cr) } // Post-processing effects - if (effect != NULL && effect->post != NULL) { - effect->post(effect, layout, cr); + if (effect != NULL && effect->info->post != NULL) { + effect->info->post(effect, layout, cr); } if (layout->block->effect == NULL && effect != NULL) @@ -28,7 +28,7 @@ void color_print(FILE *stream, color_t *color) fprintf(stream, "#%02x%02x%02x%02x", r, g, b, a); } -struct timespec timespec_from_ms(long ms) +const struct timespec timespec_from_ms(long ms) { struct timespec ts = { .tv_sec = ms / 1000, @@ -37,7 +37,7 @@ struct timespec timespec_from_ms(long ms) return ts; } -long timespec_to_ms(struct timespec ts) +const long timespec_to_ms(struct timespec ts) { return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000ul); } @@ -29,9 +29,9 @@ char *color_to_string(color_t *color); void color_print(FILE *stream, color_t *color); -struct timespec timespec_from_ms(long ms); +const struct timespec timespec_from_ms(long ms); -long timespec_to_ms(struct timespec ts); +const long timespec_to_ms(struct timespec ts); struct timespec timespec_diff(struct timespec a, struct timespec b); |
