Commit ad24c4fb authored by Felix Abecassis's avatar Felix Abecassis

core: add a new type of callback for list variables

This new callback is triggered when an element is added/removed from
the list, or when the list is cleared.
parent c4cd36ee
...@@ -382,7 +382,7 @@ struct vlc_list_t ...@@ -382,7 +382,7 @@ struct vlc_list_t
#define VLC_ENOITEM (-8) /**< Item not found */ #define VLC_ENOITEM (-8) /**< Item not found */
/***************************************************************************** /*****************************************************************************
* Variable callbacks * Variable callbacks: called when the value is modified
*****************************************************************************/ *****************************************************************************/
typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */
char const *, /* variable name */ char const *, /* variable name */
...@@ -390,6 +390,21 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */ ...@@ -390,6 +390,21 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */
vlc_value_t, /* new value */ vlc_value_t, /* new value */
void * ); /* callback data */ void * ); /* callback data */
/*****************************************************************************
* List callbacks: called when elements are added/removed from the list
*****************************************************************************/
typedef int ( * vlc_list_callback_t ) ( vlc_object_t *, /* variable's object */
char const *, /* variable name */
int, /* VLC_VAR_* action */
vlc_value_t *, /* new/deleted value */
void *); /* callback data */
typedef enum
{
vlc_value_callback,
vlc_list_callback
} vlc_callback_type_t;
/***************************************************************************** /*****************************************************************************
* OS-specific headers and thread types * OS-specific headers and thread types
*****************************************************************************/ *****************************************************************************/
......
...@@ -183,10 +183,16 @@ VLC_API int var_AddCallback( vlc_object_t *, const char *, vlc_callback_t, void ...@@ -183,10 +183,16 @@ VLC_API int var_AddCallback( vlc_object_t *, const char *, vlc_callback_t, void
VLC_API int var_DelCallback( vlc_object_t *, const char *, vlc_callback_t, void * ); VLC_API int var_DelCallback( vlc_object_t *, const char *, vlc_callback_t, void * );
VLC_API int var_TriggerCallback( vlc_object_t *, const char * ); VLC_API int var_TriggerCallback( vlc_object_t *, const char * );
VLC_API int var_AddListCallback( vlc_object_t *, const char *, vlc_list_callback_t, void * );
VLC_API int var_DelListCallback( vlc_object_t *, const char *, vlc_list_callback_t, void * );
#define var_AddCallback(a,b,c,d) var_AddCallback( VLC_OBJECT(a), b, c, d ) #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 ) #define var_DelCallback(a,b,c,d) var_DelCallback( VLC_OBJECT(a), b, c, d )
#define var_TriggerCallback(a,b) var_TriggerCallback( VLC_OBJECT(a), b ) #define var_TriggerCallback(a,b) var_TriggerCallback( VLC_OBJECT(a), b )
#define var_AddListCallback(a,b,c,d) var_AddListCallback( VLC_OBJECT(a), b, c, d )
#define var_DelListCallback(a,b,c,d) var_DelListCallback( VLC_OBJECT(a), b, c, d )
/***************************************************************************** /*****************************************************************************
* helpers functions * helpers functions
*****************************************************************************/ *****************************************************************************/
......
...@@ -452,9 +452,11 @@ vlc_socket ...@@ -452,9 +452,11 @@ vlc_socket
vlc_accept vlc_accept
utf8_vfprintf utf8_vfprintf
var_AddCallback var_AddCallback
var_AddListCallback
var_Change var_Change
var_Create var_Create
var_DelCallback var_DelCallback
var_DelListCallback
var_Destroy var_Destroy
var_FreeList var_FreeList
var_Get var_Get
......
...@@ -49,7 +49,12 @@ ...@@ -49,7 +49,12 @@
*****************************************************************************/ *****************************************************************************/
struct callback_entry_t struct callback_entry_t
{ {
vlc_callback_t pf_callback; union
{
vlc_callback_t pf_value_callback;
vlc_list_callback_t pf_list_callback;
void * p_callback;
} u;
void * p_data; void * p_data;
}; };
...@@ -136,6 +141,10 @@ static void CheckValue ( variable_t *, vlc_value_t * ); ...@@ -136,6 +141,10 @@ static void CheckValue ( variable_t *, vlc_value_t * );
static int TriggerCallback( vlc_object_t *, variable_t *, const char *, static int TriggerCallback( vlc_object_t *, variable_t *, const char *,
vlc_value_t ); vlc_value_t );
static int TriggerListCallback( vlc_object_t *, variable_t *,
const char *, int,
vlc_value_t * );
static int varcmp( const void *a, const void *b ) static int varcmp( const void *a, const void *b )
{ {
const variable_t *va = a, *vb = b; const variable_t *va = a, *vb = b;
...@@ -461,6 +470,8 @@ int var_Change( vlc_object_t *p_this, const char *psz_name, ...@@ -461,6 +470,8 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
strdup( p_val2->psz_string ) : NULL; strdup( p_val2->psz_string ) : NULL;
CheckValue( p_var, &p_var->val ); CheckValue( p_var, &p_var->val );
TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_ADDCHOICE, p_val);
break; break;
} }
case VLC_VAR_DELCHOICE: case VLC_VAR_DELCHOICE:
...@@ -490,6 +501,8 @@ int var_Change( vlc_object_t *p_this, const char *psz_name, ...@@ -490,6 +501,8 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
p_var->choices_text.i_count, i ); p_var->choices_text.i_count, i );
CheckValue( p_var, &p_var->val ); CheckValue( p_var, &p_var->val );
TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_DELCHOICE, p_val);
break; break;
} }
case VLC_VAR_CHOICESCOUNT: case VLC_VAR_CHOICESCOUNT:
...@@ -509,6 +522,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name, ...@@ -509,6 +522,7 @@ int var_Change( vlc_object_t *p_this, const char *psz_name,
p_var->choices_text.i_count = 0; p_var->choices_text.i_count = 0;
p_var->choices_text.p_values = NULL; p_var->choices_text.p_values = NULL;
p_var->i_default = -1; p_var->i_default = -1;
TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_CLEARCHOICES, NULL);
break; break;
case VLC_VAR_SETDEFAULT: case VLC_VAR_SETDEFAULT:
{ {
...@@ -805,7 +819,7 @@ int var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val ) ...@@ -805,7 +819,7 @@ int var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val )
} }
static int AddCallback( vlc_object_t *p_this, const char *psz_name, static int AddCallback( vlc_object_t *p_this, const char *psz_name,
callback_entry_t entry ) callback_entry_t entry, vlc_callback_type_t i_type )
{ {
variable_t *p_var; variable_t *p_var;
...@@ -820,12 +834,17 @@ static int AddCallback( vlc_object_t *p_this, const char *psz_name, ...@@ -820,12 +834,17 @@ static int AddCallback( vlc_object_t *p_this, const char *psz_name,
{ {
vlc_mutex_unlock( &p_priv->var_lock ); vlc_mutex_unlock( &p_priv->var_lock );
msg_Err( p_this, "cannot add callback %p to nonexistent " msg_Err( p_this, "cannot add callback %p to nonexistent "
"variable '%s'", entry.pf_callback, psz_name ); "variable '%s'", entry.u.p_callback, psz_name );
return VLC_ENOVAR; return VLC_ENOVAR;
} }
WaitUnused( p_this, p_var ); WaitUnused( p_this, p_var );
callback_table_t *p_table = &p_var->value_callbacks;
callback_table_t *p_table;
if (i_type == vlc_value_callback)
p_table = &p_var->value_callbacks;
else
p_table = &p_var->list_callbacks;
INSERT_ELEM( p_table->p_entries, INSERT_ELEM( p_table->p_entries,
p_table->i_entries, p_table->i_entries,
p_table->i_entries, p_table->i_entries,
...@@ -857,14 +876,14 @@ int var_AddCallback( vlc_object_t *p_this, const char *psz_name, ...@@ -857,14 +876,14 @@ int var_AddCallback( vlc_object_t *p_this, const char *psz_name,
vlc_callback_t pf_callback, void *p_data ) vlc_callback_t pf_callback, void *p_data )
{ {
callback_entry_t entry; callback_entry_t entry;
entry.pf_callback = pf_callback; entry.u.pf_value_callback = pf_callback;
entry.p_data = p_data; entry.p_data = p_data;
return AddCallback(p_this, psz_name, entry); return AddCallback(p_this, psz_name, entry, vlc_value_callback);
} }
static int DelCallback( vlc_object_t *p_this, const char *psz_name, static int DelCallback( vlc_object_t *p_this, const char *psz_name,
callback_entry_t entry ) callback_entry_t entry, vlc_callback_type_t i_type )
{ {
int i_entry; int i_entry;
variable_t *p_var; variable_t *p_var;
...@@ -887,16 +906,21 @@ static int DelCallback( vlc_object_t *p_this, const char *psz_name, ...@@ -887,16 +906,21 @@ static int DelCallback( vlc_object_t *p_this, const char *psz_name,
WaitUnused( p_this, p_var ); WaitUnused( p_this, p_var );
callback_table_t *p_table = &p_var->value_callbacks; callback_table_t *p_table;
if (i_type == vlc_value_callback)
p_table = &p_var->value_callbacks;
else
p_table = &p_var->list_callbacks;
for( i_entry = p_table->i_entries ; i_entry-- ; ) for( i_entry = p_table->i_entries ; i_entry-- ; )
{ {
if( p_table->p_entries[i_entry].pf_callback == entry.pf_callback if( p_table->p_entries[i_entry].u.p_callback == entry.u.p_callback
&& p_table->p_entries[i_entry].p_data == entry.p_data ) && p_table->p_entries[i_entry].p_data == entry.p_data )
{ {
break; break;
} }
#ifndef NDEBUG #ifndef NDEBUG
else if( p_table->p_entries[i_entry].pf_callback == entry.pf_callback ) else if( p_table->p_entries[i_entry].u.p_callback == entry.u.p_callback )
b_found_similar = true; b_found_similar = true;
#endif #endif
} }
...@@ -931,10 +955,10 @@ int var_DelCallback( vlc_object_t *p_this, const char *psz_name, ...@@ -931,10 +955,10 @@ int var_DelCallback( vlc_object_t *p_this, const char *psz_name,
vlc_callback_t pf_callback, void *p_data ) vlc_callback_t pf_callback, void *p_data )
{ {
callback_entry_t entry; callback_entry_t entry;
entry.pf_callback = pf_callback; entry.u.pf_value_callback = pf_callback;
entry.p_data = p_data; entry.p_data = p_data;
return DelCallback(p_this, psz_name, entry); return DelCallback(p_this, psz_name, entry, vlc_value_callback);
} }
#undef var_TriggerCallback #undef var_TriggerCallback
...@@ -972,6 +996,41 @@ int var_TriggerCallback( vlc_object_t *p_this, const char *psz_name ) ...@@ -972,6 +996,41 @@ int var_TriggerCallback( vlc_object_t *p_this, const char *psz_name )
return i_ret; return i_ret;
} }
#undef var_AddListCallback
/**
* Register a callback for a list variable
*
* The callback is triggered when an element is added/removed from the
* list or when the list is cleared.
*
* See var_AddCallback().
*/
int var_AddListCallback( vlc_object_t *p_this, const char *psz_name,
vlc_list_callback_t pf_callback, void *p_data )
{
callback_entry_t entry;
entry.u.pf_list_callback = pf_callback;
entry.p_data = p_data;
return AddCallback(p_this, psz_name, entry, vlc_list_callback);
}
#undef var_DelListCallback
/**
* Remove a callback from a list variable
*
* See var_DelCallback().
*/
int var_DelListCallback( vlc_object_t *p_this, const char *psz_name,
vlc_list_callback_t pf_callback, void *p_data )
{
callback_entry_t entry;
entry.u.pf_list_callback = pf_callback;
entry.p_data = p_data;
return DelCallback(p_this, psz_name, entry, vlc_list_callback);
}
/** Parse a stringified option /** Parse a stringified option
* This function parse a string option and create the associated object * This function parse a string option and create the associated object
* variable * variable
...@@ -1334,8 +1393,39 @@ static int TriggerCallback( vlc_object_t *p_this, variable_t *p_var, ...@@ -1334,8 +1393,39 @@ static int TriggerCallback( vlc_object_t *p_this, variable_t *p_var,
/* The real calls */ /* The real calls */
for( ; i_entries-- ; ) for( ; i_entries-- ; )
{ {
p_entries[i_entries].pf_callback( p_this, psz_name, oldval, p_var->val, p_entries[i_entries].u.pf_value_callback( p_this, psz_name, oldval, p_var->val,
p_entries[i_entries].p_data ); p_entries[i_entries].p_data );
}
vlc_mutex_lock( &p_priv->var_lock );
p_var->b_incallback = false;
vlc_cond_broadcast( &p_priv->var_wait );
return VLC_SUCCESS;
}
static int TriggerListCallback( vlc_object_t *p_this, variable_t *p_var,
const char *psz_name, int i_action,
vlc_value_t *val )
{
assert( p_this );
callback_table_t *p_table = &p_var->list_callbacks;
int i_entries = p_table->i_entries;
if( i_entries == 0 )
return VLC_SUCCESS;
callback_entry_t *p_entries = p_table->p_entries;
vlc_object_internals_t *p_priv = vlc_internals( p_this );
assert( !p_var->b_incallback );
p_var->b_incallback = true;
vlc_mutex_unlock( &p_priv->var_lock );
for( ; i_entries-- ; )
{
p_entries[i_entries].u.pf_list_callback( p_this, psz_name, i_action, val,
p_entries[i_entries].p_data );
} }
vlc_mutex_lock( &p_priv->var_lock ); vlc_mutex_lock( &p_priv->var_lock );
......
...@@ -107,6 +107,8 @@ struct variable_t ...@@ -107,6 +107,8 @@ struct variable_t
/** Registered value callbacks */ /** Registered value callbacks */
callback_table_t value_callbacks; callback_table_t value_callbacks;
/** Registered list callbacks */
callback_table_t list_callbacks;
}; };
extern void var_DestroyAll( vlc_object_t * ); extern void var_DestroyAll( vlc_object_t * );
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment