]> git.sesse.net Git - vlc/blob - src/misc/events.c
Something went wrong here
[vlc] / src / misc / events.c
1 /*****************************************************************************
2  * events.c: events interface
3  * This library provides an interface to the send and receive events.
4  * It is more lightweight than variable based callback.
5  * Methode
6  *****************************************************************************
7  * Copyright (C) 1998-2005 the VideoLAN team
8  * $Id$
9  *
10  * Authors: Pierre d'Herbemont <pdherbemont # videolan.org >
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /*****************************************************************************
28  * Preamble
29  *****************************************************************************/
30
31 #include <vlc/vlc.h>
32
33 #include <assert.h>
34
35 #include <vlc_events.h>
36 #include <vlc_arrays.h>
37
38 /*****************************************************************************
39  * Documentation : Read vlc_events.h
40  *****************************************************************************/
41
42 /*****************************************************************************
43  *  Private types.
44  *****************************************************************************/
45
46 typedef struct vlc_event_listener_t
47 {
48     void *               p_user_data;
49     vlc_event_callback_t pf_callback;
50 } vlc_event_listener_t;
51
52 typedef struct vlc_event_listeners_group_t
53 {
54     vlc_event_type_t    event_type;
55     DECL_ARRAY(struct vlc_event_listener_t *) listeners;
56 } vlc_event_listeners_group_t;
57
58 /*****************************************************************************
59  * 
60  *****************************************************************************/
61
62 /**
63  * Initialize event manager object
64  * p_obj is the object that contains the event manager. But not
65  * necessarily a vlc_object_t (an input_item_t is not a vlc_object_t
66  * for instance).
67  * p_parent_obj gives a libvlc instance
68  */
69 int vlc_event_manager_init( vlc_event_manager_t * p_em, void * p_obj,
70                             vlc_object_t * p_parent_obj )
71 {
72     p_em->p_obj = p_obj;
73     vlc_mutex_init( p_parent_obj, &p_em->object_lock );
74     ARRAY_INIT( p_em->listeners_groups );
75     return VLC_SUCCESS;
76 }
77
78 /**
79  * Destroy the event manager
80  */
81 void vlc_event_manager_fini( vlc_event_manager_t * p_em )
82 {
83     struct vlc_event_listeners_group_t * listeners_group;
84     struct vlc_event_listener_t * listener;
85
86     vlc_mutex_destroy( &p_em->object_lock );
87
88     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
89         FOREACH_ARRAY( listener, listeners_group->listeners )
90             free( listener );
91         FOREACH_END()
92         free( listeners_group );
93     FOREACH_END()
94 }
95
96 /**
97  * Destroy the event manager
98  */
99 int vlc_event_manager_register_event_type(
100         vlc_event_manager_t * p_em,
101         vlc_event_type_t event_type )
102 {
103     vlc_event_listeners_group_t * listeners_group;
104     listeners_group = malloc(sizeof(vlc_event_listeners_group_t));
105
106     if( !listeners_group )
107         return VLC_ENOMEM;
108
109     listeners_group->event_type = event_type;
110     ARRAY_INIT( listeners_group->listeners );
111     
112     vlc_mutex_lock( &p_em->object_lock );
113     ARRAY_APPEND( p_em->listeners_groups, listeners_group );
114     vlc_mutex_unlock( &p_em->object_lock );
115
116     return VLC_SUCCESS;
117 }
118
119 /**
120  * Send an event to the listener attached to this p_em.
121  */
122 void vlc_event_send( vlc_event_manager_t * p_em,
123                      vlc_event_t * p_event )
124 {
125     vlc_event_listeners_group_t * listeners_group;
126     vlc_event_listener_t * listener;
127     vlc_event_callback_t func = NULL;
128     void * user_data = NULL;
129
130     /* Fill event with the sending object now */
131     p_event->p_obj = p_em->p_obj;
132
133     vlc_mutex_lock( &p_em->object_lock );
134     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
135         if( listeners_group->event_type == p_event->type )
136         {
137             /* We found the group, now send every one the event */
138             FOREACH_ARRAY( listener, listeners_group->listeners )
139                 func = listener->pf_callback;
140                 user_data = listener->p_user_data;
141                 /* This is safe to do that because we are sure 
142                  * that there will be no object owned references
143                  * used after the lock. */
144                 vlc_mutex_unlock( &p_em->object_lock );
145                 func( p_event, user_data );
146                 vlc_mutex_lock( &p_em->object_lock );
147             FOREACH_END()
148             break;
149         }
150     FOREACH_END()
151     vlc_mutex_unlock( &p_em->object_lock );
152 }
153
154 /**
155  * Add a callback for an event.
156  */
157 int vlc_event_attach( vlc_event_manager_t * p_em,
158                       vlc_event_type_t event_type,
159                       vlc_event_callback_t pf_callback,
160                       void *p_user_data )
161 {
162     vlc_event_listeners_group_t * listeners_group;
163     vlc_event_listener_t * listener;
164     listener = malloc(sizeof(vlc_event_listener_t));
165     if( !listener )
166         return VLC_ENOMEM;
167     
168     listener->p_user_data = p_user_data;
169     listener->pf_callback = pf_callback;
170
171     vlc_mutex_lock( &p_em->object_lock );
172     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
173         if( listeners_group->event_type == event_type )
174         {
175             ARRAY_APPEND( listeners_group->listeners, listener );
176             vlc_mutex_unlock( &p_em->object_lock );
177             return VLC_SUCCESS;
178         }
179     FOREACH_END()
180     vlc_mutex_unlock( &p_em->object_lock );
181
182     free(listener);
183     return VLC_EGENERIC;
184 }
185
186 /**
187  * Remove a callback for an event.
188  */
189 int vlc_event_detach( vlc_event_manager_t *p_em,
190                       vlc_event_type_t event_type,
191                       vlc_event_callback_t pf_callback,
192                       void *p_user_data )
193 {
194     vlc_event_listeners_group_t * listeners_group;
195     struct vlc_event_listener_t * listener;
196
197     vlc_mutex_lock( &p_em->object_lock );
198     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
199         if( listeners_group->event_type == event_type )
200         {
201             FOREACH_ARRAY( listener, listeners_group->listeners )
202                 if( listener->pf_callback == pf_callback &&
203                     listener->p_user_data == p_user_data )
204                 {
205                     /* that's our listener */
206                     ARRAY_REMOVE( listeners_group->listeners,
207                         fe_idx /* This comes from the macro (and that's why
208                                   I hate macro) */ );
209                     free( listener );
210                     vlc_mutex_unlock( &p_em->object_lock );
211                     return VLC_SUCCESS;
212                 }
213             FOREACH_END()
214         }
215     FOREACH_END()
216     vlc_mutex_unlock( &p_em->object_lock );
217
218     return VLC_EGENERIC;
219 }
220
221