diff --git a/input/cmd.h b/input/cmd.h index 4a0f9d3800..239404725a 100644 --- a/input/cmd.h +++ b/input/cmd.h @@ -114,6 +114,7 @@ typedef struct mp_cmd { bool repeated : 1; bool mouse_move : 1; bool canceled : 1; + bool coalesce : 1; int mouse_x, mouse_y; struct mp_cmd *queue_next; double scale; // for scaling numeric arguments diff --git a/options/m_config_frontend.c b/options/m_config_frontend.c index 9fe30ac391..2b812e0232 100644 --- a/options/m_config_frontend.c +++ b/options/m_config_frontend.c @@ -737,6 +737,9 @@ int m_config_set_option_cli(struct m_config *config, struct bstr name, param = bstr0("no"); } + if (flags & M_SETOPT_FROM_CONFIG_FILE) + co->coalesce = true; + // This is the only mandatory function mp_assert(co->opt->type->parse); diff --git a/options/m_config_frontend.h b/options/m_config_frontend.h index 8ee42c16e0..97d0d7527e 100644 --- a/options/m_config_frontend.h +++ b/options/m_config_frontend.h @@ -49,6 +49,7 @@ struct m_config_option { bool is_set_from_config : 1; // Set by a config file bool is_set_locally : 1; // Has a backup entry bool warning_was_printed : 1; + bool coalesce : 1; // Property changes should be coalesced int32_t opt_id; // For some m_config APIs const char *name; // Full name (ie option-subopt) const struct m_option *opt; // Option description diff --git a/options/m_property.h b/options/m_property.h index 8fbb83384d..c4838cd204 100644 --- a/options/m_property.h +++ b/options/m_property.h @@ -147,6 +147,8 @@ struct m_property { void *priv; // Special-case: mark options for which command.c uses the option-bridge bool is_option; + // Special-case: option-bridge properties should be coalesced + bool coalesce; }; struct m_property *m_property_list_find(const struct m_property *list, diff --git a/player/command.c b/player/command.c index 49e3456ef0..0a3ece4448 100644 --- a/player/command.c +++ b/player/command.c @@ -434,6 +434,7 @@ static int mp_property_generic_option(void *ctx, struct m_property *prop, m_option_copy(opt->opt, arg, opt->data); return M_PROPERTY_OK; case M_PROPERTY_SET: + opt->coalesce = prop->coalesce; if (m_config_set_option_raw(mpctx->mconfig, opt, arg, 0) < 0) return M_PROPERTY_ERROR; return M_PROPERTY_OK; @@ -5219,8 +5220,17 @@ static void show_property_status(struct mp_cmd_ctx *cmd, const char *name, int r static void change_property_cmd(struct mp_cmd_ctx *cmd, const char *name, int action, void *arg) { + struct m_property *prop = NULL; + if (cmd->cmd->coalesce) { + struct command_ctx *ctx = cmd->mpctx->command_ctx; + prop = m_property_list_find(ctx->properties, name); + if (prop) + prop->coalesce = true; + } int r = mp_property_do(name, action, arg, cmd->mpctx); show_property_status(cmd, name, r); + if (prop) + prop->coalesce = false; } static void cmd_cycle_values(void *p) @@ -7657,6 +7667,7 @@ void run_command_opts(struct MPContext *mpctx) for (int i = 0; opts->input_commands[i]; i++) { struct mp_cmd *cmd = mp_input_parse_cmd(mpctx->input, bstr0(opts->input_commands[i]), "the command line"); + cmd->coalesce = true; mp_input_queue_cmd(mpctx->input, cmd); } ctx->command_opts_processed = true; @@ -7715,6 +7726,13 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, uint64_t f if (self_update) return; + // Run these immediately. + if (co && !co->coalesce) { + struct mp_option_callback callback = {.co = co, .flags = flags}; + mp_option_run_callback(mpctx, &callback); + return; + } + // Coalesce redundant updates and only keep the newest one. bool drop = false; for (int i = 0; i < mpctx->num_option_callbacks; i++) { @@ -7737,12 +7755,12 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, uint64_t f } } -void mp_option_run_callback(struct MPContext *mpctx, int index) +void mp_option_run_callback(struct MPContext *mpctx, struct mp_option_callback *callback) { struct MPOpts *opts = mpctx->opts; - struct m_config_option *co = mpctx->option_callbacks[index].co; + struct m_config_option *co = callback->co; void *opt_ptr = co ? co->data : NULL; - uint64_t flags = mpctx->option_callbacks[index].flags; + uint64_t flags = callback->flags; if (flags & UPDATE_TERM) mp_update_logging(mpctx, false); diff --git a/player/command.h b/player/command.h index cebd56b392..9a24b2d7af 100644 --- a/player/command.h +++ b/player/command.h @@ -87,7 +87,7 @@ int mp_property_do(const char* name, int action, void* val, void mp_option_change_callback(void *ctx, struct m_config_option *co, uint64_t flags, bool self_update); -void mp_option_run_callback(struct MPContext *mpctx, int index); +void mp_option_run_callback(struct MPContext *mpctx, struct mp_option_callback *callback); void mp_notify(struct MPContext *mpctx, int event, void *arg); void mp_notify_property(struct MPContext *mpctx, const char *property); diff --git a/player/playloop.c b/player/playloop.c index f61cf3a1ff..e4b59dfe69 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -125,7 +125,7 @@ static void mp_process_input(struct MPContext *mpctx) void handle_option_callbacks(struct MPContext *mpctx) { for (int i = 0; i < mpctx->num_option_callbacks; i++) - mp_option_run_callback(mpctx, i); + mp_option_run_callback(mpctx, &mpctx->option_callbacks[i]); mpctx->num_option_callbacks = 0; }