* variables.h: variables handling
*****************************************************************************
* Copyright (C) 2002 VideoLAN
- * $Id: variables.h,v 1.3 2002/10/14 19:04:51 sam Exp $
+ * $Id: variables.h,v 1.4 2002/10/16 19:39:42 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
-/* Variable types - probably very incomplete */
-#define VLC_VAR_BOOL 0x0100
-#define VLC_VAR_INTEGER 0x0200
-#define VLC_VAR_STRING 0x0300
-#define VLC_VAR_MODULE 0x0301
-#define VLC_VAR_FILE 0x0302
-#define VLC_VAR_FLOAT 0x0400
-#define VLC_VAR_TIME 0x0500
-#define VLC_VAR_ADDRESS 0x0600
-#define VLC_VAR_COMMAND 0x0700
-#define VLC_VAR_MUTEX 0x0800
+typedef struct callback_entry_t callback_entry_t;
/*****************************************************************************
* vlc_value_t is the common union for variable values; variable_t is the
*****************************************************************************/
struct variable_t
{
- u32 i_hash;
- char * psz_name;
+ /* The variable's exported value */
+ vlc_value_t val;
+ /* The variable unique name, (almost) unique hashed value, and type */
+ char * psz_name;
+ u32 i_hash;
int i_type;
- vlc_value_t val;
/* Lots of other things that can be added */
int i_usage;
- vlc_bool_t b_set;
- vlc_bool_t b_active;
+
+ int i_entries;
+ callback_entry_t * p_entries;
};
+/*****************************************************************************
+ * Variable types - probably very incomplete
+ *****************************************************************************/
+#define VLC_VAR_BOOL 0x0100
+#define VLC_VAR_INTEGER 0x0200
+#define VLC_VAR_STRING 0x0300
+#define VLC_VAR_MODULE 0x0301
+#define VLC_VAR_FILE 0x0302
+#define VLC_VAR_FLOAT 0x0400
+#define VLC_VAR_TIME 0x0500
+#define VLC_VAR_ADDRESS 0x0600
+#define VLC_VAR_COMMAND 0x0700
+#define VLC_VAR_MUTEX 0x0800
+
/*****************************************************************************
* Prototypes
*****************************************************************************/
VLC_EXPORT( int, __var_Set, ( vlc_object_t *, const char *, vlc_value_t ) );
VLC_EXPORT( int, __var_Get, ( vlc_object_t *, const char *, vlc_value_t * ) );
-#define var_Create(a,b,c) \
- __var_Create( VLC_OBJECT(a), b, c )
+#define var_Create(a,b,c) __var_Create( VLC_OBJECT(a), b, c )
+#define var_Destroy(a,b) __var_Destroy( VLC_OBJECT(a), b )
-#define var_Destroy(a,b) \
- __var_Destroy( VLC_OBJECT(a), b )
+#define var_Type(a,b) __var_Type( VLC_OBJECT(a), b )
+#define var_Set(a,b,c) __var_Set( VLC_OBJECT(a), b, c )
+#define var_Get(a,b,c) __var_Get( VLC_OBJECT(a), b, c )
-#define var_Type(a,b) \
- __var_Type( VLC_OBJECT(a), b )
-
-#define var_Set(a,b,c) \
- __var_Set( VLC_OBJECT(a), b, c )
+/*****************************************************************************
+ * Variable callbacks
+ *****************************************************************************
+ * int MyCallback( vlc_object_t *p_this,
+ * char const *psz_variable,
+ * vlc_value_t oldvalue,
+ * vlc_value_t newvalue,
+ * void *p_data);
+ *****************************************************************************/
+VLC_EXPORT( int, __var_AddCallback, ( vlc_object_t *, const char *, vlc_callback_t, void * ) );
+VLC_EXPORT( int, __var_DelCallback, ( vlc_object_t *, const char *, vlc_callback_t, void * ) );
-#define var_Get(a,b,c) \
- __var_Get( VLC_OBJECT(a), b, c )
+#define var_AddCallback(a,b,c,d) __var_AddCallback( VLC_OBJECT(a), b, c, d )
+#define var_DelCallback(a,b,c,d) __var_DelCallback( VLC_OBJECT(a), b, c, d )
* variables.c: routines for object variables handling
*****************************************************************************
* Copyright (C) 2002 VideoLAN
- * $Id: variables.c,v 1.6 2002/10/16 10:31:58 sam Exp $
+ * $Id: variables.c,v 1.7 2002/10/16 19:39:42 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
# include <stdlib.h> /* realloc() */
#endif
+/*****************************************************************************
+ * Private types
+ *****************************************************************************/
+struct callback_entry_t
+{
+ vlc_callback_t pf_callback;
+ void * p_data;
+};
+
/*****************************************************************************
* Local prototypes
*****************************************************************************/
memset( &p_var->val, 0, sizeof(vlc_value_t) );
p_var->i_usage = 1;
- p_var->b_set = VLC_FALSE;
- p_var->b_active = VLC_TRUE;
+ p_var->i_entries = 0;
+ p_var->p_entries = NULL;
+
+ /* Always initialize the variable */
switch( i_type )
{
+ case VLC_VAR_BOOL:
+ p_var->val.b_bool = VLC_FALSE;
+ break;
+ case VLC_VAR_INTEGER:
+ p_var->val.i_int = 0;
+ break;
+ case VLC_VAR_STRING:
+ case VLC_VAR_MODULE:
+ case VLC_VAR_FILE:
+ p_var->val.psz_string = strdup( "" );
+ break;
+ case VLC_VAR_FLOAT:
+ p_var->val.f_float = 0.0;
+ break;
+ case VLC_VAR_TIME:
+ /* TODO */
+ break;
+ case VLC_VAR_ADDRESS:
+ case VLC_VAR_COMMAND:
+ p_var->val.p_address = NULL;
+ break;
case VLC_VAR_MUTEX:
p_var->val.p_address = malloc( sizeof(vlc_mutex_t) );
vlc_mutex_init( p_this, (vlc_mutex_t*)p_var->val.p_address );
- p_var->b_set = VLC_TRUE;
break;
}
case VLC_VAR_STRING:
case VLC_VAR_MODULE:
case VLC_VAR_FILE:
- if( p_var->b_set && p_var->val.psz_string )
- {
- free( p_var->val.psz_string );
- }
+ free( p_var->val.psz_string );
break;
case VLC_VAR_MUTEX:
break;
}
+ /* Free callbacks if needed */
+ if( p_var->p_entries )
+ {
+ free( p_var->p_entries );
+ }
+
free( p_var->psz_name );
memmove( p_this->p_vars + i_del,
int __var_Set( vlc_object_t *p_this, const char *psz_name, vlc_value_t val )
{
int i_var;
+ variable_t *p_var;
+ vlc_value_t oldval;
vlc_mutex_lock( &p_this->var_lock );
return VLC_ENOVAR;
}
- /* Duplicate value if needed */
- switch( p_this->p_vars[i_var].i_type )
+ p_var = &p_this->p_vars[i_var];
+
+ /* Duplicate data if needed */
+ switch( p_var->i_type )
{
case VLC_VAR_STRING:
case VLC_VAR_MODULE:
case VLC_VAR_FILE:
- if( p_this->p_vars[i_var].b_set
- && p_this->p_vars[i_var].val.psz_string )
- {
- free( p_this->p_vars[i_var].val.psz_string );
- }
- if( val.psz_string )
- {
- val.psz_string = strdup( val.psz_string );
- }
+ val.psz_string = strdup( val.psz_string );
break;
}
- p_this->p_vars[i_var].val = val;
- p_this->p_vars[i_var].b_set = VLC_TRUE;
+ /* Backup needed stuff */
+ oldval = p_var->val;
- /* XXX: callback stuff will go here */
+ /* Set the variable */
+ p_var->val = val;
+
+ /* Deal with callbacks */
+ if( p_var->i_entries )
+ {
+ int i;
+
+ for( i = p_var->i_entries ; i-- ; )
+ {
+ /* FIXME: oooh, see the deadlocks! see the race conditions! */
+ p_var->p_entries[i].pf_callback( p_this, p_var->psz_name,
+ oldval, val,
+ p_var->p_entries[i].p_data );
+ }
+ }
+
+ /* Free data if needed */
+ switch( p_var->i_type )
+ {
+ case VLC_VAR_STRING:
+ case VLC_VAR_MODULE:
+ case VLC_VAR_FILE:
+ free( oldval.psz_string );
+ break;
+ }
vlc_mutex_unlock( &p_this->var_lock );
int __var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val )
{
int i_var;
+ variable_t *p_var;
vlc_mutex_lock( &p_this->var_lock );
return VLC_ENOVAR;
}
- if( !p_this->p_vars[i_var].b_set )
- {
- vlc_mutex_unlock( &p_this->var_lock );
- return VLC_EBADVAR;
- }
+ p_var = &p_this->p_vars[i_var];
/* Some variables trigger special behaviour. */
- switch( p_this->p_vars[i_var].i_type )
+ switch( p_var->i_type )
{
case VLC_VAR_COMMAND:
- if( p_this->p_vars[i_var].b_set )
+ if( p_var->val.p_address )
{
- /* We need this to avoid deadlocks */
+ /* We need to save data before releasing the lock */
int i_ret;
int (*pf_command) (vlc_object_t *, char *, char *) =
- p_this->p_vars[i_var].val.p_address;
- char *psz_cmd = strdup( p_this->p_vars[i_var].psz_name );
+ p_var->val.p_address;
+ char *psz_cmd = strdup( p_var->psz_name );
char *psz_arg = strdup( p_val->psz_string );
vlc_mutex_unlock( &p_this->var_lock );
+
i_ret = pf_command( p_this, psz_cmd, psz_arg );
free( psz_cmd );
free( psz_arg );
}
/* Really set the variable */
- *p_val = p_this->p_vars[i_var].val;
+ *p_val = p_var->val;
/* Duplicate value if needed */
- switch( p_this->p_vars[i_var].i_type )
+ switch( p_var->i_type )
{
case VLC_VAR_STRING:
case VLC_VAR_MODULE:
return VLC_SUCCESS;
}
+/*****************************************************************************
+ * var_AddCallback: register a callback in a variable
+ *****************************************************************************
+ * We store a function pointer pf_callback that will be called upon variable
+ * modification. p_data is a generic pointer that will be passed as additional
+ * argument to the callback function.
+ *****************************************************************************/
+int __var_AddCallback( vlc_object_t *p_this, const char *psz_name,
+ vlc_callback_t pf_callback, void *p_data )
+{
+ int i_var, i_entry;
+ variable_t *p_var;
+
+ vlc_mutex_lock( &p_this->var_lock );
+
+ i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name );
+ if( i_var < 0 )
+ {
+ vlc_mutex_unlock( &p_this->var_lock );
+ return VLC_ENOVAR;
+ }
+
+ p_var = &p_this->p_vars[i_var];
+
+ i_entry = p_var->i_entries++;
+
+ if( i_entry )
+ {
+ p_var->p_entries = realloc( p_var->p_entries,
+ sizeof( callback_entry_t ) * p_var->i_entries );
+ }
+ else
+ {
+ p_var->p_entries = malloc( sizeof( callback_entry_t ) );
+ }
+
+ p_var->p_entries[ i_entry ].pf_callback = pf_callback;
+ p_var->p_entries[ i_entry ].p_data = p_data;
+
+ vlc_mutex_unlock( &p_this->var_lock );
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * var_DelCallback: remove a callback from a variable
+ *****************************************************************************
+ * pf_callback and p_data have to be given again, because different objects
+ * might have registered the same callback function.
+ *****************************************************************************/
+int __var_DelCallback( vlc_object_t *p_this, const char *psz_name,
+ vlc_callback_t pf_callback, void *p_data )
+{
+ int i_var, i_entry;
+ variable_t *p_var;
+
+ vlc_mutex_lock( &p_this->var_lock );
+
+ i_var = Lookup( p_this->p_vars, p_this->i_vars, psz_name );
+ if( i_var < 0 )
+ {
+ vlc_mutex_unlock( &p_this->var_lock );
+ return VLC_ENOVAR;
+ }
+
+ p_var = &p_this->p_vars[i_var];
+
+ for( i_entry = p_var->i_entries ; i_entry-- ; )
+ {
+ if( p_var->p_entries[i_entry].pf_callback == pf_callback
+ || p_var->p_entries[i_entry].p_data == p_data )
+ {
+ break;
+ }
+ }
+
+ if( i_entry < 0 )
+ {
+ vlc_mutex_unlock( &p_this->var_lock );
+ return VLC_EGENERIC;
+ }
+
+ p_var->i_entries--;
+
+ memmove( p_var->p_entries + i_entry,
+ p_var->p_entries + i_entry + 1,
+ sizeof( callback_entry_t ) * ( p_var->i_entries - i_entry ) );
+
+ if( p_var->i_entries )
+ {
+ p_var->p_entries = realloc( p_var->p_entries,
+ sizeof( callback_entry_t ) * ( p_var->i_entries ) );
+ }
+ else
+ {
+ free( p_var->p_entries );
+ p_var->p_entries = NULL;
+ }
+
+ vlc_mutex_unlock( &p_this->var_lock );
+
+ return VLC_SUCCESS;
+}
+
/* Following functions are local */
/*****************************************************************************