1
0
Fork 0
mirror of https://github.com/yshui/picom.git synced 2025-04-14 17:53:25 -04:00

config_libconfig: parse animation scripts

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-04-20 13:51:59 +01:00
parent da76a40407
commit 9502d7509d
No known key found for this signature in database
GPG key ID: D3A4405BE6CC17F4
5 changed files with 224 additions and 0 deletions

View file

@ -81,6 +81,38 @@ enum vblank_scheduler_type {
LAST_VBLANK_SCHEDULER,
};
enum animation_trigger {
ANIMATION_TRIGGER_INVALID = -1,
/// When a hidden window is shown
ANIMATION_TRIGGER_SHOW = 0,
/// When a window is hidden
ANIMATION_TRIGGER_HIDE,
/// When window opacity is increased
ANIMATION_TRIGGER_INCREASE_OPACITY,
/// When window opacity is decreased
ANIMATION_TRIGGER_DECREASE_OPACITY,
/// When a new window opens
ANIMATION_TRIGGER_OPEN,
/// When a window is closed
ANIMATION_TRIGGER_CLOSE,
ANIMATION_TRIGGER_LAST = ANIMATION_TRIGGER_CLOSE,
};
static const char *animation_trigger_names[] attr_unused = {
[ANIMATION_TRIGGER_SHOW] = "show",
[ANIMATION_TRIGGER_HIDE] = "hide",
[ANIMATION_TRIGGER_INCREASE_OPACITY] = "increase-opacity",
[ANIMATION_TRIGGER_DECREASE_OPACITY] = "decrease-opacity",
[ANIMATION_TRIGGER_OPEN] = "open",
[ANIMATION_TRIGGER_CLOSE] = "close",
};
struct script;
struct win_script {
int output_indices[NUM_OF_WIN_SCRIPT_OUTPUTS];
struct script *script;
};
extern const char *vblank_scheduler_str[];
/// Internal, private options for debugging and development use.
@ -292,6 +324,11 @@ typedef struct options {
c2_lptr_t *transparent_clipping_blacklist;
bool dithered_present;
// === Animation ===
struct win_script animations[ANIMATION_TRIGGER_LAST + 1];
/// Array of all the scripts used in `animations`.
struct script **all_scripts;
int number_of_scripts;
} options_t;
extern const char *const BACKEND_STRS[NUM_BKEND + 1];

View file

@ -15,8 +15,10 @@
#include "config.h"
#include "err.h"
#include "log.h"
#include "script.h"
#include "string_utils.h"
#include "utils.h"
#include "win.h"
#pragma GCC diagnostic error "-Wunused-parameter"
@ -220,6 +222,140 @@ static inline void parse_wintype_config(const config_t *cfg, const char *member_
}
}
static enum animation_trigger parse_animation_trigger(const char *trigger) {
for (int i = 0; i <= ANIMATION_TRIGGER_LAST; i++) {
if (strcasecmp(trigger, animation_trigger_names[i]) == 0) {
return i;
}
}
return ANIMATION_TRIGGER_INVALID;
}
static struct script *
compile_win_script(config_setting_t *setting, int *output_indices, char **err) {
struct script_output_info outputs[ARR_SIZE(win_script_outputs)];
memcpy(outputs, win_script_outputs, sizeof(win_script_outputs));
struct script_parse_config parse_config = {
.context_info = win_script_context_info,
.output_info = outputs,
};
auto script = script_compile(setting, parse_config, err);
if (script == NULL) {
return script;
}
for (int i = 0; i < NUM_OF_WIN_SCRIPT_OUTPUTS; i++) {
output_indices[i] = outputs[i].slot;
}
return script;
}
static bool set_animation(struct win_script *animations,
const enum animation_trigger *triggers, int number_of_triggers,
struct script *script, const int *output_indices, unsigned line) {
bool needed = false;
for (int i = 0; i < number_of_triggers; i++) {
if (triggers[i] == ANIMATION_TRIGGER_INVALID) {
log_error("Invalid trigger defined at line %d", line);
continue;
}
if (animations[triggers[i]].script != NULL) {
log_error("Duplicate animation defined for trigger %s at line "
"%d, it will be ignored.",
animation_trigger_names[triggers[i]], line);
continue;
}
memcpy(animations[triggers[i]].output_indices, output_indices,
sizeof(int[NUM_OF_WIN_SCRIPT_OUTPUTS]));
animations[triggers[i]].script = script;
needed = true;
}
return needed;
}
static struct script *
parse_animation_one(struct win_script *animations, config_setting_t *setting) {
auto triggers = config_setting_lookup(setting, "triggers");
if (!triggers) {
log_error("Missing triggers in animation script, at line %d",
config_setting_source_line(setting));
return NULL;
}
if (!config_setting_is_list(triggers) && !config_setting_is_array(triggers) &&
config_setting_get_string(triggers) == NULL) {
log_error("The \"triggers\" option must either be a string, a list, or "
"an array, but is none of those at line %d",
config_setting_source_line(triggers));
return NULL;
}
auto number_of_triggers =
config_setting_get_string(triggers) == NULL ? config_setting_length(triggers) : 1;
if (number_of_triggers > ANIMATION_TRIGGER_LAST) {
log_error("Too many triggers in animation defined at line %d",
config_setting_source_line(triggers));
return NULL;
}
if (number_of_triggers == 0) {
log_error("Trigger list is empty in animation defined at line %d",
config_setting_source_line(triggers));
return NULL;
}
enum animation_trigger *trigger_types =
alloca(sizeof(enum animation_trigger[number_of_triggers]));
const char *trigger0 = config_setting_get_string(triggers);
if (trigger0 == NULL) {
for (int i = 0; i < number_of_triggers; i++) {
auto trigger_i = config_setting_get_string_elem(triggers, i);
trigger_types[i] = trigger_i == NULL
? ANIMATION_TRIGGER_INVALID
: parse_animation_trigger(trigger_i);
}
} else {
trigger_types[0] = parse_animation_trigger(trigger0);
}
// script parser shouldn't see this.
config_setting_remove(setting, "triggers");
int output_indices[NUM_OF_WIN_SCRIPT_OUTPUTS];
char *err;
auto script = compile_win_script(setting, output_indices, &err);
if (!script) {
log_error("Failed to parse animation script at line %d: %s",
config_setting_source_line(setting), err);
free(err);
return NULL;
}
bool needed = set_animation(animations, trigger_types, number_of_triggers, script,
output_indices, config_setting_source_line(setting));
if (!needed) {
script_free(script);
script = NULL;
}
return script;
}
static struct script **parse_animations(struct win_script *animations,
config_setting_t *setting, int *number_of_scripts) {
auto number_of_animations = config_setting_length(setting);
auto all_scripts = ccalloc(number_of_animations + 1, struct script *);
auto len = 0;
for (int i = 0; i < number_of_animations; i++) {
auto sub = config_setting_get_elem(setting, (unsigned)i);
auto script = parse_animation_one(animations, sub);
if (script != NULL) {
all_scripts[len++] = script;
}
}
if (len == 0) {
free(all_scripts);
all_scripts = NULL;
}
*number_of_scripts = len;
return all_scripts;
}
/**
* Parse a configuration file from default location.
*
@ -607,6 +743,12 @@ char *parse_config_libconfig(options_t *opt, const char *config_file) {
parse_wintype_config(&cfg, "notify", &opt->wintype_option[WINTYPE_NOTIFICATION],
&opt->wintype_option_mask[WINTYPE_NOTIFICATION]);
config_setting_t *animations = config_lookup(&cfg, "animations");
if (animations) {
opt->all_scripts =
parse_animations(opt->animations, animations, &opt->number_of_scripts);
}
config_destroy(&cfg);
return path;

View file

@ -930,6 +930,13 @@ void options_destroy(struct options *options) {
}
free(options->blur_kerns);
free(options->glx_fshader_win_str);
for (int i = 0; i < options->number_of_scripts; i++) {
script_free(options->all_scripts[i]);
options->all_scripts[i] = NULL;
}
free(options->all_scripts);
memset(options->animations, 0, sizeof(options->animations));
}
// vim: set noet sw=8 ts=8 :

View file

@ -16,6 +16,7 @@
#include "list.h"
#include "region.h"
#include "render.h"
#include "script.h"
#include "transition.h"
#include "types.h"
#include "utils.h"
@ -305,6 +306,32 @@ struct managed_win {
region_t damaged;
};
struct win_script_context {
double x, y, width, height;
double opacity_before, opacity;
};
static const struct script_context_info win_script_context_info[] = {
{"window-x", offsetof(struct win_script_context, x)},
{"window-y", offsetof(struct win_script_context, y)},
{"window-width", offsetof(struct win_script_context, width)},
{"window-height", offsetof(struct win_script_context, height)},
{"window-raw-opacity-before", offsetof(struct win_script_context, opacity_before)},
{"window-raw-opacity", offsetof(struct win_script_context, opacity)},
{NULL, 0} //
};
static const struct script_output_info win_script_outputs[] = {
[WIN_SCRIPT_OFFSET_X] = {"offset-x"},
[WIN_SCRIPT_OFFSET_Y] = {"offset-y"},
[WIN_SCRIPT_SHADOW_OFFSET_X] = {"shadow-offset-x"},
[WIN_SCRIPT_SHADOW_OFFSET_Y] = {"shadow-offset-y"},
[WIN_SCRIPT_OPACITY] = {"opacity"},
[WIN_SCRIPT_BLUR_OPACITY] = {"blur-opacity"},
[WIN_SCRIPT_SHADOW_OPACITY] = {"shadow-opacity"},
[NUM_OF_WIN_SCRIPT_OUTPUTS] = {NULL},
};
/// Process pending updates/images flags on a window. Has to be called in X critical
/// section
void win_process_update_flags(session_t *ps, struct managed_win *w);

View file

@ -65,3 +65,14 @@ enum win_flags {
/// need better name for this, is set when some aspects of the window changed
WIN_FLAGS_FACTOR_CHANGED = 1024,
};
enum win_script_output {
WIN_SCRIPT_OFFSET_X = 0,
WIN_SCRIPT_OFFSET_Y,
WIN_SCRIPT_SHADOW_OFFSET_X,
WIN_SCRIPT_SHADOW_OFFSET_Y,
WIN_SCRIPT_OPACITY,
WIN_SCRIPT_BLUR_OPACITY,
WIN_SCRIPT_SHADOW_OPACITY,
};
#define NUM_OF_WIN_SCRIPT_OUTPUTS (WIN_SCRIPT_SHADOW_OPACITY + 1)