]> git.sesse.net Git - vlc/blob - src/control/event.c
libvlc event: Fix the various leaks and point indication on where locking should...
[vlc] / src / control / event.c
1 /*****************************************************************************
2  * event.c: New libvlc event control API
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * $Id $
6  *
7  * Authors: Filippo Carone <filippo@carone.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include "libvlc_internal.h"
25 #include <vlc/libvlc.h>
26
27
28 /*
29  * Private functions
30  */
31
32 static int handle_event( vlc_object_t *p_this, char const *psz_cmd,
33                          vlc_value_t oldval, vlc_value_t newval,
34                          void *p_data )
35 {
36     struct libvlc_callback_entry_t *entry = p_data; /* FIXME: we need some locking here */
37     libvlc_event_t event;
38     event.type = entry->i_event_type;
39     switch ( event.type )
40     {
41         case VOLUME_CHANGED:
42             event.value_type = BOOLEAN_EVENT;
43             break;
44         case INPUT_POSITION_CHANGED:
45             break;
46         default:
47             break;
48     }
49     event.old_value = oldval;
50     event.new_value = newval;
51
52     /* Call the client entry */
53     entry->f_callback( entry->p_instance, &event, entry->p_user_data );
54
55     return VLC_SUCCESS;
56 }
57
58 static inline void add_callback_entry( struct libvlc_callback_entry_t *entry,
59                                        struct libvlc_callback_entry_list_t **list )
60 {
61     struct libvlc_callback_entry_list_t *new_listitem;
62
63     /* malloc/free strategy:
64      *  - alloc-ded in add_callback_entry
65      *  - free-ed by libvlc_event_remove_callback
66      *  - free-ed in libvlc_destroy threw libvlc_event_remove_callback
67      *    when entry is destroyed
68      */
69     new_listitem = malloc( sizeof( struct libvlc_callback_entry_list_t ) );
70     new_listitem->elmt = entry;
71     new_listitem->next = *list;
72     new_listitem->prev = NULL;
73
74     if(*list)
75         (*list)->prev = new_listitem;
76
77     *list = new_listitem;
78 }
79
80 /*
81  * Public libvlc functions
82  */
83
84 void libvlc_event_add_callback( libvlc_instance_t *p_instance,
85                                 libvlc_event_type_t i_event_type,
86                                 libvlc_callback_t f_callback,
87                                 void *user_data,
88                                 libvlc_exception_t *p_e )
89 {
90     struct libvlc_callback_entry_t *entry;
91     const char *callback_name = NULL;
92
93     if ( !f_callback )
94         RAISEVOID (" Callback function is null ");
95
96     /* malloc/free strategy:
97      *  - alloc-ded in libvlc_event_add_callback
98      *  - free-ed by libvlc_event_add_callback on error
99      *  - free-ed by libvlc_event_remove_callback
100      *  - free-ed in libvlc_destroy threw libvlc_event_remove_callback
101      *    when entry is destroyed
102      */
103     entry = malloc( sizeof( struct libvlc_callback_entry_t ) );
104     entry->f_callback = f_callback;
105     entry->i_event_type = i_event_type;
106     entry->p_user_data = user_data;
107     
108     switch ( i_event_type )
109     {
110         case VOLUME_CHANGED:
111             callback_name = "volume-change";
112             break;
113         case INPUT_POSITION_CHANGED:
114             break;
115         default:
116             free( entry );
117             RAISEVOID( "Unsupported event." );
118     }
119
120     int res = var_AddCallback( p_instance->p_libvlc_int,
121                                callback_name,
122                                handle_event,
123                                entry );
124     
125     if (res != VLC_SUCCESS)
126     {
127         free ( entry );
128         RAISEVOID("Internal callback registration was not successful. Callback not registered.");
129     }
130     
131     add_callback_entry( entry, &p_instance->p_callback_list );
132
133     return;
134 }
135
136 void libvlc_event_remove_all_callbacks( libvlc_instance_t *p_instance,
137                                        libvlc_exception_t *p_e )
138 {
139     struct libvlc_callback_entry_list_t *p_listitem = p_instance->p_callback_list;
140
141     while( p_listitem )
142     {
143         libvlc_event_remove_callback( p_instance,
144             p_listitem->elmt->i_event_type,
145             p_listitem->elmt->f_callback,
146             p_listitem->elmt->p_user_data,
147             p_e);
148         /* libvlc_event_remove_callback will reset the p_callback_list */
149         p_listitem = p_instance->p_callback_list;
150     }
151 }
152
153 void libvlc_event_remove_callback( libvlc_instance_t *p_instance,
154                                    libvlc_event_type_t i_event_type,
155                                    libvlc_callback_t f_callback,
156                                    void *p_user_data,
157                                    libvlc_exception_t *p_e )
158 {
159     struct libvlc_callback_entry_list_t *p_listitem = p_instance->p_callback_list;
160
161     while( p_listitem )
162     {
163         if( p_listitem->elmt->f_callback == f_callback
164             && ( p_listitem->elmt->i_event_type == i_event_type )
165             && ( p_listitem->elmt->p_user_data == p_user_data )
166         
167         )
168         {
169             if( p_listitem->prev )
170                 p_listitem->prev->next = p_listitem->next;
171             else
172                 p_instance->p_callback_list = p_listitem->next;
173
174             p_listitem->next->prev = p_listitem->prev;
175             free( p_listitem->elmt ); /* FIXME: need some locking here */
176             free( p_listitem );
177             break;
178         }
179         p_listitem = p_listitem->next;
180     }
181 }