From ad24c4fbf7e1bdef1df40be8e78a97b70a7b7af4 Mon Sep 17 00:00:00 2001 From: Felix Abecassis Date: Mon, 4 Aug 2014 12:06:29 +0200 Subject: [PATCH] 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. --- include/vlc_common.h | 17 +++++- include/vlc_variables.h | 6 ++ src/libvlccore.sym | 2 + src/misc/variables.c | 118 +++++++++++++++++++++++++++++++++++----- src/misc/variables.h | 2 + 5 files changed, 130 insertions(+), 15 deletions(-) diff --git a/include/vlc_common.h b/include/vlc_common.h index 8b4b923d9e..128177e022 100644 --- a/include/vlc_common.h +++ b/include/vlc_common.h @@ -382,7 +382,7 @@ struct vlc_list_t #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 */ char const *, /* variable name */ @@ -390,6 +390,21 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *, /* variable's object */ vlc_value_t, /* new value */ 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 *****************************************************************************/ diff --git a/include/vlc_variables.h b/include/vlc_variables.h index 420f0b4d02..6f48aa1760 100644 --- a/include/vlc_variables.h +++ b/include/vlc_variables.h @@ -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_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_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_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 *****************************************************************************/ diff --git a/src/libvlccore.sym b/src/libvlccore.sym index 1b9973e47b..bdd7b065f1 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -452,9 +452,11 @@ vlc_socket vlc_accept utf8_vfprintf var_AddCallback +var_AddListCallback var_Change var_Create var_DelCallback +var_DelListCallback var_Destroy var_FreeList var_Get diff --git a/src/misc/variables.c b/src/misc/variables.c index 46d5194b9c..05a11d409a 100644 --- a/src/misc/variables.c +++ b/src/misc/variables.c @@ -49,7 +49,12 @@ *****************************************************************************/ 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; }; @@ -136,6 +141,10 @@ static void CheckValue ( variable_t *, vlc_value_t * ); static int TriggerCallback( vlc_object_t *, variable_t *, const char *, 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 ) { const variable_t *va = a, *vb = b; @@ -461,6 +470,8 @@ int var_Change( vlc_object_t *p_this, const char *psz_name, strdup( p_val2->psz_string ) : NULL; CheckValue( p_var, &p_var->val ); + + TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_ADDCHOICE, p_val); break; } case VLC_VAR_DELCHOICE: @@ -490,6 +501,8 @@ int var_Change( vlc_object_t *p_this, const char *psz_name, p_var->choices_text.i_count, i ); CheckValue( p_var, &p_var->val ); + + TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_DELCHOICE, p_val); break; } case VLC_VAR_CHOICESCOUNT: @@ -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.p_values = NULL; p_var->i_default = -1; + TriggerListCallback(p_this, p_var, psz_name, VLC_VAR_CLEARCHOICES, NULL); break; 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 ) } 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; @@ -820,12 +834,17 @@ static int AddCallback( vlc_object_t *p_this, const char *psz_name, { vlc_mutex_unlock( &p_priv->var_lock ); 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; } 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, p_table->i_entries, p_table->i_entries, @@ -857,14 +876,14 @@ int var_AddCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ) { callback_entry_t entry; - entry.pf_callback = pf_callback; + entry.u.pf_value_callback = pf_callback; 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, - callback_entry_t entry ) + callback_entry_t entry, vlc_callback_type_t i_type ) { int i_entry; variable_t *p_var; @@ -887,16 +906,21 @@ static int DelCallback( vlc_object_t *p_this, const char *psz_name, 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-- ; ) { - 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 ) { break; } #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; #endif } @@ -931,10 +955,10 @@ int var_DelCallback( vlc_object_t *p_this, const char *psz_name, vlc_callback_t pf_callback, void *p_data ) { callback_entry_t entry; - entry.pf_callback = pf_callback; + entry.u.pf_value_callback = pf_callback; 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 @@ -972,6 +996,41 @@ int var_TriggerCallback( vlc_object_t *p_this, const char *psz_name ) 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 * This function parse a string option and create the associated object * variable @@ -1334,8 +1393,39 @@ static int TriggerCallback( vlc_object_t *p_this, variable_t *p_var, /* The real calls */ for( ; i_entries-- ; ) { - p_entries[i_entries].pf_callback( p_this, psz_name, oldval, p_var->val, - p_entries[i_entries].p_data ); + p_entries[i_entries].u.pf_value_callback( p_this, psz_name, oldval, p_var->val, + 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 ); diff --git a/src/misc/variables.h b/src/misc/variables.h index d09ba6618f..35b82030e2 100644 --- a/src/misc/variables.h +++ b/src/misc/variables.h @@ -107,6 +107,8 @@ struct variable_t /** Registered value callbacks */ callback_table_t value_callbacks; + /** Registered list callbacks */ + callback_table_t list_callbacks; }; extern void var_DestroyAll( vlc_object_t * );