control/event.c: Definition at the top of the function and outline the alloc/free...
[vlc.git] / 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;
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 when entry is destroyed
67      */
68     new_listitem = malloc( sizeof( struct libvlc_callback_entry_list_t ) );
69     new_listitem->elmt = entry;
70     new_listitem->next = *list;
71     new_listitem->prev = NULL;
72
73     if(*list)
74         (*list)->prev = new_listitem;
75
76     *list = new_listitem;
77 }
78
79 /*
80  * Public libvlc functions
81  */
82
83 void libvlc_event_add_callback( libvlc_instance_t *p_instance,
84                                 libvlc_event_type_t i_event_type,
85                                 libvlc_callback_t f_callback,
86                                 void *user_data,
87                                 libvlc_exception_t *p_e )
88 {
89     struct libvlc_callback_entry_t *entry;
90     const char *callback_name = NULL;
91
92     if ( !f_callback )
93         RAISEVOID (" Callback function is null ");
94
95     /* malloc/free strategy:
96      *  - alloc-ded in libvlc_event_add_callback
97      *  - free-ed by libvlc_event_add_callback on error
98      *  - Not free-ed by libvlc_event_remove_callback  (FIXME leaks)
99      *  - Not free-ed in libvlc_destroy when entry is destroyed (FIXME leaks)
100      */
101     entry = malloc( sizeof( struct libvlc_callback_entry_t ) );
102     entry->f_callback = f_callback;
103     entry->i_event_type = i_event_type;
104     entry->p_user_data = user_data;
105     
106     switch ( i_event_type )
107     {
108         case VOLUME_CHANGED:
109             callback_name = "volume-change";
110             break;
111         case INPUT_POSITION_CHANGED:
112             break;
113         default:
114             free( entry );
115             RAISEVOID( "Unsupported event." );
116     }
117
118     int res = var_AddCallback( p_instance->p_libvlc_int,
119                                callback_name,
120                                handle_event,
121                                entry );
122     
123     if (res != VLC_SUCCESS)
124     {
125         free ( entry );
126         RAISEVOID("Internal callback registration was not successful. Callback not registered.");
127     }
128     
129     add_callback_entry( entry, &p_instance->p_callback_list );
130
131     return;
132 }
133
134 void libvlc_event_remove_callback( libvlc_instance_t *p_instance,
135                                    libvlc_event_type_t i_event_type,
136                                    libvlc_callback_t f_callback,
137                                    void *p_user_data,
138                                    libvlc_exception_t *p_e )
139 {
140     struct libvlc_callback_entry_list_t *p_listitem = p_instance->p_callback_list;
141
142     while( p_listitem )
143     {
144         if( p_listitem->elmt->f_callback == f_callback
145             && ( p_listitem->elmt->i_event_type == i_event_type )
146             && ( p_listitem->elmt->p_user_data == p_user_data )
147         
148         )
149         {
150             if( p_listitem->prev )
151                 p_listitem->prev->next = p_listitem->next;
152             else
153                 p_instance->p_callback_list = p_listitem->next;
154             
155             p_listitem->next->prev = p_listitem->prev;
156             free( p_listitem );
157             break;
158         }
159         p_listitem = p_listitem->next;
160     }
161 }