]> git.sesse.net Git - vlc/blob - src/misc/events.c
Remember not to include anything before vlc/vlc.h
[vlc] / src / misc / events.c
1  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
2  *****************************************************************************/
3
4 /*****************************************************************************
5  * Preamble
6  *****************************************************************************/
7
8 #include <vlc/vlc.h>
9
10 #include <assert.h>
11
12 #include <vlc_events.h>
13 #include <vlc_arrays.h>
14
15 /*****************************************************************************
16  * Documentation : Read vlc_events.h
17  *****************************************************************************/
18
19 /*****************************************************************************
20  *  Private types.
21  *****************************************************************************/
22
23 typedef struct vlc_event_listener_t
24 {
25     void *               p_user_data;
26     vlc_event_callback_t pf_callback;
27 } vlc_event_listener_t;
28
29 typedef struct vlc_event_listeners_group_t
30 {
31     vlc_event_type_t    event_type;
32     DECL_ARRAY(struct vlc_event_listener_t *) listeners;
33 } vlc_event_listeners_group_t;
34
35 /*****************************************************************************
36  * 
37  *****************************************************************************/
38
39 /**
40  * Initialize event manager object
41  * p_obj is the object that contains the event manager. But not
42  * necessarily a vlc_object_t (an input_item_t is not a vlc_object_t
43  * for instance).
44  * p_parent_obj gives a libvlc instance
45  */
46 int vlc_event_manager_init( vlc_event_manager_t * p_em, void * p_obj,
47                             vlc_object_t * p_parent_obj )
48 {
49     p_em->p_obj = p_obj;
50     vlc_mutex_init( p_parent_obj, &p_em->object_lock );
51     ARRAY_INIT( p_em->listeners_groups );
52     return VLC_SUCCESS;
53 }
54
55 /**
56  * Destroy the event manager
57  */
58 void vlc_event_manager_fini( vlc_event_manager_t * p_em )
59 {
60     struct vlc_event_listeners_group_t * listeners_group;
61     struct vlc_event_listener_t * listener;
62
63     vlc_mutex_destroy( &p_em->object_lock );
64
65     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
66         FOREACH_ARRAY( listener, listeners_group->listeners )
67             free( listener );
68         FOREACH_END()
69         free( listeners_group );
70     FOREACH_END()
71 }
72
73 /**
74  * Destroy the event manager
75  */
76 int vlc_event_manager_register_event_type(
77         vlc_event_manager_t * p_em,
78         vlc_event_type_t event_type )
79 {
80     vlc_event_listeners_group_t * listeners_group;
81     listeners_group = malloc(sizeof(vlc_event_listeners_group_t));
82
83     if( !listeners_group )
84         return VLC_ENOMEM;
85
86     listeners_group->event_type = event_type;
87     ARRAY_INIT( listeners_group->listeners );
88     
89     vlc_mutex_lock( &p_em->object_lock );
90     ARRAY_APPEND( p_em->listeners_groups, listeners_group );
91     vlc_mutex_unlock( &p_em->object_lock );
92
93     return VLC_SUCCESS;
94 }
95
96 /**
97  * Send an event to the listener attached to this p_em.
98  */
99 void vlc_event_send( vlc_event_manager_t * p_em,
100                      vlc_event_t * p_event )
101 {
102     vlc_event_listeners_group_t * listeners_group;
103     vlc_event_listener_t * listener;
104     vlc_event_callback_t func = NULL;
105     void * user_data = NULL;
106
107     /* Fill event with the sending object now */
108     p_event->p_obj = p_em->p_obj;
109
110     vlc_mutex_lock( &p_em->object_lock );
111     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
112         if( listeners_group->event_type == p_event->type )
113         {
114             /* We found the group, now send every one the event */
115             FOREACH_ARRAY( listener, listeners_group->listeners )
116                 func = listener->pf_callback;
117                 user_data = listener->p_user_data;
118                 /* This is safe to do that because we are sure 
119                  * that there will be no object owned references
120                  * used after the lock. */
121                 vlc_mutex_unlock( &p_em->object_lock );
122                 func( p_event, user_data );
123                 vlc_mutex_lock( &p_em->object_lock );
124             FOREACH_END()
125             break;
126         }
127     FOREACH_END()
128     vlc_mutex_unlock( &p_em->object_lock );
129 }
130
131 /**
132  * Add a callback for an event.
133  */
134 int vlc_event_attach( vlc_event_manager_t * p_em,
135                       vlc_event_type_t event_type,
136                       vlc_event_callback_t pf_callback,
137                       void *p_user_data )
138 {
139     vlc_event_listeners_group_t * listeners_group;
140     vlc_event_listener_t * listener;
141     listener = malloc(sizeof(vlc_event_listener_t));
142     if( !listener )
143         return VLC_ENOMEM;
144     
145     listener->p_user_data = p_user_data;
146     listener->pf_callback = pf_callback;
147
148     vlc_mutex_lock( &p_em->object_lock );
149     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
150         if( listeners_group->event_type == event_type )
151         {
152             ARRAY_APPEND( listeners_group->listeners, listener );
153             vlc_mutex_unlock( &p_em->object_lock );
154             return VLC_SUCCESS;
155         }
156     FOREACH_END()
157     vlc_mutex_unlock( &p_em->object_lock );
158
159     free(listener);
160     return VLC_EGENERIC;
161 }
162
163 /**
164  * Remove a callback for an event.
165  */
166 int vlc_event_detach( vlc_event_manager_t *p_em,
167                       vlc_event_type_t event_type,
168                       vlc_event_callback_t pf_callback,
169                       void *p_user_data )
170 {
171     vlc_event_listeners_group_t * listeners_group;
172     struct vlc_event_listener_t * listener;
173
174     vlc_mutex_lock( &p_em->object_lock );
175     FOREACH_ARRAY( listeners_group, p_em->listeners_groups )
176         if( listeners_group->event_type == event_type )
177         {
178             FOREACH_ARRAY( listener, listeners_group->listeners )
179                 if( listener->pf_callback == pf_callback &&
180                     listener->p_user_data == p_user_data )
181                 {
182                     /* that's our listener */
183                     ARRAY_REMOVE( listeners_group->listeners,
184                         fe_idx /* This comes from the macro (and that's why
185                                   I hate macro) */ );
186                     free( listener );
187                     vlc_mutex_unlock( &p_em->object_lock );
188                     return VLC_SUCCESS;
189                 }
190             FOREACH_END()
191         }
192     FOREACH_END()
193     vlc_mutex_unlock( &p_em->object_lock );
194
195     return VLC_EGENERIC;
196 }
197
198