]> git.sesse.net Git - vlc/blob - src/misc/events.c
misc/events.c: Avoid a couple of warning and move the calling back out of the lock.
[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 <stdio.h>                                               /* required */
34 #include <stdlib.h>                                              /* malloc() */
35
36 #include <assert.h>
37
38 #include <vlc_events.h>
39 #include <vlc_arrays.h>
40
41 /*****************************************************************************
42  * Documentation : Read vlc_events.h
43  *****************************************************************************/
44
45 /*****************************************************************************
46  *  Private types.
47  *****************************************************************************/
48
49 typedef struct vlc_event_listener_t
50 {
51     void *               p_user_data;
52     vlc_event_callback_t pf_callback;
53 } vlc_event_listener_t;
54
55 typedef struct vlc_event_listeners_group_t
56 {
57     vlc_event_type_t    event_type;
58     DECL_ARRAY(struct vlc_event_listener_t *) listeners;
59 } vlc_event_listeners_group_t;
60
61 /*****************************************************************************
62  * 
63  *****************************************************************************/
64
65 /**
66  * Initialize event manager object
67  * p_obj is the object that contains the event manager. But not
68  * necessarily a vlc_object_t (an input_item_t is not a vlc_object_t
69  * for instance).
70  * p_parent_obj gives a libvlc instance
71  */
72 int vlc_event_manager_init( vlc_event_manager_t * p_em, void * p_obj,
73                             vlc_object_t * p_parent_obj )
74 {
75     p_em->p_obj = p_obj;
76     vlc_mutex_init( p_parent_obj, &p_em->object_lock );
77     ARRAY_INIT( p_em->listeners_groups );
78     return VLC_SUCCESS;
79 }
80
81 /**
82  * Destroy the event manager
83  */
84 void vlc_event_manager_fini( vlc_event_manager_t * p_em )
85 {
86     struct vlc_event_listeners_group_t * listeners_group;
87     struct vlc_event_listener_t * listener;
88
89     vlc_mutex_destroy( &p_em->object_lock );
90
91     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
92         FOREACH_ARRAY( listener, listeners_group->listeners )
93             free( listener );
94         FOREACH_END()
95         free( listeners_group );
96     FOREACH_END()
97 }
98
99 /**
100  * Destroy the event manager
101  */
102 int vlc_event_manager_register_event_type(
103         vlc_event_manager_t * p_em,
104         vlc_event_type_t event_type )
105 {
106     vlc_event_listeners_group_t * listeners_group;
107     listeners_group = malloc(sizeof(vlc_event_listeners_group_t));
108
109     if( !listeners_group )
110         return VLC_ENOMEM;
111
112     listeners_group->event_type = event_type;
113     ARRAY_INIT( listeners_group->listeners );
114     
115     vlc_mutex_lock( &p_em->object_lock );
116     ARRAY_APPEND( p_em->listeners_groups, listeners_group );
117     vlc_mutex_unlock( &p_em->object_lock );
118
119     return VLC_SUCCESS;
120 }
121
122 /**
123  * Send an event to the listener attached to this p_em.
124  */
125 void vlc_event_send( vlc_event_manager_t * p_em,
126                      vlc_event_t * p_event )
127 {
128     vlc_event_listeners_group_t * listeners_group;
129     vlc_event_listener_t * listener;
130     vlc_event_callback_t func;
131     void * user_data;
132
133     /* Fill event with the sending object now */
134     p_event->p_obj = p_em->p_obj;
135
136     vlc_mutex_lock( &p_em->object_lock );
137     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
138         if( listeners_group->event_type == p_event->type )
139         {
140             /* We found the group, now send every one the event */
141             FOREACH_ARRAY( listener, listeners_group->listeners )
142                 func = listener->pf_callback;
143                 user_data = listener->p_user_data;
144             FOREACH_END()
145             break;
146         }
147     FOREACH_END()
148     vlc_mutex_unlock( &p_em->object_lock );
149     
150     func( p_event, user_data );
151 }
152
153 /**
154  * Add a callback for an event.
155  */
156 int vlc_event_attach( vlc_event_manager_t * p_em,
157                       vlc_event_type_t event_type,
158                       vlc_event_callback_t pf_callback,
159                       void *p_user_data )
160 {
161     vlc_event_listeners_group_t * listeners_group;
162     vlc_event_listener_t * listener;
163     listener = malloc(sizeof(vlc_event_listener_t));
164     if( !listener )
165         return VLC_ENOMEM;
166     
167     listener->p_user_data = p_user_data;
168     listener->pf_callback = pf_callback;
169
170     vlc_mutex_lock( &p_em->object_lock );
171     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
172         if( listeners_group->event_type == event_type )
173         {
174             ARRAY_APPEND( listeners_group->listeners, listener );
175             vlc_mutex_unlock( &p_em->object_lock );
176             return VLC_SUCCESS;
177         }
178     FOREACH_END()
179     vlc_mutex_unlock( &p_em->object_lock );
180
181     free(listener);
182     return VLC_EGENERIC;
183 }
184
185 /**
186  * Remove a callback for an event.
187  */
188 int vlc_event_detach( vlc_event_manager_t *p_em,
189                       vlc_event_type_t event_type,
190                       vlc_event_callback_t pf_callback,
191                       void *p_user_data )
192 {
193     vlc_event_listeners_group_t * listeners_group;
194     struct vlc_event_listener_t * listener;
195
196     vlc_mutex_lock( &p_em->object_lock );
197     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
198         if( listeners_group->event_type == event_type )
199         {
200             FOREACH_ARRAY( listener, listeners_group->listeners )
201                 if( listener->pf_callback == pf_callback &&
202                     listener->p_user_data == p_user_data )
203                 {
204                     /* that's our listener */
205                     ARRAY_REMOVE( listeners_group->listeners,
206                         fe_idx /* This comes from the macro (and that's why
207                                   I hate macro) */ );
208                     free( listener );
209                     vlc_mutex_unlock( &p_em->object_lock );
210                     return VLC_SUCCESS;
211                 }
212             FOREACH_END()
213         }
214     FOREACH_END()
215     vlc_mutex_unlock( &p_em->object_lock );
216
217     return VLC_EGENERIC;
218 }
219
220