aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFederico Angelilli <code@fedang.net>2024-09-18 14:49:59 +0200
committerFederico Angelilli <code@fedang.net>2024-09-18 14:49:59 +0200
commit0eceb95c0a4b517d7eb537a464089f011e3804e2 (patch)
tree54e2646d5a7c43b3fec074ebe98d4a33aefde025 /src
parentbc70dead7fb518f073fecb21a04fa374e9ad6dd0 (diff)
Add effect parsingeffect-conf
Diffstat (limited to 'src')
-rw-r--r--src/blocks/scheme.h4
-rw-r--r--src/config.c117
-rw-r--r--src/config.h6
-rw-r--r--src/effect.c43
-rw-r--r--src/effect.h16
-rw-r--r--src/effects/pulse.c75
-rw-r--r--src/effects/scheme.c8
-rw-r--r--src/effects/scheme.h23
-rw-r--r--src/event.c6
9 files changed, 236 insertions, 62 deletions
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),