[vlc-devel] [PATCH 3/3] core: add a new type of callback for list variables

Felix Abecassis felix.abecassis at gmail.com
Fri Jul 25 16:38:59 CEST 2014


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 8b4b923..128177e 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 */
@@ -391,6 +391,21 @@ typedef int ( * vlc_callback_t ) ( vlc_object_t *,      /* variable's object */
                                    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
  *****************************************************************************/
 #if defined( _WIN32 )
diff --git a/include/vlc_variables.h b/include/vlc_variables.h
index 420f0b4..6f48aa1 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 325c8f6..679958d 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 d40469f..70653c3 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_var->p_entries[i_entry].pf_callback == pf_callback )
+        else if( 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 d09ba66..35b8203 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 * );
-- 
1.9.1




More information about the vlc-devel mailing list