From c4118a4bf19ae2a5fb168867952e7737ac576204 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 25 Nov 2021 17:46:16 +0900 Subject: [PATCH] [util] Add listeners to cvars Listeners are separate to the main callback as listeners have only read-only access to the objects, but the main callback is free to modify the cvar and thus can act as a parser and validator. The listeners are invoked after the main callback if the cvar is modified. There does not need to be a main callback for the listeners to be invoked. --- include/QF/cvar.h | 8 ++++++++ libs/util/cvar.c | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/include/QF/cvar.h b/include/QF/cvar.h index 461ff4bf6..2fe20aafa 100644 --- a/include/QF/cvar.h +++ b/include/QF/cvar.h @@ -33,6 +33,7 @@ */ ///@{ +#include "QF/listener.h" #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -51,6 +52,7 @@ typedef struct cvar_s { \param var This cvar. */ void (*callback)(struct cvar_s *var); + struct cvar_listener_set_s *listeners; const char *description; ///< for "help" command float value; ///< The current cvar value as a float int int_val; ///< The current cvar value as an integer @@ -58,6 +60,10 @@ typedef struct cvar_s { struct cvar_s *next; ///< \internal Linked list of cvars. } cvar_t; +typedef struct cvar_listener_set_s LISTENER_SET_TYPE (cvar_t) + cvar_listener_set_t; +typedef void (*cvar_listener_t) (void *data, const cvar_t *cvar); + typedef struct cvar_alias_s { char *name; ///< The name of the alias. cvar_t *cvar; ///< The cvar to which this alias refers @@ -97,6 +103,8 @@ cvar_t *Cvar_FindAlias (const char *alias_name); cvar_t *Cvar_MakeAlias (const char *name, cvar_t *cvar); cvar_t *Cvar_RemoveAlias (const char *name); +void Cvar_AddListener (cvar_t *cvar, cvar_listener_t listener, void *data); +void Cvar_RemoveListener (cvar_t *cvar, cvar_listener_t listener, void *data); // equivelants to " " typed at the console void Cvar_Set (cvar_t *var, const char *value); diff --git a/libs/util/cvar.c b/libs/util/cvar.c index 333e1ca9b..add043f11 100644 --- a/libs/util/cvar.c +++ b/libs/util/cvar.c @@ -249,6 +249,24 @@ Cvar_CompleteBuildList (const char *partial) return buf; } +VISIBLE void +Cvar_AddListener (cvar_t *cvar, cvar_listener_t listener, void *data) +{ + if (!cvar->listeners) { + cvar->listeners = malloc (sizeof (*cvar->listeners)); + LISTENER_SET_INIT (cvar->listeners, 8); + } + LISTENER_ADD (cvar->listeners, listener, data); +} + +VISIBLE void +Cvar_RemoveListener (cvar_t *cvar, cvar_listener_t listener, void *data) +{ + if (cvar->listeners) { + LISTENER_REMOVE (cvar->listeners, listener, data); + } +} + VISIBLE void Cvar_Set (cvar_t *var, const char *value) { @@ -279,6 +297,10 @@ Cvar_Set (cvar_t *var, const char *value) if (var->callback) var->callback (var); + + if (var->listeners) { + LISTENER_INVOKE (var->listeners, var); + } } } @@ -710,7 +732,7 @@ VISIBLE cvar_t * Cvar_Get (const char *name, const char *string, int cvarflags, void (*callback)(cvar_t*), const char *description) { - + int changed = 0; cvar_t *var; if (Cmd_Exists (name)) { @@ -740,10 +762,13 @@ Cvar_Get (const char *name, const char *string, int cvarflags, break; var->next = *v; *v = var; + + changed = 1; } else { // Cvar does exist, so we update the flags and return. var->flags &= ~CVAR_USER_CREATED; var->flags |= cvarflags; + changed = !strequal (var->string, string) || var->callback != callback; if (!var->callback) var->callback = callback; if (!var->description @@ -753,8 +778,14 @@ Cvar_Get (const char *name, const char *string, int cvarflags, if (!var->default_string) var->default_string = strdup (string); } - if (var->callback) - var->callback (var); + if (changed) { + if (var->callback) + var->callback (var); + + if (var->listeners) { + LISTENER_INVOKE (var->listeners, var); + } + } return var; }